[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 if (typeof(PhpDebugBar) == 'undefined') { 2 // namespace 3 var PhpDebugBar = {}; 4 PhpDebugBar.$ = jQuery; 5 } 6 7 (function($) { 8 9 /** 10 * @namespace 11 */ 12 PhpDebugBar.Widgets = {}; 13 14 var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-'); 15 16 /** 17 * Replaces spaces with and line breaks with <br> 18 * 19 * @param {String} text 20 * @return {String} 21 */ 22 var htmlize = PhpDebugBar.Widgets.htmlize = function(text) { 23 return text.replace(/\n/g, '<br>').replace(/\s/g, " ") 24 }; 25 26 /** 27 * Returns a string representation of value, using JSON.stringify 28 * if it's an object. 29 * 30 * @param {Object} value 31 * @param {Boolean} prettify Uses htmlize() if true 32 * @return {String} 33 */ 34 var renderValue = PhpDebugBar.Widgets.renderValue = function(value, prettify) { 35 if (typeof(value) !== 'string') { 36 if (prettify) { 37 return htmlize(JSON.stringify(value, undefined, 2)); 38 } 39 return JSON.stringify(value); 40 } 41 return value; 42 }; 43 44 /** 45 * Highlights a block of code 46 * 47 * @param {String} code 48 * @param {String} lang 49 * @return {String} 50 */ 51 var highlight = PhpDebugBar.Widgets.highlight = function(code, lang) { 52 if (typeof(code) === 'string') { 53 if (typeof(hljs) === 'undefined') { 54 return htmlize(code); 55 } 56 if (lang) { 57 return hljs.highlight(lang, code).value; 58 } 59 return hljs.highlightAuto(code).value; 60 } 61 62 if (typeof(hljs) === 'object') { 63 code.each(function(i, e) { hljs.highlightBlock(e); }); 64 } 65 return code; 66 }; 67 68 /** 69 * Creates a <pre> element with a block of code 70 * 71 * @param {String} code 72 * @param {String} lang 73 * @param {Number} [firstLineNumber] If provided, shows line numbers beginning with the given value. 74 * @param {Number} [highlightedLine] If provided, the given line number will be highlighted. 75 * @return {String} 76 */ 77 var createCodeBlock = PhpDebugBar.Widgets.createCodeBlock = function(code, lang, firstLineNumber, highlightedLine) { 78 var pre = $('<pre />').addClass(csscls('code-block')); 79 // Add a newline to prevent <code> element from vertically collapsing too far if the last 80 // code line was empty: that creates problems with the horizontal scrollbar being 81 // incorrectly positioned - most noticeable when line numbers are shown. 82 var codeElement = $('<code />').text(code + '\n').appendTo(pre); 83 84 // Add a span with a special class if we are supposed to highlight a line. highlight.js will 85 // still correctly format code even with existing markup in it. 86 if ($.isNumeric(highlightedLine)) { 87 if ($.isNumeric(firstLineNumber)) { 88 highlightedLine = highlightedLine - firstLineNumber + 1; 89 } 90 codeElement.html(function (index, html) { 91 var currentLine = 1; 92 return html.replace(/^.*$/gm, function(line) { 93 if (currentLine++ == highlightedLine) { 94 return '<span class="' + csscls('highlighted-line') + '">' + line + '</span>'; 95 } else { 96 return line; 97 } 98 }); 99 }); 100 } 101 102 // Format the code 103 if (lang) { 104 pre.addClass("language-" + lang); 105 } 106 highlight(pre); 107 108 // Show line numbers in a list 109 if ($.isNumeric(firstLineNumber)) { 110 var lineCount = code.split('\n').length; 111 var $lineNumbers = $('<ul />').prependTo(pre); 112 pre.children().addClass(csscls('numbered-code')); 113 for (var i = firstLineNumber; i < firstLineNumber + lineCount; i++) { 114 $('<li />').text(i).appendTo($lineNumbers); 115 } 116 } 117 118 return pre; 119 }; 120 121 // ------------------------------------------------------------------ 122 // Generic widgets 123 // ------------------------------------------------------------------ 124 125 /** 126 * Displays array element in a <ul> list 127 * 128 * Options: 129 * - data 130 * - itemRenderer: a function used to render list items (optional) 131 */ 132 var ListWidget = PhpDebugBar.Widgets.ListWidget = PhpDebugBar.Widget.extend({ 133 134 tagName: 'ul', 135 136 className: csscls('list'), 137 138 initialize: function(options) { 139 if (!options['itemRenderer']) { 140 options['itemRenderer'] = this.itemRenderer; 141 } 142 this.set(options); 143 }, 144 145 render: function() { 146 this.bindAttr(['itemRenderer', 'data'], function() { 147 this.$el.empty(); 148 if (!this.has('data')) { 149 return; 150 } 151 152 var data = this.get('data'); 153 for (var i = 0; i < data.length; i++) { 154 var li = $('<li />').addClass(csscls('list-item')).appendTo(this.$el); 155 this.get('itemRenderer')(li, data[i]); 156 } 157 }); 158 }, 159 160 /** 161 * Renders the content of a <li> element 162 * 163 * @param {jQuery} li The <li> element as a jQuery Object 164 * @param {Object} value An item from the data array 165 */ 166 itemRenderer: function(li, value) { 167 li.html(renderValue(value)); 168 } 169 170 }); 171 172 // ------------------------------------------------------------------ 173 174 /** 175 * Displays object property/value paris in a <dl> list 176 * 177 * Options: 178 * - data 179 * - itemRenderer: a function used to render list items (optional) 180 */ 181 var KVListWidget = PhpDebugBar.Widgets.KVListWidget = ListWidget.extend({ 182 183 tagName: 'dl', 184 185 className: csscls('kvlist'), 186 187 render: function() { 188 this.bindAttr(['itemRenderer', 'data'], function() { 189 this.$el.empty(); 190 if (!this.has('data')) { 191 return; 192 } 193 194 var self = this; 195 $.each(this.get('data'), function(key, value) { 196 var dt = $('<dt />').addClass(csscls('key')).appendTo(self.$el); 197 var dd = $('<dd />').addClass(csscls('value')).appendTo(self.$el); 198 self.get('itemRenderer')(dt, dd, key, value); 199 }); 200 }); 201 }, 202 203 /** 204 * Renders the content of the <dt> and <dd> elements 205 * 206 * @param {jQuery} dt The <dt> element as a jQuery Object 207 * @param {jQuery} dd The <dd> element as a jQuery Object 208 * @param {String} key Property name 209 * @param {Object} value Property value 210 */ 211 itemRenderer: function(dt, dd, key, value) { 212 dt.text(key); 213 dd.html(htmlize(value)); 214 } 215 216 }); 217 218 // ------------------------------------------------------------------ 219 220 /** 221 * An extension of KVListWidget where the data represents a list 222 * of variables 223 * 224 * Options: 225 * - data 226 */ 227 var VariableListWidget = PhpDebugBar.Widgets.VariableListWidget = KVListWidget.extend({ 228 229 className: csscls('kvlist varlist'), 230 231 itemRenderer: function(dt, dd, key, value) { 232 $('<span />').attr('title', key).text(key).appendTo(dt); 233 234 var v = value; 235 if (v && v.length > 100) { 236 v = v.substr(0, 100) + "..."; 237 } 238 var prettyVal = null; 239 dd.text(v).click(function() { 240 if (dd.hasClass(csscls('pretty'))) { 241 dd.text(v).removeClass(csscls('pretty')); 242 } else { 243 prettyVal = prettyVal || createCodeBlock(value); 244 dd.addClass(csscls('pretty')).empty().append(prettyVal); 245 } 246 }); 247 } 248 249 }); 250 251 // ------------------------------------------------------------------ 252 253 /** 254 * An extension of KVListWidget where the data represents a list 255 * of variables whose contents are HTML; this is useful for showing 256 * variable output from VarDumper's HtmlDumper. 257 * 258 * Options: 259 * - data 260 */ 261 var HtmlVariableListWidget = PhpDebugBar.Widgets.HtmlVariableListWidget = KVListWidget.extend({ 262 263 className: csscls('kvlist htmlvarlist'), 264 265 itemRenderer: function(dt, dd, key, value) { 266 $('<span />').attr('title', key).text(key).appendTo(dt); 267 dd.html(value); 268 } 269 270 }); 271 272 // ------------------------------------------------------------------ 273 274 /** 275 * Iframe widget 276 * 277 * Options: 278 * - data 279 */ 280 var IFrameWidget = PhpDebugBar.Widgets.IFrameWidget = PhpDebugBar.Widget.extend({ 281 282 tagName: 'iframe', 283 284 className: csscls('iframe'), 285 286 render: function() { 287 this.$el.attr({ 288 seamless: "seamless", 289 border: "0", 290 width: "100%", 291 height: "100%" 292 }); 293 this.bindAttr('data', function(url) { this.$el.attr('src', url); }); 294 } 295 296 }); 297 298 299 // ------------------------------------------------------------------ 300 // Collector specific widgets 301 // ------------------------------------------------------------------ 302 303 /** 304 * Widget for the MessagesCollector 305 * 306 * Uses ListWidget under the hood 307 * 308 * Options: 309 * - data 310 */ 311 var MessagesWidget = PhpDebugBar.Widgets.MessagesWidget = PhpDebugBar.Widget.extend({ 312 313 className: csscls('messages'), 314 315 render: function() { 316 var self = this; 317 318 this.$list = new ListWidget({ itemRenderer: function(li, value) { 319 if (value.message_html) { 320 var val = $('<span />').addClass(csscls('value')).html(value.message_html).appendTo(li); 321 } else { 322 var m = value.message; 323 if (m.length > 100) { 324 m = m.substr(0, 100) + "..."; 325 } 326 327 var val = $('<span />').addClass(csscls('value')).text(m).appendTo(li); 328 if (!value.is_string || value.message.length > 100) { 329 var prettyVal = value.message; 330 if (!value.is_string) { 331 prettyVal = null; 332 } 333 li.css('cursor', 'pointer').click(function () { 334 if (val.hasClass(csscls('pretty'))) { 335 val.text(m).removeClass(csscls('pretty')); 336 } else { 337 prettyVal = prettyVal || createCodeBlock(value.message, 'php'); 338 val.addClass(csscls('pretty')).empty().append(prettyVal); 339 } 340 }); 341 } 342 } 343 344 if (value.collector) { 345 $('<span />').addClass(csscls('collector')).text(value.collector).prependTo(li); 346 } 347 if (value.label) { 348 val.addClass(csscls(value.label)); 349 $('<span />').addClass(csscls('label')).text(value.label).prependTo(li); 350 } 351 }}); 352 353 this.$list.$el.appendTo(this.$el); 354 this.$toolbar = $('<div><i class="phpdebugbar-fa phpdebugbar-fa-search"></i></div>').addClass(csscls('toolbar')).appendTo(this.$el); 355 356 $('<input type="text" />') 357 .on('change', function() { self.set('search', this.value); }) 358 .appendTo(this.$toolbar); 359 360 this.bindAttr('data', function(data) { 361 this.set({ exclude: [], search: '' }); 362 this.$toolbar.find(csscls('.filter')).remove(); 363 364 var filters = [], self = this; 365 for (var i = 0; i < data.length; i++) { 366 if (!data[i].label || $.inArray(data[i].label, filters) > -1) { 367 continue; 368 } 369 filters.push(data[i].label); 370 $('<a />') 371 .addClass(csscls('filter')) 372 .text(data[i].label) 373 .attr('rel', data[i].label) 374 .on('click', function() { self.onFilterClick(this); }) 375 .appendTo(this.$toolbar); 376 } 377 }); 378 379 this.bindAttr(['exclude', 'search'], function() { 380 var data = this.get('data'), 381 exclude = this.get('exclude'), 382 search = this.get('search'), 383 caseless = false, 384 fdata = []; 385 386 if (search && search === search.toLowerCase()) { 387 caseless = true; 388 } 389 390 for (var i = 0; i < data.length; i++) { 391 var message = caseless ? data[i].message.toLowerCase() : data[i].message; 392 393 if ((!data[i].label || $.inArray(data[i].label, exclude) === -1) && (!search || message.indexOf(search) > -1)) { 394 fdata.push(data[i]); 395 } 396 } 397 398 this.$list.set('data', fdata); 399 }); 400 }, 401 402 onFilterClick: function(el) { 403 $(el).toggleClass(csscls('excluded')); 404 405 var excludedLabels = []; 406 this.$toolbar.find(csscls('.filter') + csscls('.excluded')).each(function() { 407 excludedLabels.push(this.rel); 408 }); 409 410 this.set('exclude', excludedLabels); 411 } 412 413 }); 414 415 // ------------------------------------------------------------------ 416 417 /** 418 * Widget for the TimeDataCollector 419 * 420 * Options: 421 * - data 422 */ 423 var TimelineWidget = PhpDebugBar.Widgets.TimelineWidget = PhpDebugBar.Widget.extend({ 424 425 tagName: 'ul', 426 427 className: csscls('timeline'), 428 429 render: function() { 430 this.bindAttr('data', function(data) { 431 432 // ported from php DataFormatter 433 var formatDuration = function(seconds) { 434 if (seconds < 0.001) 435 return (seconds * 1000000).toFixed() + 'μs'; 436 else if (seconds < 1) 437 return (seconds * 1000).toFixed(2) + 'ms'; 438 return (seconds).toFixed(2) + 's'; 439 }; 440 441 this.$el.empty(); 442 if (data.measures) { 443 var aggregate = {}; 444 445 for (var i = 0; i < data.measures.length; i++) { 446 var measure = data.measures[i]; 447 448 if(!aggregate[measure.label]) 449 aggregate[measure.label] = { count: 0, duration: 0 }; 450 451 aggregate[measure.label]['count'] += 1; 452 aggregate[measure.label]['duration'] += measure.duration; 453 454 var m = $('<div />').addClass(csscls('measure')), 455 li = $('<li />'), 456 left = (measure.relative_start * 100 / data.duration).toFixed(2), 457 width = Math.min((measure.duration * 100 / data.duration).toFixed(2), 100 - left); 458 459 m.append($('<span />').addClass(csscls('value')).css({ 460 left: left + "%", 461 width: width + "%" 462 })); 463 m.append($('<span />').addClass(csscls('label')).text(measure.label + " (" + measure.duration_str + ")")); 464 465 if (measure.collector) { 466 $('<span />').addClass(csscls('collector')).text(measure.collector).appendTo(m); 467 } 468 469 m.appendTo(li); 470 this.$el.append(li); 471 472 if (measure.params && !$.isEmptyObject(measure.params)) { 473 var table = $('<table><tr><th colspan="2">Params</th></tr></table>').addClass(csscls('params')).appendTo(li); 474 for (var key in measure.params) { 475 if (typeof measure.params[key] !== 'function') { 476 table.append('<tr><td class="' + csscls('name') + '">' + key + '</td><td class="' + csscls('value') + 477 '"><pre><code>' + measure.params[key] + '</code></pre></td></tr>'); 478 } 479 } 480 li.css('cursor', 'pointer').click(function() { 481 var table = $(this).find('table'); 482 if (table.is(':visible')) { 483 table.hide(); 484 } else { 485 table.show(); 486 } 487 }); 488 } 489 } 490 491 // convert to array and sort by duration 492 aggregate = $.map(aggregate, function(data, label) { 493 return { 494 label: label, 495 data: data 496 } 497 }).sort(function(a, b) { 498 return b.data.duration - a.data.duration 499 }); 500 501 // build table and add 502 var aggregateTable = $('<table style="display: table; border: 0; width: 99%"></table>').addClass(csscls('params')); 503 $.each(aggregate, function(i, aggregate) { 504 width = Math.min((aggregate.data.duration * 100 / data.duration).toFixed(2), 100); 505 506 aggregateTable.append('<tr><td class="' + csscls('name') + '">' + aggregate.data.count + ' x ' + aggregate.label + ' (' + width + '%)</td><td class="' + csscls('value') + '">' + 507 '<div class="' + csscls('measure') +'">' + 508 '<span class="' + csscls('value') + '" style="width:' + width + '%"></span>' + 509 '<span class="' + csscls('label') + '">' + formatDuration(aggregate.data.duration) + '</span>' + 510 '</div></td></tr>'); 511 }); 512 513 this.$el.append('<li/>').find('li:last').append(aggregateTable); 514 } 515 }); 516 } 517 518 }); 519 520 // ------------------------------------------------------------------ 521 522 /** 523 * Widget for the displaying exceptions 524 * 525 * Options: 526 * - data 527 */ 528 var ExceptionsWidget = PhpDebugBar.Widgets.ExceptionsWidget = PhpDebugBar.Widget.extend({ 529 530 className: csscls('exceptions'), 531 532 render: function() { 533 this.$list = new ListWidget({ itemRenderer: function(li, e) { 534 $('<span />').addClass(csscls('message')).text(e.message).appendTo(li); 535 if (e.file) { 536 var header = $('<span />').addClass(csscls('filename')).text(e.file + "#" + e.line); 537 if (e.xdebug_link) { 538 if (e.xdebug_link.ajax) { 539 $('<a title="' + e.xdebug_link.url + '"></a>').on('click', function () { 540 $.ajax(e.xdebug_link.url); 541 }).addClass(csscls('editor-link')).appendTo(header); 542 } else { 543 $('<a href="' + e.xdebug_link.url + '"></a>').addClass(csscls('editor-link')).appendTo(header); 544 } 545 } 546 header.appendTo(li); 547 } 548 if (e.type) { 549 $('<span />').addClass(csscls('type')).text(e.type).appendTo(li); 550 } 551 if (e.surrounding_lines) { 552 var pre = createCodeBlock(e.surrounding_lines.join(""), 'php').addClass(csscls('file')).appendTo(li); 553 if (!e.stack_trace_html) { 554 // This click event makes the var-dumper hard to use. 555 li.click(function () { 556 if (pre.is(':visible')) { 557 pre.hide(); 558 } else { 559 pre.show(); 560 } 561 }); 562 } 563 } 564 if (e.stack_trace_html) { 565 var $trace = $('<span />').addClass(csscls('filename')).html(e.stack_trace_html); 566 $trace.appendTo(li); 567 } else if (e.stack_trace) { 568 e.stack_trace.split("\n").forEach(function (trace) { 569 var $traceLine = $('<div />'); 570 $('<span />').addClass(csscls('filename')).text(trace).appendTo($traceLine); 571 $traceLine.appendTo(li); 572 }); 573 } 574 }}); 575 this.$list.$el.appendTo(this.$el); 576 577 this.bindAttr('data', function(data) { 578 this.$list.set('data', data); 579 if (data.length == 1) { 580 this.$list.$el.children().first().find(csscls('.file')).show(); 581 } 582 }); 583 584 } 585 586 }); 587 588 589 })(PhpDebugBar.$);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |