1 /*globals Editor fileId SplitView PanelContainerView EditorView FlashView messageCenter*/
2 Editor.Model = Editor.Object.extend({
7 Editor.ToolbarButtonsModel = Editor.Model.extend({
8 className: 'Editor.ToolbarButtonsModel',
16 if (!this.get('buttons').length) {
18 url: documentInfo.toolbarURL,
20 success: this.loadSucceeded.bind(this)
25 loadSucceeded: function(data)
28 $.each(data, function() {
29 $.each(this.buttons, function() {
30 //do some lame escapes
31 this.tooltip = this.tooltip.replace(/"/g, """);
34 this.set('buttons', data);
40 // HTML Document Model
42 Editor.HTMLModel = Editor.Model.extend({
43 _className: 'Editor.HTMLModel',
47 init: function(document, textURL) {
49 this.set('state', 'empty');
50 this.set('revision', document.get('revision'));
51 this.document = document;
53 this.textURL = textURL;
59 // create a parser and a serializer
60 this.parser = new DOMParser();
61 this.serializer = new XMLSerializer();
63 this.addObserver(this, 'data', this.dataChanged.bind(this));
66 load: function(force) {
67 if (force || this.get('state') == 'empty') {
68 this.set('state', 'loading');
69 messageCenter.addMessage('info', 'xmlload', 'Wczytuję HTML...');
71 // request all stylesheets
73 url: documentInfo.staticURL + 'xsl/wl2html_client.xsl',
75 success: this.htmlXSLLoadSuccess.bind(this),
76 error: this.loadingFailed.bind(this)
80 url: documentInfo.staticURL + 'xsl/html2wl_client.xsl',
82 success: this.wlmlXSLLoadSuccess.bind(this),
83 error: this.loadingFailed.bind(this)
90 revision: this.get('revision'),
91 user: this.document.get('user')
93 success: this.textLoadSuccess.bind(this),
94 error: this.loadingFailed.bind(this)
101 asWLML: function(element, inner)
103 console.log("Source", element);
104 var doc = this.parser.parseFromString(this.serializer.serializeToString(element), 'text/xml');
106 var result = this.wlmlXSL.transformToDocument(doc);
109 console.log("Failed", this.wlmlXSL, doc);
110 throw "Failed to transform fragment";
113 console.log("Transformed", doc, " to: ", result.documentElement);
115 var children = result.documentElement.childNodes;
118 for(var i=0; i < children.length; i++)
119 buf += this.serializer.serializeToString(children.item(i));
124 return this.serializer.serializeToString(result.documentElement);
127 innerAsWLML: function(elem)
129 return this.asWLML(elem, true);
132 updateInnerWithWLML: function($element, innerML)
134 var e = $element.clone().html('<span x-node="out-of-flow-text" x-content="%"></span>')[0];
135 var s = this.asWLML(e);
136 // hurray for dirty hacks :P
137 s = s.replace(/>%<\//, '>'+innerML+'</');
138 return this.updateWithWLML($element, s);
141 updateWithWLML: function($element, text)
144 text = text.replace(/\/\s+/g, '<br />');
146 var chunk = this.parser.parseFromString("<chunk>"+text+"</chunk>", "text/xml");
148 console.log('Caught parse exception.');
149 return "<p>Źle sformatowana zawartość:" + e.toString() + "</p>";
152 var parseError = chunk.getElementsByTagName('parsererror');
153 console.log("Errors:", parseError);
155 if(parseError.length > 0)
157 console.log("Parse errors.")
158 return this.serializer.serializeToString(parseError.item(0));
161 console.log("Transforming to HTML");
162 var result = this.htmlXSL.transformToFragment(chunk, $element[0].ownerDocument).firstChild;
165 return "Błąd aplikacji - nie udało się wygenerować nowego widoku HTML.";
168 var errors = result.getElementsByTagName('error');
169 if(errors.length > 0)
171 var errorMessage = 'Wystąpiły błędy:<ul>';
172 for(var i=0; i < errors.length; i++)
174 var estr = this.serializer.serializeToString(errors.item(i));
175 console.log("XFRM error:", estr);
176 errorMessage += "<li>"+estr+"</li>";
178 errorMessage += "</ul>";
183 $element.replaceWith(result);
184 this.set('state', 'dirty');
187 return "Błąd podczas wstawiania tekstu: '" + e.toString() + "'";
191 createXSLT: function(xslt_doc) {
192 var p = new XSLTProcessor();
193 p.importStylesheet(xslt_doc);
197 htmlXSLLoadSuccess: function(data)
200 this.htmlXSL = this.createXSLT(data);
202 if(this.wlmlXSL && this.htmlXSL && this.rawText)
206 this.set('error', e.toString() );
207 this.set('state', 'error');
211 wlmlXSLLoadSuccess: function(data)
214 this.wlmlXSL = this.createXSLT(data);
216 if(this.wlmlXSL && this.htmlXSL && this.rawText)
220 this.set('error', e.toString() );
221 this.set('state', 'error');
225 textLoadSuccess: function(data) {
228 if(this.wlmlXSL && this.htmlXSL && this.rawText)
232 loadSuccess: function() {
233 if (this.get('state') != 'loading') {
234 alert('erroneous state:', this.get('state'));
239 doc = this.rawText.replace(/\/\s+/g, '<br />');
240 doc = this.parser.parseFromString(doc, 'text/xml');
241 doc = this.htmlXSL.transformToFragment(doc, document).firstChild;
243 this.set('data', doc);
244 this.set('state', 'synced');
245 messageCenter.addMessage('success', 'xmlload', 'Wczytałem HTML :-)');
248 loadingFailed: function(response)
250 if (this.get('state') != 'loading') {
251 alert('erroneous state:', this.get('state'));
254 var message = parseXHRError(response);
256 this.set('error', '<h2>Błąd przy ładowaniu XML</h2><p>'+message+'</p>');
257 this.set('state', 'error');
258 messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
261 save: function(message) {
262 if (this.get('state') == 'dirty') {
263 this.set('state', 'saving');
265 messageCenter.addMessage('info', 'htmlsave', 'Zapisuję HTML...');
266 var wlml = this.asWLML(this.get('data'));
270 revision: this.get('revision'),
271 user: this.document.get('user')
275 payload.message = message;
283 success: this.saveSucceeded.bind(this),
284 error: this.saveFailed.bind(this)
291 saveSucceeded: function(data) {
292 if (this.get('state') != 'saving') {
293 alert('erroneous state:', this.get('state'));
295 this.set('revision', data.revision);
296 this.set('state', 'updated');
297 messageCenter.addMessage('success', 'htmlsave', 'Zapisałem :-)');
300 saveFailed: function() {
301 if (this.get('state') != 'saving') {
302 alert('erroneous state:', this.get('state'));
304 messageCenter.addMessage('error', 'htmlsave', 'Nie udało mi się zapisać.');
305 this.set('state', 'dirty');
309 set: function(property, value) {
310 if (property == 'state') {
311 console.log(this.description(), ':', property, '=', value);
313 return this._super(property, value);
316 dataChanged: function(property, value) {
317 if (this.get('state') == 'synced') {
318 this.set('state', 'dirty');
322 dispose: function() {
323 this.removeObserver(this);
331 // -> error -> loading
333 // empty -> loading -> synced -> unsynced -> loading
335 // -> dirty -> updating -> updated -> synced
337 Editor.XMLModel = Editor.Model.extend({
338 _className: 'Editor.XMLModel',
343 init: function(document, serverURL) {
345 this.set('state', 'empty');
346 this.set('revision', document.get('revision'));
347 this.document = document;
348 this.serverURL = serverURL;
349 this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
350 this.addObserver(this, 'data', this.dataChanged.bind(this));
353 load: function(force) {
354 if (force || this.get('state') == 'empty') {
355 this.set('state', 'loading');
356 messageCenter.addMessage('info', 'xmlload', 'Wczytuję XML...');
361 revision: this.get('revision'),
362 user: this.document.get('user')
364 success: this.loadingSucceeded.bind(this),
365 error: this.loadingFailed.bind(this)
372 loadingSucceeded: function(data) {
373 if (this.get('state') != 'loading') {
374 alert('erroneous state:', this.get('state'));
376 this.set('data', data);
377 this.set('state', 'synced');
378 messageCenter.addMessage('success', 'xmlload', 'Wczytałem XML :-)');
381 loadingFailed: function(response)
383 if (this.get('state') != 'loading') {
384 alert('erroneous state:', this.get('state'));
387 var message = parseXHRError(response);
389 this.set('error', '<h2>Błąd przy ładowaniu XML</h2><p>'+message+'</p>');
390 this.set('state', 'error');
391 messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
394 save: function(message) {
395 if (this.get('state') == 'dirty') {
396 this.set('state', 'updating');
397 messageCenter.addMessage('info', 'xmlsave', 'Zapisuję XML...');
400 contents: this.get('data'),
401 revision: this.get('revision'),
402 user: this.document.get('user')
405 payload.message = message;
413 success: this.saveSucceeded.bind(this),
414 error: this.saveFailed.bind(this)
421 saveSucceeded: function(data) {
422 if (this.get('state') != 'updating') {
423 alert('erroneous state:', this.get('state'));
425 this.set('revision', data.revision);
426 this.set('state', 'updated');
427 messageCenter.addMessage('success', 'xmlsave', 'Zapisałem XML :-)');
430 saveFailed: function() {
431 if (this.get('state') != 'updating') {
432 alert('erroneous state:', this.get('state'));
434 messageCenter.addMessage('error', 'xmlsave', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
435 this.set('state', 'dirty');
439 set: function(property, value) {
440 if (property == 'state') {
441 console.log(this.description(), ':', property, '=', value);
443 return this._super(property, value);
446 dataChanged: function(property, value) {
447 if (this.get('state') == 'synced') {
448 this.set('state', 'dirty');
452 dispose: function() {
453 this.removeObserver(this);
458 Editor.ImageGalleryModel = Editor.Model.extend({
459 _className: 'Editor.ImageGalleryModel',
464 init: function(document, serverURL) {
466 this.set('state', 'empty');
467 this.serverURL = serverURL;
472 setGallery: function(path) {
479 success: this.settingGallerySucceeded.bind(this)
483 settingGallerySucceeded: function(data) {
484 console.log('settingGallerySucceeded');
488 load: function(force) {
489 if (force || this.get('state') == 'empty') {
490 console.log("setting state");
491 this.set('state', 'loading');
492 console.log("going ajax");
496 success: this.loadingSucceeded.bind(this),
497 error: this.loadingFailed.bind(this)
502 loadingSucceeded: function(data)
504 console.log("success");
506 if (this.get('state') != 'loading') {
507 alert('erroneous state:', this.get('state'));
510 console.log('galleries:', data);
512 if (data.length === 0) {
513 this.set('data', []);
515 this.set('data', data[0].pages);
518 this.set('state', 'synced');
521 loadingFailed: function(data) {
522 console.log("failed");
524 if (this.get('state') != 'loading') {
525 alert('erroneous state:', this.get('state'));
528 this.set('state', 'error');
531 set: function(property, value) {
532 if (property == 'state') {
533 console.log(this.description(), ':', property, '=', value);
535 return this._super(property, value);
540 Editor.DocumentModel = Editor.Model.extend({
541 _className: 'Editor.DocumentModel',
542 data: null, // name, text_url, revision, latest_shared_rev, parts_url, dc_url, size, merge_url
551 this.set('state', 'empty');
555 if (this.get('state') == 'empty') {
556 this.set('state', 'loading');
557 messageCenter.addMessage('info', 'docload', 'Ładuję dane dokumentu...');
560 url: documentInfo.docURL,
562 success: this.successfulLoad.bind(this),
563 error: this.failedLoad.bind(this)
568 successfulLoad: function(data) {
569 this.set('data', data);
570 this.set('state', 'synced');
572 this.set('revision', data.revision);
573 this.set('user', data.user);
575 this.contentModels = {
576 'xml': new Editor.XMLModel(this, data.text_url),
577 'html': new Editor.HTMLModel(this, data.text_url),
578 'gallery': new Editor.ImageGalleryModel(this, data.gallery_url)
581 for (var key in this.contentModels) {
582 this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
587 messageCenter.addMessage('success', 'docload', 'Dokument załadowany poprawnie :-)');
590 failedLoad: function(response) {
591 if (this.get('state') != 'loading') {
592 alert('erroneous state:', this.get('state'));
595 var err = parseXHRError(response);
596 this.set('error', '<h2>Nie udało się wczytać dokumentu</h2><p>'+err.error_message+"</p>");
597 this.set('state', 'error');
600 contentModelStateChanged: function(property, value, contentModel) {
601 if (value == 'dirty') {
602 this.set('state', 'dirty');
603 for (var key in this.contentModels) {
604 if (this.contentModels[key].guid() != contentModel.guid()) {
605 this.contentModels[key].set('state', 'unsynced');
608 } else if (value == 'updated') {
609 this.set('state', 'synced');
610 for (key in this.contentModels) {
611 if (this.contentModels[key].guid() == contentModel.guid()) {
612 this.contentModels[key].set('state', 'synced');
613 this.revision = this.contentModels[key].get('revision');
617 for (key in this.contentModels) {
618 if (this.contentModels[key].guid() != contentModel.guid()) {
619 this.contentModels[key].set('revision', this.revision);
620 this.contentModels[key].set('state', 'empty');
626 saveDirtyContentModel: function(message) {
627 for (var key in this.contentModels) {
628 if (this.contentModels[key].get('state') == 'dirty') {
629 this.contentModels[key].save(message);
636 this.set('state', 'loading');
638 messageCenter.addMessage('info', 'doc_update',
639 'Uaktualniam dokument...');
642 url: this.data.merge_url,
647 revision: this.get('revision'),
648 user: this.get('user')
650 complete: this.updateCompleted.bind(this)
654 updateCompleted: function(xhr, textStatus)
656 console.log(xhr.status, xhr.responseText);
657 var response = parseXHRResponse(xhr);
660 if( (response.data.result == 'no-op')
661 || (response.data.timestamp == response.data.parent_timestamp))
663 if( (response.data.revision) && (response.data.revision != this.get('revision')) )
666 this.set('state', 'unsynced');
670 messageCenter.addMessage('info', 'doc_update',
671 'Już posiadasz najbardziej aktualną wersję.');
672 this.set('state', 'synced');
677 this.set('revision', response.data.revision);
678 this.set('user', response.data.user);
680 messageCenter.addMessage('info', 'doc_update',
681 'Uaktualnienie dokumentu do wersji ' + response.data.revision);
683 for (var key in this.contentModels) {
684 this.contentModels[key].set('revision', this.get('revision') );
685 this.contentModels[key].set('state', 'empty');
688 this.set('state', 'synced');
692 // no success means trouble
693 messageCenter.addMessage(response.error_level, 'doc_update',
694 response.error_message);
696 this.set('state', 'unsynced');
699 merge: function(message) {
700 this.set('state', 'loading');
701 messageCenter.addMessage('info', 'doc_merge',
702 'Scalam dokument z głównym repozytorium...');
705 url: this.data.merge_url,
710 revision: this.get('revision'),
711 user: this.get('user'),
714 complete: this.mergeCompleted.bind(this),
715 success: function(data) {
716 this.set('mergeData', data);
721 mergeCompleted: function(xhr, textStatus) {
722 console.log(xhr.status, xhr.responseText);
723 var response = parseXHRResponse(xhr);
725 if(response.success) {
727 if( (response.data.result == 'no-op') ||
728 ( response.data.shared_parent_timestamp
729 && response.data.shared_timestamp
730 && (response.data.shared_timestamp == response.data.shared_parent_timestamp)) )
732 if( (response.data.revision) && (response.data.revision != this.get('revision')) )
735 this.set('state', 'unsynced');
739 messageCenter.addMessage('info', 'doc_merge',
740 'Twoja aktualna wersja nie różni się od ostatnio zatwierdzonej.');
741 this.set('state', 'synced');
745 if( response.data.result == 'accepted')
747 messageCenter.addMessage('info', 'doc_merge',
748 'Prośba o zatwierdzenie została przyjęta i oczekuję na przyjęcie.');
749 this.set('state', 'synced');
754 this.set('revision', response.data.revision);
755 this.set('user', response.data.user);
757 messageCenter.addMessage('info', 'doc_merge',
758 'Twoja wersja dokumentu została zatwierdzona.');
760 this.set('state', 'synced');
764 // no success means trouble
765 messageCenter.addMessage(response.error_level, 'doc_merge',
766 response.error_message);
768 this.set('state', 'unsynced');
772 set: function(property, value) {
773 if (property == 'state') {
774 console.log(this.description(), ':', property, '=', value);
776 return this._super(property, value);
781 var leftPanelView, rightPanelContainer, doc;
785 var flashView = new FlashView('#flashview', messageCenter);
787 doc = new Editor.DocumentModel();
789 EditorView = new EditorView('#body-wrap', doc);
790 EditorView.freeze("<h1>Wczytuję dokument...</h1>");
792 leftPanelView = new PanelContainerView('#left-panel-container', doc);
793 rightPanelContainer = new PanelContainerView('#right-panel-container', doc);