isIE = ua.indexOf("msie") > -1,
isIE7 = ua.indexOf("msie 7") > -1,
isIE11 = /trident.*rv\:11\./.test(ua),
+ isEdge = ua.indexOf("edge") > -1,
isGecko = !isSafari && ua.indexOf("gecko") > -1,
isBorderBox = isIE && !isStrict,
isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
isLinux = (ua.indexOf("linux") != -1),
isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
isIOS = /iphone|ipad/.test(ua),
+ isAndroid = /android/.test(ua),
isTouch = (function() {
try {
if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
return; // alerT?
}
- console.log(s);
+ console.log(s);
},
/**
* Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
/** @type Boolean */
isIE11 : isIE11,
/** @type Boolean */
+ isEdge : isEdge,
+ /** @type Boolean */
isGecko : isGecko,
/** @type Boolean */
isBorderBox : isBorderBox,
/** @type Boolean */
isIOS : isIOS,
/** @type Boolean */
+ isAndroid : isAndroid,
+ /** @type Boolean */
isTouch : isTouch,
/**
return Roo.util.Format.htmlEncode(args[i]);
});
}
+
+
});
/**
String.prototype.toggle = function(value, other){
return this == value ? other : value;
-};/*
+};
+
+
+/**
+ * Remove invalid unicode characters from a string
+ *
+ * @return {String} The clean string
+ */
+String.prototype.unicodeClean = function () {
+ return this.replace(/[\s\S]/g,
+ function(character) {
+ if (character.charCodeAt()< 256) {
+ return character;
+ }
+ try {
+ encodeURIComponent(character);
+ } catch(e) {
+ return '';
+ }
+ return character;
+ }
+ );
+};
+
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
}
return res;
+ },
+ /**
+ * equals
+ * @param {Array} o The array to compare to
+ * @returns {Boolean} true if the same
+ */
+ equals : function(b)
+ {
+ // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
+ if (this === b) {
+ return true;
+ }
+ if (b == null) {
+ return false;
+ }
+ if (this.length !== b.length) {
+ return false;
+ }
+
+ // sort?? a.sort().equals(b.sort());
+
+ for (var i = 0; i < this.length; ++i) {
+ if (this[i] !== b[i]) {
+ return false;
+ }
+ }
+ return true;
}
-
});
};
Roo.Template.prototype = {
+ /**
+ * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
+ */
+ onLoad : false,
+
+
/**
* @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
* it should be fixed so that template is observable...
* @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
*/
html : '',
+
+
+ compiled : false,
+ loaded : false,
/**
* Returns an HTML fragment of this template with the specified values applied.
* @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
* @return {String} The HTML fragment
*/
+
+
+
applyTemplate : function(values){
+ //Roo.log(["applyTemplate", values]);
try {
if(this.compiled){
method : 'GET',
success : function (response) {
_t.loading = false;
- _t.html = response.responseText;
_t.url = false;
- _t.compile();
+
+ _t.set(response.responseText,true);
+ _t.loaded = true;
+ if (_t.onLoad) {
+ _t.onLoad();
+ }
},
failure : function(response) {
Roo.log("Template failed to load from " + _t.url);
*/
set : function(html, compile){
this.html = html;
- this.compiled = null;
+ this.compiled = false;
if(compile){
this.compile();
}
relayEvents : function(o, events){
var createHandler = function(ename){
return function(){
+
return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
};
};
for(var i = 0, len = events.length; i < len; i++){
var ename = events[i];
- if(!this.events[ename]){ this.events[ename] = true; };
+ if(!this.events[ename]){
+ this.events[ename] = true;
+ };
o.on(ename, createHandler(ename), this);
}
},
var ls = this.listeners, scope, len = ls.length;
if(len > 0){
this.firing = true;
- var args = Array.prototype.slice.call(arguments, 0);
+ var args = Array.prototype.slice.call(arguments, 0);
for(var i = 0; i < len; i++){
- var l = ls[i];
- if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
+ var l = ls[i];
+ if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
this.firing = false;
return false;
}
}
};
})();/*
+ * RooJS Library
+ * Copyright(c) 2007-2017, Roo J Solutions Ltd
+ *
+ * Licence LGPL
+ *
+ */
+
+/**
+ * @class Roo.Document
+ * @extends Roo.util.Observable
+ * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
+ *
+ * @param {Object} config the methods and properties of the 'base' class for the application.
+ *
+ * Generic Page handler - implement this to start your app..
+ *
+ * eg.
+ * MyProject = new Roo.Document({
+ events : {
+ 'load' : true // your events..
+ },
+ listeners : {
+ 'ready' : function() {
+ // fired on Roo.onReady()
+ }
+ }
+ *
+ */
+Roo.Document = function(cfg) {
+
+ this.addEvents({
+ 'ready' : true
+ });
+ Roo.util.Observable.call(this,cfg);
+
+ var _this = this;
+
+ Roo.onReady(function() {
+ _this.fireEvent('ready');
+ },null,false);
+
+
+}
+
+Roo.extend(Roo.Document, Roo.util.Observable, {});/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
}
}
+
var listen = function(element, ename, opt, fn, scope){
var o = (!opt || typeof opt == "boolean") ? {} : opt;
if(o.buffer){
h = createBuffered(h, o);
}
+
fn._handlers = fn._handlers || [];
var cls = [
Roo.isIE ? "roo-ie"
+ : Roo.isIE11 ? "roo-ie11"
+ : Roo.isEdge ? "roo-edge"
: Roo.isGecko ? "roo-gecko"
: Roo.isOpera ? "roo-opera"
: Roo.isSafari ? "roo-safari" : ""];
El.prototype = {
/**
- * The element's default display mode (defaults to "")
+ * The element's default display mode (defaults to "")
* @type String
*/
originalDisplay : "",
- visibilityMode : 1,
+
+ // note this is overridden in BS version..
+ visibilityMode : 1,
/**
* The default unit to append to CSS values where a unit isn't provided (defaults to px).
* @type String
var p = Roo.fly(this.dom.parentNode, '_internal');
return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
},
+
+ /**
+ * Looks at the scrollable parent element
+ */
+ findScrollableParent : function()
+ {
+ var overflowRegex = /(auto|scroll)/;
+
+ if(this.getStyle('position') === 'fixed'){
+ return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+ }
+
+ var excludeStaticParent = this.getStyle('position') === "absolute";
+
+ for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
+
+ if (excludeStaticParent && parent.getStyle('position') === "static") {
+ continue;
+ }
+
+ if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
+ return parent;
+ }
+
+ if(parent.dom.nodeName.toLowerCase() == 'body'){
+ return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+ }
+ }
+
+ return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+ },
/**
* Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
if (this.dom) {
Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
}
+ if (eventName == 'dblclick') {
+ this.addListener('touchstart', this.onTapHandler, this);
+ }
},
+ tapedTwice : false,
+ onTapHandler : function(event)
+ {
+ if(!this.tapedTwice) {
+ this.tapedTwice = true;
+ var s = this;
+ setTimeout( function() {
+ s.tapedTwice = false;
+ }, 300 );
+ return;
+ }
+ event.preventDefault();
+ var revent = new MouseEvent('dblclick', {
+ view: window,
+ bubbles: true,
+ cancelable: true
+ });
+
+ this.dom.dispatchEvent(revent);
+ //action on double tap goes below
+
+ },
/**
* Removes an event handler from this element
* @param {Array} offsets (optional) Offset the positioning by [x, y]
* @return {Array} [x, y]
*/
- getAlignToXY : function(el, p, o){
+ getAlignToXY : function(el, p, o)
+ {
el = Roo.get(el);
var d = this.dom;
if(!el.dom){
//otherwise swap the aligned el to the opposite border of the target.
var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
- var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
+ var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
var doc = document;
if(!this._mask){
this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
}
+
this.addClass("x-masked");
this._mask.setDisplayed(true);
if(typeof msg == 'string'){
if(!this._maskMsg){
- this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
+ this._maskMsg = Roo.DomHelper.append(this.dom, {
+ cls: "roo-el-mask-msg",
+ cn: [
+ {
+ tag: 'i',
+ cls: 'fa fa-spinner fa-spin'
+ },
+ {
+ tag: 'div'
+ }
+ ]
+ }, true);
}
var mm = this._maskMsg;
mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
- if (mm.dom.firstChild) { // weird IE issue?
- mm.dom.firstChild.innerHTML = msg;
+ if (mm.dom.lastChild) { // weird IE issue?
+ mm.dom.lastChild.innerHTML = msg;
}
mm.setDisplayed(true);
mm.center(this);
/**
* @private
*/
- fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
+ fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
/**
* Sizes this element to its parent element's dimensions performing
* @class Roo.data.Connection
* @extends Roo.util.Observable
* The class encapsulates a connection to the page's originating domain, allowing requests to be made
- * either to a configured URL, or to a URL specified at request time.<br><br>
- * <p>
+ * either to a configured URL, or to a URL specified at request time.
+ *
* Requests made by this class are asynchronous, and will return immediately. No data from
* the server will be available to the statement immediately following the {@link #request} call.
- * To process returned data, use a callback in the request options object, or an event listener.</p><br>
- * <p>
+ * To process returned data, use a callback in the request options object, or an event listener.
+ *
* Note: If you are doing a file upload, you will not get a normal response object sent back to
* your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
* The response object is created using the innerHTML of the IFRAME's document as the responseText
- * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
+ * property and, if present, the IFRAME's XML document as the responseXML property.
+ *
* This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
* that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
* using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
url = url || form.action;
var enctype = form.getAttribute("enctype");
+
+ if (o.formData) {
+ return this.doFormDataUpload(o, url);
+ }
+
if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
return this.doFormUpload(o, p, url);
}
var f = Roo.lib.Ajax.serializeForm(form);
p = p ? (p + '&' + f) : f;
}
+
+ if (!o.form && o.formData) {
+ o.formData = o.formData === true ? new FormData() : o.formData;
+ for (var k in o.params) {
+ o.formData.append(k,o.params[k]);
+ }
+
+ return this.doFormDataUpload(o, url);
+ }
+
var hs = o.headers;
if(this.defaultHeaders){
url += (url.indexOf('?') != -1 ? '&' : '?') + p;
p = '';
}
+ Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
+ Roo.lib.Ajax.useDefaultHeader == true;
return this.transId;
}else{
Roo.callback(o.callback, o.scope, [o, null, null]);
form.removeChild(hiddens[i]);
}
}
+ },
+ // this is a 'formdata version???'
+
+
+ doFormDataUpload : function(o, url)
+ {
+ var formData;
+ if (o.form) {
+ var form = Roo.getDom(o.form);
+ form.enctype = form.encoding = 'multipart/form-data';
+ formData = o.formData === true ? new FormData(form) : o.formData;
+ } else {
+ formData = o.formData === true ? new FormData() : o.formData;
+ }
+
+
+ var cb = {
+ success: this.handleResponse,
+ failure: this.handleFailure,
+ scope: this,
+ argument: {options: o},
+ timeout : o.timeout || this.timeout
+ };
+
+ if(typeof o.autoAbort == 'boolean'){ // options gets top priority
+ if(o.autoAbort){
+ this.abort();
+ }
+ }else if(this.autoAbort !== false){
+ this.abort();
+ }
+
+ //Roo.lib.Ajax.defaultPostHeader = null;
+ Roo.lib.Ajax.useDefaultHeader = false;
+ this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
+ Roo.lib.Ajax.useDefaultHeader = true;
+
+
}
+
});
/*
* Based on:
* @return {Object} The item associated with the passed key.
*/
item : function(key){
+ if (key === 'length') {
+ return null;
+ }
var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
},
* eventually this should probably emulate php's number_format
* @param {Number/String} value The numeric value to format
* @param {Number} decimals number of decimal places
+ * @param {String} delimiter for thousands (default comma)
* @return {String} The formatted currency string
*/
- number : function(v,decimals)
+ number : function(v, decimals, thousandsDelimiter)
{
// multiply and round.
decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
+ thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
+
var mul = Math.pow(10, decimals);
var zero = String(mul).substring(1);
v = (Math.round((v-0)*mul))/mul;
var ps = v.split('.');
var whole = ps[0];
-
var r = /(\d+)(\d{3})/;
// add comma's
- while (r.test(whole)) {
- whole = whole.replace(r, '$1' + ',' + '$2');
- }
+ if(thousandsDelimiter.length != 0) {
+ whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
+ }
var sub = ps[1] ?
// has decimals..
/**
* @cfg {String} actionMode
* which property holds the element that used for hide() / show() / disable() / enable()
- * default is 'el'
+ * default is 'el' for forms you probably want to set this to fieldEl
*/
actionMode : "el",
* @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
*/
render : function(container, position){
- if(!this.rendered && this.fireEvent("beforerender", this) !== false){
- if(!container && this.el){
- this.el = Roo.get(this.el);
- container = this.el.dom.parentNode;
- this.allowDomMove = false;
- }
- this.container = Roo.get(container);
- this.rendered = true;
- if(position !== undefined){
- if(typeof position == 'number'){
- position = this.container.dom.childNodes[position];
- }else{
- position = Roo.getDom(position);
- }
- }
- this.onRender(this.container, position || null);
- if(this.cls){
- this.el.addClass(this.cls);
- delete this.cls;
- }
- if(this.style){
- this.el.applyStyles(this.style);
- delete this.style;
- }
- this.fireEvent("render", this);
- this.afterRender(this.container);
- if(this.hidden){
- this.hide();
- }
- if(this.disabled){
- this.disable();
+
+ if(this.rendered){
+ return this;
+ }
+
+ if(this.fireEvent("beforerender", this) === false){
+ return false;
+ }
+
+ if(!container && this.el){
+ this.el = Roo.get(this.el);
+ container = this.el.dom.parentNode;
+ this.allowDomMove = false;
+ }
+ this.container = Roo.get(container);
+ this.rendered = true;
+ if(position !== undefined){
+ if(typeof position == 'number'){
+ position = this.container.dom.childNodes[position];
+ }else{
+ position = Roo.getDom(position);
}
}
+ this.onRender(this.container, position || null);
+ if(this.cls){
+ this.el.addClass(this.cls);
+ delete this.cls;
+ }
+ if(this.style){
+ this.el.applyStyles(this.style);
+ delete this.style;
+ }
+ this.fireEvent("render", this);
+ this.afterRender(this.container);
+ if(this.hidden){
+ this.hide();
+ }
+ if(this.disabled){
+ this.disable();
+ }
+
return this;
+
},
/** @private */
return {x : x, y: y};
}
});/*
- * Original code for Roojs - LGPL
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
* <script type="text/javascript">
*/
-
+ (function(){
/**
- * @class Roo.XComponent
- * A delayed Element creator...
- * Or a way to group chunks of interface together.
- * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
- * used in conjunction with XComponent.build() it will create an instance of each element,
- * then call addxtype() to build the User interface.
- *
- * Mypart.xyx = new Roo.XComponent({
-
- parent : 'Mypart.xyz', // empty == document.element.!!
- order : '001',
- name : 'xxxx'
- region : 'xxxx'
- disabled : function() {}
-
- tree : function() { // return an tree of xtype declared components
- var MODULE = this;
- return
- {
- xtype : 'NestedLayoutPanel',
- // technicall
- }
- ]
- *})
- *
- *
- * It can be used to build a big heiracy, with parent etc.
- * or you can just use this to render a single compoent to a dom element
- * MYPART.render(Roo.Element | String(id) | dom_element )
- *
- *
- * Usage patterns.
- *
- * Classic Roo
- *
- * Roo is designed primarily as a single page application, so the UI build for a standard interface will
- * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
- *
- * Each sub module is expected to have a parent pointing to the class name of it's parent module.
- *
- * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
- * - if mulitple topModules exist, the last one is defined as the top module.
- *
- * Embeded Roo
- *
- * When the top level or multiple modules are to embedded into a existing HTML page,
- * the parent element can container '#id' of the element where the module will be drawn.
- *
- * Bootstrap Roo
- *
- * Unlike classic Roo, the bootstrap tends not to be used as a single page.
- * it relies more on a include mechanism, where sub modules are included into an outer page.
- * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
- *
- * Bootstrap Roo Included elements
- *
- * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
- * hence confusing the component builder as it thinks there are multiple top level elements.
- *
- *
- *
- * @extends Roo.util.Observable
+ * @class Roo.Layer
+ * @extends Roo.Element
+ * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
+ * automatic maintaining of shadow/shim positions.
+ * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
+ * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
+ * you can pass a string with a CSS class name. False turns off the shadow.
+ * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
+ * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
+ * @cfg {String} cls CSS class to add to the element
+ * @cfg {Number} zindex Starting z-index (defaults to 11000)
+ * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
* @constructor
- * @param cfg {Object} configuration of component
- *
+ * @param {Object} config An object with config options.
+ * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
*/
-Roo.XComponent = function(cfg) {
- Roo.apply(this, cfg);
- this.addEvents({
- /**
- * @event built
- * Fires when this the componnt is built
- * @param {Roo.XComponent} c the component
- */
- 'built' : true
-
- });
- this.region = this.region || 'center'; // default..
- Roo.XComponent.register(this);
- this.modules = false;
- this.el = false; // where the layout goes..
-
-
-}
-Roo.extend(Roo.XComponent, Roo.util.Observable, {
- /**
- * @property el
- * The created element (with Roo.factory())
- * @type {Roo.Layout}
- */
- el : false,
-
- /**
- * @property el
- * for BC - use el in new code
- * @type {Roo.Layout}
- */
- panel : false,
-
- /**
- * @property layout
- * for BC - use el in new code
- * @type {Roo.Layout}
- */
- layout : false,
-
- /**
- * @cfg {Function|boolean} disabled
- * If this module is disabled by some rule, return true from the funtion
- */
- disabled : false,
-
- /**
- * @cfg {String} parent
- * Name of parent element which it get xtype added to..
- */
- parent: false,
-
- /**
- * @cfg {String} order
- * Used to set the order in which elements are created (usefull for multiple tabs)
- */
-
- order : false,
- /**
- * @cfg {String} name
- * String to display while loading.
- */
- name : false,
- /**
- * @cfg {String} region
- * Region to render component to (defaults to center)
- */
- region : 'center',
-
- /**
- * @cfg {Array} items
- * A single item array - the first element is the root of the tree..
- * It's done this way to stay compatible with the Xtype system...
- */
- items : false,
-
- /**
- * @property _tree
- * The method that retuns the tree of parts that make up this compoennt
- * @type {function}
- */
- _tree : false,
-
- /**
- * render
- * render element to dom or tree
- * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
- */
-
- render : function(el)
- {
-
- el = el || false;
- var hp = this.parent ? 1 : 0;
- Roo.debug && Roo.log(this);
-
- 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;
- Roo.debug && Roo.log(ename);
- switch (ename) {
- case 'bootstrap-body' :
- if (typeof(Roo.bootstrap.Body) != 'undefined') {
- this.parent = { el : new Roo.bootstrap.Body() };
- Roo.debug && Roo.log("setting el to doc body");
-
- } else {
- throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
- }
- break;
- case 'bootstrap':
- this.parent = { el : true};
- // fall through
- default:
- el = Roo.get(ename);
- break;
- }
-
-
- if (!el && !this.parent) {
- Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
- return;
- }
- }
- Roo.debug && Roo.log("EL:");
- Roo.debug && Roo.log(el);
- Roo.debug && Roo.log("this.parent.el:");
- Roo.debug && Roo.log(this.parent.el);
-
- var tree = this._tree ? this._tree() : this.tree();
- // altertive root elements ??? - we need a better way to indicate these.
- var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
- (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
-
- if (!this.parent && is_alt) {
- //el = Roo.get(document.body);
- this.parent = { el : true };
+Roo.Layer = function(config, existingEl){
+ config = config || {};
+ var dh = Roo.DomHelper;
+ var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
+ if(existingEl){
+ this.dom = Roo.getDom(existingEl);
+ }
+ if(!this.dom){
+ var o = config.dh || {tag: "div", cls: "x-layer"};
+ this.dom = dh.append(pel, o);
+ }
+ if(config.cls){
+ this.addClass(config.cls);
+ }
+ this.constrain = config.constrain !== false;
+ this.visibilityMode = Roo.Element.VISIBILITY;
+ if(config.id){
+ this.id = this.dom.id = config.id;
+ }else{
+ this.id = Roo.id(this.dom);
+ }
+ this.zindex = config.zindex || this.getZIndex();
+ this.position("absolute", this.zindex);
+ if(config.shadow){
+ this.shadowOffset = config.shadowOffset || 4;
+ this.shadow = new Roo.Shadow({
+ offset : this.shadowOffset,
+ mode : config.shadow
+ });
+ }else{
+ this.shadowOffset = 0;
+ }
+ this.useShim = config.shim !== false && Roo.useShims;
+ this.useDisplay = config.useDisplay;
+ this.hide();
+};
+
+var supr = Roo.Element.prototype;
+
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
+
+Roo.extend(Roo.Layer, Roo.Element, {
+
+ getZIndex : function(){
+ return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+ },
+
+ getShim : function(){
+ if(!this.useShim){
+ return null;
}
-
-
-
- if (!this.parent) {
-
- Roo.debug && Roo.log("no parent - creating one");
-
- el = el ? Roo.get(el) : false;
-
- // it's a top level one..
- this.parent = {
- el : new Roo.BorderLayout(el || document.body, {
-
- center: {
- titlebar: false,
- autoScroll:false,
- closeOnTab: true,
- tabPosition: 'top',
- //resizeTabs: true,
- alwaysShowTabs: el && hp? false : true,
- hideTabs: el || !hp ? true : false,
- minTabWidth: 140
- }
- })
- };
+ if(this.shim){
+ return this.shim;
}
-
- if (!this.parent.el) {
- // probably an old style ctor, which has been disabled.
- return;
-
+ var shim = shims.shift();
+ if(!shim){
+ shim = this.createShim();
+ shim.enableDisplayMode('block');
+ shim.dom.style.display = 'none';
+ shim.dom.style.visibility = 'visible';
}
- // The 'tree' method is '_tree now'
-
- tree.region = tree.region || this.region;
- var is_body = false;
- if (this.parent.el === true) {
- // bootstrap... - body..
- this.parent.el = Roo.factory(tree);
- is_body = true;
+ var pn = this.dom.parentNode;
+ if(shim.dom.parentNode != pn){
+ pn.insertBefore(shim.dom, this.dom);
}
-
- this.el = this.parent.el.addxtype(tree, undefined, is_body);
- this.fireEvent('built', this);
-
- this.panel = this.el;
- this.layout = this.panel.layout;
- this.parentLayout = this.parent.layout || false;
-
- }
-
-});
+ shim.setStyle('z-index', this.getZIndex()-2);
+ this.shim = shim;
+ return shim;
+ },
-Roo.apply(Roo.XComponent, {
- /**
- * @property hideProgress
- * true to disable the building progress bar.. usefull on single page renders.
- * @type Boolean
- */
- hideProgress : false,
- /**
- * @property buildCompleted
- * True when the builder has completed building the interface.
- * @type Boolean
+ hideShim : function(){
+ if(this.shim){
+ this.shim.setDisplayed(false);
+ shims.push(this.shim);
+ delete this.shim;
+ }
+ },
+
+ disableShadow : function(){
+ if(this.shadow){
+ this.shadowDisabled = true;
+ this.shadow.hide();
+ this.lastShadowOffset = this.shadowOffset;
+ this.shadowOffset = 0;
+ }
+ },
+
+ enableShadow : function(show){
+ if(this.shadow){
+ this.shadowDisabled = false;
+ this.shadowOffset = this.lastShadowOffset;
+ delete this.lastShadowOffset;
+ if(show){
+ this.sync(true);
+ }
+ }
+ },
+
+ // private
+ // this code can execute repeatedly in milliseconds (i.e. during a drag) so
+ // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
+ sync : function(doShow){
+ var sw = this.shadow;
+ if(!this.updating && this.isVisible() && (sw || this.useShim)){
+ var sh = this.getShim();
+
+ var w = this.getWidth(),
+ h = this.getHeight();
+
+ var l = this.getLeft(true),
+ t = this.getTop(true);
+
+ if(sw && !this.shadowDisabled){
+ if(doShow && !sw.isVisible()){
+ sw.show(this);
+ }else{
+ sw.realign(l, t, w, h);
+ }
+ if(sh){
+ if(doShow){
+ sh.show();
+ }
+ // fit the shim behind the shadow, so it is shimmed too
+ var a = sw.adjusts, s = sh.dom.style;
+ s.left = (Math.min(l, l+a.l))+"px";
+ s.top = (Math.min(t, t+a.t))+"px";
+ s.width = (w+a.w)+"px";
+ s.height = (h+a.h)+"px";
+ }
+ }else if(sh){
+ if(doShow){
+ sh.show();
+ }
+ sh.setSize(w, h);
+ sh.setLeftTop(l, t);
+ }
+
+ }
+ },
+
+ // private
+ destroy : function(){
+ this.hideShim();
+ if(this.shadow){
+ this.shadow.hide();
+ }
+ this.removeAllListeners();
+ var pn = this.dom.parentNode;
+ if(pn){
+ pn.removeChild(this.dom);
+ }
+ Roo.Element.uncache(this.id);
+ },
+
+ remove : function(){
+ this.destroy();
+ },
+
+ // private
+ beginUpdate : function(){
+ this.updating = true;
+ },
+
+ // private
+ endUpdate : function(){
+ this.updating = false;
+ this.sync(true);
+ },
+
+ // private
+ hideUnders : function(negOffset){
+ if(this.shadow){
+ this.shadow.hide();
+ }
+ this.hideShim();
+ },
+
+ // private
+ constrainXY : function(){
+ if(this.constrain){
+ var vw = Roo.lib.Dom.getViewWidth(),
+ vh = Roo.lib.Dom.getViewHeight();
+ var s = Roo.get(document).getScroll();
+
+ var xy = this.getXY();
+ var x = xy[0], y = xy[1];
+ var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
+ // only move it if it needs it
+ var moved = false;
+ // first validate right/bottom
+ if((x + w) > vw+s.left){
+ x = vw - w - this.shadowOffset;
+ moved = true;
+ }
+ if((y + h) > vh+s.top){
+ y = vh - h - this.shadowOffset;
+ moved = true;
+ }
+ // then make sure top/left isn't negative
+ if(x < s.left){
+ x = s.left;
+ moved = true;
+ }
+ if(y < s.top){
+ y = s.top;
+ moved = true;
+ }
+ if(moved){
+ if(this.avoidY){
+ var ay = this.avoidY;
+ if(y <= ay && (y+h) >= ay){
+ y = ay-h-5;
+ }
+ }
+ xy = [x, y];
+ this.storeXY(xy);
+ supr.setXY.call(this, xy);
+ this.sync();
+ }
+ }
+ },
+
+ isVisible : function(){
+ return this.visible;
+ },
+
+ // private
+ showAction : function(){
+ this.visible = true; // track visibility to prevent getStyle calls
+ if(this.useDisplay === true){
+ this.setDisplayed("");
+ }else if(this.lastXY){
+ supr.setXY.call(this, this.lastXY);
+ }else if(this.lastLT){
+ supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
+ }
+ },
+
+ // private
+ hideAction : function(){
+ this.visible = false;
+ if(this.useDisplay === true){
+ this.setDisplayed(false);
+ }else{
+ this.setLeftTop(-10000,-10000);
+ }
+ },
+
+ // overridden Element method
+ setVisible : function(v, a, d, c, e){
+ if(v){
+ this.showAction();
+ }
+ if(a && v){
+ var cb = function(){
+ this.sync(true);
+ if(c){
+ c();
+ }
+ }.createDelegate(this);
+ supr.setVisible.call(this, true, true, d, cb, e);
+ }else{
+ if(!v){
+ this.hideUnders(true);
+ }
+ var cb = c;
+ if(a){
+ cb = function(){
+ this.hideAction();
+ if(c){
+ c();
+ }
+ }.createDelegate(this);
+ }
+ supr.setVisible.call(this, v, a, d, cb, e);
+ if(v){
+ this.sync(true);
+ }else if(!a){
+ this.hideAction();
+ }
+ }
+ },
+
+ storeXY : function(xy){
+ delete this.lastLT;
+ this.lastXY = xy;
+ },
+
+ storeLeftTop : function(left, top){
+ delete this.lastXY;
+ this.lastLT = [left, top];
+ },
+
+ // private
+ beforeFx : function(){
+ this.beforeAction();
+ return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+ },
+
+ // private
+ afterFx : function(){
+ Roo.Layer.superclass.afterFx.apply(this, arguments);
+ this.sync(this.isVisible());
+ },
+
+ // private
+ beforeAction : function(){
+ if(!this.updating && this.shadow){
+ this.shadow.hide();
+ }
+ },
+
+ // overridden Element method
+ setLeft : function(left){
+ this.storeLeftTop(left, this.getTop(true));
+ supr.setLeft.apply(this, arguments);
+ this.sync();
+ },
+
+ setTop : function(top){
+ this.storeLeftTop(this.getLeft(true), top);
+ supr.setTop.apply(this, arguments);
+ this.sync();
+ },
+
+ setLeftTop : function(left, top){
+ this.storeLeftTop(left, top);
+ supr.setLeftTop.apply(this, arguments);
+ this.sync();
+ },
+
+ setXY : function(xy, a, d, c, e){
+ this.fixDisplay();
+ this.beforeAction();
+ this.storeXY(xy);
+ var cb = this.createCB(c);
+ supr.setXY.call(this, xy, a, d, cb, e);
+ if(!a){
+ cb();
+ }
+ },
+
+ // private
+ createCB : function(c){
+ var el = this;
+ return function(){
+ el.constrainXY();
+ el.sync(true);
+ if(c){
+ c();
+ }
+ };
+ },
+
+ // overridden Element method
+ setX : function(x, a, d, c, e){
+ this.setXY([x, this.getY()], a, d, c, e);
+ },
+
+ // overridden Element method
+ setY : function(y, a, d, c, e){
+ this.setXY([this.getX(), y], a, d, c, e);
+ },
+
+ // overridden Element method
+ setSize : function(w, h, a, d, c, e){
+ this.beforeAction();
+ var cb = this.createCB(c);
+ supr.setSize.call(this, w, h, a, d, cb, e);
+ if(!a){
+ cb();
+ }
+ },
+
+ // overridden Element method
+ setWidth : function(w, a, d, c, e){
+ this.beforeAction();
+ var cb = this.createCB(c);
+ supr.setWidth.call(this, w, a, d, cb, e);
+ if(!a){
+ cb();
+ }
+ },
+
+ // overridden Element method
+ setHeight : function(h, a, d, c, e){
+ this.beforeAction();
+ var cb = this.createCB(c);
+ supr.setHeight.call(this, h, a, d, cb, e);
+ if(!a){
+ cb();
+ }
+ },
+
+ // overridden Element method
+ setBounds : function(x, y, w, h, a, d, c, e){
+ this.beforeAction();
+ var cb = this.createCB(c);
+ if(!a){
+ this.storeXY([x, y]);
+ supr.setXY.call(this, [x, y]);
+ supr.setSize.call(this, w, h, a, d, cb, e);
+ cb();
+ }else{
+ supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
+ }
+ return this;
+ },
+
+ /**
+ * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
+ * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
+ * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
+ * @param {Number} zindex The new z-index to set
+ * @return {this} The Layer
+ */
+ setZIndex : function(zindex){
+ this.zindex = zindex;
+ this.setStyle("z-index", zindex + 2);
+ if(this.shadow){
+ this.shadow.setZIndex(zindex + 1);
+ }
+ if(this.shim){
+ this.shim.setStyle("z-index", zindex);
+ }
+ }
+});
+})();/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * Or a way to group chunks of interface together.
+ * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
+ * used in conjunction with XComponent.build() it will create an instance of each element,
+ * then call addxtype() to build the User interface.
+ *
+ * Mypart.xyx = new Roo.XComponent({
+
+ parent : 'Mypart.xyz', // empty == document.element.!!
+ order : '001',
+ name : 'xxxx'
+ region : 'xxxx'
+ disabled : function() {}
+
+ tree : function() { // return an tree of xtype declared components
+ var MODULE = this;
+ return
+ {
+ xtype : 'NestedLayoutPanel',
+ // technicall
+ }
+ ]
+ *})
+ *
+ *
+ * It can be used to build a big heiracy, with parent etc.
+ * or you can just use this to render a single compoent to a dom element
+ * MYPART.render(Roo.Element | String(id) | dom_element )
+ *
+ *
+ * Usage patterns.
+ *
+ * Classic Roo
+ *
+ * Roo is designed primarily as a single page application, so the UI build for a standard interface will
+ * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
+ *
+ * Each sub module is expected to have a parent pointing to the class name of it's parent module.
+ *
+ * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
+ * - if mulitple topModules exist, the last one is defined as the top module.
+ *
+ * Embeded Roo
+ *
+ * When the top level or multiple modules are to embedded into a existing HTML page,
+ * the parent element can container '#id' of the element where the module will be drawn.
+ *
+ * Bootstrap Roo
+ *
+ * Unlike classic Roo, the bootstrap tends not to be used as a single page.
+ * it relies more on a include mechanism, where sub modules are included into an outer page.
+ * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
+ *
+ * Bootstrap Roo Included elements
+ *
+ * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
+ * hence confusing the component builder as it thinks there are multiple top level elements.
+ *
+ * String Over-ride & Translations
+ *
+ * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
+ * and also the 'overlaying of string values - needed when different versions of the same application with different text content
+ * are needed. @see Roo.XComponent.overlayString
+ *
+ *
+ *
+ * @extends Roo.util.Observable
+ * @constructor
+ * @param cfg {Object} configuration of component
+ *
+ */
+Roo.XComponent = function(cfg) {
+ Roo.apply(this, cfg);
+ this.addEvents({
+ /**
+ * @event built
+ * Fires when this the componnt is built
+ * @param {Roo.XComponent} c the component
+ */
+ 'built' : true
+
+ });
+ this.region = this.region || 'center'; // default..
+ Roo.XComponent.register(this);
+ this.modules = false;
+ this.el = false; // where the layout goes..
+
+
+}
+Roo.extend(Roo.XComponent, Roo.util.Observable, {
+ /**
+ * @property el
+ * The created element (with Roo.factory())
+ * @type {Roo.Layout}
+ */
+ el : false,
+
+ /**
+ * @property el
+ * for BC - use el in new code
+ * @type {Roo.Layout}
+ */
+ panel : false,
+
+ /**
+ * @property layout
+ * for BC - use el in new code
+ * @type {Roo.Layout}
+ */
+ layout : false,
+
+ /**
+ * @cfg {Function|boolean} disabled
+ * If this module is disabled by some rule, return true from the funtion
+ */
+ disabled : false,
+
+ /**
+ * @cfg {String} parent
+ * Name of parent element which it get xtype added to..
+ */
+ parent: false,
+
+ /**
+ * @cfg {String} order
+ * Used to set the order in which elements are created (usefull for multiple tabs)
+ */
+
+ order : false,
+ /**
+ * @cfg {String} name
+ * String to display while loading.
+ */
+ name : false,
+ /**
+ * @cfg {String} region
+ * Region to render component to (defaults to center)
+ */
+ region : 'center',
+
+ /**
+ * @cfg {Array} items
+ * A single item array - the first element is the root of the tree..
+ * It's done this way to stay compatible with the Xtype system...
+ */
+ items : false,
+
+ /**
+ * @property _tree
+ * The method that retuns the tree of parts that make up this compoennt
+ * @type {function}
+ */
+ _tree : false,
+
+ /**
+ * render
+ * render element to dom or tree
+ * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
+ */
+
+ render : function(el)
+ {
+
+ el = el || false;
+ var hp = this.parent ? 1 : 0;
+ Roo.debug && Roo.log(this);
+
+ var tree = this._tree ? this._tree() : this.tree();
+
+
+ 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;
+ Roo.debug && Roo.log(ename);
+ switch (ename) {
+ case 'bootstrap-body':
+ if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
+ // this is the BorderLayout standard?
+ this.parent = { el : true };
+ break;
+ }
+ if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
+ // need to insert stuff...
+ this.parent = {
+ el : new Roo.bootstrap.layout.Border({
+ el : document.body,
+
+ center: {
+ titlebar: false,
+ autoScroll:false,
+ closeOnTab: true,
+ tabPosition: 'top',
+ //resizeTabs: true,
+ alwaysShowTabs: true,
+ hideTabs: false
+ //minTabWidth: 140
+ }
+ })
+
+ };
+ break;
+ }
+
+ if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
+ this.parent = { el : new Roo.bootstrap.Body() };
+ Roo.debug && Roo.log("setting el to doc body");
+
+ } else {
+ throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
+ }
+ break;
+ case 'bootstrap':
+ this.parent = { el : true};
+ // fall through
+ default:
+ el = Roo.get(ename);
+ if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
+ this.parent = { el : true};
+ }
+
+ break;
+ }
+
+
+ if (!el && !this.parent) {
+ Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
+ return;
+ }
+ }
+
+ Roo.debug && Roo.log("EL:");
+ Roo.debug && Roo.log(el);
+ Roo.debug && Roo.log("this.parent.el:");
+ Roo.debug && Roo.log(this.parent.el);
+
+
+ // altertive root elements ??? - we need a better way to indicate these.
+ var is_alt = Roo.XComponent.is_alt ||
+ (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
+ (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+ (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
+
+
+
+ if (!this.parent && is_alt) {
+ //el = Roo.get(document.body);
+ this.parent = { el : true };
+ }
+
+
+
+ if (!this.parent) {
+
+ Roo.debug && Roo.log("no parent - creating one");
+
+ el = el ? Roo.get(el) : false;
+
+ if (typeof(Roo.BorderLayout) == 'undefined' ) {
+
+ this.parent = {
+ el : new Roo.bootstrap.layout.Border({
+ el: el || document.body,
+
+ center: {
+ titlebar: false,
+ autoScroll:false,
+ closeOnTab: true,
+ tabPosition: 'top',
+ //resizeTabs: true,
+ alwaysShowTabs: false,
+ hideTabs: true,
+ minTabWidth: 140,
+ overflow: 'visible'
+ }
+ })
+ };
+ } else {
+
+ // it's a top level one..
+ this.parent = {
+ el : new Roo.BorderLayout(el || document.body, {
+ center: {
+ titlebar: false,
+ autoScroll:false,
+ closeOnTab: true,
+ tabPosition: 'top',
+ //resizeTabs: true,
+ alwaysShowTabs: el && hp? false : true,
+ hideTabs: el || !hp ? true : false,
+ minTabWidth: 140
+ }
+ })
+ };
+ }
+ }
+
+ if (!this.parent.el) {
+ // probably an old style ctor, which has been disabled.
+ return;
+
+ }
+ // The 'tree' method is '_tree now'
+
+ tree.region = tree.region || this.region;
+ var is_body = false;
+ if (this.parent.el === true) {
+ // bootstrap... - body..
+ if (el) {
+ tree.el = el;
+ }
+ this.parent.el = Roo.factory(tree);
+ is_body = true;
+ }
+
+ this.el = this.parent.el.addxtype(tree, undefined, is_body);
+ this.fireEvent('built', this);
+
+ this.panel = this.el;
+ this.layout = this.panel.layout;
+ this.parentLayout = this.parent.layout || false;
+
+ }
+
+});
+
+Roo.apply(Roo.XComponent, {
+ /**
+ * @property hideProgress
+ * true to disable the building progress bar.. usefull on single page renders.
+ * @type Boolean
+ */
+ hideProgress : false,
+ /**
+ * @property buildCompleted
+ * True when the builder has completed building the interface.
+ * @type Boolean
*/
buildCompleted : false,
break;
default:
- if (obj.disabled) {
+ if (obj.disabled || obj.region == '#disabled') {
return;
}
break;
msg: msg,
width:450,
progress:true,
+ buttons : false,
closable:false,
modal: false
" of " + total +
(m.name ? (' - ' + m.name) : '');
Roo.debug && Roo.log(msg);
- if (!this.hideProgress && Roo.MessageBox) {
+ if (!_this.hideProgress && Roo.MessageBox) {
Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
}
},
-
+ /**
+ * Overlay a set of modified strings onto a component
+ * This is dependant on our builder exporting the strings and 'named strings' elements.
+ *
+ * @param {Object} element to overlay on - eg. Pman.Dialog.Login
+ * @param {Object} associative array of 'named' string and it's new value.
+ *
+ */
+ overlayStrings : function( component, strings )
+ {
+ if (typeof(component['_named_strings']) == 'undefined') {
+ throw "ERROR: component does not have _named_strings";
+ }
+ for ( var k in strings ) {
+ var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
+ if (md !== false) {
+ component['_strings'][md] = strings[k];
+ } else {
+ Roo.log('could not find named string: ' + k + ' in');
+ Roo.log(component);
+ }
+
+ }
+
+ },
+
/**
* Event Object.
//
(function() {
+ /**
+ * eval:var:escape
+ * eval:var:unescape
+ * eval:var:replace
+ */
+
+ /**
+ * Helpers
+ */
+
+ var escape = function (html, encode) {
+ return html
+ .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
+
+ var unescape = function (html) {
+ // explicitly match decimal, hex, and named HTML entities
+ return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
+ n = n.toLowerCase();
+ if (n === 'colon') { return ':'; }
+ if (n.charAt(0) === '#') {
+ return n.charAt(1) === 'x'
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
+ : String.fromCharCode(+n.substring(1));
+ }
+ return '';
+ });
+ }
+
+ var replace = function (regex, opt) {
+ regex = regex.source;
+ opt = opt || '';
+ return function self(name, val) {
+ if (!name) { return new RegExp(regex, opt); }
+ val = val.source || val;
+ val = val.replace(/(^|[^\[])\^/g, '$1');
+ regex = regex.replace(name, val);
+ return self;
+ };
+ }
+
+
+ /**
+ * eval:var:noop
+ */
+ var noop = function () {}
+ noop.exec = noop;
+
+ /**
+ * eval:var:merge
+ */
+ var merge = function (obj) {
+ var i = 1
+ , target
+ , key;
+
+ for (; i < arguments.length; i++) {
+ target = arguments[i];
+ for (key in target) {
+ if (Object.prototype.hasOwnProperty.call(target, key)) {
+ obj[key] = target[key];
+ }
+ }
+ }
+
+ return obj;
+ }
+
+
/**
* Block-Level Grammar
*/
+
+
+
var block = {
newline: /^\n+/,
code: /^( {4}[^\n]+\n*)+/,
* Block Lexer
*/
- function Lexer(options) {
+ var Lexer = function (options) {
this.tokens = [];
this.tokens.links = {};
this.options = options || marked.defaults;
* Inline Lexer & Compiler
*/
- function InlineLexer(links, options) {
+ var InlineLexer = function (links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
* Renderer
*/
- function Renderer(options) {
+ /**
+ * eval:var:Renderer
+ */
+
+ var Renderer = function (options) {
this.options = options || {};
}
/**
* Parsing & Compiling
*/
+ /**
+ * eval:var:Parser
+ */
- function Parser(options) {
+ var Parser= function (options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
}
}
};
-
- /**
- * Helpers
- */
-
- function escape(html, encode) {
- return html
- .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''');
- }
-
- function unescape(html) {
- // explicitly match decimal, hex, and named HTML entities
- return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
- n = n.toLowerCase();
- if (n === 'colon') { return ':'; }
- if (n.charAt(0) === '#') {
- return n.charAt(1) === 'x'
- ? String.fromCharCode(parseInt(n.substring(2), 16))
- : String.fromCharCode(+n.substring(1));
- }
- return '';
- });
- }
-
- function replace(regex, opt) {
- regex = regex.source;
- opt = opt || '';
- return function self(name, val) {
- if (!name) { return new RegExp(regex, opt); }
- val = val.source || val;
- val = val.replace(/(^|[^\[])\^/g, '$1');
- regex = regex.replace(name, val);
- return self;
- };
- }
-
- function noop() {}
- noop.exec = noop;
-
- function merge(obj) {
- var i = 1
- , target
- , key;
-
- for (; i < arguments.length; i++) {
- target = arguments[i];
- for (key in target) {
- if (Object.prototype.hasOwnProperty.call(target, key)) {
- obj[key] = target[key];
- }
- }
- }
-
- return obj;
- }
-
+
/**
* Marked
*/
-
- function marked(src, opt, callback) {
+ /**
+ * eval:var:marked
+ */
+ var marked = function (src, opt, callback) {
if (callback || typeof opt === 'function') {
if (!callback) {
callback = opt;
}
pending = tokens.length;
-
+ /**
+ * eval:var:done
+ */
var done = function(err) {
if (err) {
opt.highlight = highlight;
if (id) {
this.initTarget(id, sGroup, config);
}
- if (config.listeners || config.events) {
- Roo.dd.DragDrop.superclass.constructor.call(this, {
+ if (config && (config.listeners || config.events)) {
+ Roo.dd.DragDrop.superclass.constructor.call(this, {
listeners : config.listeners || {},
events : config.events || {}
});
* target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
* and returns the dropAllowed config value. This method should be overridden if drop validation is required.
*
- * IMPORTANT : it should set this.overClass and this.dropAllowed
+ * IMPORTANT : it should set this.valid to true|false
*
* @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
* @param {Event} e The event
* This method will be called on every mouse movement while the drag source is over the drop target.
* This default implementation simply returns the dropAllowed config value.
*
- * IMPORTANT : it should set this.dropAllowed
+ * IMPORTANT : it should set this.valid to true|false
*
* @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
* @param {Event} e The event
* out of the target without dropping. This default implementation simply removes the CSS class specified by
* overClass (if any) from the drop element.
*
+ *
* @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
* @param {Event} e The event
* @param {Object} data An object containing arbitrary data supplied by the drag source
remove : function(record){
var index = this.data.indexOf(record);
this.data.removeAt(index);
+
if(this.pruneModifiedRecords){
this.modified.remove(record);
}
this.totalLength = Math.max(t, this.data.length+r.length);
this.add(r);
}
+
+ if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
+
+ var e = new Roo.data.Record({});
+
+ e.set(this.parent.displayField, this.parent.emptyTitle);
+ e.set(this.parent.valueField, '');
+
+ this.insert(0, e);
+ }
+
this.fireEvent("load", this, r, options, o);
if(options.callback){
options.callback.call(options.scope || this, r, options, true);
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.MemoryProxy, Roo.data.DataProxy, {
+
/**
* Load data from the requested source (in this case an in-memory
* data object passed to the constructor), read the data object into
params = params || {};
var result;
try {
- result = reader.readRecords(this.data);
+ result = reader.readRecords(params.data ? params.data :this.data);
}catch(e){
this.fireEvent("loadexception", this, arg, null, e);
callback.call(scope, null, arg, false);
};
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
* <pre><code>
[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
</code></pre>
- * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
+
* @constructor
* Create a new JsonReader
* @param {Object} meta Metadata configuration options.
- * @param {Object} recordType Either an Array of field definition objects
+ * @param {Object|Array} recordType Either an Array of field definition objects
+ *
+ * @cfg {Array} fields Array of field definition objects
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
* as specified to {@link Roo.data.Record#create},
* or an {@link Roo.data.Record} object
+ *
+ *
* created using {@link Roo.data.Record#create}.
*/
-Roo.data.ArrayReader = function(meta, recordType){
- Roo.data.ArrayReader.superclass.constructor.call(this, 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} data A data block which is used by an Roo.data.Store object as
+ * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
* a cache of Roo.data.Records.
*/
- readRecords : function(o){
+ readRecords : function(o)
+ {
var sid = this.meta ? this.meta.id : null;
- var recordType = this.recordType, fields = recordType.prototype.fields;
- var records = [];
- var root = o;
- for(var i = 0; i < root.length; i++){
- var n = root[i];
- var values = {};
- var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
- for(var j = 0, jlen = fields.length; j < jlen; j++){
+ var recordType = this.recordType, fields = recordType.prototype.fields;
+ var records = [];
+ var root = o;
+ for(var i = 0; i < root.length; i++){
+ var n = root[i];
+ var values = {};
+ var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+ for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
var v = n[k] !== undefined ? n[k] : f.defaultValue;
v = f.convert(v);
values[f.name] = v;
}
- var record = new recordType(values, id);
- record.json = n;
- records[records.length] = record;
- }
- return {
- records : records,
- totalRecords : records.length
- };
+ var record = new recordType(values, id);
+ record.json = n;
+ records[records.length] = record;
+ }
+ return {
+ records : records,
+ totalRecords : records.length
+ };
+ },
+ // used when loading children.. @see loadDataFromChildren
+ toLoadData: function(rec)
+ {
+ // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+ return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+
}
+
+
});/*
* Based on:
* Ext JS Library 1.1.1
this.listeners = this.attributes.listeners;
Roo.data.Node.superclass.constructor.call(this);
};
-
-Roo.extend(Roo.data.Node, Roo.util.Observable, {
- fireEvent : function(evtName){
- // first do standard event for this node
- if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
- return false;
- }
- // then bubble it up to the tree if the event wasn't cancelled
- var ot = this.getOwnerTree();
- if(ot){
- if(ot.proxyNodeEvent.apply(ot, arguments) === false){
- return false;
- }
- }
- return true;
- },
-
- /**
- * Returns true if this node is a leaf
- * @return {Boolean}
- */
- isLeaf : function(){
- return this.leaf === true;
- },
-
- // private
- setFirstChild : function(node){
- this.firstChild = node;
- },
-
- //private
- setLastChild : function(node){
- this.lastChild = node;
- },
-
-
- /**
- * Returns true if this node is the last child of its parent
- * @return {Boolean}
- */
- isLast : function(){
- return (!this.parentNode ? true : this.parentNode.lastChild == this);
- },
-
- /**
- * Returns true if this node is the first child of its parent
- * @return {Boolean}
- */
- isFirst : function(){
- return (!this.parentNode ? true : this.parentNode.firstChild == this);
- },
-
- hasChildNodes : function(){
- return !this.isLeaf() && this.childNodes.length > 0;
- },
-
- /**
- * Insert node(s) as the last child node of this node.
- * @param {Node/Array} node The node or Array of nodes to append
- * @return {Node} The appended node if single append, or null if an array was passed
- */
- appendChild : function(node){
- var multi = false;
- if(node instanceof Array){
- multi = node;
- }else if(arguments.length > 1){
- multi = arguments;
- }
- // if passed an array or multiple args do them one by one
- if(multi){
- for(var i = 0, len = multi.length; i < len; i++) {
- this.appendChild(multi[i]);
- }
- }else{
- if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
- return false;
- }
- var index = this.childNodes.length;
- var oldParent = node.parentNode;
- // it's a move, make sure we move it cleanly
- if(oldParent){
- if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
- return false;
- }
- oldParent.removeChild(node);
- }
- index = this.childNodes.length;
- if(index == 0){
- this.setFirstChild(node);
- }
- this.childNodes.push(node);
- node.parentNode = this;
- var ps = this.childNodes[index-1];
- if(ps){
- node.previousSibling = ps;
- ps.nextSibling = node;
- }else{
- node.previousSibling = null;
- }
- node.nextSibling = null;
- this.setLastChild(node);
- node.setOwnerTree(this.getOwnerTree());
- this.fireEvent("append", this.ownerTree, this, node, index);
- if(oldParent){
- node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
- }
- return node;
- }
- },
-
- /**
- * Removes a child node from this node.
- * @param {Node} node The node to remove
- * @return {Node} The removed node
- */
- removeChild : function(node){
- var index = this.childNodes.indexOf(node);
- if(index == -1){
- return false;
- }
- if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
- return false;
- }
-
- // remove it from childNodes collection
- this.childNodes.splice(index, 1);
-
- // update siblings
- if(node.previousSibling){
- node.previousSibling.nextSibling = node.nextSibling;
- }
- if(node.nextSibling){
- node.nextSibling.previousSibling = node.previousSibling;
- }
-
- // update child refs
- if(this.firstChild == node){
- this.setFirstChild(node.nextSibling);
- }
- if(this.lastChild == node){
- this.setLastChild(node.previousSibling);
- }
-
- node.setOwnerTree(null);
- // clear any references from the node
- node.parentNode = null;
- node.previousSibling = null;
- node.nextSibling = null;
- this.fireEvent("remove", this.ownerTree, this, node);
- return node;
- },
-
- /**
- * Inserts the first node before the second node in this nodes childNodes collection.
- * @param {Node} node The node to insert
- * @param {Node} refNode The node to insert before (if null the node is appended)
- * @return {Node} The inserted node
- */
- insertBefore : function(node, refNode){
- if(!refNode){ // like standard Dom, refNode can be null for append
- return this.appendChild(node);
- }
- // nothing to do
- if(node == refNode){
- return false;
- }
-
- if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
- return false;
- }
- var index = this.childNodes.indexOf(refNode);
- var oldParent = node.parentNode;
- var refIndex = index;
-
- // when moving internally, indexes will change after remove
- if(oldParent == this && this.childNodes.indexOf(node) < index){
- refIndex--;
- }
-
- // it's a move, make sure we move it cleanly
- if(oldParent){
- if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
- return false;
- }
- oldParent.removeChild(node);
- }
- if(refIndex == 0){
- this.setFirstChild(node);
- }
- this.childNodes.splice(refIndex, 0, node);
- node.parentNode = this;
- var ps = this.childNodes[refIndex-1];
- if(ps){
- node.previousSibling = ps;
- ps.nextSibling = node;
- }else{
- node.previousSibling = null;
- }
- node.nextSibling = refNode;
- refNode.previousSibling = node;
- node.setOwnerTree(this.getOwnerTree());
- this.fireEvent("insert", this.ownerTree, this, node, refNode);
- if(oldParent){
- node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
- }
- return node;
- },
-
- /**
- * Returns the child node at the specified index.
- * @param {Number} index
- * @return {Node}
- */
- item : function(index){
- return this.childNodes[index];
- },
-
- /**
- * Replaces one child node in this node with another.
- * @param {Node} newChild The replacement node
- * @param {Node} oldChild The node to replace
- * @return {Node} The replaced node
- */
- replaceChild : function(newChild, oldChild){
- this.insertBefore(newChild, oldChild);
- this.removeChild(oldChild);
- return oldChild;
- },
-
- /**
- * Returns the index of a child node
- * @param {Node} node
- * @return {Number} The index of the node or -1 if it was not found
- */
- indexOf : function(child){
- return this.childNodes.indexOf(child);
- },
-
- /**
- * Returns the tree this node is in.
- * @return {Tree}
- */
- getOwnerTree : function(){
- // if it doesn't have one, look for one
- if(!this.ownerTree){
- var p = this;
- while(p){
- if(p.ownerTree){
- this.ownerTree = p.ownerTree;
- break;
- }
- p = p.parentNode;
+
+Roo.extend(Roo.data.Node, Roo.util.Observable, {
+ fireEvent : function(evtName){
+ // first do standard event for this node
+ if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
+ return false;
+ }
+ // then bubble it up to the tree if the event wasn't cancelled
+ var ot = this.getOwnerTree();
+ if(ot){
+ if(ot.proxyNodeEvent.apply(ot, arguments) === false){
+ return false;
}
}
- return this.ownerTree;
+ return true;
},
/**
- * Returns depth of this node (the root node has a depth of 0)
- * @return {Number}
+ * Returns true if this node is a leaf
+ * @return {Boolean}
*/
- getDepth : function(){
- var depth = 0;
- var p = this;
- while(p.parentNode){
- ++depth;
- p = p.parentNode;
- }
- return depth;
+ isLeaf : function(){
+ return this.leaf === true;
},
// private
- setOwnerTree : function(tree){
- // if it's move, we need to update everyone
- if(tree != this.ownerTree){
- if(this.ownerTree){
- this.ownerTree.unregisterNode(this);
- }
- this.ownerTree = tree;
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- cs[i].setOwnerTree(tree);
- }
- if(tree){
- tree.registerNode(this);
- }
- }
+ setFirstChild : function(node){
+ this.firstChild = node;
},
- /**
- * Returns the path for this node. The path can be used to expand or select this node programmatically.
- * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
- * @return {String} The path
- */
- getPath : function(attr){
- attr = attr || "id";
- var p = this.parentNode;
- var b = [this.attributes[attr]];
- while(p){
- b.unshift(p.attributes[attr]);
- p = p.parentNode;
- }
- var sep = this.getOwnerTree().pathSeparator;
- return sep + b.join(sep);
+ //private
+ setLastChild : function(node){
+ this.lastChild = node;
},
- /**
- * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
- * function call will be the scope provided or the current node. The arguments to the function
- * will be the args provided or the current node. If the function returns false at any point,
- * the bubble is stopped.
- * @param {Function} fn The function to call
- * @param {Object} scope (optional) The scope of the function (defaults to current node)
- * @param {Array} args (optional) The args to call the function with (default to passing the current node)
- */
- bubble : function(fn, scope, args){
- var p = this;
- while(p){
- if(fn.call(scope || p, args || p) === false){
- break;
- }
- p = p.parentNode;
- }
- },
/**
- * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
- * function call will be the scope provided or the current node. The arguments to the function
- * will be the args provided or the current node. If the function returns false at any point,
- * the cascade is stopped on that branch.
- * @param {Function} fn The function to call
- * @param {Object} scope (optional) The scope of the function (defaults to current node)
- * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+ * Returns true if this node is the last child of its parent
+ * @return {Boolean}
*/
- cascade : function(fn, scope, args){
- if(fn.call(scope || this, args || this) !== false){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- cs[i].cascade(fn, scope, args);
- }
- }
+ isLast : function(){
+ return (!this.parentNode ? true : this.parentNode.lastChild == this);
},
/**
- * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
- * function call will be the scope provided or the current node. The arguments to the function
- * will be the args provided or the current node. If the function returns false at any point,
- * the iteration stops.
- * @param {Function} fn The function to call
- * @param {Object} scope (optional) The scope of the function (defaults to current node)
- * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+ * Returns true if this node is the first child of its parent
+ * @return {Boolean}
*/
- eachChild : function(fn, scope, args){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- if(fn.call(scope || this, args || cs[i]) === false){
- break;
- }
- }
+ isFirst : function(){
+ return (!this.parentNode ? true : this.parentNode.firstChild == this);
},
- /**
- * Finds the first child that has the attribute with the specified value.
- * @param {String} attribute The attribute name
- * @param {Mixed} value The value to search for
- * @return {Node} The found child or null if none was found
- */
- findChild : function(attribute, value){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- if(cs[i].attributes[attribute] == value){
- return cs[i];
- }
- }
- return null;
+ hasChildNodes : function(){
+ return !this.isLeaf() && this.childNodes.length > 0;
},
/**
- * Finds the first child by a custom function. The child matches if the function passed
- * returns true.
- * @param {Function} fn
- * @param {Object} scope (optional)
- * @return {Node} The found child or null if none was found
+ * Insert node(s) as the last child node of this node.
+ * @param {Node/Array} node The node or Array of nodes to append
+ * @return {Node} The appended node if single append, or null if an array was passed
*/
- findChildBy : function(fn, scope){
- var cs = this.childNodes;
- for(var i = 0, len = cs.length; i < len; i++) {
- if(fn.call(scope||cs[i], cs[i]) === true){
- return cs[i];
- }
+ appendChild : function(node){
+ var multi = false;
+ if(node instanceof Array){
+ multi = node;
+ }else if(arguments.length > 1){
+ multi = arguments;
}
- return null;
- },
-
- /**
- * Sorts this nodes children using the supplied sort function
- * @param {Function} fn
- * @param {Object} scope (optional)
- */
- sort : function(fn, scope){
- var cs = this.childNodes;
- var len = cs.length;
- if(len > 0){
- var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
- cs.sort(sortFn);
- for(var i = 0; i < len; i++){
- var n = cs[i];
- n.previousSibling = cs[i-1];
- n.nextSibling = cs[i+1];
- if(i == 0){
- this.setFirstChild(n);
- }
- if(i == len-1){
- this.setLastChild(n);
+
+ // if passed an array or multiple args do them one by one
+ if(multi){
+ for(var i = 0, len = multi.length; i < len; i++) {
+ this.appendChild(multi[i]);
+ }
+ }else{
+ if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
+ return false;
+ }
+ var index = this.childNodes.length;
+ var oldParent = node.parentNode;
+ // it's a move, make sure we move it cleanly
+ if(oldParent){
+ if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
+ return false;
}
+ oldParent.removeChild(node);
+ }
+
+ index = this.childNodes.length;
+ if(index == 0){
+ this.setFirstChild(node);
+ }
+ this.childNodes.push(node);
+ node.parentNode = this;
+ var ps = this.childNodes[index-1];
+ if(ps){
+ node.previousSibling = ps;
+ ps.nextSibling = node;
+ }else{
+ node.previousSibling = null;
+ }
+ node.nextSibling = null;
+ this.setLastChild(node);
+ node.setOwnerTree(this.getOwnerTree());
+ this.fireEvent("append", this.ownerTree, this, node, index);
+ if(this.ownerTree) {
+ this.ownerTree.fireEvent("appendnode", this, node, index);
}
+ if(oldParent){
+ node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+ }
+ return node;
}
},
/**
- * Returns true if this node is an ancestor (at any point) of the passed node.
- * @param {Node} node
- * @return {Boolean}
- */
- contains : function(node){
- return node.isAncestor(this);
- },
-
- /**
- * Returns true if the passed node is an ancestor (at any point) of this node.
- * @param {Node} node
- * @return {Boolean}
+ * Removes a child node from this node.
+ * @param {Node} node The node to remove
+ * @return {Node} The removed node
*/
- isAncestor : function(node){
- var p = this.parentNode;
- while(p){
- if(p == node){
- return true;
- }
- p = p.parentNode;
- }
- return false;
- },
-
- toString : function(){
- return "[Node"+(this.id?" "+this.id:"")+"]";
- }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
- (function(){
-/**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
- * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
- * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
- */
-
-Roo.Layer = function(config, existingEl){
- config = config || {};
- var dh = Roo.DomHelper;
- var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
- if(existingEl){
- this.dom = Roo.getDom(existingEl);
- }
- if(!this.dom){
- var o = config.dh || {tag: "div", cls: "x-layer"};
- this.dom = dh.append(pel, o);
- }
- if(config.cls){
- this.addClass(config.cls);
- }
- this.constrain = config.constrain !== false;
- this.visibilityMode = Roo.Element.VISIBILITY;
- if(config.id){
- this.id = this.dom.id = config.id;
- }else{
- this.id = Roo.id(this.dom);
- }
- this.zindex = config.zindex || this.getZIndex();
- this.position("absolute", this.zindex);
- if(config.shadow){
- this.shadowOffset = config.shadowOffset || 4;
- this.shadow = new Roo.Shadow({
- offset : this.shadowOffset,
- mode : config.shadow
- });
- }else{
- this.shadowOffset = 0;
- }
- this.useShim = config.shim !== false && Roo.useShims;
- this.useDisplay = config.useDisplay;
- this.hide();
-};
-
-var supr = Roo.Element.prototype;
-
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
-
-Roo.extend(Roo.Layer, Roo.Element, {
-
- getZIndex : function(){
- return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
- },
-
- getShim : function(){
- if(!this.useShim){
- return null;
- }
- if(this.shim){
- return this.shim;
- }
- var shim = shims.shift();
- if(!shim){
- shim = this.createShim();
- shim.enableDisplayMode('block');
- shim.dom.style.display = 'none';
- shim.dom.style.visibility = 'visible';
- }
- var pn = this.dom.parentNode;
- if(shim.dom.parentNode != pn){
- pn.insertBefore(shim.dom, this.dom);
+ removeChild : function(node){
+ var index = this.childNodes.indexOf(node);
+ if(index == -1){
+ return false;
}
- shim.setStyle('z-index', this.getZIndex()-2);
- this.shim = shim;
- return shim;
- },
-
- hideShim : function(){
- if(this.shim){
- this.shim.setDisplayed(false);
- shims.push(this.shim);
- delete this.shim;
+ if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
+ return false;
}
- },
- disableShadow : function(){
- if(this.shadow){
- this.shadowDisabled = true;
- this.shadow.hide();
- this.lastShadowOffset = this.shadowOffset;
- this.shadowOffset = 0;
- }
- },
+ // remove it from childNodes collection
+ this.childNodes.splice(index, 1);
- enableShadow : function(show){
- if(this.shadow){
- this.shadowDisabled = false;
- this.shadowOffset = this.lastShadowOffset;
- delete this.lastShadowOffset;
- if(show){
- this.sync(true);
- }
+ // update siblings
+ if(node.previousSibling){
+ node.previousSibling.nextSibling = node.nextSibling;
}
- },
-
- // private
- // this code can execute repeatedly in milliseconds (i.e. during a drag) so
- // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
- sync : function(doShow){
- var sw = this.shadow;
- if(!this.updating && this.isVisible() && (sw || this.useShim)){
- var sh = this.getShim();
-
- var w = this.getWidth(),
- h = this.getHeight();
-
- var l = this.getLeft(true),
- t = this.getTop(true);
-
- if(sw && !this.shadowDisabled){
- if(doShow && !sw.isVisible()){
- sw.show(this);
- }else{
- sw.realign(l, t, w, h);
- }
- if(sh){
- if(doShow){
- sh.show();
- }
- // fit the shim behind the shadow, so it is shimmed too
- var a = sw.adjusts, s = sh.dom.style;
- s.left = (Math.min(l, l+a.l))+"px";
- s.top = (Math.min(t, t+a.t))+"px";
- s.width = (w+a.w)+"px";
- s.height = (h+a.h)+"px";
- }
- }else if(sh){
- if(doShow){
- sh.show();
- }
- sh.setSize(w, h);
- sh.setLeftTop(l, t);
- }
-
+ if(node.nextSibling){
+ node.nextSibling.previousSibling = node.previousSibling;
}
- },
- // private
- destroy : function(){
- this.hideShim();
- if(this.shadow){
- this.shadow.hide();
+ // update child refs
+ if(this.firstChild == node){
+ this.setFirstChild(node.nextSibling);
}
- this.removeAllListeners();
- var pn = this.dom.parentNode;
- if(pn){
- pn.removeChild(this.dom);
+ if(this.lastChild == node){
+ this.setLastChild(node.previousSibling);
}
- Roo.Element.uncache(this.id);
- },
-
- remove : function(){
- this.destroy();
- },
-
- // private
- beginUpdate : function(){
- this.updating = true;
- },
-
- // private
- endUpdate : function(){
- this.updating = false;
- this.sync(true);
- },
- // private
- hideUnders : function(negOffset){
- if(this.shadow){
- this.shadow.hide();
- }
- this.hideShim();
+ node.setOwnerTree(null);
+ // clear any references from the node
+ node.parentNode = null;
+ node.previousSibling = null;
+ node.nextSibling = null;
+ this.fireEvent("remove", this.ownerTree, this, node);
+ return node;
},
- // private
- constrainXY : function(){
- if(this.constrain){
- var vw = Roo.lib.Dom.getViewWidth(),
- vh = Roo.lib.Dom.getViewHeight();
- var s = Roo.get(document).getScroll();
-
- var xy = this.getXY();
- var x = xy[0], y = xy[1];
- var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
- // only move it if it needs it
- var moved = false;
- // first validate right/bottom
- if((x + w) > vw+s.left){
- x = vw - w - this.shadowOffset;
- moved = true;
- }
- if((y + h) > vh+s.top){
- y = vh - h - this.shadowOffset;
- moved = true;
- }
- // then make sure top/left isn't negative
- if(x < s.left){
- x = s.left;
- moved = true;
- }
- if(y < s.top){
- y = s.top;
- moved = true;
- }
- if(moved){
- if(this.avoidY){
- var ay = this.avoidY;
- if(y <= ay && (y+h) >= ay){
- y = ay-h-5;
- }
- }
- xy = [x, y];
- this.storeXY(xy);
- supr.setXY.call(this, xy);
- this.sync();
- }
+ /**
+ * Inserts the first node before the second node in this nodes childNodes collection.
+ * @param {Node} node The node to insert
+ * @param {Node} refNode The node to insert before (if null the node is appended)
+ * @return {Node} The inserted node
+ */
+ insertBefore : function(node, refNode){
+ if(!refNode){ // like standard Dom, refNode can be null for append
+ return this.appendChild(node);
+ }
+ // nothing to do
+ if(node == refNode){
+ return false;
}
- },
-
- isVisible : function(){
- return this.visible;
- },
- // private
- showAction : function(){
- this.visible = true; // track visibility to prevent getStyle calls
- if(this.useDisplay === true){
- this.setDisplayed("");
- }else if(this.lastXY){
- supr.setXY.call(this, this.lastXY);
- }else if(this.lastLT){
- supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
+ if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
+ return false;
}
- },
+ var index = this.childNodes.indexOf(refNode);
+ var oldParent = node.parentNode;
+ var refIndex = index;
- // private
- hideAction : function(){
- this.visible = false;
- if(this.useDisplay === true){
- this.setDisplayed(false);
- }else{
- this.setLeftTop(-10000,-10000);
+ // when moving internally, indexes will change after remove
+ if(oldParent == this && this.childNodes.indexOf(node) < index){
+ refIndex--;
}
- },
- // overridden Element method
- setVisible : function(v, a, d, c, e){
- if(v){
- this.showAction();
+ // it's a move, make sure we move it cleanly
+ if(oldParent){
+ if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
+ return false;
+ }
+ oldParent.removeChild(node);
}
- if(a && v){
- var cb = function(){
- this.sync(true);
- if(c){
- c();
- }
- }.createDelegate(this);
- supr.setVisible.call(this, true, true, d, cb, e);
+ if(refIndex == 0){
+ this.setFirstChild(node);
+ }
+ this.childNodes.splice(refIndex, 0, node);
+ node.parentNode = this;
+ var ps = this.childNodes[refIndex-1];
+ if(ps){
+ node.previousSibling = ps;
+ ps.nextSibling = node;
}else{
- if(!v){
- this.hideUnders(true);
- }
- var cb = c;
- if(a){
- cb = function(){
- this.hideAction();
- if(c){
- c();
- }
- }.createDelegate(this);
- }
- supr.setVisible.call(this, v, a, d, cb, e);
- if(v){
- this.sync(true);
- }else if(!a){
- this.hideAction();
- }
+ node.previousSibling = null;
}
+ node.nextSibling = refNode;
+ refNode.previousSibling = node;
+ node.setOwnerTree(this.getOwnerTree());
+ this.fireEvent("insert", this.ownerTree, this, node, refNode);
+ if(oldParent){
+ node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
+ }
+ return node;
},
- storeXY : function(xy){
- delete this.lastLT;
- this.lastXY = xy;
- },
-
- storeLeftTop : function(left, top){
- delete this.lastXY;
- this.lastLT = [left, top];
+ /**
+ * Returns the child node at the specified index.
+ * @param {Number} index
+ * @return {Node}
+ */
+ item : function(index){
+ return this.childNodes[index];
},
- // private
- beforeFx : function(){
- this.beforeAction();
- return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+ /**
+ * Replaces one child node in this node with another.
+ * @param {Node} newChild The replacement node
+ * @param {Node} oldChild The node to replace
+ * @return {Node} The replaced node
+ */
+ replaceChild : function(newChild, oldChild){
+ this.insertBefore(newChild, oldChild);
+ this.removeChild(oldChild);
+ return oldChild;
},
- // private
- afterFx : function(){
- Roo.Layer.superclass.afterFx.apply(this, arguments);
- this.sync(this.isVisible());
+ /**
+ * Returns the index of a child node
+ * @param {Node} node
+ * @return {Number} The index of the node or -1 if it was not found
+ */
+ indexOf : function(child){
+ return this.childNodes.indexOf(child);
},
- // private
- beforeAction : function(){
- if(!this.updating && this.shadow){
- this.shadow.hide();
+ /**
+ * Returns the tree this node is in.
+ * @return {Tree}
+ */
+ getOwnerTree : function(){
+ // if it doesn't have one, look for one
+ if(!this.ownerTree){
+ var p = this;
+ while(p){
+ if(p.ownerTree){
+ this.ownerTree = p.ownerTree;
+ break;
+ }
+ p = p.parentNode;
+ }
}
+ return this.ownerTree;
},
- // overridden Element method
- setLeft : function(left){
- this.storeLeftTop(left, this.getTop(true));
- supr.setLeft.apply(this, arguments);
- this.sync();
- },
-
- setTop : function(top){
- this.storeLeftTop(this.getLeft(true), top);
- supr.setTop.apply(this, arguments);
- this.sync();
+ /**
+ * Returns depth of this node (the root node has a depth of 0)
+ * @return {Number}
+ */
+ getDepth : function(){
+ var depth = 0;
+ var p = this;
+ while(p.parentNode){
+ ++depth;
+ p = p.parentNode;
+ }
+ return depth;
},
- setLeftTop : function(left, top){
- this.storeLeftTop(left, top);
- supr.setLeftTop.apply(this, arguments);
- this.sync();
+ // private
+ setOwnerTree : function(tree){
+ // if it's move, we need to update everyone
+ if(tree != this.ownerTree){
+ if(this.ownerTree){
+ this.ownerTree.unregisterNode(this);
+ }
+ this.ownerTree = tree;
+ var cs = this.childNodes;
+ for(var i = 0, len = cs.length; i < len; i++) {
+ cs[i].setOwnerTree(tree);
+ }
+ if(tree){
+ tree.registerNode(this);
+ }
+ }
},
- setXY : function(xy, a, d, c, e){
- this.fixDisplay();
- this.beforeAction();
- this.storeXY(xy);
- var cb = this.createCB(c);
- supr.setXY.call(this, xy, a, d, cb, e);
- if(!a){
- cb();
+ /**
+ * Returns the path for this node. The path can be used to expand or select this node programmatically.
+ * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
+ * @return {String} The path
+ */
+ getPath : function(attr){
+ attr = attr || "id";
+ var p = this.parentNode;
+ var b = [this.attributes[attr]];
+ while(p){
+ b.unshift(p.attributes[attr]);
+ p = p.parentNode;
}
+ var sep = this.getOwnerTree().pathSeparator;
+ return sep + b.join(sep);
},
- // private
- createCB : function(c){
- var el = this;
- return function(){
- el.constrainXY();
- el.sync(true);
- if(c){
- c();
+ /**
+ * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+ * function call will be the scope provided or the current node. The arguments to the function
+ * will be the args provided or the current node. If the function returns false at any point,
+ * the bubble is stopped.
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope of the function (defaults to current node)
+ * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+ */
+ bubble : function(fn, scope, args){
+ var p = this;
+ while(p){
+ if(fn.call(scope || p, args || p) === false){
+ break;
}
- };
+ p = p.parentNode;
+ }
},
- // overridden Element method
- setX : function(x, a, d, c, e){
- this.setXY([x, this.getY()], a, d, c, e);
+ /**
+ * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+ * function call will be the scope provided or the current node. The arguments to the function
+ * will be the args provided or the current node. If the function returns false at any point,
+ * the cascade is stopped on that branch.
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope of the function (defaults to current node)
+ * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+ */
+ cascade : function(fn, scope, args){
+ if(fn.call(scope || this, args || this) !== false){
+ var cs = this.childNodes;
+ for(var i = 0, len = cs.length; i < len; i++) {
+ cs[i].cascade(fn, scope, args);
+ }
+ }
},
- // overridden Element method
- setY : function(y, a, d, c, e){
- this.setXY([this.getX(), y], a, d, c, e);
+ /**
+ * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
+ * function call will be the scope provided or the current node. The arguments to the function
+ * will be the args provided or the current node. If the function returns false at any point,
+ * the iteration stops.
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope of the function (defaults to current node)
+ * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+ */
+ eachChild : function(fn, scope, args){
+ var cs = this.childNodes;
+ for(var i = 0, len = cs.length; i < len; i++) {
+ if(fn.call(scope || this, args || cs[i]) === false){
+ break;
+ }
+ }
},
- // overridden Element method
- setSize : function(w, h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setSize.call(this, w, h, a, d, cb, e);
- if(!a){
- cb();
+ /**
+ * Finds the first child that has the attribute with the specified value.
+ * @param {String} attribute The attribute name
+ * @param {Mixed} value The value to search for
+ * @return {Node} The found child or null if none was found
+ */
+ findChild : function(attribute, value){
+ var cs = this.childNodes;
+ for(var i = 0, len = cs.length; i < len; i++) {
+ if(cs[i].attributes[attribute] == value){
+ return cs[i];
+ }
}
+ return null;
},
- // overridden Element method
- setWidth : function(w, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setWidth.call(this, w, a, d, cb, e);
- if(!a){
- cb();
+ /**
+ * Finds the first child by a custom function. The child matches if the function passed
+ * returns true.
+ * @param {Function} fn
+ * @param {Object} scope (optional)
+ * @return {Node} The found child or null if none was found
+ */
+ findChildBy : function(fn, scope){
+ var cs = this.childNodes;
+ for(var i = 0, len = cs.length; i < len; i++) {
+ if(fn.call(scope||cs[i], cs[i]) === true){
+ return cs[i];
+ }
}
+ return null;
},
- // overridden Element method
- setHeight : function(h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- supr.setHeight.call(this, h, a, d, cb, e);
- if(!a){
- cb();
+ /**
+ * Sorts this nodes children using the supplied sort function
+ * @param {Function} fn
+ * @param {Object} scope (optional)
+ */
+ sort : function(fn, scope){
+ var cs = this.childNodes;
+ var len = cs.length;
+ if(len > 0){
+ var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
+ cs.sort(sortFn);
+ for(var i = 0; i < len; i++){
+ var n = cs[i];
+ n.previousSibling = cs[i-1];
+ n.nextSibling = cs[i+1];
+ if(i == 0){
+ this.setFirstChild(n);
+ }
+ if(i == len-1){
+ this.setLastChild(n);
+ }
+ }
}
},
- // overridden Element method
- setBounds : function(x, y, w, h, a, d, c, e){
- this.beforeAction();
- var cb = this.createCB(c);
- if(!a){
- this.storeXY([x, y]);
- supr.setXY.call(this, [x, y]);
- supr.setSize.call(this, w, h, a, d, cb, e);
- cb();
- }else{
- supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
- }
- return this;
+ /**
+ * Returns true if this node is an ancestor (at any point) of the passed node.
+ * @param {Node} node
+ * @return {Boolean}
+ */
+ contains : function(node){
+ return node.isAncestor(this);
},
-
+
/**
- * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
- * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
- * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
- * @param {Number} zindex The new z-index to set
- * @return {this} The Layer
+ * Returns true if the passed node is an ancestor (at any point) of this node.
+ * @param {Node} node
+ * @return {Boolean}
*/
- setZIndex : function(zindex){
- this.zindex = zindex;
- this.setStyle("z-index", zindex + 2);
- if(this.shadow){
- this.shadow.setZIndex(zindex + 1);
- }
- if(this.shim){
- this.shim.setStyle("z-index", zindex);
+ isAncestor : function(node){
+ var p = this.parentNode;
+ while(p){
+ if(p == node){
+ return true;
+ }
+ p = p.parentNode;
}
+ return false;
+ },
+
+ toString : function(){
+ return "[Node"+(this.id?" "+this.id:"")+"]";
}
-});
-})();/*
+});/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
* A simple class that renders text directly into a toolbar.
* @constructor
* Creates a new TextItem
- * @param {String} text
+ * @cfg {string} text
*/
Roo.Toolbar.TextItem = function(cfg){
var text = cfg || "";
if(ttp){
showProc = show.defer(tm.showDelay, tm, [{
el: t,
- text: ttp,
+ text: ttp.replace(/\\n/g,'<br/>'),
width: et.getAttributeNS(ns, cfg.width),
autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
title: et.getAttributeNS(ns, cfg.title),
* </ul>
* @param {Object} dragOverEvent
*/
- "nodedragover" : true
+ "nodedragover" : true,
+ /**
+ * @event appendnode
+ * Fires when append node to the tree
+ * @param {Roo.tree.TreePanel} this
+ * @param {Roo.tree.TreeNode} node
+ * @param {Number} index The index of the newly appended node
+ */
+ "appendnode" : true
});
if(this.singleExpand){
* @cfg {Boolean} allowDrop false if this node cannot be drop on
* @cfg {Boolean} disabled true to start the node disabled
* @cfg {String} icon The path to an icon for the node. The preferred way to do this
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.
+ * is to use the cls or iconCls attributes and add the icon via a CSS background image.
* @cfg {String} cls A css class to be added to the node
* @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
* @cfg {String} href URL of the link used for the node (defaults to #)
this.renderChildren();
}
this.expanded = true;
- if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
+
+ if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
this.ui.animExpand(function(){
this.fireEvent("expand", this);
if(typeof callback == "function"){
this.addClass("x-tree-node-disabled");
}
var ot = this.node.getOwnerTree();
- var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
+ var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
if(dd && (!this.node.isRoot || ot.rootVisible)){
Roo.dd.Registry.register(this.elNode, {
node: this.node,
// 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);
+ var txt = t && 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 tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
var cb = typeof a.checked == 'boolean';
var href = a.href ? a.href : Roo.isGecko ? "" : "#";
var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
myTreeLoader.on("beforeload", function(treeLoader, node) {
this.baseParams.category = node.attributes.category;
}, this);
-</code></pre><
+
+</code></pre>
+ *
* This would pass an HTTP parameter called "category" to the server containing
* the value of the Node's "category" attribute.
* @constructor
* @param {Object} config Configuration options
*/
Roo.menu.Menu = function(config){
- Roo.apply(this, config);
+
+ Roo.menu.Menu.superclass.constructor.call(this, config);
+
this.id = this.id || Roo.id();
this.addEvents({
/**
Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
/**
- * @cfg {Boolean} text Text to show on item.
+ * @cfg {String} text Text to show on item.
*/
text : '',
* <script type="text/javascript">
*/
+/**
+ * @class Roo.form.TextItem
+ * @extends Roo.BoxComponent
+ * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
+ * @constructor
+ * Creates a new TextItem
+ * @param {Object} config Configuration options
+ */
+Roo.form.TextItem = function(config){
+ Roo.form.TextItem.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
+
+ /**
+ * @cfg {String} tag the tag for this item (default div)
+ */
+ tag : 'div',
+ /**
+ * @cfg {String} html the content for this item
+ */
+ html : '',
+
+ getAutoCreate : function()
+ {
+ var cfg = {
+ id: this.id,
+ tag: this.tag,
+ html: this.html,
+ cls: 'x-form-item'
+ };
+
+ return cfg;
+
+ },
+
+ onRender : function(ct, position)
+ {
+ Roo.form.TextItem.superclass.onRender.call(this, ct, position);
+
+ if(!this.el){
+ var cfg = this.getAutoCreate();
+ if(!cfg.name){
+ cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
+ }
+ if (!cfg.name.length) {
+ delete cfg.name;
+ }
+ this.el = ct.createChild(cfg, position);
+ }
+ },
+ /*
+ * setHTML
+ * @param {String} html update the Contents of the element.
+ */
+ setHTML : function(html)
+ {
+ this.fieldEl.dom.innerHTML = html;
+ }
+
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
/**
* @class Roo.form.Field
* @extends Roo.BoxComponent
*/
reset : function(){
this.setValue(this.resetValue);
+ this.originalValue = this.getValue();
this.clearInvalid();
},
* @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
*/
selectOnFocus : false,
+ /**
+ * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
+ */
+ allowLeadingSpace : false,
/**
* @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
*/
if(this.selectOnFocus){
this.on("focus", this.preFocus, this);
-
}
+ if (!this.allowLeadingSpace) {
+ this.on('blur', this.cleanLeadingSpace, this);
+ }
+
if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
this.el.on("keypress", this.filterKeys, this);
}
this.autoSize();
}
},
-
+ // private - clean the leading white space
+ cleanLeadingSpace : function(e)
+ {
+ 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.
*
reset : function(){
Roo.form.TextField.superclass.reset.call(this);
- },
-
-
+ },
// private
preFocus : function(){
* 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);
reset : function(){
// overridden so that last data is reset..
this.setValue(this.resetValue);
+ this.originalValue = this.getValue();
this.clearInvalid();
this.lastData = false;
if (this.view) {
this.view.select(match);
var sn = Roo.get(this.view.getSelectedNodes()[0]);
sn.scrollIntoView(sn.dom.parentNode, false);
- }
+ }
/**
* @cfg {Boolean} grow
* @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
*/
hiddenName : false,
-
+ /**
+ * @cfg {String} seperator The value seperator normally ','
+ */
+ seperator : ',',
// private the array of items that are displayed..
items : false,
// give fake names to child combo;
this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
- this.combo.name = this.name? (this.name+'-subcombo') : this.name;
+ this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
this.combo = Roo.factory(this.combo, Roo.form);
this.combo.onRender(ct, position);
{
var valueField = this.combo.valueField;
var displayField = this.combo.displayField;
+
if (this.items.indexOfKey(rec[valueField]) > -1) {
//console.log("GOT " + rec.data.id);
return;
this.items.each(function(f) {
ar.push(f.data[idField]);
-
});
- this.hiddenEl.dom.value = ar.join(',');
+ this.hiddenEl.dom.value = ar.join(this.seperator);
this.validate();
},
},
setValue: function(v) // not a valid action - must use addItems..
{
-
- this.reset();
-
-
+ this.reset();
+
if (this.store.isLocal && (typeof(v) == 'string')) {
// then we can use the store to find the values..
// comma seperated at present.. this needs to allow JSON based encoding..
this.hiddenEl.value = v;
var v_ar = [];
- Roo.each(v.split(','), function(k) {
+ Roo.each(v.split(this.seperator), function(k) {
Roo.log("CHECK " + this.valueField + ',' + k);
var li = this.store.query(this.valueField, k);
if (!li.length) {
if (typeof(v) == 'object' ) {
// then let's assume it's an array of objects..
Roo.each(v, function(l) {
- this.addItem(l);
+ var add = l;
+ if (typeof(l) == 'string') {
+ add = {};
+ add[this.valueField] = l;
+ add[this.displayField] = l
+ }
+ this.addItem(add);
}, this);
}
dv = typeof(dv) != 'string' ? '' : dv;
- var keys = kv.split(',');
- var display = dv.split(',');
+ var keys = kv.split(this.seperator);
+ var display = dv.split(this.seperator);
for (var i = 0 ; i < keys.length; i++) {
-
add = {};
add[this.valueField] = keys[i];
add[this.displayField] = display[i];
originalValue.push(d[i][this.valueField]);
}
- return String(this.getValue()) !== String(originalValue.join(','));
+ return String(this.getValue()) !== String(originalValue.join(this.seperator));
}
}
}
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011 Alan Knowles
+ *
+ * License - LGPL
+ */
+
+
+/**
+ * @class Roo.form.ComboNested
+ * @extends Roo.form.ComboBox
+ * A combobox for that allows selection of nested items in a list,
+ * eg.
+ *
+ * Book
+ * -> red
+ * -> green
+ * Table
+ * -> square
+ * ->red
+ * ->green
+ * -> rectangle
+ * ->green
+ *
+ *
+ * @constructor
+ * Create a new ComboNested
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboNested = function(config){
+ Roo.form.ComboCheck.superclass.constructor.call(this, config);
+ // should verify some data...
+ // like
+ // hiddenName = required..
+ // displayField = required
+ // valudField == required
+ var req= [ 'hiddenName', 'displayField', 'valueField' ];
+ var _t = this;
+ Roo.each(req, function(e) {
+ if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+ throw "Roo.form.ComboNested : missing value for: " + e;
+ }
+ });
+
+
+};
+
+Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
+
+ /*
+ * @config {Number} max Number of columns to show
+ */
+
+ maxColumns : 3,
+
+ list : null, // the outermost div..
+ innerLists : null, // the
+ views : null,
+ stores : null,
+ // private
+ loadingChildren : false,
+
+ onRender : function(ct, position)
+ {
+ Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
+
+ if(this.hiddenName){
+ this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
+ 'before', true);
+ this.hiddenField.value =
+ this.hiddenValue !== undefined ? this.hiddenValue :
+ this.value !== undefined ? this.value : '';
+
+ // prevent input submission
+ this.el.dom.removeAttribute('name');
+
+
+ }
+
+ if(Roo.isGecko){
+ this.el.dom.setAttribute('autocomplete', 'off');
+ }
+
+ var cls = 'x-combo-list';
+
+ this.list = new Roo.Layer({
+ shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+ });
+
+ var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
+ this.list.setWidth(lw);
+ this.list.swallowEvent('mousewheel');
+ this.assetHeight = 0;
+
+ if(this.title){
+ this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+ this.assetHeight += this.header.getHeight();
+ }
+ this.innerLists = [];
+ this.views = [];
+ this.stores = [];
+ for (var i =0 ; i < this.maxColumns; i++) {
+ this.onRenderList( cls, i);
+ }
+
+ // always needs footer, as we are going to have an 'OK' button.
+ this.footer = this.list.createChild({cls:cls+'-ft'});
+ this.pageTb = new Roo.Toolbar(this.footer);
+ var _this = this;
+ this.pageTb.add( {
+
+ text: 'Done',
+ handler: function()
+ {
+ _this.collapse();
+ }
+ });
+
+ if ( this.allowBlank && !this.disableClear) {
+
+ this.pageTb.add(new Roo.Toolbar.Fill(), {
+ cls: 'x-btn-icon x-btn-clear',
+ text: ' ',
+ handler: function()
+ {
+ _this.collapse();
+ _this.clearValue();
+ _this.onSelect(false, -1);
+ }
+ });
+ }
+ if (this.footer) {
+ this.assetHeight += this.footer.getHeight();
+ }
+
+ },
+ onRenderList : function ( cls, i)
+ {
+
+ var lw = Math.floor(
+ ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+ );
+
+ this.list.setWidth(lw); // default to '1'
+
+ var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
+ //il.on('mouseover', this.onViewOver, this, { list: i });
+ //il.on('mousemove', this.onViewMove, this, { list: i });
+ il.setWidth(lw);
+ il.setStyle({ 'overflow-x' : 'hidden'});
+
+ if(!this.tpl){
+ this.tpl = new Roo.Template({
+ html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
+ isEmpty: function (value, allValues) {
+ //Roo.log(value);
+ var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
+ return dl ? 'has-children' : 'no-children'
+ }
+ });
+ }
+
+ var store = this.store;
+ if (i > 0) {
+ store = new Roo.data.SimpleStore({
+ //fields : this.store.reader.meta.fields,
+ reader : this.store.reader,
+ data : [ ]
+ });
+ }
+ this.stores[i] = store;
+
+ var view = this.views[i] = new Roo.View(
+ il,
+ this.tpl,
+ {
+ singleSelect:true,
+ store: store,
+ selectedClass: this.selectedClass
+ }
+ );
+ view.getEl().setWidth(lw);
+ view.getEl().setStyle({
+ position: i < 1 ? 'relative' : 'absolute',
+ top: 0,
+ left: (i * lw ) + 'px',
+ display : i > 0 ? 'none' : 'block'
+ });
+ view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
+ view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
+ //view.on('click', this.onViewClick, this, { list : i });
+
+ store.on('beforeload', this.onBeforeLoad, this);
+ store.on('load', this.onLoad, this, { list : i});
+ store.on('loadexception', this.onLoadException, this);
+
+ // hide the other vies..
+
+
+
+ },
+
+ restrictHeight : function()
+ {
+ var mh = 0;
+ Roo.each(this.innerLists, function(il,i) {
+ var el = this.views[i].getEl();
+ el.dom.style.height = '';
+ var inner = el.dom;
+ var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
+ // only adjust heights on other ones..
+ mh = Math.max(h, mh);
+ if (i < 1) {
+
+ el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+ il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+
+ }
+
+
+ }, this);
+
+ this.list.beginUpdate();
+ this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
+ this.list.alignTo(this.el, this.listAlign);
+ this.list.endUpdate();
+
+ },
+
+
+ // -- store handlers..
+ // private
+ onBeforeLoad : function()
+ {
+ if(!this.hasFocus){
+ return;
+ }
+ this.innerLists[0].update(this.loadingText ?
+ '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+ this.restrictHeight();
+ this.selectedIndex = -1;
+ },
+ // private
+ onLoad : function(a,b,c,d)
+ {
+ if (!this.loadingChildren) {
+ // then we are loading the top level. - hide the children
+ for (var i = 1;i < this.views.length; i++) {
+ this.views[i].getEl().setStyle({ display : 'none' });
+ }
+ var lw = Math.floor(
+ ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+ );
+
+ this.list.setWidth(lw); // default to '1'
+
+
+ }
+ if(!this.hasFocus){
+ return;
+ }
+
+ if(this.store.getCount() > 0) {
+ this.expand();
+ this.restrictHeight();
+ } else {
+ this.onEmptyResults();
+ }
+
+ if (!this.loadingChildren) {
+ this.selectActive();
+ }
+ /*
+ this.stores[1].loadData([]);
+ this.stores[2].loadData([]);
+ this.views
+ */
+
+ //this.el.focus();
+ },
+
+
+ // private
+ onLoadException : function()
+ {
+ this.collapse();
+ Roo.log(this.store.reader.jsonData);
+ if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+ Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+ }
+
+
+ },
+ // no cleaning of leading spaces on blur here.
+ cleanLeadingSpace : function(e) { },
+
+
+ onSelectChange : function (view, sels, opts )
+ {
+ var ix = view.getSelectedIndexes();
+
+ if (opts.list > this.maxColumns - 2) {
+ if (view.store.getCount()< 1) {
+ this.views[opts.list ].getEl().setStyle({ display : 'none' });
+
+ } else {
+ if (ix.length) {
+ // used to clear ?? but if we are loading unselected
+ this.setFromData(view.store.getAt(ix[0]).data);
+ }
+
+ }
+
+ return;
+ }
+
+ if (!ix.length) {
+ // this get's fired when trigger opens..
+ // this.setFromData({});
+ var str = this.stores[opts.list+1];
+ str.data.clear(); // removeall wihtout the fire events..
+ return;
+ }
+
+ var rec = view.store.getAt(ix[0]);
+
+ this.setFromData(rec.data);
+ this.fireEvent('select', this, rec, ix[0]);
+
+ var lw = Math.floor(
+ (
+ (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
+ ) / this.maxColumns
+ );
+ this.loadingChildren = true;
+ this.stores[opts.list+1].loadDataFromChildren( rec );
+ this.loadingChildren = false;
+ var dl = this.stores[opts.list+1]. getTotalCount();
+
+ this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
+
+ this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
+ for (var i = opts.list+2; i < this.views.length;i++) {
+ this.views[i].getEl().setStyle({ display : 'none' });
+ }
+
+ this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
+ this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
+
+ if (this.isLoading) {
+ // this.selectActive(opts.list);
+ }
+
+ },
+
+
+
+
+ onDoubleClick : function()
+ {
+ this.collapse(); //??
+ },
+
+
+
+
+
+ // private
+ recordToStack : function(store, prop, value, stack)
+ {
+ var cstore = new Roo.data.SimpleStore({
+ //fields : this.store.reader.meta.fields, // we need array reader.. for
+ reader : this.store.reader,
+ data : [ ]
+ });
+ var _this = this;
+ var record = false;
+ var srec = false;
+ if(store.getCount() < 1){
+ return false;
+ }
+ store.each(function(r){
+ if(r.data[prop] == value){
+ record = r;
+ srec = r;
+ return false;
+ }
+ if (r.data.cn && r.data.cn.length) {
+ cstore.loadDataFromChildren( r);
+ var cret = _this.recordToStack(cstore, prop, value, stack);
+ if (cret !== false) {
+ record = cret;
+ srec = r;
+ return false;
+ }
+ }
+
+ return true;
+ });
+ if (record == false) {
+ return false
+ }
+ stack.unshift(srec);
+ return record;
+ },
+
+ /*
+ * find the stack of stores that match our value.
+ *
+ *
+ */
+
+ selectActive : function ()
+ {
+ // if store is not loaded, then we will need to wait for that to happen first.
+ var stack = [];
+ this.recordToStack(this.store, this.valueField, this.getValue(), stack);
+ for (var i = 0; i < stack.length; i++ ) {
+ this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
+ }
+
+ }
+
+
+
+
+
+
});/*
* Based on:
* Ext JS Library 1.1.1
black: false,
white: false,
-
+ bodyCls : '',
/**
* Protected method that will not generally be called directly. It
st = '<style type="text/css">' +
'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
'</style>';
- } else {
+ } else {
+ for (var i in this.stylesheets) {
+ st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+ }
}
'IMG { cursor: pointer } ' +
'</style>';
+ var cls = 'roo-htmleditor-body';
+
+ if(this.bodyCls.length){
+ cls += ' ' + this.bodyCls;
+ }
return '<html><head>' + st +
//<style type="text/css">' +
//'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
//'</style>' +
- ' </head><body class="roo-htmleditor-body"></body></html>';
+ ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
},
// private
html = this.cleanHtml(html);
// fix up the special chars.. normaly like back quotes in word...
// however we do not want to do this with chinese..
- html = html.replace(/([\x80-\uffff])/g, function (a, b) {
- var cc = b.charCodeAt();
- if (
+ html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+
+ var cc = match.charCodeAt();
+
+ // Get the character value, handling surrogate pairs
+ if (match.length == 2) {
+ // It's a surrogate pair, calculate the Unicode code point
+ var high = match.charCodeAt(0) - 0xD800;
+ var low = match.charCodeAt(1) - 0xDC00;
+ cc = (high * 0x400) + low + 0x10000;
+ } else if (
(cc >= 0x4E00 && cc < 0xA000 ) ||
(cc >= 0x3400 && cc < 0x4E00 ) ||
(cc >= 0xf900 && cc < 0xfb00 )
) {
- return b;
- }
- return "&#"+cc+";"
+ return match;
+ }
+
+ // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+ return "&#" + cc + ";";
+
+
});
+
+
+
if(this.owner.fireEvent('beforesync', this, html) !== false){
this.el.dom.value = html;
this.owner.fireEvent('sync', this, html);
insertTag : function(tg)
{
// could be a bit smarter... -> wrap the current selected tRoo..
- if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+ if (tg.toLowerCase() == 'span' ||
+ tg.toLowerCase() == 'code' ||
+ tg.toLowerCase() == 'sup' ||
+ tg.toLowerCase() == 'sub'
+ ) {
range = this.createRange(this.getSelection());
var wrappingNode = this.doc.createElement(tg.toLowerCase());
insertAtCursor : function(text)
{
-
-
if(!this.activated){
return;
}
var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
+ // spans with no attributes - just remove them..
+ if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
+ remove_keep_children = true;
+ }
+
// remove <a name=....> as rendering on yahoo mailer is borked with this.
// this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
}
if (!node.attributes || !node.attributes.length) {
+
+
+
+
this.cleanUpChildren(node);
return;
}
if (v.match(/^\./) || v.match(/^\//)) {
return;
}
- if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
+ if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
return;
}
if (v.match(/^#/)) {
return;
}
+ if (v.match(/^\{/)) { // allow template editing.
+ return;
+ }
// Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
node.removeAttribute(n);
if (a.name == 'class') {
if (a.value.match(/^Mso/)) {
- node.className = '';
+ node.removeAttribute('class');
}
- if (a.value.match(/body/)) {
- node.className = '';
+ if (a.value.match(/^body$/)) {
+ node.removeAttribute('class');
}
continue;
}
*/
cleanWord : function(node)
{
-
-
if (!node) {
this.cleanWord(this.doc.body);
return;
}
+
+ if(
+ node.nodeName == 'SPAN' &&
+ !node.hasAttributes() &&
+ node.childNodes.length == 1 &&
+ node.firstChild.nodeName == "#text"
+ ) {
+ var textNode = node.firstChild;
+ node.removeChild(textNode);
+ if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
+ node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+ }
+ node.parentNode.insertBefore(textNode, node);
+ if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
+ node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+ }
+ node.parentNode.removeChild(node);
+ }
+
if (node.nodeName == "#text") {
// clean up silly Windows -- stuff?
return;
node.parentNode.removeChild(node);
return;
}
-
+ //Roo.log(node.tagName);
// remove - but keep children..
- if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+ if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+ //Roo.log('-- removed');
while (node.childNodes.length) {
var cn = node.childNodes[0];
node.removeChild(cn);
node.parentNode.insertBefore(cn, node);
+ // move node to parent - and clean it..
+ this.cleanWord(cn);
}
node.parentNode.removeChild(node);
- this.iterateChildren(node, this.cleanWord);
+ /// no need to iterate chidlren = it's got none..
+ //this.iterateChildren(node, this.cleanWord);
return;
}
// clean styles
Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
s.remove();
});
+ },
+
+ setStyle : function(style)
+ {
+ Roo.get(this.iframe.contentDocument.head).createChild({
+ tag : 'style',
+ type : 'text/css',
+ html : style
+ });
+
+ return;
}
// hide stuff that is not compatible
Roo.HtmlEditorCore.swapCodes =[
- [ 8211, "--" ],
- [ 8212, "--" ],
+ [ 8211, "–" ],
+ [ 8212, "—" ],
[ 8216, "'" ],
[ 8217, "'" ],
[ 8220, '"' ],
["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
["pre"],[ "code"],
["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
- ['div'],['span']
+ ['div'],['span'],
+ ['sup'],['sub']
],
cleanStyles : [
var c = Roo.get(editorcore.doc.body);
c.select('[class]').each(function(s) {
- s.dom.className = '';
+ s.dom.removeAttribute('class');
});
+ editorcore.cleanWord();
editorcore.syncValue();
},
tabIndex:-1
this.initEl(el);
}
Roo.form.BasicForm.superclass.constructor.call(this);
+
+ Roo.form.BasicForm.popover.apply();
};
Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
* @type Mixed
*/
waitMsgTarget : false,
+
+ /**
+ * @type Boolean
+ */
+ disableMask : false,
+
+ /**
+ * @cfg {Boolean} errorMask (true|false) default false
+ */
+ errorMask : false,
+
+ /**
+ * @cfg {Number} maskOffset Default 100
+ */
+ maskOffset : 100,
// private
initEl : function(el){
*/
isValid : function(){
var valid = true;
+ var target = false;
this.items.each(function(f){
- if(!f.validate()){
- valid = false;
- }
+ if(f.validate()){
+ return;
+ }
+
+ valid = false;
+
+ if(!target && f.el.isVisible(true)){
+ target = f;
+ }
});
+
+ if(this.errorMask && !valid){
+ Roo.form.BasicForm.popover.mask(this, target);
+ }
+
return valid;
},
-
+ /**
+ * Returns array of invalid form fields.
+ * @return Array
+ */
+
+ invalidFields : function()
+ {
+ var ret = [];
+ this.items.each(function(f){
+ if(f.validate()){
+ return;
+ }
+ ret.push(f);
+
+ });
+
+ return ret;
+ },
+
+
/**
* DEPRICATED Returns true if any fields in this form have changed since their original load.
* @return Boolean
beforeAction : function(action){
var o = action.options;
-
- if(this.waitMsgTarget === true){
- this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
- }else if(this.waitMsgTarget){
- this.waitMsgTarget = Roo.get(this.waitMsgTarget);
- this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
- }else {
- Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+ if(!this.disableMask) {
+ if(this.waitMsgTarget === true){
+ this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
+ }else if(this.waitMsgTarget){
+ this.waitMsgTarget = Roo.get(this.waitMsgTarget);
+ this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+ }else {
+ Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+ }
}
+
},
this.activeAction = null;
var o = action.options;
- if(this.waitMsgTarget === true){
- this.el.unmask();
- }else if(this.waitMsgTarget){
- this.waitMsgTarget.unmask();
- }else{
- Roo.MessageBox.updateProgress(1);
- Roo.MessageBox.hide();
+ if(!this.disableMask) {
+ if(this.waitMsgTarget === true){
+ this.el.unmask();
+ }else if(this.waitMsgTarget){
+ this.waitMsgTarget.unmask();
+ }else{
+ Roo.MessageBox.updateProgress(1);
+ Roo.MessageBox.hide();
+ }
}
-
+
if(success){
if(o.reset){
this.reset();
return this;
},
-
+
/**
* Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
* they are returned as an array.
}, this);
}
+ // use formdata
+ if (typeof(FormData) != 'undefined' && asString !== true) {
+ // this relies on a 'recent' version of chrome apparently...
+ try {
+ var fd = (new FormData(this.el.dom)).entries();
+ var ret = {};
+ var ent = fd.next();
+ while (!ent.done) {
+ ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+ ent = fd.next();
+ };
+ return ret;
+ } catch(e) {
+
+ }
+
+ }
var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
});
// back compat
-Roo.BasicForm = Roo.form.BasicForm;/*
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+
+ popover : {
+
+ padding : 5,
+
+ isApplied : false,
+
+ isMasked : false,
+
+ form : false,
+
+ target : false,
+
+ intervalID : false,
+
+ maskEl : false,
+
+ apply : function()
+ {
+ if(this.isApplied){
+ return;
+ }
+
+ this.maskEl = {
+ top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+ left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+ bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+ right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+ };
+
+ this.maskEl.top.enableDisplayMode("block");
+ this.maskEl.left.enableDisplayMode("block");
+ this.maskEl.bottom.enableDisplayMode("block");
+ this.maskEl.right.enableDisplayMode("block");
+
+ Roo.get(document.body).on('click', function(){
+ this.unmask();
+ }, this);
+
+ Roo.get(document.body).on('touchstart', function(){
+ this.unmask();
+ }, this);
+
+ this.isApplied = true
+ },
+
+ mask : function(form, target)
+ {
+ this.form = form;
+
+ this.target = target;
+
+ if(!this.form.errorMask || !target.el){
+ return;
+ }
+
+ var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+
+ var ot = this.target.el.calcOffsetsTo(scrollable);
+
+ var scrollTo = ot[1] - this.form.maskOffset;
+
+ scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+
+ scrollable.scrollTo('top', scrollTo);
+
+ var el = this.target.wrap || this.target.el;
+
+ var box = el.getBox();
+
+ this.maskEl.top.setStyle('position', 'absolute');
+ this.maskEl.top.setStyle('z-index', 10000);
+ this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+ this.maskEl.top.setLeft(0);
+ this.maskEl.top.setTop(0);
+ this.maskEl.top.show();
+
+ this.maskEl.left.setStyle('position', 'absolute');
+ this.maskEl.left.setStyle('z-index', 10000);
+ this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+ this.maskEl.left.setLeft(0);
+ this.maskEl.left.setTop(box.y - this.padding);
+ this.maskEl.left.show();
+
+ this.maskEl.bottom.setStyle('position', 'absolute');
+ this.maskEl.bottom.setStyle('z-index', 10000);
+ this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+ this.maskEl.bottom.setLeft(0);
+ this.maskEl.bottom.setTop(box.bottom + this.padding);
+ this.maskEl.bottom.show();
+
+ this.maskEl.right.setStyle('position', 'absolute');
+ this.maskEl.right.setStyle('z-index', 10000);
+ this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+ this.maskEl.right.setLeft(box.right + this.padding);
+ this.maskEl.right.setTop(box.y - this.padding);
+ this.maskEl.right.show();
+
+ this.intervalID = window.setInterval(function() {
+ Roo.form.BasicForm.popover.unmask();
+ }, 10000);
+
+ window.onwheel = function(){ return false;};
+
+ (function(){ this.isMasked = true; }).defer(500, this);
+
+ },
+
+ unmask : function()
+ {
+ if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+ return;
+ }
+
+ this.maskEl.top.setStyle('position', 'absolute');
+ this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.top.hide();
+
+ this.maskEl.left.setStyle('position', 'absolute');
+ this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.left.hide();
+
+ this.maskEl.bottom.setStyle('position', 'absolute');
+ this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.bottom.hide();
+
+ this.maskEl.right.setStyle('position', 'absolute');
+ this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.right.hide();
+
+ window.onwheel = function(){ return true;};
+
+ if(this.intervalID){
+ window.clearInterval(this.intervalID);
+ this.intervalID = false;
+ }
+
+ this.isMasked = false;
+
+ }
+
+ }
+
+});/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
Roo.each(xitems, this.addxtype, this);
-
-
};
Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
*/
progressUrl : false,
-
+ /**
+ * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
+ * sending a formdata with extra parameters - eg uploaded elements.
+ */
+
+ formData : false,
+
/**
* Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
* fields are added and the column is closed. If no fields are passed the column remains open
url:this.getUrl(!isPost),
method: method,
params:isPost ? this.getParams() : null,
- isUpload: this.form.fileUpload
+ isUpload: this.form.fileUpload,
+ formData : this.form.formData
}));
this.uploadProgress();
this.getEl().setStyle("outline", "0px none");
this.getEl().unselectable();
if (this.dragGroup) {
- this.setDraggable(this.dragGroup.split(","));
+ this.setDraggable(this.dragGroup.split(","));
}
if (this.dropGroup) {
- this.setDroppable(this.dropGroup.split(","));
+ this.setDroppable(this.dropGroup.split(","));
}
if (this.deletable) {
this.setDeletable();
* @param {Roo.ContentPanel} panel The panel
*/
"panelremoved" : true,
+ /**
+ * @event beforecollapse
+ * Fires when this region before collapse.
+ * @param {Roo.LayoutRegion} this
+ */
+ "beforecollapse" : true,
/**
* @event collapsed
* Fires when this region is collapsed.
* Collapses this region.
* @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
*/
- collapse : function(skipAnim){
+ collapse : function(skipAnim, skipCheck){
if(this.collapsed) {
return;
}
- this.collapsed = true;
- if(this.split){
- this.split.el.hide();
- }
- if(this.config.animate && skipAnim !== true){
- this.fireEvent("invalidated", this);
- this.animateCollapse();
- }else{
- this.el.setLocation(-20000,-20000);
- this.el.hide();
- this.collapsedEl.show();
- this.fireEvent("collapsed", this);
- this.fireEvent("invalidated", this);
+
+ if(skipCheck || this.fireEvent("beforecollapse", this) != false){
+
+ this.collapsed = true;
+ if(this.split){
+ this.split.el.hide();
+ }
+ if(this.config.animate && skipAnim !== true){
+ this.fireEvent("invalidated", this);
+ this.animateCollapse();
+ }else{
+ this.el.setLocation(-20000,-20000);
+ this.el.hide();
+ this.collapsedEl.show();
+ this.fireEvent("collapsed", this);
+ this.fireEvent("invalidated", this);
+ }
}
+
},
animateCollapse : function(){
* @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
* @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
* @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
+ * @cfg {String} style Extra style to add to the content panel
* @constructor
* Create a new ContentPanel.
{tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
}
}
+
+
this.closable = false;
this.loaded = false;
this.active = false;
* @param {Roo.ContentPanel} this
*/
"render" : true
-
-
+
});
}
if(this.footer){
var te = this.footer.getEl();
- Roo.log("footer:" + te.getHeight());
+ //Roo.log("footer:" + te.getHeight());
height -= te.getHeight();
te.setWidth(width);
/**
* @cfg {String} ddGroup - drag drop group.
*/
+ /**
+ * @cfg {String} dragGroup - drag group (?? not sure if needed.)
+ */
/**
* @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
/**
* @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
+ */
+ /**
+ * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
*/
/**
/**
* @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
*/
+
+
+ /**
+ * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
+ * %0 is replaced with the number of selected rows.
+ */
+ ddText : "{0} selected row{1}",
+
+
/**
* Called once after all setup has been completed and the grid is ready to be rendered.
* @return {Roo.grid.Grid} this
return this;
},
- /**
- * Reconfigures the grid to use a different Store and Column Model.
- * The View will be bound to the new objects and refreshed.
- * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
- * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
- */
+ /**
+ * Reconfigures the grid to use a different Store and Column Model.
+ * The View will be bound to the new objects and refreshed.
+ * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+ * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
+ */
reconfigure : function(dataSource, colModel){
if(this.loadMask){
this.loadMask.destroy();
this.colModel = colModel;
this.view.refresh(true);
},
-
+ /**
+ * addColumns
+ * Add's a column, default at the end..
+
+ * @param {int} position to add (default end)
+ * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
+ */
+ addColumns : function(pos, ar)
+ {
+
+ for (var i =0;i< ar.length;i++) {
+ var cfg = ar[i];
+ cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+ this.cm.lookup[cfg.id] = cfg;
+ }
+
+
+ if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+ pos = this.cm.config.length; //this.cm.config.push(cfg);
+ }
+ pos = Math.max(0,pos);
+ ar.unshift(0);
+ ar.unshift(pos);
+ this.cm.config.splice.apply(this.cm.config, ar);
+
+
+
+ this.view.generateRules(this.cm);
+ this.view.refresh(true);
+
+ },
+
+
+
+
// private
onKeyDown : function(e){
this.fireEvent("keydown", e);
getView : function(){
if(!this.view){
this.view = new Roo.grid.GridView(this.viewConfig);
+ this.relayEvents(this.view, [
+ "beforerowremoved", "beforerowsinserted",
+ "beforerefresh", "rowremoved",
+ "rowsinserted", "rowupdated" ,"refresh"
+ ]);
}
return this.view;
},
/**
* Called to get grid's drag proxy text, by default returns this.ddText.
+ * Override this to put something different in the dragged text.
* @return {String}
*/
getDragDropText : function(){
return String.format(this.ddText, count, count == 1 ? '' : 's');
}
});
-/**
- * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
- * %0 is replaced with the number of selected rows.
- * @type String
- */
-Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
);
*/
if(ctop < stop){
- c.scrollTop = ctop;
+ c.scrollTop = ctop;
//Roo.log("set scrolltop to ctop DISABLE?");
}else if(cbot > sbot){
//Roo.log("set scrolltop to cbot-ch");
}
},
- layout : function(initialRender, is2ndPass){
+ layout : function(initialRender, is2ndPass)
+ {
var g = this.grid;
var auto = g.autoHeight;
var scrollOffset = 16;
}
}
+ if (sm.getSelections && sm.getSelections().length < 1) {
+ return false;
+ }
+
+ // before it used to all dragging of unseleted... - now we dont do that.
if(rowIndex !== false){
// if editorgrid..
grid: this.grid,
ddel: this.ddel,
rowIndex: rowIndex,
- selections:sm.getSelections ? sm.getSelections() : (
- sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
- )
+ selections: sm.getSelections ? sm.getSelections() : (
+ sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
};
}
return false;
},
-
+
+
onInitDrag : function(e){
var data = this.dragData;
this.ddel.innerHTML = this.grid.getDragDropText();
/**
* @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
* given the cell's data value. See {@link #setRenderer}. If not specified, the
- * default renderer uses the raw data value. If an object is returned (bootstrap only)
+ * default renderer returns the escaped data value. If an object is returned (bootstrap only)
* then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
*/
/**
/**
* @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
*/
+ /**
+ * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
+ */
/**
* @cfg {String} cursor (Optional)
*/
}
});
-Roo.grid.ColumnModel.defaultRenderer = function(value){
+Roo.grid.ColumnModel.defaultRenderer = function(value)
+{
+ if(typeof value == "object") {
+ return value;
+ }
if(typeof value == "string" && value.length < 1){
return " ";
}
- return value;
+
+ return String.format("{0}", value);
};
// Alias for backwards compatibility
}
*/
-
-
- this.el.unmask(this.removeMask);
+ (function() { this.el.unmask(this.removeMask); }).defer(50, this);
},
// private
onLoad : function()
{
- this.el.unmask(this.removeMask);
+ (function() { this.el.unmask(this.removeMask); }).defer(50, this);
},
// private
onBeforeLoad : function(){
if(!this.disabled){
- this.el.mask(this.msg, this.msgCls);
+ (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
}
},