mirror of
https://github.com/maximebf/php-debugbar.git
synced 2025-01-16 13:00:42 +01:00
huge refactoring, comments and docs
This commit is contained in:
parent
2d4d840d21
commit
836050cea5
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2013 Maxime Bouroumeau-Fuseau
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
84
README.md
84
README.md
@ -1,3 +1,83 @@
|
||||
# Debug bar for PHP
|
||||
# PHP Debug Bar
|
||||
|
||||
Displays a debug bar in the browser with information from php
|
||||
Displays a debug bar in the browser with information from php.
|
||||
No more `var_dump()` in your code!
|
||||
|
||||
![Screenshot](docs/screenshot.png)
|
||||
|
||||
**Features:**
|
||||
|
||||
- Generic debug bar with no other dependencies
|
||||
- Easy to integrate with any project
|
||||
- Clean, fast and easy to use interface
|
||||
- Handles AJAX request
|
||||
- Includes generic data collectors and collectors for well known libraries
|
||||
- The client side bar is 100% coded in javascript
|
||||
- Easily create your own collectors and their associated view in the bar
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest way to install DebugBar is using [Composer](https://github.com/composer/composer)
|
||||
with the following requirement:
|
||||
|
||||
{
|
||||
"require": {
|
||||
"maximebf/debugbar": ">=1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
Alternatively, you can [download the archive](https://github.com/maximebf/php-debugbar/zipball/master)
|
||||
and add the src/ folder to PHP's include path:
|
||||
|
||||
set_include_path('/path/to/src' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
DebugBar does not provide an autoloader but follows the [PSR-0 convention](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md).
|
||||
You can use the following snippet to autoload ConsoleKit classes:
|
||||
|
||||
spl_autoload_register(function($className) {
|
||||
if (substr($className, 0, 8) === 'DebugBar') {
|
||||
$filename = str_replace('\\', DIRECTORY_SEPARATOR, trim($className, '\\')) . '.php';
|
||||
require_once $filename;
|
||||
}
|
||||
});
|
||||
|
||||
## Quick start
|
||||
|
||||
DebugBar is very easy to use and you can add it to any of your projets in no time.
|
||||
The easiest way is using the `render()` functions
|
||||
|
||||
<?php
|
||||
use DebugBar\StandardDebugBar;
|
||||
use DebugBar\Renderer\JavascriptRenderer;
|
||||
|
||||
$debugbar = new StandardDebugBar();
|
||||
$debugbarRenderer = $debugbar->getJavascriptRenderer();
|
||||
|
||||
$debugbar["messages"]->addMessage("hello world!");
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<?php echo $debugbarRenderer->renderHead() ?>
|
||||
</head>
|
||||
<body>
|
||||
...
|
||||
<?php echo $debugbarRenderer->render() ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
The DebugBar uses DataCollectors to collect data from your PHP code. Some of them are
|
||||
automated but others are manual. Use the `DebugBar` like an array where keys are the
|
||||
collector names. In our previous example, we add a message to the `MessagesCollector`:
|
||||
|
||||
$debugbar["messages"]->addMessage("hello world!");
|
||||
|
||||
`StandardDebugBar` activates all bundled collectors:
|
||||
|
||||
- `MemoryCollector` (*memory*)
|
||||
- `MessagesCollector` (*messages*)
|
||||
- `PhpInfoCollector` (*php*)
|
||||
- `RequestDataCollector` (*request*)
|
||||
- `TimeDataCollector` (*time*)
|
||||
|
||||
Learn more about DebugBar in the [docs](http://maximebf.github.io/php-debugbar).
|
||||
|
19
composer.json
Normal file
19
composer.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "maximebf/debugbar",
|
||||
"description": "Debug bar in the browser for php application",
|
||||
"keywords": ["debug"],
|
||||
"homepage": "https://github.com/maximebf/php-debugbar",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [{
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
}],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"DebugBar": "src/"}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
include '../tests/bootstrap.php';
|
||||
|
||||
use DebugBar\StandardDebugBar;
|
||||
use DebugBar\Renderer\JavascriptRenderer;
|
||||
|
||||
$debugbar = new StandardDebugBar();
|
||||
$debugbarRenderer = new JavascriptRenderer($debugbar, '../web/');
|
||||
$debugbarRenderer = $debugbar->getJavascriptRenderer()->setBaseUrl('../web');
|
||||
|
@ -20,7 +20,7 @@ $debugbar['time']->startMeasure('render');
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<?php echo $debugbarRenderer->renderIncludes() ?>
|
||||
<?php echo $debugbarRenderer->renderHead() ?>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('.ajax').click(function() {
|
||||
@ -39,8 +39,7 @@ $debugbar['time']->startMeasure('render');
|
||||
<p><a href="demo_ajax_exception.php" class="ajax">load ajax content with exception</a></p>
|
||||
<?php
|
||||
usleep(100);
|
||||
$debugbar->collect();
|
||||
echo $debugbarRenderer->renderToolbar();
|
||||
echo $debugbarRenderer->render();
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,6 +6,5 @@ $debugbar['messages']->addMessage('hello from ajax');
|
||||
?>
|
||||
hello from AJAX
|
||||
<?php
|
||||
$debugbar->collect();
|
||||
echo $debugbarRenderer->renderAjaxToolbar();
|
||||
echo $debugbarRenderer->render(false);
|
||||
?>
|
||||
|
@ -11,6 +11,5 @@ try {
|
||||
?>
|
||||
error from AJAX
|
||||
<?php
|
||||
$debugbar->collect();
|
||||
echo $debugbarRenderer->renderAjaxToolbar();
|
||||
echo $debugbarRenderer->render(false);
|
||||
?>
|
||||
|
80
docs/data_collectors.md
Normal file
80
docs/data_collectors.md
Normal file
@ -0,0 +1,80 @@
|
||||
# Collecting Data
|
||||
|
||||
## Using collectors
|
||||
|
||||
Collectors can be added to your debug bar using `addCollector()`.
|
||||
|
||||
$debugbar = new DebugBar();
|
||||
$debugbar->addCollector(new DataCollector\RequestDataCollector());
|
||||
|
||||
Each collector as a unique name as defined by its `getName()` method. You can
|
||||
access collectors using `getCollector($name)`.
|
||||
|
||||
$debugbar->addCollector(new DataCollector\MessagesCollector());
|
||||
$debugbar->getCollector('messages')->addMessage("foobar");
|
||||
// or:
|
||||
$debugbar['messages']->addMessage("foobar");
|
||||
|
||||
Data will be collected from them when the debug bar is rendered. You can however
|
||||
collect the data earlier using `collect()`.
|
||||
|
||||
$debugbar->collect();
|
||||
|
||||
## Creating collectors
|
||||
|
||||
Collectors must implement the `DebugBar\DataCollector\DataCollectorInterface`. They
|
||||
may subclass `DebugBar\DataCollector\DataCollector` which provides utility methods.
|
||||
|
||||
Collectors must provide a `getName()` function returning their unique name and a
|
||||
`collect()` function returning some json-encodable data. The latter will be called at the
|
||||
same time the `DebugBar::collect()` method is called.
|
||||
|
||||
class MyDataCollector extends DebugBar\DataCollector\DataCollector
|
||||
{
|
||||
public function collect()
|
||||
{
|
||||
return array("uniqid" => uniqid());
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'mycollector';
|
||||
}
|
||||
}
|
||||
|
||||
$debugbar->addCollector(new MyDataCollector());
|
||||
|
||||
This however won't show anything in the debug bar as no information are provided
|
||||
on how to display these data. You could do that manually as you'll see in later chapter
|
||||
or implement the `DebugBar\DataSource\Renderable` interface.
|
||||
|
||||
To implement it, you must define a `getWidgets()` function which returns an array
|
||||
of key/value pairs where key are control names and values control options as defined
|
||||
in `JavascriptRenderer::addControl($name, $options)` (see Rendering chapter).
|
||||
|
||||
class MyDataCollector extends DebugBar\DataCollector\DataCollector implements DebugBar\DataCollector\Renderable
|
||||
{
|
||||
// ...
|
||||
|
||||
public function getWidgets()
|
||||
{
|
||||
return array(
|
||||
"mycollector" => array(
|
||||
"icon" => "cogs",
|
||||
"tooltip" => "uniqid()",
|
||||
"map" => "uniqid",
|
||||
"default" => "''"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
This will have the result of adding a new indicator to the debug bar.
|
||||
|
||||
## Included collectors
|
||||
|
||||
- `MemoryCollector` (*memory*)
|
||||
- `MessagesCollector` (*messages*)
|
||||
- `PhpInfoCollector` (*php*)
|
||||
- `RequestDataCollector` (*request*)
|
||||
- `TimeDataCollector` (*time*)
|
120
docs/javascript_bar.md
Normal file
120
docs/javascript_bar.md
Normal file
@ -0,0 +1,120 @@
|
||||
# Javascript Bar
|
||||
|
||||
The default client side implementation of the debug bar is made
|
||||
entirely in Javascript and is located in the *debugbar.js* file.
|
||||
|
||||
It adds a bottom-anchored bar which can have tabs and indicators.
|
||||
The bar can be in an open or close state. When open, the tab panel is
|
||||
visible.
|
||||
An indicator is a piece of information displayed in the always-visible
|
||||
part of the bar.
|
||||
|
||||
The bar handles multiple datasets by displaying a select box
|
||||
which allows you to switch between them.
|
||||
|
||||
The state of the bar (height, visibilty, active panel) can be saved
|
||||
between requests (enabled in the standard bar).
|
||||
|
||||
Each panel is composed of a widget which is used to display the
|
||||
data from a data collector. Some common widgets are provided in
|
||||
the *widgets.js* file.
|
||||
|
||||
The `PhpDebugBar` namespace is used for all objects and the only
|
||||
dependencies are *jQuery*, *jquery-drag* and *FontAwesome* (css).
|
||||
|
||||
The main class is `PhpDebugBar.DebugBar`. It provides the infrastructure
|
||||
to manage tabs, indicators and datasets.
|
||||
|
||||
When initialized, the `DebugBar` class adds itself to the `<body>` of the
|
||||
page. It is empty by default.
|
||||
|
||||
## Tabs and indicators
|
||||
|
||||
Controls (ie. tabs and indicators) are uniquely named. You can check if
|
||||
a control exists using `isControl(name)`.
|
||||
|
||||
Tabs can be added using the `createTab(name, widget, title)` function.
|
||||
The third argument is optional and will be computed from the name if not
|
||||
provided.
|
||||
|
||||
var debugbar = new PhpDebugBar.DebugBar();
|
||||
debugbar.createTab("messages", new PhpDebugBar.Widgets.MessagesWidget());
|
||||
|
||||
Indicators can be added using `createIndicator(name, icon, tooltip, position)`.
|
||||
Only `name` is required in this case. `icon` should be the name of a FontAwesome
|
||||
icon. `position` can either by *right* (default) or *left*.
|
||||
|
||||
debugbar.createIndicator("time", "cogs", "Request duration");
|
||||
|
||||
You may have noticed that the data to use inside these controls is not
|
||||
specified at the moment. Although it could be specified when initialized, it
|
||||
is better to use data mapping to support dynamically changing the data set.
|
||||
|
||||
## Data mapping
|
||||
|
||||
To enable dynamically changing the data sets, we need to specify which values
|
||||
should be feed into which controls. This can be done using `setDataMap(map)`
|
||||
which takes as argument an object where properties are control names. Values
|
||||
should be arrays where the first item is the property from the data set and
|
||||
the second a default value.
|
||||
|
||||
debugbar.setDataMap({
|
||||
"messages": ["messages", []],
|
||||
"time": ["time.duration_str", "0ms"]
|
||||
});
|
||||
|
||||
You can notice that nested properties can also be accessed using the dot
|
||||
notation.
|
||||
|
||||
In this mapping, `data["messages"]` will be fed to the *messages* tab
|
||||
and `data["time"]["duration_str"]` will be fed to the *time* indicator.
|
||||
|
||||
Note: you can append mapping info using `addDataMap(map)`
|
||||
|
||||
## Datasets
|
||||
|
||||
Although you shouldn't have to do anything regarding managing datasets,
|
||||
it is interesting to know a few functions related to them.
|
||||
|
||||
`addDataSet(data, id)` adds a dataset to the bar. The select box that
|
||||
allows to swtich between sets is only displayed if more than one are added.
|
||||
`id` is optional and will be auto-generated if not specified.
|
||||
|
||||
`showDataSet(id)` allows you to switch to a specific dataset.
|
||||
|
||||
## Widgets
|
||||
|
||||
A widget is a javascript object which must contain at least an `element`
|
||||
property. `element`'s value will be appended to the tab panel.
|
||||
|
||||
Widgets should provide a `setData()` function so they can be used with
|
||||
the data mapper.
|
||||
|
||||
var MyWidget = function() {
|
||||
this.element = $('<div class="mywidget" />');
|
||||
};
|
||||
|
||||
MyWidget.prototype.setData = function(text) {
|
||||
this.element.text(text);
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
debugbar.createTab("mytab", new MyWidget());
|
||||
debugbar.addDataMap({"mytab": ["mydata", ""]});
|
||||
|
||||
Widgets for bundled data collectors are included as well as more generic
|
||||
widgets that you can build on top of. They are located in *widgets.js* in
|
||||
the `PhpDebugBar.Widgets` namespace.
|
||||
|
||||
Generic widgets:
|
||||
|
||||
- `ListWidget`: renders an array as a UL list
|
||||
- `KVListWidget`: renders a hash as a DL list
|
||||
- `VariablesListWidget`: an extension of `KVListWidget` to display a list of variables
|
||||
- `IFrameWidget`: renders an iframe
|
||||
|
||||
Data collectors related widgets:
|
||||
|
||||
- `MessagesWidget`: for the `MessagesCollector`
|
||||
- `TimelineWidget`: for the `TimeDataCollector`
|
10
docs/manifest.json
Normal file
10
docs/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"title": "PHP Debug Bar",
|
||||
"home": "../README.md",
|
||||
"files": [
|
||||
"../README.md",
|
||||
"data_collectors.md",
|
||||
"rendering.md",
|
||||
"javascript_bar.md"
|
||||
]
|
||||
}
|
117
docs/rendering.md
Normal file
117
docs/rendering.md
Normal file
@ -0,0 +1,117 @@
|
||||
# Rendering
|
||||
|
||||
Rendering is performed using the `DebugBar\JavascriptRenderer̀ class. It contains
|
||||
all the useful functions to included the needed assets and generate a debug bar.
|
||||
|
||||
$renderer = $debugbar->getJavascriptRenderer();
|
||||
|
||||
## Assets
|
||||
|
||||
The debug bar relies on some css and javascript files which needs to be included
|
||||
into your webpage. This can be done in two ways:
|
||||
|
||||
- Using `JavascriptRenderer::renderHead()` which will returns a string with
|
||||
the needed script and link tags
|
||||
- Using [Assetic](https://github.com/kriswallsmith/assetic) and
|
||||
`JavascriptRenderer::getAsseticCollection()`
|
||||
|
||||
I would recommend using the second method as Assetic is a very powerful asset
|
||||
manager but the first method is provided to quickly integrate the debug bar
|
||||
into any projets.
|
||||
|
||||
You can define the base url of your assets using `setBaseUrl()`. This is needed
|
||||
in 99% of cases. If you are using Assetic, you may have to change the base path
|
||||
of the assets if you moved the folder. This can be done using `setBasePath()`.
|
||||
|
||||
Using `renderHead()`:
|
||||
|
||||
<html>
|
||||
<head>
|
||||
...
|
||||
<?php echo $renderer->renderHead() ?>
|
||||
...
|
||||
</head>
|
||||
...
|
||||
</html>
|
||||
|
||||
Using Assetic:
|
||||
|
||||
list($cssCollection, $jsCollection) = $renderer->getAsseticCollection();
|
||||
|
||||
Note that you can only use the debug bar assets and manage the dependencies by yourself
|
||||
using `$renderer->setIncludeVendors(false)`.
|
||||
|
||||
## The javascript object
|
||||
|
||||
The renderer will generate all the needed code for your debug bar. This means
|
||||
initializing the DebugBar js object, adding tabs and indicators, defining a data map, etc...
|
||||
|
||||
Data collectors can provide their own controls when implementing the
|
||||
`DebugBar\DataCollector\Renderable` interface as explained in the Collecting Data chapter.
|
||||
|
||||
Thus in almost all cases, you should only have to use `render()` right away:
|
||||
|
||||
<html>
|
||||
...
|
||||
<body>
|
||||
<?php echo $renderer->render() ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
This will print the initilization code for the toolbar and the dataset for the request.
|
||||
When you are performing AJAX requests, you do not want to initialize a new toolbar but
|
||||
add the dataset to the existing one. You can disable initialization using ̀false` as
|
||||
the first argument of ̀render()`.
|
||||
|
||||
<p>my ajax content</p>
|
||||
<?php echo $renderer->render(false) ?>
|
||||
|
||||
### Controlling object initialization
|
||||
|
||||
You can further control the initialization of the javascript object using `setInitialization()`.
|
||||
It takes a bitwise value made out of the constants ̀INITIALIZE_CONSTRUCTOR` and `INITIALIZE_CONTROLS`.
|
||||
The first one controls whether to initialize the variable (ie. `var debugbar = new DebugBar()`). The
|
||||
second one whether to initialize all the controls (ie. adding tab and indicators as well as data mapping).
|
||||
|
||||
You can also control the class name of the object using `setJavascriptClass()` and the name of
|
||||
the instance variable using `setVariableName()`.
|
||||
|
||||
Let's say you have subclassed `PhpDebugBar.DebugBar` in javascript to do your own initilization.
|
||||
Your new object is called `MyDebugBar`.
|
||||
|
||||
$renderer->setJavascriptClass("MyDebugBar");
|
||||
$renderer->setInitialization(JavascriptRenderer::INITIALIZE_CONSTRUCTOR);
|
||||
// ...
|
||||
echo $renderer->render();
|
||||
|
||||
This has the result of printing:
|
||||
|
||||
<script type="text/javascript">
|
||||
var phpdebugbar = new MyDebugBar();
|
||||
phpdebugbar.addDataSet({ ... });
|
||||
</script>
|
||||
|
||||
Using `setInitialization(0)` will only render the addDataSet part.
|
||||
|
||||
### Defining controls
|
||||
|
||||
Controls can be manually added to the debug bar using `addControl($name, $options)`. You should read
|
||||
the Javascript bar chapter before this section.
|
||||
|
||||
`$name` will be the name of your control and `$options` is a key/value pair array with these
|
||||
possible values:
|
||||
|
||||
- *icon*: icon name
|
||||
- *tooltip*: string
|
||||
- *widget*: widget class name
|
||||
- *map*: a property name from the data to map the control to
|
||||
- *default*: a js string, default value of the data map
|
||||
|
||||
At least *icon* or *widget* are needed. If *widget* is specified, a tab will be created, otherwise
|
||||
an indicator.
|
||||
|
||||
$renderer->addControl('messages', array(
|
||||
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
|
||||
"map" => "messages",
|
||||
"default" => "[]"
|
||||
));
|
BIN
docs/screenshot.png
Normal file
BIN
docs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -1,9 +1,26 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
/**
|
||||
* Abstract class for data collectors
|
||||
*/
|
||||
abstract class DataCollector implements DataCollectorInterface
|
||||
{
|
||||
/**
|
||||
* Transforms a PHP variable to a string representation
|
||||
*
|
||||
* @param mixed $var
|
||||
* @return string
|
||||
*/
|
||||
public function varToString($var)
|
||||
{
|
||||
return print_r($var, true);
|
||||
|
@ -1,10 +1,31 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
/**
|
||||
* DataCollector Interface
|
||||
*/
|
||||
interface DataCollectorInterface
|
||||
{
|
||||
function getName();
|
||||
|
||||
/**
|
||||
* Called by the DebugBar when data needs to be collected
|
||||
*
|
||||
* @return array Collected data
|
||||
*/
|
||||
function collect();
|
||||
|
||||
/**
|
||||
* Returns the unique name of the collector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getName();
|
||||
}
|
||||
|
@ -1,16 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
class DependencyCollector extends DataCollector
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'dependency';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'dependency';
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
class MemoryCollector extends DataCollector
|
||||
/**
|
||||
* Collects info about memory usage
|
||||
*/
|
||||
class MemoryCollector extends DataCollector implements Renderable
|
||||
{
|
||||
protected $peakUsage = 0;
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'memory';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the peak memory usage
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getPeakUsage()
|
||||
{
|
||||
return $this->peakUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the peak memory usage value
|
||||
*/
|
||||
public function updatePeakUsage()
|
||||
{
|
||||
$this->peakUsage = memory_get_peak_usage(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in bytes to a human readable string
|
||||
*
|
||||
* @param string $size
|
||||
* @param integer $precision
|
||||
* @return string
|
||||
*/
|
||||
public function toReadableString($size, $precision = 2)
|
||||
{
|
||||
$base = log($size) / log(1024);
|
||||
@ -28,6 +49,9 @@ class MemoryCollector extends DataCollector
|
||||
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$this->updatePeakUsage();
|
||||
@ -36,4 +60,27 @@ class MemoryCollector extends DataCollector
|
||||
'peak_usage_str' => $this->toReadableString($this->peakUsage)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'memory';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
return array(
|
||||
"memory" => array(
|
||||
"icon" => "cogs",
|
||||
"tooltip" => "Memory Usage",
|
||||
"map" => "peak_usage_str",
|
||||
"default" => "'0B'"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
class MessagesCollector extends DataCollector
|
||||
/**
|
||||
* Provides a way to log messages
|
||||
*/
|
||||
class MessagesCollector extends DataCollector implements Renderable
|
||||
{
|
||||
protected $messages = array();
|
||||
|
||||
/**
|
||||
* Adds a message
|
||||
*
|
||||
* A message can be anything from an object to a string
|
||||
*
|
||||
* @param mixed $message
|
||||
* @param string $label
|
||||
*/
|
||||
public function addMessage($message, $label = 'info')
|
||||
{
|
||||
$this->messages[] = array(
|
||||
@ -18,18 +37,43 @@ class MessagesCollector extends DataCollector
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all messages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessages()
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'messages';
|
||||
}
|
||||
|
||||
public function collect()
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
return $this->messages;
|
||||
return array(
|
||||
"messages" => array(
|
||||
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
|
||||
"map" => "messages",
|
||||
"default" => "[]"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
/**
|
||||
* Collects info about PHP
|
||||
*/
|
||||
class PhpInfoCollector extends DataCollector
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
return array(
|
||||
'version' => PHP_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
}
|
||||
|
25
src/DebugBar/DataCollector/Renderable.php
Normal file
25
src/DebugBar/DataCollector/Renderable.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
/**
|
||||
* Indicates that a DataCollector is renderable using JavascriptRenderer
|
||||
*/
|
||||
interface Renderable
|
||||
{
|
||||
/**
|
||||
* Returns a hash where keys are control names and their values
|
||||
* an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getWidgets();
|
||||
}
|
@ -1,14 +1,23 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
class RequestDataCollector extends DataCollector
|
||||
/**
|
||||
* Collects info about the current request
|
||||
*/
|
||||
class RequestDataCollector extends DataCollector implements Renderable
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'request';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$vars = array('_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER');
|
||||
@ -22,4 +31,26 @@ class RequestDataCollector extends DataCollector
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'request';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
return array(
|
||||
"request" => array(
|
||||
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
|
||||
"map" => "request",
|
||||
"default" => "{}"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\DataCollector;
|
||||
|
||||
class TimeCollector extends DataCollector
|
||||
/**
|
||||
* Collects info about the request duration as well as providing
|
||||
* a way to log duration of any operations
|
||||
*/
|
||||
class TimeDataCollector extends DataCollector implements Renderable
|
||||
{
|
||||
|
||||
protected $requestStartTime;
|
||||
|
||||
protected $requestEndTime;
|
||||
|
||||
protected $measures = array();
|
||||
|
||||
/**
|
||||
* @param float $requestStartTime
|
||||
*/
|
||||
public function __construct($requestStartTime = null)
|
||||
{
|
||||
if ($requestStartTime === null) {
|
||||
@ -23,6 +37,12 @@ class TimeCollector extends DataCollector
|
||||
$this->requestStartTime = $requestStartTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a measure
|
||||
*
|
||||
* @param string $name Internal name, used to stop the measure
|
||||
* @param string $label Public name
|
||||
*/
|
||||
public function startMeasure($name, $label = null)
|
||||
{
|
||||
$start = microtime(true);
|
||||
@ -33,6 +53,11 @@ class TimeCollector extends DataCollector
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a measure
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function stopMeasure($name)
|
||||
{
|
||||
$end = microtime(true);
|
||||
@ -42,16 +67,54 @@ class TimeCollector extends DataCollector
|
||||
$this->measures[$name]['duration_str'] = $this->toReadableString($this->measures[$name]['duration']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to measure the execution of a Closure
|
||||
*
|
||||
* @param Closure $closure
|
||||
*/
|
||||
public function measure(\Closure $closure)
|
||||
{
|
||||
$name = spl_object_hash($closure);
|
||||
$this->startMeasure($name, $closure);
|
||||
$closure();
|
||||
$this->stopMeasure($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all measures
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMeasures()
|
||||
{
|
||||
return $this->measures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request start time
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getRequestStartTime()
|
||||
{
|
||||
return $this->requestStartTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request end time
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getRequestEndTime()
|
||||
{
|
||||
return $this->requestEndTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of a request
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getRequestDuration()
|
||||
{
|
||||
if ($this->requestEndTime !== null) {
|
||||
@ -60,21 +123,20 @@ class TimeCollector extends DataCollector
|
||||
return microtime(true) - $this->requestStartTime;
|
||||
}
|
||||
|
||||
public function getMeasures()
|
||||
{
|
||||
return $this->measures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a duration in seconds in a readable string
|
||||
*
|
||||
* @param float $value
|
||||
* @return string
|
||||
*/
|
||||
public function toReadableString($value)
|
||||
{
|
||||
return round($value / 1000) . 'ms';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'time';
|
||||
return round($value * 1000) . 'ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$this->requestEndTime = microtime(true);
|
||||
@ -92,4 +154,32 @@ class TimeCollector extends DataCollector
|
||||
'measures' => array_values($this->measures)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'time';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
return array(
|
||||
"time" => array(
|
||||
"icon" => "time",
|
||||
"tooltip" => "Request Duration",
|
||||
"map" => "time.duration_str",
|
||||
"default" => "'0ms'"
|
||||
),
|
||||
"timeline" => array(
|
||||
"widget" => "PhpDebugBar.Widgets.TimelineWidget",
|
||||
"map" => "time",
|
||||
"default" => "{}"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,28 +1,69 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar;
|
||||
|
||||
use ArrayAccess;
|
||||
use DebugBar\DataCollector\DataCollector;
|
||||
use DebugBar\Renderer\Renderer;
|
||||
use DebugBar\Renderer\JavascriptRenderer;
|
||||
|
||||
/**
|
||||
* Main DebugBar object
|
||||
*
|
||||
* Mananges data collectors. DebugBar provides an array-like access
|
||||
* to collectors by name.
|
||||
*
|
||||
* <code>
|
||||
* $debugbar = new DebugBar();
|
||||
* $debugbar->addCollector(new DataCollector\MessagesCollector());
|
||||
* $debugbar['messages']->addMessage("foobar");
|
||||
* </code>
|
||||
*/
|
||||
class DebugBar implements ArrayAccess
|
||||
{
|
||||
protected $collectors = array();
|
||||
|
||||
protected $data;
|
||||
|
||||
protected $jsRenderer;
|
||||
|
||||
/**
|
||||
* Adds a data collector
|
||||
*
|
||||
* @param DataCollector $collector
|
||||
*/
|
||||
public function addCollector(DataCollector $collector)
|
||||
{
|
||||
if (isset($this->collectors[$collector->getName()])) {
|
||||
throw new DebugBarException("'$name' is already a registered collector");
|
||||
}
|
||||
$this->collectors[$collector->getName()] = $collector;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a data collector has been added
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasCollector($name)
|
||||
{
|
||||
return isset($this->collectors[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data collector
|
||||
*
|
||||
* @param string $name
|
||||
* @return DataCollector
|
||||
*/
|
||||
public function getCollector($name)
|
||||
{
|
||||
if (!isset($this->collectors[$name])) {
|
||||
@ -31,11 +72,61 @@ class DebugBar implements ArrayAccess
|
||||
return $this->collectors[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all data collectors
|
||||
*
|
||||
* @return array[DataCollector]
|
||||
*/
|
||||
public function getCollectors()
|
||||
{
|
||||
return $this->collectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data from the collectors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$this->data = array();
|
||||
foreach ($this->collectors as $name => $collector) {
|
||||
$this->data[$name] = $collector->collect();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns collected data
|
||||
*
|
||||
* Will collect the data if none have been collected yet
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
if ($this->data === null) {
|
||||
$this->collect();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JavascriptRenderer for this instance
|
||||
*
|
||||
* @return JavascriptRenderer
|
||||
*/
|
||||
public function getJavascriptRenderer()
|
||||
{
|
||||
if ($this->jsRenderer === null) {
|
||||
$this->jsRenderer = new JavascriptRenderer($this);
|
||||
}
|
||||
return $this->jsRenderer;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
// ArrayAccess implementation
|
||||
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw new DebugBarException("DebugBar[] is read-only");
|
||||
@ -55,18 +146,4 @@ class DebugBar implements ArrayAccess
|
||||
{
|
||||
throw new DebugBarException("DebugBar[] is read-only");
|
||||
}
|
||||
|
||||
public function collect()
|
||||
{
|
||||
$this->data = array();
|
||||
foreach ($this->collectors as $name => $collector) {
|
||||
$this->data[$name] = $collector->collect();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar;
|
||||
|
||||
|
407
src/DebugBar/JavascriptRenderer.php
Normal file
407
src/DebugBar/JavascriptRenderer.php
Normal file
@ -0,0 +1,407 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar;
|
||||
|
||||
use DebugBar\DataCollector\Renderable;
|
||||
|
||||
/**
|
||||
* Renders the debug bar using the client side javascript implementation
|
||||
*
|
||||
* Generates all the needed initialization code of controls
|
||||
*/
|
||||
class JavascriptRenderer
|
||||
{
|
||||
const INITIALIZE_CONSTRUCTOR = 2;
|
||||
|
||||
const INITIALIZE_CONTROLS = 4;
|
||||
|
||||
protected $debugBar;
|
||||
|
||||
protected $baseUrl;
|
||||
|
||||
protected $basePath;
|
||||
|
||||
protected $cssVendors = array('vendor/font-awesome/css/font-awesome.css');
|
||||
|
||||
protected $jsVendors = array('vendor/jquery-1.8.3.min.js', 'vendor/jquery.event.drag-2.2.js');
|
||||
|
||||
protected $includeVendors = true;
|
||||
|
||||
protected $cssFiles = array('debugbar.css');
|
||||
|
||||
protected $jsFiles = array('debugbar.js', 'widgets.js');
|
||||
|
||||
protected $javascriptClass = 'PhpDebugBar.DebugBar';
|
||||
|
||||
protected $variableName = 'phpdebugbar';
|
||||
|
||||
protected $initialization;
|
||||
|
||||
protected $controls = array();
|
||||
|
||||
/**
|
||||
* @param DebugBar $debugBar
|
||||
* @param string $baseUrl
|
||||
* @param string $basePath
|
||||
*/
|
||||
public function __construct(DebugBar $debugBar, $baseUrl = '/debugbar', $basePath = null)
|
||||
{
|
||||
$this->debugBar = $debugBar;
|
||||
$this->baseUrl = $baseUrl;
|
||||
|
||||
if ($basePath === null) {
|
||||
$basePath = __DIR__ . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array('..', '..', '..', 'web'));
|
||||
}
|
||||
$this->basePath = $basePath;
|
||||
|
||||
// bitwise operations cannot be done in class definition :(
|
||||
$this->initialization = self::INITIALIZE_CONSTRUCTOR | self::INITIALIZE_CONTROLS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path which assets are relative to
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function setBasePath($path)
|
||||
{
|
||||
$this->basePath = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path which assets are relative to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBasePath()
|
||||
{
|
||||
return $this->basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base URL from which assets will be served
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
public function setBaseUrl($url)
|
||||
{
|
||||
$this->baseUrl = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base URL from which assets will be served
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseUrl()
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to include vendor assets
|
||||
*
|
||||
* @param boolean $enabled
|
||||
*/
|
||||
public function setIncludeVendors($enabled = true)
|
||||
{
|
||||
$this->includeVendors = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if vendors assets are included
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function areVendorsIncluded()
|
||||
{
|
||||
return $this->includeVendors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the javascript class name
|
||||
*
|
||||
* @param string $className
|
||||
*/
|
||||
public function setJavascriptClass($className)
|
||||
{
|
||||
$this->javascriptClass = $className;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the javascript class name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getJavascriptClass()
|
||||
{
|
||||
return $this->javascriptClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable name of the class instance
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setVariableName($name)
|
||||
{
|
||||
$this->variableName = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable name of the class instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVariableName()
|
||||
{
|
||||
return $this->variableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets what should be initialized
|
||||
*
|
||||
* - INITIALIZE_CONSTRUCTOR: only initializes the instance
|
||||
* - INITIALIZE_CONTROLS: initializes the controls and data mapping
|
||||
* - INITIALIZE_CONSTRUCTOR | INITIALIZE_CONTROLS: initialize everything (default)
|
||||
*
|
||||
* @param integer $init
|
||||
*/
|
||||
public function setInitialization($init)
|
||||
{
|
||||
$this->initialization = $init;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns what should be initialized
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getInitialization()
|
||||
{
|
||||
return $this->initialization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a control to initialize
|
||||
*
|
||||
* Possible options:
|
||||
* - icon: icon name
|
||||
* - tooltip: string
|
||||
* - widget: widget class name
|
||||
* - map: a property name from the data to map the control to
|
||||
* - default: a js string, default value of the data map
|
||||
*
|
||||
* "icon" or "widget" are at least needed
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $options
|
||||
*/
|
||||
public function addControl($name, $options)
|
||||
{
|
||||
if (!isset($options['icon']) || !isset($options['widget'])) {
|
||||
throw new DebugBarException("Missing 'icon' or 'widget' option for control '$name'");
|
||||
}
|
||||
$this->controls[$name] = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of asset files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAssetFiles()
|
||||
{
|
||||
$cssFiles = $this->cssFiles;
|
||||
$jsFiles = $this->jsFiles;
|
||||
|
||||
if ($this->includeVendors) {
|
||||
$cssFiles = array_merge($this->cssVendors, $cssFiles);
|
||||
$jsFiles = array_merge($this->jsVendors, $jsFiles);
|
||||
}
|
||||
|
||||
return array($cssFiles, $jsFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tuple where the both items are Assetic AssetCollection,
|
||||
* the first one being css files and the second js files
|
||||
*
|
||||
* @return array or \Assetic\Asset\AssetCollection
|
||||
*/
|
||||
public function getAsseticCollection()
|
||||
{
|
||||
list($cssFiles, $jsFiles) = $this->getAssetFiles();
|
||||
return array(
|
||||
$this->createAsseticCollection($cssFiles),
|
||||
$this->createAsseticCollection($jsFiles)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Assetic AssetCollection with the given files.
|
||||
* Filenames will be converted to absolute path using
|
||||
* the base path.
|
||||
*
|
||||
* @param array $files
|
||||
* @return \Assetic\Asset\AssetCollection
|
||||
*/
|
||||
protected function createAsseticCollection($files)
|
||||
{
|
||||
$assets = array();
|
||||
foreach ($files as $file) {
|
||||
$assets[] = new \Assetic\Asset\FileAsset($this->makeUriRelativeTo($file, $this->basePath));
|
||||
}
|
||||
return new \Assetic\Asset\AssetCollection($assets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the html to include needed assets
|
||||
*
|
||||
* Only useful if Assetic is not used
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renderHead()
|
||||
{
|
||||
list($cssFiles, $jsFiles) = $this->getAssetFiles();
|
||||
$html = '';
|
||||
|
||||
foreach ($cssFiles as $file) {
|
||||
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n",
|
||||
$this->makeUriRelativeTo($file, $this->baseUrl));
|
||||
}
|
||||
|
||||
foreach ($jsFiles as $file) {
|
||||
$html .= sprintf('<script type"text/javascript" src="%s"></script>' . "\n",
|
||||
$this->makeUriRelativeTo($file, $this->baseUrl));
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a URI relative to another
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $root
|
||||
* @return string
|
||||
*/
|
||||
protected function makeUriRelativeTo($uri, $root)
|
||||
{
|
||||
if (substr($uri, 0, 1) === '/' || preg_match('/^([a-z]+:\/\/|[a-zA-Z]:\/)/', $uri)) {
|
||||
return $uri;
|
||||
}
|
||||
return rtrim($root, '/') . "/$uri";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code needed to display the debug bar
|
||||
*
|
||||
* AJAX request should not render the initialization code.
|
||||
*
|
||||
* @param boolean $initialize Whether to render the de bug bar initialization code
|
||||
* @return string
|
||||
*/
|
||||
public function render($initialize = true)
|
||||
{
|
||||
$js = '';
|
||||
|
||||
if ($initialize) {
|
||||
$js = $this->getJsInitializationCode();
|
||||
}
|
||||
|
||||
$js .= sprintf("%s.addDataSet(%s);\n", $this->variableName, json_encode($this->debugBar->getData()));
|
||||
return "<script type=\"text/javascript\">\n$js\n</script>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the js code needed to initialize the debug bar
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getJsInitializationCode()
|
||||
{
|
||||
$js = '';
|
||||
|
||||
if (($this->initialization & self::INITIALIZE_CONSTRUCTOR) === self::INITIALIZE_CONSTRUCTOR) {
|
||||
$js = sprintf("var %s = new %s();\n", $this->variableName, $this->javascriptClass);
|
||||
}
|
||||
|
||||
if (($this->initialization & self::INITIALIZE_CONTROLS) === self::INITIALIZE_CONTROLS) {
|
||||
$js .= $this->getJsControlsDefinitionCode($this->variableName);
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the js code needed to initialized the controls and data mapping of the debug bar
|
||||
*
|
||||
* Controls can be defined by collectors themselves or using {@see addControl()}
|
||||
*
|
||||
* @param string $varname Debug bar's variable name
|
||||
* @return string
|
||||
*/
|
||||
protected function getJsControlsDefinitionCode($varname)
|
||||
{
|
||||
$js = '';
|
||||
$dataMap = array();
|
||||
$controls = $this->controls;
|
||||
|
||||
// finds controls provided by collectors
|
||||
foreach ($this->debugBar->getCollectors() as $collector) {
|
||||
if ($collector instanceof Renderable) {
|
||||
$controls = array_merge($controls, $collector->getWidgets());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($controls as $name => $options) {
|
||||
if (isset($options['widget'])) {
|
||||
$js .= sprintf("%s.createTab(\"%s\", new %s());\n",
|
||||
$varname,
|
||||
$name,
|
||||
$options['widget']
|
||||
);
|
||||
} else {
|
||||
$js .= sprintf("%s.createIndicator(\"%s\", \"%s\", \"%s\");\n",
|
||||
$varname,
|
||||
$name,
|
||||
isset($options['icon']) ? $options['icon'] : 'null',
|
||||
isset($options['tooltip']) ? $options['tooltip'] : 'null'
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($options['map']) && isset($options['default'])) {
|
||||
$dataMap[$name] = array($options['map'], $options['default']);
|
||||
}
|
||||
}
|
||||
|
||||
// creates the data mapping object
|
||||
$mapJson = array();
|
||||
foreach ($dataMap as $name => $values) {
|
||||
$mapJson[] = sprintf('"%s": ["%s", %s]', $name, $values[0], $values[1]);
|
||||
}
|
||||
$js .= sprintf("%s.setDataMap({\n%s\n});\n", $varname, implode(",\n", $mapJson));
|
||||
|
||||
// activate state restauration
|
||||
$js .= sprintf("%s.restoreState();\n", $varname);
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DebugBar\Renderer;
|
||||
|
||||
use DebugBar\DebugBar;
|
||||
|
||||
class JavascriptRenderer
|
||||
{
|
||||
protected $baseUrl = '/';
|
||||
|
||||
protected $cssVendors = array('vendor/font-awesome/css/font-awesome.css');
|
||||
|
||||
protected $jsVendors = array('vendor/jquery-1.8.3.min.js', 'vendor/jquery.event.drag-2.2.js');
|
||||
|
||||
protected $cssFiles = array('debugbar.css');
|
||||
|
||||
protected $jsFiles = array('debugbar.js', 'widgets.js');
|
||||
|
||||
protected $includeVendors = true;
|
||||
|
||||
protected $includeFiles = true;
|
||||
|
||||
protected $toolbarFile = 'standard-debugbar.js';
|
||||
|
||||
protected $toolbarClass = 'StandardPhpDebugBar';
|
||||
|
||||
protected $toolbarVariableName = 'phpdebugbar';
|
||||
|
||||
/**
|
||||
* @param \DebugBar\DebugBar $debugBar
|
||||
* @param string $baseUrl
|
||||
*
|
||||
* @Inject(debugBar="debugBar", baseUrl="$[debugBarRenderer][baseUrl]")
|
||||
*/
|
||||
public function __construct(DebugBar $debugBar, $baseUrl = '/')
|
||||
{
|
||||
$this->debugBar = $debugBar;
|
||||
$this->setBaseUrl($baseUrl);
|
||||
}
|
||||
|
||||
public function setBaseUrl($url)
|
||||
{
|
||||
$this->baseUrl = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBaseUrl()
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
public function setIncludeVendors($enabled = true)
|
||||
{
|
||||
$this->includeVendors = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function areVendorsIncluded()
|
||||
{
|
||||
return $this->includeVendors;
|
||||
}
|
||||
|
||||
public function setIncludeFiles($enabled = true)
|
||||
{
|
||||
$this->includeFiles = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function areFilesIncluded()
|
||||
{
|
||||
return $this->includeFiles;
|
||||
}
|
||||
|
||||
public function setToolbarFile($file)
|
||||
{
|
||||
$this->toolbarFile = $file;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getToolbarFile()
|
||||
{
|
||||
return $this->toolbarFile;
|
||||
}
|
||||
|
||||
public function setToolbarClass($className)
|
||||
{
|
||||
$this->toolbarClass = $className;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getToolbarClass()
|
||||
{
|
||||
return $this->toolbarClass;
|
||||
}
|
||||
|
||||
public function setToolbarVariableName($name)
|
||||
{
|
||||
$this->toolbarVariableName = $name;
|
||||
}
|
||||
|
||||
public function getToolbarVariableName()
|
||||
{
|
||||
return $this->toolbarVariableName;
|
||||
}
|
||||
|
||||
public function renderIncludes()
|
||||
{
|
||||
$cssFiles = array();
|
||||
$jsFiles = array();
|
||||
|
||||
if ($this->includeVendors) {
|
||||
$cssFiles = array_merge($cssFiles, $this->cssVendors);
|
||||
$jsFiles = array_merge($jsFiles, $this->jsVendors);
|
||||
}
|
||||
|
||||
if ($this->includeFiles) {
|
||||
$cssFiles = array_merge($cssFiles, $this->cssFiles);
|
||||
$jsFiles = array_merge($jsFiles, $this->jsFiles);
|
||||
}
|
||||
|
||||
$jsFiles[] = $this->toolbarFile;
|
||||
|
||||
$html = '';
|
||||
foreach ($cssFiles as $file) {
|
||||
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n",
|
||||
$this->makeUrlRelativeTo($file, $this->baseUrl));
|
||||
}
|
||||
foreach ($jsFiles as $file) {
|
||||
$html .= sprintf('<script type"text/javascript" src="%s"></script>' . "\n",
|
||||
$this->makeUrlRelativeTo($file, $this->baseUrl));
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function renderToolbar()
|
||||
{
|
||||
return sprintf('<script type="text/javascript">var %s = new %s(%s);</script>' . "\n",
|
||||
$this->toolbarVariableName, $this->toolbarClass, json_encode($this->debugBar->getData()));
|
||||
}
|
||||
|
||||
public function renderAjaxToolbar()
|
||||
{
|
||||
return sprintf('<script type="text/javascript">%s.addDataStack(%s);</script>' . "\n",
|
||||
$this->toolbarVariableName, json_encode($this->debugBar->getData()));
|
||||
}
|
||||
|
||||
public function renderAll()
|
||||
{
|
||||
return $this->renderIncludes() . $this->renderToolbar();
|
||||
}
|
||||
|
||||
protected function makeUrlRelativeTo($url, $root)
|
||||
{
|
||||
if (substr($url, 0, 1) === '/' || preg_match('/^[a-z]+:\/\//', $url)) {
|
||||
return $url;
|
||||
}
|
||||
return rtrim($root, '/') . "/$url";
|
||||
}
|
||||
}
|
@ -1,21 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar;
|
||||
|
||||
use DebugBar\DataCollector\PhpInfoCollector;
|
||||
use DebugBar\DataCollector\MessagesCollector;
|
||||
use DebugBar\DataCollector\TimeCollector;
|
||||
use DebugBar\DataCollector\TimeDataCollector;
|
||||
use DebugBar\DataCollector\RequestDataCollector;
|
||||
use DebugBar\DataCollector\MemoryCollector;
|
||||
|
||||
/**
|
||||
* Debug bar subclass which adds all included collectors
|
||||
*/
|
||||
class StandardDebugBar extends DebugBar
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->addCollector(new PhpInfoCollector());
|
||||
$this->addCollector(new MessagesCollector());
|
||||
$this->addCollector(new TimeCollector());
|
||||
$this->addCollector(new RequestDataCollector());
|
||||
$this->addCollector(new TimeDataCollector());
|
||||
$this->addCollector(new MemoryCollector());
|
||||
}
|
||||
}
|
||||
|
8
tests/DebugBar/Tests/DebugBarTestCase.php
Normal file
8
tests/DebugBar/Tests/DebugBarTestCase.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace DebugBar\Tests;
|
||||
|
||||
abstract class DebugBarTestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
}
|
338
web/debugbar.css
338
web/debugbar.css
@ -1,27 +1,27 @@
|
||||
.phpdebugbar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #ccc;
|
||||
font-family: arial;
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #ccc;
|
||||
font-family: arial;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-header {
|
||||
background: #efefef url(php-icon.png) no-repeat 5px 4px;
|
||||
padding-left: 29px;
|
||||
min-height: 26px;
|
||||
background: #efefef url(php-icon.png) no-repeat 5px 4px;
|
||||
padding-left: 29px;
|
||||
min-height: 26px;
|
||||
}
|
||||
.phpdebugbar-header:before, .phpdebugbar-header:after {
|
||||
display: table;
|
||||
line-height: 0;
|
||||
content: "";
|
||||
display: table;
|
||||
line-height: 0;
|
||||
content: "";
|
||||
}
|
||||
.phpdebugbar-header:after {
|
||||
clear: both;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
@ -29,79 +29,70 @@
|
||||
.phpdebugbar-tab,
|
||||
.phpdebugbar-indicator,
|
||||
.phpdebugbar-close-btn {
|
||||
float: left;
|
||||
padding: 5px 8px;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
float: left;
|
||||
padding: 5px 8px;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
}
|
||||
.phpdebugbar-indicator,
|
||||
.phpdebugbar-close-btn {
|
||||
float: right;
|
||||
border-right: 1px solid #ddd;
|
||||
float: right;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.phpdebugbar-tab.active {
|
||||
background: #ccc;
|
||||
color: #444;
|
||||
background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
|
||||
background-image: -webkit-gradient(
|
||||
linear,
|
||||
left bottom,
|
||||
left top,
|
||||
color-stop(0.41, rgb(173,173,173)),
|
||||
color-stop(0.71, rgb(209,209,209))
|
||||
);
|
||||
background: #ccc;
|
||||
color: #444;
|
||||
background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.41, rgb(173,173,173)), color-stop(0.71, rgb(209,209,209)));
|
||||
}
|
||||
|
||||
.phpdebugbar-close-btn {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.phpdebugbar-indicator {
|
||||
position: relative;
|
||||
position: relative;
|
||||
}
|
||||
.phpdebugbar-indicator .text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.phpdebugbar-indicator .tooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
background: #efefef;
|
||||
opacity: .7;
|
||||
border: 1px solid #ccc;
|
||||
color: #555;
|
||||
font-size: 11px;
|
||||
padding: 2px 3px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.phpdebugbar-indicator:hover .tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.phpdebugbar-data-stacks {
|
||||
float: right;
|
||||
.phpdebugbar-indicator .text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.phpdebugbar-indicator .tooltip {
|
||||
display: none;
|
||||
margin: 2px 0 0 7px;
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
background: #efefef;
|
||||
opacity: .7;
|
||||
border: 1px solid #ccc;
|
||||
color: #555;
|
||||
font-size: 11px;
|
||||
padding: 2px 3px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.phpdebugbar-indicator:hover .tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.phpdebugbar-datasets-switcher {
|
||||
float: right;
|
||||
display: none;
|
||||
margin: 2px 0 0 7px;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-body {
|
||||
border-top: 1px solid #ccc;
|
||||
display: none;
|
||||
position: relative;
|
||||
height: 300px;
|
||||
border-top: 1px solid #ccc;
|
||||
display: none;
|
||||
position: relative;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.phpdebugbar-resize-handle {
|
||||
.phpdebugbar-resize-handle {
|
||||
display: none;
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
@ -110,148 +101,151 @@
|
||||
cursor: move;
|
||||
position: absolute;
|
||||
top: -33px;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-panel {
|
||||
display: none;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
display: none;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.phpdebugbar-panel.active {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-widgets-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-family: monospace;
|
||||
}
|
||||
.phpdebugbar-widgets-list .list-item {
|
||||
padding: 3px 6px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.phpdebugbar-widgets-list .list-item:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
.phpdebugbar-widgets-list .list-item {
|
||||
padding: 3px 6px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.phpdebugbar-widgets-list .list-item:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-widgets-messages {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .value.warn:before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f071";
|
||||
margin-right: 8px;
|
||||
font-size: 11px;
|
||||
color: #ecb03d;
|
||||
.phpdebugbar-widgets-messages .list-item .value.warn:before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f071";
|
||||
margin-right: 8px;
|
||||
font-size: 11px;
|
||||
color: #ecb03d;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .value.error {
|
||||
color: red;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .value.error:before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f057";
|
||||
margin-right: 8px;
|
||||
font-size: 11px;
|
||||
color: red;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .backtrace,
|
||||
.phpdebugbar-widgets-messages .list-item .label {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
color: #888;
|
||||
margin: 0 2px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar input {
|
||||
border: 0;
|
||||
margin-left: 7px;
|
||||
width: 50%;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .value.error {
|
||||
color: red;
|
||||
.phpdebugbar-widgets-messages .toolbar input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .value.error:before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f057";
|
||||
margin-right: 8px;
|
||||
font-size: 11px;
|
||||
color: red;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .list-item .backtrace,
|
||||
.phpdebugbar-widgets-messages .list-item .label {
|
||||
.phpdebugbar-widgets-messages .toolbar .filter {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
color: #888;
|
||||
background: #7cacd5;
|
||||
margin: 0 2px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar input {
|
||||
border: 0;
|
||||
margin-left: 7px;
|
||||
width: 50%;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar .filter {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
background: #7cacd5;
|
||||
margin: 0 2px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar .filter.disabled {
|
||||
background: #eee;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
.phpdebugbar-widgets-messages .toolbar .filter.disabled {
|
||||
background: #eee;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-widgets-kvlist {
|
||||
margin: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.phpdebugbar-widgets-kvlist dt {
|
||||
float: left;
|
||||
width: 140px;
|
||||
padding: 5px;
|
||||
border-top: 1px solid #eee;
|
||||
font-weight: bold;
|
||||
clear: both;
|
||||
}
|
||||
.phpdebugbar-widgets-kvlist dd {
|
||||
margin-left: 150px;
|
||||
padding: 5px;
|
||||
border-top: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
.phpdebugbar-widgets-kvlist dt {
|
||||
float: left;
|
||||
width: 140px;
|
||||
padding: 5px;
|
||||
border-top: 1px solid #eee;
|
||||
font-weight: bold;
|
||||
clear: both;
|
||||
}
|
||||
.phpdebugbar-widgets-kvlist dd {
|
||||
margin-left: 150px;
|
||||
padding: 5px;
|
||||
border-top: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-widgets-varlist {
|
||||
font-family: monospace;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
.phpdebugbar-widgets-timeline {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li {
|
||||
height: 20px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
.phpdebugbar-widgets-timeline li {
|
||||
height: 20px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li .label {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
color: #555;
|
||||
top: 4px;
|
||||
left: 5px;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li .value {
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
background: #3db9ec;
|
||||
top: 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li .label {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
color: #555;
|
||||
top: 4px;
|
||||
left: 5px;
|
||||
}
|
||||
.phpdebugbar-widgets-timeline li .value {
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
background: #3db9ec;
|
||||
top: 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
461
web/debugbar.js
461
web/debugbar.js
@ -1,41 +1,176 @@
|
||||
if (typeof(PhpDebugBar) == 'undefined') {
|
||||
// namespace
|
||||
var PhpDebugBar = {};
|
||||
}
|
||||
|
||||
if (typeof(localStorage) == 'undefined') {
|
||||
// provide mock localStorage object for dumb browsers
|
||||
var localStorage = {
|
||||
setItem: function(key, value) {},
|
||||
getItem: function(key) { return null; }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* DebugBar
|
||||
*
|
||||
* Creates a bar that appends itself to the body of your page
|
||||
* and sticks to the bottom.
|
||||
*
|
||||
* The bar can be customized by adding tabs and indicators.
|
||||
* A data map is used to fill those controls with data provided
|
||||
* from datasets.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
PhpDebugBar.DebugBar = (function($) {
|
||||
|
||||
function getDictValue(dict, key, def) {
|
||||
/**
|
||||
* Returns the value from an object property.
|
||||
* Using dots in the key, it is possible to retreive nested property values
|
||||
*
|
||||
* @param {Object} dict
|
||||
* @param {String} key
|
||||
* @param {Object} default_value
|
||||
* @return {Object}
|
||||
*/
|
||||
function getDictValue(dict, key, default_value) {
|
||||
var d = dict, parts = key.split('.');
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
if (!d[parts[i]]) {
|
||||
return def;
|
||||
return default_value;
|
||||
}
|
||||
d = d[parts[i]];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Tab
|
||||
*
|
||||
* A tab is composed of a tab label which is always visible and
|
||||
* a tab panel which is visible only when the tab is active.
|
||||
*
|
||||
* The panel must contain a widget. A widget is an object which has
|
||||
* an element property containing something appendable to a jQuery object.
|
||||
*
|
||||
* @this {Tab}
|
||||
* @constructor
|
||||
* @param {String} title
|
||||
* @param {Object} widget
|
||||
*/
|
||||
var Tab = function(title, widget) {
|
||||
this.tab = $('<a href="javascript:" class="phpdebugbar-tab" />').text(title);
|
||||
this.panel = $('<div class="phpdebugbar-panel" />');
|
||||
this.replaceWidget(widget);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the title of the tab
|
||||
*
|
||||
* @this {Tab}
|
||||
* @param {String} text
|
||||
*/
|
||||
Tab.prototype.setTitle = function(text) {
|
||||
this.tab.text(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces the widget inside the panel
|
||||
*
|
||||
* @this {Tab}
|
||||
* @param {Object} new_widget
|
||||
*/
|
||||
Tab.prototype.replaceWidget = function(new_widget) {
|
||||
this.panel.empty().append(new_widget.element);
|
||||
this.widget = new_widget;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Indicator
|
||||
*
|
||||
* An indicator is a text and an icon to display single value information
|
||||
* right inside the always visible part of the debug bar
|
||||
*
|
||||
* @this {Indicator}
|
||||
* @constructor
|
||||
* @param {String} icon
|
||||
* @param {String} tooltip
|
||||
* @param {String} position "right" or "left", default is "right"
|
||||
*/
|
||||
var Indicator = function(icon, tooltip, position) {
|
||||
if (!position) {
|
||||
position = 'right'
|
||||
}
|
||||
|
||||
this.position = position;
|
||||
this.element = $('<span class="phpdebugbar-indicator" />').css('float', position);
|
||||
this.label = $('<span class="text" />').appendTo(this.element);
|
||||
|
||||
if (icon) {
|
||||
$('<i class="icon-' + icon + '" />').insertBefore(this.label);
|
||||
}
|
||||
if (tooltip) {
|
||||
this.element.append($('<span class="tooltip" />').text(tooltip));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the text of the indicator
|
||||
*
|
||||
* @this {Indicator}
|
||||
* @param {String} text
|
||||
*/
|
||||
Indicator.prototype.setText = function(text) {
|
||||
this.element.find('.text').text(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the tooltip of the indicator
|
||||
*
|
||||
* @this {Indicator}
|
||||
* @param {String} text
|
||||
*/
|
||||
Indicator.prototype.setTooltip = function(text) {
|
||||
this.element.find('.tooltip').text(text);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* DebugBar
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @constructor
|
||||
*/
|
||||
var DebugBar = function() {
|
||||
this.controls = {};
|
||||
this.dataMap = {};
|
||||
this.datasets = {};
|
||||
this.initUI();
|
||||
this.init();
|
||||
this.restoreState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialiazes the UI
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.initUI = function() {
|
||||
var self = this;
|
||||
this.element = $('<div class="phpdebugbar" />').appendTo('body');
|
||||
this.header = $('<div class="phpdebugbar-header" />').appendTo(this.element);
|
||||
this.body = $('<div class="phpdebugbar-body" />').appendTo(this.element);
|
||||
this.resizeHandle = $('<div class="phpdebugbar-resize-handle" />').appendTo(this.body);
|
||||
this.firstPanelName = null;
|
||||
this.activePanelName = null;
|
||||
|
||||
// allow resizing by dragging handle
|
||||
this.body.drag('start', function(e, dd) {
|
||||
dd.height = $(this).height();
|
||||
}).drag(function(e, dd) {
|
||||
@ -44,21 +179,35 @@ PhpDebugBar.DebugBar = (function($) {
|
||||
localStorage.setItem('phpdebugbar-height', h);
|
||||
}, {handle: '.phpdebugbar-resize-handle'});
|
||||
|
||||
// close button
|
||||
this.closeButton = $('<a class="phpdebugbar-close-btn" href="javascript:"><i class="icon-remove"></i></a>').appendTo(this.header);
|
||||
var self = this;
|
||||
this.closeButton.click(function() {
|
||||
self.hidePanels();
|
||||
});
|
||||
|
||||
this.stackSelectBox = $('<select class="phpdebugbar-data-stacks" />').appendTo(this.header);
|
||||
this.stackSelectBox.change(function() {
|
||||
self.dataChangeHandler(self.stacks[this.value]);
|
||||
// select box for data sets
|
||||
this.datasetSelectBox = $('<select class="phpdebugbar-datasets-switcher" />').appendTo(this.header);
|
||||
this.datasetSelectBox.change(function() {
|
||||
self.dataChangeHandler(self.datasets[this.value]);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom initialiaze function for subsclasses
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.init = function() {};
|
||||
|
||||
/**
|
||||
* Restores the state of the DebugBar using localStorage
|
||||
* This is not called by default in the constructor and
|
||||
* needs to be called by subclasses in their init() method
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.restoreState = function() {
|
||||
// bar height
|
||||
var height = localStorage.getItem('phpdebugbar-height');
|
||||
if (height) {
|
||||
this.body.css('height', height);
|
||||
@ -66,86 +215,171 @@ PhpDebugBar.DebugBar = (function($) {
|
||||
localStorage.setItem('phpdebugbar-height', this.body.height());
|
||||
}
|
||||
|
||||
// bar visibility
|
||||
var visible = localStorage.getItem('phpdebugbar-visible');
|
||||
if (visible && visible == '1') {
|
||||
this.showPanel(localStorage.getItem('phpdebugbar-panel'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and adds a new tab
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name Internal name
|
||||
* @param {Object} widget A widget object with an element property
|
||||
* @param {String} title The text in the tab, if not specified, name will be used
|
||||
* @return {Tab}
|
||||
*/
|
||||
DebugBar.prototype.createTab = function(name, widget, title) {
|
||||
var tab = new Tab(title || (name.replace(/[_\-]/g, ' ').charAt(0).toUpperCase() + name.slice(1)), widget);
|
||||
return this.addTab(name, tab);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a new tab
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name Internal name
|
||||
* @param {Tab} tab Tab object
|
||||
* @return {Tab}
|
||||
*/
|
||||
DebugBar.prototype.addTab = function(name, tab) {
|
||||
if (this.isControl(name)) {
|
||||
throw new Exception(name + ' already exists');
|
||||
}
|
||||
|
||||
var tab = $('<a href="javascript:" class="phpdebugbar-tab" />').text(title || (name.charAt(0).toUpperCase() + name.slice(1))),
|
||||
panel = $('<div class="phpdebugbar-panel" data-id="' + name + '" />'),
|
||||
self = this;
|
||||
var self = this;
|
||||
tab.tab.appendTo(this.header).click(function() { self.showPanel(name); });
|
||||
tab.panel.appendTo(this.body);
|
||||
|
||||
tab.appendTo(this.header).click(function() { self.showPanel(name); });
|
||||
panel.appendTo(this.body).append(widget.element);
|
||||
|
||||
this.controls[name] = {type: "tab", tab: tab, panel: panel, widget: widget};
|
||||
return widget;
|
||||
this.controls[name] = tab;
|
||||
if (this.firstPanelName == null) {
|
||||
this.firstPanelName = name;
|
||||
}
|
||||
return tab;
|
||||
};
|
||||
|
||||
DebugBar.prototype.setTabTitle = function(name, title) {
|
||||
/**
|
||||
* Returns a Tab object
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name
|
||||
* @return {Tab}
|
||||
*/
|
||||
DebugBar.prototype.getTab = function(name) {
|
||||
if (this.isTab(name)) {
|
||||
this.controls[name].tab.text(title);
|
||||
}
|
||||
};
|
||||
|
||||
DebugBar.prototype.getTabWidget = function(name) {
|
||||
if (this.isTab(name)) {
|
||||
return this.controls[name].widget;
|
||||
return this.controls[name];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and adds an indicator
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name Internal name
|
||||
* @param {String} icon
|
||||
* @param {String} tooltip
|
||||
* @param {String} position "right" or "left", default is "right"
|
||||
* @return {Indicator}
|
||||
*/
|
||||
DebugBar.prototype.createIndicator = function(name, icon, tooltip, position) {
|
||||
var indicator = new Indicator(icon, tooltip, position);
|
||||
return this.addIndicator(name, indicator);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an indicator
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name Internal name
|
||||
* @param {Indicator} indicator Indicator object
|
||||
* @return {Indicator}
|
||||
*/
|
||||
DebugBar.prototype.addIndicator = function(name, indicator) {
|
||||
if (this.isControl(name)) {
|
||||
throw new Exception(name + ' already exists');
|
||||
}
|
||||
if (!position) {
|
||||
position = 'right'
|
||||
}
|
||||
|
||||
var indicator = $('<span class="phpdebugbar-indicator" />').css('float', position),
|
||||
text = $('<span class="text" />').appendTo(indicator);
|
||||
|
||||
if (icon) {
|
||||
$('<i class="icon-' + icon + '" />').insertBefore(text);
|
||||
}
|
||||
if (tooltip) {
|
||||
indicator.append($('<span class="tooltip" />').text(tooltip));
|
||||
}
|
||||
|
||||
if (position == 'right') {
|
||||
indicator.appendTo(this.header);
|
||||
if (indicator.position == 'right') {
|
||||
indicator.element.appendTo(this.header);
|
||||
} else {
|
||||
indicator.insertBefore(this.header.children().first())
|
||||
indicator.element.insertBefore(this.header.children().first())
|
||||
}
|
||||
|
||||
this.controls[name] = {type: "indicator", indicator: indicator};
|
||||
return text;
|
||||
this.controls[name] = indicator;
|
||||
return indicator;
|
||||
};
|
||||
|
||||
DebugBar.prototype.setIndicatorText = function(name, text) {
|
||||
/**
|
||||
* Returns an Indicator object
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name
|
||||
* @return {Indicator}
|
||||
*/
|
||||
DebugBar.prototype.getIndicator = function(name) {
|
||||
if (this.isIndicator(name)) {
|
||||
this.controls[name].indicator.find('.text').text(text);
|
||||
return this.controls[name];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a control
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} control
|
||||
* @return {Object}
|
||||
*/
|
||||
DebugBar.prototype.addControl = function(name, control) {
|
||||
if (control instanceof Tab) {
|
||||
this.addTab(name, control);
|
||||
} else if (control instanceof Indicator) {
|
||||
this.addIndicator(name, control);
|
||||
} else {
|
||||
throw new Exception("Unknown type of control");
|
||||
}
|
||||
return control;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if there's a control under the specified name
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name
|
||||
* @return {Boolean}
|
||||
*/
|
||||
DebugBar.prototype.isControl = function(name) {
|
||||
return typeof(this.controls[name]) != 'undefined';
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a tab with the specified name exists
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name
|
||||
* @return {Boolean}
|
||||
*/
|
||||
DebugBar.prototype.isTab = function(name) {
|
||||
return typeof(this.controls[name]) != 'undefined' && this.controls[name].type === 'tab';
|
||||
return this.isControl(name) && this.controls[name] instanceof Tab;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if an indicator with the specified name exists
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name
|
||||
* @return {Boolean}
|
||||
*/
|
||||
DebugBar.prototype.isIndicator = function(name) {
|
||||
return this.isControl(name) && this.controls[name].type === 'indicator';
|
||||
return this.isControl(name) && this.controls[name] instanceof Indicator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all tabs and indicators from the debug bar and hides it
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.reset = function() {
|
||||
this.hidePanels();
|
||||
this.body.find('.phpdebugbar-panel').remove();
|
||||
@ -153,17 +387,22 @@ PhpDebugBar.DebugBar = (function($) {
|
||||
this.controls = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the debug bar and display a specified panel
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} name If not specified, display the first panel
|
||||
*/
|
||||
DebugBar.prototype.showPanel = function(name) {
|
||||
this.resizeHandle.show();
|
||||
this.body.show();
|
||||
this.closeButton.show();
|
||||
|
||||
if (!name) {
|
||||
activePanel = this.body.find('.phpdebugbar-panel.active');
|
||||
if (activePanel.length > 0) {
|
||||
name = activePanel.data('id');
|
||||
if (this.activePanelName) {
|
||||
name = this.activePanelName;
|
||||
} else {
|
||||
name = this.body.find('.phpdebugbar-panel').first().data('id');
|
||||
name = this.firstPanelName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,15 +412,26 @@ PhpDebugBar.DebugBar = (function($) {
|
||||
if (this.isTab(name)) {
|
||||
this.controls[name].tab.addClass('active');
|
||||
this.controls[name].panel.addClass('active').show();
|
||||
this.activePanelName = name;
|
||||
}
|
||||
localStorage.setItem('phpdebugbar-visible', '1');
|
||||
localStorage.setItem('phpdebugbar-panel', name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows the first panel
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.showFirstPanel = function() {
|
||||
this.showPanel(this.body.find('.phpdebugbar-panel').first().data('id'));
|
||||
this.showPanel(this.firstPanelName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide panels and "close" the debug bar
|
||||
*
|
||||
* @this {DebugBar}
|
||||
*/
|
||||
DebugBar.prototype.hidePanels = function() {
|
||||
this.header.find('.phpdebugbar-tab.active').removeClass('active');
|
||||
this.body.hide();
|
||||
@ -190,40 +440,121 @@ PhpDebugBar.DebugBar = (function($) {
|
||||
localStorage.setItem('phpdebugbar-visible', '0');
|
||||
};
|
||||
|
||||
DebugBar.prototype.setData = function(data) {
|
||||
this.stacks = {};
|
||||
this.addDataStack(data);
|
||||
/**
|
||||
* Sets the data map used by dataChangeHandler to populate
|
||||
* indicators and widgets
|
||||
*
|
||||
* A data map is an object where properties are control names.
|
||||
* The value of each property should be an array where the first
|
||||
* item is the name of a property from the data object (nested properties
|
||||
* can be specified) and the second item the default value.
|
||||
*
|
||||
* Example:
|
||||
* {"memory": ["memory.peak_usage_str", "0B"]}
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {Object} map
|
||||
*/
|
||||
DebugBar.prototype.setDataMap = function(map) {
|
||||
this.dataMap = map;
|
||||
};
|
||||
|
||||
DebugBar.prototype.addDataStack = function(data, id) {
|
||||
id = id || ("Request #" + (Object.keys(this.stacks).length + 1));
|
||||
this.stacks[id] = data;
|
||||
/**
|
||||
* Same as setDataMap() but appends to the existing map
|
||||
* rather than replacing it
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {Object} map
|
||||
*/
|
||||
DebugBar.prototype.addDataMap = function(map) {
|
||||
$.extend(this.dataMap, map);
|
||||
};
|
||||
|
||||
this.stackSelectBox.append($('<option value="' + id + '">' + id + '</option>'));
|
||||
if (Object.keys(this.stacks).length > 1) {
|
||||
this.stackSelectBox.show();
|
||||
/**
|
||||
* Resets datasets and add one set of data
|
||||
*
|
||||
* For this method to be usefull, you need to specify
|
||||
* a dataMap using setDataMap()
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {Object} data
|
||||
* @return {String} Dataset's id
|
||||
*/
|
||||
DebugBar.prototype.setData = function(data) {
|
||||
this.datasets = {};
|
||||
return this.addDataSet(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a dataset
|
||||
*
|
||||
* If more than one dataset are added, the dataset selector
|
||||
* will be displayed.
|
||||
*
|
||||
* For this method to be usefull, you need to specify
|
||||
* a dataMap using setDataMap()
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {Object} data
|
||||
* @param {String} id The name of this set, optional
|
||||
* @return {String} Dataset's id
|
||||
*/
|
||||
DebugBar.prototype.addDataSet = function(data, id) {
|
||||
id = id || ("Request #" + (Object.keys(this.datasets).length + 1));
|
||||
this.datasets[id] = data;
|
||||
|
||||
this.datasetSelectBox.append($('<option value="' + id + '">' + id + '</option>'));
|
||||
if (Object.keys(this.datasets).length > 1) {
|
||||
this.datasetSelectBox.show();
|
||||
}
|
||||
|
||||
this.switchDataStack(id);
|
||||
this.showDataSet(id);
|
||||
return id;
|
||||
};
|
||||
|
||||
DebugBar.prototype.switchDataStack = function(id) {
|
||||
this.dataChangeHandler(this.stacks[id]);
|
||||
this.stackSelectBox.val(id);
|
||||
/**
|
||||
* Returns the data from a dataset
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} id
|
||||
* @return {Object}
|
||||
*/
|
||||
DebugBar.prototype.getDataSet = function(id) {
|
||||
return this.datasets[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Switch the currently displayed dataset
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {String} id
|
||||
*/
|
||||
DebugBar.prototype.showDataSet = function(id) {
|
||||
this.dataChangeHandler(this.datasets[id]);
|
||||
this.datasetSelectBox.val(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the current dataset is modified.
|
||||
*
|
||||
* @this {DebugBar}
|
||||
* @param {Object} data
|
||||
*/
|
||||
DebugBar.prototype.dataChangeHandler = function(data) {
|
||||
var self = this;
|
||||
$.each(this.dataMap, function(key, def) {
|
||||
var d = getDictValue(data, def[0], def[1]);
|
||||
if (self.isIndicator(key)) {
|
||||
self.setIndicatorText(key, d);
|
||||
self.getIndicator(key).setText(d);
|
||||
} else {
|
||||
self.getTabWidget(key).setData(d);
|
||||
self.getTab(key).widget.setData(d);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
DebugBar.Tab = Tab;
|
||||
DebugBar.Indicator = Indicator;
|
||||
|
||||
return DebugBar;
|
||||
|
||||
})(jQuery);
|
||||
|
@ -1,30 +0,0 @@
|
||||
|
||||
var StandardPhpDebugBar = (function() {
|
||||
|
||||
var DebugBar = function(data) {
|
||||
PhpDebugBar.DebugBar.apply(this);
|
||||
this.setData(data);
|
||||
};
|
||||
|
||||
DebugBar.prototype = new PhpDebugBar.DebugBar();
|
||||
|
||||
DebugBar.prototype.init = function() {
|
||||
this.createIndicator('memory', 'cogs', 'Memory Usage');
|
||||
this.createIndicator('time', 'time', 'Request duration');
|
||||
|
||||
this.createTab('messages', new PhpDebugBar.Widgets.MessagesWidget());
|
||||
this.createTab('request', new PhpDebugBar.Widgets.VariableListWidget());
|
||||
this.createTab('timeline', new PhpDebugBar.Widgets.TimelineWidget());
|
||||
|
||||
this.dataMap = {
|
||||
"memory": ["memory.peak_usage_str", "0B"],
|
||||
"time": ["time.duration_str", "0ms"],
|
||||
"messages": ["messages", []],
|
||||
"request": ["request", {}],
|
||||
"timeline": ["time", {}]
|
||||
};
|
||||
};
|
||||
|
||||
return DebugBar;
|
||||
|
||||
})();
|
266
web/widgets.js
266
web/widgets.js
@ -1,15 +1,35 @@
|
||||
if (typeof(PhpDebugBar) == 'undefined') {
|
||||
// namespace
|
||||
var PhpDebugBar = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
*/
|
||||
PhpDebugBar.Widgets = (function($) {
|
||||
|
||||
var widgets = {};
|
||||
|
||||
/**
|
||||
* Replaces spaces with and line breaks with <br>
|
||||
*
|
||||
* @param {String} text
|
||||
* @return {String}
|
||||
*/
|
||||
var htmlize = function(text) {
|
||||
return text.replace(/\n/g, '<br>').replace(/\s/g, " ")
|
||||
};
|
||||
|
||||
widgets.htmlize = htmlize;
|
||||
|
||||
/**
|
||||
* 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 = function(value, prettify) {
|
||||
if (typeof(value) !== 'string') {
|
||||
if (prettify) {
|
||||
@ -20,8 +40,21 @@ PhpDebugBar.Widgets = (function($) {
|
||||
return value;
|
||||
};
|
||||
|
||||
// ------------------------------------------
|
||||
widgets.renderValue = renderValue;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Generic widgets
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Displays array element in a <ul> list
|
||||
*
|
||||
* @this {ListWidget}
|
||||
* @constructor
|
||||
* @param {Array} data
|
||||
* @param {Function} itemRenderer Optional
|
||||
*/
|
||||
var ListWidget = function(data, itemRenderer) {
|
||||
this.element = $('<ul class="phpdebugbar-widgets-list" />');
|
||||
if (itemRenderer) {
|
||||
@ -32,6 +65,12 @@ PhpDebugBar.Widgets = (function($) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the data and updates the list
|
||||
*
|
||||
* @this {ListWidget}
|
||||
* @param {Array} data
|
||||
*/
|
||||
ListWidget.prototype.setData = function(data) {
|
||||
this.element.empty();
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
@ -40,14 +79,154 @@ PhpDebugBar.Widgets = (function($) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the content of a <li> element
|
||||
*
|
||||
* @this {ListWidget}
|
||||
* @param {jQuery} li The <li> element as a jQuery Object
|
||||
* @param {Object} value An item from the data array
|
||||
*/
|
||||
ListWidget.prototype.itemRenderer = function(li, value) {
|
||||
li.html(renderValue(value));
|
||||
};
|
||||
|
||||
widgets.ListWidget = ListWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Displays object property/value paris in a <dl> list
|
||||
*
|
||||
* @this {KVListWidget}
|
||||
* @constructor
|
||||
* @param {Object} data
|
||||
* @param {Function} itemRenderer Optional
|
||||
*/
|
||||
var KVListWidget = function(data, itemRenderer) {
|
||||
this.element = $('<dl class="phpdebugbar-widgets-kvlist" />');
|
||||
if (itemRenderer) {
|
||||
this.itemRenderer = itemRenderer;
|
||||
}
|
||||
if (data) {
|
||||
this.setData(data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the data and updates the list
|
||||
*
|
||||
* @this {KVListWidget}
|
||||
* @param {Object} data
|
||||
*/
|
||||
KVListWidget.prototype.setData = function(data) {
|
||||
var self = this;
|
||||
this.element.empty();
|
||||
$.each(data, function(key, value) {
|
||||
var dt = $('<dt class="key" />').appendTo(self.element);
|
||||
var dd = $('<dd class="value" />').appendTo(self.element);
|
||||
self.itemRenderer(dt, dd, key, value);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the content of the <dt> and <dd> elements
|
||||
*
|
||||
* @this {KVListWidget}
|
||||
* @param {jQuery} dt The <dt> element as a jQuery Object
|
||||
* @param {jQuery} dd The <dd> element as a jQuery Object
|
||||
* @param {String} key Property name
|
||||
* @param {Object} value Property value
|
||||
*/
|
||||
KVListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||
dt.text(key);
|
||||
dd.html(htmlize(value));
|
||||
};
|
||||
|
||||
widgets.KVListWidget = KVListWidget;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* An extension of KVListWidget where the data represents a list
|
||||
* of variables
|
||||
*
|
||||
* @this {VariableListWidget}
|
||||
* @constructor
|
||||
* @param {Object} data
|
||||
*/
|
||||
var VariableListWidget = function(data) {
|
||||
KVListWidget.apply(this, [data]);
|
||||
this.element.addClass('phpdebugbar-widgets-varlist');
|
||||
};
|
||||
|
||||
VariableListWidget.prototype = new KVListWidget();
|
||||
VariableListWidget.constructor = VariableListWidget;
|
||||
|
||||
VariableListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||
dt.text(key);
|
||||
|
||||
var v = value;
|
||||
if (v.length > 100) {
|
||||
v = v.substr(0, 100) + "...";
|
||||
}
|
||||
dd.text(v).click(function() {
|
||||
if (dd.hasClass('pretty')) {
|
||||
dd.text(v).removeClass('pretty');
|
||||
} else {
|
||||
dd.html(htmlize(value)).addClass('pretty');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
widgets.VariableListWidget = VariableListWidget;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Iframe widget
|
||||
*
|
||||
* @this {IFrameWidget}
|
||||
* @constructor
|
||||
* @param {String} url
|
||||
*/
|
||||
var IFrameWidget = function(url) {
|
||||
this.element = $('<iframe src="" class="phpdebugbar-widgets-iframe" seamless="seamless" border="0" width="100%" height="100%" />');
|
||||
if (url) {
|
||||
this.setData(url);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the iframe url
|
||||
*
|
||||
* @this {IFrameWidget}
|
||||
* @param {String} url
|
||||
*/
|
||||
IFrameWidget.prototype.setUrl = function(url) {
|
||||
this.element.attr('src', url);
|
||||
};
|
||||
|
||||
// for compatibility with data mapping
|
||||
IFrameWidget.prototype.setData = function(url) {
|
||||
this.setUrl(url);
|
||||
};
|
||||
|
||||
widgets.IFrameWidget = IFrameWidget;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Collector specific widgets
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Widget for the MessagesCollector
|
||||
*
|
||||
* Uses ListWidget under the hood
|
||||
*
|
||||
* @this {MessagesWidget}
|
||||
* @constructor
|
||||
* @param {Array} data
|
||||
*/
|
||||
var MessagesWidget = function(data) {
|
||||
this.element = $('<div class="phpdebugbar-widgets-messages" />');
|
||||
|
||||
@ -142,80 +321,15 @@ PhpDebugBar.Widgets = (function($) {
|
||||
|
||||
widgets.MessagesWidget = MessagesWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
var KVListWidget = function(data, itemRenderer) {
|
||||
this.element = $('<dl class="phpdebugbar-widgets-kvlist" />');
|
||||
if (itemRenderer) {
|
||||
this.itemRenderer = itemRenderer;
|
||||
}
|
||||
if (data) {
|
||||
this.setData(data);
|
||||
}
|
||||
};
|
||||
|
||||
KVListWidget.prototype.setData = function(data) {
|
||||
var self = this;
|
||||
this.element.empty();
|
||||
$.each(data, function(key, value) {
|
||||
var dt = $('<dt class="key" />').appendTo(self.element);
|
||||
var dd = $('<dd class="value" />').appendTo(self.element);
|
||||
self.itemRenderer(dt, dd, key, value);
|
||||
});
|
||||
};
|
||||
|
||||
KVListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||
dt.text(key);
|
||||
dd.html(htmlize(value));
|
||||
};
|
||||
|
||||
widgets.KVListWidget = KVListWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
var VariableListWidget = function(data) {
|
||||
KVListWidget.apply(this, [data]);
|
||||
this.element.addClass('phpdebugbar-widgets-varlist');
|
||||
};
|
||||
|
||||
VariableListWidget.prototype = new KVListWidget();
|
||||
VariableListWidget.constructor = VariableListWidget;
|
||||
|
||||
VariableListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||
dt.text(key);
|
||||
|
||||
var v = value;
|
||||
if (v.length > 100) {
|
||||
v = v.substr(0, 100) + "...";
|
||||
}
|
||||
dd.text(v).click(function() {
|
||||
if (dd.hasClass('pretty')) {
|
||||
dd.text(v).removeClass('pretty');
|
||||
} else {
|
||||
dd.html(htmlize(value)).addClass('pretty');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
widgets.VariableListWidget = VariableListWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
|
||||
var IFrameWidget = function(url) {
|
||||
this.element = $('<iframe src="" class="phpdebugbar-widgets-iframe" seamless="seamless" border="0" width="100%" height="100%" />');
|
||||
if (url) {
|
||||
this.setData(url);
|
||||
}
|
||||
};
|
||||
|
||||
IFrameWidget.prototype.setData = function(url) {
|
||||
this.element.attr('src', url);
|
||||
};
|
||||
|
||||
widgets.IFrameWidget = IFrameWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Widget for the TimeDataCollector
|
||||
*
|
||||
* @this {TimelineWidget}
|
||||
* @constructor
|
||||
* @param {Object} data
|
||||
*/
|
||||
var TimelineWidget = function(data) {
|
||||
this.element = $('<ul class="phpdebugbar-widgets-timeline" />');
|
||||
if (data) {
|
||||
@ -240,7 +354,7 @@ PhpDebugBar.Widgets = (function($) {
|
||||
|
||||
widgets.TimelineWidget = TimelineWidget;
|
||||
|
||||
// ------------------------------------------
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
return widgets;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user