if (typeof(PhpDebugBar) == 'undefined') {
// namespace
var PhpDebugBar = {};
PhpDebugBar.$ = jQuery;
}
(function($) {
/**
* @namespace
*/
PhpDebugBar.Widgets = {};
var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-');
/**
* Replaces spaces with and line breaks with
*
* @param {String} text
* @return {String}
*/
var htmlize = PhpDebugBar.Widgets.htmlize = function(text) {
return text.replace(/\n/g, ' ').replace(/\s/g, " ")
};
/**
* Returns a string representation of value, using JSON.stringify
* if it's an object.
*
* @param {Object} value
* @param {Boolean} prettify Uses htmlize() if true
* @return {String}
*/
var renderValue = PhpDebugBar.Widgets.renderValue = function(value, prettify) {
if (typeof(value) !== 'string') {
if (prettify) {
return htmlize(JSON.stringify(value, undefined, 2));
}
return JSON.stringify(value);
}
return value;
};
/**
* Highlights a block of code
*
* @param {String} code
* @param {String} lang
* @return {String}
*/
var highlight = PhpDebugBar.Widgets.highlight = function(code, lang) {
if (typeof(code) === 'string') {
if (typeof(hljs) === 'undefined') {
return htmlize(code);
}
if (lang) {
return hljs.highlight(code, {language: lang}).value;
}
return hljs.highlightAuto(code).value;
}
if (typeof(hljs) === 'object') {
code.each(function(i, e) { hljs.highlightElement(e); });
}
return code;
};
/**
* Creates a
element with a block of code
*
* @param {String} code
* @param {String} lang
* @param {Number} [firstLineNumber] If provided, shows line numbers beginning with the given value.
* @param {Number} [highlightedLine] If provided, the given line number will be highlighted.
* @return {String}
*/
var createCodeBlock = PhpDebugBar.Widgets.createCodeBlock = function(code, lang, firstLineNumber, highlightedLine) {
var pre = $('').addClass(csscls('code-block'));
// Add a newline to prevent element from vertically collapsing too far if the last
// code line was empty: that creates problems with the horizontal scrollbar being
// incorrectly positioned - most noticeable when line numbers are shown.
var codeElement = $('').text(code + '\n').appendTo(pre);
// Format the code
if (lang) {
codeElement.addClass("language-" + lang);
}
highlight(codeElement).removeClass('hljs');
// Show line numbers in a list
if (!isNaN(parseFloat(firstLineNumber))) {
var lineCount = code.split('\n').length;
var $lineNumbers = $('
').prependTo(pre);
pre.children().addClass(csscls('numbered-code'));
for (var i = firstLineNumber; i < firstLineNumber + lineCount; i++) {
var li = $('').text(i).appendTo($lineNumbers);
// Add a span with a special class if we are supposed to highlight a line.
if (highlightedLine === i) {
li.addClass(csscls('highlighted-line')).append('');
}
}
}
return pre;
};
var getDictValue = PhpDebugBar.utils.getDictValue = function(dict, key, default_value) {
var d = dict, parts = key.split('.');
for (var i = 0; i < parts.length; i++) {
if (!d[parts[i]]) {
return default_value;
}
d = d[parts[i]];
}
return d;
}
// ------------------------------------------------------------------
// Generic widgets
// ------------------------------------------------------------------
/**
* Displays array element in a
list
*
* Options:
* - data
* - itemRenderer: a function used to render list items (optional)
*/
var ListWidget = PhpDebugBar.Widgets.ListWidget = PhpDebugBar.Widget.extend({
tagName: 'ul',
className: csscls('list'),
initialize: function(options) {
if (!options['itemRenderer']) {
options['itemRenderer'] = this.itemRenderer;
}
this.set(options);
},
render: function() {
this.bindAttr(['itemRenderer', 'data'], function() {
this.$el.empty();
if (!this.has('data')) {
return;
}
var data = this.get('data');
for (var i = 0; i < data.length; i++) {
var li = $('').addClass(csscls('list-item')).appendTo(this.$el);
this.get('itemRenderer')(li, data[i]);
}
});
},
/**
* Renders the content of a
element
*
* @param {jQuery} li The
element as a jQuery Object
* @param {Object} value An item from the data array
*/
itemRenderer: function(li, value) {
li.html(renderValue(value));
}
});
// ------------------------------------------------------------------
/**
* Displays object property/value paris in a
list
*
* Options:
* - data
* - itemRenderer: a function used to render list items (optional)
*/
var KVListWidget = PhpDebugBar.Widgets.KVListWidget = ListWidget.extend({
tagName: 'dl',
className: csscls('kvlist'),
render: function() {
this.bindAttr(['itemRenderer', 'data'], function() {
this.$el.empty();
if (!this.has('data')) {
return;
}
var self = this;
$.each(this.get('data'), function(key, value) {
var dt = $('').addClass(csscls('key')).appendTo(self.$el);
var dd = $('').addClass(csscls('value')).appendTo(self.$el);
self.get('itemRenderer')(dt, dd, key, value);
});
});
},
/**
* Renders the content of the
and
elements
*
* @param {jQuery} dt The
element as a jQuery Object
* @param {jQuery} dd The
element as a jQuery Object
* @param {String} key Property name
* @param {Object} value Property value
*/
itemRenderer: function(dt, dd, key, value) {
dt.text(key);
dd.html(htmlize(value));
}
});
// ------------------------------------------------------------------
/**
* An extension of KVListWidget where the data represents a list
* of variables
*
* Options:
* - data
*/
var VariableListWidget = PhpDebugBar.Widgets.VariableListWidget = KVListWidget.extend({
className: csscls('kvlist varlist'),
itemRenderer: function(dt, dd, key, value) {
$('').attr('title', key).text(key).appendTo(dt);
var v = value && value.value || value;
if (v && v.length > 100) {
v = v.substr(0, 100) + "...";
}
var prettyVal = null;
dd.text(v).click(function() {
if (dd.hasClass(csscls('pretty'))) {
dd.text(v).removeClass(csscls('pretty'));
} else {
prettyVal = prettyVal || createCodeBlock(value);
dd.addClass(csscls('pretty')).empty().append(prettyVal);
}
});
}
});
// ------------------------------------------------------------------
/**
* An extension of KVListWidget where the data represents a list
* of variables whose contents are HTML; this is useful for showing
* variable output from VarDumper's HtmlDumper.
*
* Options:
* - data
*/
var HtmlVariableListWidget = PhpDebugBar.Widgets.HtmlVariableListWidget = KVListWidget.extend({
className: csscls('kvlist htmlvarlist'),
itemRenderer: function(dt, dd, key, value) {
$('').attr('title', $('').html(key || '').text()).html(key || '').appendTo(dt);
dd.html(value && value.value || value);
if (value && value.xdebug_link) {
var header = $('').addClass(csscls('filename')).text(value.xdebug_link.filename + ( value.xdebug_link.line ? "#" + value.xdebug_link.line : ''));
if (value.xdebug_link) {
if (value.xdebug_link.ajax) {
$('').on('click', function () {
$.ajax(value.xdebug_link.url);
}).addClass(csscls('editor-link')).appendTo(header);
} else {
$('').addClass(csscls('editor-link')).appendTo(header);
}
}
header.appendTo(dd);
}
}
});
// ------------------------------------------------------------------
/**
* Iframe widget
*
* Options:
* - data
*/
var IFrameWidget = PhpDebugBar.Widgets.IFrameWidget = PhpDebugBar.Widget.extend({
tagName: 'iframe',
className: csscls('iframe'),
render: function() {
this.$el.attr({
seamless: "seamless",
border: "0",
width: "100%",
height: "100%"
});
this.bindAttr('data', function(url) { this.$el.attr('src', url); });
}
});
// ------------------------------------------------------------------
// Collector specific widgets
// ------------------------------------------------------------------
/**
* Widget for the MessagesCollector
*
* Uses ListWidget under the hood
*
* Options:
* - data
*/
var MessagesWidget = PhpDebugBar.Widgets.MessagesWidget = PhpDebugBar.Widget.extend({
className: csscls('messages'),
render: function() {
var self = this;
this.$list = new ListWidget({ itemRenderer: function(li, value) {
if (value.message_html) {
var val = $('').addClass(csscls('value')).html(value.message_html).appendTo(li);
} else {
var m = value.message;
if (m.length > 100) {
m = m.substr(0, 100) + "...";
}
var val = $('').addClass(csscls('value')).text(m).appendTo(li);
if (!value.is_string || value.message.length > 100) {
var prettyVal = value.message;
if (!value.is_string) {
prettyVal = null;
}
li.css('cursor', 'pointer').click(function () {
if (window.getSelection().type == "Range") {
return''
}
if (val.hasClass(csscls('pretty'))) {
val.text(m).removeClass(csscls('pretty'));
} else {
prettyVal = prettyVal || createCodeBlock(value.message, 'php');
val.addClass(csscls('pretty')).empty().append(prettyVal);
}
});
}
}
if (value.xdebug_link) {
var header = $('').addClass(csscls('filename')).text(value.xdebug_link.filename + ( value.xdebug_link.line ? "#" + value.xdebug_link.line : ''));
if (value.xdebug_link) {
if (value.xdebug_link.ajax) {
$('').on('click', function () {
$.ajax(value.xdebug_link.url);
}).addClass(csscls('editor-link')).appendTo(header);
} else {
$('').addClass(csscls('editor-link')).appendTo(header);
}
}
header.appendTo(li);
}
if (value.collector) {
$('').addClass(csscls('collector')).text(value.collector).prependTo(li);
}
if (value.label) {
val.addClass(csscls(value.label));
$('').addClass(csscls('label')).text(value.label).prependTo(li);
}
}});
this.$list.$el.appendTo(this.$el);
this.$toolbar = $('