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);
 
  41 //                  -> error -> loading
 
  43 // empty -> loading -> synced -> unsynced -> loading
 
  45 //                            -> dirty -> updating -> updated -> synced
 
  47 Editor.XMLModel = Editor.Model.extend({
 
  48     _className: 'Editor.XMLModel',
 
  53     init: function(document, serverURL) {
 
  55         this.set('state', 'empty');
 
  56         this.set('revision', document.get('revision'));
 
  57         this.document = document;
 
  58         this.serverURL = serverURL;
 
  59         this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
 
  60         this.addObserver(this, 'data', this.dataChanged.bind(this));
 
  63     load: function(force) {
 
  64         if (force || this.get('state') == 'empty') {
 
  65             this.set('state', 'loading');
 
  66             messageCenter.addMessage('info', 'xmlload', 'Wczytuję XML...');
 
  71                     revision: this.get('revision'),
 
  72                     user: this.document.get('user')
 
  74                 success: this.loadingSucceeded.bind(this),
 
  75                 error: this.loadingFailed.bind(this)
 
  82     loadingSucceeded: function(data) {
 
  83         if (this.get('state') != 'loading') {
 
  84             alert('erroneous state:', this.get('state'));
 
  86         this.set('data', data);
 
  87         this.set('state', 'synced');
 
  88         messageCenter.addMessage('success', 'xmlload', 'Wczytałem XML :-)');
 
  91     loadingFailed: function(response)
 
  93         if (this.get('state') != 'loading') {
 
  94             alert('erroneous state:', this.get('state'));
 
  97         var message = parseXHRError(response);
 
  99         this.set('error', '<h2>Błąd przy ładowaniu XML</h2><p>'+message+'</p>');
 
 100         this.set('state', 'error');
 
 101         messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
 
 104     save: function(message) {
 
 105         if (this.get('state') == 'dirty') {
 
 106             this.set('state', 'updating');
 
 107             messageCenter.addMessage('info', 'xmlsave', 'Zapisuję XML...');
 
 110                 contents: this.get('data'),
 
 111                 revision: this.get('revision'),
 
 112                 user: this.document.get('user')
 
 115                 payload.message = message;
 
 123                 success: this.saveSucceeded.bind(this),
 
 124                 error: this.saveFailed.bind(this)
 
 131     saveSucceeded: function(data) {
 
 132         if (this.get('state') != 'updating') {
 
 133             alert('erroneous state:', this.get('state'));
 
 135         this.set('revision', data.revision);
 
 136         this.set('state', 'updated');
 
 137         messageCenter.addMessage('success', 'xmlsave', 'Zapisałem XML :-)');
 
 140     saveFailed: function() {
 
 141         if (this.get('state') != 'updating') {
 
 142             alert('erroneous state:', this.get('state'));
 
 144         messageCenter.addMessage('error', 'xmlsave', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
 
 145         this.set('state', 'dirty');
 
 149     set: function(property, value) {
 
 150         if (property == 'state') {
 
 151             console.log(this.description(), ':', property, '=', value);
 
 153         return this._super(property, value);
 
 156     dataChanged: function(property, value) {
 
 157         if (this.get('state') == 'synced') {
 
 158             this.set('state', 'dirty');
 
 162     dispose: function() {
 
 163         this.removeObserver(this);
 
 169 Editor.HTMLModel = Editor.Model.extend({
 
 170     _className: 'Editor.HTMLModel',
 
 178     init: function(document, dataURL, htmlURL) {
 
 180         this.set('state', 'empty');
 
 181         this.set('revision', document.get('revision'));        
 
 183         this.document = document;
 
 184         this.htmlURL = htmlURL;
 
 185         this.dataURL = dataURL;
 
 186         this.renderURL = documentInfo.renderURL;
 
 190     load: function(force) {
 
 191         if (force || this.get('state') == 'empty') {
 
 192             this.set('state', 'loading');
 
 194             // load the transformed data
 
 195             // messageCenter.addMessage('info', 'Wczytuję HTML...');
 
 201                     revision: this.get('revision'),
 
 202                     user: this.document.get('user')
 
 204                 success: this.loadingSucceeded.bind(this),
 
 205                 error: this.loadingFailed.bind(this)
 
 210     loadingSucceeded: function(data) {
 
 211         if (this.get('state') != 'loading') {
 
 212             alert('erroneous state:', this.get('state'));
 
 214         this.set('data', data);
 
 215         this.set('state', 'synced');
 
 218     loadingFailed: function(response) {
 
 219         if (this.get('state') != 'loading') {
 
 220             alert('erroneous state:', this.get('state'));
 
 223         var err = parseXHRError(response);
 
 225         this.set('error', '<p>Nie udało się wczytać widoku HTML: </p>' + err.error_message);
 
 226         this.set('state', 'error');        
 
 229     getXMLPart: function(elem, callback)
 
 231         var path = elem.attr('x-pointer');
 
 232         if(!this.xmlParts[path])
 
 233             this.loadXMLPart(elem, callback);
 
 235             callback(path, this.xmlParts[path]);
 
 238     loadXMLPart: function(elem, callback)
 
 240         var path = elem.attr('x-pointer');
 
 247                 revision: this.get('revision'),
 
 248                 user: this.document.get('user'),
 
 252             success: function(data) {
 
 253                 self.xmlParts[path] = data;
 
 255                 callback(path, data);
 
 257             // TODO: error handling
 
 258             error: function(data) {
 
 259                 console.log('Failed to load fragment');
 
 260                 callback(undefined, undefined);
 
 265     putXMLPart: function(elem, data, callback) {
 
 268         var path = elem.attr('x-pointer');
 
 269         this.xmlParts[path] = data;
 
 271         this.set('state', 'dirty');
 
 273         /* re-render the changed fragment */
 
 277             dataType: 'text; charset=utf-8',
 
 283             success: function(htmldata) {
 
 284                 callback(elem, htmldata);
 
 285                 self.set('state', 'dirty');
 
 290     save: function(message) {
 
 291         if (this.get('state') == 'dirty') {
 
 292             this.set('state', 'updating');
 
 295                 chunks: $.toJSON(this.xmlParts),
 
 296                 revision: this.get('revision'),
 
 297                 user: this.document.get('user')
 
 301                 payload.message = message;
 
 311                 success: this.saveSucceeded.bind(this),
 
 312                 error: this.saveFailed.bind(this)
 
 320     saveSucceeded: function(data) {
 
 321         if (this.get('state') != 'updating') {
 
 322             alert('erroneous state:', this.get('state'));
 
 328         this.set('revision', data.revision);
 
 329         this.set('state', 'updated');
 
 332     saveFailed: function() {
 
 333         if (this.get('state') != 'updating') {
 
 334             alert('erroneous state:', this.get('state'));
 
 336         this.set('state', 'dirty');
 
 340     set: function(property, value) {
 
 341         if (property == 'state') {
 
 342             console.log(this.description(), ':', property, '=', value);
 
 344         return this._super(property, value);
 
 349 Editor.ImageGalleryModel = Editor.Model.extend({
 
 350     _className: 'Editor.ImageGalleryModel',
 
 355     init: function(document, serverURL) {
 
 357         this.set('state', 'empty');
 
 358         this.serverURL = serverURL;
 
 363     load: function(force) {
 
 364         if (force || this.get('state') == 'empty') {
 
 365             console.log("setting state");
 
 366             this.set('state', 'loading');
 
 367             console.log("going ajax");
 
 371                 success: this.loadingSucceeded.bind(this),
 
 372                 error: this.loadingFailed.bind(this)
 
 377     loadingSucceeded: function(data) 
 
 379         console.log("success");        
 
 381         if (this.get('state') != 'loading') {
 
 382             alert('erroneous state:', this.get('state'));
 
 385         console.log('galleries:', data);
 
 387         if (data.length === 0) {
 
 388             this.set('data', []);
 
 390             this.set('data', data[0].pages);
 
 393         this.set('state', 'synced');
 
 396     loadingFailed: function(data) {
 
 397         console.log("failed");
 
 399         if (this.get('state') != 'loading') {
 
 400             alert('erroneous state:', this.get('state'));
 
 403         this.set('state', 'error');
 
 406     set: function(property, value) {
 
 407         if (property == 'state') {
 
 408             console.log(this.description(), ':', property, '=', value);
 
 410         return this._super(property, value);
 
 415 Editor.DocumentModel = Editor.Model.extend({
 
 416     _className: 'Editor.DocumentModel',
 
 417     data: null, // name, text_url, revision, latest_shared_rev, parts_url, dc_url, size, merge_url
 
 426         this.set('state', 'empty');        
 
 430         if (this.get('state') == 'empty') {
 
 431             this.set('state', 'loading');
 
 432             messageCenter.addMessage('info', 'docload', 'Ładuję dane dokumentu...');
 
 435                 url: documentInfo.docURL,
 
 437                 success: this.successfulLoad.bind(this),
 
 438                 error: this.failedLoad.bind(this)
 
 443     successfulLoad: function(data) {
 
 444         this.set('data', data);
 
 445         this.set('state', 'synced');
 
 447         this.set('revision', data.revision);
 
 448         this.set('user', data.user);
 
 450         this.contentModels = {
 
 451             'xml': new Editor.XMLModel(this, data.text_url),
 
 452             'html': new Editor.HTMLModel(this, data.text_url, data.html_url),
 
 453             'gallery': new Editor.ImageGalleryModel(this, data.gallery_url)
 
 456         for (var key in this.contentModels) {
 
 457             this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
 
 462         messageCenter.addMessage('success', 'docload', 'Dokument załadowany poprawnie :-)');
 
 465     failedLoad: function(response) {
 
 466         if (this.get('state') != 'loading') {
 
 467             alert('erroneous state:', this.get('state'));
 
 470         var err = parseXHRError(response);
 
 471         this.set('error', '<h2>Nie udało się wczytać dokumentu</h2><p>'+err.error_message+"</p>");
 
 472         this.set('state', 'error');
 
 475     contentModelStateChanged: function(property, value, contentModel) {
 
 476         if (value == 'dirty') {
 
 477             this.set('state', 'dirty');
 
 478             for (var key in this.contentModels) {
 
 479                 if (this.contentModels[key].guid() != contentModel.guid()) {
 
 480                     this.contentModels[key].set('state', 'unsynced');
 
 483         } else if (value == 'updated') {
 
 484             this.set('state', 'synced');
 
 485             for (key in this.contentModels) {
 
 486                 if (this.contentModels[key].guid() == contentModel.guid()) {
 
 487                     this.contentModels[key].set('state', 'synced');
 
 488                     this.revision = this.contentModels[key].get('revision');
 
 492             for (key in this.contentModels) {
 
 493                 if (this.contentModels[key].guid() != contentModel.guid()) {
 
 494                     this.contentModels[key].set('revision', this.revision);
 
 495                     this.contentModels[key].set('state', 'empty');
 
 501     saveDirtyContentModel: function(message) {
 
 502         for (var key in this.contentModels) {
 
 503             if (this.contentModels[key].get('state') == 'dirty') {
 
 504                 this.contentModels[key].save(message);
 
 511         this.set('state', 'loading');
 
 513         messageCenter.addMessage('info', 'doc_update',
 
 514             'Uaktualniam dokument...');
 
 517             url: this.data.merge_url,
 
 522                 revision: this.get('revision'),
 
 523                 user: this.get('user')
 
 525             complete: this.updateCompleted.bind(this)           
 
 529     updateCompleted: function(xhr, textStatus)
 
 531         console.log(xhr.status, xhr.responseText);
 
 532         var response = parseXHRResponse(xhr);
 
 535             if( (response.data.result == 'no-op')
 
 536              || (response.data.timestamp == response.data.parent_timestamp))
 
 538                 if( (response.data.revision) && (response.data.revision != this.get('revision')) )
 
 541                     this.set('state', 'unsynced');
 
 545                 messageCenter.addMessage('info', 'doc_update',
 
 546                     'Już posiadasz najbardziej aktualną wersję.');
 
 547                     this.set('state', 'synced');
 
 552             this.set('revision', response.data.revision);
 
 553             this.set('user', response.data.user);
 
 555             messageCenter.addMessage('info', 'doc_update',
 
 556                 'Uaktualnienie dokumentu do wersji ' + response.data.revision);
 
 558             for (var key in this.contentModels) {
 
 559                 this.contentModels[key].set('revision', this.get('revision') );
 
 560                 this.contentModels[key].set('state', 'empty');
 
 563             this.set('state', 'synced');
 
 567         // no success means trouble
 
 568         messageCenter.addMessage(response.error_level, 'doc_update', 
 
 569             response.error_message);       
 
 571         this.set('state', 'unsynced');
 
 574     merge: function(message) {
 
 575         this.set('state', 'loading');
 
 576         messageCenter.addMessage('info', 'doc_merge',
 
 577             'Scalam dokument z głównym repozytorium...');
 
 580             url: this.data.merge_url,
 
 585                 revision: this.get('revision'),
 
 586                 user: this.get('user'),
 
 589             complete: this.mergeCompleted.bind(this),
 
 590             success: function(data) {
 
 591                 this.set('mergeData', data);
 
 596     mergeCompleted: function(xhr, textStatus) {
 
 597         console.log(xhr.status, xhr.responseText);
 
 598         var response = parseXHRResponse(xhr);
 
 600         if(response.success) {
 
 602             if( (response.data.result == 'no-op') ||             
 
 603              ( response.data.shared_parent_timestamp
 
 604                && response.data.shared_timestamp
 
 605                && (response.data.shared_timestamp == response.data.shared_parent_timestamp)) )
 
 607                 if( (response.data.revision) && (response.data.revision != this.get('revision')) )
 
 610                     this.set('state', 'unsynced');
 
 614                 messageCenter.addMessage('info', 'doc_merge',
 
 615                     'Twoja aktualna wersja nie różni się od ostatnio zatwierdzonej.');
 
 616                 this.set('state', 'synced');
 
 620             if( response.data.result == 'accepted')
 
 622                 messageCenter.addMessage('info', 'doc_merge',
 
 623                     'Prośba o zatwierdzenie została przyjęta i oczekuję na przyjęcie.');
 
 624                 this.set('state', 'synced');
 
 629             this.set('revision', response.data.revision);
 
 630             this.set('user', response.data.user);
 
 632             messageCenter.addMessage('info', 'doc_merge',
 
 633                 'Twoja wersja dokumentu została zatwierdzona.');
 
 635             this.set('state', 'synced');
 
 639         // no success means trouble
 
 640         messageCenter.addMessage(response.error_level, 'doc_merge',
 
 641             response.error_message);
 
 643         this.set('state', 'unsynced');
 
 647     set: function(property, value) {
 
 648         if (property == 'state') {
 
 649             console.log(this.description(), ':', property, '=', value);
 
 651         return this._super(property, value);
 
 656 var leftPanelView, rightPanelContainer, doc;
 
 660     var flashView = new FlashView('#flashview', messageCenter);
 
 662     doc = new Editor.DocumentModel();
 
 664     EditorView = new EditorView('#body-wrap', doc);
 
 665     EditorView.freeze("<h1>Wczytuję dokument...</h1>");
 
 667     leftPanelView = new PanelContainerView('#left-panel-container', doc);
 
 668     rightPanelContainer = new PanelContainerView('#right-panel-container', doc);