[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/vendor/debugbar/ -> debugbar.js (source)

   1  if (typeof(PhpDebugBar) == 'undefined') {
   2      // namespace
   3      var PhpDebugBar = {};
   4      PhpDebugBar.$ = jQuery;
   5  }
   6  
   7  (function($) {
   8  
   9      if (typeof(localStorage) == 'undefined') {
  10          // provide mock localStorage object for dumb browsers
  11          localStorage = {
  12              setItem: function(key, value) {},
  13              getItem: function(key) { return null; }
  14          };
  15      }
  16  
  17      if (typeof(PhpDebugBar.utils) == 'undefined') {
  18          PhpDebugBar.utils = {};
  19      }
  20  
  21      /**
  22       * Returns the value from an object property.
  23       * Using dots in the key, it is possible to retrieve nested property values
  24       *
  25       * @param {Object} dict
  26       * @param {String} key
  27       * @param {Object} default_value
  28       * @return {Object}
  29       */
  30      var getDictValue = PhpDebugBar.utils.getDictValue = function(dict, key, default_value) {
  31          var d = dict, parts = key.split('.');
  32          for (var i = 0; i < parts.length; i++) {
  33              if (!d[parts[i]]) {
  34                  return default_value;
  35              }
  36              d = d[parts[i]];
  37          }
  38          return d;
  39      }
  40  
  41      /**
  42       * Counts the number of properties in an object
  43       *
  44       * @param {Object} obj
  45       * @return {Integer}
  46       */
  47      var getObjectSize = PhpDebugBar.utils.getObjectSize = function(obj) {
  48          if (Object.keys) {
  49              return Object.keys(obj).length;
  50          }
  51          var count = 0;
  52          for (var k in obj) {
  53              if (obj.hasOwnProperty(k)) {
  54                  count++;
  55              }
  56          }
  57          return count;
  58      }
  59  
  60      /**
  61       * Returns a prefixed css class name
  62       *
  63       * @param {String} cls
  64       * @return {String}
  65       */
  66      PhpDebugBar.utils.csscls = function(cls, prefix) {
  67          if (cls.indexOf(' ') > -1) {
  68              var clss = cls.split(' '), out = [];
  69              for (var i = 0, c = clss.length; i < c; i++) {
  70                  out.push(PhpDebugBar.utils.csscls(clss[i], prefix));
  71              }
  72              return out.join(' ');
  73          }
  74          if (cls.indexOf('.') === 0) {
  75              return '.' + prefix + cls.substr(1);
  76          }
  77          return prefix + cls;
  78      };
  79  
  80      /**
  81       * Creates a partial function of csscls where the second
  82       * argument is already defined
  83       *
  84       * @param  {string} prefix
  85       * @return {Function}
  86       */
  87      PhpDebugBar.utils.makecsscls = function(prefix) {
  88          var f = function(cls) {
  89              return PhpDebugBar.utils.csscls(cls, prefix);
  90          };
  91          return f;
  92      }
  93  
  94      var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-');
  95  
  96  
  97      // ------------------------------------------------------------------
  98  
  99      /**
 100       * Base class for all elements with a visual component
 101       *
 102       * @param {Object} options
 103       * @constructor
 104       */
 105      var Widget = PhpDebugBar.Widget = function(options) {
 106          this._attributes = $.extend({}, this.defaults);
 107          this._boundAttributes = {};
 108          this.$el = $('<' + this.tagName + ' />');
 109          if (this.className) {
 110              this.$el.addClass(this.className);
 111          }
 112          this.initialize.apply(this, [options || {}]);
 113          this.render.apply(this);
 114      };
 115  
 116      $.extend(Widget.prototype, {
 117  
 118          tagName: 'div',
 119  
 120          className: null,
 121  
 122          defaults: {},
 123  
 124          /**
 125           * Called after the constructor
 126           *
 127           * @param {Object} options
 128           */
 129          initialize: function(options) {
 130              this.set(options);
 131          },
 132  
 133          /**
 134           * Called after the constructor to render the element
 135           */
 136          render: function() {},
 137  
 138          /**
 139           * Sets the value of an attribute
 140           *
 141           * @param {String} attr Can also be an object to set multiple attributes at once
 142           * @param {Object} value
 143           */
 144          set: function(attr, value) {
 145              if (typeof(attr) != 'string') {
 146                  for (var k in attr) {
 147                      this.set(k, attr[k]);
 148                  }
 149                  return;
 150              }
 151  
 152              this._attributes[attr] = value;
 153              if (typeof(this._boundAttributes[attr]) !== 'undefined') {
 154                  for (var i = 0, c = this._boundAttributes[attr].length; i < c; i++) {
 155                      this._boundAttributes[attr][i].apply(this, [value]);
 156                  }
 157              }
 158          },
 159  
 160          /**
 161           * Checks if an attribute exists and is not null
 162           *
 163           * @param {String} attr
 164           * @return {[type]} [description]
 165           */
 166          has: function(attr) {
 167              return typeof(this._attributes[attr]) !== 'undefined' && this._attributes[attr] !== null;
 168          },
 169  
 170          /**
 171           * Returns the value of an attribute
 172           *
 173           * @param {String} attr
 174           * @return {Object}
 175           */
 176          get: function(attr) {
 177              return this._attributes[attr];
 178          },
 179  
 180          /**
 181           * Registers a callback function that will be called whenever the value of the attribute changes
 182           *
 183           * If cb is a jQuery element, text() will be used to fill the element
 184           *
 185           * @param {String} attr
 186           * @param {Function} cb
 187           */
 188          bindAttr: function(attr, cb) {
 189              if ($.isArray(attr)) {
 190                  for (var i = 0, c = attr.length; i < c; i++) {
 191                      this.bindAttr(attr[i], cb);
 192                  }
 193                  return;
 194              }
 195  
 196              if (typeof(this._boundAttributes[attr]) == 'undefined') {
 197                  this._boundAttributes[attr] = [];
 198              }
 199              if (typeof(cb) == 'object') {
 200                  var el = cb;
 201                  cb = function(value) { el.text(value || ''); };
 202              }
 203              this._boundAttributes[attr].push(cb);
 204              if (this.has(attr)) {
 205                  cb.apply(this, [this._attributes[attr]]);
 206              }
 207          }
 208  
 209      });
 210  
 211  
 212      /**
 213       * Creates a subclass
 214       *
 215       * Code from Backbone.js
 216       *
 217       * @param {Array} props Prototype properties
 218       * @return {Function}
 219       */
 220      Widget.extend = function(props) {
 221          var parent = this;
 222  
 223          var child = function() { return parent.apply(this, arguments); };
 224          $.extend(child, parent);
 225  
 226          var Surrogate = function() { this.constructor = child; };
 227          Surrogate.prototype = parent.prototype;
 228          child.prototype = new Surrogate;
 229          $.extend(child.prototype, props);
 230  
 231          child.__super__ = parent.prototype;
 232  
 233          return child;
 234      };
 235  
 236      // ------------------------------------------------------------------
 237  
 238      /**
 239       * Tab
 240       *
 241       * A tab is composed of a tab label which is always visible and
 242       * a tab panel which is visible only when the tab is active.
 243       *
 244       * The panel must contain a widget. A widget is an object which has
 245       * an element property containing something appendable to a jQuery object.
 246       *
 247       * Options:
 248       *  - title
 249       *  - badge
 250       *  - widget
 251       *  - data: forward data to widget data
 252       */
 253      var Tab = Widget.extend({
 254  
 255          className: csscls('panel'),
 256  
 257          render: function() {
 258              this.$tab = $('<a />').addClass(csscls('tab'));
 259  
 260              this.$icon = $('<i />').appendTo(this.$tab);
 261              this.bindAttr('icon', function(icon) {
 262                  if (icon) {
 263                      this.$icon.attr('class', 'phpdebugbar-fa phpdebugbar-fa-' + icon);
 264                  } else {
 265                      this.$icon.attr('class', '');
 266                  }
 267              });
 268  
 269              this.bindAttr('title', $('<span />').addClass(csscls('text')).appendTo(this.$tab));
 270  
 271              this.$badge = $('<span />').addClass(csscls('badge')).appendTo(this.$tab);
 272              this.bindAttr('badge', function(value) {
 273                  if (value !== null) {
 274                      this.$badge.text(value);
 275                      this.$badge.addClass(csscls('visible'));
 276                  } else {
 277                      this.$badge.removeClass(csscls('visible'));
 278                  }
 279              });
 280  
 281              this.bindAttr('widget', function(widget) {
 282                  this.$el.empty().append(widget.$el);
 283              });
 284  
 285              this.bindAttr('data', function(data) {
 286                  if (this.has('widget')) {
 287                      this.get('widget').set('data', data);
 288                  }
 289              })
 290          }
 291  
 292      });
 293  
 294      // ------------------------------------------------------------------
 295  
 296      /**
 297       * Indicator
 298       *
 299       * An indicator is a text and an icon to display single value information
 300       * right inside the always visible part of the debug bar
 301       *
 302       * Options:
 303       *  - icon
 304       *  - title
 305       *  - tooltip
 306       *  - data: alias of title
 307       */
 308      var Indicator = Widget.extend({
 309  
 310          tagName: 'span',
 311  
 312          className: csscls('indicator'),
 313  
 314          render: function() {
 315              this.$icon = $('<i />').appendTo(this.$el);
 316              this.bindAttr('icon', function(icon) {
 317                  if (icon) {
 318                      this.$icon.attr('class', 'phpdebugbar-fa phpdebugbar-fa-' + icon);
 319                  } else {
 320                      this.$icon.attr('class', '');
 321                  }
 322              });
 323  
 324              this.bindAttr(['title', 'data'], $('<span />').addClass(csscls('text')).appendTo(this.$el));
 325  
 326              this.$tooltip = $('<span />').addClass(csscls('tooltip disabled')).appendTo(this.$el);
 327              this.bindAttr('tooltip', function(tooltip) {
 328                  if (tooltip) {
 329                      this.$tooltip.text(tooltip).removeClass(csscls('disabled'));
 330                  } else {
 331                      this.$tooltip.addClass(csscls('disabled'));
 332                  }
 333              });
 334          }
 335  
 336      });
 337  
 338      // ------------------------------------------------------------------
 339  
 340      /**
 341       * Dataset title formater
 342       *
 343       * Formats the title of a dataset for the select box
 344       */
 345      var DatasetTitleFormater = PhpDebugBar.DatasetTitleFormater = function(debugbar) {
 346          this.debugbar = debugbar;
 347      };
 348  
 349      $.extend(DatasetTitleFormater.prototype, {
 350  
 351          /**
 352           * Formats the title of a dataset
 353           *
 354           * @this {DatasetTitleFormater}
 355           * @param {String} id
 356           * @param {Object} data
 357           * @param {String} suffix
 358           * @return {String}
 359           */
 360          format: function(id, data, suffix) {
 361              if (suffix) {
 362                  suffix = ' ' + suffix;
 363              } else {
 364                  suffix = '';
 365              }
 366  
 367              var nb = getObjectSize(this.debugbar.datasets) + 1;
 368  
 369              if (typeof(data['__meta']) === 'undefined') {
 370                  return "#" + nb + suffix;
 371              }
 372  
 373              var uri = data['__meta']['uri'], filename;
 374              if (uri.length && uri.charAt(uri.length - 1) === '/') {
 375                  // URI ends in a trailing /: get the portion before then to avoid returning an empty string
 376                  filename = uri.substr(0, uri.length - 1); // strip trailing '/'
 377                  filename = filename.substr(filename.lastIndexOf('/') + 1); // get last path segment
 378                  filename += '/'; // add the trailing '/' back
 379              } else {
 380                  filename = uri.substr(uri.lastIndexOf('/') + 1);
 381              }
 382  
 383              // truncate the filename in the label, if it's too long
 384              var maxLength = 150;
 385              if (filename.length > maxLength) {
 386                  filename = filename.substr(0, maxLength) + '...';
 387              }
 388  
 389              var label = "#" + nb + " " + filename + suffix + ' (' + data['__meta']['datetime'].split(' ')[1] + ')';
 390              return label;
 391          }
 392  
 393      });
 394  
 395      // ------------------------------------------------------------------
 396  
 397  
 398      /**
 399       * DebugBar
 400       *
 401       * Creates a bar that appends itself to the body of your page
 402       * and sticks to the bottom.
 403       *
 404       * The bar can be customized by adding tabs and indicators.
 405       * A data map is used to fill those controls with data provided
 406       * from datasets.
 407       */
 408      var DebugBar = PhpDebugBar.DebugBar = Widget.extend({
 409  
 410          className: "phpdebugbar " + csscls('minimized'),
 411  
 412          options: {
 413              bodyMarginBottom: true,
 414              bodyMarginBottomHeight: 0
 415          },
 416  
 417          initialize: function() {
 418              this.controls = {};
 419              this.dataMap = {};
 420              this.datasets = {};
 421              this.firstTabName = null;
 422              this.activePanelName = null;
 423              this.datesetTitleFormater = new DatasetTitleFormater(this);
 424              this.options.bodyMarginBottomHeight = parseInt($('body').css('margin-bottom'));
 425              this.registerResizeHandler();
 426          },
 427  
 428          /**
 429           * Register resize event, for resize debugbar with reponsive css.
 430           *
 431           * @this {DebugBar}
 432           */
 433          registerResizeHandler: function() {
 434              if (typeof this.resize.bind == 'undefined') return;
 435  
 436              var f = this.resize.bind(this);
 437              this.respCSSSize = 0;
 438              $(window).resize(f);
 439              setTimeout(f, 20);
 440          },
 441  
 442          /**
 443           * Resizes the debugbar to fit the current browser window
 444           */
 445          resize: function() {
 446              var contentSize = this.respCSSSize;
 447              if (this.respCSSSize == 0) {
 448                  this.$header.find("> div > *:visible").each(function () {
 449                      contentSize += $(this).outerWidth();
 450                  });
 451              }
 452  
 453              var currentSize = this.$header.width();
 454              var cssClass = "phpdebugbar-mini-design";
 455              var bool = this.$header.hasClass(cssClass);
 456  
 457              if (currentSize <= contentSize && !bool) {
 458                  this.respCSSSize = contentSize;
 459                  this.$header.addClass(cssClass);
 460              } else if (contentSize < currentSize && bool) {
 461                  this.respCSSSize = 0;
 462                  this.$header.removeClass(cssClass);
 463              }
 464  
 465              // Reset height to ensure bar is still visible
 466              this.setHeight(this.$body.height());
 467          },
 468  
 469          /**
 470           * Initialiazes the UI
 471           *
 472           * @this {DebugBar}
 473           */
 474          render: function() {
 475              var self = this;
 476              this.$el.appendTo('body');
 477              this.$dragCapture = $('<div />').addClass(csscls('drag-capture')).appendTo(this.$el);
 478              this.$resizehdle = $('<div />').addClass(csscls('resize-handle')).appendTo(this.$el);
 479              this.$header = $('<div />').addClass(csscls('header')).appendTo(this.$el);
 480              this.$headerLeft = $('<div />').addClass(csscls('header-left')).appendTo(this.$header);
 481              this.$headerRight = $('<div />').addClass(csscls('header-right')).appendTo(this.$header);
 482              var $body = this.$body = $('<div />').addClass(csscls('body')).appendTo(this.$el);
 483              this.recomputeBottomOffset();
 484  
 485              // dragging of resize handle
 486              var pos_y, orig_h;
 487              this.$resizehdle.on('mousedown', function(e) {
 488                  orig_h = $body.height(), pos_y = e.pageY;
 489                  $body.parents().on('mousemove', mousemove).on('mouseup', mouseup);
 490                  self.$dragCapture.show();
 491                  e.preventDefault();
 492              });
 493              var mousemove = function(e) {
 494                  var h = orig_h + (pos_y - e.pageY);
 495                  self.setHeight(h);
 496              };
 497              var mouseup = function() {
 498                  $body.parents().off('mousemove', mousemove).off('mouseup', mouseup);
 499                  self.$dragCapture.hide();
 500              };
 501  
 502              // close button
 503              this.$closebtn = $('<a />').addClass(csscls('close-btn')).appendTo(this.$headerRight);
 504              this.$closebtn.click(function() {
 505                  self.close();
 506              });
 507  
 508              // minimize button
 509              this.$minimizebtn = $('<a />').addClass(csscls('minimize-btn') ).appendTo(this.$headerRight);
 510              this.$minimizebtn.click(function() {
 511                  self.minimize();
 512              });
 513  
 514              // maximize button
 515              this.$maximizebtn = $('<a />').addClass(csscls('maximize-btn') ).appendTo(this.$headerRight);
 516              this.$maximizebtn.click(function() {
 517                  self.restore();
 518              });
 519  
 520              // restore button
 521              this.$restorebtn = $('<a />').addClass(csscls('restore-btn')).hide().appendTo(this.$el);
 522              this.$restorebtn.click(function() {
 523                  self.restore();
 524              });
 525  
 526              // open button
 527              this.$openbtn = $('<a />').addClass(csscls('open-btn')).appendTo(this.$headerRight).hide();
 528              this.$openbtn.click(function() {
 529                  self.openHandler.show(function(id, dataset) {
 530                      self.addDataSet(dataset, id, "(opened)");
 531                      self.showTab();
 532                  });
 533              });
 534  
 535              // select box for data sets
 536              this.$datasets = $('<select />').addClass(csscls('datasets-switcher')).appendTo(this.$headerRight);
 537              this.$datasets.change(function() {
 538                  self.dataChangeHandler(self.datasets[this.value]);
 539                  self.showTab();
 540              });
 541          },
 542  
 543          /**
 544           * Sets the height of the debugbar body section
 545           * Forces the height to lie within a reasonable range
 546           * Stores the height in local storage so it can be restored
 547           * Resets the document body bottom offset
 548           *
 549           * @this {DebugBar}
 550           */
 551          setHeight: function(height) {
 552            var min_h = 40;
 553            var max_h = $(window).innerHeight() - this.$header.height() - 10;
 554            height = Math.min(height, max_h);
 555            height = Math.max(height, min_h);
 556            this.$body.css('height', height);
 557            localStorage.setItem('phpdebugbar-height', height);
 558            this.recomputeBottomOffset();
 559          },
 560  
 561          /**
 562           * Restores the state of the DebugBar using localStorage
 563           * This is not called by default in the constructor and
 564           * needs to be called by subclasses in their init() method
 565           *
 566           * @this {DebugBar}
 567           */
 568          restoreState: function() {
 569              // bar height
 570              var height = localStorage.getItem('phpdebugbar-height');
 571              this.setHeight(height || this.$body.height());
 572  
 573              // bar visibility
 574              var open = localStorage.getItem('phpdebugbar-open');
 575              if (open && open == '0') {
 576                  this.close();
 577              } else {
 578                  var visible = localStorage.getItem('phpdebugbar-visible');
 579                  if (visible && visible == '1') {
 580                      var tab = localStorage.getItem('phpdebugbar-tab');
 581                      if (this.isTab(tab)) {
 582                          this.showTab(tab);
 583                      }
 584                  }
 585              }
 586          },
 587  
 588          /**
 589           * Creates and adds a new tab
 590           *
 591           * @this {DebugBar}
 592           * @param {String} name Internal name
 593           * @param {Object} widget A widget object with an element property
 594           * @param {String} title The text in the tab, if not specified, name will be used
 595           * @return {Tab}
 596           */
 597          createTab: function(name, widget, title) {
 598              var tab = new Tab({
 599                  title: title || (name.replace(/[_\-]/g, ' ').charAt(0).toUpperCase() + name.slice(1)),
 600                  widget: widget
 601              });
 602              return this.addTab(name, tab);
 603          },
 604  
 605          /**
 606           * Adds a new tab
 607           *
 608           * @this {DebugBar}
 609           * @param {String} name Internal name
 610           * @param {Tab} tab Tab object
 611           * @return {Tab}
 612           */
 613          addTab: function(name, tab) {
 614              if (this.isControl(name)) {
 615                  throw new Error(name + ' already exists');
 616              }
 617  
 618              var self = this;
 619              tab.$tab.appendTo(this.$headerLeft).click(function() {
 620                  if (!self.isMinimized() && self.activePanelName == name) {
 621                      self.minimize();
 622                  } else {
 623                      self.showTab(name);
 624                  }
 625              });
 626              tab.$el.appendTo(this.$body);
 627  
 628              this.controls[name] = tab;
 629              if (this.firstTabName == null) {
 630                  this.firstTabName = name;
 631              }
 632              return tab;
 633          },
 634  
 635          /**
 636           * Creates and adds an indicator
 637           *
 638           * @this {DebugBar}
 639           * @param {String} name Internal name
 640           * @param {String} icon
 641           * @param {String} tooltip
 642           * @param {String} position "right" or "left", default is "right"
 643           * @return {Indicator}
 644           */
 645          createIndicator: function(name, icon, tooltip, position) {
 646              var indicator = new Indicator({
 647                  icon: icon,
 648                  tooltip: tooltip
 649              });
 650              return this.addIndicator(name, indicator, position);
 651          },
 652  
 653          /**
 654           * Adds an indicator
 655           *
 656           * @this {DebugBar}
 657           * @param {String} name Internal name
 658           * @param {Indicator} indicator Indicator object
 659           * @return {Indicator}
 660           */
 661          addIndicator: function(name, indicator, position) {
 662              if (this.isControl(name)) {
 663                  throw new Error(name + ' already exists');
 664              }
 665  
 666              if (position == 'left') {
 667                  indicator.$el.insertBefore(this.$headerLeft.children().first());
 668              } else {
 669                  indicator.$el.appendTo(this.$headerRight);
 670              }
 671  
 672              this.controls[name] = indicator;
 673              return indicator;
 674          },
 675  
 676          /**
 677           * Returns a control
 678           *
 679           * @param {String} name
 680           * @return {Object}
 681           */
 682          getControl: function(name) {
 683              if (this.isControl(name)) {
 684                  return this.controls[name];
 685              }
 686          },
 687  
 688          /**
 689           * Checks if there's a control under the specified name
 690           *
 691           * @this {DebugBar}
 692           * @param {String} name
 693           * @return {Boolean}
 694           */
 695          isControl: function(name) {
 696              return typeof(this.controls[name]) != 'undefined';
 697          },
 698  
 699          /**
 700           * Checks if a tab with the specified name exists
 701           *
 702           * @this {DebugBar}
 703           * @param {String} name
 704           * @return {Boolean}
 705           */
 706          isTab: function(name) {
 707              return this.isControl(name) && this.controls[name] instanceof Tab;
 708          },
 709  
 710          /**
 711           * Checks if an indicator with the specified name exists
 712           *
 713           * @this {DebugBar}
 714           * @param {String} name
 715           * @return {Boolean}
 716           */
 717          isIndicator: function(name) {
 718              return this.isControl(name) && this.controls[name] instanceof Indicator;
 719          },
 720  
 721          /**
 722           * Removes all tabs and indicators from the debug bar and hides it
 723           *
 724           * @this {DebugBar}
 725           */
 726          reset: function() {
 727              this.minimize();
 728              var self = this;
 729              $.each(this.controls, function(name, control) {
 730                  if (self.isTab(name)) {
 731                      control.$tab.remove();
 732                  }
 733                  control.$el.remove();
 734              });
 735              this.controls = {};
 736          },
 737  
 738          /**
 739           * Open the debug bar and display the specified tab
 740           *
 741           * @this {DebugBar}
 742           * @param {String} name If not specified, display the first tab
 743           */
 744          showTab: function(name) {
 745              if (!name) {
 746                  if (this.activePanelName) {
 747                      name = this.activePanelName;
 748                  } else {
 749                      name = this.firstTabName;
 750                  }
 751              }
 752  
 753              if (!this.isTab(name)) {
 754                  throw new Error("Unknown tab '" + name + "'");
 755              }
 756  
 757              this.$resizehdle.show();
 758              this.$body.show();
 759              this.recomputeBottomOffset();
 760  
 761              $(this.$header).find('> div > .' + csscls('active')).removeClass(csscls('active'));
 762              $(this.$body).find('> .' + csscls('active')).removeClass(csscls('active'));
 763  
 764              this.controls[name].$tab.addClass(csscls('active'));
 765              this.controls[name].$el.addClass(csscls('active'));
 766              this.activePanelName = name;
 767  
 768              this.$el.removeClass(csscls('minimized'));
 769              localStorage.setItem('phpdebugbar-visible', '1');
 770              localStorage.setItem('phpdebugbar-tab', name);
 771              this.resize();
 772          },
 773  
 774          /**
 775           * Hide panels and minimize the debug bar
 776           *
 777           * @this {DebugBar}
 778           */
 779          minimize: function() {
 780              this.$header.find('> div > .' + csscls('active')).removeClass(csscls('active'));
 781              this.$body.hide();
 782              this.$resizehdle.hide();
 783              this.recomputeBottomOffset();
 784              localStorage.setItem('phpdebugbar-visible', '0');
 785              this.$el.addClass(csscls('minimized'));
 786              this.resize();
 787          },
 788  
 789          /**
 790           * Checks if the panel is minimized
 791           *
 792           * @return {Boolean}
 793           */
 794          isMinimized: function() {
 795              return this.$el.hasClass(csscls('minimized'));
 796          },
 797  
 798          /**
 799           * Close the debug bar
 800           *
 801           * @this {DebugBar}
 802           */
 803          close: function() {
 804              this.$resizehdle.hide();
 805              this.$header.hide();
 806              this.$body.hide();
 807              this.$restorebtn.show();
 808              localStorage.setItem('phpdebugbar-open', '0');
 809              this.$el.addClass(csscls('closed'));
 810              this.recomputeBottomOffset();
 811          },
 812  
 813          /**
 814           * Checks if the panel is closed
 815           *
 816           * @return {Boolean}
 817           */
 818          isClosed: function() {
 819              return this.$el.hasClass(csscls('closed'));
 820          },
 821  
 822          /**
 823           * Restore the debug bar
 824           *
 825           * @this {DebugBar}
 826           */
 827          restore: function() {
 828              this.$resizehdle.show();
 829              this.$header.show();
 830              this.$restorebtn.hide();
 831              localStorage.setItem('phpdebugbar-open', '1');
 832              var tab = localStorage.getItem('phpdebugbar-tab');
 833              if (this.isTab(tab)) {
 834                  this.showTab(tab);
 835              } else {
 836                  this.showTab();
 837              }
 838              this.$el.removeClass(csscls('closed'));
 839              this.resize();
 840          },
 841  
 842          /**
 843           * Recomputes the margin-bottom css property of the body so
 844           * that the debug bar never hides any content
 845           */
 846          recomputeBottomOffset: function() {
 847              if (this.options.bodyMarginBottom) {
 848                  if (this.isClosed()) {
 849                      return $('body').css('margin-bottom', this.options.bodyMarginBottomHeight || '');
 850                  }
 851  
 852                  var offset = parseInt(this.$el.height()) + (this.options.bodyMarginBottomHeight || 0);
 853                  $('body').css('margin-bottom', offset);
 854              }
 855          },
 856  
 857          /**
 858           * Sets the data map used by dataChangeHandler to populate
 859           * indicators and widgets
 860           *
 861           * A data map is an object where properties are control names.
 862           * The value of each property should be an array where the first
 863           * item is the name of a property from the data object (nested properties
 864           * can be specified) and the second item the default value.
 865           *
 866           * Example:
 867           *     {"memory": ["memory.peak_usage_str", "0B"]}
 868           *
 869           * @this {DebugBar}
 870           * @param {Object} map
 871           */
 872          setDataMap: function(map) {
 873              this.dataMap = map;
 874          },
 875  
 876          /**
 877           * Same as setDataMap() but appends to the existing map
 878           * rather than replacing it
 879           *
 880           * @this {DebugBar}
 881           * @param {Object} map
 882           */
 883          addDataMap: function(map) {
 884              $.extend(this.dataMap, map);
 885          },
 886  
 887          /**
 888           * Resets datasets and add one set of data
 889           *
 890           * For this method to be usefull, you need to specify
 891           * a dataMap using setDataMap()
 892           *
 893           * @this {DebugBar}
 894           * @param {Object} data
 895           * @return {String} Dataset's id
 896           */
 897          setData: function(data) {
 898              this.datasets = {};
 899              return this.addDataSet(data);
 900          },
 901  
 902          /**
 903           * Adds a dataset
 904           *
 905           * If more than one dataset are added, the dataset selector
 906           * will be displayed.
 907           *
 908           * For this method to be usefull, you need to specify
 909           * a dataMap using setDataMap()
 910           *
 911           * @this {DebugBar}
 912           * @param {Object} data
 913           * @param {String} id The name of this set, optional
 914           * @param {String} suffix
 915           * @param {Bool} show Whether to show the new dataset, optional (default: true)
 916           * @return {String} Dataset's id
 917           */
 918          addDataSet: function(data, id, suffix, show) {
 919              var label = this.datesetTitleFormater.format(id, data, suffix);
 920              id = id || (getObjectSize(this.datasets) + 1);
 921              this.datasets[id] = data;
 922  
 923              this.$datasets.append($('<option value="' + id + '">' + label + '</option>'));
 924              if (this.$datasets.children().length > 1) {
 925                  this.$datasets.show();
 926              }
 927  
 928              if (typeof(show) == 'undefined' || show) {
 929                  this.showDataSet(id);
 930              }
 931              return id;
 932          },
 933  
 934          /**
 935           * Loads a dataset using the open handler
 936           *
 937           * @param {String} id
 938           * @param {Bool} show Whether to show the new dataset, optional (default: true)
 939           */
 940          loadDataSet: function(id, suffix, callback, show) {
 941              if (!this.openHandler) {
 942                  throw new Error('loadDataSet() needs an open handler');
 943              }
 944              var self = this;
 945              this.openHandler.load(id, function(data) {
 946                  self.addDataSet(data, id, suffix, show);
 947                  self.resize();
 948                  callback && callback(data);
 949              });
 950          },
 951  
 952          /**
 953           * Returns the data from a dataset
 954           *
 955           * @this {DebugBar}
 956           * @param {String} id
 957           * @return {Object}
 958           */
 959          getDataSet: function(id) {
 960              return this.datasets[id];
 961          },
 962  
 963          /**
 964           * Switch the currently displayed dataset
 965           *
 966           * @this {DebugBar}
 967           * @param {String} id
 968           */
 969          showDataSet: function(id) {
 970              this.dataChangeHandler(this.datasets[id]);
 971              this.$datasets.val(id);
 972          },
 973  
 974          /**
 975           * Called when the current dataset is modified.
 976           *
 977           * @this {DebugBar}
 978           * @param {Object} data
 979           */
 980          dataChangeHandler: function(data) {
 981              var self = this;
 982              $.each(this.dataMap, function(key, def) {
 983                  var d = getDictValue(data, def[0], def[1]);
 984                  if (key.indexOf(':') != -1) {
 985                      key = key.split(':');
 986                      self.getControl(key[0]).set(key[1], d);
 987                  } else {
 988                      self.getControl(key).set('data', d);
 989                  }
 990              });
 991          },
 992  
 993          /**
 994           * Sets the handler to open past dataset
 995           *
 996           * @this {DebugBar}
 997           * @param {object} handler
 998           */
 999          setOpenHandler: function(handler) {
1000              this.openHandler = handler;
1001              if (handler !== null) {
1002                  this.$openbtn.show();
1003              } else {
1004                  this.$openbtn.hide();
1005              }
1006          },
1007  
1008          /**
1009           * Returns the handler to open past dataset
1010           *
1011           * @this {DebugBar}
1012           * @return {object}
1013           */
1014          getOpenHandler: function() {
1015              return this.openHandler;
1016          }
1017  
1018      });
1019  
1020      DebugBar.Tab = Tab;
1021      DebugBar.Indicator = Indicator;
1022  
1023      // ------------------------------------------------------------------
1024  
1025      /**
1026       * AjaxHandler
1027       *
1028       * Extract data from headers of an XMLHttpRequest and adds a new dataset
1029       *
1030       * @param {Bool} autoShow Whether to immediately show new datasets, optional (default: true)
1031       */
1032      var AjaxHandler = PhpDebugBar.AjaxHandler = function(debugbar, headerName, autoShow) {
1033          this.debugbar = debugbar;
1034          this.headerName = headerName || 'phpdebugbar';
1035          this.autoShow = typeof(autoShow) == 'undefined' ? true : autoShow;
1036      };
1037  
1038      $.extend(AjaxHandler.prototype, {
1039  
1040          /**
1041           * Handles a Fetch API Response or an XMLHttpRequest
1042           *
1043           * @this {AjaxHandler}
1044           * @param {Response|XMLHttpRequest} response
1045           * @return {Bool}
1046           */
1047          handle: function(response) {
1048              // Check if the debugbar header is available
1049              if (this.isFetch(response) && !response.headers.has(this.headerName + '-id')) {
1050                  return true;
1051              } else if (this.isXHR(response) && response.getAllResponseHeaders().indexOf(this.headerName) === -1) {
1052                  return true;
1053              }
1054              if (!this.loadFromId(response)) {
1055                  return this.loadFromData(response);
1056              }
1057              return true;
1058          },
1059  
1060          getHeader: function(response, header) {
1061              if (this.isFetch(response)) {
1062                  return response.headers.get(header)
1063              }
1064  
1065              return response.getResponseHeader(header)
1066          },
1067  
1068          isFetch: function(response) {
1069              return Object.prototype.toString.call(response) == '[object Response]'
1070          },
1071  
1072          isXHR: function(response) {
1073              return Object.prototype.toString.call(response) == '[object XMLHttpRequest]'
1074          },
1075  
1076          /**
1077           * Checks if the HEADER-id exists and loads the dataset using the open handler
1078           *
1079           * @param {Response|XMLHttpRequest} response
1080           * @return {Bool}
1081           */
1082          loadFromId: function(response) {
1083              var id = this.extractIdFromHeaders(response);
1084              if (id && this.debugbar.openHandler) {
1085                  this.debugbar.loadDataSet(id, "(ajax)", undefined, this.autoShow);
1086                  return true;
1087              }
1088              return false;
1089          },
1090  
1091          /**
1092           * Extracts the id from the HEADER-id
1093           *
1094           * @param {Response|XMLHttpRequest} response
1095           * @return {String}
1096           */
1097          extractIdFromHeaders: function(response) {
1098              return this.getHeader(response, this.headerName + '-id');
1099          },
1100  
1101          /**
1102           * Checks if the HEADER exists and loads the dataset
1103           *
1104           * @param {Response|XMLHttpRequest} response
1105           * @return {Bool}
1106           */
1107          loadFromData: function(response) {
1108              var raw = this.extractDataFromHeaders(response);
1109              if (!raw) {
1110                  return false;
1111              }
1112  
1113              var data = this.parseHeaders(raw);
1114              if (data.error) {
1115                  throw new Error('Error loading debugbar data: ' + data.error);
1116              } else if(data.data) {
1117                  this.debugbar.addDataSet(data.data, data.id, "(ajax)", this.autoShow);
1118              }
1119              return true;
1120          },
1121  
1122          /**
1123           * Extract the data as a string from headers of an XMLHttpRequest
1124           *
1125           * @this {AjaxHandler}
1126           * @param {Response|XMLHttpRequest} response
1127           * @return {string}
1128           */
1129          extractDataFromHeaders: function(response) {
1130              var data = this.getHeader(response, this.headerName);
1131              if (!data) {
1132                  return;
1133              }
1134              for (var i = 1;; i++) {
1135                  var header = this.getHeader(response, this.headerName + '-' + i);
1136                  if (!header) {
1137                      break;
1138                  }
1139                  data += header;
1140              }
1141              return decodeURIComponent(data);
1142          },
1143  
1144          /**
1145           * Parses the string data into an object
1146           *
1147           * @this {AjaxHandler}
1148           * @param {string} data
1149           * @return {string}
1150           */
1151          parseHeaders: function(data) {
1152              return JSON.parse(data);
1153          },
1154  
1155          /**
1156           * Attaches an event listener to fetch
1157           *
1158           * @this {AjaxHandler}
1159           */
1160          bindToFetch: function() {
1161              var self = this;
1162              var proxied = window.fetch;
1163  
1164              if (proxied !== undefined && proxied.polyfill !== undefined) {
1165                  return;
1166              }
1167  
1168              window.fetch = function () {
1169                  var promise = proxied.apply(this, arguments);
1170  
1171                  promise.then(function (response) {
1172                      self.handle(response);
1173                  });
1174  
1175                  return promise;
1176              };
1177          },
1178  
1179          /**
1180           * Attaches an event listener to jQuery.ajaxComplete()
1181           *
1182           * @this {AjaxHandler}
1183           * @param {jQuery} jq Optional
1184           */
1185          bindToJquery: function(jq) {
1186              var self = this;
1187              jq(document).ajaxComplete(function(e, xhr, settings) {
1188                  if (!settings.ignoreDebugBarAjaxHandler) {
1189                      self.handle(xhr);
1190                  }
1191              });
1192          },
1193  
1194          /**
1195           * Attaches an event listener to XMLHttpRequest
1196           *
1197           * @this {AjaxHandler}
1198           */
1199          bindToXHR: function() {
1200              var self = this;
1201              var proxied = XMLHttpRequest.prototype.open;
1202              XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
1203                  var xhr = this;
1204                  this.addEventListener("readystatechange", function() {
1205                      var skipUrl = self.debugbar.openHandler ? self.debugbar.openHandler.get('url') : null;
1206                      if (xhr.readyState == 4 && url.indexOf(skipUrl) !== 0) {
1207                          self.handle(xhr);
1208                      }
1209                  }, false);
1210                  proxied.apply(this, Array.prototype.slice.call(arguments));
1211              };
1212          }
1213  
1214      });
1215  
1216  })(PhpDebugBar.$);


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer