[svn:p5ee] r13245 - in p5ee/trunk/App-Widget-ExtJS: . htdocs/App lib/App/SessionObject/ExtJS lib/App/Widget lib/App/Widget/ExtJS
[email protected] Tue, 1 Sep 2009 12:50:26 -0700 (PDT)
| Newsgroups | perl.cvs.p5ee |
|---|---|
| Message-ID | <[email protected]> |
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 = " "; - 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);