Further optimize viewport redraw
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 21 Apr 2010 19:39:21 +0000 (13:39 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 21 Apr 2010 19:39:21 +0000 (13:39 -0600)
Try to reuse existing DOM elements, especially for common actions like
delete and scrolling. This avoids the overhead of removing/creating the
DOM element and the corresponding callbacks (making the element
draggable/attaching context menus).

imp/js/DimpBase.js
imp/js/ViewPort.js

index 49369c6..6a894d9 100644 (file)
@@ -520,15 +520,23 @@ var DimpBase = {
         });
 
         /* Custom ViewPort events. */
+        container.observe('ViewPort:add', function(e) {
+            var row = e.memo.identify();
+
+            // Add context menu
+            this._addMouseEvents({ id: row, type: 'message' });
+            new Drag(row, this._msgDragConfig);
+        }.bindAsEventListener(this));
+
         container.observe('ViewPort:cacheUpdate', function(e) {
             delete this.cacheids[e.memo];
         }.bindAsEventListener(this));
 
         container.observe('ViewPort:clear', function(e) {
-            e.memo.each(this._removeMouseEvents.bind(this));
+            this._removeMouseEvents(e.memo);
         }.bindAsEventListener(this));
 
-        container.observe('ViewPort:contentComplete', function(e) {
+        container.observe('ViewPort:contentComplete', function() {
             var flags, ssc, tmp,
                 ham = spam = 'show',
                 l = this.viewport.getMetaData('label');
@@ -544,12 +552,6 @@ var DimpBase = {
                 this.rownum = null;
             }
 
-            e.memo.each(function(row) {
-                // Add context menu
-                this._addMouseEvents({ id: row.VP_domid, type: 'message' });
-                new Drag(row.VP_domid, this._msgDragConfig);
-            }, this);
-
             // 'label' will not be set if there has been an error
             // retrieving data from the server.
             l = this.viewport.getMetaData('label');
index 4e79757..de1809f 100644 (file)
  * Custom events are triggered on the container element. The parameters given
  * below are available through the 'memo' property of the Event object.
  *
+ * ViewPort:add
+ *   Fired when a row has been added to the screen.
+ *   params: (Element) The viewport row being added.
+ *
  * ViewPort:cacheUpdate
  *   Fired when the internal cached data of a view is changed.
  *   params: (string) View which is being updated.
  *
  * ViewPort:clear
  *   Fired when a row is being removed from the screen.
- *   params: (array) The list of viewport rows being removed.
+ *   params: (Element) The viewport row being removed.
  *
  * ViewPort:contentComplete
- *   Fired when a row has been added to the screen.
- *   params: (array) The list of viewport rows that were added.
+ *   Fired when the view has changed and all viewport rows have been added.
+ *   params: NONE
  *
  * ViewPort:deselect
  *   Fired when rows are deselected.
@@ -323,7 +327,7 @@ var ViewPort = Class.create({
         }
 
         if (!init) {
-            this.opts.content.fire('ViewPort:clear', this.visibleRows());
+            this.visibleRows().each(this.opts.content.fire.curry('ViewPort:clear'));
             this.opts.content.update();
             this.scroller.clear();
         }
@@ -435,7 +439,6 @@ var ViewPort = Class.create({
     {
         this._getBuffer(opts.view).setMetaData({ total_rows: this.getMetaData('total_rows', opts.view) - vs.size() }, true);
 
-        this.opts.content.fire('ViewPort:clear', vs.get('div').compact());
         this._getBuffer().remove(vs.get('rownum'));
         this.opts.container.fire('ViewPort:cacheUpdate', opts.view || this.view);
 
@@ -901,12 +904,12 @@ var ViewPort = Class.create({
             return false;
         }
 
-        var c = this.opts.content,
-            c_nodes = [],
+        var added = {},
+            c = this.opts.content,
             page_size = this.getPageSize(),
-            rows;
-
-        this.opts.container.fire('ViewPort:clear', this.visibleRows());
+            tmp = [],
+            vr = this.visibleRows(),
+            fdiv, rows;
 
         this.scroller.setSize(page_size, this.getMetaData('total_rows'));
         this.scrollTo(offset + 1, { noupdate: true, top: true });
@@ -919,15 +922,37 @@ var ViewPort = Class.create({
         rows = this.createSelection('rownum', $A($R(offset + 1, offset + page_size)));
 
         if (rows.size()) {
-            c_nodes = rows.get('dataob');
-            c.update(c_nodes.collect(this.prepareRow.bind(this)).join(''));
+            fdiv = document.createDocumentFragment().appendChild(new Element('DIV'));
+
+            rows.get('dataob').each(function(r) {
+                var elt = $(r.VP_domid);
+                if (elt) {
+                    tmp.push(elt);
+                } else {
+                    fdiv.update(this.prepareRow(r));
+                    added[r.VP_domid] = 1;
+                    tmp.push(fdiv.down());
+                }
+            }, this);
+
+            vr.pluck('id').diff(rows.get('domid')).each($).compact().each(this.opts.content.fire.curry('ViewPort:clear'));
+
+            c.childElements().invoke('remove');
+
+            tmp.each(function(r) {
+                c.insert(r);
+                if (added[r.identify()]) {
+                    this.opts.container.fire('ViewPort:add', r);
+                }
+            }, this);
         } else {
+            vr.each(this.opts.content.fire.curry('ViewPort:clear'));
+            vr.invoke('remove');
             c.update(this.empty_msg);
         }
 
         this.scroller.updateDisplay();
-
-        this.opts.container.fire('ViewPort:contentComplete', c_nodes);
+        this.opts.container.fire('ViewPort:contentComplete');
 
         return true;
     },
@@ -947,11 +972,9 @@ var ViewPort = Class.create({
     {
         var d = $(row.VP_domid);
         if (d) {
-            this.opts.container.fire('ViewPort:clear', [ d ]);
-
+            this.opts.container.fire('ViewPort:clear', d);
             d.replace(this.prepareRow(row));
-
-            this.opts.container.fire('ViewPort:contentComplete', [ row ]);
+            this.opts.container.fire('ViewPort:add', $(row.VP_domid));
         }
     },