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');
 
  58             messageCenter.addMessage('info', 'Wczytuję XML...');
 
  63                     revision: this.get('revision')
 
  65                 success: this.loadingSucceeded.bind(this),
 
  66                 error: this.loadingFailed.bind(this)
 
  73     loadingSucceeded: function(data) {
 
  74         if (this.get('state') != 'loading') {
 
  75             alert('erroneous state:', this.get('state'));
 
  77         this.set('data', data);
 
  78         this.set('state', 'synced');
 
  79         messageCenter.addMessage('success', 'Wczytałem XML :-)');
 
  82     loadingFailed: function() {
 
  83         if (this.get('state') != 'loading') {
 
  84             alert('erroneous state:', this.get('state'));
 
  86         this.set('error', 'Nie udało się załadować panelu');
 
  87         this.set('state', 'error');
 
  88         messageCenter.addMessage('error', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
 
  91     update: function(message) {
 
  92         if (this.get('state') == 'dirty') {
 
  93             this.set('state', 'updating');
 
  94             messageCenter.addMessage('info', 'Zapisuję XML...');
 
  97                 contents: this.get('data'),
 
  98                 revision: this.get('revision')
 
 101                 payload.message = message;
 
 109                 success: this.updatingSucceeded.bind(this),
 
 110                 error: this.updatingFailed.bind(this)
 
 117     updatingSucceeded: function(data) {
 
 118         if (this.get('state') != 'updating') {
 
 119             alert('erroneous state:', this.get('state'));
 
 121         this.set('revision', data.revision);
 
 122         this.set('state', 'updated');
 
 123         messageCenter.addMessage('success', 'Zapisałem XML :-)');
 
 126     updatingFailed: function() {
 
 127         if (this.get('state') != 'updating') {
 
 128             alert('erroneous state:', this.get('state'));
 
 130         messageCenter.addMessage('error', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
 
 131         this.set('state', 'dirty');
 
 135     set: function(property, value) {
 
 136         if (property == 'state') {
 
 137             console.log(this.description(), ':', property, '=', value);
 
 139         return this._super(property, value);
 
 142     dataChanged: function(property, value) {
 
 143         if (this.get('state') == 'synced') {
 
 144             this.set('state', 'dirty');
 
 148     dispose: function() {
 
 149         this.removeObserver(this);
 
 155 Editor.HTMLModel = Editor.Model.extend({
 
 156     _className: 'Editor.HTMLModel',
 
 164     init: function(htmlURL, revision, dataURL) {
 
 166         this.set('state', 'empty');
 
 167         this.set('revision', revision);
 
 168         this.htmlURL = htmlURL;
 
 169         this.dataURL = dataURL;
 
 170         this.renderURL = "http://localhost:8000/api/render";
 
 174     load: function(force) {
 
 175         if (force || this.get('state') == 'empty') {
 
 176             this.set('state', 'loading');
 
 178             // load the transformed data
 
 179             messageCenter.addMessage('info', 'Wczytuję HTML...');
 
 185                     revision: this.get('revision')
 
 187                 success: this.loadingSucceeded.bind(this),
 
 188                 error: this.loadingFailed.bind(this)
 
 193     loadingSucceeded: function(data) {
 
 194         if (this.get('state') != 'loading') {
 
 195             alert('erroneous state:', this.get('state'));
 
 197         this.set('data', data);
 
 198         this.set('state', 'synced');
 
 199         messageCenter.addMessage('success', 'Wczytałem HTML :-)');
 
 202     loadingFailed: function() {
 
 203         if (this.get('state') != 'loading') {
 
 204             alert('erroneous state:', this.get('state'));
 
 206         this.set('error', 'Nie udało się załadować panelu');
 
 207         this.set('state', 'error');
 
 208         messageCenter.addMessage('error', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
 
 211     getXMLPart: function(elem, callback)
 
 213         var path = elem.attr('wl2o:path');
 
 214         if(!this.xmlParts[path])
 
 215             this.loadXMLPart(elem, callback);
 
 217             callback(path, this.xmlParts[path]);
 
 220     loadXMLPart: function(elem, callback)
 
 222         var path = elem.attr('wl2o:path');
 
 227             dataType: 'text; charset=utf-8',
 
 229                 revision: this.get('revision'),
 
 232             success: function(data) {
 
 233                 self.xmlParts[path] = data;
 
 234                 callback(path, data);
 
 236             // TODO: error handling
 
 237             error: function(data) {
 
 238                 console.log('Failed to load fragment');
 
 239                 callback(undefined, undefined);
 
 244     putXMLPart: function(elem, data) {
 
 247         var path = elem.attr('wl2o:path');
 
 248         this.xmlParts[path] = data;
 
 250         this.set('state', 'unsynced');
 
 252         /* re-render the changed fragment */
 
 256             dataType: 'text; charset=utf-8',
 
 261             success: function(htmldata) {
 
 262                 elem.replaceWith(htmldata);
 
 263                 self.set('state', 'dirty');
 
 268     update: function(message) {
 
 269         if (this.get('state') == 'dirty') {
 
 270             this.set('state', 'updating');
 
 273                 chunks: $.toJSON(this.xmlParts),
 
 274                 revision: this.get('revision')
 
 278                 payload.message = message;
 
 288                 success: this.updatingSucceeded.bind(this),
 
 289                 error: this.updatingFailed.bind(this)
 
 297     updatingSucceeded: function(data) {
 
 298         if (this.get('state') != 'updating') {
 
 299             alert('erroneous state:', this.get('state'));
 
 305         this.set('revision', data.revision);
 
 306         this.set('state', 'updated');
 
 309     updatingFailed: function() {
 
 310         if (this.get('state') != 'updating') {
 
 311             alert('erroneous state:', this.get('state'));
 
 313         messageCenter.addMessage('error', 'Uaktualnienie nie powiodło się', 'Uaktualnienie nie powiodło się');
 
 314         this.set('state', 'dirty');
 
 318     set: function(property, value) {
 
 319         if (property == 'state') {
 
 320             console.log(this.description(), ':', property, '=', value);
 
 322         return this._super(property, value);
 
 327 Editor.ImageGalleryModel = Editor.Model.extend({
 
 328     _className: 'Editor.ImageGalleryModel',
 
 333     init: function(serverURL) {
 
 335         this.set('state', 'empty');
 
 336         this.serverURL = serverURL;
 
 341     load: function(force) {
 
 342         if (force || this.get('state') == 'empty') {
 
 343             this.set('state', 'loading');
 
 347                 success: this.loadingSucceeded.bind(this)
 
 352     loadingSucceeded: function(data) {
 
 353         if (this.get('state') != 'loading') {
 
 354             alert('erroneous state:', this.get('state'));
 
 357         console.log('galleries:', data);
 
 359         if (data.length === 0) {
 
 360             this.set('data', []);
 
 363             this.set('data', data[0].pages);
 
 366         this.set('state', 'synced');
 
 369     set: function(property, value) {
 
 370         if (property == 'state') {
 
 371             console.log(this.description(), ':', property, '=', value);
 
 373         return this._super(property, value);
 
 378 Editor.DocumentModel = Editor.Model.extend({
 
 379     _className: 'Editor.DocumentModel',
 
 380     data: null, // name, text_url, user_revision, latest_shared_rev, parts_url, dc_url, size, merge_url
 
 386         this.set('state', 'empty');
 
 391         if (this.get('state') == 'empty') {
 
 392             this.set('state', 'loading');
 
 393             messageCenter.addMessage('info', 'Ładuję dane dokumentu...');
 
 396                 url: documentsUrl + fileId,
 
 398                 success: this.successfulLoad.bind(this)
 
 403     successfulLoad: function(data) {
 
 404         this.set('data', data);
 
 405         this.set('state', 'synced');
 
 406         this.contentModels = {
 
 407             'xml': new Editor.XMLModel(data.text_url, data.user_revision),
 
 408             'html': new Editor.HTMLModel(data.html_url, data.user_revision, data.text_url),
 
 409             'gallery': new Editor.ImageGalleryModel(data.gallery_url)
 
 411         for (var key in this.contentModels) {
 
 412             this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
 
 414         messageCenter.addMessage('success', 'Dane dokumentu zostały załadowane :-)');
 
 417     contentModelStateChanged: function(property, value, contentModel) {
 
 418         if (value == 'dirty') {
 
 419             this.set('state', 'dirty');
 
 420             for (var key in this.contentModels) {
 
 421                 if (this.contentModels[key].guid() != contentModel.guid()) {
 
 422                     this.contentModels[key].set('state', 'unsynced');
 
 425         } else if (value == 'updated') {
 
 426             this.set('state', 'synced');
 
 427             for (key in this.contentModels) {
 
 428                 if (this.contentModels[key].guid() == contentModel.guid()) {
 
 429                     this.contentModels[key].set('state', 'synced');
 
 430                     this.data.user_revision = this.contentModels[key].get('revision');
 
 433             for (key in this.contentModels) {
 
 434                 if (this.contentModels[key].guid() != contentModel.guid()) {
 
 435                     this.contentModels[key].set('revision', this.data.user_revision);
 
 436                     this.contentModels[key].set('state', 'empty');
 
 442     saveDirtyContentModel: function(message) {
 
 443         for (var key in this.contentModels) {
 
 444             if (this.contentModels[key].get('state') == 'dirty') {
 
 445                 this.contentModels[key].update(message);
 
 452         this.set('state', 'loading');
 
 453         messageCenter.addMessage('info', 'Uaktualniam dokument...');
 
 455             url: this.data.merge_url,
 
 460                 target_revision: this.data.user_revision
 
 462             complete: this.updateCompleted.bind(this),
 
 463             success: function(data) {
 
 464                 this.set('updateData', data);
 
 469     updateCompleted: function(xhr, textStatus) {
 
 470         console.log(xhr.status, textStatus);
 
 471         if (xhr.status == 200) { // Sukces
 
 472             this.data.user_revision = this.get('updateData').revision;
 
 473             messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision,
 
 474                 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision);
 
 475             for (var key in this.contentModels) {
 
 476                 this.contentModels[key].set('revision', this.data.user_revision);
 
 477                 this.contentModels[key].set('state', 'empty');
 
 479             messageCenter.addMessage('success', 'Uaktualniłem dokument do najnowszej wersji :-)');
 
 480         } else if (xhr.status == 202) { // Wygenerowano PullRequest (tutaj?)
 
 481         } else if (xhr.status == 204) { // Nic nie zmieniono
 
 482             messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniej aktualizacji. Po co mam uaktualniać?');
 
 483         } else if (xhr.status == 409) { // Konflikt podczas operacji
 
 484             messageCenter.addMessage('error', 'Wystąpił konflikt podczas aktualizacji. Pędź po programistów! :-(');
 
 485         } else if (xhr.status == 500) {
 
 486             messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
 
 488         this.set('state', 'synced');
 
 489         this.set('updateData', null);
 
 492     merge: function(message) {
 
 493         this.set('state', 'loading');
 
 494         messageCenter.addMessage('info', 'Scalam dokument z głównym repozytorium...');
 
 496             url: this.data.merge_url,
 
 501                 target_revision: this.data.user_revision,
 
 504             complete: this.mergeCompleted.bind(this),
 
 505             success: function(data) {
 
 506                 this.set('mergeData', data);
 
 511     mergeCompleted: function(xhr, textStatus) {
 
 512         console.log(xhr.status, textStatus);
 
 513         if (xhr.status == 200) { // Sukces
 
 514             this.data.user_revision = this.get('mergeData').revision;
 
 515             for (var key in this.contentModels) {
 
 516                 this.contentModels[key].set('revision', this.data.user_revision);
 
 517                 this.contentModels[key].set('state', 'empty');
 
 519             messageCenter.addMessage('success', 'Scaliłem dokument z głównym repozytorium :-)');
 
 520         } else if (xhr.status == 202) { // Wygenerowano PullRequest
 
 521             messageCenter.addMessage('success', 'Wysłałem prośbę o scalenie dokumentu z głównym repozytorium.');
 
 522         } else if (xhr.status == 204) { // Nic nie zmieniono
 
 523             messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniego scalenia. Po co mam scalać?');
 
 524         } else if (xhr.status == 409) { // Konflikt podczas operacji
 
 525             messageCenter.addMessage('error', 'Wystąpił konflikt podczas scalania. Pędź po programistów! :-(');
 
 526         } else if (xhr.status == 500) {
 
 527             messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
 
 529         this.set('state', 'synced');
 
 530         this.set('mergeData', null);
 
 534     set: function(property, value) {
 
 535         if (property == 'state') {
 
 536             console.log(this.description(), ':', property, '=', value);
 
 538         return this._super(property, value);
 
 543 var leftPanelView, rightPanelContainer, doc;
 
 547     documentsUrl = $('#api-base-url').text() + '/';
 
 548     toolbarUrl = $('#api-toolbar-url').text();
 
 550     doc = new Editor.DocumentModel();
 
 551     var editor = new EditorView('#body-wrap', doc);
 
 554     var flashView = new FlashView('#flashview', messageCenter);
 
 555     var splitView = new SplitView('#splitview', doc);
 
 557     leftPanelView = new PanelContainerView('#left-panel-container', doc);
 
 558     rightPanelContainer = new PanelContainerView('#right-panel-container', doc);