OSDN Git Service

git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/plugin@1020 1ca29b6e-896d...
[nucleus-jp/nucleus-plugins.git] / NP_TrackBack / branches / DOM-branch / trackback / js / rico / ricoLiveGridAjax.js
1 if(typeof Rico=='undefined') throw("LiveGridAjax requires the Rico JavaScript framework");
2 if(typeof RicoUtil=='undefined') throw("LiveGridAjax requires the RicoUtil object");
3 if(typeof Rico.Buffer=='undefined') throw("LiveGridAjax requires the Rico.Buffer object");
4
5
6 /**
7  * Data source is a static XML file located on the server
8  */
9 Rico.Buffer.AjaxXML = Class.create();
10
11 Rico.Buffer.AjaxXML.prototype = {
12
13   initialize: function(url,options,ajaxOptions) {
14     Object.extend(this, new Rico.Buffer.Base());
15     Object.extend(this, new Rico.Buffer.AjaxXMLMethods);
16     this.dataSource=url;
17     this.options.bufferTimeout = 20000;  // time to wait for ajax response (milliseconds)
18     this.options.requestParameters = [];
19     Object.extend(this.options, options || {});
20     this.ajaxOptions = { parameters: null, method : 'get' };
21     Object.extend(this.ajaxOptions, ajaxOptions || {});
22     this.requestCount=0;
23     this.processingRequest=false;
24     this.pendingRequest=-1;
25   }
26 }
27
28 Rico.Buffer.AjaxXMLMethods = function() {};
29
30 Rico.Buffer.AjaxXMLMethods.prototype = {
31
32   fetch: function(offset) {
33     if ( this.isInRange(offset) ) {
34       Rico.writeDebugMsg("AjaxXML fetch: in buffer");
35       this.liveGrid.refreshContents(offset);
36       return;
37     }
38     this.processingRequest=true
39     Rico.writeDebugMsg("AjaxXML fetch, offset="+offset);
40     this.liveGrid.showMsg("Waiting for data...");
41     this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
42     this.sendAjaxRequest(offset,0,this.ajaxUpdate.bind(this,offset));
43   },
44
45 /**
46  * Server did not respond in time... assume that there could have been
47  * an error, and allow requests to be processed again.
48  */
49   handleTimedOut: function() {
50     Rico.writeDebugMsg("Request Timed Out");
51     this.liveGrid.showMsg("Request for data timed out!");
52   },
53
54   formQueryHash: function(startPos,fetchSize) {
55     if (typeof fetchSize!='number') fetchSize=this.totalRows;
56     var queryHash= {
57       id: this.liveGrid.tableId,
58       page_size: fetchSize,
59       offset: startPos
60     };
61     if (!this.foundRowCount) queryHash['get_total']='true';
62     if (this.options.requestParameters) {
63       for ( var i=0; i < this.options.requestParameters.length; i++ ) {
64         var anArg = this.options.requestParameters[i];
65         if ( anArg.name != undefined && anArg.value != undefined ) {
66           queryHash[anArg.name]=anArg.value;
67         } else {
68           var ePos  = anArg.indexOf('=');
69           var argName  = anArg.substring( 0, ePos );
70           var argValue = anArg.substring( ePos + 1 );
71           queryHash[argName]=argValue;
72         }
73       }
74     }
75     
76     // sort
77     Object.extend(queryHash,this.sortParm);
78
79     // filters
80     for (n=0; n<this.liveGrid.columns.length; n++) {
81       var c=this.liveGrid.columns[n];
82       if (c.filterType == Rico.TableColumn.UNFILTERED) continue;
83       queryHash['f['+c.index+'][op]']=c.filterOp;
84       queryHash['f['+c.index+'][len]']=c.filterValues.length
85       for (var i=0; i<c.filterValues.length; i++)
86         queryHash['f['+c.index+']['+i+']']=c.filterValues[i];
87     }
88       
89     return $H(queryHash);
90   },
91
92   sendAjaxRequest: function(startPos,fetchSize,onComplete) {
93     this.ajaxOptions.parameters = this.formQueryHash(startPos,fetchSize);
94     this.ajaxOptions.onComplete = onComplete;
95     this.requestCount++;
96     Rico.writeDebugMsg('req '+this.requestCount+':'+this.ajaxOptions.parameters.inspect());
97     new Ajax.Request(this.dataSource, this.ajaxOptions);
98   },
99   
100   clearTimer: function() {
101     if(typeof this.timeoutHandler != "number") return;
102     window.clearTimeout(this.timeoutHandler);
103     delete this.timeoutHandler;
104   },
105
106   ajaxUpdate: function(startPos,request) {
107     this.clearTimer();
108     this.processingRequest=false;
109     if (request.status != 200) {
110       Rico.writeDebugMsg("ajaxUpdate: received http error="+request.status);
111       this.liveGrid.showMsg('Received HTTP error: '+request.status);
112       return;
113     }
114     var response = request.responseXML.getElementsByTagName("ajax-response");
115     if (response == null || response.length != 1) return;
116     this.updateBuffer(response[0],startPos);
117     this.CheckRowCount(response[0],startPos);
118     if (this.options.TimeOut && this.timerMsg)
119       this.restartSessionTimer();
120     if (this.options.onAjaxUpdate)
121       this.options.onAjaxUpdate();
122     if (this.pendingRequest>=0) {
123       var offset=this.pendingRequest;
124       Rico.writeDebugMsg("ajaxUpdate: found pending request for offset="+offset);
125       this.pendingRequest=-1;
126       this.fetch(offset);
127     }
128   },
129
130   CheckRowCount: function(ajaxResponse,offset) {
131     //try {
132       Rico.writeDebugMsg("CheckRowCount, size="+this.size+' rcv cnt type='+typeof(this.rowcntContent));
133       if (this.rcvdRowCount==true) {
134         Rico.writeDebugMsg("found row cnt: "+this.rowcntContent);
135         var eofrow=parseInt(this.rowcntContent);
136         var lastTotalRows=this.totalRows;
137         if (!isNaN(eofrow) && eofrow!=lastTotalRows) {
138           this.setTotalRows(eofrow);
139           var newpos=Math.min(this.liveGrid.topOfLastPage(),offset);
140           Rico.writeDebugMsg("CheckRowCount: new rowcnt="+eofrow+" newpos="+newpos);
141           if (lastTotalRows==0 && this.liveGrid.sizeTo=='data')
142             this.liveGrid.adjustPageSize();
143           //this.lastRowPos=-1;
144           this.liveGrid.scrollToRow(newpos);
145           if ( this.isInRange(newpos) ) {
146             this.liveGrid.refreshContents(newpos);
147           } else {
148             this.fetch(newpos);
149           }
150           return;
151         }
152       } else {
153         var lastbufrow=offset+this.rcvdRows;
154         if (lastbufrow>this.totalRows) {
155           var newcnt=lastbufrow;
156           Rico.writeDebugMsg("extending totrows to "+newcnt);
157           this.setTotalRows(newcnt);
158         }
159       }
160       var newpos=this.liveGrid.pixeltorow(this.liveGrid.scrollDiv.scrollTop);
161       Rico.writeDebugMsg("CheckRowCount: newpos="+newpos);
162       this.liveGrid.refreshContents(newpos);
163     //}
164     //catch(err) {
165     //  alert("Error in CheckRowCount:"+err.message);
166     //}
167   },
168
169   updateBuffer: function(ajaxResponse, start) {
170     Rico.writeDebugMsg("updateBuffer: "+start);
171     this.rcvdRows = 0;
172     var newRows = this.loadRows(ajaxResponse);
173     if (newRows==null) return;
174     this.rcvdRows = newRows.length;
175     Rico.writeDebugMsg("updateBuffer: # of rows="+this.rcvdRows);
176     if (this.rows.length == 0) { // initial load
177       this.rows = newRows;
178       this.startPos = start;
179     } else if (start > this.startPos) { //appending
180       if (this.startPos + this.rows.length < start) {
181         this.rows =  newRows;
182         this.startPos = start;//
183       } else {
184         this.rows = this.rows.concat( newRows.slice(0, newRows.length));
185         if (this.rows.length > this.maxBufferSize) {
186           var fullSize = this.rows.length;
187           this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
188           this.startPos = this.startPos +  (fullSize - this.rows.length);
189         }
190       }
191     } else { //prepending
192       if (start + newRows.length < this.startPos) {
193         this.rows =  newRows;
194       } else {
195         this.rows = newRows.slice(0, this.startPos).concat(this.rows);
196         if (this.maxBufferSize && this.rows.length > this.maxBufferSize)
197           this.rows = this.rows.slice(0, this.maxBufferSize)
198       }
199       this.startPos =  start;
200     }
201     this.size = this.rows.length;
202   },
203
204   loadRows: function(ajaxResponse) {
205     Rico.writeDebugMsg("loadRows");
206     this.rcvdRowCount = false;
207     var debugtags = ajaxResponse.getElementsByTagName('debug');
208     for (var i=0; i<debugtags.length; i++)
209       Rico.writeDebugMsg("loadRows, debug msg "+i+": "+RicoUtil.getContentAsString(debugtags[i],this.options.isEncoded));
210     var error = ajaxResponse.getElementsByTagName('error');
211     if (error.length > 0) {
212       var msg=RicoUtil.getContentAsString(error[0],this.options.isEncoded);
213       alert("Data provider returned an error:\n"+msg);
214       Rico.writeDebugMsg("Data provider returned an error:\n"+msg);
215       return null;
216     }
217     var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
218     var rowcnttags = ajaxResponse.getElementsByTagName('rowcount');
219     if (rowcnttags && rowcnttags.length==1) {
220       this.rowcntContent = RicoUtil.getContentAsString(rowcnttags[0],this.options.isEncoded);
221       this.rcvdRowCount = true;
222       this.foundRowCount = true;
223       Rico.writeDebugMsg("loadRows, found RowCount="+this.rowcntContent);
224     }
225     this.updateUI = rowsElement.getAttribute("update_ui") == "true";
226     this.rcvdOffset = rowsElement.getAttribute("offset");
227     Rico.writeDebugMsg("loadRows, rcvdOffset="+this.rcvdOffset);
228     return this.dom2jstable(rowsElement);
229   }
230
231 };
232
233
234
235 Rico.Buffer.AjaxSQL = Class.create();
236
237 Rico.Buffer.AjaxSQL.prototype = {
238
239   initialize: function(url,options,ajaxOptions) {
240     Object.extend(this, new Rico.Buffer.AjaxXML());
241     Object.extend(this, new Rico.Buffer.AjaxSQLMethods());
242     this.dataSource=url;
243     this.options.canFilter=true;
244     this.options.largeBufferSize  = 7.0;   // 7 pages
245     this.options.nearLimitFactor  = 1.0;   // 1 page
246     Object.extend(this.options, options || {});
247     Object.extend(this.ajaxOptions, ajaxOptions || {});
248     this.sortParm={};
249   }
250 }
251   
252 Rico.Buffer.AjaxSQLMethods = function() {};
253
254 Rico.Buffer.AjaxSQLMethods.prototype = {
255
256   registerGrid: function(liveGrid) {
257     this.liveGrid = liveGrid;
258     this.sessionExpired=false;
259     this.timerMsg=$(liveGrid.tableId+'_timer');
260     if (this.options.TimeOut && this.timerMsg) {
261       if (!this.timerMsg.title) this.timerMsg.title=RicoTranslate.getPhrase("minutes before your session expires")
262       this.restartSessionTimer();
263     }
264   },
265   
266   setBufferSize: function(pageSize) {
267     this.maxFetchSize = Math.max(50,parseInt(this.options.largeBufferSize * pageSize));
268     this.nearLimit = parseInt(this.options.nearLimitFactor * pageSize);
269     this.maxBufferSize = this.maxFetchSize * 3;
270   },
271
272   restartSessionTimer: function() {
273     if (this.sessionExpired==true) return;
274     this.timeRemaining=this.options.TimeOut+1;
275     if (this.sessionTimer) clearTimeout(this.sessionTimer);
276     this.updateSessionTimer();
277   },
278   
279   updateSessionTimer: function() {
280     if (--this.timeRemaining<=0) {
281       this.displaySessionTimer(RicoTranslate.getPhrase("EXPIRED"));
282       this.timerMsg.style.backgroundColor="red";
283       this.sessionExpired=true;
284     } else {
285       this.displaySessionTimer(this.timeRemaining);
286       this.sessionTimer=setTimeout(this.updateSessionTimer.bind(this),60000);
287     }
288   },
289   
290   displaySessionTimer: function(msg) {
291     this.timerMsg.innerHTML='&nbsp;'+msg+'&nbsp;';
292   },
293   
294   refresh: function() {
295     this.fetch(this.lastOffset);
296   },
297   
298   /**
299    * Fetch data from database.
300    * @param offset position (row) within the dataset (-1=clear existing buffer before issuing request)
301    */
302   fetch: function(offset) {
303     Rico.writeDebugMsg("AjaxSQL fetch, offset="+offset+' lastOffset='+this.lastOffset);
304     if (this.processingRequest) {
305       Rico.writeDebugMsg("AjaxSQL fetch: queue request");
306       this.pendingRequest=offset;
307       return;
308     }
309     if (offset < 0) {
310       this.clear();
311       this.setTotalRows(0);
312       this.foundRowCount = false;
313       offset=0;
314     }
315     var lastOffset = this.lastOffset;
316     this.lastOffset = offset;
317     var inRange=this.isInRange(offset);
318     if (inRange) {
319       Rico.writeDebugMsg("AjaxSQL fetch: in buffer");
320       this.liveGrid.refreshContents(offset);
321       if (offset > lastOffset) {
322         if (offset+this.liveGrid.pageSize < this.endPos()-this.nearLimit) return;
323         if (this.endPos()==this.totalRows && this.foundRowCount) return;
324       } else if (offset < lastOffset) {
325         if (offset > this.startPos+this.nearLimit) return;
326         if (this.startPos==0) return;
327       } else return;
328     }
329     if (offset >= this.totalRows && this.foundRowCount) return;
330     
331     this.processingRequest=true
332     Rico.writeDebugMsg("AjaxSQL fetch, processing offset="+offset);
333     var bufferStartPos = this.getFetchOffset(offset);
334     var fetchSize = this.getFetchSize(bufferStartPos);
335     var partialLoaded = false;
336
337     if (!inRange) this.liveGrid.showMsg("Waiting for data...");
338     this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
339     this.sendAjaxRequest(bufferStartPos,fetchSize,this.ajaxUpdate.bind(this,bufferStartPos));
340   },
341
342   getFetchSize: function(adjustedOffset) {
343     var adjustedSize = 0;
344     if (adjustedOffset >= this.startPos) { //appending
345       var endFetchOffset = this.maxFetchSize + adjustedOffset;
346       adjustedSize = endFetchOffset - adjustedOffset;
347       if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize)
348         adjustedSize = this.maxFetchSize;
349       Rico.writeDebugMsg("getFetchSize/append, adjustedSize="+adjustedSize+" adjustedOffset="+adjustedOffset+' endFetchOffset='+endFetchOffset);
350     } else { //prepending
351       adjustedSize = Math.min(this.startPos - adjustedOffset,this.maxFetchSize);
352     }
353     return adjustedSize;
354   },
355
356   getFetchOffset: function(offset) {
357     var adjustedOffset = offset;
358     if (offset > this.startPos)
359       adjustedOffset = Math.max(offset, this.endPos());  //appending
360     else if (offset + this.maxFetchSize >= this.startPos)
361       adjustedOffset = Math.max(this.startPos - this.maxFetchSize, 0);  //prepending
362     return adjustedOffset;
363   },
364
365   sortBuffer: function(colnum,sortdir,coltype) {
366     this.sortParm={};
367     if (this.options.sortParmFmt && this.options.sortParmFmt=='displayName') {
368       this.sortParm['sort_col']=this.liveGrid.columns[colnum].displayName.toLowerCase();
369       this.sortParm['sort_dir']=sortdir;
370     }else{
371      this.sortParm['s'+colnum]=sortdir;
372     }
373     this.clear();
374   },
375   
376   exportAllRows: function(populate,finish) {
377     this.exportPopulate=populate;
378     this.exportFinish=finish;
379     this.liveGrid.showMsg("Waiting for data...");
380     this.sendExportRequest(0);
381   },
382   
383 /**
384  * Make ajax request for print window data
385  */
386   sendExportRequest: function(offset) {
387     this.timeoutHandler = setTimeout(this.exportTimedOut.bind(this), this.options.bufferTimeout);
388     this.sendAjaxRequest(offset,200,this.exportAppend.bind(this,offset));
389   },
390
391   exportTimedOut: function() {
392     Rico.writeDebugMsg("Print Request Timed Out");
393     this.liveGrid.showMsg("Request for data timed out!");
394     this.exportFinish();
395   },
396
397   exportAppend: function(startPos,request) {
398     this.clearTimer();
399     var response = request.responseXML.getElementsByTagName("ajax-response");
400     if (response == null || response.length != 1) return;
401     var rowsElement = response[0].getElementsByTagName('rows')[0];
402     var rows=this.dom2jstable(rowsElement);
403     this.exportPopulate(rows);
404     if (rows.length==0)
405       this.exportFinish();
406     else
407       this.sendExportRequest(startPos+rows.length);
408   }
409
410 };
411
412 Rico.includeLoaded('ricoLiveGridAjax.js');