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 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;
+ 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;
}
- 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
// 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
// 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.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..
}
}
+});/*
+ * 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
+ 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, this, {list : i });
+ view.on('dblclick', this.onDoubleClick, this, {list : i });
+ //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..
+
+
+
+ },
+ onResize : function() {},
+
+ 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(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
+ // only adjust heights on other ones..
+ if (i < 1) {
+
+ el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+ il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+ mh = Math.max(el.getHeight(), mh);
+ }
+
+
+ }, 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.hasFocus){
+ return;
+ }
+
+ if(this.store.getCount() > 0) {
+ this.expand();
+ this.restrictHeight();
+ } else {
+ this.onEmptyResults();
+ }
+ /*
+ 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);
+ }
+
+
+ } ,
+
+
+
+ onSelectChange : function (view, sels, opts )
+ {
+ var ix = view.getSelectedIndexes();
+
+ if (opts.list > this.maxColumns - 2) {
+
+ this.setFromData(ix.length ? view.store.getAt(ix[0]).data : {});
+ return;
+ }
+
+ if (!ix.length) {
+ this.setFromData({});
+ var str = this.stores[opts.list+1];
+ str.removeAll();
+ return;
+ }
+
+ var rec = view.store.getAt(ix[0]);
+ if (!this.isLoading) {
+ this.setFromData(rec.data);
+ }
+
+
+ var lw = Math.floor(
+ ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+ );
+
+ this.stores[opts.list+1].loadDataFromChildren( rec );
+ 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' });
+ 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(); //??
+ },
+
+
+
+ findRecord : function (prop,value)
+ {
+ return this.findRecordInStore(this.store, prop,value);
+ },
+
+ // private
+ findRecordInStore : function(store, prop, value)
+ {
+ 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;
+ if(store.getCount() > 0){
+ store.each(function(r){
+ if(r.data[prop] == value){
+ record = r;
+ return false;
+ }
+ if (r.data.cn && r.data.cn.length) {
+ cstore.loadDataFromChildren( r);
+ var cret = _this.findRecordInStore(cstore, prop, value);
+ if (cret !== false) {
+ record = cret;
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }
+ return record;
+ },
+
+ function selectActive()
+
+
+
+
});/*
* Based on:
* Ext JS Library 1.1.1
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 (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
["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 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) {
+ 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;
+ }
var fs = Roo.lib.Ajax.serializeForm(this.el.dom);