document.execCommand("BackgroundImageCache", false, true);
}catch(e){}
}
-
+
Roo.apply(Roo, {
/**
* True if the browser is in strict mode
i 05 Minutes with leading zeros
s 01 Seconds, with leading zeros
O -0600 Difference to Greenwich time (GMT) in hours
+ P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
T CST Timezone setting of the machine running the code
Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
</pre>
return "String.leftPad(this.getSeconds(), 2, '0') + ";
case "O":
return "this.getGMTOffset() + ";
+ case "P":
+ return "this.getGMTColonOffset() + ";
case "T":
return "this.getTimezone() + ";
case "Z":
" (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
].join(""),
s:"([+\-]\\d{4})"};
+ case "P":
+ return {g:1,
+ c:[
+ "o = results[", currentGroup, "];\n",
+ "var sn = o.substring(0,1);\n",
+ "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
+ "var mn = o.substring(4,6) % 60;\n",
+ "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
+ " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
+ ].join(""),
+ s:"([+\-]\\d{4})"};
case "T":
return {g:0,
c:null,
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
};
+/**
+ * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
+ * @return {String} 2-characters representing hours and 2-characters representing minutes
+ * seperated by a colon and prefixed with + or - (e.g. '-06:00')
+ */
+Date.prototype.getGMTColonOffset = function() {
+ return (this.getTimezoneOffset() > 0 ? "-" : "+")
+ + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+ + ":"
+ + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
+}
+
/**
* Get the numeric day number of the year, adjusted for leap year.
* @return {Number} 0 through 364 (365 in leap years)
break;
}
return d;
-};/*
+};
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
*/
(function() {
-
+ /**
+ * @class Roo.lib.Ajax
+ *
+ */
Roo.lib.Ajax = {
+ /**
+ * @static
+ */
request : function(method, uri, cb, data, options) {
if(options){
var hs = options.headers;
* @param {String} msgCls (optional) A css class to apply to the msg element
* @return {Element} The mask element
*/
- mask : function(msg, msgCls){
+ mask : function(msg, msgCls)
+ {
if(this.getStyle("position") == "static"){
this.setStyle("position", "relative");
}
}
this.addClass("x-masked");
this._mask.setDisplayed(true);
+
+ // we wander
+ var z = 0;
+ var dom = this.dom
+ while (dom && dom.style) {
+ if (!isNaN(parseInt(dom.style.zIndex))) {
+ z = Math.max(z, parseInt(dom.style.zIndex));
+ }
+ dom = dom.parentNode;
+ }
+
+
if(typeof msg == 'string'){
if(!this._maskMsg){
this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
mm.dom.firstChild.innerHTML = msg;
mm.setDisplayed(true);
mm.center(this);
+ mm.setStyle('z-index', z + 102);
}
if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
this._mask.setHeight(this.getHeight());
}
+ this._mask.setStyle('z-index', z + 100);
+
return this._mask;
},
*/
/**
+ * Global Ajax request class.
+ *
* @class Roo.Ajax
* @extends Roo.data.Connection
- * Global Ajax request class.
- *
- * @instanceOf Roo.data.Connection
+ * @static
+ *
+ * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
+ * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
+ * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
+ * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
+ * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+ * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
+ * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
*/
Roo.Ajax = new Roo.data.Connection({
// fix up the docs
-
/**
- * fix up scoping
* @scope Roo.Ajax
- */
-
- /**
- * @cfg {String} url @hide
- */
- /**
- * @cfg {Object} extraParams @hide
- */
- /**
- * @cfg {Object} defaultHeaders @hide
- */
- /**
- * @cfg {String} method (Optional) @hide
- */
- /**
- * @cfg {Number} timeout (Optional) @hide
- */
- /**
- * @cfg {Boolean} autoAbort (Optional) @hide
- */
-
- /**
- * @cfg {Boolean} disableCaching (Optional) @hide
- */
-
- /**
- * @property disableCaching
- * True to add a unique cache-buster param to GET requests. (defaults to true)
- * @type Boolean
- */
- /**
- * @property url
- * The default URL to be used for requests to the server. (defaults to undefined)
- * @type String
- */
- /**
- * @property extraParams
- * An object containing properties which are used as
- * extra parameters to each request made by this object. (defaults to undefined)
- * @type Object
- */
- /**
- * @property defaultHeaders
- * An object containing request headers which are added to each request made by this object. (defaults to undefined)
- * @type Object
- */
- /**
- * @property method
- * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
- * @type String
- */
- /**
- * @property timeout
- * The timeout in milliseconds to be used for requests. (defaults to 30000)
- * @type Number
- */
-
- /**
- * @property autoAbort
- * Whether a new request should abort any pending requests. (defaults to false)
- * @type Boolean
+ * @type {Boolear}
*/
autoAbort : false,
/**
* Serialize the passed form into a url encoded string
+ * @scope Roo.Ajax
* @param {String/HTMLElement} form
* @return {String}
*/
this.modified[name] = this.data[name];
}
this.data[name] = value;
- if(!this.editing){
+ if(!this.editing && this.store){
this.store.afterEdit(this);
}
},
}
// if data returned failure - throw an exception.
if (o.success === false) {
+ // show a message if no listener is registered.
+ if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
+ Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
+ }
+ // loadmask wil be hooked into this..
this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
return;
}
}
},
+
/**
* Loads data from a passed data block. A Reader which understands the format of the data
* must have been configured in the constructor.
}
this.fireEvent("update", this, record, Roo.data.Record.EDIT);
},
-
+
// private
afterReject : function(record){
this.modified.remove(record);
}
};
-// private
+/** @private */
Roo.Component.AUTO_ID = 1000;
Roo.extend(Roo.Component, Roo.util.Observable, {
/**
- * @property {Boolean} hidden
+ * @scope Roo.Component.prototype
+ * @type {Boolean}
* true if this component is hidden. Read-only.
*/
hidden : false,
/**
+ * @type {Boolean}
* true if this component is disabled. Read-only.
*/
disabled : false,
/**
+ * @type {Boolean}
* true if this component has been rendered. Read-only.
*/
rendered : false,
*/
hideMode: 'display',
- // private
+ /** @private */
ctype : "Roo.Component",
- /** @cfg {String} actionMode
+ /**
+ * @cfg {String} actionMode
* which property holds the element that used for hide() / show() / disable() / enable()
* default is 'el'
*/
actionMode : "el",
- // private
+ /** @private */
getActionEl : function(){
return this[this.actionMode];
},
return this;
},
- // private
+ /** @private */
// default function is not really useful
onRender : function(ct, position){
if(this.el){
}
},
- // private
+ /** @private */
getAutoCreate : function(){
var cfg = typeof this.autoCreate == "object" ?
this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
return cfg;
},
- // private
+ /** @private */
afterRender : Roo.emptyFn,
/**
}
},
- // private
+ /** @private */
beforeDestroy : function(){
},
- // private
+ /** @private */
onDestroy : function(){
},
return this;
},
- // private
+ /** @private */
blur : function(){
if(this.rendered){
this.el.blur();
/** @private */
this.addEvents({
- /**
- * @event beforeclick
- * Fires before a click is processed. Returns false to cancel the default action.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "beforeclick" : true,
- /**
- * @event click
- * Fires when a template node is clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "click" : true,
- /**
- * @event dblclick
- * Fires when a template node is double clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "dblclick" : true,
- /**
- * @event contextmenu
- * Fires when a template node is right clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "contextmenu" : true,
- /**
- * @event selectionchange
- * Fires when the selected nodes change.
- * @param {Roo.View} this
- * @param {Array} selections Array of the selected nodes
- */
- "selectionchange" : true,
-
- /**
- * @event beforeselect
- * Fires before a selection is made. If any handlers return false, the selection is cancelled.
- * @param {Roo.View} this
- * @param {HTMLElement} node The node to be selected
- * @param {Array} selections Array of currently selected nodes
- */
- "beforeselect" : true
- });
+ /**
+ * @event beforeclick
+ * Fires before a click is processed. Returns false to cancel the default action.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "beforeclick" : true,
+ /**
+ * @event click
+ * Fires when a template node is clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "click" : true,
+ /**
+ * @event dblclick
+ * Fires when a template node is double clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "dblclick" : true,
+ /**
+ * @event contextmenu
+ * Fires when a template node is right clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "contextmenu" : true,
+ /**
+ * @event selectionchange
+ * Fires when the selected nodes change.
+ * @param {Roo.View} this
+ * @param {Array} selections Array of the selected nodes
+ */
+ "selectionchange" : true,
+
+ /**
+ * @event beforeselect
+ * Fires before a selection is made. If any handlers return false, the selection is cancelled.
+ * @param {Roo.View} this
+ * @param {HTMLElement} node The node to be selected
+ * @param {Array} selections Array of currently selected nodes
+ */
+ "beforeselect" : true,
+ /**
+ * @event preparedata
+ * Fires on every row to render, to allow you to change the data.
+ * @param {Roo.View} this
+ * @param {Object} data to be rendered (change this)
+ */
+ "preparedata" : true
+ });
this.el.on({
"click": this.onClick,
/**
* @cfg {Boolean} multiSelect Allow multiple selection
*/
-
multiSelect : false,
/**
* @cfg {Boolean} singleSelect Allow single selection
*/
singleSelect: false,
+ /**
+ * @cfg {Boolean} toggleSelect - selecting
+ */
+ toggleSelect : false,
+
/**
* Returns the element this view is bound to.
* @return {Roo.Element}
}
for(var i = 0, len = records.length; i < len; i++){
var data = this.prepareData(records[i].data, i, records[i]);
+ this.fireEvent("preparedata", this, data, i, records[i]);
html[html.length] = t.apply(data);
}
this.el.update(html.join(""));
}
},
- onItemClick : function(item, index, e){
+ onItemClick : function(item, index, e)
+ {
if(this.fireEvent("beforeclick", this, index, item, e) === false){
return false;
}
+ if (this.toggleSelect) {
+ var m = this.isSelected(item) ? 'unselect' : 'select';
+ Roo.log(m);
+ var _t = this;
+ _t[m](item, true, false);
+ return true;
+ }
if(this.multiSelect || this.singleSelect){
if(this.multiSelect && e.shiftKey && this.lastSelection){
this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
for(var i = 0, len = nodeInfo.length; i < len; i++){
this.select(nodeInfo[i], true, true);
}
- } else{
- var node = this.getNode(nodeInfo);
- if(node && !this.isSelected(node)){
- if(!keepExisting){
- this.clearSelections(true);
- }
- if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
- Roo.fly(node).addClass(this.selectedClass);
- this.selections.push(node);
- if(!suppressEvent){
- this.fireEvent("selectionchange", this, this.selections);
- }
- }
+ return;
+ }
+ var node = this.getNode(nodeInfo);
+ if(!node || this.isSelected(node)){
+ return; // already selected.
+ }
+ if(!keepExisting){
+ this.clearSelections(true);
+ }
+ if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
+ Roo.fly(node).addClass(this.selectedClass);
+ this.selections.push(node);
+ if(!suppressEvent){
+ this.fireEvent("selectionchange", this, this.selections);
}
}
+
+
+ },
+ /**
+ * Unselects nodes.
+ * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+ * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
+ * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+ */
+ unselect : function(nodeInfo, keepExisting, suppressEvent)
+ {
+ if(nodeInfo instanceof Array){
+ Roo.each(this.selections, function(s) {
+ this.unselect(s, nodeInfo);
+ }, this);
+ return;
+ }
+ var node = this.getNode(nodeInfo);
+ if(!node || !this.isSelected(node)){
+ Roo.log("not selected");
+ return; // not selected.
+ }
+ // fireevent???
+ var ns = [];
+ Roo.each(this.selections, function(s) {
+ if (s == node ) {
+ Roo.fly(node).removeClass(this.selectedClass);
+
+ return;
+ }
+ ns.push(s);
+ },this);
+
+ this.selections= ns;
+ this.fireEvent("selectionchange", this, this.selections);
},
/**
* @param {DatePicker} this
* @param {Date} date The selected date
*/
- select: true
+ 'select': true,
+ /**
+ * @event monthchange
+ * Fires when the displayed month changes
+ * @param {DatePicker} this
+ * @param {Date} date The selected month
+ */
+ 'monthchange': true
});
if(this.handler){
},
// private
- update : function(date){
+ update : function(date)
+ {
var vd = this.activeDate;
this.activeDate = date;
if(vd && this.el){
return;
}
}
+
var days = date.getDaysInMonth();
var firstOfMonth = date.getFirstDateOfMonth();
var startingPos = firstOfMonth.getDay()-this.startDay;
}
this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
-
+ this.fireEvent('monthchange', this, date);
+
if(!this.internalRender){
var main = this.el.dom.firstChild;
var w = main.offsetWidth;
this.update.defer(10, this, [date]);
}
}
+
+
}
-});/*
+}); /*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
}
if(this.tabPosition != "bottom"){
- /** The body element that contains {@link Roo.TabPanelItem} bodies. +
- * @type Roo.Element
- */
- this.bodyEl = Roo.get(this.createBody(this.el.dom));
- this.el.addClass("x-tabs-top");
+ /** The body element that contains {@link Roo.TabPanelItem} bodies. +
+ * @type Roo.Element
+ */
+ this.bodyEl = Roo.get(this.createBody(this.el.dom));
+ this.el.addClass("x-tabs-top");
}
this.items = [];
this.cpad = this.el.getPadding("lr");
this.hiddenCount = 0;
+
+ // toolbar on the tabbar support...
+ if (this.toolbar) {
+ var tcfg = this.toolbar;
+ tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
+ this.toolbar = new Roo.Toolbar(tcfg);
+ if (Roo.isSafari) {
+ var tbl = tcfg.container.child('table', true);
+ tbl.setAttribute('width', '100%');
+ }
+
+ }
+
+
+
Roo.TabPanel.superclass.constructor.call(this);
};
Roo.extend(Roo.TabPanel, Roo.util.Observable, {
- /*
- *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
- */
+ /*
+ *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
+ */
tabPosition : "top",
- /*
- *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
- */
+ /*
+ *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
+ */
currentTabWidth : 0,
- /*
- *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
- */
+ /*
+ *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
+ */
minTabWidth : 40,
- /*
- *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
- */
+ /*
+ *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
+ */
maxTabWidth : 250,
- /*
- *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
- */
+ /*
+ *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
+ */
preferredTabWidth : 175,
- /*
- *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
- */
+ /*
+ *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
+ */
resizeTabs : false,
- /*
- *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
- */
+ /*
+ *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
+ */
monitorResize : true,
+ /*
+ *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
+ */
+ toolbar : false,
/**
* Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
* Basic Toolbar class.
* @constructor
* Creates a new Toolbar
- * @param {Object} config The config object
+ * @param {Object} container The config object
*/
Roo.Toolbar = function(container, buttons, config)
{
if (typeof(container) == 'object' && container.xtype) {
config = container;
container = config.container;
- buttons = config.buttons; // not really - use items!!
+ buttons = config.buttons || []; // not really - use items!!
}
var xitems = [];
if (config && config.items) {
if(container){
this.render(container);
}
+ this.xitems = xitems;
Roo.each(xitems, function(b) {
this.add(b);
}, this);
Roo.Toolbar.prototype = {
/**
- * @cfg {Roo.data.Store} items
- * array of button configs or elements to add
+ * @cfg {Array} items
+ * array of button configs or elements to add (will be converted to a MixedCollection)
*/
/**
fields : false,
/**
- * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
- * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
+ * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
+ * Note: the field should not have been rendered yet. For a field that has already been
+ * rendered, use {@link #addElement}.
* @param {Roo.form.Field} field
* @return {Roo.ToolbarItem}
*/
if(dlg.isVisible()){
dlg.fixedcenter = false;
}
+ // to big, make it scoll.
+ if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
+ bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
+ bodyEl.dom.style.overflowY = 'auto';
+ } else {
+ bodyEl.dom.style.height = '';
+ bodyEl.dom.style.overflowY = '';
+ }
+
dlg.setContentSize(w, bodyEl.getHeight());
if(dlg.isVisible()){
dlg.fixedcenter = true;
* @param {Object} config Configuration options
* @return {Roo.MessageBox} This message box
*/
- show : function(options){
+ show : function(options)
+ {
+
+ // this causes nightmares if you show one dialog after another
+ // especially on callbacks..
+
if(this.isVisible()){
+
this.hide();
+ Roo.log("Old Dialog Message:" + msgEl.innerHTML )
+ //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
+ //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
+
}
var d = this.getDialog();
opt = options;
* @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
* @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
* @cfg {Boolean} loader A TreeLoader for use with this TreePanel
+ * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
* @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
- * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
- * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
+ * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
+ * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
*
* @constructor
* @param {String/HTMLElement/Element} el The container element
/**
* Read-only. The id of the container element becomes this TreePanel's id.
*/
- this.id = this.el.id;
- this.addEvents({
+ this.id = this.el.id;
+ this.addEvents({
/**
* @event beforeload
* Fires before a node is loaded, return false to cancel
* @param {Node} node The node
*/
"beforechildrenrendered":true,
+ /**
+ * @event startdrag
+ * Fires when a node starts being dragged
+ * @param {Roo.tree.TreePanel} this
+ * @param {Roo.tree.TreeNode} node
+ * @param {event} e The raw browser event
+ */
+ "startdrag" : true,
/**
- * @event startdrag
- * Fires when a node starts being dragged
- * @param {Roo.tree.TreePanel} this
- * @param {Roo.tree.TreeNode} node
- * @param {event} e The raw browser event
- */
- "startdrag" : true,
- /**
- * @event enddrag
- * Fires when a drag operation is complete
- * @param {Roo.tree.TreePanel} this
- * @param {Roo.tree.TreeNode} node
- * @param {event} e The raw browser event
- */
- "enddrag" : true,
- /**
- * @event dragdrop
- * Fires when a dragged node is dropped on a valid DD target
- * @param {Roo.tree.TreePanel} this
- * @param {Roo.tree.TreeNode} node
- * @param {DD} dd The dd it was dropped on
- * @param {event} e The raw browser event
- */
- "dragdrop" : true,
- /**
- * @event beforenodedrop
- * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
- * passed to handlers has the following properties:<br />
- * <ul style="padding:5px;padding-left:16px;">
- * <li>tree - The TreePanel</li>
- * <li>target - The node being targeted for the drop</li>
- * <li>data - The drag data from the drag source</li>
- * <li>point - The point of the drop - append, above or below</li>
- * <li>source - The drag source</li>
- * <li>rawEvent - Raw mouse event</li>
- * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
- * to be inserted by setting them on this object.</li>
- * <li>cancel - Set this to true to cancel the drop.</li>
- * </ul>
- * @param {Object} dropEvent
- */
- "beforenodedrop" : true,
- /**
- * @event nodedrop
- * Fires after a DD object is dropped on a node in this tree. The dropEvent
- * passed to handlers has the following properties:<br />
- * <ul style="padding:5px;padding-left:16px;">
- * <li>tree - The TreePanel</li>
- * <li>target - The node being targeted for the drop</li>
- * <li>data - The drag data from the drag source</li>
- * <li>point - The point of the drop - append, above or below</li>
- * <li>source - The drag source</li>
- * <li>rawEvent - Raw mouse event</li>
- * <li>dropNode - Dropped node(s).</li>
- * </ul>
- * @param {Object} dropEvent
- */
- "nodedrop" : true,
- /**
- * @event nodedragover
- * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
- * passed to handlers has the following properties:<br />
- * <ul style="padding:5px;padding-left:16px;">
- * <li>tree - The TreePanel</li>
- * <li>target - The node being targeted for the drop</li>
- * <li>data - The drag data from the drag source</li>
- * <li>point - The point of the drop - append, above or below</li>
- * <li>source - The drag source</li>
- * <li>rawEvent - Raw mouse event</li>
- * <li>dropNode - Drop node(s) provided by the source.</li>
- * <li>cancel - Set this to true to signal drop not allowed.</li>
- * </ul>
- * @param {Object} dragOverEvent
- */
- "nodedragover" : true
+ * @event enddrag
+ * Fires when a drag operation is complete
+ * @param {Roo.tree.TreePanel} this
+ * @param {Roo.tree.TreeNode} node
+ * @param {event} e The raw browser event
+ */
+ "enddrag" : true,
+ /**
+ * @event dragdrop
+ * Fires when a dragged node is dropped on a valid DD target
+ * @param {Roo.tree.TreePanel} this
+ * @param {Roo.tree.TreeNode} node
+ * @param {DD} dd The dd it was dropped on
+ * @param {event} e The raw browser event
+ */
+ "dragdrop" : true,
+ /**
+ * @event beforenodedrop
+ * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
+ * passed to handlers has the following properties:<br />
+ * <ul style="padding:5px;padding-left:16px;">
+ * <li>tree - The TreePanel</li>
+ * <li>target - The node being targeted for the drop</li>
+ * <li>data - The drag data from the drag source</li>
+ * <li>point - The point of the drop - append, above or below</li>
+ * <li>source - The drag source</li>
+ * <li>rawEvent - Raw mouse event</li>
+ * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
+ * to be inserted by setting them on this object.</li>
+ * <li>cancel - Set this to true to cancel the drop.</li>
+ * </ul>
+ * @param {Object} dropEvent
+ */
+ "beforenodedrop" : true,
+ /**
+ * @event nodedrop
+ * Fires after a DD object is dropped on a node in this tree. The dropEvent
+ * passed to handlers has the following properties:<br />
+ * <ul style="padding:5px;padding-left:16px;">
+ * <li>tree - The TreePanel</li>
+ * <li>target - The node being targeted for the drop</li>
+ * <li>data - The drag data from the drag source</li>
+ * <li>point - The point of the drop - append, above or below</li>
+ * <li>source - The drag source</li>
+ * <li>rawEvent - Raw mouse event</li>
+ * <li>dropNode - Dropped node(s).</li>
+ * </ul>
+ * @param {Object} dropEvent
+ */
+ "nodedrop" : true,
+ /**
+ * @event nodedragover
+ * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
+ * passed to handlers has the following properties:<br />
+ * <ul style="padding:5px;padding-left:16px;">
+ * <li>tree - The TreePanel</li>
+ * <li>target - The node being targeted for the drop</li>
+ * <li>data - The drag data from the drag source</li>
+ * <li>point - The point of the drop - append, above or below</li>
+ * <li>source - The drag source</li>
+ * <li>rawEvent - Raw mouse event</li>
+ * <li>dropNode - Drop node(s) provided by the source.</li>
+ * <li>cancel - Set this to true to signal drop not allowed.</li>
+ * </ul>
+ * @param {Object} dragOverEvent
+ */
+ "nodedragover" : true
- });
- if(this.singleExpand){
+ });
+ if(this.singleExpand){
this.on("beforeexpand", this.restrictExpand, this);
- }
+ }
+ if (this.editor) {
+ this.editor.tree = this;
+ this.editor = Roo.factory(this.editor, Roo.tree);
+ }
+
+ if (this.selModel) {
+ this.selModel = Roo.factory(this.selModel, Roo.tree);
+ }
+
};
Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
rootVisible : true,
* @class Roo.tree.DefaultSelectionModel
* @extends Roo.util.Observable
* The default single selection for a TreePanel.
+ * @param {Object} cfg Configuration
*/
-Roo.tree.DefaultSelectionModel = function(){
+Roo.tree.DefaultSelectionModel = function(cfg){
this.selNode = null;
+
+
this.addEvents({
/**
* @event selectionchange
*/
"beforeselect" : true
});
+
+ Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
};
Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
* @class Roo.tree.MultiSelectionModel
* @extends Roo.util.Observable
* Multi selection for a TreePanel.
+ * @param {Object} cfg Configuration
*/
Roo.tree.MultiSelectionModel = function(){
this.selNodes = [];
*/
"selectionchange" : true
});
+ Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
+
};
Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
}
},
- renderElements : function(n, a, targetNode, bulkRender){
+ renderElements : function(n, a, targetNode, bulkRender)
+ {
// add some indent caching, this helps performance when rendering a large tree
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
var t = n.getOwnerTree();
var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
+ if (typeof(n.attributes.html) != 'undefined') {
+ txt = n.attributes.html;
+ }
var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
var cb = typeof a.checked == 'boolean';
var href = a.href ? a.href : Roo.isGecko ? "" : "#";
this.c1 = c1; this.c2 = c2;
}
}else{
- if(!this.wasLeaf){
+ // this changes non-leafs into leafs if they have no children.
+ // it's not very rational behaviour..
+
+ if(!this.wasLeaf && this.node.leaf){
Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
delete this.c1;
delete this.c2;
/**
* @cfg {Object} uiProviders (optional) An object containing properties which
*
- * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
+ * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
* specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
* <i>uiProvider</i> attribute of a returned child node is a string rather
* than a reference to a TreeNodeUI implementation, this that string value
},
// private
- createNode : function(attr){
+ createNode : function(attr)
+ {
// apply baseAttrs, nice idea Corey!
if(this.baseAttrs){
Roo.applyIf(attr, this.baseAttrs);
new Roo.tree.AsyncTreeNode(attr));
},
- processResponse : function(response, node, callback){
+ processResponse : function(response, node, callback)
+ {
var json = response.responseText;
try {
- var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
+ var o = Roo.decode(json);
+
+ if (!o.success) {
+ // it's a failure condition.
+ var a = response.argument;
+ this.fireEvent("loadexception", this, a.node, response);
+ Roo.log("Load failed - should have a handler really");
+ return;
+ }
+
if (this.root !== false) {
o = o[this.root];
}
this.fireEvent("load", this, a.node, response);
},
- handleFailure : function(response){
+ handleFailure : function(response)
+ {
+ // should handle failure better..
this.transId = false;
var a = response.argument;
this.fireEvent("loadexception", this, a.node, response);
* Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
* as the editor field.
* @constructor
- * @param {TreePanel} tree
- * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
+ * @param {Object} config (used to be the tree panel.)
+ * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
+ *
+ * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
+ * @cfg {Roo.form.TextField|Object} field The field configuration
+ *
+ *
*/
-Roo.tree.TreeEditor = function(tree, config){
+Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
+ var tree = config;
+ var field;
+ if (oldconfig) { // old style..
+ field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
+ } else {
+ // new style..
+ tree = config.tree;
+ config.field = config.field || {};
+ config.field.xtype = 'TextField';
+ field = Roo.factory(config.field, Roo.form);
+ }
config = config || {};
- var field = config.events ? config : new Roo.form.TextField(config);
- Roo.tree.TreeEditor.superclass.constructor.call(this, field);
+
+
+ this.addEvents({
+ /**
+ * @event beforenodeedit
+ * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
+ * false from the handler of this event.
+ * @param {Editor} this
+ * @param {Roo.tree.Node} node
+ */
+ "beforenodeedit" : true
+ });
+
+ //Roo.log(config);
+ Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
this.tree = tree;
this.maxWidth,
(td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
this.setSize(w, '');
+
+ return this.fireEvent('beforenodeedit', this, this.editNode);
+
},
// private
this.triggerEdit(node);
return false;
}
+ return true;
},
// private
this.value = v;
if(this.rendered){
this.el.dom.value = (v === null || v === undefined ? '' : v);
- this.validate();
+ this.validate();
}
},
* in order for a value to be mapped.
*/
valueField: undefined,
+
+
/**
* @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
* field's data value (defaults to the underlying DOM element's name)
addicon : false,
editicon: false,
-
+ // element that contains real text value.. (when hidden is used..)
+
// private
onRender : function(ct, position){
Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
// prevent input submission
this.el.dom.removeAttribute('name');
+
+
}
if(Roo.isGecko){
this.el.dom.setAttribute('autocomplete', 'off');
this.store.on('beforeload', this.onBeforeLoad, this);
this.store.on('load', this.onLoad, this);
- this.store.on('loadexception', this.collapse, this);
+ this.store.on('loadexception', this.onLoadException, this);
if(this.resizable){
this.resizer = new Roo.Resizable(this.list, {
"tab" : function(e){
this.onViewClick(false);
+ this.fireEvent("specialkey", this, e);
return true;
},
if(this.store){
this.store.un('beforeload', this.onBeforeLoad, this);
this.store.un('load', this.onLoad, this);
- this.store.un('loadexception', this.collapse, this);
+ this.store.un('loadexception', this.onLoadException, this);
}
Roo.form.ComboBox.superclass.onDestroy.call(this);
},
}
//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);
+ }
+
+
+ },
// private
onTypeAhead : function(){
if(this.store.getCount() > 0){
record = r;
return false;
}
+ return true;
});
}
return record;
},
-
+
+ getName: function()
+ {
+ // returns hidden if it's set..
+ if (!this.rendered) {return ''};
+ return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
+
+ },
// private
onViewMove : function(e, t){
this.inKeyMode = false;
},
// private
- onViewClick : function(doFocus){
+ onViewClick : function(doFocus)
+ {
var index = this.view.getSelectedIndexes()[0];
var r = this.store.getAt(index);
if(r){
*/
defaultLinkValue : 'http:/'+'/',
+ /**
+ * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
+ * Roo.resizable.
+ */
+ resizable : false,
+ /**
+ * @cfg {Number} height (in pixels)
+ */
+ height: 300,
+ /**
+ * @cfg {Number} width (in pixels)
+ */
+ width: 500,
+
+ /**
+ * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+ *
+ */
+ stylesheets: false,
// id of frame..
frameId: false,
onFocus : Roo.emptyFn,
iframePad:3,
hideMode:'offsets',
- defaultAutoCreate : {
+
+ defaultAutoCreate : { // modified by initCompnoent..
tag: "textarea",
style:"width:500px;height:300px;",
autocomplete: "off"
* @param {HtmlEditor} this
*/
editorevent: true
- })
+ });
+ this.defaultAutoCreate = {
+ tag: "textarea",
+ style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
+ autocomplete: "off"
+ };
},
/**
* want to change the initialization markup of the iframe (e.g. to add stylesheets).
*/
getDocMarkup : function(){
- return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
+ // body styles..
+ var st = '';
+ if (this.stylesheets === false) {
+
+ Roo.get(document.head).select('style').each(function(node) {
+ st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+ });
+
+ Roo.get(document.head).select('link').each(function(node) {
+ st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+ });
+
+ } else if (!this.stylesheets.length) {
+ // simple..
+ st = '<style type="text/css">' +
+ 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+ '</style>';
+ } else {
+ Roo.each(this.stylesheets, function(s) {
+ st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
+ });
+
+ }
+
+ return '<html><head>' + st +
+ //<style type="text/css">' +
+ //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+ //'</style>' +
+ ' </head><body></body></html>';
},
// private
- onRender : function(ct, position){
+ onRender : function(ct, position)
+ {
+ var _t = this;
Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
this.el.dom.style.border = '0 none';
this.el.dom.setAttribute('tabIndex', -1);
this.wrap = this.el.wrap({
cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
});
+
+ if (this.resizable) {
+ this.resizeEl = new Roo.Resizable(this.wrap, {
+ pinned : true,
+ wrap: true,
+ dynamic : true,
+ minHeight : this.height,
+ height: this.height,
+ handles : this.resizable,
+ width: this.width,
+ listeners : {
+ resize : function(r, w, h) {
+ _t.onResize(w,h); // -something
+ }
+ }
+ });
+
+ }
this.frameId = Roo.id();
- this.createToolbar(this);
-
-
+ this.createToolbar(this);
name: this.frameId,
frameBorder : 'no',
'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
- });
+ }, this.el
+ );
// console.log(iframe);
//this.wrap.dom.appendChild(iframe);
Roo.TaskMgr.start(task);
if(!this.width){
- this.setSize(this.el.getSize());
+ this.setSize(this.wrap.getSize());
+ }
+ if (this.resizeEl) {
+ this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
+ // should trigger onReize..
}
},
// private
- onResize : function(w, h){
+ onResize : function(w, h)
+ {
+ //Roo.log('resize: ' +w + ',' + h );
Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
if(this.el && this.iframe){
if(typeof w == 'number'){
for (var i =0; i < this.toolbars.length;i++) {
// fixme - ask toolbars for heights?
tbh += this.toolbars[i].tb.el.getHeight();
+ if (this.toolbars[i].footer) {
+ tbh += this.toolbars[i].footer.el.getHeight();
+ }
}
var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
+ ah -= 5; // knock a few pixes off for look..
this.el.setHeight(this.adjustWidth('textarea', ah));
this.iframe.style.height = ah + 'px';
if(this.doc){
syncValue : function(){
if(this.initialized){
var bd = (this.doc.body || this.doc.documentElement);
- this.cleanUpPaste();
+ //this.cleanUpPaste();
var html = bd.innerHTML;
if(Roo.isSafari){
var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
dbody.bgProperties = 'fixed'; // ie
Roo.DomHelper.applyStyles(dbody, ss);
Roo.EventManager.on(this.doc, {
- 'mousedown': this.onEditorEvent,
+ //'mousedown': this.onEditorEvent,
+ 'mouseup': this.onEditorEvent,
'dblclick': this.onEditorEvent,
'click': this.onEditorEvent,
'keyup': this.onEditorEvent,
onEditorEvent : function(e){
this.fireEvent('editorevent', this, e);
// this.updateToolbar();
- this.syncValue();
+ this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
},
insertTag : function(tg)
break;
case 'u':
cmd = 'underline';
+ break;
case 'v':
this.cleanUpPaste.defer(100, this);
return;
- var range = this.createRange(this.getSelection());
+ var range = this.createRange(this.getSelection()).cloneRange();
if (Roo.isIE) {
var parent = range.parentElement();
return parent;
}
-
- var ar = range.endContainer.childNodes;
- if (!ar.length) {
- ar = range.commonAncestorContainer.childNodes;
- //alert(ar.length);
+ // is ancestor a text element.
+ var ac = range.commonAncestorContainer;
+ if (ac.nodeType == 3) {
+ ac = ac.parentNode;
}
+
+ var ar = ac.childNodes;
+
var nodes = [];
var other_nodes = [];
var has_other_nodes = false;
other_nodes.push(ar[i]);
continue;
}
+ // outer..
if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
continue;
}
}
},
+ /***
+ *
+ * Range intersection.. the hard stuff...
+ * '-1' = before
+ * '0' = hits..
+ * '1' = after.
+ * [ -- selected range --- ]
+ * [fail] [fail]
+ *
+ * basically..
+ * if end is before start or hits it. fail.
+ * if start is after end or hits it fail.
+ *
+ * if either hits (but other is outside. - then it's not
+ *
+ *
+ **/
-
- // BC Hacks - cause I cant work out what i was trying to do..
+ // @see http://www.thismuchiknow.co.uk/?p=64.
rangeIntersectsNode : function(range, node)
{
var nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
- }
- catch (e) {
+ } catch (e) {
nodeRange.selectNodeContents(node);
}
-
- return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
- range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
+
+ var rangeStartRange = range.cloneRange();
+ rangeStartRange.collapse(true);
+
+ var rangeEndRange = range.cloneRange();
+ rangeEndRange.collapse(false);
+
+ var nodeStartRange = nodeRange.cloneRange();
+ nodeStartRange.collapse(true);
+
+ var nodeEndRange = nodeRange.cloneRange();
+ nodeEndRange.collapse(false);
+
+ return rangeStartRange.compareBoundaryPoints(
+ Range.START_TO_START, nodeEndRange) == -1 &&
+ rangeEndRange.compareBoundaryPoints(
+ Range.START_TO_START, nodeStartRange) == 1;
+
+
},
- rangeCompareNode : function(range, node) {
+ rangeCompareNode : function(range, node)
+ {
var nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
} catch (e) {
nodeRange.selectNodeContents(node);
}
- var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
- var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
-
- if (nodeIsBefore && !nodeIsAfter)
- return 0;
- if (!nodeIsBefore && nodeIsAfter)
- return 1;
+
+
+ range.collapse(true);
+
+ nodeRange.collapse(true);
+
+ var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
+ var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
+
+ //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
+
+ var nodeIsBefore = ss == 1;
+ var nodeIsAfter = ee == -1;
+
if (nodeIsBefore && nodeIsAfter)
- return 2;
-
+ return 0; // outer
+ if (!nodeIsBefore && nodeIsAfter)
+ return 1; //right trailed.
+
+ if (nodeIsBefore && !nodeIsAfter)
+ return 2; // left trailed.
+ // fully contined.
return 3;
},
cleanUpPaste : function()
{
// cleans up the whole document..
- // console.log('cleanuppaste');
+ Roo.log('cleanuppaste');
this.cleanUpChildren(this.doc.body);
+ var clean = this.cleanWordChars(this.doc.body.innerHTML);
+ if (clean != this.doc.body.innerHTML) {
+ this.doc.body.innerHTML = clean;
+ }
+ },
+
+ cleanWordChars : function(input) {
+ var he = Roo.form.HtmlEditor;
+
+ var output = input;
+ Roo.each(he.swapCodes, function(sw) {
+ var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
+ output = output.replace(swapper, sw[1]);
+ });
+ return output;
},
+
+
cleanUpChildren : function (n)
{
if (!n.childNodes.length) {
return;
}
+
+ var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
+
+ // remove <a name=....> as rendering on yahoo mailer is bored with this.
+
+ if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
+ remove_keep_children = true;
+ }
+
+ if (remove_keep_children) {
+ this.cleanUpChildren(node);
+ // inserts everything just before this node...
+ while (node.childNodes.length) {
+ var cn = node.childNodes[0];
+ node.removeChild(cn);
+ node.parentNode.insertBefore(cn, node);
+ }
+ node.parentNode.removeChild(node);
+ return;
+ }
+
if (!node.attributes || !node.attributes.length) {
this.cleanUpChildren(node);
return;
Roo.each(parts, function(p) {
p = p.replace(/\s+/g,'');
if (!p.length) {
- return;
+ return true;
}
var l = p.split(':').shift().replace(/\s+/g,'');
+ // only allow 'c whitelisted system attributes'
if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
node.removeAttribute(n);
return false;
}
+ return true;
});
cleanStyle(a.name,a.value);
}
/// clean up MS crap..
+ // tecnically this should be a list of valid class'es..
+
+
if (a.name == 'class') {
if (a.value.match(/^Mso/)) {
node.className = '';
}
+
+ if (a.value.match(/body/)) {
+ node.className = '';
+ }
}
// style cleanup!?
Roo.form.HtmlEditor.clean = [
'script', 'style', 'title', 'xml'
];
-
+Roo.form.HtmlEditor.remove = [
+ 'font'
+];
// attributes..
Roo.form.HtmlEditor.ablack = [
'http', 'https', 'mailto'
];
+// white listed style attributes.
Roo.form.HtmlEditor.cwhite= [
'text-align',
'font-size'
];
-// <script type="text/javascript">
+
+Roo.form.HtmlEditor.swapCodes =[
+ [ 8211, "--" ],
+ [ 8212, "--" ],
+ [ 8216, "'" ],
+ [ 8217, "'" ],
+ [ 8220, '"' ],
+ [ 8221, '"' ],
+ [ 8226, "*" ],
+ [ 8230, "..." ]
+];
+
+ // <script type="text/javascript">
/*
* Based on
* Ext JS Library 1.1.1
{
Roo.apply(this, config);
+
+ // default disabled, based on 'good practice'..
+ this.disable = this.disable || {};
+ Roo.applyIf(this.disable, {
+ fontSize : true,
+ colors : true,
+ specialElements : true
+ });
+
+
//Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
// dont call parent... till later.
}
// "é" , // e ecute
// "ú" , // u ecute?
],
+
+ specialElements : [
+ {
+ text: "Insert Table",
+ xtype: 'MenuItem',
+ xns : Roo.Menu,
+ ihtml : '<table><tr><td>Cell</td></tr></table>'
+
+ },
+ {
+ text: "Insert Image",
+ xtype: 'MenuItem',
+ xns : Roo.Menu,
+ ihtml : '<img src="about:blank"/>'
+
+ }
+
+
+ ],
+
+
inputElements : [
"form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
"input:submit", "input:button", "select", "textarea", "label" ],
};
- if(this.disable.colors){
+ if(!this.disable.colors){
tb.add(
'-', {
id:editor.frameId +'-forecolor',
smenu = {
text: "©",
cls: 'x-edit-none',
+
menu : {
items : []
- }
+ }
};
for (var i =0; i < this.specialChars.length; i++) {
smenu.menu.items.push({
}
+
+ if (!this.disable.specialElements) {
+ var semenu = {
+ text: "Other;",
+ cls: 'x-edit-none',
+ menu : {
+ items : []
+ }
+ };
+ for (var i =0; i < this.specialElements.length; i++) {
+ semenu.menu.items.push(
+ Roo.apply({
+ handler: function(a,b) {
+ editor.insertAtCursor(this.ihtml);
+ }
+ }, this.specialElements[i])
+ );
+
+ }
+
+ tb.add(semenu);
+
+
+ }
+
+
if (this.btns) {
for(var i =0; i< this.btns.length;i++) {
var b = this.btns[i];
new Roo.form.HtmlEditor({
....
toolbars : [
- new Roo.form.HtmlEditor.ToolbarStandard(),
- new Roo.form.HtmlEditor.ToolbarContext()
- })
- }
+ { xtype: 'ToolbarStandard', styles : {} }
+ { xtype: 'ToolbarContext', disable : {} }
+ ]
+})
+
*
* @config : {Object} disable List of elements to disable.. (not done yet.)
- *
+ * @config : {Object} styles Map of styles available.
*
*/
Roo.apply(this, config);
//Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
// dont call parent... till later.
+ this.styles = this.styles || {};
}
Roo.form.HtmlEditor.ToolbarContext.types = {
'IMG' : {
align: {
title: "Align",
opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
- width: 40
+ width: 80
},
valign: {
title: "Valign",
opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
- width: 40
+ width: 80
},
colspan: {
title: "Colspan",
width: 200
}
},
+
+ // should we really allow this??
+ // should this just be
'BODY' : {
title : {
title: "title",
- width: 120,
+ width: 200,
disabled : true
}
+ },
+ '*' : {
+ // empty..
}
};
*/
disable : false,
+ /**
+ * @cfg {Object} styles List of styles
+ * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
+ *
+ * These must be defined in the page, so they get rendered correctly..
+ * .headline { }
+ * TD.underline { }
+ *
+ */
+ styles : false,
}
this.tb = this.toolbars.BODY;
this.tb.el.show();
-
+ this.buildFooter();
+ this.footer.show();
this.rendered = true;
* Protected method that will not generally be called directly. It triggers
* a toolbar update by reading the markup state of the current selection in the editor.
*/
- updateToolbar: function(){
+ updateToolbar: function(ignore_a,ignore_b,sel){
+
if(!this.editor.activated){
- this.editor.onFirstFocus();
+ this.editor.onFirstFocus();
return;
}
-
+ var updateFooter = sel ? false : true;
+
var ans = this.editor.getAllAncestors();
// pick
var ty= Roo.form.HtmlEditor.ToolbarContext.types;
- var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
- sel = sel ? sel : this.editor.doc.body;
- sel = sel.tagName.length ? sel : this.editor.doc.body;
+
+ if (!sel) {
+ sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
+ sel = sel ? sel : this.editor.doc.body;
+ sel = sel.tagName.length ? sel : this.editor.doc.body;
+
+ }
+ // pick a menu that exists..
var tn = sel.tagName.toUpperCase();
- sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
+ //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
+
tn = sel.tagName.toUpperCase();
- if (this.tb.name == tn) {
- return; // no change
+
+ var lastSel = this.tb.selectedNode
+
+ this.tb.selectedNode = sel;
+
+ // if current menu does not match..
+ if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
+
+ this.tb.el.hide();
+ ///console.log("show: " + tn);
+ this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
+ this.tb.el.show();
+ // update name
+ this.tb.items.first().el.innerHTML = tn + ': ';
+
+
+ // update attributes
+ if (this.tb.fields) {
+ this.tb.fields.each(function(e) {
+ e.setValue(sel.getAttribute(e.name));
+ });
+ }
+
+ // update styles
+ var st = this.tb.fields.item(0);
+ st.store.removeAll();
+ var cn = sel.className.split(/\s+/);
+
+ var avs = [];
+ if (this.styles['*']) {
+
+ Roo.each(this.styles['*'], function(v) {
+ avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
+ });
+ }
+ if (this.styles[tn]) {
+ Roo.each(this.styles[tn], function(v) {
+ avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
+ });
+ }
+
+ st.store.loadData(avs);
+ st.collapse();
+ st.setValue(cn);
+
+ // flag our selected Node.
+ this.tb.selectedNode = sel;
+
+
+ Roo.menu.MenuMgr.hideAll();
+
}
- this.tb.el.hide();
- ///console.log("show: " + tn);
- this.tb = this.toolbars[tn];
- this.tb.el.show();
- this.tb.fields.each(function(e) {
- e.setValue(sel.getAttribute(e.name));
+
+ if (!updateFooter) {
+ return;
+ }
+ // update the footer
+ //
+ var html = '';
+
+ this.footerEls = ans.reverse();
+ Roo.each(this.footerEls, function(a,i) {
+ if (!a) { return; }
+ html += html.length ? ' > ' : '';
+
+ html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
+
});
- this.tb.selectedNode = sel;
+
+ //
+ var sz = this.footDisp.up('td').getSize();
+ this.footDisp.dom.style.width = (sz.width -10) + 'px';
+ this.footDisp.dom.style.marginLeft = '5px';
+ this.footDisp.dom.style.overflow = 'hidden';
- Roo.menu.MenuMgr.hideAll();
-
+ this.footDisp.dom.innerHTML = html;
+
//this.editorsyncValue();
},
var tb = new Roo.Toolbar(wdiv);
+ // add the name..
+
tb.add(nm+ ": ");
+
+ // styles...
+ if (this.styles) {
+
+ // this needs a multi-select checkbox...
+ tb.addField( new Roo.form.ComboBox({
+ store: new Roo.data.SimpleStore({
+ id : 'val',
+ fields: ['val', 'selected'],
+ data : []
+ }),
+ name : 'className',
+ displayField:'val',
+ typeAhead: false,
+ mode: 'local',
+ editable : false,
+ triggerAction: 'all',
+ emptyText:'Select Style',
+ selectOnFocus:true,
+ width: 130,
+ listeners : {
+ 'select': function(c, r, i) {
+ // initial support only for on class per el..
+ tb.selectedNode.className = r ? r.get('val') : '';
+ }
+ }
+
+ }));
+ }
+
+
+
for (var i in tlist) {
+
var item = tlist[i];
tb.add(item.title + ": ");
+
+
+
+
if (item.opts) {
- // fixme
-
-
+ // opts == pulldown..
tb.addField( new Roo.form.ComboBox({
store: new Roo.data.SimpleStore({
id : 'val',
fields: ['val'],
- data : item.opts // from states.js
+ data : item.opts
}),
name : i,
displayField:'val',
}));
continue;
-
-
-
+
tb.addField( new Roo.form.TextField({
name: i,
return tb;
+ },
+ buildFooter : function()
+ {
+
+ var fel = this.editor.wrap.createChild();
+ this.footer = new Roo.Toolbar(fel);
+ // toolbar has scrolly on left / right?
+ var footDisp= new Roo.Toolbar.Fill();
+ var _t = this;
+ this.footer.add(
+ {
+ text : '<',
+ xtype: 'Button',
+ handler : function() {
+ _t.footDisp.scrollTo('left',0,true)
+ }
+ }
+ );
+ this.footer.add( footDisp );
+ this.footer.add(
+ {
+ text : '>',
+ xtype: 'Button',
+ handler : function() {
+ // no animation..
+ _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
+ }
+ }
+ );
+ var fel = Roo.get(footDisp.el);
+ fel.addClass('x-editor-context');
+ this.footDispWrap = fel;
+ this.footDispWrap.overflow = 'hidden';
+
+ this.footDisp = fel.createChild();
+ this.footDispWrap.on('click', this.onContextClick, this)
+
+
+ },
+ onContextClick : function (ev,dom)
+ {
+ ev.preventDefault();
+ var cn = dom.className;
+ Roo.log(cn);
+ if (!cn.match(/x-ed-loc-/)) {
+ return;
+ }
+ var n = cn.split('-').pop();
+ var ans = this.footerEls;
+ var sel = ans[n];
+
+ // pick
+ var range = this.editor.createRange();
+
+ range.selectNodeContents(sel);
+ //range.selectNode(sel);
+
+
+ var selection = this.editor.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+
+
+ this.updateToolbar(null, null, sel);
+
+
}
+
});
Roo.callback(o.failure, o.scope, [this, action]);
// show an error message if no failed handler is set..
if (!this.hasListener('actionfailed')) {
- Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
+ Roo.MessageBox.alert("Error",
+ (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
+ action.result.errorMsg :
+ "Saving Failed, please check your entries"
+ );
}
this.fireEvent('actionfailed', this, action);
* This differs from getValues as it calls getValue on each child item, rather than using dom data.
* @return {Object}
*/
- getFieldValues : function()
+ getFieldValues : function(with_hidden)
{
if (this.childForms) {
// copy values from the child forms
+ // should this call getFieldValues - probably not as we do not currently copy
+ // hidden fields when we generate..
Roo.each(this.childForms, function (f) {
this.setValues(f.getValues());
}, this);
return;
}
var v = f.getValue();
+ // not sure if this supported any more..
if ((typeof(v) == 'object') && f.getRawValue) {
v = f.getRawValue() ; // dates..
}
+ // combo boxes where name != hiddenName...
+ if (f.name != f.getName()) {
+ ret[f.name] = f.getRawValue();
+ }
ret[f.getName()] = v;
});
Roo.MessageBox.hide();
}
-
this.response = response;
this.failureType = Roo.form.Action.CONNECT_FAILURE;
this.form.afterAction(this, false);
data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
ds.loadData( data);
}
+ // clear selection so it does not get stale.
+ if (this.grid.sm) {
+ this.grid.sm.clearSelections();
+ }
+
Roo.form.GridField.superclass.setValue.call(this, v);
this.refreshValue();
// should load data in the grid really....
Roo.form.DayPicker.superclass.onDestroy.call(this);
}
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011 Alan Knowles
+ *
+ * License - LGPL
+ */
+
+
+/**
+ * @class Roo.form.ComboCheck
+ * @extends Roo.form.ComboBox
+ * A combobox for multiple select items.
+ *
+ * FIXME - could do with a reset button..
+ *
+ * @constructor
+ * Create a new ComboCheck
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboCheck = 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.ComboCheck : missing value for: " + e;
+ }
+ });
+
+
+};
+
+Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
+
+
+ editable : false,
+
+ selectedClass: 'x-menu-item-checked',
+
+ // private
+ onRender : function(ct, position){
+ var _t = this;
+
+
+
+ if(!this.tpl){
+ var cls = 'x-combo-list';
+
+
+ this.tpl = new Roo.Template({
+ html : '<div class="'+cls+'-item x-menu-check-item">' +
+ '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
+ '<span>{' + this.displayField + '}</span>' +
+ '</div>'
+
+ });
+ }
+
+
+ Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
+ this.view.singleSelect = false;
+ this.view.multiSelect = true;
+ this.view.toggleSelect = true;
+ this.pageTb.add(new Roo.Toolbar.Fill(), {
+
+ text: 'Done',
+ handler: function()
+ {
+ _t.collapse();
+ }
+ });
+ },
+
+ onViewOver : function(e, t){
+ // do nothing...
+ return;
+
+ },
+
+ onViewClick : function(doFocus,index){
+ return;
+
+ },
+ select: function () {
+ //Roo.log("SELECT CALLED");
+ },
+
+ selectByValue : function(xv, scrollIntoView){
+ var ar = this.getValueArray();
+ var sels = [];
+
+ Roo.each(ar, function(v) {
+ if(v === undefined || v === null){
+ return;
+ }
+ var r = this.findRecord(this.valueField, v);
+ if(r){
+ sels.push(this.store.indexOf(r))
+
+ }
+ },this);
+ this.view.select(sels);
+ return false;
+ },
+
+
+
+ onSelect : function(record, index){
+ // Roo.log("onselect Called");
+ // this is only called by the clear button now..
+ this.view.clearSelections();
+ this.setValue('[]');
+ if (this.value != this.valueBefore) {
+ this.fireEvent('change', this, this.value, this.valueBefore);
+ }
+ },
+ getValueArray : function()
+ {
+ var ar = [] ;
+
+ try {
+ //Roo.log(this.value);
+ if (typeof(this.value) == 'undefined') {
+ return [];
+ }
+ var ar = Roo.decode(this.value);
+ return ar instanceof Array ? ar : []; //?? valid?
+
+ } catch(e) {
+ Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
+ return [];
+ }
+
+ },
+ expand : function ()
+ {
+ Roo.form.ComboCheck.superclass.expand.call(this);
+ this.valueBefore = this.value;
+
+
+ },
+
+ collapse : function(){
+ Roo.form.ComboCheck.superclass.collapse.call(this);
+ var sl = this.view.getSelectedIndexes();
+ var st = this.store;
+ var nv = [];
+ var tv = [];
+ var r;
+ Roo.each(sl, function(i) {
+ r = st.getAt(i);
+ nv.push(r.get(this.valueField));
+ },this);
+ this.setValue(Roo.encode(nv));
+ if (this.value != this.valueBefore) {
+
+ this.fireEvent('change', this, this.value, this.valueBefore);
+ }
+
+ },
+
+ setValue : function(v){
+ // Roo.log(v);
+ this.value = v;
+
+ var vals = this.getValueArray();
+ var tv = [];
+ Roo.each(vals, function(k) {
+ var r = this.findRecord(this.valueField, k);
+ if(r){
+ tv.push(r.data[this.displayField]);
+ }else if(this.valueNotFoundText !== undefined){
+ tv.push( this.valueNotFoundText );
+ }
+ },this);
+ // Roo.log(tv);
+
+ Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
+ this.hiddenField.value = v;
+ this.value = v;
+ }
+
});//<script type="text/javasscript">
{
// basically accepts a pannel...
// can accept a layout region..!?!?
- // console.log('BorderLayout add ' + cfg.xtype)
+ //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
if (!cfg.xtype.match(/Panel$/)) {
return false;
}
var ret = false;
+
+ if (typeof(cfg.region) == 'undefined') {
+ Roo.log("Failed to add Panel, region was not set");
+ Roo.log(cfg);
+ return false;
+ }
var region = cfg.region;
delete cfg.region;
xitems = cfg.items;
delete cfg.items;
}
-
+ var nb = false;
switch(cfg.xtype)
{
ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
//console.log('adding nested layout panel ' + cfg.toSource());
this.add(region, ret);
-
+ nb = {}; /// find first...
break;
case 'GridPanel':
}
this.beginUpdate();
// add children..
+ var region = '';
+ var abn = {};
Roo.each(xitems, function(i) {
- ret.addxtype(i);
+ region = nb && i.region ? i.region : false;
+
+ var add = ret.addxtype(i);
+
+ if (region) {
+ nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
+ if (!i.background) {
+ abn[region] = nb[region] ;
+ }
+ }
+
});
this.endUpdate();
+
+ // make the last non-background panel active..
+ //if (nb) { Roo.log(abn); }
+ if (nb) {
+
+ for(var r in abn) {
+ region = this.getRegion(r);
+ if (region) {
+ // tried using nb[r], but it does not work..
+
+ region.showPanel(abn[r]);
+
+ }
+ }
+ }
return ret;
}
* @class Roo.LayoutRegion
* @extends Roo.BasicLayoutRegion
* This class represents a region in a layout manager.
- * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
- * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
- * @cfg {Boolean} floatable False to disable floating (defaults to true)
- * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
- * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
- * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
- * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
- * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
- * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
- * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
- * @cfg {String} title The title for the region (overrides panel titles)
- * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
- * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
- * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
- * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
- * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
- * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
- * the space available, similar to FireFox 1.5 tabs (defaults to false)
- * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
- * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
- * @cfg {Boolean} showPin True to show a pin button
-* @cfg {Boolean} hidden True to start the region hidden (defaults to false)
-* @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
-* @cfg {Boolean} disableTabTips True to disable tab tooltips
-* @cfg {Number} width For East/West panels
-* @cfg {Number} height For North/South panels
-* @cfg {Boolean} split To show the splitter
+ * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
+ * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
+ * @cfg {Boolean} floatable False to disable floating (defaults to true)
+ * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
+ * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
+ * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
+ * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
+ * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
+ * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
+ * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
+ * @cfg {String} title The title for the region (overrides panel titles)
+ * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
+ * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
+ * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
+ * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
+ * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
+ * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
+ * the space available, similar to FireFox 1.5 tabs (defaults to false)
+ * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
+ * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
+ * @cfg {Boolean} showPin True to show a pin button
+ * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
+ * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
+ * @cfg {Boolean} disableTabTips True to disable tab tooltips
+ * @cfg {Number} width For East/West panels
+ * @cfg {Number} height For North/South panels
+ * @cfg {Boolean} split To show the splitter
+ * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
*/
Roo.LayoutRegion = function(mgr, config, pos){
Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
// overridden
},
- initTabs : function(){
+ initTabs : function()
+ {
this.bodyEl.setStyle("overflow", "hidden");
- var ts = new Roo.TabPanel(this.bodyEl.dom, {
- tabPosition: this.bottomTabs ? 'bottom' : 'top',
- disableTooltips: this.config.disableTabTips
- });
+ var ts = new Roo.TabPanel(
+ this.bodyEl.dom,
+ {
+ tabPosition: this.bottomTabs ? 'bottom' : 'top',
+ disableTooltips: this.config.disableTabTips,
+ toolbar : this.config.toolbar
+ }
+ );
if(this.config.hideTabs){
ts.stripWrap.setDisplayed(false);
}
* @class Roo.ContentPanel
* @extends Roo.util.Observable
* A basic ContentPanel element.
- * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
- * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
+ * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
+ * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
* @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
- * @cfg {Boolean} closable True if the panel can be closed/removed
- * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
+ * @cfg {Boolean} closable True if the panel can be closed/removed
+ * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
* @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
- * @cfg {Toolbar} toolbar A toolbar for this panel
+ * @cfg {Toolbar} toolbar A toolbar for this panel
* @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
* @cfg {String} title The title for this panel
* @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
* @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
* @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} content Raw content to fill content panel with (uses setContent on construction.)
* @constructor
* Create a new ContentPanel.
}
if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
- this.wrapEl = this.el.wrap();
- this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
-
+ this.wrapEl = this.el.wrap();
+ this.toolbar.container = this.el.insertSibling(false, 'before');
+ this.toolbar = new Roo.Toolbar(this.toolbar);
}
* @param {Number} width The width after any component adjustments
* @param {Number} height The height after any component adjustments
*/
- "resize" : true
+ "resize" : true,
+
+ /**
+ * @event render
+ * Fires when this tab is created
+ * @param {Roo.ContentPanel} this
+ */
+ "render" : true
+
+
+
});
if(this.autoScroll){
this.resizeEl.setStyle("overflow", "auto");
Roo.ContentPanel.superclass.constructor.call(this);
+
+ this.fireEvent('render', this);
};
Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
this.el = null;
},
+ /**
+ * form - if the content panel contains a form - this is a reference to it.
+ * @type {Roo.form.Form}
+ */
+ form : false,
+ /**
+ * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
+ * This contains a reference to it.
+ * @type {Roo.View}
+ */
+ view : false,
+
/**
* Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
* <pre><code>
if ( this.form.allItems.length) this.form.render(el.dom);
return this.form;
}
-
+ // should only have one of theses..
if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
// views..
cfg.el = this.el.appendChild(document.createElement("div"));
// factory?
- var ret = new Roo[cfg.xtype](cfg);
- ret.render(false, ''); // render blank..
- return ret;
+ var ret = new Roo.factory(cfg);
+ ret.render && ret.render(false, ''); // render blank..
+ this.view = ret;
+ return ret;
}
return false;
-
}
});
this.rowEl.elements = els;
return this.rowEl;
},
-
+ /**
+ * Gets the 'td' of the cell
+ *
+ * @param {Integer} rowIndex row to select
+ * @param {Integer} colIndex column to select
+ *
+ * @return {Object}
+ */
getCell : function(rowIndex, colIndex){
var locked = this.cm.getLockedCount();
var source;
* This class provides the basic implementation for cell selection in a grid.
* @constructor
* @param {Object} config The object containing the configuration of this model.
+ * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
*/
Roo.grid.CellSelectionModel = function(config){
Roo.apply(this, config);
<li>o.cell: An array of [rowIndex, columnIndex]</li>
</ul>
*/
- "selectionchange" : true
+ "selectionchange" : true,
+ /**
+ * @event tabend
+ * Fires when the tab (or enter) was pressed on the last editable cell
+ * You can use this to trigger add new row.
+ * @param {SelectionModel} this
+ */
+ "tabend" : true
});
Roo.grid.CellSelectionModel.superclass.constructor.call(this);
};
Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
+
+ enter_is_tab: false,
/** @ignore */
initEvents : function(){
/** @ignore */
handleKeyDown : function(e){
- Roo.log('Cell Sel Model handleKeyDown');
+ //Roo.log('Cell Sel Model handleKeyDown');
if(!e.isNavKeyPress()){
return;
}
var k = e.getKey(), r = s.cell[0], c = s.cell[1];
var newCell;
+
+
switch(k){
case e.TAB:
// handled by onEditorKey
if (g.isEditor && g.editing) {
return;
}
- if(e.shiftKey){
- newCell = walk(r, c-1, -1);
- }else{
- newCell = walk(r, c+1, 1);
+ if(e.shiftKey) {
+ newCell = walk(r, c-1, -1);
+ } else {
+ newCell = walk(r, c+1, 1);
}
- break;
- case e.DOWN:
- newCell = walk(r+1, c, 1);
- break;
- case e.UP:
- newCell = walk(r-1, c, -1);
- break;
- case e.RIGHT:
- newCell = walk(r, c+1, 1);
- break;
- case e.LEFT:
- newCell = walk(r, c-1, -1);
- break;
- case e.ENTER:
- if(g.isEditor && !g.editing){
- g.startEditing(r, c);
- e.stopEvent();
- return;
+ break;
+
+ case e.DOWN:
+ newCell = walk(r+1, c, 1);
+ break;
+
+ case e.UP:
+ newCell = walk(r-1, c, -1);
+ break;
+
+ case e.RIGHT:
+ newCell = walk(r, c+1, 1);
+ break;
+
+ case e.LEFT:
+ newCell = walk(r, c-1, -1);
+ break;
+
+ case e.ENTER:
+
+ if(g.isEditor && !g.editing){
+ g.startEditing(r, c);
+ e.stopEvent();
+ return;
}
+
+
break;
};
if(newCell){
this.select(newCell[0], newCell[1]);
e.stopEvent();
+
}
},
acceptsNav : function(row, col, cm){
return !cm.isHidden(col) && cm.isCellEditable(col, row);
},
-
+ /**
+ * Selects a cell.
+ * @param {Number} field (not used) - as it's normally used as a listener
+ * @param {Number} e - event - fake it by using
+ *
+ * var e = Roo.EventObjectImpl.prototype;
+ * e.keyCode = e.TAB
+ *
+ *
+ */
onEditorKey : function(field, e){
- var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
+ var k = e.getKey(),
+ newCell,
+ g = this.grid,
+ ed = g.activeEditor,
+ forward = false;
///Roo.log('onEditorKey' + k);
+
+ if (this.enter_is_tab && k == e.ENTER) {
+ k = e.TAB;
+ }
+
if(k == e.TAB){
if(e.shiftKey){
newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
}else{
newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+ forward = true;
}
+
e.stopEvent();
- }else if(k == e.ENTER && !e.ctrlKey){
+
+ }else if(k == e.ENTER && !e.ctrlKey){
ed.completeEdit();
e.stopEvent();
newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
if(newCell){
//Roo.log('next cell after edit');
g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
+ } else if (forward) {
+ // tabbed past last
+ this.fireEvent.defer(100, this, ['tabend',this]);
}
}
});/*
cancel:false,
editor: ed
};
+ var cell = Roo.get(this.view.getCell(ed.row,ed.col))
+ cell.show();
+
if(String(value) !== String(startValue)){
if(this.fireEvent("validateedit", e) !== false && !e.cancel){
this.stopEditing();
if(this.colModel.isCellEditable(col, row)){
this.view.ensureVisible(row, col, true);
+
var r = this.dataSource.getAt(row);
var field = this.colModel.getDataIndex(col);
+ var cell = Roo.get(this.view.getCell(row,col));
var e = {
grid: this,
record: r,
value: r.data[field],
row: row,
column: col,
- cancel:false
+ cancel:false
};
if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
this.editing = true;
ed.render(ed.parentEl || document.body);
}
ed.field.reset();
+
+ cell.hide();
+
(function(){ // complex but required for focus issues in safari, ie and opera
ed.row = row;
ed.col = col;
ed.record = r;
- ed.on("complete", this.onEditComplete, this, {single: true});
- ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
+ ed.on("complete", this.onEditComplete, this, {single: true});
+ ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
this.activeEditor = ed;
var v = r.data[field];
ed.startEdit(this.view.getCell(row, col), v);
if(this.store){
this.store.on('beforeload', this.onBeforeLoad, this);
this.store.on('load', this.onLoad, this);
- this.store.on('loadexception', this.onLoad, this);
+ this.store.on('loadexception', this.onLoadException, this);
this.removeMask = false;
}else{
var um = this.el.getUpdateManager();
enable : function(){
this.disabled = false;
},
-
+
+ onLoadException : function()
+ {
+ if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+ Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+ }
+ this.el.unmask(this.removeMask);
+ },
// private
- onLoad : function(){
+ onLoad : function()
+ {
this.el.unmask(this.removeMask);
},
if(this.store){
this.store.un('beforeload', this.onBeforeLoad, this);
this.store.un('load', this.onLoad, this);
- this.store.un('loadexception', this.onLoad, this);
+ this.store.un('loadexception', this.onLoadException, this);
}else{
var um = this.el.getUpdateManager();
um.un('beforeupdate', this.onBeforeLoad, this);
{
el = el || false;
+ var hp = this.parent ? 1 : 0;
- if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
+ if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
// if parent is a '#.....' string, then let's use that..
var ename = this.parent.substr(1)
this.parent = false;
return;
}
}
+
+
if (!this.parent) {
el = el ? Roo.get(el) : false;
closeOnTab: true,
tabPosition: 'top',
//resizeTabs: true,
- alwaysShowTabs: el ? false : true,
- hideTabs: el ? true : false,
+ alwaysShowTabs: el && hp? false : true,
+ hideTabs: el || !hp ? true : false,
minTabWidth: 140
}
})
if (!str || typeof(str) == 'object') {
return str;
}
- if (str[0]=='#') {
+ if (str.substring(0,1) == '#') {
return str;
}
var rt, o;
rt = ar.shift();
/** eval:var:o */
- eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+ try {
+ eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+ } catch (e) {
+ throw "Module not found : " + str;
+ }
+
if (o === false) {
throw "Module not found : " + str;
}
}
o = o[e];
});
+
return o;
},
*/
preBuild : function ()
{
-
+ var _t = this;
Roo.each(this.modules , function (obj)
{
- obj.parent = this.toObject(obj.parent);
+ var opar = obj.parent;
+ try {
+ obj.parent = this.toObject(opar);
+ } catch(e) {
+ Roo.log(e.toString());
+ return;
+ }
if (!obj.parent) {
this.topModule = obj;
this.elmodules.push(obj);
return;
}
-
+ if (obj.parent.constructor != Roo.XComponent) {
+ Roo.log("Object Parent is not instance of XComponent:" + obj.name)
+ }
if (!obj.parent.modules) {
obj.parent.modules = new Roo.util.MixedCollection(false,
function(o) { return o.order + '' }