Author: spadkins
Date: Tue Sep  1 12:50:17 2009
New Revision: 13245

Modified:
   p5ee/trunk/App-Widget-ExtJS/Makefile.PL
   p5ee/trunk/App-Widget-ExtJS/htdocs/App/ext-addon.js
   p5ee/trunk/App-Widget-ExtJS/lib/App/SessionObject/ExtJS/Store.pm
   p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS.pm
   p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS/DataTable.pm

Log:
next generation of ExtJS::DataTable. does Ajax/paging/filtering/sorting

Modified: p5ee/trunk/App-Widget-ExtJS/Makefile.PL
==============================================================================
--- p5ee/trunk/App-Widget-ExtJS/Makefile.PL     (original)
+++ p5ee/trunk/App-Widget-ExtJS/Makefile.PL     Tue Sep  1 12:50:17 2009
@@ -25,6 +25,7 @@
 
 install ::
        @\$(MOD_INSTALL) htdocs  "\$(PREFIX)/htdocs"
+       @\$(MOD_INSTALL) cgi-bin "\$(PREFIX)/cgi-bin"
 
 EOF
 }

Modified: p5ee/trunk/App-Widget-ExtJS/htdocs/App/ext-addon.js
==============================================================================
--- p5ee/trunk/App-Widget-ExtJS/htdocs/App/ext-addon.js (original)
+++ p5ee/trunk/App-Widget-ExtJS/htdocs/App/ext-addon.js Tue Sep  1 12:50:17 2009
@@ -1,250 +1,852 @@
-/*
- * Ext JS Library 2.0.1
- * Copyright(c) 2006-2008, Ext JS, LLC.
- * [email protected]
- * 
- * http://extjs.com/license
- */
-
-Ext.grid.GroupSummary = function(config){
-    Ext.apply(this, config);
-};
-
-Ext.extend(Ext.grid.GroupSummary, Ext.util.Observable, {
-    init : function(grid){
-        this.grid = grid;
-        this.cm = grid.getColumnModel();
-        this.view = grid.getView();
-
-        var v = this.view;
-        v.doGroupEnd = this.doGroupEnd.createDelegate(this);
-
-        v.afterMethod('onColumnWidthUpdated', this.doWidth, this);
-        v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
-        v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);
-        v.afterMethod('onUpdate', this.doUpdate, this);
-        v.afterMethod('onRemove', this.doRemove, this);
-
-        if(!this.rowTpl){
-            this.rowTpl = new Ext.Template(
-                '<div class="x-grid3-summary-row" style="{tstyle}">',
-                '<table class="x-grid3-summary-table" border="0" 
cellspacing="0" cellpadding="0" style="{tstyle}">',
-                    '<tbody><tr>{cells}</tr></tbody>',
-                '</table></div>'
-            );
-            this.rowTpl.disableFormats = true;
-        }
-        this.rowTpl.compile();
-
-        if(!this.cellTpl){
-            this.cellTpl = new Ext.Template(
-                '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" 
style="{style}">',
-                '<div class="x-grid3-cell-inner x-grid3-col-{id}" 
unselectable="on">{value}</div>',
-                "</td>"
-            );
-            this.cellTpl.disableFormats = true;
-        }
-        this.cellTpl.compile();
-    },
-
-    toggleSummaries : function(visible){
-        var el = this.grid.getGridEl();
-        if(el){
-            if(visible === undefined){
-                visible = el.hasClass('x-grid-hide-summary');
-            }
-            el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary');
-        }
-    },
-
-    renderSummary : function(o, cs){
-        cs = cs || this.view.getColumnData();
-        var cfg = this.cm.config;
-
-        var buf = [], c, p = {}, cf, last = cs.length-1;
-        for(var i = 0, len = cs.length; i < len; i++){
-            c = cs[i];
-            cf = cfg[i];
-            p.id = c.id;
-            p.style = c.style;
-            p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 
'x-grid3-cell-last ' : '');
-            if(cf.summaryType || cf.summaryRenderer){
-                p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], 
p, o);
-            }else{
-                p.value = '';
-            }
-            if(p.value == undefined || p.value === "") p.value = "&#160;";
-            buf[buf.length] = this.cellTpl.apply(p);
-        }
-
-        return this.rowTpl.apply({
-            tstyle: 'width:'+this.view.getTotalWidth()+';',
-            cells: buf.join('')
-        });
-    },
-
-    calculate : function(rs, cs){
-        var data = {}, r, c, cfg = this.cm.config, cf;
-        for(var j = 0, jlen = rs.length; j < jlen; j++){
-            r = rs[j];
-            for(var i = 0, len = cs.length; i < len; i++){
-                c = cs[i];
-                cf = cfg[i];
-                if(cf.summaryType){
-                    data[c.name] = 
Ext.grid.GroupSummary.Calculations[cf.summaryType](data[c.name] || 0, r, 
c.name, data);
-                }
-            }
-        }
-        return data;
-    },
-
-    doGroupEnd : function(buf, g, cs, ds, colCount){
-        var data = this.calculate(g.rs, cs);
-        buf.push('</div>', this.renderSummary({data: data}, cs), '</div>');
-    },
-
-    doWidth : function(col, w, tw){
-        var gs = this.view.getGroups(), s;
-        for(var i = 0, len = gs.length; i < len; i++){
-            s = gs[i].childNodes[2];
-            s.style.width = tw;
-            s.firstChild.style.width = tw;
-            s.firstChild.rows[0].childNodes[col].style.width = w;
-        }
-    },
-
-    doAllWidths : function(ws, tw){
-        var gs = this.view.getGroups(), s, cells, wlen = ws.length;
-        for(var i = 0, len = gs.length; i < len; i++){
-            s = gs[i].childNodes[2];
-            s.style.width = tw;
-            s.firstChild.style.width = tw;
-            cells = s.firstChild.rows[0].childNodes;
-            for(var j = 0; j < wlen; j++){
-                cells[j].style.width = ws[j];
-            }
-        }
-    },
-
-    doHidden : function(col, hidden, tw){
-        var gs = this.view.getGroups(), s, display = hidden ? 'none' : '';
-        for(var i = 0, len = gs.length; i < len; i++){
-            s = gs[i].childNodes[2];
-            s.style.width = tw;
-            s.firstChild.style.width = tw;
-            s.firstChild.rows[0].childNodes[col].style.display = display;
-        }
-    },
-
-    // Note: requires that all (or the first) record in the 
-    // group share the same group value. Returns false if the group
-    // could not be found.
-    refreshSummary : function(groupValue){
-        return this.refreshSummaryById(this.view.getGroupId(groupValue));
-    },
-
-    getSummaryNode : function(gid){
-        var g = Ext.fly(gid, '_gsummary');
-        if(g){
-            return g.down('.x-grid3-summary-row', true);
-        }
-        return null;
-    },
-
-    refreshSummaryById : function(gid){
-        var g = document.getElementById(gid);
-        if(!g){
-            return false;
-        }
-        var rs = [];
-        this.grid.store.each(function(r){
-            if(r._groupId == gid){
-                rs[rs.length] = r;
-            }
-        });
-        var cs = this.view.getColumnData();
-        var data = this.calculate(rs, cs);
-        var markup = this.renderSummary({data: data}, cs);
-
-        var existing = this.getSummaryNode(gid);
-        if(existing){
-            g.removeChild(existing);
-        }
-        Ext.DomHelper.append(g, markup);
-        return true;
-    },
-
-    doUpdate : function(ds, record){
-        this.refreshSummaryById(record._groupId);
-    },
-
-    doRemove : function(ds, record, index, isUpdate){
-        if(!isUpdate){
-            this.refreshSummaryById(record._groupId);
-        }
-    },
-
-    showSummaryMsg : function(groupValue, msg){
-        var gid = this.view.getGroupId(groupValue);
-        var node = this.getSummaryNode(gid);
-        if(node){
-            node.innerHTML = '<div class="x-grid3-summary-msg">' + msg + 
'</div>';
-        }
-    }
-});
-
-Ext.grid.GroupSummary.Calculations = {
-    'sum' : function(v, record, field){
-        return v + (record.data[field]||0);
-    },
-
-    'count' : function(v, record, field, data){
-        return data[field+'count'] ? ++data[field+'count'] : 
(data[field+'count'] = 1);
-    },
-
-    'max' : function(v, record, field, data){
-        var v = record.data[field];
-        var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : 
data[field+'max'];
-        return v > max ? (data[field+'max'] = v) : max;
-    },
-
-    'min' : function(v, record, field, data){
-        var v = record.data[field];
-        var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : 
data[field+'min'];
-        return v < min ? (data[field+'min'] = v) : min;
-    },
-
-    'average' : function(v, record, field, data){
-        var c = data[field+'count'] ? ++data[field+'count'] : 
(data[field+'count'] = 1);
-        var t = (data[field+'total'] = ((data[field+'total']||0) + 
(record.data[field]||0)));
-        return t === 0 ? 0 : t / c;
-    }
-}
-
-Ext.grid.HybridSummary = Ext.extend(Ext.grid.GroupSummary, {
-    calculate : function(rs, cs){
-        var gcol = this.view.getGroupField();
-        var gvalue = rs[0].data[gcol];
-        var gdata = this.getSummaryData(gvalue);
-        return gdata || Ext.grid.HybridSummary.superclass.calculate.call(this, 
rs, cs);
-    },
-
-    updateSummaryData : function(groupValue, data, skipRefresh){
-        var json = this.grid.store.reader.jsonData;
-        if(!json.summaryData){
-            json.summaryData = {};
-        }
-        json.summaryData[groupValue] = data;
-        if(!skipRefresh){
-            this.refreshSummary(groupValue);
-        }
-    },
-
-    getSummaryData : function(groupValue){
-        var json = this.grid.store.reader.jsonData;
-        if(json && json.summaryData){
-            return json.summaryData[groupValue];
+
+// *******************************************************************
+// * ext-addon.js
+// *******************************************************************
+
+if (!Ext.app) {
+    Ext.app = new Object();
+}
+
+// *******************************************************************
+// * app.init() - Autodetect deployment values
+// * The app.options object is initially populated with values by the
+// * application.  However, we can auto-detect other values and fill
+// * them in if they have not been supplied.
+// *******************************************************************
+
+// Example: http://localhost/1.0.4/members/app/edit.html?x=1&y=2
+//    (a web page)
+//    urlFull       = http://localhost/1.0.4/members/app/edit.html?x=1&y=2
+//    urlBase       = http://localhost/1.0.4/members/app/edit.html
+//    urlParams     = ?x=1&y=2
+//    urlDir        = http://localhost/1.0.4/members/app
+//    urlFile       = edit.html
+//    appName       = edit
+//    urlDocRoot    = http://localhost/1.0.4                     (a guess)
+//    urlScriptRoot = http://localhost/cgi-bin/1.0.4             (a guess)
+//    urlDocDir     = http://localhost/1.0.4/members/app         (same as 
urlDir)
+//    urlScriptDir  = http://localhost/cgi-bin/1.0.4/members/app (add cgi-bin)
+
+// Example: http://localhost/cgi-bin/1.0.4/members/app/edit?x=1&y=2
+//    (a cgi program)
+//    urlFull       = http://localhost/cgi-bin/1.0.4/members/app/edit?x=1&y=2
+//    urlBase       = http://localhost/cgi-bin/1.0.4/members/app/edit
+//    urlParams     = ?x=1&y=2
+//    urlDir        = http://localhost/cgi-bin/1.0.4/members/app
+//    urlFile       = edit.html
+//    appName       = edit
+//    urlDocRoot    = http://localhost/1.0.4                 (a guess)
+//    urlScriptRoot = http://localhost/cgi-bin/1.0.4         (a guess)
+//    urlScriptDir  = http://localhost/cgi-bin/1.0.4/members/app (same as 
urlDir)
+//    urlDocDir     = http://localhost/1.0.4/members/app     (remove cgi-bin)
+
+Ext.app.init = function () {
+    var appName, urlFull, urlBase, urlDir, urlFile, urlParams;
+    var urlDocRoot, urlScriptRoot, urlDocDir, urlScriptDir;
+    var pos, pos2;
+
+    // augment the deployment values with values we can autodetect
+    // Do some sanity checks
+    if (!Ext.app.options) {
+        Ext.app.options = new Object();
+    }
+    var options = Ext.app.options;
+
+    if (!Ext.app.conf) {
+        Ext.app.conf = new Object();
+    }
+    if (!Ext.app.conf.global) {
+        Ext.app.conf.global = new Object();
+    }
+
+    // if (options.urlDocRoot == null) {
+    //     alert("ERROR: options.urlDocRoot not set\nDefine 'var options = { 
urlDocRoot : 'value' }; in your app deployment values");
+    // }
+    // if (options.urlScriptRoot == null) {
+    //     alert("ERROR: options.urlScriptRoot not set\nDefine 'var options = 
{ urlScriptRoot : 'value' }; in your app deployment values");
+    // }
+    
+    // This parsing is (or should be) 100% JavaScript 1.0 (!) compatible
+
+    urlFull = document.location.href;
+
+    pos = urlFull.lastIndexOf("?");
+    if (pos > 0) {
+        urlParams = urlFull.substring(pos, urlFull.length);
+        urlBase   = urlFull.substring(0, pos);
+    }
+    else {
+        urlParams = "";
+        urlBase   = urlFull;
+    }
+    pos = urlBase.lastIndexOf("/");
+    if (pos > 0 && pos < urlBase.length - 1) {
+        urlFile   = urlBase.substring(pos+1, urlBase.length);
+        urlDir    = urlBase.substring(0, pos);
+    }
+    else {
+        urlFile   = "";
+        urlDir    = urlBase;
+    }
+    pos = urlFile.lastIndexOf(".");
+    if (pos > 0) {
+        appName   = urlFile.substring(0, pos);
+    }
+    else if (urlFile) {
+        appName   = urlFile;
+    }
+    else {
+        appName   = "main";
+    }
+
+    pos = urlDir.lastIndexOf("/cgi-bin/");
+    if (pos >= 0) {
+        var part1 = urlFull.substring(0, pos);
+        var part2 = urlFull.substring(pos+8, urlFull.length);
+        urlDocDir = part1 + part2;
+        urlScriptDir = urlDir;
+    }
+    else {   // no "/cgi-bin/"
+        urlDocDir = urlDir;
+        pos = urlDir.indexOf("http");
+        if (pos == 0) {
+            pos = urlDir.indexOf("/",9);
+            urlScriptDir = urlDir.substring(0,pos) + "/cgi-bin" + 
urlDir.substring(pos,urlDir.length);
+        }
+        else {
+            urlScriptDir = "/cgi-bin" + urlDir;
+        }
+    }
+
+    pos = urlDocDir.indexOf("http");
+    if (pos == 0) {
+        pos = urlDocDir.indexOf("/",9);
+        pos2 = urlDocDir.indexOf("/",pos+1);
+        urlDocRoot = urlDocDir.substring(0,pos2);
+        urlScriptRoot = urlDocDir.substring(0,pos) + "/cgi-bin" + 
urlDocDir.substring(pos,pos2);
+
+        // alert("urlDocRoot = " + urlDocRoot + "\n" +
+        //       "urlScriptRoot = " + urlScriptRoot + "\n" +
+        //       "urlDocDir = " + urlDocDir + "\n" +
+        //       "urlScriptDir = " + urlScriptDir + "\n" +
+        //       "pos = " + pos + "; pos2 = " + pos2);
+    }
+    else {
+        pos = urlDocDir.indexOf("/",1);
+        urlDocRoot = urlDocDir.substring(0,pos);
+        urlScriptRoot = "/cgi-bin" + urlDocDir.substring(0,pos);
+    }
+
+    if (options.urlFull       == null) options.urlFull       = urlFull;
+    if (options.urlBase       == null) options.urlBase       = urlBase;
+    if (options.urlDir        == null) options.urlDir        = urlDir;
+    if (options.urlFile       == null) options.urlFile       = urlFile;
+    if (options.urlParams     == null) options.urlParams     = urlParams;
+    if (options.urlDocRoot    == null) options.urlDocRoot    = urlDocRoot;
+    if (options.urlScriptRoot == null) options.urlScriptRoot = urlScriptRoot;
+    if (options.urlDocDir     == null) options.urlDocDir     = urlDocDir;
+    if (options.urlScriptDir  == null) options.urlScriptDir  = urlScriptDir;
+    if (options.appName       == null) options.appName       = appName;
+
+    // Only during development time would you allow the person
+    // at the browser to overwrite your deployment values.
+    // To enable this, set options.urlConfigOK = 1.
+    // alert("urlConfigOK=" + options.urlConfigOK);
+    if (options.urlConfigOK != null && options.urlConfigOK != 0) {
+        urlParams = options.urlParams;
+        if (urlParams != "") {
+            // get rid of leading "?"
+            urlParams = urlParams.substring(1,urlParams.length);
+        }
+        var urlParamAssignment, urlParam, urlParamValue;
+        // I might need to do some unescaping here. We'll see.
+        while (urlParams != "") {
+            pos = urlParams.indexOf("&");
+            if (pos > 0) {
+                urlParamAssignment = urlParams.substring(0,pos);
+                urlParams = urlParams.substring(pos+1,urlParams.length);
+            }
+            else {
+                urlParamAssignment = urlParams;
+                urlParams = "";
+            }
+            pos = urlParamAssignment.indexOf("=");
+            if (pos > 0) {
+                urlParam = urlParamAssignment.substring(0,pos);
+                urlParamValue = 
urlParamAssignment.substring(pos+1,urlParamAssignment.length);
+            }
+            else {
+                urlParam = urlParamAssignmen;
+                urlParamValue = 1;
+            }
+            options[urlParam] = urlParamValue;
+            // alert("urlConfig: " + urlParam + "=" + urlParamValue);
+        }
+    }
+
+    // These values have wide cross-browser support.
+    // They are useful for determining what JavaScript features/bugs are 
supported.
+    //    navigator.userAgent:    Mozilla/5.0 (Windows; U; Windows NT 5.1; 
en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2
+    //    navigator.appCodeName:  Mozilla
+    //    navigator.appName:      Netscape
+    //    navigator.appVersion:   5.0 (Windows; en-US)
+    if (options.userAgent      == null) options.userAgent      = 
navigator.userAgent;
+    if (options.appCodeName    == null) options.appCodeName    = 
navigator.appCodeName;
+    if (options.appName        == null) options.appName        = 
navigator.appName;
+    if (options.appVersion     == null) options.appVersion     = 
navigator.appVersion;
+
+    // These are (or should be) derived from the above 4 "standard" values
+    if (options.browserVersion == null) options.browserVersion = 
parseInt(navigator.appVersion);
+    if (options.lang           == null) options.lang           = 'en';
+    if (options.langx          == null) options.langx          = 'en-US';
+
+    // These must have some default value if they are not set already
+    if (options.theme          == null) options.theme          = 'js-app';
+
+    Ext.app.context = new Ext.app.Context();
+}
+
+Ext.app.Context = function () {
+    this.session  = new Object();
+    this.cache    = new Object();
+    this.cache["SessionObject"] = new Object();
+    this.precache = new Object();
+
+    this.service = function (serviceType, serviceName, codedConf) {
+        // alert("context.service(" + serviceType + "," + serviceName + "," + 
codedConf + ")");
+        var s;
+        if (this.cache[serviceType] != null &&
+            this.cache[serviceType][serviceName] != null) {
+            s = this.cache[serviceType][serviceName];
+        }
+        else {
+            if (!codedConf && serviceName != "default") {
+                //alert("context.service(" + serviceType + "," + serviceName + 
") not cached and no codedConf given");
+            }
+            // get the precache values
+            var precacheValues;
+            if (this.precache[serviceType] != null) {
+                if (this.precache[serviceType][serviceName] != null) {
+                    precacheValues = this.precache[serviceType][serviceName];
+                }
+            }
+            // get the serviceConf
+            var serviceConf;
+            if (appConf[serviceType]) {
+                if (appConf[serviceType][serviceName] != null) {
+                    serviceConf = appConf[serviceType][serviceName];
+                }
+            }
+            // alert("service(" + serviceType + "," + serviceName + "," + 
codedConf + ") : conf=" + serviceConf);
+            if (!serviceConf && codedConf) {
+                serviceConf = codedConf;
+            }
+
+            // get the serviceTypeConf
+            var serviceTypeName, serviceTypeType, serviceTypeConf;
+            if (serviceConf != null) {
+                serviceTypeName = serviceConf.serviceType;
+            }
+            if (serviceTypeName == null) {
+                serviceTypeName = "default";
+            }
+            serviceTypeType = serviceType + "Type";
+            if (appConf[serviceTypeType] != null) {
+                if (appConf[serviceTypeType][serviceTypeName] != null) {
+                    serviceTypeConf = 
appConf[serviceTypeType][serviceTypeName];
+                }
+            }
+
+            // get serviceClass
+            var serviceClass;
+            if (serviceConf != null && serviceConf.serviceClass != null) {
+                serviceClass = serviceConf.serviceClass;
+            }
+            else if (serviceTypeConf != null && serviceTypeConf.serviceClass 
!= null) {
+                serviceClass = serviceTypeConf.serviceClass;
+            }
+            else {
+                serviceClass = serviceType;
+            }
+
+            // construct an instance of the class
+            var serviceConstructor = 'var s = new ' + serviceClass + '();';
+            // alert(serviceConstructor);
+            eval(serviceConstructor);
+
+            // initialize some standard attributes
+            if (precacheValues) {
+                this.copyObject(precacheValues, s);
+            }
+            this.copyObject(serviceConf, s);
+            this.copyObject(serviceTypeConf, s);
+            s.serviceName  = serviceName;
+            s.serviceType  = serviceType;
+            s.serviceClass = serviceClass;
+            if (this.cache[serviceType] == null) {
+                this.cache[serviceType] = new Object();
+            }
+            this.cache[serviceType][serviceName] = s;
+
+            if (s.initService) {
+                s.initService();
+            }
+            s.init();
+        }
+        return(s);
+    }
+
+    this.repository = function (serviceName,conf) {
+        return(this.service("Repository",serviceName,conf));
+    }
+
+    this.sessionObject = function (serviceName,conf) {
+        return(this.service("SessionObject",serviceName,conf));
+    }
+
+    this.valueDomain = function (serviceName,conf) {
+        return(this.service("ValueDomain",serviceName,conf));
+    }
+
+    this.widget = function (serviceName,conf) {
+        return(this.service("SessionObject",serviceName,conf));
+    }
+
+    this.getValue = function (serviceName, attrib, valueDefault, setDefault) {
+        var s, container, value, pos;
+        if (serviceName) {
+            if (typeof serviceName == "string") {
+                if (!attrib) {
+                    pos = serviceName.lastIndexOf("-");
+                    if (pos >= 0) {
+                        attrib = 
serviceName.substring(pos+1,serviceName.length);
+                        serviceName = serviceName.substring(0,pos);
+                    }
+                    else {
+                        attrib = serviceName;
+                        serviceName = "default";
+                    }
+                }
+                s = this.cache["SessionObject"][serviceName];
+                if (!s && this.precache["SessionObject"] != null &&
+                          this.precache["SessionObject"][serviceName] != null) 
{
+                    s = this.precache["SessionObject"][serviceName];
+                }
+                if (!s) {
+                    return(null);
+                }
+            }
+            else {
+                s = serviceName;
+            }
+            value = s[attrib];
+        }
+        if (value == null && valueDefault != null) {
+            value = valueDefault;
+            if (setDefault) s[attrib] = value;
+        }
+        return(value);
+    }
+
+    this.setValue = function (serviceName, attrib, value) {
+        var s, container, value, pos;
+        var changed = 0;
+        if (serviceName) {
+            if (typeof serviceName == "string") {
+                if (!attrib) {
+                    pos = serviceName.lastIndexOf("-");
+                    if (pos >= 0) {
+                        attrib = 
serviceName.substring(pos+1,serviceName.length);
+                        serviceName = serviceName.substring(0,pos);
+                    }
+                    else {
+                        attrib = serviceName;
+                        serviceName = "default";
+                    }
+                }
+                s = this.cache["SessionObject"][serviceName];
+                if (!s) {
+                    if (this.precache["SessionObject"] == null) {
+                        this.precache["SessionObject"] = new Object();
+                    }
+                    if (this.precache["SessionObject"][serviceName] == null) {
+                        this.precache["SessionObject"][serviceName] = new 
Object();
+                    }
+                    s = this.precache["SessionObject"][serviceName];
+                }
+            }
+            else {
+                s = serviceName;
+            }
+            if (s[attrib] != value) {
+                s[attrib] = value;
+                changed = 1;
+            }
+        }
+        return(changed);
+    }
+
+    this.getValues = function (serviceName, attrib, valueDefault, setDefault) {
+        // alert(this + ".getValue(" + serviceName + ", " + attrib + ", " + 
valueDefault + ", " + setDefault + ")");
+        var value = this.getValue(serviceName, attrib, valueDefault, 
setDefault);
+        if (value == null) {
+            value = "";
+        }
+        return(value.split(","));
+    }
+
+    this.setValues = function (serviceName, attrib, values) {
+        if (typeof(values) == "Array") {
+            return(this.setValue(serviceName, attrib, values.join(",")));
+        }
+        else {
+            return(this.setValue(serviceName, attrib, values));
+        }
+    }
+
+    this.getDOMValue = function (name) {
+        var value;
+        var elem = this.getElementByName(name);
+        if (elem) {
+            var i;
+            if (elem.value != null) {
+                value = elem.value;
+            }
+            else if (elem.type == "select-one") {
+                value = elem.options[elem.selectedIndex].value;
+            }
+            else if (elem.type == "select-multiple") {
+                for (i = 0; i < elem.options.length; i++) {
+                    if (elem.options[i].selected) {
+                        if (value == null) { value = elem.options[i].value;   }
+                        else               { value += "," + 
elem.options[i].value; }
+                    }
+                }
+            }
+        }
+        return(value);
+    }
+
+    this.setDOMValue = function (name, value) {
+        var elem = this.getElementByName(name);
+        // alert("setDOMValue(" + name + "," + value + ") [" + elem + "]");
+        var changed = 0;
+        if (elem) {
+            var i;
+            var type = elem.type;
+            if (type == null) {
+                // do nothing
+            }
+            else if (type == "select-one") {
+                // It seems that IE and DOM1 allow elem.value = value
+                // for a "select-one" element, but NS4+ and even Firefox
+                // don't seem to allow this.
+                if (elem.options[elem.selectedIndex].value != value) {
+                    elem.options[elem.selectedIndex].selected = false;
+                    for (i = 0; i < elem.options.length; i++) {
+                        if (elem.options[i].value == value) {
+                            if (elem.options[i].selected != true) {
+                                elem.options[i].selected = true;
+                                changed = 1;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+            else if (type == "select-multiple") {
+                var values;
+                if (value == null) {
+                    values = [];
+                }
+                else {
+                    values = value.split(",");
+                }
+                // set up a hash of the values to be set (comma-sep in "value")
+                var valuesToBeSet = new Object();
+                for (i = 0; i < values.length; i++) {
+                    valuesToBeSet[values[i]] = 1;
+                }
+                for (i = 0; i < elem.options.length; i++) {
+                    if (elem.options[i].selected) {
+                        if (! valuesToBeSet[elem.options[i].value]) {
+                            elem.options[i].selected = false;
+                            changed = 1;
+                        }
+                    }
+                    else {
+                        if (valuesToBeSet[elem.options[i].value]) {
+                            elem.options[i].selected = true;
+                            changed = 1;
+                        }
+                    }
+                }
+            }
+            else if (type == "hidden" ||
+                     type == "text" ||
+                     type == "textarea" ||
+                     type == "radio" ||
+                     type == "checkbox" ||
+                     type == "file" ||
+                     type == "image" ||
+                     type == "password" ||
+                     type == "reset" ||
+                     type == "submit" ||
+                     type == "button") {
+                if (elem.value != value) {
+                    elem.value = value;
+                    changed = 1;
+                }
+            }
+        }
+        return(changed);
+    }
+}
+
+Ext.app.init();
+
+// *******************************************************************
+// CLASS: Service
+// *******************************************************************
+Ext.app.Service = function () {
+    this.html = html;
+    function html () {
+        var html = '[' + this.serviceType + '(' + this.serviceName + ') : ' + 
this.serviceClass + ']';
+        return(html);
+    }
+    this.write = write;
+    function write () {
+        document.write(this.html());
+    }
+    this.init = init;
+    function init () {
+        // do nothing (available for overriding in a subclass)
+    }
+}
+
+// *******************************************************************
+// CLASS: SessionObject
+// *******************************************************************
+Ext.app.SessionObject = function () {
+
+    // this.init = init;
+    // function init () {
+    // }
+
+    this.container   = container;
+    function container (serviceName) {
+        if (serviceName == null) {
+            serviceName = this.serviceName;
+        }
+        var containerServiceName;
+        if (serviceName != "default") {
+            var pos = serviceName.lastIndexOf("-");
+            if (pos <= 0) {
+                containerServiceName = "default";
+            }
+            else {
+                containerServiceName = serviceName.substring(0, pos);
+            }
+        }
+        return(containerServiceName);
+    }
+
+    // not sure if anyone needs this. it is provided in parallel to the 
container() function
+    this.containerAttrib   = containerAttrib;
+    function containerAttrib (serviceName) {
+        if (serviceName == null) {
+            serviceName = this.serviceName;
+        }
+        var containerAttribName;
+        if (serviceName != "default") {
+            var pos = serviceName.lastIndexOf("-");
+            if (pos <= 0) {
+                containerAttribName = "serviceName";
+            }
+            else {
+                containerAttribName = serviceName.substring(pos+1, 
serviceName.length);
+            }
+        }
+        return(containerAttribName);
+    }
+
+    // This is a tricky area for compatibility between IE and Firefox, 
particularly
+    // when it comes to arriving at the page via the "Back" button.
+    this.initDefaultValue = initDefaultValue;
+    function initDefaultValue () {
+        var currentValue = context.getValue(this.serviceName);     // get if 
from the session
+        if (currentValue == null) {                                // if not...
+            currentValue = context.getDOMValue(this.serviceName);  // try 
getting from the DOM
+            if (currentValue != null) {                            // if so 
(i.e. "Back" button) ...
+                context.setValue(this.serviceName, null, currentValue);  // 
set it in the session
+            }
+        }
+        if (currentValue == null) {                                // 
otherwise ...
+            if (this["default"] != null) {
+                context.setValue(this.serviceName, null, this["default"]);
+            }
+            else {
+                context.setValue(this.serviceName, null, "");
+            }
+        }
+    }
+
+    this.validateCurrentValues = validateCurrentValues;
+    function validateCurrentValues () {
+        var values, validatedValues;
+        if (this.controlWidget || this.validate) {
+            values = context.getValue(this.serviceName);  // get as a single 
string
+            validatedValues = this.validateValues(values);
+            this.setCurrentValue(validatedValues);  // set as a single string
+        }
+    }
+
+    this.validateValues = validateValues;
+    function validateValues (values) {
+        var initialValues;
+        var i, value, validValues, valueIsValid, validationPattern;
+        var possibleValues, wantarray;
+        possibleValues = this.getValues();
+        // alert(this.serviceName + ".validateValues(" + values + ") : [" + 
typeof(values) + "]");
+        if (typeof(values) == "Array") {
+            initialValues = values;
+            wantarray = 1;
+        }
+        else if (possibleValues != null) {
+            if (values == "") {
+                initialValues = [];
+            }
+            else {
+                initialValues = values.split(",");
+            }
+            wantarray = 0;
+        }
+        else {
+            initialValues = new Array();
+            initialValues[0] = values;
+            wantarray = 0;
+        }
+        // begin keeping a list of the *valid* values
+        validValues = new Array();
+        // they might be validated by an enumerated list...
+        if (possibleValues && possibleValues.length > 0) {
+            // make a set of the valid values
+            valueIsValid = new Object();
+            for (i = 0; i < possibleValues.length; i++) {
+                valueIsValid[possibleValues[i]] = 1;
+            }
+            // check each possible value for inclusion in the set
+            for (i = 0; i < initialValues.length; i++) {
+                if (valueIsValid[initialValues[i]]) {
+                    validValues.push(initialValues[i]);
+                    // alert(this.serviceName + ".validateValues() : " + 
initialValues[i] + " is valid");
+                }
+            }
+            // alert(this.serviceName + ".validateValues() : valid.len=" + 
validValues.length + " possible.len=" + possibleValues.length);
+            if (validValues.length == 0 && ! this.nullable && 
possibleValues.length > 0) {
+                validValues[0] = possibleValues[0];
+                // alert(this.serviceName + ".validateValues() : setting 
value=" + validValues[0]);
+            }
+        }
+        // they might be validated by a regular expression ...
+        else if (this.validate) {
+            validationPattern = this.validate;
+            validValues = new Array();
+            for (v = 0; v < initialValues.length; v++) {
+                value = initialValues[v];
+                if (value.match(validationPattern) != null) {
+                    validValues.push(value);
+                }
+            }
+            if (validValues.length == 0 && ! this.nullable && this["default"]) 
{
+                validValues[0] = this["default"];
+            }
+        }
+        else {
+            validValues = initialValues;
+            if (validValues.length == 0 && ! this.nullable && this["default"]) 
{
+                validValues[0] = this["default"];
+            }
+        }
+        if (wantarray) {
+            return(validValues);
+        }
+        else {
+            return(validValues.join(","));
+        }
+    }
+
+    this.getCurrentValue = getCurrentValue;
+    function getCurrentValue () {
+        return(context.getValue(this.serviceName));
+    }
+
+    this.setCurrentValue = setCurrentValue;
+    function setCurrentValue (value) {
+        if (this.validate) {
+            value = this.validateValues(value);
+        }
+        var changed = context.setValue(this.serviceName, null, value);
+        return(changed);
+    }
+
+    this.getCurrentValues = getCurrentValues;
+    function getCurrentValues () {
+        var value = this.getCurrentValue();
+        if (value == null || value == "") {
+            return(new Array());
+        }
+        else {
+            return(value.split(","));
+        }
+    }
+
+    this.setCurrentValues = setCurrentValues;
+    function setCurrentValues (values) {
+        this.setCurrentValue(values.join(","));
+    }
+
+    this.getValues = getValues;
+    function getValues () {
+        var values = this.values;
+        var controlValue, controlValueOptions;
+        if (values == null && this.domain) {
+            var domain = context.service("ValueDomain", this.domain);
+            values = domain.getValues();
+        }
+        if (values == null && this.controlWidget && this.controlValueOptions) {
+            controlValueOptions = this.controlValueOptions;
+            controlValue = context.getValue(this.controlWidget);
+            if (controlValueOptions[controlValue] && 
controlValueOptions[controlValue].values) {
+                values = controlValueOptions[controlValue].values;
+            }
+            else if (controlValueOptions["default"] && 
controlValueOptions["default"].values) {
+                values = controlValueOptions["default"].values;
+            }
+            else {
+                values = this.values;
+            }
+        }
+        if (values == null) {
+            values = new Array();
+        }
+        return(values);
+    }
+
+    this.getLabels = getLabels;
+    function getLabels () {
+        var labels = this.labels;
+        var controlValue, controlValueOptions;
+        if (labels == null && this.domain) {
+            var domain = context.service("ValueDomain", this.domain);
+            labels = domain.getLabels();
+        }
+        if (labels == null && this.controlWidget && this.controlValueOptions) {
+            controlValueOptions = this.controlValueOptions;
+            controlValue = context.getValue(this.controlWidget);
+            if (controlValueOptions[controlValue] && 
controlValueOptions[controlValue].labels) {
+                labels = controlValueOptions[controlValue].labels;
+            }
+            else if (controlValueOptions["default"] && 
controlValueOptions["default"].labels) {
+                labels = controlValueOptions["default"].labels;
+            }
+            else {
+                labels = this.labels;
+            }
         }
-        return null;
+        if (labels == null) {
+            labels = new Object();
+        }
+        return(labels);
     }
-});
\ No newline at end of file
+
+    this.handleEvent = handleEvent;
+    function handleEvent (thisServiceName, eventServiceName, eventName, 
eventArgs) {
+        var containerServiceName = this.container(thisServiceName);
+        var argString;
+        if (eventArgs == null) {
+            argString = "null";
+        }
+        else {
+            var i;
+            argString = "";
+            for (i = 0; i < eventArgs.length; i++) {
+                argString += (i == 0) ? "[" : ",";
+                argString += eventArgs[i];
+            }
+            argString += "]";
+        }
+        var handled;
+        if (containerServiceName) {
+            var s = context.service("SessionObject", containerServiceName);
+            handled = s.handleEvent(containerServiceName, eventServiceName, 
eventName, eventArgs);
+        }
+        else if (eventName == "change") {  // ignore change events that are 
not otherwise handled
+            handled = 1;
+        }
+        else {
+            context.log("handleEvent(" + thisServiceName + "," + 
eventServiceName + "," +
+                eventName + "," + argString + ") : Event not handled\n");
+            handled = 0;
+        }
+        return(handled);
+    }
+
+    this.getId = getId;
+    function getId (withAttrib) {
+        var id = this.serviceName;
+        // id.replace(/\./g,"-");
+        if (withAttrib != null && withAttrib) {
+            id = ' id="' + id + '"';
+        }
+        return(id);
+    }
+}
+Ext.app.SessionObject.prototype = new Ext.app.Service();
+
+// *******************************************************************
+// CLASS: ValueDomain
+// *******************************************************************
+Ext.app.ValueDomain = function () {
+
+    this.getLabels = getLabels;
+    function getLabels () {
+        var labels = this.labels;
+        if (labels == null) {
+            labels = new Object();
+        }
+        return(labels);
+    }
+
+    this.getValues = getValues;
+    function getValues () {
+        var values = this.values;
+        var labels, key;
+        if (values == null) {
+            values = new Array();
+            labels = this.labels;
+            if (labels != null) {
+                for (key in labels) {
+                    values.push(key);
+                }
+                values.sort();
+            }
+        }
+        return(values);
+    }
+}
+Ext.app.ValueDomain.prototype = new Ext.app.Service();
+
+// *******************************************************************
+// CLASS: Repository
+// *******************************************************************
+Ext.app.Repository = function () {
+
+    this.sort = sort;
+    function sort (rows, sortKeys, sortType, sortDir) {
+        var sortedRows = rows;
+        return(sortedRows);
+    }
+}
+Ext.app.Repository.prototype = new Ext.app.Service();
+

Modified: p5ee/trunk/App-Widget-ExtJS/lib/App/SessionObject/ExtJS/Store.pm
==============================================================================
--- p5ee/trunk/App-Widget-ExtJS/lib/App/SessionObject/ExtJS/Store.pm    
(original)
+++ p5ee/trunk/App-Widget-ExtJS/lib/App/SessionObject/ExtJS/Store.pm    Tue Sep 
 1 12:50:17 2009
@@ -39,7 +39,7 @@
     }
 
     my $start   = $context->so_get("start") || 0;
-    my $limit   = $context->so_get("limit") || 25;
+    my $limit   = $context->so_get("limit");
     my $options = { startrow => $start+1, endrow => $start+$limit };
     if ($sort) {
         my $sort_spec = $sort;

Modified: p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS.pm
==============================================================================
--- p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS.pm (original)
+++ p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS.pm Tue Sep  1 12:50:17 2009
@@ -327,6 +327,12 @@
         $response->include("javascript", $js);
         $response->include("javascript", "$html_url_dir/App/ext-addon.js");
         $response->include("javascript", "$html_url_dir/App/ext-app.js");
+        my $js_additional = <<EOF;
+<script type="text/javascript">
+Ext.BLANK_IMAGE_URL = '$html_url_dir/$version/resources/images/default/s.gif';
+</script>
+EOF
+        $response->include("javascript", $js_additional);
     }
 
     &App::sub_exit() if ($App::trace);

Modified: p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS/DataTable.pm
==============================================================================
--- p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS/DataTable.pm       
(original)
+++ p5ee/trunk/App-Widget-ExtJS/lib/App/Widget/ExtJS/DataTable.pm       Tue Sep 
 1 12:50:17 2009
@@ -50,6 +50,28 @@
             $self->{keycolidx} = \...@keycolidx if ($#keycolidx == 
$#$primary_key);
         }
     }
+
+    my $filterable        = $self->{filterable};
+    my $lock_columns      = $self->{lock_columns};
+    my $context           = $self->{context};
+    my $options           = $context->{options};
+    my $html_url_dir      = $options->{html_url_dir} || "";
+    my $ext_extension_dir = $options->{ext_extension_dir} || "/App";
+
+    my ($response, $js, $css);
+    if ($lock_columns || $filterable) {
+        $response = $context->response() if (!$response);
+        $css = "${html_url_dir}${ext_extension_dir}/Ext.ux.ColumnLock.css";
+        $js  = "${html_url_dir}${ext_extension_dir}/Ext.ux.ColumnLock.js";
+        if (!$response->is_included("javascript", $js)) {
+            $response->include("css",        $css);
+            $response->include("javascript", $js);
+        }
+        $js = 
"${html_url_dir}${ext_extension_dir}/Ext.ux.grid.LockingGridHeaderFilters.js";
+        if (!$response->is_included("javascript", $js)) {
+            $response->include("javascript", $js);
+        }
+    }
 }
 
 sub repository {
@@ -237,8 +259,8 @@
         my $order_by   = $self->{order_by} || $self->{ordercols};   # 
ordercols is deprecated in favor of order_by
         my $group_by   = $self->{group_by};
         my $direction  = $self->{direction} || $self->{directions} || {}; # 
directions is deprecated in favor of direction
-        $startrow      = $self->get("startrow", 1, 1);
-        $maxrows       = $self->get("maxrows", 20, 1);
+        $startrow      = $self->get("startrow",   1, 1);
+        $maxrows       = $self->get("maxrows");
         $endrow        = ($maxrows != 0) ? ($startrow + $maxrows - 1) : 0;
 
         if ($App::DEBUG && $self->{context}->dbg(1)) {
@@ -284,22 +306,30 @@
     $value = "" if (!defined $value);
     my $table = $self->{table} || "unknown";
 
+    my $scrollable = $self->{scrollable};
+    my $sortable   = $self->{sortable};
+    my $filterable = $self->{filterable};
+    my $editable   = $self->{editable};
+
+    my $lock_columns = $self->{lock_columns};
+
     my $rep = $self->repository();
     my $tabledef = $rep->get_table_def($table);
 
-    my $data = $self->get_data();
-    my $js_data = $self->serialize_as_javascript($data);
-
     my $columns = $self->get_columns();
+    my $columns_list = join(",", @$columns);
     my $column_data_defs = [];
     my $column_display_defs = [];
-    my ($column_data_def, $column_display_def, $label);
-    foreach my $column (@$columns) {
-        $column_data_def = { name => $column };
+    my ($column_data_def, $column_display_def, $label, $column);
+    for (my $i = 0; $i <= $#$columns; $i++) {
+        $column = $columns->[$i];
+        $column_data_def = { name => $column, mapping => $i };
         push(@$column_data_defs, $column_data_def);
         $label = $tabledef->{column}{$column}{label} || $column;
         $label =~ s/<br>//g;
-        $column_display_def = { header => $label, sortable => "true", width => 
100, dataIndex => $column };
+        $column_display_def = { header => $label, width => 100, dataIndex => 
$column };
+        $column_display_def->{sortable} = "true" if ($sortable);
+        $column_display_def->{filter} = {xtype => "textfield"} if 
($filterable);
         push(@$column_display_defs, $column_display_def);
     }
     my $js_column_data_defs = 
$self->serialize_as_javascript($column_data_defs);
@@ -314,7 +344,78 @@
         $table_label = ucfirst($table_label);
     }
 
-    my $html = <<EOF;
+    my ($html);
+
+    if ($scrollable) {
+        my $context = $self->{context};
+        my $options = $context->{options};
+
+        my $order_by   = $self->{order_by};
+        $order_by = join(",", @$order_by) if (ref($order_by) eq "ARRAY");
+        my $order_by_js = $order_by ? ", order_by: '$order_by'" : "";
+
+        my $script_url_dir = $options->{script_url_dir}  || die "The parameter 
'script_url_dir' must be set in the option file";
+        my $script_url     = "$script_url_dir/App/app-ext-repository";
+        my $pagesize       = 100;
+
+        my (@plugins);
+        my $plugins_js = "";
+        if ($filterable || $lock_columns) {
+            push(@plugins, "Ext.ux.grid.LockingGridHeaderFilters");
+        }
+        $plugins_js .= "\n        plugins: [new " . join("(), new ", @plugins) 
. "()],";
+
+        $html = <<EOF;
+<script type="text/javascript">
+Ext.onReady(function(){
+
+    // create the data store
+    var dataStore = new Ext.data.JsonStore({
+        id: '$name-store',
+        fields: $js_column_data_defs,
+        root: 'data',
+        totalProperty: 'totalCount',
+        remoteSort: true,
+        proxy: new Ext.data.HttpProxy({ url: '$script_url', method: 'POST' }),
+        baseParams: {table: '$table', columns: '$columns_list'$order_by_js}
+    });
+
+    var pagingBar = new Ext.PagingToolbar({
+        pageSize: $pagesize,
+        store: dataStore,
+        displayInfo: true,
+        displayMsg: 'Displaying records {0} - {1} of {2}',
+        emptyMsg: 'No data to display'
+    });
+
+    // create the Grid
+    var grid = new Ext.grid.GridPanel({
+        id: '$name-grid',
+        store: dataStore,$plugins_js
+        columns: $js_column_display_defs,
+        stripeRows: true,
+        frame:  true,
+        // stateful: true,
+        height: $height,
+        width:  $width,
+        title: '$table_label',
+        bbar: pagingBar
+    });
+
+    grid.render('$name');
+    dataStore.load({params: {start: 0, limit: $pagesize}});
+
+    grid.getSelectionModel().selectFirstRow();
+});
+</script>
+<div id="$name"></div>
+EOF
+    }
+    else {
+        my $data = $self->get_data();
+        my $js_data = $self->serialize_as_javascript($data);
+
+        $html = <<EOF;
 <script type="text/javascript">
 Ext.onReady(function(){
 
@@ -347,6 +448,7 @@
 </script>
 <div id="$name"></div>
 EOF
+    }
 
     &App::sub_exit("<html...>") if ($App::trace);
     return($html);

Reply via email to