Dodanie KVC/KVO. Przeniesienie modeli do models.js.
authorzuber <marek@stepniowski.com>
Sat, 26 Sep 2009 21:50:55 +0000 (23:50 +0200)
committerzuber <marek@stepniowski.com>
Sat, 26 Sep 2009 21:50:55 +0000 (23:50 +0200)
project/static/js/app.js
project/static/js/models.js [new file with mode: 0644]
project/static/js/views/html.js
project/static/js/views/view.js
project/static/js/views/xml.js
project/templates/explorer/editor.html

index 6e6f0f8..7bf026b 100644 (file)
@@ -70,6 +70,7 @@ var panel_hooks;
   };
 })();
 
+
 (function() {
   var slice = Array.prototype.slice;
   
@@ -97,189 +98,66 @@ var panel_hooks;
   }
   
 })();
-var panels = [];
 
-var documentsUrl = '/api/documents/';
 
+var Editor = Editor || {};
 
-var Model = Class.extend({
-  observers: {},
-  
-  init: function() {},
-  
-  signal: function(event, data) {
-    console.log('signal', this, event, data);
-    if (this.observers[event]) {
-      for (key in this.observers[event]) {
-        this.observers[event][key](event, data);
-      }
-    };
-    return this;
-  },
+// Obiekt implementujący wzorzec KVC/KVO
+Editor.Object = Class.extend({
+  _observers: {},
   
-  addObserver: function(observer, event, callback) {
-    if (!this.observers[event]) {
-      this.observers[event] = {};
+  addObserver: function(observer, property, callback) {
+    if (!this._observers[property]) {
+      this._observers[property] = {}
     }
-    this.observers[event][observer.id] = callback;
+    this._observers[property][this.guid()] = callback;
     return this;
   },
   
-  removeObserver: function(observer, event) {
-    if (!event) {
-      for (e in this.observers) {
-        this.removeObserver(observer, e);
+  removeObserver: function(observer, property) {
+    if (!property) {
+      for (var property in this._observers) {
+        this.removeObserver(observer, property)
       }
     } else {
-      delete this.observers[event][observer.id];
+      delete this._observers[property][observer.guid()];
     }
     return this;
-  }
-});
-
-
-var XMLModel = Model.extend({
-  parent: null,
-  data: '',
-  serverURL: null,
-  needsReload: false,
-  
-  init: function(parent, serverURL) {
-    this.parent = parent;
-    this.serverURL = serverURL;
-  },
-  
-  getData: function() {
-    if (!this.data) {
-      this.reload();
-    }
-    return this.data;
-  },
-  
-  setData: function(data) {
-    this.data = data;
-    this.dataChanged();
-  },
-  
-  reload: function() {
-    $.ajax({
-      url: this.serverURL,
-      dataType: 'text',
-      success: this.reloadSucceeded.bind(this)
-    });
-  },
-  
-  reloadSucceeded: function(data) {
-    this.data = data;
-    this.signal('reloaded');
-  },
-  
-  dataChanged: function() {
-    this.parent.modelChanged('xml');
-    this.signal('dataChanged');
-  },
-  
-  needsReload: function() {
-    this.needsReload = true;
-    this.signal('needsReload');
-  }
-})
-
-
-
-var HTMLModel = Model.extend({
-  parent: null,
-  data: '',
-  serverURL: null,
-  needsReload: false,
-  
-  init: function(parent, serverURL) {
-    this.parent = parent;
-    this.serverURL = serverURL;
   },
   
-  getData: function() {
-    if (!this.data) {
-      this.reload();
+  notifyObservers: function(property) {
+    var currentValue = this[property];
+    for (var guid in this._observers[property]) {
+      this._observers[property][guid](property, currentValue);
     }
-    return this.data;
+    return this;
   },
   
-  setData: function(data) {
-    console.log('setData');
-    if (this.data != data) {
-      this.data = data;
-      this.dataChanged();
+  guid: function() {
+    if (!this._guid) {
+      this._guid = ('editor-' + Editor.Object._lastGuid++);
     }
+    return this._guid;
   },
   
-  reload: function() {
-    $.ajax({
-      url: this.serverURL,
-      dataType: 'text',
-      success: this.reloadSucceeded.bind(this)
-    });
+  get: function(property) {
+    return this[property];
   },
   
-  reloadSucceeded: function(data) {
-    this.data = data;
-    this.signal('reloaded');
-  },
-  
-  dataChanged: function() {
-    this.parent.modelChanged('html');
-  },
-  
-  needsReload: function() {
-    this.needsReload = true;
-    this.signal('needsReload');
-  }
-})
-
-
-var DocumentModel = Model.extend({
-  data: null, // name, text_url, latest_rev, latest_shared_rev, parts_url, dc_url, size
-  xml: null,
-  html: null,
-  contentModels: {},
-  
-  init: function() {
-    this.getData();
-  },
-  
-  getData: function() {
-    console.log('DocumentModel#getData');
-    $.ajax({
-      cache: false,
-      url: documentsUrl + fileId,
-      dataType: 'json',
-      success: this.successfulGetData.bind(this)
-    });
-  },
-  
-  successfulGetData: function(data) {
-    console.log('DocumentModel#successfulGetData:', data);
-    this.data = data;
-    this.contentModels = {
-      'xml': new XMLModel(this, data.text_url)
-    };
+  set: function(property, value) {
+    if (this[property] != value) {
+      this[property] = value;
+      this.notifyObservers(property);
+    }
+    return this;
   },
   
-  modelChanged: function(contentModelName) {
-    for (modelName in this.contentModels) {
-      if (!(modelName == contentModelName)) {
-        this.contentModels[modelName].needsReload();
-      }
-    }
+  dispose: function() {
+    delete this._observers;
   }
 });
 
-var leftPanelView, rightPanelContainer, doc;
+Editor.Object._lastGuid = 0;
 
-$(function() {
-  doc = new DocumentModel();
-  var splitView = new SplitView('#splitview', doc);
-  leftPanelView = new PanelContainerView('#left-panel-container', doc);
-  rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
-});
+
+var panels = [];
diff --git a/project/static/js/models.js b/project/static/js/models.js
new file mode 100644 (file)
index 0000000..9ccefca
--- /dev/null
@@ -0,0 +1,107 @@
+/*globals Editor fileId SplitView PanelContainerView*/
+var documentsUrl = '/api/documents/';
+
+
+Editor.Model = Editor.Object.extend({
+  synced: false,
+  data: null
+});
+
+
+Editor.XMLModel = Editor.Model.extend({
+  serverURL: null,
+  
+  init: function(serverURL) {
+    this.serverURL = serverURL;
+  },
+  
+  getData: function() {
+    if (!this.data) {
+      this.reload();
+    }
+    return this.data;
+  },
+  
+  setData: function(data) {
+    this.data = data;
+    this.dataChanged();
+  },
+  
+  load: function() {
+    if (!this.get('synced')) {
+      $.ajax({
+        url: this.serverURL,
+        dataType: 'text',
+        success: this.reloadSucceeded.bind(this)
+      });
+    }
+  },
+  
+  reloadSucceeded: function(data) {
+    this.set('data', data);
+    this.set('synced', true);
+  }
+});
+
+
+Editor.HTMLModel = Editor.Model.extend({
+  serverURL: null,
+  
+  init: function(serverURL) {
+    this.serverURL = serverURL;
+  },
+  
+  load: function() {
+    if (!this.get('synced')) {
+      $.ajax({
+        url: this.serverURL,
+        dataType: 'text',
+        success: this.reloadSucceeded.bind(this)
+      });
+    }
+  },
+  
+  reloadSucceeded: function(data) {
+    this.set('data', data);
+    this.set('synced', true);
+  }
+});
+
+
+Editor.DocumentModel = Editor.Model.extend({
+  data: null, // name, text_url, latest_rev, latest_shared_rev, parts_url, dc_url, size
+  contentModels: {},
+  
+  init: function() {
+    this.load();
+  },
+  
+  load: function() {
+    console.log('DocumentModel#load');
+    $.ajax({
+      cache: false,
+      url: documentsUrl + fileId,
+      dataType: 'json',
+      success: this.successfulLoad.bind(this)
+    });
+  },
+  
+  successfulLoad: function(data) {
+    console.log('DocumentModel#successfulLoad:', data);
+    this.set('data', data);
+    this.contentModels = {
+      'xml': new Editor.XMLModel(data.text_url),
+      'html': new Editor.HTMLModel(data.html_url)
+    };
+  }
+});
+
+
+var leftPanelView, rightPanelContainer, doc;
+
+$(function() {
+  doc = new Editor.DocumentModel();
+  var splitView = new SplitView('#splitview', doc);
+  leftPanelView = new PanelContainerView('#left-panel-container', doc);
+  rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
+});
index 87f2ab7..59579af 100644 (file)
@@ -6,9 +6,33 @@ var HTMLView = View.extend({
   
   init: function(element, model, template) {
     this._super(element, model, template);
+    
+    this.model
+      .addObserver(this, 'data', this.modelDataChanged.bind(this))
+      .addObserver(this, 'synced', this.modelSyncChanged.bind(this));
+      
+    if (!this.model.get('synced')) {
+      this.freeze('Niezsynchronizowany...');
+      this.model.load();
+    } else {
+      $('.htmlview', this.element).html(this.model.get('data'));
+    }
+  },
+  
+  modelDataChanged: function(property, value) {
+    $('.htmlview', this.element).html(value);
+  },
+  
+  modelSyncChanged: function(property, value) {
+    if (value) {
+      this.unfreeze();
+    } else {
+      this.freeze('Niezsynchronizowany...');
+    }
   },
   
   dispose: function() {
+    this.model.removeObserver(this);
     this._super();
   }
 });
index 498341e..59b339f 100644 (file)
@@ -1,5 +1,5 @@
-/*globals Class render_template*/
-var View = Class.extend({
+/*globals Editor render_template*/
+var View = Editor.Object.extend({
   element: null,
   model: null,
   template: null,
@@ -13,7 +13,7 @@ var View = Class.extend({
     this.template = template || this.template;
     
     if (this.template) {
-      this.element.html(render_template(this.template, {}));
+      this.element.html(render_template(this.template, this));
     }
     
     View.lastId = View.lastId + 1;
index 54abf16..9df8954 100644 (file)
@@ -4,6 +4,7 @@ var XMLView = View.extend({
   model: null,
   template: 'xml-view-template',
   editor: null,
+  buttonToolbar: null,
   
   init: function(element, model, template) {
     this._super(element, model, template);
@@ -17,40 +18,50 @@ var XMLView = View.extend({
       textWrapping: false,
       tabMode: 'spaces',
       indentUnit: 0,
-      onChange: this.changed.bind(this),
+      onChange: this.editorDataChanged.bind(this),
       initCallback: this.editorDidLoad.bind(this)
     });
   },
   
-  changed: function() {
-    this.model.setData(this.editor.getCode());
-  },
-  
   editorDidLoad: function(editor) {
-    editor.setCode('Ładowanie edytora...');
     $(editor.frame).css({width: '100%', height: '100%'});
-    this.editor.setCode(this.model.getData());
-    this.unfreeze();
+    
     this.model
-      .addObserver(this, 'reloaded', function() {
-        this.editor.setCode(this.model.getData()); this.unfreeze(); }.bind(this))
-      .addObserver(this, 'needsReload', function() { 
-        this.freeze('Niezsynchronizowany'); }.bind(this))
-      .addObserver(this, 'dataChanged', this.textDidChange.bind(this));
-
+      .addObserver(this, 'data', this.modelDataChanged.bind(this))
+      .addObserver(this, 'synced', this.modelSyncChanged.bind(this));
+    
+    if (!this.model.get('synced')) {
+      this.freeze('Niezsynchronizowany...');
+      this.model.load();
+    } else {
+      this.editor.setCode(this.model.get('data'));
+    }
+    this.unfreeze();
+  
     // editor.grabKeys(
     //   $.fbind(self, self.hotkeyPressed),
     //   $.fbind(self, self.isHotkey)
     // );
   },
   
-  textDidChange: function(event) {
-    console.log('textDidChange!');
-    if (this.editor.getCode() != this.model.getData()) {
-      this.editor.setCode(this.model.getData());
+  editorDataChanged: function() {
+    this.model.set('data', this.editor.getCode());
+  },
+  
+  modelDataChanged: function(property, value) {
+    if (this.editor.getCode() != value) {
+      this.editor.setCode(value);
     }
   },
   
+  modelSyncChanged: function(property, value) {
+    if (value) {
+      this.unfreeze();
+    } else {
+      this.freeze('Niezsynchronizowany...');
+    }
+  },
+    
   dispose: function() {
     this.model.removeObserver(this);
     $(this.editor.frame).remove();
index f7e827f..27f7e59 100644 (file)
@@ -4,14 +4,7 @@
        <script type="text/javascript" charset="utf-8">
                var fileId = '{{ fileid }}';
        </script>
-    <link rel="stylesheet" href="{{STATIC_URL}}css/toolbar.css" type="text/css" />
-    <link rel="stylesheet" href="{{STATIC_URL}}css/jquery.modal.css" type="text/css" />
-    <script src="{{STATIC_URL}}js/lib/jquery.lazyload.js" type="text/javascript" charset="utf-8"></script>
     <script src="{{STATIC_URL}}js/lib/codemirror/codemirror.js" type="text/javascript" charset="utf-8"></script>
-    <script src="{{STATIC_URL}}js/lib/jquery.wtooltip.js" type="text/javascript" charset="utf-8"></script>
-    <script src="{{STATIC_URL}}js/lib/jquery.json.js" type="text/javascript" charset="utf-8"></script>
-    <script src="{{STATIC_URL}}js/lib/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
-    <script src="{{STATIC_URL}}js/lib/jquery.modal.js" type="text/javascript" charset="utf-8"></script>
        
        {# App and views #}
        <script src="{{STATIC_URL}}js/app.js" type="text/javascript" charset="utf-8"></script>
@@ -21,9 +14,8 @@
        <script src="{{STATIC_URL}}js/views/html.js" type="text/javascript" charset="utf-8"></script>
        <script src="{{STATIC_URL}}js/views/panel_container.js" type="text/javascript" charset="utf-8"></script>
        
-    <script src="{{STATIC_URL}}js/editor.js" type="text/javascript" charset="utf-8"></script>
-    <script src="{{STATIC_URL}}js/editor.ui.js" type="text/javascript" charset="utf-8"></script>
-
+       <script src="{{STATIC_URL}}js/models.js" type="text/javascript" charset="utf-8"></script>
+       
        {# JavaScript templates #}
        <script type="text/html" charset="utf-8" id="panel-container-view-template">
                <select>
@@ -40,7 +32,8 @@
        </script>
        
        <script type="text/html" charset="utf-8" id="html-view-template">
-               <p>Hej! Jestem widokiem HTML!</p>
+               <div class="htmlview">
+               </div>
        </script>
 {% endblock extrahead %}
 
     </div>
 
 
-    <div id="commit-dialog" class="jqmWindow">
-        <form action="{% url file_commit fileid %}" method="POST">
-            <label for="message">Commit message:</label>
-            <textarea cols="60" rows="10" name="message" id="commit-dialog-message"></textarea>
-            <p id="commit-dialog-error-empty-message">Wiadomość nie może być pusta.</p>                
-            <fieldset id="commit-dialog-related-issues" 
-                      ui:ajax-src="http://localhost:3000/publications/issues/{{fileid}}">
-                <legend>Related issues</legend>
-                <div class="loading-box" style="display: none;">
-                    <p>Loading related issues...</p>
-                </div>
-                <div class="container-box">No related issues.</div>
-            </fieldset>
-            <p>
-               <input type="button" value="Save" id="commit-dialog-save-button" />
-               <input type="reset" value="Cancel" id="commit-dialog-cancel-button" />
-            </p>
-        </form>
-    </div>
-
-    <div id="split-dialog" class="jqmWindow">
-        <div class="container-box"> </div>
-        <div class="loading-box" style="display: none;">
-            <p>Loading dialog contents...</p>
-            <!-- <p><button type="button" class="dialog-close-button">Close</button></p> -->
-        </div>
-        <div class="fatal-error-box" style="display: none;">
-            <p>Server error, while loading dialog :(</p>
-            <p><button type="button" class="dialog-close-button">Close</button></p>
-        </div>
-    </div>
+    {# <div id="commit-dialog" class="jqmWindow"> #}
+    {#     <form action="{% url file_commit fileid %}" method="POST"> #}
+    {#         <label for="message">Commit message:</label> #}
+    {#         <textarea cols="60" rows="10" name="message" id="commit-dialog-message"></textarea> #}
+    {#         <p id="commit-dialog-error-empty-message">Wiadomość nie może być pusta.</p>                 #}
+    {#         <fieldset id="commit-dialog-related-issues"  #}
+    {#                   ui:ajax-src="http://localhost:3000/publications/issues/{{fileid}}"> #}
+    {#             <legend>Related issues</legend> #}
+    {#             <div class="loading-box" style="display: none;"> #}
+    {#                 <p>Loading related issues...</p> #}
+    {#             </div> #}
+    {#             <div class="container-box">No related issues.</div> #}
+    {#         </fieldset> #}
+    {#         <p> #}
+    {#            <input type="button" value="Save" id="commit-dialog-save-button" /> #}
+    {#            <input type="reset" value="Cancel" id="commit-dialog-cancel-button" /> #}
+    {#         </p> #}
+    {#     </form> #}
+    {# </div> #}
+    {#  #}
+    {# <div id="split-dialog" class="jqmWindow"> #}
+    {#     <div class="container-box"> </div> #}
+    {#     <div class="loading-box" style="display: none;"> #}
+    {#         <p>Loading dialog contents...</p> #}
+    {#         <!-- <p><button type="button" class="dialog-close-button">Close</button></p> --> #}
+    {#     </div> #}
+    {#     <div class="fatal-error-box" style="display: none;"> #}
+    {#         <p>Server error, while loading dialog :(</p> #}
+    {#         <p><button type="button" class="dialog-close-button">Close</button></p> #}
+    {#     </div> #}
+    {# </div> #}
 {% endblock maincontent %}