debug.js
/*
* These functions are only included in -debug files
*
*/Ext.debug = {
init : function(){
var CP = Ext.ContentPanel;
var bd = Ext.get(document.body);
// create the dialog
var dlg = new Ext.LayoutDialog('x-debug-browser', {
autoCreate:true,
width:800,
height:450,
title: 'Ext Debug Console & Inspector',
proxyDrag:true,
shadow:true,
center:{alwaysShowTabs:true},
constraintoviewport:false
});
// prevent dialog events from bubbling
dlg.el.swallowEvent('click');
// build the layout
var mainLayout = dlg.getLayout();
mainLayout.beginUpdate();
// create the nested layouts
var clayout = mainLayout.add('center',
new Ext.debug.InnerLayout('x-debug-console', 400, {
title: 'Debug Console'
}
));
var ilayout = mainLayout.add('center',
new Ext.debug.InnerLayout('x-debug-inspector', 250, {
title: 'DOM Inspector'
}
));
var scriptPanel = clayout.add('east', new CP({
autoCreate:{
tag: 'div', children: [
{tag: 'div'},
{tag:'textarea'}
]
},
fitContainer:true,
fitToFrame:true,
title:'Script Console',
autoScroll: Ext.isGecko, // hideous block for firefox missing cursor AND bad sizing textareas
setSize : function(w, h){
Ext.ContentPanel.prototype.setSize.call(this, w, h);
if(Ext.isGecko && Ext.isStrict){
var s = this.adjustForComponents(w, h);
this.resizeEl.setSize(s.width-2, s.height-2);
}
}
}));
var sel = scriptPanel.el;
var script = sel.child('textarea');
scriptPanel.resizeEl = script;
var sctb = scriptPanel.toolbar = new Ext.Toolbar(sel.child('div'));
sctb.add({
text: 'Run',
handler: function(){
var s = script.dom.value;
if(trap.checked){
try{
var rt = eval(s);
Ext.debug.dump(rt === undefined? '(no return)' : rt);
}catch(e){
Ext.debug.log(e.message || e.descript);
}
}else{
var rt = eval(s);
Ext.debug.dump(rt === undefined? '(no return)' : rt);
}
}
}, {
text: 'Clear',
handler: function(){
script.dom.value = '';
script.dom.focus();
}
});
var trap = Ext.DomHelper.append(sctb.el, {tag:'input', type:'checkbox', checked: 'checked'});
trap.checked = true;
sctb.add('-', trap, 'Trap Errors');
var stylesGrid = new Ext.grid.PropertyGrid(bd.createChild(), {
nameText: 'Style',
enableCtxMenu: false,
enableColumnResize: false
});
var stylePanel = ilayout.add('east', new Ext.GridPanel(stylesGrid,
{title: '(No element selected)'}));
stylesGrid.render();
// hide the header
stylesGrid.getView().mainHd.setDisplayed(false);
clayout.tbar.add({
text: 'Clear',
handler: function(){
Ext.debug.console.jsonData = [];
Ext.debug.console.refresh();
}
});
var treeEl = ilayout.main.getEl();
// create main inspector toolbar
var tb = ilayout.tbar;
var inspectIgnore, inspecting;
function inspectListener(e, t){
if(!inspectIgnore.contains(e.getPoint())){
findNode(t);
}
}
function stopInspecting(e, t){
if(!inspectIgnore.contains(e.getPoint())){
inspect.toggle(false);
if(findNode(t) !== false){
e.stopEvent();
}
}
}
function stopInspectingEsc(e, t){
if(e.getKey() == e.ESC){
inspect.toggle(false);
}
}
var inspect = tb.addButton({
text: 'Inspect',
enableToggle: true,
pressed:false,
toggleHandler: function(n, pressed){
var d = Ext.get(document);
if(pressed){
d.on('mouseover', inspectListener, window, {buffer:50});
d.on('mousedown', stopInspecting);
d.on('keydown', stopInspectingEsc);
inspectIgnore = dlg.el.getRegion();
inspecting = true;
}else{
d.un('mouseover', inspectListener);
d.un('mousedown', stopInspecting);
d.on('keydown', stopInspectingEsc);
inspecting = false;
var n = tree.getSelectionModel().getSelectedNode();
if(n && n.htmlNode){
onNodeSelect(tree, n, false);
}
}
}
});
tb.addSeparator();
var frameEl = tb.addButton({
text: 'Highlight Selection',
enableToggle: true,
pressed:false,
toggleHandler: function(n, pressed){
var n = tree.getSelectionModel().getSelectedNode();
if(n && n.htmlNode){
n[pressed ? 'frame' : 'unframe']();
}
}
});
tb.addSeparator();
var reload = tb.addButton({
text: 'Refresh Children',
disabled:true,
handler: function(){
var n = tree.getSelectionModel().getSelectedNode();
if(n && n.reload){
n.reload();
}
}
});
tb.add( '-', {
text: 'Collapse All',
handler: function(){
tree.root.collapse(true);
}
});
// perform the main layout
mainLayout.endUpdate();
mainLayout.getRegion('center').showPanel(0);
stylesGrid.on('propertychange', function(s, name, value){
var node = stylesGrid.treeNode;
if(styles){
node.htmlNode.style[name] = value;
}else{
node.htmlNode[name] = value;
}
node.refresh(true);
});
// Create the style toolbar
var stb = new Ext.Toolbar(stylesGrid.view.getHeaderPanel(true));
var swap = stb.addButton({
text: 'DOM Attributes',
menu: {
items: [
new Ext.menu.CheckItem({id:'dom', text:'DOM Attributes', checked: true, group:'xdb-styles'}),
new Ext.menu.CheckItem({id:'styles', text:'CSS Properties', group:'xdb-styles'})
]
}
});
swap.menu.on('click', function(){
styles = swap.menu.items.get('styles').checked;
showAll[styles? 'show' : 'hide']();
swap.setText(styles ? 'CSS Properties' : 'DOM Attributes');
var n = tree.getSelectionModel().getSelectedNode();
if(n){
onNodeSelect(tree, n);
}
});
var addStyle = stb.addButton({
text: 'Add',
disabled: true,
handler: function(){
Ext.MessageBox.prompt('Add Property', 'Property Name:', function(btn, v){
// store.store is disgusting TODO: clean up the API
var store = stylesGrid.store.store;
if(btn == 'ok' && v && !store.getById(v)){
var r = new Ext.grid.PropertyRecord({name:v, value: ''}, v);
store.add(r);
stylesGrid.startEditing(store.getCount()-1, 1);
}
});
}
});
var showAll = stb.addButton({
text: 'Computed Styles',
hidden: true,
pressed: false,
enableToggle: true,
toggleHandler: function(){
var n = tree.getSelectionModel().getSelectedNode();
if(n){
onNodeSelect(tree, n);
}
}
});
// tree related stuff
var styles = false, hnode;
var nonSpace = /^\s*$/;
var html = Ext.util.Format.htmlEncode;
var ellipsis = Ext.util.Format.ellipsis;
var styleRe = /\s?([a-z\-]*)\:([^;]*)(?:[;\s\n\r]*)/gi;
function findNode(n){
if(!n || n.nodeType != 1 || n == document.body || n == document){
return false;
}
var pn = [n], p = n;
while((p = p.parentNode) && p.nodeType == 1 && p.tagName.toUpperCase() != 'HTML'){
pn.unshift(p);
}
var cn = hnode;
for(var i = 0, len = pn.length; i < len; i++){
cn.expand();
cn = cn.findChild('htmlNode', pn[i]);
if(!cn){ // in this dialog?
return false;
}
}
cn.select();
var a = cn.ui.anchor;
treeEl.dom.scrollTop = Math.max(0 ,a.offsetTop-10);
//treeEl.dom.scrollLeft = Math.max(0 ,a.offsetLeft-10); no likey
cn.highlight();
return true;
}
function nodeTitle(n){
var s = n.tagName;
if(n.id){
s += '#'+n.id;
}else if(n.className){
s += '.'+n.className;
}
return s;
}
function onNodeSelect(t, n, last){
if(last && last.unframe){
last.unframe();
}
var props = {};
if(n && n.htmlNode){
if(frameEl.pressed){
n.frame();
}
if(inspecting){
return;
}
addStyle.enable();
reload.setDisabled(n.leaf);
var dom = n.htmlNode;
stylePanel.setTitle(nodeTitle(dom));
if(styles && !showAll.pressed){
var s = dom.style ? dom.style.cssText : '';
if(s){
var m;
while ((m = styleRe.exec(s)) != null){
props[m[1].toLowerCase()] = m[2];
}
}
}else if(styles){
var cl = Ext.debug.cssList;
var s = dom.style, fly = Ext.fly(dom);
if(s){
for(var i = 0, len = cl.length; i<len; i++){
var st = cl[i];
var v = s[st] || fly.getStyle(st);
if(v != undefined && v !== null && v !== ''){
props[st] = v;
}
}
}
}else{
for(var a in dom){
var v = dom[a];
if((isNaN(a+10)) && v != undefined && v !== null && v !== '' && !(Ext.isGecko && a[0] == a[0].toUpperCase())){
props[a] = v;
}
}
}
}else{
if(inspecting){
return;
}
addStyle.disable();
reload.disabled();
}
stylesGrid.setSource(props);
stylesGrid.treeNode = n;
stylesGrid.view.fitColumns();
}
// lets build a list of nodes to filter from the tree
// this is gonna be nasty
var filterIds = '^(?:';
var eds = stylesGrid.colModel.editors;
for(var edType in eds){
filterIds += eds[edType].id +'|';
}
Ext.each([dlg.shim? dlg.shim.id : 'noshim', dlg.proxyDrag.id], function(id){
filterIds += id +'|';
});
filterIds += dlg.el.id;
filterIds += ')$';
var filterRe = new RegExp(filterIds);
var loader = new Ext.tree.TreeLoader();
loader.load = function(n, cb){
var isBody = n.htmlNode == bd.dom;
var cn = n.htmlNode.childNodes;
for(var i = 0, c; c = cn[i]; i++){
if(isBody && filterRe.test(c.id)){
continue;
}
if(c.nodeType == 1){
n.appendChild(new Ext.debug.HtmlNode(c));
}else if(c.nodeType == 3 && !nonSpace.test(c.nodeValue)){
n.appendChild(new Ext.tree.TreeNode({
text:'<em>' + ellipsis(html(String(c.nodeValue)), 35) + '</em>',
cls: 'x-tree-noicon'
}));
}
}
cb();
};
var tree = new Ext.tree.TreePanel(treeEl, {
enableDD:false ,
loader: loader,
lines:false,
rootVisible:false,
animate:false,
hlColor:'ffff9c'
});
tree.getSelectionModel().on('selectionchange', onNodeSelect, null, {buffer:250});
var root = tree.setRootNode(new Ext.tree.TreeNode('Ext'));
hnode = root.appendChild(new Ext.debug.HtmlNode(
document.getElementsByTagName('html')[0]
));
tree.render();
Ext.debug.console = new Ext.JsonView(clayout.main.getEl(),
'<pre><xmp>> {msg}</xmp></pre>');
Ext.debug.console.jsonData = [];
Ext.debug.dialog = dlg;
},
show : function(){
var d = Ext.debug;
if(!d.dialog){
d.init();
}
if(!d.dialog.isVisible()){
d.dialog.show();
}
},
hide : function(){
if(Ext.debug.dialog){
Ext.debug.dialog.hide();
}
},
/**
* Debugging function. Prints all arguments to a resizable, movable, scrolling region without
* the need to include separate js or css. Double click it to hide it.
* @param {Mixed} arg1
* @param {Mixed} arg2
* @param {Mixed} etc
* @method print
*/
log : function(arg1, arg2, etc){
Ext.debug.show();
var m = "";
for(var i = 0, len = arguments.length; i < len; i++){
m += (i == 0 ? "" : ", ") + arguments[i];
}
var cn = Ext.debug.console;
cn.jsonData.unshift({msg: m});
cn.refresh();
},
/**
* Applies the passed C#/DomHelper style format (e.g. "The variable {0} is equal to {1}") before calling Ext.debug.log
* @param {String} format
* @param {Mixed} arg1
* @param {Mixed} arg2
* @param {Mixed} etc
* @method printf
*/
logf : function(format, arg1, arg2, etc){
Ext.debug.log(String.format.apply(String, arguments));
},
/**
* Dumps an object to Ext.debug.log
* @param {Object} o
* @method dump
*/
dump : function(o){
if(typeof o == 'string' || typeof o == 'number' || typeof o == 'undefined' || o instanceof Date){
Ext.debug.log(o);
}else if(!o){
Ext.debug.log("null");
}else if(typeof o != "object"){
Ext.debug.log('Unknown return type');
}else if(o instanceof Array){
Ext.debug.log('['+o.join(',')+']');
}else{
var b = ["{\n"];
for(var key in o){
var to = typeof o[key];
if(to != "function" && to != "object"){
b.push(String.format(" {0}: {1},\n", key, o[key]));
}
}
var s = b.join("");
if(s.length > 3){
s = s.substr(0, s.length-2);
}
Ext.debug.log(s + "\n}");
}
},
_timers : {},
/**
* Starts a timer.
* @param {String} name (optional)
* @method timer
*/
time : function(name){
name = name || "def";
Ext._timers[name] = new Date().getTime();
},
/**
* Ends a timer, returns the results (formatted "{1} ms") and optionally prints them to Ext.print()
* @param {String} name (optional)
* @param {Boolean} printResults (optional) false to stop printing the results to Ext.print
* @method timerEnd
*/
timeEnd : function(name, printResults){
var t = new Date().getTime();
name = name || "def";
var v = String.format("{0} ms", t-Ext._timers[name]);
Ext._timers[name] = new Date().getTime();
if(printResults !== false){
Ext.debug.log('Timer ' + (name == "def" ? v : name + ": " + v));
}
return v;
}
};
// highly unusual class declaration
Ext.debug.HtmlNode = function(){
var html = Ext.util.Format.htmlEncode;
var ellipsis = Ext.util.Format.ellipsis;
var nonSpace = /^\s*$/;
var attrs = [
{n: 'id', v: 'id'},
{n: 'className', v: 'class'},
{n: 'name', v: 'name'},
{n: 'type', v: 'type'},
{n: 'src', v: 'src'},
{n: 'href', v: 'href'}
];
function hasChild(n){
for(var i = 0, c; c = n.childNodes[i]; i++){
if(c.nodeType == 1){
return true;
}
}
return false;
}
function renderNode(n, leaf){
var tag = n.tagName.toLowerCase();
var s = '<' + tag;
for(var i = 0, len = attrs.length; i < len; i++){
var a = attrs[i];
var v = n[a.n];
if(v && !nonSpace.test(v)){
s += ' ' + a.v + '="<i>' + html(v) +'</i>"';
}
}
var style = n.style ? n.style.cssText : '';
if(style){
s += ' style="<i>' + html(style.toLowerCase()) +'</i>"';
}
if(leaf && n.childNodes.length > 0){
s+='><em>' + ellipsis(html(String(n.innerHTML)), 35) + '</em></'+tag+'>';
}else if(leaf){
s += ' />';
}else{
s += '>';
}
return s;
}
var HtmlNode = function(n){
var leaf = !hasChild(n);
this.htmlNode = n;
this.tagName = n.tagName.toLowerCase();
var attr = {
text : renderNode(n, leaf),
leaf : leaf,
cls: 'x-tree-noicon'
};
HtmlNode.superclass.constructor.call(this, attr);
this.attributes.htmlNode = n; // for searching
if(!leaf){
this.on('expand', this.onExpand, this);
this.on('collapse', this.onCollapse, this);
}
};
Ext.extend(HtmlNode, Ext.tree.AsyncTreeNode, {
cls: 'x-tree-noicon',
preventHScroll: true,
refresh : function(highlight){
var leaf = !hasChild(this.htmlNode);
this.setText(renderNode(this.htmlNode, leaf));
if(highlight){
Ext.fly(this.ui.textNode).highlight();
}
},
onExpand : function(){
if(!this.closeNode && this.parentNode){
this.closeNode = this.parentNode.insertBefore(new Ext.tree.TreeNode({
text:'</' + this.tagName + '>',
cls: 'x-tree-noicon'
}), this.nextSibling);
}else if(this.closeNode){
this.closeNode.ui.show();
}
},
onCollapse : function(){
if(this.closeNode){
this.closeNode.ui.hide();
}
},
render : function(bulkRender){
HtmlNode.superclass.render.call(this, bulkRender);
},
highlightNode : function(){
//Ext.fly(this.htmlNode).highlight();
},
highlight : function(){
//Ext.fly(this.ui.textNode).highlight();
},
frame : function(){
this.htmlNode.style.border = '1px solid #0000ff';
//this.highlightNode();
},
unframe : function(){
//Ext.fly(this.htmlNode).removeClass('x-debug-frame');
this.htmlNode.style.border = '';
}
});
return HtmlNode;
}();
// subclass for the standard layout panels
Ext.debug.InnerLayout = function(id, w, cfg){
// console layout
var el = Ext.DomHelper.append(document.body, {id:id});
var layout = new Ext.BorderLayout(el, {
north: {
initialSize:28
},
center: {
titlebar: false
},
east: {
split:true,
initialSize:w,
titlebar:true
}
});
Ext.debug.InnerLayout.superclass.constructor.call(this, layout, cfg);
layout.beginUpdate();
var tbPanel = layout.add('north', new Ext.ContentPanel({
autoCreate:true, fitToFrame:true}));
this.main = layout.add('center', new Ext.ContentPanel({
autoCreate:true, fitToFrame:true, autoScroll:true}));
this.tbar = new Ext.Toolbar(tbPanel.el);
var mtbEl = tbPanel.resizeEl = tbPanel.el.child('div.x-toolbar');
mtbEl.setStyle('border-bottom', '0 none');
layout.endUpdate(true);
};
Ext.extend(Ext.debug.InnerLayout, Ext.NestedLayoutPanel, {
add : function(){
return this.layout.add.apply(this.layout, arguments);
}
});
Ext.debug.cssList = ['background-color','border','border-color','border-spacing',
'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
'top','width','word-spacing','z-index','opacity','outline-offset'];
if(typeof console == 'undefined'){
console = Ext.debug;
}
/*
if(Ext.isSafari || Ext.isIE || Ext.isOpera){
window.onerror = function(msg, url, line){
Ext.log.apply(Ext, arguments);
};
}*/
// attach shortcut key
Ext.EventManager.on(window, 'load', function(){
Ext.get(document).on('keydown', function(e){
if(e.ctrlKey && e.shiftKey && e.getKey() == e.HOME){
Ext.debug.show();
}
});
});
// backwards compat
Ext.print = Ext.log = Ext.debug.log;
Ext.printf = Ext.logf = Ext.debug.logf;
Ext.dump = Ext.debug.dump;
Ext.timer = Ext.debug.time;
Ext.timerEnd = Ext.debug.timeEnd;
Ext - Copyright © 2006-2007 Ext JS, LLC
All rights reserved.