1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2 <html>
3    <head>
4       <title>Scroll Bar</title>
5       <link rel="stylesheet" href="scrollbar.css" type="text/css" />
6       <script type="text/javascript" src="scrollbar.js"></script>
7  
8       <!-- Load the generated client side code... -->
9       <script type=’text/javascript’ src=’server.php?client’></script>
10       <script type=’text/javascript’ src=’objectPool.js’></script>
11       <script type='text/javascript'>
12          var remote = new nail_remote();
13          remote.Sync();
14          // our get data function to call in onScroll methods
15          function getDataSync(start,rows) {
16             ret = remote.data(start,rows);
17             document.getElementById(‘trace').innerHTML += "<li>Sync Fetch Rows: " +start + " - "+rows+”</li>”;
18             return ret;
19          }
20  
21          function getNumRowsSync() {
22          ret = remote.num_rows();
23          return ret;
24          }
25  
26          // our get data function to call in onScroll Up methods
27          function getData(start,rows) {
28             var r = remotePool.getObject();
29  
30             document.getElementById(‘trace').innerHTML += "<li>Async Call data("+start+”,”+rows+”)</li>”;
31             r.data(start,rows);
32          }
33  
34          // callback class
35          function NailCallback() {}
36          NailCallback.prototype.data = function(result) {
37             var start = false;
38             var rows = 0;
39             for(var key in result) {
40                if (!start) {
41                   start = key;
42                }
43                if (!tableData[key]) {
44                   tableData[key] = result[key];
45                   rows++;
46                }
47             }
48             document.getElementById(‘trace').innerHTML += "<li>ASync Fetch Rows: " +start + " - "+rows+”</li>”;
49             remotePool.returnObject(this.parent.poolId);
50          }
51  
52          // jpspan remote proxy class pool
53          var remotePool = new objectPool();
54          remotePool.createObject = function() {
55             var callback = new NailCallback();
56             var remote = new nail_remote(callback);
57             callback.parent = remote;
58             return remote;
59          }
60  
61          var lastPrefetch = false;
62  
63          // decide if we should try to prefetch some data
64          function prefetchDownAsNeeded(currentIndex) {
65             var testUntil = currentIndex + 5;
66  
67             var startPrefetch = false;
68             for(var i = currentIndex; i < testUntil; i++) {
69                if (!tableData[i]) {
70                   startPrefetch = i;
71                   break;
72                }
73             }
74  
75             if (startPrefetch && startPrefetch != lastPrefetch) {
76                lastPrefetch = startPrefetch;
77                getData(startPrefetch,10);
78             }
79          }
80  
81          function prefetchUpAsNeeded(currentIndex) {
82             var testUntil = currentIndex - 5;
83  
84             var startPrefetch = false;
85             for(var i = currentIndex; i > testUntil; i--) {
86                if (!tableData[i]) {
87                   startPrefetch = i-10;
88                   break;
89                }
90             }
91  
92             if (startPrefetch < 0) {
93                startPrefetch = 0;
94             }
95  
96             if (startPrefetch && startPrefetch != lastPrefetch) {
97                lastPrefetch = startPrefetch;
98                getData(startPrefetch,10);
99             }
100       }
101    </script>
102 </head>
103 <body>
104    </script>
105 </head>
106 <body>
107    <table cellpadding=0 cellspacing=0 border=0>
108          <tr>
109          <td>
110  
111       <table border="1">
112          <tr>
113             <th>Nail Id</th>
114             <th>Length</th>
115             <th>Diameter</th>
116          </tr>
117          <tbody id="table">
118          </tbody>
119       </table>
120          </td>
121          <td>
122             <div class="scrollBar" id="bar"></div>
123          </td>
124       </tr>
125    </table>
126    <ol id="trace">
127    </ol>
128    <script type="text/javascript">
129    <?php
130    // allow the table to start at other places then the beginning
131    if (isset($_GET['start'])) {
132       $start = $_GET['start'];
133    }
134    else {
135       $start = 0;
136    }
137    echo "var start = $start;”;
138    ?>
139    // load in some starting data
140    var tableData = new Object();
141    var d = getDataSync(start,5);
142  
143    for(var i = start; i < (start+5); i++) {
144       tableData[i] = d[i];
145    }
146  
147    // render 5 rows of data
148    var table = document.getElementById('table');
149    for(var i = start; i < (start+5); i++) {
150       var row = document.createElement('tr');
151       for(var key in tableData[i]) {
152          var cell = document.createElement('td');
153          cell.appendChild(document.createTextNode(tableData[i][key]));
154          row.appendChild(cell);
155       }
156       table.appendChild(row);
157    }
158  
159    // add our scroll bar
160    var bar = new ScrollBar('bar');
161    bar.currentRow = 0;
162    bar.scrollSize = 5;
163    bar.numRows = getNumRowsSync();
164    bar.currentRow = start;
165  
166    // override the scrollbars onScrollDown method
167    // use currentRow and scrollSize to see if we have more data to scroll
168    // Scrolling means remove a row from the top add one to the bottom
169    bar.onScrollDown = function() {
170       // check if we should scroll
171       if ( (this.currentRow + 1 + this.scrollSize) > this.numRows) {
172          return; // no data to scroll too bail
173       }
174  
175       this.currentRow += 1;
176  
177       // add our new row
178       var index = this.currentRow + this.scrollSize -1;
179  
180       if (!tableData[index]) {
181          var d = getDataSync(index,5);
182  
183          for(var i in d) {
184             tableData[i] = d[i];
185             }
186          }
187          else {
188             prefetchDownAsNeeded(index);
189          }
190          var row = document.createElement('tr');
191          for(var key in tableData[index]) {
192             var cell = document.createElement('td');
193             cell.appendChild(document.createTextNode(tableData[index][key]));
194             row.appendChild(cell);
195          }
196          table.appendChild(row);
197  
198          // remove the first row
199          table.removeChild(table.getElementsByTagName('tr').item(0));
200       }
201  
202       // override the scrollbars onScrollUp method
203       // same as onScrollDown only in the other direction
204       bar.onScrollUp = function() {
205          // check if we should scroll
206          if ( this.currentRow == 0) {
207             return; // no data to scroll too bail
208          }
209  
210          this.currentRow -= 1;
211  
212          // add our new row
213          var index = this.currentRow;
214  
215          // to hit this get you need to pass in a start value ?start=100 and then scroll up
216          if (!tableData[index]) {
217             var start = index - 4;
218             var d = getDataSync(start,5);
219  
220             for(var i in d) {
221                tableData[i] = d[i];
222             }
223          }
224          else {
225             prefetchUpAsNeeded(index);
226          }
227  
228          var row = document.createElement('tr');
229          for(var key in tableData[index]) {
230             var cell = document.createElement('td');
231             cell.appendChild(document.createTextNode(tableData[index][key]));
232             row.appendChild(cell);
233          }
234  
235          table.insertBefore(row,table.getElementsByTagName('tr').item(0));
236  
237          // remove the last row
238          table.removeChild(table.getElementsByTagName('tr').item(this.scrollSize));
239       }
240       </script>
241  
242    </body>
243  
244 </head>