r85434 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85433‎ | r85434 | r85435 >
Date:13:38, 5 April 2011
Author:demon
Status:ok
Tags:
Comment:
Modified paths:
  • /branches/REL1_17/phase3 (modified) (history)
  • /branches/REL1_17/phase3/HISTORY (modified) (history)
  • /branches/REL1_17/phase3/RELEASE-NOTES (modified) (history)
  • /branches/REL1_17/phase3/includes/AutoLoader.php (modified) (history)
  • /branches/REL1_17/phase3/includes/DefaultSettings.php (modified) (history)
  • /branches/REL1_17/phase3/includes/ImageGallery.php (modified) (history)
  • /branches/REL1_17/phase3/includes/OutputPage.php (modified) (history)
  • /branches/REL1_17/phase3/includes/api/ApiQueryBase.php (modified) (history)
  • /branches/REL1_17/phase3/includes/api/ApiQueryCategoryMembers.php (modified) (history)
  • /branches/REL1_17/phase3/includes/job/JobQueue.php (modified) (history)
  • /branches/REL1_17/phase3/includes/libs (modified) (history)
  • /branches/REL1_17/phase3/includes/libs/CSSMin.php (modified) (history)
  • /branches/REL1_17/phase3/includes/libs/JavaScriptMinifier.php (added) (history)
  • /branches/REL1_17/phase3/includes/resourceloader/ResourceLoader.php (modified) (history)
  • /branches/REL1_17/phase3/includes/specials/SpecialListfiles.php (modified) (history)
  • /branches/REL1_17/phase3/includes/specials/SpecialUpload.php (modified) (history)
  • /branches/REL1_17/phase3/includes/upload/UploadBase.php (modified) (history)
  • /branches/REL1_17/phase3/maintenance/minify.php (modified) (history)
  • /branches/REL1_17/phase3/maintenance/tests/parser/parserTests.txt (modified) (history)
  • /branches/REL1_17/phase3/maintenance/update.php (modified) (history)

Diff [purge]

Index: branches/REL1_17/phase3/maintenance/update.php
@@ -35,7 +35,7 @@
3636 return 2 /* Maintenance::DB_ADMIN */;
3737 }
3838
39 - private function compatChecks() {
 39+ function compatChecks() {
4040 $test = new PhpXmlBugTester();
4141 if ( !$test->ok ) {
4242 $this->error(
Property changes on: branches/REL1_17/phase3/maintenance/update.php
___________________________________________________________________
Modified: svn:mergeinfo
4343 Merged /trunk/phase3/maintenance/update.php:r83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/maintenance/minify.php
@@ -17,9 +17,12 @@
1818 "Directory for output. If this is not specified, and neither is --outfile, then the\n" .
1919 "output files will be sent to the same directories as the input files.",
2020 false, true );
21 - $this->addOption( 'minify-vertical-space',
22 - "Boolean value for minifying the vertical space for javascript.",
 21+ $this->addOption( 'js-statements-on-own-line',
 22+ "Boolean value for putting statements on their own line when minifying JavaScript.",
2323 false, true );
 24+ $this->addOption( 'js-max-line-length',
 25+ "Maximum line length for JavaScript minification.",
 26+ false, true );
2427 $this->mDescription = "Minify a file or set of files.\n\n" .
2528 "If --outfile is not specified, then the output file names will have a .min extension\n" .
2629 "added, e.g. jquery.js -> jquery.min.js.";
@@ -81,7 +84,7 @@
8285 }
8386
8487 public function minify( $inPath, $outPath ) {
85 - global $wgResourceLoaderMinifyJSVerticalSpace;
 88+ global $wgResourceLoaderMinifierStatementsOnOwnLine, $wgResourceLoaderMinifierMaxLineLength;
8689
8790 $extension = $this->getExtension( $inPath );
8891 $this->output( basename( $inPath ) . ' -> ' . basename( $outPath ) . '...' );
@@ -99,7 +102,10 @@
100103
101104 switch ( $extension ) {
102105 case 'js':
103 - $outText = JavaScriptDistiller::stripWhiteSpace( $inText, $this->getOption( 'minify-vertical-space', $wgResourceLoaderMinifyJSVerticalSpace ) );
 106+ $outText = JavaScriptMinifier::minify( $inText,
 107+ $this->getOption( 'js-statements-on-own-line', $wgResourceLoaderMinifierStatementsOnOwnLine ),
 108+ $this->getOption( 'js-max-line-length', $wgResourceLoaderMinifierMaxLineLength )
 109+ );
104110 break;
105111 case 'css':
106112 $outText = CSSMin::minify( $inText );
Index: branches/REL1_17/phase3/maintenance/tests/parser/parserTests.txt
@@ -6658,7 +6658,7 @@
66596659 image:foobar.jpg
66606660 </gallery>
66616661 !! result
6662 -<ul class="gallery" style="max-width: 220px;_width: 220px;">
 6662+<ul class="gallery" style="max-width: 202px;_width: 202px;">
66636663 <li class='gallerycaption'>Foo <a href="https://www.mediawiki.org/wiki/Main_Page">Main Page</a></li>
66646664 <li class="gallerybox" style="width: 95px"><div style="width: 95px">
66656665 <div style="height: 70px;">Nonexistant.jpg</div>
Property changes on: branches/REL1_17/phase3/maintenance/tests/parser/parserTests.txt
___________________________________________________________________
Added: svn:mergeinfo
66666666 Merged /trunk/phase3/tests/parser/parserTests.txt:r83965
66676667 Merged /trunk/phase3/maintenance/tests/parser/parserTests.txt:r83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
66686668 Merged /branches/phpunit-restructure/maintenance/tests/parser/parserTests.txt:r72257-72560
Index: branches/REL1_17/phase3/HISTORY
@@ -221,9 +221,6 @@
222222 * Note on non-existing user and user talk pages if user does not exist
223223 * New hook ShowMissingArticle so extensions can modify the output for
224224 non-existent pages.
225 -* Added $wgUseAJAXCategories allow enabling AJAX based categories system.
226 - This works on all namespaces. Enabled namespaces can be reduces using
227 - $wgAJAXCategoriesNamespaces.
228225 * Admins could disable some variants using $wgDisabledVariants now. ONLY apply
229226 on wikis enabled LanguageConverter.
230227 * (bug 16310) Credits page now lists IP addresses rather than saying the number
Index: branches/REL1_17/phase3/includes/upload/UploadBase.php
@@ -415,7 +415,7 @@
416416
417417 $overwriteError = $this->checkOverwrite( $user );
418418 if ( $overwriteError !== true ) {
419 - return array( array( $overwriteError ) );
 419+ return array( $overwriteError );
420420 }
421421
422422 return true;
@@ -1016,14 +1016,14 @@
10171017 * Check if there's an overwrite conflict and, if so, if restrictions
10181018 * forbid this user from performing the upload.
10191019 *
1020 - * @return mixed true on success, error string on failure
 1020+ * @return mixed true on success, array on failure
10211021 */
10221022 private function checkOverwrite( $user ) {
10231023 // First check whether the local file can be overwritten
10241024 $file = $this->getLocalFile();
10251025 if( $file->exists() ) {
10261026 if( !self::userCanReUpload( $user, $file ) ) {
1027 - return 'fileexists-forbidden';
 1027+ return array( 'fileexists-forbidden', $file->getName() );
10281028 } else {
10291029 return true;
10301030 }
@@ -1034,7 +1034,7 @@
10351035 */
10361036 $file = wfFindFile( $this->getTitle() );
10371037 if ( $file && !$user->isAllowed( 'reupload-shared' ) ) {
1038 - return 'fileexists-shared-forbidden';
 1038+ return array( 'fileexists-shared-forbidden', $file->getName() );
10391039 }
10401040
10411041 return true;
Property changes on: branches/REL1_17/phase3/includes/upload/UploadBase.php
___________________________________________________________________
Modified: svn:mergeinfo
10421042 Merged /trunk/phase3/includes/upload/UploadBase.php:r83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/OutputPage.php
@@ -2422,10 +2422,12 @@
24232423 }
24242424 continue;
24252425 }
2426 - // Special handling for user and site groups; because users might change their stuff
2427 - // on-wiki like site or user pages, or user preferences; we need to find the highest
 2426+ // Special handling for the user group; because users might change their stuff
 2427+ // on-wiki like user pages, or user preferences; we need to find the highest
24282428 // timestamp of these user-changable modules so we can ensure cache misses on change
2429 - if ( $group === 'user' || $group === 'site' ) {
 2429+ // This should NOT be done for the site group (bug 27564) because anons get that too
 2430+ // and we shouldn't be putting timestamps in Squid-cached HTML
 2431+ if ( $group === 'user' ) {
24302432 // Get the maximum timestamp
24312433 $timestamp = 1;
24322434 foreach ( $modules as $module ) {
Property changes on: branches/REL1_17/phase3/includes/OutputPage.php
___________________________________________________________________
Modified: svn:mergeinfo
24332435 Merged /trunk/phase3/includes/OutputPage.php:r83891,83897,83902-83903,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/api/ApiQueryBase.php
@@ -246,14 +246,29 @@
247247 * Execute a SELECT query based on the values in the internal arrays
248248 * @param $method string Function the query should be attributed to.
249249 * You should usually use __METHOD__ here
 250+ * @param $extraQuery array Query data to add but not store in the object
 251+ * Format is array( 'tables' => ..., 'fields' => ..., 'where' => ..., 'options' => ..., 'join_conds' => ... )
250252 * @return ResultWrapper
251253 */
252 - protected function select( $method ) {
 254+ protected function select( $method, $extraQuery = array() ) {
 255+ $tables = $this->tables;
 256+ $fields = $this->fields;
 257+ $where = $this->where;
 258+ $options = $this->options;
 259+ $join_conds = $this->join_conds;
 260+
 261+ // Merge $this->tables with $extraQuery['tables'], $this->fields with $extraQuery['fields'], etc.
 262+ foreach ( array( 'tables', 'fields', 'where', 'options', 'join_conds' ) as $var ) {
 263+ if ( isset( $extraQuery[$var] ) ) {
 264+ $$var = array_merge( $$var, (array)$extraQuery[$var] );
 265+ }
 266+ }
 267+
253268 // getDB has its own profileDBIn/Out calls
254269 $db = $this->getDB();
255270
256271 $this->profileDBIn();
257 - $res = $db->select( $this->tables, $this->fields, $this->where, $method, $this->options, $this->join_conds );
 272+ $res = $db->select( $tables, $fields, $where, $method, $options, $join_conds );
258273 $this->profileDBOut();
259274
260275 return $res;
Index: branches/REL1_17/phase3/includes/api/ApiQueryCategoryMembers.php
@@ -83,7 +83,8 @@
8484 $this->addTables( array( 'page', 'categorylinks' ) ); // must be in this order for 'USE INDEX'
8585
8686 $this->addWhereFld( 'cl_to', $categoryTitle->getDBkey() );
87 - $this->addWhereFld( 'cl_type', $params['type'] );
 87+ $queryTypes = $params['type'];
 88+ $contWhere = false;
8889
8990 // Scanning large datasets for rare categories sucks, and I already told
9091 // how to have efficient subcategory access :-) ~~~~ (oh well, domas)
@@ -113,20 +114,22 @@
114115 'by the previous query', '_badcontinue'
115116 );
116117 }
117 - $escType = $this->getDB()->addQuotes( $cont[0] );
 118+
 119+ // Remove the types to skip from $queryTypes
 120+ $contTypeIndex = array_search( $cont[0], $queryTypes );
 121+ $queryTypes = array_slice( $queryTypes, $contTypeIndex );
 122+
 123+ // Add a WHERE clause for sortkey and from
118124 $from = intval( $cont[1] );
119125 $escSortkey = $this->getDB()->addQuotes( $cont[2] );
120126 $op = $dir == 'newer' ? '>' : '<';
121 - $this->addWhere( "cl_type $op $escType OR " .
122 - "(cl_type = $escType AND " .
123 - "(cl_sortkey $op $escSortkey OR " .
 127+ // $contWhere is used further down
 128+ $contWhere = "cl_sortkey $op $escSortkey OR " .
124129 "(cl_sortkey = $escSortkey AND " .
125 - "cl_from $op= $from)))"
126 - );
 130+ "cl_from $op= $from)";
127131
128132 } else {
129 - // The below produces ORDER BY cl_type, cl_sortkey, cl_from, possibly with DESC added to each of them
130 - $this->addWhereRange( 'cl_type', $dir, null, null );
 133+ // The below produces ORDER BY cl_sortkey, cl_from, possibly with DESC added to each of them
131134 $this->addWhereRange( 'cl_sortkey',
132135 $dir,
133136 $params['startsortkey'],
@@ -141,9 +144,29 @@
142145 $limit = $params['limit'];
143146 $this->addOption( 'LIMIT', $limit + 1 );
144147
 148+ // Run a separate SELECT query for each value of cl_type.
 149+ // This is needed because cl_type is an enum, and MySQL has
 150+ // inconsistencies between ORDER BY cl_type and
 151+ // WHERE cl_type >= 'foo' making proper paging impossible
 152+ // and unindexed.
 153+ $rows = array();
 154+ $first = true;
 155+ foreach ( $queryTypes as $type ) {
 156+ $extraConds = array( 'cl_type' => $type );
 157+ if ( $first && $contWhere ) {
 158+ // Continuation condition. Only added to the
 159+ // first query, otherwise we'll skip things
 160+ $extraConds[] = $contWhere;
 161+ }
 162+ $res = $this->select( __METHOD__, array( 'where' => $extraConds ) );
 163+ $rows = array_merge( $rows, iterator_to_array( $res ) );
 164+ if ( count( $rows ) >= $limit + 1 ) {
 165+ break;
 166+ }
 167+ $first = false;
 168+ }
145169 $count = 0;
146 - $res = $this->select( __METHOD__ );
147 - foreach ( $res as $row ) {
 170+ foreach ( $rows as $row ) {
148171 if ( ++ $count > $limit ) {
149172 // We've reached the one extra which shows that there are additional pages to be had. Stop here...
150173 // TODO: Security issue - if the user has no right to view next title, it will still be shown
Index: branches/REL1_17/phase3/includes/resourceloader/ResourceLoader.php
@@ -29,6 +29,7 @@
3030 class ResourceLoader {
3131
3232 /* Protected Static Members */
 33+ protected static $filterCacheVersion = 2;
3334
3435 /** Array: List of module name/ResourceLoaderModule object pairs */
3536 protected $modules = array();
@@ -108,7 +109,7 @@
109110 * Runs JavaScript or CSS data through a filter, caching the filtered result for future calls.
110111 *
111112 * Available filters are:
112 - * - minify-js \see JavaScriptDistiller::stripWhiteSpace
 113+ * - minify-js \see JavaScriptMinifier::minify
113114 * - minify-css \see CSSMin::minify
114115 *
115116 * If $data is empty, only contains whitespace or the filter was unknown,
@@ -119,8 +120,7 @@
120121 * @return String: Filtered data, or a comment containing an error message
121122 */
122123 protected function filter( $filter, $data ) {
123 - global $wgResourceLoaderMinifyJSVerticalSpace;
124 -
 124+ global $wgResourceLoaderMinifierStatementsOnOwnLine, $wgResourceLoaderMinifierMaxLineLength;
125125 wfProfileIn( __METHOD__ );
126126
127127 // For empty/whitespace-only data or for unknown filters, don't perform
@@ -146,8 +146,9 @@
147147 try {
148148 switch ( $filter ) {
149149 case 'minify-js':
150 - $result = JavaScriptDistiller::stripWhiteSpace(
151 - $data, $wgResourceLoaderMinifyJSVerticalSpace
 150+ $result = JavaScriptMinifier::minify( $data,
 151+ $wgResourceLoaderMinifierStatementsOnOwnLine,
 152+ $wgResourceLoaderMinifierMaxLineLength
152153 );
153154 break;
154155 case 'minify-css':
@@ -462,7 +463,9 @@
463464 // Scripts
464465 $scripts = '';
465466 if ( $context->shouldIncludeScripts() ) {
466 - $scripts .= $module->getScript( $context ) . "\n";
 467+ // bug 27054: Append semicolon to prevent weird bugs
 468+ // caused by files not terminating their statements right
 469+ $scripts .= $module->getScript( $context ) . ";\n";
467470 }
468471
469472 // Styles
Property changes on: branches/REL1_17/phase3/includes/resourceloader/ResourceLoader.php
___________________________________________________________________
Modified: svn:mergeinfo
470473 Merged /trunk/phase3/includes/resourceloader/ResourceLoader.php:r83885,83891,83897,83902-83903,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/AutoLoader.php
@@ -137,6 +137,7 @@
138138 'Interwiki' => 'includes/Interwiki.php',
139139 'IP' => 'includes/IP.php',
140140 'JavaScriptDistiller' => 'includes/libs/JavaScriptDistiller.php',
 141+ 'JavaScriptMinifier' => 'includes/libs/JavaScriptMinifier.php',
141142 'LCStore_DB' => 'includes/LocalisationCache.php',
142143 'LCStore_CDB' => 'includes/LocalisationCache.php',
143144 'LCStore_Null' => 'includes/LocalisationCache.php',
Property changes on: branches/REL1_17/phase3/includes/AutoLoader.php
___________________________________________________________________
Modified: svn:mergeinfo
144145 Merged /trunk/phase3/includes/AutoLoader.php:r83885,83891,83897,83902-83903,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/job/JobQueue.php
@@ -217,12 +217,12 @@
218218 * @param $jobs array of Job objects
219219 */
220220 static function batchInsert( $jobs ) {
221 - if( !count( $jobs ) ) {
 221+ if ( !count( $jobs ) ) {
222222 return;
223223 }
224224 $dbw = wfGetDB( DB_MASTER );
225225 $rows = array();
226 - foreach( $jobs as $job ) {
 226+ foreach ( $jobs as $job ) {
227227 $rows[] = $job->insertFields();
228228 if ( count( $rows ) >= 50 ) {
229229 # Do a small transaction to avoid slave lag
@@ -232,13 +232,42 @@
233233 $rows = array();
234234 }
235235 }
236 - if ( $rows ) {
 236+ if ( $rows ) { // last chunk
237237 $dbw->begin();
238238 $dbw->insert( 'job', $rows, __METHOD__, 'IGNORE' );
239239 $dbw->commit();
240240 }
 241+ wfIncrStats( 'job-insert', count( $jobs ) );
241242 }
242243
 244+ /**
 245+ * Insert a group of jobs into the queue.
 246+ *
 247+ * Same as batchInsert() but does not commit and can thus
 248+ * be rolled-back as part of a larger transaction. However,
 249+ * large batches of jobs can cause slave lag.
 250+ *
 251+ * @param $jobs array of Job objects
 252+ */
 253+ static function safeBatchInsert( $jobs ) {
 254+ if ( !count( $jobs ) ) {
 255+ return;
 256+ }
 257+ $dbw = wfGetDB( DB_MASTER );
 258+ $rows = array();
 259+ foreach ( $jobs as $job ) {
 260+ $rows[] = $job->insertFields();
 261+ if ( count( $rows ) >= 500 ) {
 262+ $dbw->insert( 'job', $rows, __METHOD__, 'IGNORE' );
 263+ $rows = array();
 264+ }
 265+ }
 266+ if ( $rows ) { // last chunk
 267+ $dbw->insert( 'job', $rows, __METHOD__, 'IGNORE' );
 268+ }
 269+ wfIncrStats( 'job-insert', count( $jobs ) );
 270+ }
 271+
243272 /*-------------------------------------------------------------------------
244273 * Non-static functions
245274 *------------------------------------------------------------------------*/
Index: branches/REL1_17/phase3/includes/libs/JavaScriptMinifier.php
@@ -0,0 +1,579 @@
 2+<?php
 3+/**
 4+ * JavaScript Minifier
 5+ *
 6+ * This class is meant to safely minify javascript code, while leaving syntactically correct
 7+ * programs intact. Other libraries, such as JSMin require a certain coding style to work
 8+ * correctly. OTOH, libraries like jsminplus, that do parse the code correctly are rather
 9+ * slow, because they construct a complete parse tree before outputting the code minified.
 10+ * So this class is meant to allow arbitrary (but syntactically correct) input, while being
 11+ * fast enough to be used for on-the-fly minifying.
 12+ *
 13+ * Author: Paul Copperman <paul.copperman@gmail.com>
 14+ * License: choose any of Apache, MIT, GPL, LGPL
 15+ */
 16+
 17+class JavaScriptMinifier {
 18+
 19+ /* Class constants */
 20+ /* Parsing states.
 21+ * The state machine is only necessary to decide whether to parse a slash as division
 22+ * operator or as regexp literal.
 23+ * States are named after the next expected item. We only distinguish states when the
 24+ * distinction is relevant for our purpose.
 25+ */
 26+ const STATEMENT = 0;
 27+ const CONDITION = 1;
 28+ const PROPERTY_ASSIGNMENT = 2;
 29+ const EXPRESSION = 3;
 30+ const EXPRESSION_NO_NL = 4; // only relevant for semicolon insertion
 31+ const EXPRESSION_OP = 5;
 32+ const EXPRESSION_FUNC = 6;
 33+ const EXPRESSION_TERNARY = 7; // used to determine the role of a colon
 34+ const EXPRESSION_TERNARY_OP = 8;
 35+ const EXPRESSION_TERNARY_FUNC = 9;
 36+ const PAREN_EXPRESSION = 10; // expression which is not on the top level
 37+ const PAREN_EXPRESSION_OP = 11;
 38+ const PAREN_EXPRESSION_FUNC = 12;
 39+ const PROPERTY_EXPRESSION = 13; // expression which is within an object literal
 40+ const PROPERTY_EXPRESSION_OP = 14;
 41+ const PROPERTY_EXPRESSION_FUNC = 15;
 42+
 43+ /* Token types */
 44+ const TYPE_UN_OP = 1; // unary operators
 45+ const TYPE_INCR_OP = 2; // ++ and --
 46+ const TYPE_BIN_OP = 3; // binary operators
 47+ const TYPE_ADD_OP = 4; // + and - which can be either unary or binary ops
 48+ const TYPE_HOOK = 5; // ?
 49+ const TYPE_COLON = 6; // :
 50+ const TYPE_COMMA = 7; // ,
 51+ const TYPE_SEMICOLON = 8; // ;
 52+ const TYPE_BRACE_OPEN = 9; // {
 53+ const TYPE_BRACE_CLOSE = 10; // }
 54+ const TYPE_PAREN_OPEN = 11; // ( and [
 55+ const TYPE_PAREN_CLOSE = 12; // ) and ]
 56+ const TYPE_RETURN = 13; // keywords: break, continue, return, throw
 57+ const TYPE_IF = 14; // keywords: catch, for, with, switch, while, if
 58+ const TYPE_DO = 15; // keywords: case, var, finally, else, do, try
 59+ const TYPE_FUNC = 16; // keywords: function
 60+ const TYPE_LITERAL = 17; // all literals, identifiers and unrecognised tokens
 61+
 62+ // Sanity limit to avoid excessive memory usage
 63+ const STACK_LIMIT = 1000;
 64+
 65+ /* Static functions */
 66+
 67+ /**
 68+ * Returns minified JavaScript code.
 69+ *
 70+ * NOTE: $maxLineLength isn't a strict maximum. Longer lines will be produced when
 71+ * literals (e.g. quoted strings) longer than $maxLineLength are encountered
 72+ * or when required to guard against semicolon insertion.
 73+ *
 74+ * @param $s String JavaScript code to minify
 75+ * @param $statementsOnOwnLine Bool Whether to put each statement on its own line
 76+ * @param $maxLineLength Int Maximum length of a single line, or -1 for no maximum.
 77+ * @return String Minified code
 78+ */
 79+ public static function minify( $s, $statementsOnOwnLine = false, $maxLineLength = 1000 ) {
 80+ // First we declare a few tables that contain our parsing rules
 81+
 82+ // $opChars : characters, which can be combined without whitespace in between them
 83+ $opChars = array(
 84+ '!' => true,
 85+ '"' => true,
 86+ '%' => true,
 87+ '&' => true,
 88+ "'" => true,
 89+ '(' => true,
 90+ ')' => true,
 91+ '*' => true,
 92+ '+' => true,
 93+ ',' => true,
 94+ '-' => true,
 95+ '.' => true,
 96+ '/' => true,
 97+ ':' => true,
 98+ ';' => true,
 99+ '<' => true,
 100+ '=' => true,
 101+ '>' => true,
 102+ '?' => true,
 103+ '[' => true,
 104+ ']' => true,
 105+ '^' => true,
 106+ '{' => true,
 107+ '|' => true,
 108+ '}' => true,
 109+ '~' => true
 110+ );
 111+
 112+ // $tokenTypes : maps keywords and operators to their corresponding token type
 113+ $tokenTypes = array(
 114+ '!' => self::TYPE_UN_OP,
 115+ '~' => self::TYPE_UN_OP,
 116+ 'delete' => self::TYPE_UN_OP,
 117+ 'new' => self::TYPE_UN_OP,
 118+ 'typeof' => self::TYPE_UN_OP,
 119+ 'void' => self::TYPE_UN_OP,
 120+ '++' => self::TYPE_INCR_OP,
 121+ '--' => self::TYPE_INCR_OP,
 122+ '!=' => self::TYPE_BIN_OP,
 123+ '!==' => self::TYPE_BIN_OP,
 124+ '%' => self::TYPE_BIN_OP,
 125+ '%=' => self::TYPE_BIN_OP,
 126+ '&' => self::TYPE_BIN_OP,
 127+ '&&' => self::TYPE_BIN_OP,
 128+ '&=' => self::TYPE_BIN_OP,
 129+ '*' => self::TYPE_BIN_OP,
 130+ '*=' => self::TYPE_BIN_OP,
 131+ '+=' => self::TYPE_BIN_OP,
 132+ '-=' => self::TYPE_BIN_OP,
 133+ '.' => self::TYPE_BIN_OP,
 134+ '/' => self::TYPE_BIN_OP,
 135+ '/=' => self::TYPE_BIN_OP,
 136+ '<' => self::TYPE_BIN_OP,
 137+ '<<' => self::TYPE_BIN_OP,
 138+ '<<=' => self::TYPE_BIN_OP,
 139+ '<=' => self::TYPE_BIN_OP,
 140+ '=' => self::TYPE_BIN_OP,
 141+ '==' => self::TYPE_BIN_OP,
 142+ '===' => self::TYPE_BIN_OP,
 143+ '>' => self::TYPE_BIN_OP,
 144+ '>=' => self::TYPE_BIN_OP,
 145+ '>>' => self::TYPE_BIN_OP,
 146+ '>>=' => self::TYPE_BIN_OP,
 147+ '>>>' => self::TYPE_BIN_OP,
 148+ '>>>=' => self::TYPE_BIN_OP,
 149+ '^' => self::TYPE_BIN_OP,
 150+ '^=' => self::TYPE_BIN_OP,
 151+ '|' => self::TYPE_BIN_OP,
 152+ '|=' => self::TYPE_BIN_OP,
 153+ '||' => self::TYPE_BIN_OP,
 154+ 'in' => self::TYPE_BIN_OP,
 155+ 'instanceof' => self::TYPE_BIN_OP,
 156+ '+' => self::TYPE_ADD_OP,
 157+ '-' => self::TYPE_ADD_OP,
 158+ '?' => self::TYPE_HOOK,
 159+ ':' => self::TYPE_COLON,
 160+ ',' => self::TYPE_COMMA,
 161+ ';' => self::TYPE_SEMICOLON,
 162+ '{' => self::TYPE_BRACE_OPEN,
 163+ '}' => self::TYPE_BRACE_CLOSE,
 164+ '(' => self::TYPE_PAREN_OPEN,
 165+ '[' => self::TYPE_PAREN_OPEN,
 166+ ')' => self::TYPE_PAREN_CLOSE,
 167+ ']' => self::TYPE_PAREN_CLOSE,
 168+ 'break' => self::TYPE_RETURN,
 169+ 'continue' => self::TYPE_RETURN,
 170+ 'return' => self::TYPE_RETURN,
 171+ 'throw' => self::TYPE_RETURN,
 172+ 'catch' => self::TYPE_IF,
 173+ 'for' => self::TYPE_IF,
 174+ 'if' => self::TYPE_IF,
 175+ 'switch' => self::TYPE_IF,
 176+ 'while' => self::TYPE_IF,
 177+ 'with' => self::TYPE_IF,
 178+ 'case' => self::TYPE_DO,
 179+ 'do' => self::TYPE_DO,
 180+ 'else' => self::TYPE_DO,
 181+ 'finally' => self::TYPE_DO,
 182+ 'try' => self::TYPE_DO,
 183+ 'var' => self::TYPE_DO,
 184+ 'function' => self::TYPE_FUNC
 185+ );
 186+
 187+ // $goto : This is the main table for our state machine. For every state/token pair
 188+ // the following state is defined. When no rule exists for a given pair,
 189+ // the state is left unchanged.
 190+ $goto = array(
 191+ self::STATEMENT => array(
 192+ self::TYPE_UN_OP => self::EXPRESSION,
 193+ self::TYPE_INCR_OP => self::EXPRESSION,
 194+ self::TYPE_ADD_OP => self::EXPRESSION,
 195+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 196+ self::TYPE_RETURN => self::EXPRESSION_NO_NL,
 197+ self::TYPE_IF => self::CONDITION,
 198+ self::TYPE_FUNC => self::CONDITION,
 199+ self::TYPE_LITERAL => self::EXPRESSION_OP
 200+ ),
 201+ self::CONDITION => array(
 202+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
 203+ ),
 204+ self::PROPERTY_ASSIGNMENT => array(
 205+ self::TYPE_COLON => self::PROPERTY_EXPRESSION,
 206+ self::TYPE_BRACE_OPEN => self::STATEMENT
 207+ ),
 208+ self::EXPRESSION => array(
 209+ self::TYPE_SEMICOLON => self::STATEMENT,
 210+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
 211+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 212+ self::TYPE_FUNC => self::EXPRESSION_FUNC,
 213+ self::TYPE_LITERAL => self::EXPRESSION_OP
 214+ ),
 215+ self::EXPRESSION_NO_NL => array(
 216+ self::TYPE_SEMICOLON => self::STATEMENT,
 217+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
 218+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 219+ self::TYPE_FUNC => self::EXPRESSION_FUNC,
 220+ self::TYPE_LITERAL => self::EXPRESSION_OP
 221+ ),
 222+ self::EXPRESSION_OP => array(
 223+ self::TYPE_BIN_OP => self::EXPRESSION,
 224+ self::TYPE_ADD_OP => self::EXPRESSION,
 225+ self::TYPE_HOOK => self::EXPRESSION_TERNARY,
 226+ self::TYPE_COLON => self::STATEMENT,
 227+ self::TYPE_COMMA => self::EXPRESSION,
 228+ self::TYPE_SEMICOLON => self::STATEMENT,
 229+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
 230+ ),
 231+ self::EXPRESSION_FUNC => array(
 232+ self::TYPE_BRACE_OPEN => self::STATEMENT
 233+ ),
 234+ self::EXPRESSION_TERNARY => array(
 235+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
 236+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 237+ self::TYPE_FUNC => self::EXPRESSION_TERNARY_FUNC,
 238+ self::TYPE_LITERAL => self::EXPRESSION_TERNARY_OP
 239+ ),
 240+ self::EXPRESSION_TERNARY_OP => array(
 241+ self::TYPE_BIN_OP => self::EXPRESSION_TERNARY,
 242+ self::TYPE_ADD_OP => self::EXPRESSION_TERNARY,
 243+ self::TYPE_HOOK => self::EXPRESSION_TERNARY,
 244+ self::TYPE_COMMA => self::EXPRESSION_TERNARY,
 245+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
 246+ ),
 247+ self::EXPRESSION_TERNARY_FUNC => array(
 248+ self::TYPE_BRACE_OPEN => self::STATEMENT
 249+ ),
 250+ self::PAREN_EXPRESSION => array(
 251+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
 252+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 253+ self::TYPE_FUNC => self::PAREN_EXPRESSION_FUNC,
 254+ self::TYPE_LITERAL => self::PAREN_EXPRESSION_OP
 255+ ),
 256+ self::PAREN_EXPRESSION_OP => array(
 257+ self::TYPE_BIN_OP => self::PAREN_EXPRESSION,
 258+ self::TYPE_ADD_OP => self::PAREN_EXPRESSION,
 259+ self::TYPE_HOOK => self::PAREN_EXPRESSION,
 260+ self::TYPE_COLON => self::PAREN_EXPRESSION,
 261+ self::TYPE_COMMA => self::PAREN_EXPRESSION,
 262+ self::TYPE_SEMICOLON => self::PAREN_EXPRESSION,
 263+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
 264+ ),
 265+ self::PAREN_EXPRESSION_FUNC => array(
 266+ self::TYPE_BRACE_OPEN => self::STATEMENT
 267+ ),
 268+ self::PROPERTY_EXPRESSION => array(
 269+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
 270+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
 271+ self::TYPE_FUNC => self::PROPERTY_EXPRESSION_FUNC,
 272+ self::TYPE_LITERAL => self::PROPERTY_EXPRESSION_OP
 273+ ),
 274+ self::PROPERTY_EXPRESSION_OP => array(
 275+ self::TYPE_BIN_OP => self::PROPERTY_EXPRESSION,
 276+ self::TYPE_ADD_OP => self::PROPERTY_EXPRESSION,
 277+ self::TYPE_HOOK => self::PROPERTY_EXPRESSION,
 278+ self::TYPE_COMMA => self::PROPERTY_ASSIGNMENT,
 279+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
 280+ ),
 281+ self::PROPERTY_EXPRESSION_FUNC => array(
 282+ self::TYPE_BRACE_OPEN => self::STATEMENT
 283+ )
 284+ );
 285+
 286+ // $push : This table contains the rules for when to push a state onto the stack.
 287+ // The pushed state is the state to return to when the corresponding
 288+ // closing token is found
 289+ $push = array(
 290+ self::STATEMENT => array(
 291+ self::TYPE_BRACE_OPEN => self::STATEMENT,
 292+ self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
 293+ ),
 294+ self::CONDITION => array(
 295+ self::TYPE_PAREN_OPEN => self::STATEMENT
 296+ ),
 297+ self::PROPERTY_ASSIGNMENT => array(
 298+ self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT
 299+ ),
 300+ self::EXPRESSION => array(
 301+ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
 302+ self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
 303+ ),
 304+ self::EXPRESSION_NO_NL => array(
 305+ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
 306+ self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
 307+ ),
 308+ self::EXPRESSION_OP => array(
 309+ self::TYPE_HOOK => self::EXPRESSION,
 310+ self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
 311+ ),
 312+ self::EXPRESSION_FUNC => array(
 313+ self::TYPE_BRACE_OPEN => self::EXPRESSION_OP
 314+ ),
 315+ self::EXPRESSION_TERNARY => array(
 316+ self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP,
 317+ self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
 318+ ),
 319+ self::EXPRESSION_TERNARY_OP => array(
 320+ self::TYPE_HOOK => self::EXPRESSION_TERNARY,
 321+ self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
 322+ ),
 323+ self::EXPRESSION_TERNARY_FUNC => array(
 324+ self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP
 325+ ),
 326+ self::PAREN_EXPRESSION => array(
 327+ self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP,
 328+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
 329+ ),
 330+ self::PAREN_EXPRESSION_OP => array(
 331+ self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
 332+ ),
 333+ self::PAREN_EXPRESSION_FUNC => array(
 334+ self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP
 335+ ),
 336+ self::PROPERTY_EXPRESSION => array(
 337+ self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP,
 338+ self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
 339+ ),
 340+ self::PROPERTY_EXPRESSION_OP => array(
 341+ self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
 342+ ),
 343+ self::PROPERTY_EXPRESSION_FUNC => array(
 344+ self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP
 345+ )
 346+ );
 347+
 348+ // $pop : Rules for when to pop a state from the stack
 349+ $pop = array(
 350+ self::STATEMENT => array( self::TYPE_BRACE_CLOSE => true ),
 351+ self::PROPERTY_ASSIGNMENT => array( self::TYPE_BRACE_CLOSE => true ),
 352+ self::EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ),
 353+ self::EXPRESSION_NO_NL => array( self::TYPE_BRACE_CLOSE => true ),
 354+ self::EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true ),
 355+ self::EXPRESSION_TERNARY_OP => array( self::TYPE_COLON => true ),
 356+ self::PAREN_EXPRESSION => array( self::TYPE_PAREN_CLOSE => true ),
 357+ self::PAREN_EXPRESSION_OP => array( self::TYPE_PAREN_CLOSE => true ),
 358+ self::PROPERTY_EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ),
 359+ self::PROPERTY_EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true )
 360+ );
 361+
 362+ // $semicolon : Rules for when a semicolon insertion is appropriate
 363+ $semicolon = array(
 364+ self::EXPRESSION_NO_NL => array(
 365+ self::TYPE_UN_OP => true,
 366+ self::TYPE_INCR_OP => true,
 367+ self::TYPE_ADD_OP => true,
 368+ self::TYPE_BRACE_OPEN => true,
 369+ self::TYPE_PAREN_OPEN => true,
 370+ self::TYPE_RETURN => true,
 371+ self::TYPE_IF => true,
 372+ self::TYPE_DO => true,
 373+ self::TYPE_FUNC => true,
 374+ self::TYPE_LITERAL => true
 375+ ),
 376+ self::EXPRESSION_OP => array(
 377+ self::TYPE_UN_OP => true,
 378+ self::TYPE_INCR_OP => true,
 379+ self::TYPE_BRACE_OPEN => true,
 380+ self::TYPE_RETURN => true,
 381+ self::TYPE_IF => true,
 382+ self::TYPE_DO => true,
 383+ self::TYPE_FUNC => true,
 384+ self::TYPE_LITERAL => true
 385+ )
 386+ );
 387+
 388+ // Rules for when newlines should be inserted if
 389+ // $statementsOnOwnLine is enabled.
 390+ // $newlineBefore is checked before switching state,
 391+ // $newlineAfter is checked after
 392+ $newlineBefore = array(
 393+ self::STATEMENT => array(
 394+ self::TYPE_BRACE_CLOSE => true,
 395+ ),
 396+ );
 397+ $newlineAfter = array(
 398+ self::STATEMENT => array(
 399+ self::TYPE_BRACE_OPEN => true,
 400+ self::TYPE_PAREN_CLOSE => true,
 401+ self::TYPE_SEMICOLON => true,
 402+ ),
 403+ );
 404+
 405+ // $divStates : Contains all states that can be followed by a division operator
 406+ $divStates = array(
 407+ self::EXPRESSION_OP => true,
 408+ self::EXPRESSION_TERNARY_OP => true,
 409+ self::PAREN_EXPRESSION_OP => true,
 410+ self::PROPERTY_EXPRESSION_OP => true
 411+ );
 412+
 413+ // Here's where the minifying takes place: Loop through the input, looking for tokens
 414+ // and output them to $out, taking actions to the above defined rules when appropriate.
 415+ $out = '';
 416+ $pos = 0;
 417+ $length = strlen( $s );
 418+ $lineLength = 0;
 419+ $newlineFound = true;
 420+ $state = self::STATEMENT;
 421+ $stack = array();
 422+ $last = ';'; // Pretend that we have seen a semicolon yet
 423+ while( $pos < $length ) {
 424+ // First, skip over any whitespace and multiline comments, recording whether we
 425+ // found any newline character
 426+ $skip = strspn( $s, " \t\n\r\xb\xc", $pos );
 427+ if( !$skip ) {
 428+ $ch = $s[$pos];
 429+ if( $ch === '/' && substr( $s, $pos, 2 ) === '/*' ) {
 430+ // Multiline comment. Search for the end token or EOT.
 431+ $end = strpos( $s, '*/', $pos + 2 );
 432+ $skip = $end === false ? $length - $pos : $end - $pos + 2;
 433+ }
 434+ }
 435+ if( $skip ) {
 436+ // The semicolon insertion mechanism needs to know whether there was a newline
 437+ // between two tokens, so record it now.
 438+ if( !$newlineFound && strcspn( $s, "\r\n", $pos, $skip ) !== $skip ) {
 439+ $newlineFound = true;
 440+ }
 441+ $pos += $skip;
 442+ continue;
 443+ }
 444+ // Handle C++-style comments and html comments, which are treated as single line
 445+ // comments by the browser, regardless of whether the end tag is on the same line.
 446+ // Handle --> the same way, but only if it's at the beginning of the line
 447+ if( ( $ch === '/' && substr( $s, $pos, 2 ) === '//' )
 448+ || ( $ch === '<' && substr( $s, $pos, 4 ) === '<!--' )
 449+ || ( $ch === '-' && $newlineFound && substr( $s, $pos, 3 ) === '-->' )
 450+ ) {
 451+ $pos += strcspn( $s, "\r\n", $pos );
 452+ continue;
 453+ }
 454+
 455+ // Find out which kind of token we're handling. $end will point past the end of it.
 456+ $end = $pos + 1;
 457+ // Handle string literals
 458+ if( $ch === "'" || $ch === '"' ) {
 459+ // Search to the end of the string literal, skipping over backslash escapes
 460+ $search = $ch . '\\';
 461+ do{
 462+ $end += strcspn( $s, $search, $end ) + 2;
 463+ } while( $end - 2 < $length && $s[$end - 2] === '\\' );
 464+ $end--;
 465+ // We have to distinguish between regexp literals and division operators
 466+ // A division operator is only possible in certain states
 467+ } elseif( $ch === '/' && !isset( $divStates[$state] ) ) {
 468+ // Regexp literal, search to the end, skipping over backslash escapes and
 469+ // character classes
 470+ for( ; ; ) {
 471+ do{
 472+ $end += strcspn( $s, '/[\\', $end ) + 2;
 473+ } while( $end - 2 < $length && $s[$end - 2] === '\\' );
 474+ $end--;
 475+ if( $end - 1 >= $length || $s[$end - 1] === '/' ) {
 476+ break;
 477+ }
 478+ do{
 479+ $end += strcspn( $s, ']\\', $end ) + 2;
 480+ } while( $end - 2 < $length && $s[$end - 2] === '\\' );
 481+ $end--;
 482+ };
 483+ // Search past the regexp modifiers (gi)
 484+ while( $end < $length && ctype_alpha( $s[$end] ) ) {
 485+ $end++;
 486+ }
 487+ } elseif(
 488+ ctype_digit( $ch )
 489+ || ( $ch === '.' && $pos + 1 < $length && ctype_digit( $s[$pos + 1] ) )
 490+ ) {
 491+ // Numeric literal. Search for the end of it, but don't care about [+-]exponent
 492+ // at the end, as the results of "numeric [+-] numeric" and "numeric" are
 493+ // identical to our state machine.
 494+ $end += strspn( $s, '0123456789ABCDEFabcdefXx.', $end );
 495+ while( $s[$end - 1] === '.' ) {
 496+ // Special case: When a numeric ends with a dot, we have to check the
 497+ // literal for proper syntax
 498+ $decimal = strspn( $s, '0123456789', $pos, $end - $pos - 1 );
 499+ if( $decimal === $end - $pos - 1 ) {
 500+ break;
 501+ } else {
 502+ $end--;
 503+ }
 504+ }
 505+ } elseif( isset( $opChars[$ch] ) ) {
 506+ // Punctuation character. Search for the longest matching operator.
 507+ while(
 508+ $end < $length
 509+ && isset( $tokenTypes[substr( $s, $pos, $end - $pos + 1 )] )
 510+ ) {
 511+ $end++;
 512+ }
 513+ } else {
 514+ // Identifier or reserved word. Search for the end by excluding whitespace and
 515+ // punctuation.
 516+ $end += strcspn( $s, " \t\n.;,=<>+-{}()[]?:*/%'\"!&|^~\xb\xc\r", $end );
 517+ }
 518+
 519+ // Now get the token type from our type array
 520+ $token = substr( $s, $pos, $end - $pos ); // so $end - $pos == strlen( $token )
 521+ $type = isset( $tokenTypes[$token] ) ? $tokenTypes[$token] : self::TYPE_LITERAL;
 522+
 523+ if( $newlineFound && isset( $semicolon[$state][$type] ) ) {
 524+ // This token triggers the semicolon insertion mechanism of javascript. While we
 525+ // could add the ; token here ourselves, keeping the newline has a few advantages.
 526+ $out .= "\n";
 527+ $state = self::STATEMENT;
 528+ $lineLength = 0;
 529+ } elseif( $maxLineLength > 0 && $lineLength + $end - $pos > $maxLineLength &&
 530+ !isset( $semicolon[$state][$type] ) && $type !== self::TYPE_INCR_OP )
 531+ {
 532+ // This line would get too long if we added $token, so add a newline first.
 533+ // Only do this if it won't trigger semicolon insertion and if it won't
 534+ // put a postfix increment operator on its own line, which is illegal in js.
 535+ $out .= "\n";
 536+ $lineLength = 0;
 537+ // Check, whether we have to separate the token from the last one with whitespace
 538+ } elseif( !isset( $opChars[$last] ) && !isset( $opChars[$ch] ) ) {
 539+ $out .= ' ';
 540+ $lineLength++;
 541+ // Don't accidentally create ++, -- or // tokens
 542+ } elseif( $last === $ch && ( $ch === '+' || $ch === '-' || $ch === '/' ) ) {
 543+ $out .= ' ';
 544+ $lineLength++;
 545+ }
 546+
 547+ $out .= $token;
 548+ $lineLength += $end - $pos; // += strlen( $token )
 549+ $last = $s[$end - 1];
 550+ $pos = $end;
 551+ $newlineFound = false;
 552+
 553+ // Output a newline after the token if required
 554+ // This is checked before AND after switching state
 555+ $newlineAdded = false;
 556+ if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineBefore[$state][$type] ) ) {
 557+ $out .= "\n";
 558+ $lineLength = 0;
 559+ $newlineAdded = true;
 560+ }
 561+
 562+ // Now that we have output our token, transition into the new state.
 563+ if( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) {
 564+ $stack[] = $push[$state][$type];
 565+ }
 566+ if( $stack && isset( $pop[$state][$type] ) ) {
 567+ $state = array_pop( $stack );
 568+ } elseif( isset( $goto[$state][$type] ) ) {
 569+ $state = $goto[$state][$type];
 570+ }
 571+
 572+ // Check for newline insertion again
 573+ if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineAfter[$state][$type] ) ) {
 574+ $out .= "\n";
 575+ $lineLength = 0;
 576+ }
 577+ }
 578+ return $out;
 579+ }
 580+}
Property changes on: branches/REL1_17/phase3/includes/libs/JavaScriptMinifier.php
___________________________________________________________________
Added: svn:eol-style
1581 + native
Index: branches/REL1_17/phase3/includes/libs/CSSMin.php
@@ -144,6 +144,9 @@
145145 $query = $match['query'][0];
146146 $url = "{$remote}/{$match['file'][0]}";
147147 $file = "{$local}/{$match['file'][0]}";
 148+ // bug 27052 - Guard against double slashes, because foo//../bar
 149+ // apparently resolves to foo/bar on (some?) clients
 150+ $url = preg_replace( '#([^:])//+#', '\1/', $url );
148151 $replacement = false;
149152 if ( $local !== false && file_exists( $file ) ) {
150153 // Add version parameter as a time-stamp in ISO 8601 format,
Property changes on: branches/REL1_17/phase3/includes/libs
___________________________________________________________________
Added: svn:mergeinfo
151154 Merged /branches/sqlite/includes/libs:r58211-58321
152155 Merged /trunk/phase3/includes/libs:r82474,82845,82847-82848,83934,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
153156 Merged /branches/new-installer/phase3/includes/libs:r43664-66004
154157 Merged /branches/wmf-deployment/includes/libs:r53381
155158 Merged /branches/REL1_15/phase3/includes/libs:r51646
Index: branches/REL1_17/phase3/includes/DefaultSettings.php
@@ -2434,12 +2434,19 @@
24352435 $wgResourceLoaderUseESI = false;
24362436
24372437 /**
2438 - * Enable removal of some of the vertical whitespace (like \r and \n) from
2439 - * JavaScript code when minifying.
 2438+ * Put each statement on its own line when minifying JavaScript. This makes
 2439+ * debugging in non-debug mode a bit easier.
24402440 */
2441 -$wgResourceLoaderMinifyJSVerticalSpace = false;
 2441+$wgResourceLoaderMinifierStatementsOnOwnLine = false;
24422442
24432443 /**
 2444+ * Maximum line length when minifying JavaScript. This is not a hard maximum:
 2445+ * the minifier will try not to produce lines longer than this, but may be
 2446+ * forced to do so in certain cases.
 2447+ */
 2448+$wgResourceLoaderMinifierMaxLineLength = 1000;
 2449+
 2450+/**
24442451 * Whether to include the mediawiki.legacy JS library (old wikibits.js), and its
24452452 * dependencies
24462453 */
Property changes on: branches/REL1_17/phase3/includes/DefaultSettings.php
___________________________________________________________________
Modified: svn:mergeinfo
24472454 Merged /trunk/phase3/includes/DefaultSettings.php:r83891,83897,83902-83903,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/specials/SpecialListfiles.php
@@ -235,9 +235,19 @@
236236 if ( !is_null( $this->mUserName ) ) {
237237 # Append the username to the query string
238238 foreach ( $queries as &$query ) {
239 - $query['username'] = $this->mUserName;
 239+ $query['user'] = $this->mUserName;
240240 }
241241 }
242242 return $queries;
243243 }
 244+
 245+ function getDefaultQuery() {
 246+ $queries = parent::getDefaultQuery();
 247+ if ( !isset( $queries['user'] )
 248+ && !is_null( $this->mUserName ) )
 249+ {
 250+ $queries['user'] = $this->mUserName;
 251+ }
 252+ return $queries;
 253+ }
244254 }
Index: branches/REL1_17/phase3/includes/specials/SpecialUpload.php
@@ -448,8 +448,8 @@
449449 $permErrors = $this->mUpload->verifyPermissions( $wgUser );
450450 if( $permErrors !== true ) {
451451 $code = array_shift( $permErrors[0] );
452 - $this->showRecoverableUploadError( wfMsgExt( $code,
453 - 'parseinline', $permErrors[0] ) );
 452+ $this->showRecoverableUploadError( wfMsgExt( $code[0],
 453+ 'parseinline', $code[1] ) );
454454 return;
455455 }
456456
Property changes on: branches/REL1_17/phase3/includes/specials/SpecialUpload.php
___________________________________________________________________
Modified: svn:mergeinfo
457457 Merged /trunk/phase3/includes/specials/SpecialUpload.php:r83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Index: branches/REL1_17/phase3/includes/ImageGallery.php
@@ -35,6 +35,13 @@
3636 private $mAttribs = array();
3737
3838 /**
 39+ * Fixed margins
 40+ */
 41+ const THUMB_PADDING = 30;
 42+ const GB_PADDING = 5;
 43+ const GB_BORDERS = 6;
 44+
 45+ /**
3946 * Create a new image gallery object.
4047 */
4148 function __construct( ) {
@@ -226,7 +233,7 @@
227234 $sk = $this->getSkin();
228235
229236 if ( $this->mPerRow > 0 ) {
230 - $maxwidth = $this->mPerRow * ( $this->mWidths + 50 );
 237+ $maxwidth = $this->mPerRow * ( $this->mWidths + self::THUMB_PADDING + self::GB_PADDING + self::GB_BORDERS );
231238 $oldStyle = isset( $this->mAttribs['style'] ) ? $this->mAttribs['style'] : "";
232239 $this->mAttribs['style'] = "max-width: {$maxwidth}px;_width: {$maxwidth}px;" . $oldStyle;
233240 }
@@ -258,11 +265,11 @@
259266
260267 if( !$img ) {
261268 # We're dealing with a non-image, spit out the name and be done with it.
262 - $thumbhtml = "\n\t\t\t".'<div style="height: '.(30 + $this->mHeights).'px;">'
 269+ $thumbhtml = "\n\t\t\t".'<div style="height: '.(self::THUMB_PADDING + $this->mHeights).'px;">'
263270 . htmlspecialchars( $nt->getText() ) . '</div>';
264271 } elseif( $this->mHideBadImages && wfIsBadImage( $nt->getDBkey(), $this->getContextTitle() ) ) {
265272 # The image is blacklisted, just show it as a text link.
266 - $thumbhtml = "\n\t\t\t".'<div style="height: '.(30 + $this->mHeights).'px;">' .
 273+ $thumbhtml = "\n\t\t\t".'<div style="height: '.(self::THUMB_PADDING + $this->mHeights).'px;">' .
267274 $sk->link(
268275 $nt,
269276 htmlspecialchars( $nt->getText() ),
@@ -273,13 +280,13 @@
274281 '</div>';
275282 } elseif( !( $thumb = $img->transform( $params ) ) ) {
276283 # Error generating thumbnail.
277 - $thumbhtml = "\n\t\t\t".'<div style="height: '.(30 + $this->mHeights).'px;">'
 284+ $thumbhtml = "\n\t\t\t".'<div style="height: '.(self::THUMB_PADDING + $this->mHeights).'px;">'
278285 . htmlspecialchars( $img->getLastError() ) . '</div>';
279286 } else {
280287 //We get layout problems with the margin, if the image is smaller
281288 //than the line-height, so we less margin in these cases.
282289 $minThumbHeight = $thumb->height > 17 ? $thumb->height : 17;
283 - $vpad = floor(( 30 + $this->mHeights - $minThumbHeight ) /2);
 290+ $vpad = floor(( self::THUMB_PADDING + $this->mHeights - $minThumbHeight ) /2);
284291
285292
286293 $imageParameters = array(
@@ -293,7 +300,7 @@
294301
295302 # Set both fixed width and min-height.
296303 $thumbhtml = "\n\t\t\t".
297 - '<div class="thumb" style="width: ' .($this->mWidths+30).'px;">'
 304+ '<div class="thumb" style="width: ' .($this->mWidths + self::THUMB_PADDING).'px;">'
298305 # Auto-margin centering for block-level elements. Needed now that we have video
299306 # handlers since they may emit block-level elements as opposed to simple <img> tags.
300307 # ref http://css-discuss.incutio.com/?page=CenteringBlockElement
@@ -339,8 +346,8 @@
340347 # Weird double wrapping in div needed due to FF2 bug
341348 # Can be safely removed if FF2 falls completely out of existance
342349 $s .=
343 - "\n\t\t" . '<li class="gallerybox" style="width: ' . ( $this->mWidths + 35 ) . 'px">'
344 - . '<div style="width: ' . ( $this->mWidths + 35 ) . 'px">'
 350+ "\n\t\t" . '<li class="gallerybox" style="width: ' . ( $this->mWidths + self::THUMB_PADDING + self::GB_PADDING ) . 'px">'
 351+ . '<div style="width: ' . ( $this->mWidths + self::THUMB_PADDING + self::GB_PADDING ) . 'px">'
345352 . $thumbhtml
346353 . "\n\t\t\t" . '<div class="gallerytext">' . "\n"
347354 . $textlink . $text . $nb
Property changes on: branches/REL1_17/phase3/includes/ImageGallery.php
___________________________________________________________________
Added: svn:mergeinfo
348355 Merged /branches/sqlite/includes/ImageGallery.php:r58211-58321
349356 Merged /trunk/phase3/includes/ImageGallery.php:r82474,82845,82847-82848,83965,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
350357 Merged /branches/new-installer/phase3/includes/ImageGallery.php:r43664-66004
351358 Merged /branches/wmf-deployment/includes/ImageGallery.php:r53381
352359 Merged /branches/REL1_15/phase3/includes/ImageGallery.php:r51646
Index: branches/REL1_17/phase3/RELEASE-NOTES
@@ -515,8 +515,10 @@
516516 * (bug 27560) Search queries no longer fail in walloon language
517517 * (bug 27700) The upload protection can now also be set for files that do not
518518 exist.
 519+* (bug 28034) uploading file to local wiki when file exists on shared repository
 520+ (commons) gives spurious info in the warning message
 521+* Usernames get lost when selecting different sorts on Special:listfiles
519522
520 -=== API changes in 1.17 ===
521523 * BREAKING CHANGE: action=patrol now requires POST
522524 * BREAKING CHANGE: patrol token is no longer the same as edit token
523525 * BREAKING CHANGE: Session keys returned by ApiUpload are now strings instead of integers
@@ -651,8 +653,8 @@
652654 * (bug 27633) Add characters to linkTrail for Potuguese (pt and pt-br)
653655
654656 * (bug 23156) Commafy and search normalization updated for Belarusian
655 - (Tara�kievica).
656 -* (bug 23283) Native name for Old English -> �nglisc.
 657+ (Taraškievica).
 658+* (bug 23283) Native name for Old English -> Ænglisc.
657659 * (bug 23364) Native name for Azerbaijani -> Az?rbaycanca.
658660 * (bug 24593) Native name for Sorani now uses only Arabic script.
659661 * (bug 24628) Generic translations for NS_USER/NS_USER_TALK for Esperanto.
Property changes on: branches/REL1_17/phase3/RELEASE-NOTES
___________________________________________________________________
Modified: svn:mergeinfo
660662 Merged /trunk/phase3/RELEASE-NOTES:r83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430
Property changes on: branches/REL1_17/phase3
___________________________________________________________________
Modified: svn:mergeinfo
661663 Merged /trunk/phase3:r83885,83891,83897,83902-83903,83979,83988-83989,83997-83998,84118,84228,84271,84343,84353,84392,84430

Follow-up revisions

RevisionCommit summaryAuthorDate
r86184* (bug 28568) Entries in the iwlinks table are now removed on page deletion...ialex07:51, 16 April 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r83885(bug 27528) Incorporate Paul Copperman's minifiercatrope11:44, 14 March 2011
r83891Followup r83885: implement maximum line length and statement termination (eac...catrope13:24, 14 March 2011
r83897(bug 27054) Implicit end of statement can break stuff when files are combined...catrope14:25, 14 March 2011
r83902(bug 27052) CSSMin generated URLs like foo//../bar in some cases, which appar...catrope15:01, 14 March 2011
r83903(bug 27564) Timestamp of site module embedded in Squid-cached page HTMLcatrope15:16, 14 March 2011
r83934Followup r83891: don't insert a newline before ++ or -- . Patch by Paul Coppe...catrope18:04, 14 March 2011
r83965Fix overestimation of max-width when using perrow mode....hartman21:08, 14 March 2011
r83979* (bug 28034) uploading file to local wiki when file exists on shared reposit...reedy23:33, 14 March 2011
r83988keep double slash filter from breaking absolute URLs, fix to r83902kaldari01:57, 15 March 2011
r83989oops, don't delete char before the slash, followup to r83902kaldari02:03, 15 March 2011
r83997the vertical tab \v and form feed \f escapes are not available in php5.2.4 wh...neilk04:37, 15 March 2011
r83998removing another use of the vertical tab & form feed escapes, which are not a...neilk04:41, 15 March 2011
r84118(follow-up r65035/r65013) The username parameter wasn't preserved when clicki...bawolff18:23, 16 March 2011
r84228* Fixed wfIncrStats calls from r83617 (I assume this wants the # of jobs added)...aaron07:06, 18 March 2011
r84271Fix fatal Invalid argument supplied for foreachreedy22:01, 18 March 2011
r84343update.php: restore compatibility with PHP4 to die gracefullymaxsem19:48, 19 March 2011
r84353This feature never made it into 1.16nikerabbit21:46, 19 March 2011
r84392Per r83812 CR, solve the categorymembers paging problem by doing separate que...catrope16:25, 20 March 2011
r84430Followup r84392...reedy22:35, 20 March 2011

Status & tagging log