Add exceptions in mw.Title where mb_strtoupper doesn't match String.toUpperCase

Bug: T147646
Bug: T141723
Change-Id: Ic7a3d0cebbf4aec507db195ba8f587cecc1992aa
This commit is contained in:
Ed Sanders 2016-10-07 13:14:03 -04:00 committed by Bartosz Dziewoński
parent 87c3b700ac
commit edf4dfe756
5 changed files with 270 additions and 3 deletions

View file

@ -9,6 +9,7 @@
"--warnings-exit-nonzero": true,
"--external": "Blob,File,HTMLDocument,HTMLElement,HTMLIframeElement,HTMLInputElement,KeyboardEvent,MouseEvent,Node,Window,XMLDocument",
"--output": "docs/js",
"--exclude": "resources/src/mediawiki/mediawiki.Title.phpCharToUpper.js",
"--": [
"maintenance/jsduck/external.js",
"resources/src/mediawiki",

View file

@ -1194,7 +1194,10 @@ return [
'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.Title' => [
'scripts' => 'resources/src/mediawiki/mediawiki.Title.js',
'scripts' => [
'resources/src/mediawiki/mediawiki.Title.js',
'resources/src/mediawiki/mediawiki.Title.phpCharToUpper.js',
],
'dependencies' => [
'jquery.byteLength',
'mediawiki.util',

View file

@ -826,7 +826,9 @@
) {
return this.title;
}
return this.title[ 0 ].toUpperCase() + this.title.slice( 1 );
// PHP's strtoupper differs from String.toUpperCase in a number of cases
// Bug: T147646
return mw.Title.phpCharToUpper( this.title[ 0 ] ) + this.title.slice( 1 );
},
/**

View file

@ -0,0 +1,255 @@
// This file can't be parsed by JSDuck due to <https://github.com/tenderlove/rkelly/issues/35>.
// (It is excluded in jsduck.json.)
// ESLint suggests unquoting some object keys, which would render the file unparseable by Opera 12.
/* eslint-disable quote-props */
( function ( mw ) {
var toUpperMapping = {
'ß': 'ß',
'ʼn': 'ʼn',
'Dž': 'Dž',
'dž': 'Dž',
'Lj': 'Lj',
'lj': 'Lj',
'Nj': 'Nj',
'nj': 'Nj',
'ǰ': 'ǰ',
'Dz': 'Dz',
'dz': 'Dz',
'ʝ': '',
'ͅ': 'ͅ',
'ΐ': 'ΐ',
'ΰ': 'ΰ',
'և': 'և',
'ᏸ': 'Ᏸ',
'ᏹ': 'Ᏹ',
'ᏺ': 'Ᏺ',
'ᏻ': '',
'ᏼ': '',
'ᏽ': 'Ᏽ',
'ẖ': 'ẖ',
'ẗ': 'ẗ',
'ẘ': 'ẘ',
'ẙ': 'ẙ',
'ẚ': 'ẚ',
'ὐ': 'ὐ',
'ὒ': 'ὒ',
'ὔ': 'ὔ',
'ὖ': 'ὖ',
'ᾀ': 'ᾈ',
'ᾁ': 'ᾉ',
'ᾂ': 'ᾊ',
'ᾃ': 'ᾋ',
'ᾄ': 'ᾌ',
'ᾅ': 'ᾍ',
'ᾆ': 'ᾎ',
'ᾇ': 'ᾏ',
'ᾈ': 'ᾈ',
'ᾉ': 'ᾉ',
'ᾊ': 'ᾊ',
'ᾋ': 'ᾋ',
'ᾌ': 'ᾌ',
'ᾍ': 'ᾍ',
'ᾎ': 'ᾎ',
'ᾏ': 'ᾏ',
'ᾐ': 'ᾘ',
'ᾑ': 'ᾙ',
'ᾒ': 'ᾚ',
'ᾓ': 'ᾛ',
'ᾔ': 'ᾜ',
'ᾕ': 'ᾝ',
'ᾖ': 'ᾞ',
'ᾗ': 'ᾟ',
'ᾘ': 'ᾘ',
'ᾙ': 'ᾙ',
'ᾚ': 'ᾚ',
'ᾛ': 'ᾛ',
'ᾜ': 'ᾜ',
'ᾝ': 'ᾝ',
'ᾞ': 'ᾞ',
'ᾟ': 'ᾟ',
'ᾠ': 'ᾨ',
'ᾡ': 'ᾩ',
'ᾢ': 'ᾪ',
'ᾣ': 'ᾫ',
'ᾤ': 'ᾬ',
'ᾥ': 'ᾭ',
'ᾦ': 'ᾮ',
'ᾧ': 'ᾯ',
'ᾨ': 'ᾨ',
'ᾩ': 'ᾩ',
'ᾪ': 'ᾪ',
'ᾫ': 'ᾫ',
'ᾬ': 'ᾬ',
'ᾭ': 'ᾭ',
'ᾮ': 'ᾮ',
'ᾯ': 'ᾯ',
'ᾲ': 'ᾲ',
'ᾳ': 'ᾼ',
'ᾴ': 'ᾴ',
'ᾶ': 'ᾶ',
'ᾷ': 'ᾷ',
'ᾼ': 'ᾼ',
'ῂ': 'ῂ',
'ῃ': 'ῌ',
'ῄ': 'ῄ',
'ῆ': 'ῆ',
'ῇ': 'ῇ',
'ῌ': 'ῌ',
'ῒ': 'ῒ',
'ΐ': 'ΐ',
'ῖ': 'ῖ',
'ῗ': 'ῗ',
'ῢ': 'ῢ',
'ΰ': 'ΰ',
'ῤ': 'ῤ',
'ῦ': 'ῦ',
'ῧ': 'ῧ',
'ῲ': 'ῲ',
'ῳ': 'ῼ',
'ῴ': 'ῴ',
'ῶ': 'ῶ',
'ῷ': 'ῷ',
'ῼ': 'ῼ',
'': '',
'ⅱ': 'ⅱ',
'ⅲ': 'ⅲ',
'ⅳ': 'ⅳ',
'': '',
'ⅵ': 'ⅵ',
'ⅶ': 'ⅶ',
'ⅷ': 'ⅷ',
'ⅸ': 'ⅸ',
'': '',
'ⅺ': 'ⅺ',
'ⅻ': 'ⅻ',
'': '',
'': '',
'': '',
'ⅿ': 'ⅿ',
'ⓐ': 'ⓐ',
'ⓑ': 'ⓑ',
'ⓒ': 'ⓒ',
'ⓓ': 'ⓓ',
'ⓔ': 'ⓔ',
'ⓕ': 'ⓕ',
'ⓖ': 'ⓖ',
'ⓗ': 'ⓗ',
'ⓘ': 'ⓘ',
'ⓙ': 'ⓙ',
'ⓚ': 'ⓚ',
'ⓛ': 'ⓛ',
'ⓜ': 'ⓜ',
'ⓝ': 'ⓝ',
'ⓞ': 'ⓞ',
'ⓟ': 'ⓟ',
'ⓠ': 'ⓠ',
'ⓡ': 'ⓡ',
'ⓢ': 'ⓢ',
'ⓣ': 'ⓣ',
'ⓤ': 'ⓤ',
'ⓥ': 'ⓥ',
'ⓦ': 'ⓦ',
'ⓧ': 'ⓧ',
'ⓨ': 'ⓨ',
'ⓩ': 'ⓩ',
'ꞵ': '',
'ꞷ': 'Ꞷ',
'ꭓ': '',
'ꭰ': '',
'ꭱ': '',
'ꭲ': '',
'ꭳ': 'Ꭳ',
'ꭴ': 'Ꭴ',
'': '',
'ꭶ': 'Ꭶ',
'ꭷ': 'Ꭷ',
'ꭸ': 'Ꭸ',
'ꭹ': '',
'ꭺ': '',
'ꭻ': '',
'ꭼ': '',
'ꭽ': 'Ꭽ',
'ꭾ': '',
'ꭿ': 'Ꭿ',
'ꮀ': 'Ꮀ',
'': 'Ꮁ',
'ꮂ': 'Ꮂ',
'': '',
'ꮄ': 'Ꮄ',
'ꮅ': 'Ꮅ',
'ꮆ': 'Ꮆ',
'ꮇ': '',
'ꮈ': 'Ꮈ',
'ꮉ': 'Ꮉ',
'ꮊ': 'Ꮊ',
'ꮋ': '',
'ꮌ': 'Ꮌ',
'ꮍ': '',
'ꮎ': 'Ꮎ',
'ꮏ': 'Ꮏ',
'ꮐ': '',
'ꮑ': 'Ꮑ',
'ꮒ': '',
'': '',
'ꮔ': 'Ꮔ',
'ꮕ': 'Ꮕ',
'ꮖ': 'Ꮖ',
'ꮗ': 'Ꮗ',
'ꮘ': 'Ꮘ',
'ꮙ': 'Ꮙ',
'ꮚ': 'Ꮚ',
'ꮛ': 'Ꮛ',
'ꮜ': 'Ꮜ',
'ꮝ': 'Ꮝ',
'ꮞ': '',
'ꮟ': '',
'ꮠ': 'Ꮠ',
'ꮡ': 'Ꮡ',
'ꮢ': '',
'ꮣ': 'Ꮣ',
'ꮤ': '',
'ꮥ': '',
'ꮦ': 'Ꮦ',
'ꮧ': 'Ꮧ',
'ꮨ': 'Ꮨ',
'': '',
'': '',
'ꮫ': 'Ꮫ',
'ꮬ': 'Ꮬ',
'ꮭ': 'Ꮭ',
'ꮮ': '',
'': '',
'ꮰ': 'Ꮰ',
'ꮱ': 'Ꮱ',
'ꮲ': '',
'ꮳ': 'Ꮳ',
'ꮴ': 'Ꮴ',
'ꮵ': 'Ꮵ',
'ꮶ': '',
'ꮷ': '',
'ꮸ': 'Ꮸ',
'ꮹ': 'Ꮹ',
'ꮺ': 'Ꮺ',
'ꮻ': 'Ꮻ',
'ꮼ': 'Ꮼ',
'ꮽ': 'Ꮽ',
'ꮾ': '',
'ꮿ': 'Ꮿ',
'ff': 'ff',
'fi': 'fi',
'fl': 'fl',
'ffi': 'ffi',
'ffl': 'ffl',
'ſt': 'ſt',
'st': 'st',
'ﬓ': 'ﬓ',
'ﬔ': 'ﬔ',
'ﬕ': 'ﬕ',
'ﬖ': 'ﬖ',
'ﬗ': 'ﬗ'
};
mw.Title.phpCharToUpper = function ( chr ) {
var mapped = toUpperMapping[ chr ];
return mapped || chr.toUpperCase();
};
}( mediaWiki ) );

View file

@ -298,7 +298,7 @@
}, 'Throw error on empty string' );
} );
QUnit.test( 'Case-sensivity', 3, function ( assert ) {
QUnit.test( 'Case-sensivity', 5, function ( assert ) {
var title;
// Default config
@ -307,6 +307,12 @@
title = new mw.Title( 'article' );
assert.equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
title = new mw.Title( 'ß' );
assert.equal( title.toString(), 'ß', 'Uppercasing matches PHP behaviour (ß -> ß, not SS)' );
title = new mw.Title( 'dž (digraph)' );
assert.equal( title.toString(), 'Dž_(digraph)', 'Uppercasing matches PHP behaviour (dž -> Dž, not DŽ)' );
// $wgCapitalLinks = false;
mw.config.set( 'wgCaseSensitiveNamespaces', [ 0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15 ] );