├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── DbAsset.php ├── DebugAsset.php ├── FlattenException.php ├── LogTarget.php ├── Module.php ├── Panel.php ├── TimelineAsset.php ├── UserswitchAsset.php ├── actions └── db │ └── ExplainAction.php ├── assets ├── .gitignore ├── arrow.svg ├── build.sh ├── css │ ├── .gitignore │ ├── main.css │ ├── timeline.css │ └── toolbar.css ├── js │ ├── bs4-native.min.js │ ├── db.js │ ├── polyfill.min.js │ ├── timeline.js │ ├── toolbar.js │ └── userswitch.js ├── maximize.svg ├── scss │ ├── bs-4.3.1 │ │ ├── _alert.scss │ │ ├── _badge.scss │ │ ├── _breadcrumb.scss │ │ ├── _button-group.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _close.scss │ │ ├── _code.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _grid.scss │ │ ├── _images.scss │ │ ├── _input-group.scss │ │ ├── _jumbotron.scss │ │ ├── _list-group.scss │ │ ├── _media.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _print.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _root.scss │ │ ├── _spinners.scss │ │ ├── _tables.scss │ │ ├── _toasts.scss │ │ ├── _tooltip.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── bootstrap-grid.scss │ │ ├── bootstrap-reboot.scss │ │ ├── bootstrap.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _box-shadow.scss │ │ │ ├── _breakpoints.scss │ │ │ ├── _buttons.scss │ │ │ ├── _caret.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _deprecate.scss │ │ │ ├── _float.scss │ │ │ ├── _forms.scss │ │ │ ├── _gradients.scss │ │ │ ├── _grid-framework.scss │ │ │ ├── _grid.scss │ │ │ ├── _hover.scss │ │ │ ├── _image.scss │ │ │ ├── _list-group.scss │ │ │ ├── _lists.scss │ │ │ ├── _nav-divider.scss │ │ │ ├── _pagination.scss │ │ │ ├── _reset-text.scss │ │ │ ├── _resize.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _size.scss │ │ │ ├── _table-row.scss │ │ │ ├── _text-emphasis.scss │ │ │ ├── _text-hide.scss │ │ │ ├── _text-truncate.scss │ │ │ ├── _transition.scss │ │ │ └── _visibility.scss │ │ ├── utilities │ │ │ ├── _align.scss │ │ │ ├── _background.scss │ │ │ ├── _borders.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _display.scss │ │ │ ├── _embed.scss │ │ │ ├── _flex.scss │ │ │ ├── _float.scss │ │ │ ├── _overflow.scss │ │ │ ├── _position.scss │ │ │ ├── _screenreaders.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _stretched-link.scss │ │ │ ├── _text.scss │ │ │ └── _visibility.scss │ │ └── vendor │ │ │ └── _rfs.scss │ ├── main.scss │ ├── timeline.scss │ └── toolbar.scss └── switch.svg ├── components └── search │ ├── Filter.php │ └── matchers │ ├── Base.php │ ├── GreaterThan.php │ ├── GreaterThanOrEqual.php │ ├── LowerThan.php │ ├── MatcherInterface.php │ └── SameAs.php ├── controllers ├── DefaultController.php └── UserController.php ├── models ├── Router.php ├── UserSwitch.php ├── router │ ├── ActionRoutes.php │ ├── CurrentRoute.php │ └── RouterRules.php ├── search │ ├── Base.php │ ├── Db.php │ ├── Debug.php │ ├── Event.php │ ├── Log.php │ ├── Mail.php │ ├── Profile.php │ ├── User.php │ └── UserSearchInterface.php └── timeline │ ├── DataProvider.php │ ├── Search.php │ └── Svg.php ├── panels ├── AssetPanel.php ├── ConfigPanel.php ├── DbPanel.php ├── DumpPanel.php ├── EventPanel.php ├── LogPanel.php ├── MailPanel.php ├── ProfilingPanel.php ├── RequestPanel.php ├── RouterPanel.php ├── TimelinePanel.php └── UserPanel.php ├── views ├── default │ ├── index.php │ ├── panels │ │ ├── assets │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── config │ │ │ ├── detail.php │ │ │ ├── summary.php │ │ │ └── table.php │ │ ├── db │ │ │ ├── callers.php │ │ │ ├── detail.php │ │ │ ├── queries.php │ │ │ └── summary.php │ │ ├── dump │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── event │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── log │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── mail │ │ │ ├── _item.php │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── profile │ │ │ ├── detail.php │ │ │ └── summary.php │ │ ├── request │ │ │ ├── detail.php │ │ │ ├── summary.php │ │ │ └── table.php │ │ ├── router │ │ │ ├── actions.php │ │ │ ├── current.php │ │ │ ├── detail.php │ │ │ ├── rules.php │ │ │ └── summary.php │ │ ├── timeline │ │ │ └── detail.php │ │ └── user │ │ │ ├── detail.php │ │ │ ├── roles.php │ │ │ ├── summary.php │ │ │ └── switch.php │ ├── toolbar.php │ └── view.php └── layouts │ └── main.php └── widgets └── NavigationButton.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Yii Software LLC nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

Debug Extension for Yii 2

6 |
7 |

8 | 9 | This extension provides a debugger for [Yii framework 2.0](https://www.yiiframework.com) applications. When this extension is used, 10 | a debugger toolbar will appear at the bottom of every page. The extension also provides 11 | a set of standalone pages to display more detailed debug information. 12 | 13 | For license information check the [LICENSE](LICENSE.md)-file. 14 | 15 | Documentation is at [docs/guide/README.md](docs/guide/README.md). 16 | 17 | [![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2-debug/v/stable.png)](https://packagist.org/packages/yiisoft/yii2-debug) 18 | [![Total Downloads](https://poser.pugx.org/yiisoft/yii2-debug/downloads.png)](https://packagist.org/packages/yiisoft/yii2-debug) 19 | [![Build Status](https://github.com/yiisoft/yii2-debug/workflows/build/badge.svg)](https://github.com/yiisoft/yii2-debug/actions) 20 | 21 | 22 | Installation 23 | ------------ 24 | 25 | The preferred way to install this extension is through [composer](https://getcomposer.org/download/). 26 | 27 | Either run 28 | 29 | ``` 30 | php composer.phar require --prefer-dist yiisoft/yii2-debug 31 | ``` 32 | 33 | or add 34 | 35 | ``` 36 | "yiisoft/yii2-debug": "~2.1.0" 37 | ``` 38 | 39 | to the require section of your `composer.json` file. 40 | 41 | 42 | Usage 43 | ----- 44 | 45 | Once the extension is installed, simply modify your application configuration as follows: 46 | 47 | ```php 48 | return [ 49 | 'bootstrap' => ['debug'], 50 | 'modules' => [ 51 | 'debug' => [ 52 | 'class' => 'yii\debug\Module', 53 | // uncomment and adjust the following to add your IP if you are not connecting from localhost. 54 | //'allowedIPs' => ['127.0.0.1', '::1'], 55 | ], 56 | // ... 57 | ], 58 | ... 59 | ]; 60 | ``` 61 | 62 | You will see a debugger toolbar showing at the bottom of every page of your application. 63 | You can click on the toolbar to see more detailed debug information. 64 | 65 | 66 | Open Files in IDE 67 | ----- 68 | 69 | You can create a link to open files in your favorite IDE with this configuration: 70 | 71 | ```php 72 | return [ 73 | 'bootstrap' => ['debug'], 74 | 'modules' => [ 75 | 'debug' => [ 76 | 'class' => 'yii\debug\Module', 77 | 'traceLine' => '{file}:{line}', 78 | // uncomment and adjust the following to add your IP if you are not connecting from localhost. 79 | //'allowedIPs' => ['127.0.0.1', '::1'], 80 | ], 81 | // ... 82 | ], 83 | ... 84 | ]; 85 | ``` 86 | 87 | You must make some changes to your OS. See these examples: 88 | - PHPStorm: https://github.com/aik099/PhpStormProtocol 89 | - Sublime Text 3 on Windows or Linux: https://packagecontrol.io/packages/subl%20protocol 90 | - Sublime Text 3 on Mac: https://github.com/inopinatus/sublime_url 91 | 92 | #### Virtualized or dockerized 93 | 94 | If your application is run under a virtualized or dockerized environment, it is often the case that the application's 95 | base path is different inside of the virtual machine or container than on your host machine. For the links work in those 96 | situations, you can configure `tracePathMappings` like this (change the path to your app): 97 | 98 | ```php 99 | 'tracePathMappings' => [ 100 | '/app' => '/path/to/your/app', 101 | ], 102 | ``` 103 | 104 | Or you can create a callback for `traceLine` for even more control: 105 | 106 | ```php 107 | 'traceLine' => function($options, $panel) { 108 | $filePath = $options['file']; 109 | if (StringHelper::startsWith($filePath, Yii::$app->basePath)) { 110 | $filePath = '/path/to/your/app' . substr($filePath, strlen(Yii::$app->basePath)); 111 | } 112 | return strtr('{text}', ['{file}' => $filePath]); 113 | }, 114 | ``` 115 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/yii2-debug", 3 | "description": "The debugger extension for the Yii framework", 4 | "keywords": [ 5 | "yii2", 6 | "debug", 7 | "debugger", 8 | "dev" 9 | ], 10 | "type": "yii2-extension", 11 | "license": "BSD-3-Clause", 12 | "support": { 13 | "issues": "https://github.com/yiisoft/yii2-debug/issues", 14 | "forum": "https://www.yiiframework.com/forum/", 15 | "wiki": "https://www.yiiframework.com/wiki/", 16 | "irc": "ircs://irc.libera.chat:6697/yii", 17 | "source": "https://github.com/yiisoft/yii2-debug" 18 | }, 19 | "authors": [ 20 | { 21 | "name": "Qiang Xue", 22 | "email": "qiang.xue@gmail.com" 23 | }, 24 | { 25 | "name": "Simon Karlen", 26 | "email": "simi.albi@outlook.com" 27 | } 28 | ], 29 | "minimum-stability": "dev", 30 | "require": { 31 | "php": ">=5.4", 32 | "ext-mbstring": "*", 33 | "yiisoft/yii2": "~2.0.13" 34 | }, 35 | "require-dev": { 36 | "yiisoft/yii2-swiftmailer": "*", 37 | "yiisoft/yii2-coding-standards": "~2.0", 38 | "cweagans/composer-patches": "^1.7", 39 | "phpunit/phpunit": "4.8.34" 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "yii\\debug\\": "src" 44 | } 45 | }, 46 | "autoload-dev": { 47 | "psr-4": { 48 | "yiiunit\\debug\\": "tests" 49 | } 50 | }, 51 | "extra": { 52 | "branch-alias": { 53 | "dev-master": "2.0.x-dev" 54 | }, 55 | "composer-exit-on-patch-failure": true, 56 | "patches": { 57 | "phpunit/phpunit-mock-objects": { 58 | "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" 59 | }, 60 | "phpunit/phpunit": { 61 | "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", 62 | "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch", 63 | "Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php81.patch" 64 | } 65 | } 66 | }, 67 | "repositories": [ 68 | { 69 | "type": "composer", 70 | "url": "https://asset-packagist.org" 71 | } 72 | ], 73 | "config": { 74 | "allow-plugins": { 75 | "cweagans/composer-patches": true, 76 | "yiisoft/yii2-composer": true 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/DbAsset.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class DebugAsset extends AssetBundle 19 | { 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public $sourcePath = '@yii/debug/assets'; 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public $css = [ 28 | 'css/main.css', 29 | 'css/toolbar.css', 30 | ]; 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public $js = [ 35 | 'js/polyfill.min.js', 36 | 'js/bs4-native.min.js' 37 | ]; 38 | } 39 | -------------------------------------------------------------------------------- /src/TimelineAsset.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0.7 17 | */ 18 | class TimelineAsset extends AssetBundle 19 | { 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public $sourcePath = '@yii/debug/assets'; 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public $css = [ 28 | 'css/timeline.css', 29 | ]; 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public $js = [ 34 | 'js/timeline.js', 35 | ]; 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public $depends = [ 40 | 'yii\debug\DebugAsset' 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /src/UserswitchAsset.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0.10 17 | */ 18 | class UserswitchAsset extends AssetBundle 19 | { 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public $sourcePath = '@yii/debug/assets'; 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public $js = [ 28 | 'js/userswitch.js', 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /src/actions/db/ExplainAction.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 2.0.6 19 | */ 20 | class ExplainAction extends Action 21 | { 22 | /** 23 | * @var DbPanel 24 | */ 25 | public $panel; 26 | 27 | 28 | /** 29 | * Runs the action. 30 | * 31 | * @param string $seq 32 | * @param string $tag 33 | * @return string 34 | * @throws HttpException 35 | * @throws \yii\db\Exception 36 | * @throws \yii\web\NotFoundHttpException if the view file cannot be found 37 | * @throws \yii\base\InvalidConfigException 38 | */ 39 | public function run($seq, $tag) 40 | { 41 | $this->controller->loadData($tag); 42 | 43 | $timings = $this->panel->calculateTimings(); 44 | 45 | if (!isset($timings[$seq])) { 46 | throw new HttpException(404, 'Log message not found.'); 47 | } 48 | 49 | $query = $timings[$seq]['info']; 50 | 51 | $results = $this->panel->getDb()->createCommand('EXPLAIN ' . $query)->queryAll(); 52 | 53 | $output[] = '' . implode(array_map(function ($key) { 54 | return ''; 55 | }, array_keys($results[0]))) . ''; 56 | 57 | foreach ($results as $result) { 58 | $output[] = '' . implode(array_map(function ($value) { 59 | return ''; 60 | }, $result)) . ''; 61 | } 62 | $output[] = '
' . $key . '
' . (empty($value) ? 'NULL' : htmlspecialchars($value)) . '
'; 63 | return implode($output); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/assets/.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | -------------------------------------------------------------------------------- /src/assets/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | for file in main toolbar timeline; do sass scss/$file.scss css/$file.css --no-source-map --style=compressed; done 3 | -------------------------------------------------------------------------------- /src/assets/css/.gitignore: -------------------------------------------------------------------------------- 1 | *.map 2 | -------------------------------------------------------------------------------- /src/assets/css/timeline.css: -------------------------------------------------------------------------------- 1 | .debug-timeline-panel{border:1px solid #ddd;position:relative;margin-bottom:20px}.debug-timeline-panel.inline .debug-timeline-panel__item{height:20px;margin-top:-20px;border-bottom:0}.debug-timeline-panel.inline .debug-timeline-panel__item:first-child{margin:0}.debug-timeline-panel.inline .debug-timeline-panel__item:not(.empty):hover{background-color:transparent}.debug-timeline-panel.inline .debug-timeline-panel__items .time{box-shadow:inset 0 0 3px -1px rgba(255,255,255,.7)}.debug-timeline-panel.inline .debug-timeline-panel__items .category{display:none}.debug-timeline-panel.inline .ruler.ruler-start,.debug-timeline-panel.inline .ruler.ruler-end{display:none}.debug-timeline-panel:not(.inline) .debug-timeline-panel__item a:focus{outline:none}.debug-timeline-panel:not(.inline) .debug-timeline-panel__header .control button.inline,.debug-timeline-panel.inline .debug-timeline-panel__header .control button.open{display:block}.debug-timeline-panel .category{opacity:1;font-size:10px;position:absolute;line-height:20px;padding:0 10px;color:#222;white-space:nowrap;cursor:pointer}.debug-timeline-panel .category span{color:#7d7d7d}.debug-timeline-panel .category span .memory[title]{cursor:help;border-bottom:1px dotted #777}.debug-timeline-panel .right>.category{right:100%}.debug-timeline-panel .left>.category{left:100%}.debug-timeline-panel .ruler{position:absolute;content:"";font-size:10px;padding-left:2px;top:0;height:100%;border-left:1px solid #ddd}.debug-timeline-panel .ruler.ruler-start{top:auto;margin-top:20px}.debug-timeline-panel .ruler.ruler-end{left:-1px;top:auto}.debug-timeline-panel .ruler b{position:absolute;z-index:2;color:#000;font-weight:bold;white-space:nowrap;background-color:rgba(255,255,255,.4);min-width:40px;line-height:19px;display:block;text-align:center}.debug-timeline-panel .time{position:relative;min-height:20px;display:block;min-width:1px;padding:0;background-color:#989898}.debug-timeline-panel .time+.tooltip .tooltip-inner{max-width:300px;max-height:180px;overflow:auto;word-wrap:break-word;overflow-wrap:break-word}.debug-timeline-panel__header{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background:#fff;position:-webkit-sticky;position:sticky;top:0;z-index:1}.debug-timeline-panel__header .ruler:first-child{border-left:none}.debug-timeline-panel__header .control{position:absolute;margin-left:-20px;top:0}.debug-timeline-panel__header .control button{display:none;padding:0}.debug-timeline-panel__header .control button:focus{outline:none}.debug-timeline-panel__header .control button:hover{fill:#337ab7}.debug-timeline-panel__item:last-child{border-bottom:0}.debug-timeline-panel__item:nth-child(2n){background-color:#f9f9f9}.debug-timeline-panel__item:hover{background-color:rgba(51,122,183,.16)}.debug-timeline-panel__item.empty{background-color:#f9f9f9;line-height:20px;padding-left:10px}.debug-timeline-panel__item.empty span{position:absolute;background-color:inherit}.debug-timeline-panel__header,.debug-timeline-panel__item{min-height:20px;border-bottom:1px solid #ddd;overflow:hidden}.debug-timeline-panel__search{background-color:#f9f9f9;padding:10px;margin-bottom:10px;font-size:16px}.debug-timeline-panel__search>div{display:inline-block;margin-bottom:10px}.debug-timeline-panel__search .duration{margin-right:20px}.debug-timeline-panel__search label{width:80px}.debug-timeline-panel__search input{font-size:16px;padding:4px}.debug-timeline-panel__search input#timeline-duration{width:55px;text-align:right}.debug-timeline-panel__search input#timeline-category{min-width:185px}.debug-timeline-panel__memory{position:relative;margin-top:18px;box-sizing:content-box;border-bottom:1px solid #ddd}.debug-timeline-panel__memory svg{width:100%}.debug-timeline-panel__memory .scale{font-size:12px;line-height:16px;position:absolute;border-bottom:1px dashed #000;width:100%;padding-left:6px;transition:bottom .2s ease}@media(max-width: 767px){.debug-timeline-panel .ruler:nth-child(2n) b{display:none}}@media(max-width: 991px){.debug-timeline-panel__header .control{margin-left:-17px}} 2 | -------------------------------------------------------------------------------- /src/assets/js/db.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var on = function (element, event, handler) { 5 | var i; 6 | if (null === element) { 7 | return; 8 | } 9 | if (element instanceof NodeList) { 10 | for (i = 0; i < element.length; i++) { 11 | element[i].addEventListener(event, handler, false); 12 | } 13 | return; 14 | } 15 | if (!(element instanceof Array)) { 16 | element = [element]; 17 | } 18 | for (i in element) { 19 | if (typeof element[i].addEventListener !== 'function') { 20 | continue; 21 | } 22 | element[i].addEventListener(event, handler, false); 23 | } 24 | }, ajax = function (url, settings) { 25 | var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); 26 | settings = settings || {}; 27 | xhr.open(settings.method || 'GET', url, true); 28 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 29 | xhr.setRequestHeader('Accept', 'text/html'); 30 | xhr.onreadystatechange = function () { 31 | if (xhr.readyState === 4) { 32 | if (xhr.status === 200 && settings.success) { 33 | settings.success(xhr); 34 | } else if (xhr.status !== 200 && settings.error) { 35 | settings.error(xhr); 36 | } 37 | } 38 | }; 39 | xhr.send(settings.data || ''); 40 | }; 41 | 42 | on(document.querySelectorAll('.db-explain a'), 'click', function (e) { 43 | if (e.target.tagName.toLowerCase() !== 'a') { 44 | return; 45 | } 46 | 47 | e.preventDefault(); 48 | 49 | var $explain = e.target.parentElement.parentElement.querySelector('.db-explain-text'), 50 | self = this; 51 | 52 | // hidden (see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent) 53 | if ($explain.offsetParent === null) { 54 | ajax(this.href, { 55 | success: function (xhr) { 56 | $explain.innerHTML = xhr.responseText; 57 | $explain.style.display = 'block'; 58 | self.textContent = '[-] Explain'; 59 | } 60 | }) 61 | } else { 62 | $explain.style.display = 'none'; 63 | this.textContent = '[+] Explain'; 64 | } 65 | }); 66 | 67 | on(document.querySelectorAll('.db-explain-all a'), 'click', function () { 68 | var event = new MouseEvent('click', { 69 | cancelable: true, 70 | bubbles: true 71 | }); 72 | 73 | var elements = document.querySelectorAll('.db-explain a'); 74 | for (var i = 0, len = elements.length; i < len; i++) { 75 | elements[i].dispatchEvent(event); 76 | } 77 | }); 78 | })(); 79 | -------------------------------------------------------------------------------- /src/assets/js/polyfill.min.js: -------------------------------------------------------------------------------- 1 | // Native JavaScript for Bootstrap 3/4 Polyfill 2 | (function(){var F="Document",i=document,g=this[F]||this.HTMLDocument,l="Window",E=window,p=this.constructor||this[l]||Window,u="HTMLElement",k="documentElement",D=Element,J="className",d="add",c="classList",x="remove",z="contains",s="class",e="setAttribute",A="getAttribute",t="prototype",o="indexOf",r="length",y="split",b="trim",f="Event",I="CustomEvent",C="_events",n="type",a="target",m="currentTarget",B="relatedTarget",v="cancelable",q="bubbles",w="cancelBubble",H="cancelImmediate",K="detail",L="addEventListener",h="removeEventListener",j="dispatchEvent";if(!E[u]){E[u]=E[D]}if(!Array[t][o]){Array[t][o]=function(O){if(this===undefined||this===null){throw new TypeError(this+" is not an object")}var N=this instanceof String?this[y](""):this,P=Math.max(Math.min(N[r],9007199254740991),0)||0,M=Number(arguments[1])||0;M=(M<0?Math.max(P+M,0):M)-1;while(++M-1},addClass=this[d]=function(O){if(!hasClass(O)){N.push(O);M[e](s,N.join(" "))}},removeClass=this[x]=function(O){if(hasClass(O)){N.splice(N[o](O),1);M[e](s,N.join(" "))}},toggleClass=this.toggle=function(O){if(hasClass(O)){removeClass(O)}else{addClass(O)}}};Object.defineProperty(D[t],c,{get:function(){return new G(this)}})}if(!E[f]||!p[t][f]){E[f]=p[t][f]=g[t][f]=D[t][f]=function(O,Q){if(!O){throw new Error("Not enough arguments")}var P,N=Q&&Q[q]!==undefined?Q[q]:false,M=Q&&Q[v]!==undefined?Q[v]:false;if("createEvent" in i){P=i.createEvent(f);P.initEvent(O,N,M)}else{P=i.createEventObject();P[n]=O;P[q]=N;P[v]=M}return P}}if(!(I in E)||!(I in p[t])){E[I]=p[t][I]=g[t][I]=Element[t][I]=function(M,O){if(!M){throw Error("CustomEvent TypeError: An event name must be provided.")}var N=new Event(M,O);N[K]=O&&O[K]||null;return N}}if(!E[L]||!p[t][L]){E[L]=p[t][L]=g[t][L]=D[t][L]=function(){var M=this,N=arguments[0],O=arguments[1];if(!M[C]){M[C]={}}if(!M[C][N]){M[C][N]=function(T){var U=M[C][T[n]].list,R=U.slice(),Q=-1,S=R[r],P;T.preventDefault=function(){if(T[v]!==false){T.returnValue=false}};T.stopPropagation=function(){T[w]=true};T.stopImmediatePropagation=function(){T[w]=true;T[H]=true};T[m]=M;T[B]=T[B]||T.fromElement||null;T[a]=T[a]||T.srcElement||M;T.timeStamp=new Date().getTime();if(T.clientX){T.pageX=T.clientX+i[k].scrollLeft;T.pageY=T.clientY+i[k].scrollTop}while(++Q 2 | -------------------------------------------------------------------------------- /src/assets/scss/bs-4.3.1/_alert.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .alert { 6 | position: relative; 7 | padding: $alert-padding-y $alert-padding-x; 8 | margin-bottom: $alert-margin-bottom; 9 | border: $alert-border-width solid transparent; 10 | @include border-radius($alert-border-radius); 11 | } 12 | 13 | // Headings for larger alerts 14 | .alert-heading { 15 | // Specified to prevent conflicts of changing $headings-color 16 | color: inherit; 17 | } 18 | 19 | // Provide class for links that match alerts 20 | .alert-link { 21 | font-weight: $alert-link-font-weight; 22 | } 23 | 24 | 25 | // Dismissible alerts 26 | // 27 | // Expand the right padding and account for the close button's positioning. 28 | 29 | .alert-dismissible { 30 | padding-right: $close-font-size + $alert-padding-x * 2; 31 | 32 | // Adjust close link position 33 | .close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | padding: $alert-padding-y $alert-padding-x; 38 | color: inherit; 39 | } 40 | } 41 | 42 | 43 | // Alternate styles 44 | // 45 | // Generate contextual modifier classes for colorizing the alert. 46 | 47 | @each $color, $value in $theme-colors { 48 | .alert-#{$color} { 49 | @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/assets/scss/bs-4.3.1/_badge.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Requires one of the contextual, color modifier classes for `color` and 4 | // `background-color`. 5 | 6 | .badge { 7 | display: inline-block; 8 | padding: $badge-padding-y $badge-padding-x; 9 | @include font-size($badge-font-size); 10 | font-weight: $badge-font-weight; 11 | line-height: 1; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | @include border-radius($badge-border-radius); 16 | @include transition($badge-transition); 17 | 18 | @at-root a#{&} { 19 | @include hover-focus { 20 | text-decoration: none; 21 | } 22 | } 23 | 24 | // Empty badges collapse automatically 25 | &:empty { 26 | display: none; 27 | } 28 | } 29 | 30 | // Quick fix for badges in buttons 31 | .btn .badge { 32 | position: relative; 33 | top: -1px; 34 | } 35 | 36 | // Pill badges 37 | // 38 | // Make them extra rounded with a modifier to replace v3's badges. 39 | 40 | .badge-pill { 41 | padding-right: $badge-pill-padding-x; 42 | padding-left: $badge-pill-padding-x; 43 | @include border-radius($badge-pill-border-radius); 44 | } 45 | 46 | // Colors 47 | // 48 | // Contextual variations (linked badges get darker on :hover). 49 | 50 | @each $color, $value in $theme-colors { 51 | .badge-#{$color} { 52 | @include badge-variant($value); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/assets/scss/bs-4.3.1/_breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: flex; 3 | flex-wrap: wrap; 4 | padding: $breadcrumb-padding-y $breadcrumb-padding-x; 5 | margin-bottom: $breadcrumb-margin-bottom; 6 | list-style: none; 7 | background-color: $breadcrumb-bg; 8 | @include border-radius($breadcrumb-border-radius); 9 | } 10 | 11 | .breadcrumb-item { 12 | // The separator between breadcrumbs (by default, a forward-slash: "/") 13 | + .breadcrumb-item { 14 | padding-left: $breadcrumb-item-padding; 15 | 16 | &::before { 17 | display: inline-block; // Suppress underlining of the separator in modern browsers 18 | padding-right: $breadcrumb-item-padding; 19 | color: $breadcrumb-divider-color; 20 | content: $breadcrumb-divider; 21 | } 22 | } 23 | 24 | // IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built 25 | // without `