Index: trunk/phase3/RELEASE-NOTES-1.19 |
— | — | @@ -97,6 +97,7 @@ |
98 | 98 | * (bug 32666) Special:ActiveUsers now allows a subpage to be used as the |
99 | 99 | username (eg. Special:ActiveUsers/Username) |
100 | 100 | * New JavaScript variable wgPageContentLanguage |
| 101 | +* Added new debugging toolbar, enabled with $wgDebugToolbar |
101 | 102 | |
102 | 103 | === Bug fixes in 1.19 === |
103 | 104 | * $wgUploadNavigationUrl should be used for file redlinks if. |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -374,7 +374,7 @@ |
375 | 375 | */ |
376 | 376 | public function view() { |
377 | 377 | global $wgUser, $wgOut, $wgRequest, $wgParser; |
378 | | - global $wgUseFileCache, $wgUseETag; |
| 378 | + global $wgUseFileCache, $wgUseETag, $wgDebugToolbar; |
379 | 379 | |
380 | 380 | wfProfileIn( __METHOD__ ); |
381 | 381 | |
— | — | @@ -429,7 +429,7 @@ |
430 | 430 | } |
431 | 431 | |
432 | 432 | # Try client and file cache |
433 | | - if ( $oldid === 0 && $this->mPage->checkTouched() ) { |
| 433 | + if ( !$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched() ) { |
434 | 434 | if ( $wgUseETag ) { |
435 | 435 | $wgOut->setETag( $parserCache->getETag( $this, $parserOptions ) ); |
436 | 436 | } |
Index: trunk/phase3/includes/GlobalFunctions.php |
— | — | @@ -835,6 +835,8 @@ |
836 | 836 | wfErrorLog( $text, $wgDebugLogFile ); |
837 | 837 | } |
838 | 838 | } |
| 839 | + |
| 840 | + MWDebug::debugMsg( $text ); |
839 | 841 | } |
840 | 842 | |
841 | 843 | /** |
Index: trunk/phase3/includes/db/Database.php |
— | — | @@ -840,9 +840,13 @@ |
841 | 841 | throw new MWException( 'Tainted query found' ); |
842 | 842 | } |
843 | 843 | |
| 844 | + $queryId = MWDebug::query( $sql, $fname, $isMaster ); |
| 845 | + |
844 | 846 | # Do the query and handle errors |
845 | 847 | $ret = $this->doQuery( $commentedSql ); |
846 | 848 | |
| 849 | + MWDebug::queryTime( $queryId ); |
| 850 | + |
847 | 851 | # Try reconnecting if the connection was lost |
848 | 852 | if ( false === $ret && $this->wasErrorReissuable() ) { |
849 | 853 | # Transaction is gone, like it or not |
Index: trunk/phase3/includes/Setup.php |
— | — | @@ -328,6 +328,8 @@ |
329 | 329 | $wgCookieSecure = ( substr( $wgServer, 0, 6 ) === 'https:' ); |
330 | 330 | } |
331 | 331 | |
| 332 | +MWDebug::init(); |
| 333 | + |
332 | 334 | if ( !defined( 'MW_COMPILED' ) ) { |
333 | 335 | if ( !MWInit::classExists( 'AutoLoader' ) ) { |
334 | 336 | require_once( "$IP/includes/AutoLoader.php" ); |
— | — | @@ -392,6 +394,7 @@ |
393 | 395 | } |
394 | 396 | } |
395 | 397 | wfDebug( "$debug\n" ); |
| 398 | + MWDebug::processRequest( $wgRequest ); |
396 | 399 | } |
397 | 400 | |
398 | 401 | wfProfileOut( $fname . '-misc1' ); |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -436,6 +436,9 @@ |
437 | 437 | 'ResultWrapper' => 'includes/db/DatabaseUtility.php', |
438 | 438 | 'SQLiteField' => 'includes/db/DatabaseSqlite.php', |
439 | 439 | |
| 440 | + # includes/debug |
| 441 | + 'MWDebug' => 'includes/debug/Debug.php', |
| 442 | + |
440 | 443 | # includes/diff |
441 | 444 | '_DiffEngine' => 'includes/diff/DairikiDiff.php', |
442 | 445 | '_DiffOp' => 'includes/diff/DairikiDiff.php', |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -4160,6 +4160,14 @@ |
4161 | 4161 | */ |
4162 | 4162 | $wgWikiID = false; |
4163 | 4163 | |
| 4164 | +/** |
| 4165 | + * Display the new debugging toolbar. This also enables profiling on database |
| 4166 | + * queries and other useful output. |
| 4167 | + * |
| 4168 | + * @since 1.19 |
| 4169 | + */ |
| 4170 | +$wgDebugToolbar = false; |
| 4171 | + |
4164 | 4172 | /** @} */ # end of profiling, testing and debugging } |
4165 | 4173 | |
4166 | 4174 | /************************************************************************//** |
Index: trunk/phase3/includes/Skin.php |
— | — | @@ -531,13 +531,15 @@ |
532 | 532 | protected function generateDebugHTML() { |
533 | 533 | global $wgShowDebug; |
534 | 534 | |
| 535 | + $html = MWDebug::getDebugHTML(); |
| 536 | + |
535 | 537 | if ( $wgShowDebug ) { |
536 | 538 | $listInternals = $this->formatDebugHTML( $this->getOutput()->mDebugtext ); |
537 | | - return "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">" . |
| 539 | + $html .= "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">" . |
538 | 540 | $listInternals . "</ul>\n"; |
539 | 541 | } |
540 | 542 | |
541 | | - return ''; |
| 543 | + return $html; |
542 | 544 | } |
543 | 545 | |
544 | 546 | /** |
Index: trunk/phase3/resources/Resources.php |
— | — | @@ -489,6 +489,10 @@ |
490 | 490 | 'debugScripts' => 'resources/mediawiki/mediawiki.log.js', |
491 | 491 | 'debugRaw' => false, |
492 | 492 | ), |
| 493 | + 'mediawiki.debug' => array( |
| 494 | + 'scripts' => 'resources/mediawiki/mediawiki.debug.js', |
| 495 | + 'styles' => 'resources/mediawiki/mediawiki.debug.css', |
| 496 | + ), |
493 | 497 | 'mediawiki.htmlform' => array( |
494 | 498 | 'scripts' => 'resources/mediawiki/mediawiki.htmlform.js', |
495 | 499 | ), |
Index: trunk/phase3/resources/mediawiki/mediawiki.debug.css |
— | — | @@ -0,0 +1,111 @@ |
| 2 | +.mw-debug { |
| 3 | + width: 100%; |
| 4 | + text-align: left; |
| 5 | + position: fixed; |
| 6 | + bottom: 0; |
| 7 | + background-color: #eee; |
| 8 | + border-top: 1px solid #ccc; |
| 9 | +} |
| 10 | + |
| 11 | +.mw-debug pre { |
| 12 | + font-family: Monaco, "Consolas", "Lucida Console", "Courier New", monospace; |
| 13 | + font-size: 11px; |
| 14 | + padding: 0; |
| 15 | + margin: 0; |
| 16 | + background: none; |
| 17 | + border: none; |
| 18 | +} |
| 19 | + |
| 20 | +.mw-debug ul { |
| 21 | + margin: 0; |
| 22 | + list-style: none; |
| 23 | + box-sizing: border-box; |
| 24 | +} |
| 25 | + |
| 26 | +.mw-debug li { |
| 27 | + padding: 2px 5px; |
| 28 | + width: 100%; |
| 29 | + display: table; |
| 30 | +} |
| 31 | + |
| 32 | +.mw-debug-bit { |
| 33 | + min-height: 25px; |
| 34 | + display: inline-block; |
| 35 | + padding: 5px; |
| 36 | + border-right: 1px solid #ccc; |
| 37 | + font-size: 13px; |
| 38 | +} |
| 39 | + |
| 40 | +.mw-debug-pane { |
| 41 | + max-height: 300px; |
| 42 | + overflow: scroll; |
| 43 | + border-top: 2px solid #ccc; |
| 44 | + display: none; |
| 45 | + font-size: 11px; |
| 46 | + background-color: #e1eff2; |
| 47 | + box-sizing: border-box; |
| 48 | +} |
| 49 | + |
| 50 | +.mw-debug-right { |
| 51 | + float: right; |
| 52 | +} |
| 53 | + |
| 54 | +#mw-debug-querylist tr { |
| 55 | + |
| 56 | +} |
| 57 | + |
| 58 | +#mw-debug-querylist td { |
| 59 | + padding: 2px 5px; |
| 60 | + border-bottom: 1px solid #ccc; |
| 61 | +} |
| 62 | + |
| 63 | +.mw-debug-query-time { |
| 64 | + color: #808080; |
| 65 | +} |
| 66 | + |
| 67 | +#mw-debug-pane-request { |
| 68 | + padding: 20px; |
| 69 | +} |
| 70 | + |
| 71 | +#mw-debug-pane-request table { |
| 72 | + width: 100%; |
| 73 | + margin: 10px 0 30px; |
| 74 | +} |
| 75 | + |
| 76 | +#mw-debug-pane-request tr, |
| 77 | +#mw-debug-pane-request th, |
| 78 | +#mw-debug-pane-request td, |
| 79 | +#mw-debug-pane-request table { |
| 80 | + border: 1px solid #D0DBB3; |
| 81 | + border-collapse: collapse; |
| 82 | + margin: 0; |
| 83 | +} |
| 84 | + |
| 85 | +#mw-debug-pane-request th, |
| 86 | +#mw-debug-pane-request td { |
| 87 | + font-size: 12px; |
| 88 | + padding: 8px 10px; |
| 89 | +} |
| 90 | + |
| 91 | +#mw-debug-pane-request th { |
| 92 | + background-color: #F1F7E2; |
| 93 | + font-weight: bold; |
| 94 | +} |
| 95 | + |
| 96 | +#mw-debug-pane-request td { |
| 97 | + background-color: white; |
| 98 | +} |
| 99 | + |
| 100 | +#mw-debug-pane-querylist table { |
| 101 | + border-spacing: 0; |
| 102 | +} |
| 103 | + |
| 104 | +#mw-debug-pane-includes li, |
| 105 | +#mw-debug-pane-querylist tr td { |
| 106 | + background-color: #ccc; |
| 107 | +} |
| 108 | + |
| 109 | +#mw-debug-pane-includes li:nth-child(odd), |
| 110 | +#mw-debug-pane-querylist tr:nth-child(odd) td { |
| 111 | + background-color: #ddd; |
| 112 | +} |
Index: trunk/phase3/resources/mediawiki/mediawiki.debug.js |
— | — | @@ -0,0 +1,208 @@ |
| 2 | +/** |
| 3 | + * Javascript for the new debug toolbar, enabled with $wgDebugToolbar |
| 4 | + * |
| 5 | + * @author John Du Hart |
| 6 | + * @since 1.19 |
| 7 | + */ |
| 8 | + |
| 9 | +( function( $ ) { |
| 10 | + |
| 11 | + var debug = mw.Debug = { |
| 12 | + /** |
| 13 | + * Toolbar container element |
| 14 | + * |
| 15 | + * @var {jQuery} |
| 16 | + */ |
| 17 | + $container: null, |
| 18 | + |
| 19 | + /** |
| 20 | + * Array containing data for the debug toolbar |
| 21 | + * |
| 22 | + * @var {Array} |
| 23 | + */ |
| 24 | + data: {}, |
| 25 | + |
| 26 | + /** |
| 27 | + * Initializes the debugging pane |
| 28 | + * |
| 29 | + * @param {Array} data |
| 30 | + */ |
| 31 | + init: function( data ) { |
| 32 | + this.data = data; |
| 33 | + this.buildHtml(); |
| 34 | + |
| 35 | + // Insert the container into the DOM |
| 36 | + $( 'body' ).append( this.$container ); |
| 37 | + |
| 38 | + $( '.mw-debug-panelink' ).click( this.switchPane ); |
| 39 | + }, |
| 40 | + |
| 41 | + /** |
| 42 | + * Switches between panes |
| 43 | + * |
| 44 | + * @todo Store cookie for last pane open |
| 45 | + * @context {Element} |
| 46 | + * @param {jQuery.Event} e |
| 47 | + */ |
| 48 | + switchPane: function( e ) { |
| 49 | + var currentPaneId = debug.$container.data( 'currentPane' ), |
| 50 | + requestedPaneId = $(this).parent().attr( 'id' ).substr( 9 ), |
| 51 | + $currentPane = $( '#mw-debug-pane-' + currentPaneId ), |
| 52 | + $requestedPane = $( '#mw-debug-pane-' + requestedPaneId ); |
| 53 | + e.preventDefault(); |
| 54 | + |
| 55 | + // Hide the current pane |
| 56 | + if ( requestedPaneId === currentPaneId ) { |
| 57 | + $currentPane.slideUp(); |
| 58 | + debug.$container.data( 'currentPane', null ); |
| 59 | + return; |
| 60 | + } |
| 61 | + |
| 62 | + debug.$container.data( 'currentPane', requestedPaneId ); |
| 63 | + |
| 64 | + if ( currentPaneId === undefined || currentPaneId === null ) { |
| 65 | + $requestedPane.slideDown(); |
| 66 | + } else { |
| 67 | + $currentPane.hide(); |
| 68 | + $requestedPane.show(); |
| 69 | + } |
| 70 | + }, |
| 71 | + |
| 72 | + /** |
| 73 | + * Constructs the HTML for the debugging toolbar |
| 74 | + */ |
| 75 | + buildHtml: function() { |
| 76 | + this.$container = $( '<div></div>' ) |
| 77 | + .attr({ |
| 78 | + id: 'mw-debug-container', |
| 79 | + class: 'mw-debug' |
| 80 | + }); |
| 81 | + |
| 82 | + var html = ''; |
| 83 | + |
| 84 | + html += '<div class="mw-debug-bit" id="mw-debug-mwversion">' |
| 85 | + + '<a href="https://www.mediawiki.org//www.mediawiki.org/">MediaWiki</a>: ' |
| 86 | + + this.data.mwVersion + '</div>'; |
| 87 | + |
| 88 | + html += '<div class="mw-debug-bit" id="mw-debug-phpversion">' |
| 89 | + + '<a href="https://www.mediawiki.org//www.php.net/">PHP</a>: ' |
| 90 | + + this.data.phpVersion + '</div>'; |
| 91 | + |
| 92 | + html += '<div class="mw-debug-bit" id="mw-debug-time">' |
| 93 | + + 'Time: ' + this.data.time.toFixed( 5 ) + 's</div>'; |
| 94 | + html += '<div class="mw-debug-bit" id="mw-debug-memory">' |
| 95 | + + 'Memory: ' + this.data.memory + ' (<span title="Peak usage">' |
| 96 | + + this.data.memoryPeak + '</span>)</div>'; |
| 97 | + |
| 98 | + var queryLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-query-link">Queries: ' |
| 99 | + + this.data.queries.length + '</a>'; |
| 100 | + html += '<div class="mw-debug-bit" id="mw-debug-querylist">' |
| 101 | + + queryLink + '</div>'; |
| 102 | + |
| 103 | + var debugLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-debuglog-link">Debug Log (' |
| 104 | + + this.data.debugLog.length + ' lines)</a>'; |
| 105 | + html += '<div class="mw-debug-bit" id="mw-debug-debuglog">' |
| 106 | + + debugLink + '</div>'; |
| 107 | + |
| 108 | + var requestLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-request-link">Request</a>'; |
| 109 | + html += '<div class="mw-debug-bit" id="mw-debug-request">' |
| 110 | + + requestLink + '</div>'; |
| 111 | + |
| 112 | + var filesLink = '<a href="#" class="mw-debug-panelink" id="mw-debug-files-includes">' |
| 113 | + + this.data.includes.length + ' Files Included</a>'; |
| 114 | + html += '<div class="mw-debug-bit" id="mw-debug-includes">' |
| 115 | + + filesLink + '</div>'; |
| 116 | + |
| 117 | + html += '<div class="mw-debug-pane" id="mw-debug-pane-querylist">' |
| 118 | + + this.buildQueryTable() + '</div>'; |
| 119 | + html += '<div class="mw-debug-pane" id="mw-debug-pane-debuglog">' |
| 120 | + + this.buildDebugLogTable() + '</div>'; |
| 121 | + html += '<div class="mw-debug-pane" id="mw-debug-pane-request">' |
| 122 | + + this.buildRequestPane() + '</div>'; |
| 123 | + html += '<div class="mw-debug-pane" id="mw-debug-pane-includes">' |
| 124 | + + this.buildIncludesPane() + '</div>'; |
| 125 | + |
| 126 | + this.$container.html( html ); |
| 127 | + }, |
| 128 | + |
| 129 | + /** |
| 130 | + * Query list pane |
| 131 | + */ |
| 132 | + buildQueryTable: function() { |
| 133 | + var html = '<table id="mw-debug-querylist">'; |
| 134 | + |
| 135 | + for ( var i = 0, length = this.data.queries.length; i < length; i++ ) { |
| 136 | + var query = this.data.queries[i]; |
| 137 | + |
| 138 | + html += '<tr><td>' + ( i + 1 ) + '</td>'; |
| 139 | + |
| 140 | + html += '<td>' + query.sql + '</td>'; |
| 141 | + html += '<td><span class="mw-debug-query-time">(' + query.time.toFixed( 4 ) + 'ms)</span> ' + query.function + '</td>'; |
| 142 | + |
| 143 | + html += '</tr>'; |
| 144 | + } |
| 145 | + |
| 146 | + html += '</table>'; |
| 147 | + |
| 148 | + return html; |
| 149 | + }, |
| 150 | + |
| 151 | + /** |
| 152 | + * Legacy debug log pane |
| 153 | + */ |
| 154 | + buildDebugLogTable: function() { |
| 155 | + var html = '<ul>'; |
| 156 | + |
| 157 | + for ( var i = 0, length = this.data.debugLog.length; i < length; i++ ) { |
| 158 | + var line = this.data.debugLog[i]; |
| 159 | + html += '<li>' + line.replace( /\n/g, "<br />\n" ) + '</li>'; |
| 160 | + } |
| 161 | + |
| 162 | + return html + '</ul>'; |
| 163 | + }, |
| 164 | + |
| 165 | + /** |
| 166 | + * Request information pane |
| 167 | + */ |
| 168 | + buildRequestPane: function() { |
| 169 | + var buildTable = function( title, data ) { |
| 170 | + var t = '<h2>' + title + '</h2>' |
| 171 | + + '<table> <tr> <th>Key</th> <th>Value</th> </tr>'; |
| 172 | + |
| 173 | + for ( var key in data ) { |
| 174 | + if ( !data.hasOwnProperty( key ) ) { |
| 175 | + continue; |
| 176 | + } |
| 177 | + var value = data[key]; |
| 178 | + |
| 179 | + t += '<tr><th>' + key + '</th><td>' + value + '</td></tr>'; |
| 180 | + } |
| 181 | + |
| 182 | + t += '</table>'; |
| 183 | + return t; |
| 184 | + }; |
| 185 | + |
| 186 | + var html = this.data.request.method + ' ' + this.data.request.url; |
| 187 | + html += buildTable( 'Headers', this.data.request.headers ); |
| 188 | + html += buildTable( 'Parameters', this.data.request.params ); |
| 189 | + |
| 190 | + return html; |
| 191 | + }, |
| 192 | + |
| 193 | + /** |
| 194 | + * Included files pane |
| 195 | + */ |
| 196 | + buildIncludesPane: function() { |
| 197 | + var html = '<ul>'; |
| 198 | + |
| 199 | + for ( var i = 0, l = this.data.includes.length; i < l; i++ ) { |
| 200 | + var file = this.data.includes[i]; |
| 201 | + html += '<li><span class="mw-debug-right">' + file.size + '</span> ' + file.name + '</li>'; |
| 202 | + } |
| 203 | + |
| 204 | + html += '</ul>'; |
| 205 | + return html; |
| 206 | + } |
| 207 | + }; |
| 208 | + |
| 209 | +} )( jQuery ); |
\ No newline at end of file |