var r = this.reader.readRecords(o);
this.loadRecords(r, {add: append}, true);
},
+
+ /**
+ * using 'cn' the nested child reader read the child array into it's child stores.
+ * @param {Object} rec The record with a 'children array
+ */
+ loadDataFromChildren : function(rec)
+ {
+ this.loadData(this.reader.toLoadData(rec));
+ },
+
/**
* Gets the number of cached records.
* Small helper class to make creating Stores from Array data easier.
* @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
* @cfg {Array} fields An array of field definition objects, or field name strings.
+ * @cfg {Object} an existing reader (eg. copied from another store)
* @cfg {Array} data The multi-dimensional array of data
* @constructor
* @param {Object} config
*/
-Roo.data.SimpleStore = function(config){
+Roo.data.SimpleStore = function(config)
+{
Roo.data.SimpleStore.superclass.constructor.call(this, {
isLocal : true,
- reader: new Roo.data.ArrayReader({
+ reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
id: config.id
},
Roo.data.Record.create(config.fields)
};
Roo.data.DataReader.prototype = {
+
+
+ readerType : 'Data',
/**
* Create an empty record
* @param {Object} data (optional) - overlay some values
return new this.recordType(Roo.apply(da, d));
}
+
};/*
* Based on:
* Ext JS Library 1.1.1
};
Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
+ readerType : 'Json',
+
/**
* @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
* Used by Store query builder to append _requestMeta to params.
records : records,
totalRecords : totalRecords
};
+ },
+ // used when loading children.. @see loadDataFromChildren
+ toLoadData: function(rec)
+ {
+ // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+ var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+ return { data : data, total : data.length };
+
}
});/*
* Based on:
Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
};
Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+
+ readerType : 'Xml',
+
/**
* This method is only used by a DataProxy which has retrieved data from a remote server.
* @param {Object} response The XHR object which contains the parsed XML document. The response is expected
*
* created using {@link Roo.data.Record#create}.
*/
-Roo.data.ArrayReader = function(meta, recordType){
-
-
+Roo.data.ArrayReader = function(meta, recordType)
+{
Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
};
Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
- /**
+
+ /**
* Create a data block containing Roo.data.Records from an XML document.
* @param {Object} o An Array of row objects which represents the dataset.
* @return {Object} A data block which is used by an {@link Roo.data.Store} object as
* a cache of Roo.data.Records.
*/
- readRecords : function(o){
+ readRecords : function(o)
+ {
var sid = this.meta ? this.meta.id : null;
- var recordType = this.recordType, fields = recordType.prototype.fields;
- var records = [];
- var root = o;
- for(var i = 0; i < root.length; i++){
- var n = root[i];
- var values = {};
- var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
- for(var j = 0, jlen = fields.length; j < jlen; j++){
+ var recordType = this.recordType, fields = recordType.prototype.fields;
+ var records = [];
+ var root = o;
+ for(var i = 0; i < root.length; i++){
+ var n = root[i];
+ var values = {};
+ var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+ for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
var v = n[k] !== undefined ? n[k] : f.defaultValue;
v = f.convert(v);
values[f.name] = v;
}
- var record = new recordType(values, id);
- record.json = n;
- records[records.length] = record;
- }
- return {
- records : records,
- totalRecords : records.length
- };
+ var record = new recordType(values, id);
+ record.json = n;
+ records[records.length] = record;
+ }
+ return {
+ records : records,
+ totalRecords : records.length
+ };
+ },
+ // used when loading children.. @see loadDataFromChildren
+ toLoadData: function(rec)
+ {
+ // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+ return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+
}
+
+
});/*
* Based on:
* Ext JS Library 1.1.1
* Fork - LGPL
* <script type="text/javascript">
*/
- (function(){
-/**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
- * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
- * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
- */
-
-Roo.Layer = function(config, existingEl){
- config = config || {};
- var dh = Roo.DomHelper;
- var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
- if(existingEl){
- this.dom = Roo.getDom(existingEl);
- }
- if(!this.dom){
- var o = config.dh || {tag: "div", cls: "x-layer"};
- this.dom = dh.append(pel, o);
- }
- if(config.cls){
- this.addClass(config.cls);
- }
- this.constrain = config.constrain !== false;
- this.visibilityMode = Roo.Element.VISIBILITY;
- if(config.id){
- this.id = this.dom.id = config.id;
- }else{
- this.id = Roo.id(this.dom);
- }
- this.zindex = config.zindex || this.getZIndex();
- this.position("absolute", this.zindex);
- if(config.shadow){
- this.shadowOffset = config.shadowOffset || 4;
- this.shadow = new Roo.Shadow({
- offset : this.shadowOffset,
- mode : config.shadow
- });
- }else{
- this.shadowOffset = 0;
- }
- this.useShim = config.shim !== false && Roo.useShims;
- this.useDisplay = config.useDisplay;
- this.hide();
-};
-
-var supr = Roo.Element.prototype;
-
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
-
-Roo.extend(Roo.Layer, Roo.Element, {
-
- getZIndex : function(){
- return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
- },
-
- getShim : function(){
- if(!this.useShim){
- return null;
- }
- if(this.shim){
- return this.shim;
- }
- var shim = shims.shift();
- if(!shim){
- shim = this.createShim();
- shim.enableDisplayMode('block');
- shim.dom.style.display = 'none';
- shim.dom.style.visibility = 'visible';
- }
- var pn = this.dom.parentNode;
- if(shim.dom.parentNode != pn){
- pn.insertBefore(shim.dom, this.dom);
- }
- shim.setStyle('z-index', this.getZIndex()-2);
- this.shim = shim;
- return shim;
- },
-
- hideShim : function(){
- if(this.shim){
- this.shim.setDisplayed(false);
- shims.push(this.shim);
- delete this.shim;
- }
- },
-
- disableShadow : function(){
- if(this.shadow){
- this.shadowDisabled = true;
- this.shadow.hide();
- this.lastShadowOffset = this.shadowOffset;
- this.shadowOffset = 0;
- }
- },
-
- enableShadow : function(show){
- if(this.shadow){
- this.shadowDisabled = false;
- this.shadowOffset = this.lastShadowOffset;
- delete this.lastShadowOffset;
- if(show){
- this.sync(true);
- }
- }
- },
-
- // private
- // this code can execute repeatedly in milliseconds (i.e. during a drag) so
- // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
- sync : function(doShow){
- var sw = this.shadow;
- if(!this.updating && this.isVisible() && (sw || this.useShim)){
- var sh = this.getShim();
-
- var w = this.getWidth(),
- h = this.getHeight();
-
- var l = this.getLeft(true),
- t = this.getTop(true);
-
- if(sw && !this.shadowDisabled){
- if(doShow && !sw.isVisible()){
- sw.show(this);
- }else{
- sw.realign(l, t, w, h);
- }
- if(sh){
- if(doShow){
- sh.show();
- }
- // fit the shim behind the shadow, so it is shimmed too
- var a = sw.adjusts, s = sh.dom.style;
- s.left = (Math.min(l, l+a.l))+"px";
- s.top = (Math.min(t, t+a.t))+"px";
- s.width = (w+a.w)+"px";
- s.height = (h+a.h)+"px";
- }
- }else if(sh){
- if(doShow){
- sh.show();
- }
- sh.setSize(w, h);
- sh.setLeftTop(l, t);
- }
-
- }
- },
-
- // private
- destroy : function(){
- this.hideShim();
- if(this.shadow){
- this.shadow.hide();
- }
- this.removeAllListeners();
- var pn = this.dom.parentNode;
- if(pn){
- pn.removeChild(this.dom);
- }
- Roo.Element.uncache(this.id);
- },
-
- remove : function(){
- this.destroy();
- },
-
- // private
- beginUpdate : function(){
- this.updating = true;
- },
-
- // private
- endUpdate : function(){
- this.updating = false;
- this.sync(true);
- },
-
- // private
- hideUnders : function(negOffset){
- if(this.shadow){
- this.shadow.hide();
- }
- this.hideShim();
- },
-
- // private
- constrainXY : function(){
- if(this.constrain){
- var vw = Roo.lib.Dom.getViewWidth(),
- vh = Roo.lib.Dom.getViewHeight();
- var s = Roo.get(document).getScroll();
-
- var xy = this.getXY();
- var x = xy[0], y = xy[1];
- var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
- // only move it if it needs it
- var moved = false;
- // first validate right/bottom
- if((x + w) > vw+s.left){
- x = vw - w - this.shadowOffset;
- moved = true;
- }
- if((y + h) > vh+s.top){
- y = vh - h - this.shadowOffset;
- moved = true;
- }
- // then make sure top/left isn't negative
- if(x < s.left){
- x = s.left;
- moved = true;
- }
- if(y < s.top){
- y = s.top;
- moved = true;
- }
- if(moved){
- if(this.avoidY){
- var ay = this.avoidY;
- if(y <= ay && (y+h) >= ay){
- y = ay-h-5;
- }
- }
- xy = [x, y];
- this.storeXY(xy);
- supr.setXY.call(this, xy);
- this.sync();
- }
- }
- },
-
- isVisible : function(){
- return this.visible;
- },
-
- // private
- showAction : function(){
- this.visible = true; // track visibility to prevent getStyle calls
- if(this.useDisplay === true){
- this.setDisplayed("");
- }else if(this.lastXY){
- supr.setXY.call(this, this.lastXY);
- }else if(this.lastLT){
- supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
- }
- },
-
- // private
- hideAction : function(){
- this.visible = false;
- if(this.useDisplay === true){
- this.setDisplayed(false);
- }else{
- this.setLeftTop(-10000,-10000);
- }
- },
-
- // overridden Element method
- setVisible : function(v, a, d, c, e){
- if(v){
- this.showAction();
- }
- if(a && v){
- var cb = function(){
- this.sync(true);
- if(c){
- c();
- }
- }.createDelegate(this);
- supr.setVisible.call(this, true, true, d, cb, e);
- }else{
- if(!v){
- this.hideUnders(true);
- }
- var cb = c;
- if(a){
- cb = function(){
- this.hideAction();
- if(c){
- c();
- }
- }.createDelegate(this);
- }
- supr.setVisible.call(this, v, a, d, cb, e);
- if(v){
- this.sync(true);
- }else if(!a){
- this.hideAction();
- }
- }
- },
-
- storeXY : function(xy){
- delete this.lastLT;
- this.lastXY = xy;
- },
-
- storeLeftTop : function(left, top){
- delete this.lastXY;
- this.lastLT = [left, top];
- },
-
- // private
- beforeFx : function(){
- this.beforeAction();
- return Roo.Layer.superclass.beforeFx.apply(this, arguments);
- },
-
- // private
- afterFx : function(){
- Roo.Layer.superclass.afterFx.apply(this, arguments);
- this.sync(this.isVisible());
- },
-
- // private
- beforeAction : function(){
- if(!this.updating && this.shadow){
- this.shadow.hide();
- }
- },
-
- // overridden Element method
- setLeft : function(left){
- this.storeLeftTop(left, this.getTop(true));
- supr.setLeft.apply(this, arguments);
- this.sync();
- },
-
- setTop : function(top){
- this.storeLeftTop(this.getLeft(true), top);
- supr.setTop.apply(this, arguments);
- this.sync();
- },
-
- setLeftTop : function(left, top){
- this.storeLeftTop(left, top);
- supr.setLeftTop.apply(this, arguments);
- this.sync();
- },
-
- setXY : function(xy, a, d, c, e){
- this.fixDisplay();
- this.beforeAction();
- this.storeXY(xy);
- var cb = this.createCB(c);
- supr.setXY.call(this, xy, a, d, cb, e);
- if(!a){
- cb();
- }
- },
-
- // private
- createCB : function(c){
- var el = this;
- return function(){
- el.constrainXY();
- el.sync(true);
- if(c){
- c();
- }
- };
- },
-
- // overridden Element method
- setX : function(x, a, d, c, e){
- this.setXY([x, this.getY()], a, d, c, e);
- },
-
- // overridden Element method
- setY : function(y, a, d, c, e){
- this.setXY([this.getX(), y], a, d, c, e);
- },
-
- // overridden Element method
- setSize : function(w, h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setSize.call(this, w, h, a, d, cb, e);
- if(!a){
- cb();
- }
- },
-
- // overridden Element method
- setWidth : function(w, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setWidth.call(this, w, a, d, cb, e);
- if(!a){
- cb();
- }
- },
-
- // overridden Element method
- setHeight : function(h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setHeight.call(this, h, a, d, cb, e);
- if(!a){
- cb();
- }
- },
-
- // overridden Element method
- setBounds : function(x, y, w, h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- if(!a){
- this.storeXY([x, y]);
- supr.setXY.call(this, [x, y]);
- supr.setSize.call(this, w, h, a, d, cb, e);
- cb();
- }else{
- supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
- }
- return this;
- },
-
- /**
- * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
- * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
- * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
- * @param {Number} zindex The new z-index to set
- * @return {this} The Layer
- */
- setZIndex : function(zindex){
- this.zindex = zindex;
- this.setStyle("z-index", zindex + 2);
- if(this.shadow){
- this.shadow.setZIndex(zindex + 1);
- }
- if(this.shim){
- this.shim.setStyle("z-index", zindex);
- }
- }
-});
-})();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
/**
* A simple class that renders text directly into a toolbar.
* @constructor
* Creates a new TextItem
- * @param {String} text
+ * @cfg {string} text
*/
Roo.Toolbar.TextItem = function(cfg){
var text = cfg || "";
Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
/**
- * @cfg {Boolean} text Text to show on item.
+ * @cfg {String} text Text to show on item.
*/
text : '',
}
this.el = ct.createChild(cfg, position);
}
+ },
+ /*
+ * setHTML
+ * @param {String} html update the Contents of the element.
+ */
+ setHTML : function(html)
+ {
+ this.fieldEl.dom.innerHTML = html;
}
});/*
// private - clean the leading white space
cleanLeadingSpace : function(e)
{
- this.setValue((this.getValue() + '').replace(/^\s+/,''));
+ if ( this.inputType == 'file') {
+ return;
+ }
+
+ this.setValue((this.getValue() + '').replace(/^\s+/,''));
},
/**
* Resets the current field value to the originally-loaded value and clears any validation messages.
* Create a new DateField
* @param {Object} config
*/
-Roo.form.DateField = function(config){
+Roo.form.DateField = function(config)
+{
Roo.form.DateField.superclass.constructor.call(this, config);
this.addEvents({
return String(this.getValue()) !== String(this.startValue);
+ },
+ // @overide
+ cleanLeadingSpace : function(e)
+ {
+ return;
}
+
});/*
* Based on:
* Ext JS Library 1.1.1
// element that contains real text value.. (when hidden is used..)
// private
- onRender : function(ct, position){
+ onRender : function(ct, position)
+ {
Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
- if(this.hiddenName){
+
+ if(this.hiddenName){
this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
'before', true);
this.hiddenField.value =
}
+
if(Roo.isGecko){
this.el.dom.setAttribute('autocomplete', 'off');
}
}
this.view = new Roo.View(this.innerList, this.tpl, {
- singleSelect:true, store: this.store, selectedClass: this.selectedClass
+ singleSelect:true,
+ store: this.store,
+ selectedClass: this.selectedClass
});
this.view.on('click', this.onViewClick, this);
this.view.select(match);
var sn = Roo.get(this.view.getSelectedNodes()[0]);
sn.scrollIntoView(sn.dom.parentNode, false);
- }
+ }
/**
* @cfg {Boolean} grow
* @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
*/
hiddenName : false,
-
+ /**
+ * @cfg {String} seperator The value seperator normally ','
+ */
+ seperator : ',',
// private the array of items that are displayed..
items : false,
// give fake names to child combo;
this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
- this.combo.name = this.name? (this.name+'-subcombo') : this.name;
+ this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
this.combo = Roo.factory(this.combo, Roo.form);
this.combo.onRender(ct, position);
{
var valueField = this.combo.valueField;
var displayField = this.combo.displayField;
+
if (this.items.indexOfKey(rec[valueField]) > -1) {
//console.log("GOT " + rec.data.id);
return;
this.items.each(function(f) {
ar.push(f.data[idField]);
-
});
- this.hiddenEl.dom.value = ar.join(',');
+ this.hiddenEl.dom.value = ar.join(this.seperator);
this.validate();
},
},
setValue: function(v) // not a valid action - must use addItems..
{
-
- this.reset();
-
-
+ this.reset();
+
if (this.store.isLocal && (typeof(v) == 'string')) {
// then we can use the store to find the values..
// comma seperated at present.. this needs to allow JSON based encoding..
this.hiddenEl.value = v;
var v_ar = [];
- Roo.each(v.split(','), function(k) {
+ Roo.each(v.split(this.seperator), function(k) {
Roo.log("CHECK " + this.valueField + ',' + k);
var li = this.store.query(this.valueField, k);
if (!li.length) {
if (typeof(v) == 'object' ) {
// then let's assume it's an array of objects..
Roo.each(v, function(l) {
- this.addItem(l);
+ var add = l;
+ if (typeof(l) == 'string') {
+ add = {};
+ add[this.valueField] = l;
+ add[this.displayField] = l
+ }
+ this.addItem(add);
}, this);
}
dv = typeof(dv) != 'string' ? '' : dv;
- var keys = kv.split(',');
- var display = dv.split(',');
+ var keys = kv.split(this.seperator);
+ var display = dv.split(this.seperator);
for (var i = 0 ; i < keys.length; i++) {
-
add = {};
add[this.valueField] = keys[i];
add[this.displayField] = display[i];
originalValue.push(d[i][this.valueField]);
}
- return String(this.getValue()) !== String(originalValue.join(','));
+ return String(this.getValue()) !== String(originalValue.join(this.seperator));
}
}
}
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011 Alan Knowles
+ *
+ * License - LGPL
+ */
+
+
+/**
+ * @class Roo.form.ComboNested
+ * @extends Roo.form.ComboBox
+ * A combobox for that allows selection of nested items in a list,
+ * eg.
+ *
+ * Book
+ * -> red
+ * -> green
+ * Table
+ * -> square
+ * ->red
+ * ->green
+ * -> rectangle
+ * ->green
+ *
+ *
+ * @constructor
+ * Create a new ComboNested
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboNested = function(config){
+ Roo.form.ComboCheck.superclass.constructor.call(this, config);
+ // should verify some data...
+ // like
+ // hiddenName = required..
+ // displayField = required
+ // valudField == required
+ var req= [ 'hiddenName', 'displayField', 'valueField' ];
+ var _t = this;
+ Roo.each(req, function(e) {
+ if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+ throw "Roo.form.ComboNested : missing value for: " + e;
+ }
+ });
+
+
+};
+
+Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
+
+ /*
+ * @config {Number} max Number of columns to show
+ */
+
+ maxColumns : 3,
+
+ list : null, // the outermost div..
+ innerLists : null, // the
+ views : null,
+ stores : null,
+ // private
+ loadingChildren : false,
+
+ onRender : function(ct, position)
+ {
+ Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
+
+ if(this.hiddenName){
+ this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
+ 'before', true);
+ this.hiddenField.value =
+ this.hiddenValue !== undefined ? this.hiddenValue :
+ this.value !== undefined ? this.value : '';
+
+ // prevent input submission
+ this.el.dom.removeAttribute('name');
+
+
+ }
+
+ if(Roo.isGecko){
+ this.el.dom.setAttribute('autocomplete', 'off');
+ }
+
+ var cls = 'x-combo-list';
+
+ this.list = new Roo.Layer({
+ shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+ });
+
+ var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
+ this.list.setWidth(lw);
+ this.list.swallowEvent('mousewheel');
+ this.assetHeight = 0;
+
+ if(this.title){
+ this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+ this.assetHeight += this.header.getHeight();
+ }
+ this.innerLists = [];
+ this.views = [];
+ this.stores = [];
+ for (var i =0 ; i < this.maxColumns; i++) {
+ this.onRenderList( cls, i);
+ }
+
+ // always needs footer, as we are going to have an 'OK' button.
+ this.footer = this.list.createChild({cls:cls+'-ft'});
+ this.pageTb = new Roo.Toolbar(this.footer);
+ var _this = this;
+ this.pageTb.add( {
+
+ text: 'Done',
+ handler: function()
+ {
+ _this.collapse();
+ }
+ });
+
+ if ( this.allowBlank && !this.disableClear) {
+
+ this.pageTb.add(new Roo.Toolbar.Fill(), {
+ cls: 'x-btn-icon x-btn-clear',
+ text: ' ',
+ handler: function()
+ {
+ _this.collapse();
+ _this.clearValue();
+ _this.onSelect(false, -1);
+ }
+ });
+ }
+ if (this.footer) {
+ this.assetHeight += this.footer.getHeight();
+ }
+
+ },
+ onRenderList : function ( cls, i)
+ {
+
+ var lw = Math.floor(
+ ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+ );
+
+ this.list.setWidth(lw); // default to '1'
+
+ var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
+ //il.on('mouseover', this.onViewOver, this, { list: i });
+ //il.on('mousemove', this.onViewMove, this, { list: i });
+ il.setWidth(lw);
+ il.setStyle({ 'overflow-x' : 'hidden'});
+
+ if(!this.tpl){
+ this.tpl = new Roo.Template({
+ html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
+ isEmpty: function (value, allValues) {
+ //Roo.log(value);
+ var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
+ return dl ? 'has-children' : 'no-children'
+ }
+ });
+ }
+
+ var store = this.store;
+ if (i > 0) {
+ store = new Roo.data.SimpleStore({
+ //fields : this.store.reader.meta.fields,
+ reader : this.store.reader,
+ data : [ ]
+ });
+ }
+ this.stores[i] = store;
+
+ var view = this.views[i] = new Roo.View(
+ il,
+ this.tpl,
+ {
+ singleSelect:true,
+ store: store,
+ selectedClass: this.selectedClass
+ }
+ );
+ view.getEl().setWidth(lw);
+ view.getEl().setStyle({
+ position: i < 1 ? 'relative' : 'absolute',
+ top: 0,
+ left: (i * lw ) + 'px',
+ display : i > 0 ? 'none' : 'block'
+ });
+ view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
+ view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
+ //view.on('click', this.onViewClick, this, { list : i });
+
+ store.on('beforeload', this.onBeforeLoad, this);
+ store.on('load', this.onLoad, this, { list : i});
+ store.on('loadexception', this.onLoadException, this);
+
+ // hide the other vies..
+
+
+
+ },
+
+ restrictHeight : function()
+ {
+ var mh = 0;
+ Roo.each(this.innerLists, function(il,i) {
+ var el = this.views[i].getEl();
+ el.dom.style.height = '';
+ var inner = el.dom;
+ var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
+ // only adjust heights on other ones..
+ mh = Math.max(h, mh);
+ if (i < 1) {
+
+ el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+ il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+
+ }
+
+
+ }, this);
+
+ this.list.beginUpdate();
+ this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
+ this.list.alignTo(this.el, this.listAlign);
+ this.list.endUpdate();
+
+ },
+
+
+ // -- store handlers..
+ // private
+ onBeforeLoad : function()
+ {
+ if(!this.hasFocus){
+ return;
+ }
+ this.innerLists[0].update(this.loadingText ?
+ '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+ this.restrictHeight();
+ this.selectedIndex = -1;
+ },
+ // private
+ onLoad : function(a,b,c,d)
+ {
+ if (!this.loadingChildren) {
+ // then we are loading the top level. - hide the children
+ for (var i = 1;i < this.views.length; i++) {
+ this.views[i].getEl().setStyle({ display : 'none' });
+ }
+ var lw = Math.floor(
+ ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+ );
+
+ this.list.setWidth(lw); // default to '1'
+
+
+ }
+ if(!this.hasFocus){
+ return;
+ }
+
+ if(this.store.getCount() > 0) {
+ this.expand();
+ this.restrictHeight();
+ } else {
+ this.onEmptyResults();
+ }
+
+ if (!this.loadingChildren) {
+ this.selectActive();
+ }
+ /*
+ this.stores[1].loadData([]);
+ this.stores[2].loadData([]);
+ this.views
+ */
+
+ //this.el.focus();
+ },
+
+
+ // private
+ onLoadException : function()
+ {
+ this.collapse();
+ Roo.log(this.store.reader.jsonData);
+ if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+ Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+ }
+
+
+ },
+ // no cleaning of leading spaces on blur here.
+ cleanLeadingSpace : function(e) { },
+
+
+ onSelectChange : function (view, sels, opts )
+ {
+ var ix = view.getSelectedIndexes();
+
+ if (opts.list > this.maxColumns - 2) {
+ if (view.store.getCount()< 1) {
+ this.views[opts.list ].getEl().setStyle({ display : 'none' });
+
+ } else {
+ if (ix.length) {
+ // used to clear ?? but if we are loading unselected
+ this.setFromData(view.store.getAt(ix[0]).data);
+ }
+
+ }
+
+ return;
+ }
+
+ if (!ix.length) {
+ // this get's fired when trigger opens..
+ // this.setFromData({});
+ var str = this.stores[opts.list+1];
+ str.data.clear(); // removeall wihtout the fire events..
+ return;
+ }
+
+ var rec = view.store.getAt(ix[0]);
+
+ this.setFromData(rec.data);
+ this.fireEvent('select', this, rec, ix[0]);
+
+ var lw = Math.floor(
+ (
+ (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
+ ) / this.maxColumns
+ );
+ this.loadingChildren = true;
+ this.stores[opts.list+1].loadDataFromChildren( rec );
+ this.loadingChildren = false;
+ var dl = this.stores[opts.list+1]. getTotalCount();
+
+ this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
+
+ this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
+ for (var i = opts.list+2; i < this.views.length;i++) {
+ this.views[i].getEl().setStyle({ display : 'none' });
+ }
+
+ this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
+ this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
+
+ if (this.isLoading) {
+ // this.selectActive(opts.list);
+ }
+
+ },
+
+
+
+
+ onDoubleClick : function()
+ {
+ this.collapse(); //??
+ },
+
+
+
+
+
+ // private
+ recordToStack : function(store, prop, value, stack)
+ {
+ var cstore = new Roo.data.SimpleStore({
+ //fields : this.store.reader.meta.fields, // we need array reader.. for
+ reader : this.store.reader,
+ data : [ ]
+ });
+ var _this = this;
+ var record = false;
+ var srec = false;
+ if(store.getCount() < 1){
+ return false;
+ }
+ store.each(function(r){
+ if(r.data[prop] == value){
+ record = r;
+ srec = r;
+ return false;
+ }
+ if (r.data.cn && r.data.cn.length) {
+ cstore.loadDataFromChildren( r);
+ var cret = _this.recordToStack(cstore, prop, value, stack);
+ if (cret !== false) {
+ record = cret;
+ srec = r;
+ return false;
+ }
+ }
+
+ return true;
+ });
+ if (record == false) {
+ return false
+ }
+ stack.unshift(srec);
+ return record;
+ },
+
+ /*
+ * find the stack of stores that match our value.
+ *
+ *
+ */
+
+ selectActive : function ()
+ {
+ // if store is not loaded, then we will need to wait for that to happen first.
+ var stack = [];
+ this.recordToStack(this.store, this.valueField, this.getValue(), stack);
+ for (var i = 0; i < stack.length; i++ ) {
+ this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
+ }
+
+ }
+
+
+
+
+
+
});/*
* Based on:
* Ext JS Library 1.1.1
st = '<style type="text/css">' +
'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
'</style>';
- } else {
- st = '<style type="text/css">' +
- this.stylesheets +
- '</style>';
+ } else {
+ for (var i in this.stylesheets) {
+ st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+ }
+
}
st += '<style type="text/css">' +
//<style type="text/css">' +
//'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
//'</style>' +
- ' </head><body class="' + cls + '"></body></html>';
+ ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
},
// private
html = this.cleanHtml(html);
// fix up the special chars.. normaly like back quotes in word...
// however we do not want to do this with chinese..
- html = html.replace(/([\x80-\uffff])/g, function (a, b) {
- var cc = b.charCodeAt();
- if (
+ html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+
+ var cc = match.charCodeAt();
+
+ // Get the character value, handling surrogate pairs
+ if (match.length == 2) {
+ // It's a surrogate pair, calculate the Unicode code point
+ var high = match.charCodeAt(0) - 0xD800;
+ var low = match.charCodeAt(1) - 0xDC00;
+ cc = (high * 0x400) + low + 0x10000;
+ } else if (
(cc >= 0x4E00 && cc < 0xA000 ) ||
(cc >= 0x3400 && cc < 0x4E00 ) ||
(cc >= 0xf900 && cc < 0xfb00 )
) {
- return b;
- }
- return "&#"+cc+";"
+ return match;
+ }
+
+ // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+ return "&#" + cc + ";";
+
+
});
+
+
+
if(this.owner.fireEvent('beforesync', this, html) !== false){
this.el.dom.value = html;
this.owner.fireEvent('sync', this, html);
insertTag : function(tg)
{
// could be a bit smarter... -> wrap the current selected tRoo..
- if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+ if (tg.toLowerCase() == 'span' ||
+ tg.toLowerCase() == 'code' ||
+ tg.toLowerCase() == 'sup' ||
+ tg.toLowerCase() == 'sub'
+ ) {
range = this.createRange(this.getSelection());
var wrappingNode = this.doc.createElement(tg.toLowerCase());
var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
+ // spans with no attributes - just remove them..
+ if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
+ remove_keep_children = true;
+ }
+
// remove <a name=....> as rendering on yahoo mailer is borked with this.
// this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
}
if (!node.attributes || !node.attributes.length) {
+
+
+
+
this.cleanUpChildren(node);
return;
}
if (v.match(/^#/)) {
return;
}
+ if (v.match(/^\{/)) { // allow template editing.
+ return;
+ }
// Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
node.removeAttribute(n);
if (a.name == 'class') {
if (a.value.match(/^Mso/)) {
- node.className = '';
+ node.removeAttribute('class');
}
if (a.value.match(/^body$/)) {
- node.className = '';
+ node.removeAttribute('class');
}
continue;
}
node.parentNode.removeChild(node);
return;
}
-
+ //Roo.log(node.tagName);
// remove - but keep children..
- if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+ if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+ //Roo.log('-- removed');
while (node.childNodes.length) {
var cn = node.childNodes[0];
node.removeChild(cn);
node.parentNode.insertBefore(cn, node);
+ // move node to parent - and clean it..
+ this.cleanWord(cn);
}
node.parentNode.removeChild(node);
- this.iterateChildren(node, this.cleanWord);
+ /// no need to iterate chidlren = it's got none..
+ //this.iterateChildren(node, this.cleanWord);
return;
}
// clean styles
Roo.HtmlEditorCore.swapCodes =[
- [ 8211, "--" ],
- [ 8212, "--" ],
+ [ 8211, "–" ],
+ [ 8212, "—" ],
[ 8216, "'" ],
[ 8217, "'" ],
[ 8220, '"' ],
["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
["pre"],[ "code"],
["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
- ['div'],['span']
+ ['div'],['span'],
+ ['sup'],['sub']
],
cleanStyles : [
var c = Roo.get(editorcore.doc.body);
c.select('[class]').each(function(s) {
- s.dom.className = '';
+ s.dom.removeAttribute('class');
});
+ editorcore.cleanWord();
editorcore.syncValue();
},
tabIndex:-1
return valid;
},
-
+ /**
+ * Returns array of invalid form fields.
+ * @return Array
+ */
+
+ invalidFields : function()
+ {
+ var ret = [];
+ this.items.each(function(f){
+ if(f.validate()){
+ return;
+ }
+ ret.push(f);
+
+ });
+
+ return ret;
+ },
+
+
/**
* DEPRICATED Returns true if any fields in this form have changed since their original load.
* @return Boolean
return this;
},
-
+
/**
* Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
* they are returned as an array.
}, this);
}
+ // use formdata
+ if (typeof(FormData) != 'undefined' && asString !== true) {
+ // this relies on a 'recent' version of chrome apparently...
+ try {
+ var fd = (new FormData(this.el.dom)).entries();
+ var ret = {};
+ var ent = fd.next();
+ while (!ent.done) {
+ ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+ ent = fd.next();
+ };
+ return ret;
+ } catch(e) {
+
+ }
+
+ }
var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
this.getEl().setStyle("outline", "0px none");
this.getEl().unselectable();
if (this.dragGroup) {
- this.setDraggable(this.dragGroup.split(","));
+ this.setDraggable(this.dragGroup.split(","));
}
if (this.dropGroup) {
- this.setDroppable(this.dropGroup.split(","));
+ this.setDroppable(this.dropGroup.split(","));
}
if (this.deletable) {
this.setDeletable();
* @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
* @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
* @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
+ * @cfg {String} style Extra style to add to the content panel
* @constructor
* Create a new ContentPanel.
{tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
}
}
+
+
this.closable = false;
this.loaded = false;
this.active = false;
/**
* @cfg {String} ddGroup - drag drop group.
*/
+ /**
+ * @cfg {String} dragGroup - drag group (?? not sure if needed.)
+ */
/**
* @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
/**
* @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
+ */
+ /**
+ * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
*/
/**
/**
* @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
*/
+
+
+ /**
+ * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
+ * %0 is replaced with the number of selected rows.
+ */
+ ddText : "{0} selected row{1}",
+
+
/**
* Called once after all setup has been completed and the grid is ready to be rendered.
* @return {Roo.grid.Grid} this
return this;
},
- /**
- * Reconfigures the grid to use a different Store and Column Model.
- * The View will be bound to the new objects and refreshed.
- * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
- * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
- */
+ /**
+ * Reconfigures the grid to use a different Store and Column Model.
+ * The View will be bound to the new objects and refreshed.
+ * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+ * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
+ */
reconfigure : function(dataSource, colModel){
if(this.loadMask){
this.loadMask.destroy();
this.colModel = colModel;
this.view.refresh(true);
},
-
+ /**
+ * addColumns
+ * Add's a column, default at the end..
+
+ * @param {int} position to add (default end)
+ * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
+ */
+ addColumns : function(pos, ar)
+ {
+
+ for (var i =0;i< ar.length;i++) {
+ var cfg = ar[i];
+ cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+ this.cm.lookup[cfg.id] = cfg;
+ }
+
+
+ if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+ pos = this.cm.config.length; //this.cm.config.push(cfg);
+ }
+ pos = Math.max(0,pos);
+ ar.unshift(0);
+ ar.unshift(pos);
+ this.cm.config.splice.apply(this.cm.config, ar);
+
+
+
+ this.view.generateRules(this.cm);
+ this.view.refresh(true);
+
+ },
+
+
+
+
// private
onKeyDown : function(e){
this.fireEvent("keydown", e);
getView : function(){
if(!this.view){
this.view = new Roo.grid.GridView(this.viewConfig);
+ this.relayEvents(this.view, [
+ "beforerowremoved", "beforerowsinserted",
+ "beforerefresh", "rowremoved",
+ "rowsinserted", "rowupdated" ,"refresh"
+ ]);
}
return this.view;
},
/**
* Called to get grid's drag proxy text, by default returns this.ddText.
+ * Override this to put something different in the dragged text.
* @return {String}
*/
getDragDropText : function(){
return String.format(this.ddText, count, count == 1 ? '' : 's');
}
});
-/**
- * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
- * %0 is replaced with the number of selected rows.
- * @type String
- */
-Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
);
*/
if(ctop < stop){
- c.scrollTop = ctop;
+ c.scrollTop = ctop;
//Roo.log("set scrolltop to ctop DISABLE?");
}else if(cbot > sbot){
//Roo.log("set scrolltop to cbot-ch");
}
},
- layout : function(initialRender, is2ndPass){
+ layout : function(initialRender, is2ndPass)
+ {
var g = this.grid;
var auto = g.autoHeight;
var scrollOffset = 16;
}
}
+ if (sm.getSelections && sm.getSelections().length < 1) {
+ return false;
+ }
+
+ // before it used to all dragging of unseleted... - now we dont do that.
if(rowIndex !== false){
// if editorgrid..
grid: this.grid,
ddel: this.ddel,
rowIndex: rowIndex,
- selections:sm.getSelections ? sm.getSelections() : (
- sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
- )
+ selections: sm.getSelections ? sm.getSelections() : (
+ sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
};
}
return false;
},
-
+
+
onInitDrag : function(e){
var data = this.dragData;
this.ddel.innerHTML = this.grid.getDragDropText();