})();
Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
- "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
+ "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
+ "Roo.app", "Roo.ux",
+ "Roo.bootstrap",
+ "Roo.bootstrap.dash");
/*
* Based on:
* Ext JS Library 1.1.1
var E = Roo.lib.Event;
var D = Roo.lib.Dom;
+
+
var fireDocReady = function(){
if(!docReadyState){
}, o.delay || 10);
};
};
+ var transitionEndVal = false;
+
+ var transitionEnd = function()
+ {
+ if (transitionEndVal) {
+ return transitionEndVal;
+ }
+ var el = document.createElement('div');
+
+ var transEndEventNames = {
+ WebkitTransition : 'webkitTransitionEnd',
+ MozTransition : 'transitionend',
+ OTransition : 'oTransitionEnd otransitionend',
+ transition : 'transitionend'
+ };
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ transitionEndVal = transEndEventNames[name];
+ return transitionEndVal ;
+ }
+ }
+ }
+
var listen = function(element, ename, opt, fn, scope){
var o = (!opt || typeof opt == "boolean") ? {} : opt;
fn = fn || o.fn; scope = scope || o.scope;
var el = Roo.getDom(element);
+
+
if(!el){
throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
}
+
+ if (ename == 'transitionend') {
+ ename = transitionEnd();
+ }
var h = function(e){
e = Roo.EventObject.setEvent(e);
var t;
h = createBuffered(h, o);
}
fn._handlers = fn._handlers || [];
+
+
fn._handlers.push([Roo.id(el), ename, h]);
-
+
+
+
E.on(el, ename, h);
if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
el.addEventListener("DOMMouseScroll", h, false);
*/
mask : function(msg, msgCls)
{
- if(this.getStyle("position") == "static"){
+ if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
this.setStyle("position", "relative");
}
if(!this._mask){
/**
* Sets or Returns the value the dom attribute value
- * @param {String} name The attribute name
+ * @param {String|Object} name The attribute name (or object to set multiple attributes)
* @param {String} value (optional) The value to set the attribute to
* @return {String} The attribute value
*/
this.dom.setAttribute(name, arguments[1]);
return arguments[1];
}
+ if (typeof(name) == 'object') {
+ for(var i in name) {
+ this.attr(i, name[i]);
+ }
+ return name;
+ }
+
+
if (!this.dom.hasAttribute(name)) {
return undefined;
}
* @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({
* 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
* @constructor
el = el || false;
var hp = this.parent ? 1 : 0;
+ 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 = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
- el = Roo.get(ename);
+ var ename = this.parent.substr(1);
+ this.parent = false;
+ Roo.log(ename);
+ switch (ename) {
+ case 'bootstrap-body' :
+ if (typeof(Roo.bootstrap.Body) != 'undefined') {
+ this.parent = { el : new Roo.bootstrap.Body() };
+ 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.log("Warning - element can not be found :#" + ename );
return;
}
}
+ Roo.log("EL:");Roo.log(el);
+ Roo.log("this.parent.el:");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 = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+ (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
- if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
+ if (!this.parent && is_alt) {
//el = Roo.get(document.body);
this.parent = { el : true };
}
}
}
- if (!this.parent.el) {
- // probably an old style ctor, which has been disabled.
- return;
-
- }
+ 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;
this.panel = this.el;
this.layout = this.panel.layout;
- this.parentLayout = this.parent.layout || false;
+ this.parentLayout = this.parent.layout || false;
}
*/
Roo.View = function(config, depreciated_tpl, depreciated_config){
+ this.parent = false;
+
if (typeof(depreciated_tpl) == 'undefined') {
// new way.. - universal constructor.
Roo.apply(this, config);
this.tpl.compile();
-
-
-
/** @private */
this.addEvents({
/**
*/
toggleSelect : false,
+ /**
+ * @cfg {Boolean} tickable - selecting
+ */
+ tickable : false,
+
/**
* Returns the element this view is bound to.
* @return {Roo.Element}
for(var i = 0, len = records.length; i < len; i++){
var data = this.prepareData(records[i].data, i, records[i]);
this.fireEvent("preparedata", this, data, i, records[i]);
+
+ var d = Roo.apply({}, data);
+
+ if(this.tickable){
+ Roo.apply(d, {'roo-id' : Roo.id()});
+
+ var _this = this;
+
+ Roo.each(this.parent.item, function(item){
+ if(item[_this.parent.valueField] != data[_this.parent.valueField]){
+ return;
+ }
+ Roo.apply(d, {'roo-data-checked' : 'checked'});
+ });
+ }
+
html[html.length] = Roo.util.Format.trim(
this.dataName ?
- t.applySubtemplate(this.dataName, data, this.store.meta) :
- t.apply(data)
+ t.applySubtemplate(this.dataName, d, this.store.meta) :
+ t.apply(d)
);
}
this.select(item, this.multiSelect && e.ctrlKey);
this.lastSelection = item;
}
- e.preventDefault();
+
+ if(!this.tickable){
+ e.preventDefault();
+ }
+
}
return true;
},
autoSize : function(){
//this.el.beginMeasure();
this.textEl.setWidth(1);
- this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
+ /*
+ * #2804 [new] Tabs in Roojs
+ * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
+ */
+ this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
//this.el.endMeasure();
},
getValue : function(){
if(this.valueField){
return typeof this.value != 'undefined' ? this.value : '';
- }else{
- return Roo.form.ComboBox.superclass.getValue.call(this);
}
+ return Roo.form.ComboBox.superclass.getValue.call(this);
},
/**
/**
* @event remove
* Fires when remove the value from the list
- * @param {Roo.form.ComboBox} combo This combo box
+ * @param {Roo.form.ComboBoxArray} _self This combo box array
+ * @param {Roo.form.ComboBoxArray.Item} item removed item
*/
'remove' : true
}, this)
}
- if (typeof(v) == 'object') {
+ if (typeof(v) == 'object' ) {
// then let's assume it's an array of objects..
Roo.each(v, function(l) {
this.addItem(l);
remove : function()
{
- Roo.log(this);
this.cb.items.remove(this);
this.el.child('img').un('click', this.remove, this);
this.el.remove();
this.cb.updateHiddenEl();
- Roo.log('remove?????');
this.cb.fireEvent('remove', this.cb, this);
}
});/*
// private
onClick : function(){
+ if (this.disabled) {
+ return;
+ }
this.setChecked(!this.checked);
//if(this.el.dom.checked != this.checked){
Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+
+
this.addEvents({
/**
* @event initialize
*/
editorevent: true
});
-
+
+ // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+
+ // defaults : white / black...
+ this.applyBlacklists();
+
+
+
};
clearUp: true,
+ // blacklist + whitelisted elements..
+ black: false,
+ white: false,
this.doc = iframe.contentWindow.document;
this.win = iframe.contentWindow;
} else {
- if (!Roo.get(this.frameId)) {
+// if (!Roo.get(this.frameId)) {
+// return;
+// }
+// this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+// this.win = Roo.get(this.frameId).dom.contentWindow;
+
+ if (!Roo.get(this.frameId) && !iframe.contentDocument) {
return;
}
+
this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
- this.win = Roo.get(this.frameId).dom.contentWindow;
+ this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
}
},
//var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
// this copies styles from the containing element into thsi one..
// not sure why we need all of this..
- var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
- ss['background-attachment'] = 'fixed'; // w3c
+ //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
+
+ //var ss = this.el.getStyles( 'background-image', 'background-repeat');
+ //ss['background-attachment'] = 'fixed'; // w3c
dbody.bgProperties = 'fixed'; // ie
- Roo.DomHelper.applyStyles(dbody, ss);
+ //Roo.DomHelper.applyStyles(dbody, ss);
Roo.EventManager.on(this.doc, {
//'mousedown': this.onEditorEvent,
'mouseup': this.onEditorEvent,
// clean up silly Windows -- stuff?
return;
}
+ var lcname = node.tagName.toLowerCase();
+ // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
+ // whitelist of tags..
- if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
+ if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
// remove node.
node.parentNode.removeChild(node);
return;
}
+ var cwhite = this.cwhite;
+ var cblack = this.cblack;
+
function cleanStyle(n,v)
{
if (v.match(/expression/)) { //XSS?? should we even bother..
node.removeAttribute(n);
return;
}
- var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
- var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
-
var parts = v.split(/;/);
var clean = [];
var l = p.split(':').shift().replace(/\s+/g,'');
l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
- if ( cblack.indexOf(l) > -1) {
+ if ( cwhite.length && cblack.indexOf(l) > -1) {
// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
//node.removeAttribute(n);
return true;
this.cleanUpChildren(node);
- }
+ },
+ /**
+ * Clean up MS wordisms...
+ */
+ cleanWord : function(node)
+ {
+ var _t = this;
+ var cleanWordChildren = function()
+ {
+ if (!node.childNodes.length) {
+ return;
+ }
+ for (var i = node.childNodes.length-1; i > -1 ; i--) {
+ _t.cleanWord(node.childNodes[i]);
+ }
+ }
+
+
+ if (!node) {
+ this.cleanWord(this.doc.body);
+ return;
+ }
+ if (node.nodeName == "#text") {
+ // clean up silly Windows -- stuff?
+ return;
+ }
+ if (node.nodeName == "#comment") {
+ node.parentNode.removeChild(node);
+ // clean up silly Windows -- stuff?
+ return;
+ }
+
+ if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
+ node.parentNode.removeChild(node);
+ return;
+ }
+
+ // remove - but keep children..
+ if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+ while (node.childNodes.length) {
+ var cn = node.childNodes[0];
+ node.removeChild(cn);
+ node.parentNode.insertBefore(cn, node);
+ }
+ node.parentNode.removeChild(node);
+ cleanWordChildren();
+ return;
+ }
+ // clean styles
+ if (node.className.length) {
+
+ var cn = node.className.split(/\W+/);
+ var cna = [];
+ Roo.each(cn, function(cls) {
+ if (cls.match(/Mso[a-zA-Z]+/)) {
+ return;
+ }
+ cna.push(cls);
+ });
+ node.className = cna.length ? cna.join(' ') : '';
+ if (!cna.length) {
+ node.removeAttribute("class");
+ }
+ }
+
+ if (node.hasAttribute("lang")) {
+ node.removeAttribute("lang");
+ }
+
+ if (node.hasAttribute("style")) {
+
+ var styles = node.getAttribute("style").split(";");
+ var nstyle = [];
+ Roo.each(styles, function(s) {
+ if (!s.match(/:/)) {
+ return;
+ }
+ var kv = s.split(":");
+ if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
+ return;
+ }
+ // what ever is left... we allow.
+ nstyle.push(s);
+ });
+ node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+ if (!nstyle.length) {
+ node.removeAttribute('style');
+ }
+ }
+
+ cleanWordChildren();
+
+
+ },
+ domToHTML : function(currentElement, depth, nopadtext) {
+
+ depth = depth || 0;
+ nopadtext = nopadtext || false;
+ if (!currentElement) {
+ return this.domToHTML(this.doc.body);
+ }
+
+ //Roo.log(currentElement);
+ var j;
+ var allText = false;
+ var nodeName = currentElement.nodeName;
+ var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+
+ if (nodeName == '#text') {
+ return currentElement.nodeValue;
+ }
+
+
+ var ret = '';
+ if (nodeName != 'BODY') {
+
+ var i = 0;
+ // Prints the node tagName, such as <A>, <IMG>, etc
+ if (tagName) {
+ var attr = [];
+ for(i = 0; i < currentElement.attributes.length;i++) {
+ // quoting?
+ var aname = currentElement.attributes.item(i).name;
+ if (!currentElement.attributes.item(i).value.length) {
+ continue;
+ }
+ attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
+ }
+
+ ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
+ }
+ else {
+
+ // eack
+ }
+ } else {
+ tagName = false;
+ }
+ if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
+ return ret;
+ }
+ if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
+ nopadtext = true;
+ }
+
+
+ // Traverse the tree
+ i = 0;
+ var currentElementChild = currentElement.childNodes.item(i);
+ var allText = true;
+ var innerHTML = '';
+ lastnode = '';
+ while (currentElementChild) {
+ // Formatting code (indent the tree so it looks nice on the screen)
+ var nopad = nopadtext;
+ if (lastnode == 'SPAN') {
+ nopad = true;
+ }
+ // text
+ if (currentElementChild.nodeName == '#text') {
+ var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
+ if (!nopad && toadd.length > 80) {
+ innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
+ }
+ innerHTML += toadd;
+
+ i++;
+ currentElementChild = currentElement.childNodes.item(i);
+ lastNode = '';
+ continue;
+ }
+ allText = false;
+
+ innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
+
+ // Recursively traverse the tree structure of the child node
+ innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
+ lastnode = currentElementChild.nodeName;
+ i++;
+ currentElementChild=currentElement.childNodes.item(i);
+ }
+
+ ret += innerHTML;
+
+ if (!allText) {
+ // The remaining code is mostly for formatting the tree
+ ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
+ }
+
+
+ if (tagName) {
+ ret+= "</"+tagName+">";
+ }
+ return ret;
+
+ },
+
+ applyBlacklists : function()
+ {
+ var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
+ var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
+
+ this.white = [];
+ this.black = [];
+ Roo.each(Roo.HtmlEditorCore.white, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ this.white.push(tag);
+
+ }, this);
+
+ Roo.each(w, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.white.indexOf(tag) > -1) {
+ return;
+ }
+ this.white.push(tag);
+
+ }, this);
+
+
+ Roo.each(Roo.HtmlEditorCore.black, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ this.black.push(tag);
+
+ }, this);
+
+ Roo.each(b, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.black.indexOf(tag) > -1) {
+ return;
+ }
+ this.black.push(tag);
+
+ }, this);
+
+
+ w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
+ b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
+
+ this.cwhite = [];
+ this.cblack = [];
+ Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ this.cwhite.push(tag);
+
+ }, this);
+
+ Roo.each(w, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.cwhite.indexOf(tag) > -1) {
+ return;
+ }
+ this.cwhite.push(tag);
+
+ }, this);
+
+
+ Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ this.cblack.push(tag);
+
+ }, this);
+
+ Roo.each(b, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.cblack.indexOf(tag) > -1) {
+ return;
+ }
+ this.cblack.push(tag);
+
+ }, this);
+ }
// hide stuff that is not compatible
/**
*/
stylesheets: false,
+
+ /**
+ * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
+ *
+ */
+ cblack: false,
+ /**
+ * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
+ *
+ */
+ cwhite: false,
+
+ /**
+ * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
+ *
+ */
+ black: false,
+ /**
+ * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
+ *
+ */
+ white: false,
+
// id of frame..
frameId: false,
c.select('[style]').each(function(s) {
s.dom.style.removeProperty(a.actiontype);
});
-
+ editorcore.syncValue();
},
tabIndex:-1
});
}
+ cmenu.menu.items.push({
+ actiontype : 'word',
+ html: 'Remove MS Word Formating',
+ handler: function(a,b) {
+ editorcore.cleanWord();
+ editorcore.syncValue();
+ },
+ tabIndex:-1
+ });
+
+ cmenu.menu.items.push({
+ actiontype : 'all',
+ html: 'Remove All Styles',
+ handler: function(a,b) {
+
+ var c = Roo.get(editorcore.doc.body);
+ c.select('[style]').each(function(s) {
+ s.dom.removeAttribute('style');
+ });
+ editorcore.syncValue();
+ },
+ tabIndex:-1
+ });
+ cmenu.menu.items.push({
+ actiontype : 'word',
+ html: 'Tidy HTML Source',
+ handler: function(a,b) {
+ editorcore.doc.body.innerHTML = editorcore.domToHTML();
+ editorcore.syncValue();
+ },
+ tabIndex:-1
+ });
+
tb.add(cmenu);
}
/**
* @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.
+ * default renderer uses the raw 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 {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor