Merge "Change 'editfont' default preference to 'monospace'"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 21 Aug 2017 16:42:23 +0000 (16:42 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 21 Aug 2017 16:42:23 +0000 (16:42 +0000)
732 files changed:
.gitattributes
.gitignore
.mailmap
.stylelintrc [deleted file]
.stylelintrc.json [new file with mode: 0644]
.travis.yml
CREDITS
Gruntfile.js
RELEASE-NOTES-1.30
autoload.php
composer.json
docs/database.txt
docs/hooks.txt
includes/AuthPlugin.php
includes/Block.php
includes/Category.php
includes/ConfiguredReadOnlyMode.php [new file with mode: 0644]
includes/DefaultSettings.php
includes/EditPage.php
includes/FauxRequest.php
includes/Feed.php
includes/FileDeleteForm.php
includes/GlobalFunctions.php
includes/HistoryBlob.php
includes/Licenses.php
includes/LinkFilter.php
includes/Linker.php
includes/ListToggle.php
includes/MWNamespace.php
includes/MagicWord.php
includes/MagicWordArray.php
includes/MediaWiki.php
includes/MergeHistory.php
includes/Message.php
includes/MimeMagic.php
includes/MovePage.php
includes/OutputPage.php
includes/PHPVersionCheck.php
includes/Preferences.php
includes/ProtectionForm.php
includes/RawMessage.php [new file with mode: 0644]
includes/ReadOnlyMode.php
includes/Revision.php
includes/RevisionList.php
includes/Sanitizer.php
includes/ServiceWiring.php
includes/Setup.php
includes/SiteConfiguration.php
includes/SiteStats.php
includes/StreamFile.php
includes/StubObject.php
includes/Title.php
includes/TrackingCategories.php
includes/WikiMap.php
includes/Xml.php
includes/actions/Action.php
includes/actions/InfoAction.php
includes/api/ApiAuthManagerHelper.php
includes/api/ApiBase.php
includes/api/ApiCSPReport.php
includes/api/ApiDelete.php
includes/api/ApiEmailUser.php
includes/api/ApiMain.php
includes/api/ApiPageSet.php
includes/api/ApiParamInfo.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryLinks.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQuerySearch.php
includes/api/ApiQueryWatchlist.php
includes/api/ApiResult.php
includes/api/ApiUsageException.php
includes/api/SearchApi.php
includes/api/i18n/ar.json
includes/api/i18n/he.json
includes/api/i18n/ko.json
includes/api/i18n/nb.json
includes/api/i18n/nl.json
includes/api/i18n/ru.json
includes/api/i18n/zh-hant.json
includes/auth/AbstractAuthenticationProvider.php
includes/auth/AbstractPrimaryAuthenticationProvider.php
includes/auth/AbstractSecondaryAuthenticationProvider.php
includes/auth/AuthManager.php
includes/auth/AuthenticationResponse.php
includes/auth/CreateFromLoginAuthenticationRequest.php
includes/auth/PrimaryAuthenticationProvider.php
includes/cache/HTMLFileCache.php
includes/cache/LinkBatch.php
includes/cache/MessageCache.php
includes/cache/localisation/LocalisationCache.php
includes/changes/ChangesFeed.php
includes/changes/ChangesList.php
includes/changes/ChangesListBooleanFilter.php
includes/changes/ChangesListBooleanFilterGroup.php
includes/changes/ChangesListFilterGroup.php
includes/changes/ChangesListStringOptionsFilter.php
includes/changes/ChangesListStringOptionsFilterGroup.php
includes/changes/EnhancedChangesList.php
includes/changes/OldChangesList.php
includes/changes/RecentChange.php
includes/changetags/ChangeTags.php
includes/collation/CustomUppercaseCollation.php
includes/collation/IcuCollation.php
includes/collation/NumericUppercaseCollation.php
includes/compat/normal/UtfNormal.php
includes/config/EtcdConfig.php
includes/content/ContentHandler.php
includes/content/JsonContent.php
includes/content/TextContent.php
includes/content/TextContentHandler.php
includes/context/ContextSource.php
includes/context/DerivativeContext.php
includes/context/RequestContext.php
includes/dao/DBAccessObjectUtils.php
includes/dao/IDBAccessObject.php
includes/db/CloneDatabase.php
includes/db/MWLBFactory.php
includes/db/ORAResult.php
includes/debug/MWDebug.php
includes/debug/logger/LegacyLogger.php
includes/debug/logger/monolog/BufferHandler.php
includes/debug/logger/monolog/KafkaHandler.php
includes/debug/logger/monolog/LineFormatter.php
includes/debug/logger/monolog/WikiProcessor.php
includes/deferred/DeferredUpdates.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/LinksUpdate.php
includes/deferred/SearchUpdate.php
includes/deferred/SiteStatsUpdate.php
includes/deferred/WANCacheReapUpdate.php
includes/diff/DiffFormatter.php
includes/diff/DifferenceEngine.php
includes/diff/WordLevelDiff.php
includes/exception/HttpError.php
includes/exception/MWExceptionHandler.php
includes/exception/MWExceptionRenderer.php
includes/export/DumpFilter.php
includes/export/DumpNamespaceFilter.php
includes/export/WikiExporter.php
includes/filebackend/filejournal/DBFileJournal.php
includes/filerepo/FileBackendDBRepoWrapper.php
includes/filerepo/FileRepo.php
includes/filerepo/ForeignAPIRepo.php
includes/filerepo/file/File.php
includes/filerepo/file/UnregisteredLocalFile.php
includes/gallery/TraditionalImageGallery.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/OOUIHTMLForm.php
includes/htmlform/fields/HTMLCheckField.php
includes/htmlform/fields/HTMLFormFieldCloner.php
includes/htmlform/fields/HTMLFormFieldWithButton.php
includes/htmlform/fields/HTMLMultiSelectField.php
includes/htmlform/fields/HTMLRadioField.php
includes/htmlform/fields/HTMLTextAreaField.php
includes/htmlform/fields/HTMLTextField.php
includes/htmlform/fields/HTMLUsersMultiselectField.php
includes/http/Http.php
includes/import/ImportStreamSource.php
includes/import/UploadSourceAdapter.php
includes/import/WikiImporter.php
includes/installer/CliInstaller.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/MssqlUpdater.php
includes/installer/MysqlUpdater.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteInstaller.php
includes/installer/SqliteUpdater.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerOptions.php
includes/installer/i18n/ar.json
includes/installer/i18n/be-tarask.json
includes/installer/i18n/bn.json
includes/installer/i18n/csb.json
includes/installer/i18n/de.json
includes/installer/i18n/en.json
includes/installer/i18n/fa.json
includes/installer/i18n/fr.json
includes/installer/i18n/he.json
includes/installer/i18n/hi.json
includes/installer/i18n/ko.json
includes/installer/i18n/mk.json
includes/installer/i18n/ms.json
includes/installer/i18n/nb.json
includes/installer/i18n/nl.json
includes/installer/i18n/pt.json
includes/installer/i18n/qqq.json
includes/installer/i18n/roa-tara.json
includes/installer/i18n/ru.json
includes/installer/i18n/sv.json
includes/installer/i18n/zh-hans.json
includes/jobqueue/JobQueue.php
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobQueueFederated.php
includes/jobqueue/JobQueueGroup.php
includes/jobqueue/JobQueueSecondTestQueue.php [new file with mode: 0644]
includes/jobqueue/JobRunner.php
includes/jobqueue/jobs/CategoryMembershipChangeJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/libs/ArrayUtils.php
includes/libs/CSSMin.php
includes/libs/GenericArrayObject.php
includes/libs/HashRing.php
includes/libs/IEUrlExtension.php
includes/libs/IP.php
includes/libs/MemoizedCallable.php
includes/libs/MultiHttpClient.php
includes/libs/StatusValue.php
includes/libs/StringUtils.php
includes/libs/composer/ComposerInstalled.php
includes/libs/composer/ComposerLock.php
includes/libs/filebackend/FileBackend.php
includes/libs/filebackend/FileBackendStore.php
includes/libs/filebackend/HTTPFileStreamer.php
includes/libs/filebackend/SwiftFileBackend.php
includes/libs/filebackend/fileop/FileOp.php
includes/libs/lockmanager/ScopedLock.php
includes/libs/mime/IEContentAnalyzer.php
includes/libs/mime/MimeAnalyzer.php
includes/libs/mime/XmlTypeCheck.php
includes/libs/objectcache/APCBagOStuff.php
includes/libs/objectcache/APCUBagOStuff.php
includes/libs/objectcache/BagOStuff.php
includes/libs/objectcache/HashBagOStuff.php
includes/libs/objectcache/MemcachedPeclBagOStuff.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/objectcache/RESTBagOStuff.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/objectcache/WANObjectCacheReaper.php
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/TransactionProfiler.php
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabaseMysqli.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/database/IDatabase.php
includes/libs/rdbms/database/position/MySQLMasterPos.php
includes/libs/rdbms/database/resultwrapper/MssqlResultWrapper.php
includes/libs/rdbms/encasing/Blob.php
includes/libs/rdbms/exception/DBExpectedError.php
includes/libs/rdbms/exception/DBQueryError.php
includes/libs/rdbms/lbfactory/ILBFactory.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/rdbms/loadmonitor/ILoadMonitor.php
includes/libs/rdbms/loadmonitor/LoadMonitor.php
includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
includes/libs/redis/RedisConnectionPool.php
includes/libs/stats/BufferingStatsdDataFactory.php
includes/libs/stats/IBufferingStatsdDataFactory.php
includes/libs/stats/NullStatsdDataFactory.php
includes/libs/stats/SamplingStatsdClient.php
includes/logging/BlockLogFormatter.php
includes/logging/LogEventsList.php
includes/logging/LogPage.php
includes/logging/LogPager.php
includes/mail/EmailNotification.php
includes/mail/UserMailer.php
includes/media/Bitmap.php
includes/media/Bitmap_ClientOnly.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/FormatMetadata.php
includes/media/ImageHandler.php
includes/media/Jpeg.php
includes/media/MediaHandler.php
includes/media/SVG.php
includes/media/SVGMetadataExtractor.php
includes/media/TransformationalImageHandler.php
includes/media/WebP.php
includes/objectcache/SqlBagOStuff.php
includes/page/Article.php
includes/page/CategoryPage.php
includes/page/ImagePage.php
includes/page/WikiPage.php
includes/pager/IndexPager.php
includes/parser/LinkHolderArray.php
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/profiler/ProfileSection.php
includes/profiler/Profiler.php
includes/profiler/SectionProfiler.php
includes/profiler/output/ProfilerOutput.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderJqueryMsgModule.php
includes/resourceloader/ResourceLoaderMediaWikiUtilModule.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderModule.php
includes/revisiondelete/RevDelItem.php
includes/revisiondelete/RevDelList.php
includes/revisiondelete/RevisionDeleter.php
includes/search/NullIndexField.php
includes/search/SearchDatabase.php
includes/search/SearchEngine.php
includes/search/SearchExactMatchRescorer.php
includes/search/SearchHighlighter.php
includes/search/SearchIndexField.php
includes/search/SearchIndexFieldDefinition.php
includes/search/SearchMySQL.php
includes/search/SearchResult.php
includes/search/SearchSqlite.php
includes/search/SearchSuggestion.php
includes/services/ServiceContainer.php
includes/session/CookieSessionProvider.php
includes/session/PHPSessionHandler.php
includes/session/SessionProvider.php
includes/session/Token.php
includes/site/Site.php
includes/site/SiteImporter.php
includes/skins/BaseTemplate.php
includes/skins/QuickTemplate.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specialpage/AuthManagerSpecialPage.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/RedirectSpecialPage.php
includes/specialpage/SpecialPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialActiveusers.php
includes/specials/SpecialAllMessages.php
includes/specials/SpecialAllPages.php
includes/specials/SpecialBlock.php
includes/specials/SpecialBrokenRedirects.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDiff.php
includes/specials/SpecialDoubleRedirects.php
includes/specials/SpecialExport.php
includes/specials/SpecialFilepath.php
includes/specials/SpecialImport.php
includes/specials/SpecialListgrants.php
includes/specials/SpecialListgrouprights.php
includes/specials/SpecialListredirects.php
includes/specials/SpecialListusers.php
includes/specials/SpecialMediaStatistics.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialPagesWithProp.php
includes/specials/SpecialPermanentLink.php
includes/specials/SpecialPreferences.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialRecentchangeslinked.php
includes/specials/SpecialRevisiondelete.php
includes/specials/SpecialSearch.php
includes/specials/SpecialShortpages.php
includes/specials/SpecialSpecialpages.php
includes/specials/SpecialUncategorizedcategories.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUpload.php
includes/specials/SpecialVersion.php
includes/specials/SpecialWatchlist.php
includes/specials/helpers/LoginHelper.php
includes/specials/pagers/AllMessagesTablePager.php
includes/specials/pagers/ContribsPager.php
includes/specials/pagers/ProtectedPagesPager.php
includes/specials/pagers/UsersPager.php
includes/templates/EnhancedChangesListGroup.mustache
includes/tidy/Balancer.php
includes/tidy/RemexCompatMunger.php
includes/upload/UploadBase.php
includes/upload/UploadFromChunks.php
includes/upload/UploadFromFile.php
includes/upload/UploadFromStash.php
includes/upload/UploadFromUrl.php
includes/user/BotPassword.php
includes/user/User.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowIterator.php
includes/utils/BatchRowUpdate.php
includes/utils/BatchRowWriter.php
includes/utils/UIDGenerator.php
includes/widget/SearchInputWidget.php
includes/widget/SelectWithInputWidget.php
includes/widget/search/BasicSearchResultSetWidget.php
includes/widget/search/InterwikiSearchResultSetWidget.php
includes/widget/search/InterwikiSearchResultWidget.php
jsduck.json
languages/ConverterRule.php
languages/Language.php
languages/LanguageCode.php
languages/classes/LanguageEn.php
languages/classes/LanguageKk.php
languages/classes/LanguageSr.php
languages/data/Names.php
languages/i18n/af.json
languages/i18n/ar.json
languages/i18n/as.json
languages/i18n/ast.json
languages/i18n/awa.json
languages/i18n/azb.json
languages/i18n/ba.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/bho.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/ce.json
languages/i18n/ckb.json
languages/i18n/cs.json
languages/i18n/csb.json
languages/i18n/cv.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/din.json
languages/i18n/el.json
languages/i18n/en-gb.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gd.json
languages/i18n/gl.json
languages/i18n/gor.json
languages/i18n/got.json
languages/i18n/gsw.json
languages/i18n/gu.json
languages/i18n/ha.json
languages/i18n/hak.json
languages/i18n/he.json
languages/i18n/hi.json
languages/i18n/hif-latn.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/hy.json
languages/i18n/ia.json
languages/i18n/id.json
languages/i18n/inh.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/jam.json
languages/i18n/jv.json
languages/i18n/kab.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/li.json
languages/i18n/lki.json
languages/i18n/lv.json
languages/i18n/lzh.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/mwl.json
languages/i18n/my.json
languages/i18n/nan.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/ne.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/oc.json
languages/i18n/pl.json
languages/i18n/pnb.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/rif.json
languages/i18n/rm.json
languages/i18n/ro.json
languages/i18n/roa-tara.json
languages/i18n/ru.json
languages/i18n/sa.json
languages/i18n/sd.json
languages/i18n/shi.json
languages/i18n/shn.json
languages/i18n/sk.json
languages/i18n/skr-arab.json [new file with mode: 0644]
languages/i18n/sl.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/su.json
languages/i18n/sv.json
languages/i18n/tay.json [new file with mode: 0644]
languages/i18n/te.json
languages/i18n/tet.json
languages/i18n/tg-cyrl.json
languages/i18n/th.json
languages/i18n/tl.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/ug-arab.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/vi.json
languages/i18n/vro.json
languages/i18n/yi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesKm.php
languages/messages/MessagesSkr.php [new file with mode: 0644]
languages/messages/MessagesSkr_arab.php [new file with mode: 0644]
maintenance/Maintenance.php
maintenance/addRFCandPMIDInterwiki.php
maintenance/archives/patch-ip_changes.sql [new file with mode: 0644]
maintenance/benchmarks/benchmarkLruHash.php [new file with mode: 0644]
maintenance/generateSitemap.php
maintenance/hhvm/makeRepo.php
maintenance/jsduck/categories.json
maintenance/language/checkLanguage.inc
maintenance/mssql/archives/patch-add-3d.sql [new file with mode: 0644]
maintenance/mssql/tables.sql
maintenance/namespaceDupes.php
maintenance/populatePPSortKey.php [new file with mode: 0644]
maintenance/postgres/archives/patch-add-3d.sql [new file with mode: 0644]
maintenance/postgres/tables.sql
maintenance/rebuildrecentchanges.php
maintenance/refreshLinks.php
maintenance/sqlite.inc
maintenance/sqlite/archives/patch-add-3d.sql [new file with mode: 0644]
maintenance/sqlite/archives/patch-ip_changes.sql [new file with mode: 0644]
maintenance/tables.sql
maintenance/updateCredits.php
maintenance/userOptions.inc
phpcs.xml
profileinfo.php
resources/Resources.php
resources/lib/html5shiv/html5shiv.js [new file with mode: 0644]
resources/lib/html5shiv/html5shiv.min.js [new file with mode: 0644]
resources/lib/oojs-ui/i18n/as.json
resources/lib/oojs-ui/i18n/bs.json
resources/lib/oojs-ui/i18n/pt-br.json
resources/lib/oojs-ui/oojs-ui-apex.js
resources/lib/oojs-ui/oojs-ui-core-apex.css
resources/lib/oojs-ui/oojs-ui-core-wikimediaui.css
resources/lib/oojs-ui/oojs-ui-core.js
resources/lib/oojs-ui/oojs-ui-core.js.map
resources/lib/oojs-ui/oojs-ui-toolbars-apex.css
resources/lib/oojs-ui/oojs-ui-toolbars-wikimediaui.css
resources/lib/oojs-ui/oojs-ui-toolbars.js
resources/lib/oojs-ui/oojs-ui-widgets-apex.css
resources/lib/oojs-ui/oojs-ui-widgets-wikimediaui.css
resources/lib/oojs-ui/oojs-ui-widgets.js
resources/lib/oojs-ui/oojs-ui-widgets.js.map
resources/lib/oojs-ui/oojs-ui-wikimediaui.js
resources/lib/oojs-ui/oojs-ui-windows-apex.css
resources/lib/oojs-ui/oojs-ui-windows-wikimediaui.css
resources/lib/oojs-ui/oojs-ui-windows.js
resources/lib/oojs-ui/themes/apex/icons-media.json
resources/lib/oojs-ui/themes/apex/images/icons/play-ltr.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/play-ltr.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/play-rtl.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/apex/images/icons/play-rtl.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr-invert.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr-invert.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr-progressive.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr-progressive.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-ltr.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl-invert.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl-invert.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl-progressive.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl-progressive.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/play-rtl.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop-invert.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop-invert.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop-progressive.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop-progressive.svg
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop.png
resources/lib/oojs-ui/themes/wikimediaui/images/icons/stop.svg
resources/lib/qunitjs/qunit.css
resources/lib/qunitjs/qunit.js
resources/src/jquery/jquery.mwExtension.js [deleted file]
resources/src/jquery/jquery.tablesorter.js
resources/src/mediawiki.action/mediawiki.action.edit.js
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
resources/src/mediawiki.action/mediawiki.action.edit.styles.css
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/wikibits.js
resources/src/mediawiki.less/mediawiki.mixins.animation.less
resources/src/mediawiki.less/mediawiki.ui/variables.less
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.SavedQueriesModel.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.SavedQueryItemModel.js
resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
resources/src/mediawiki.rcfilters/mw.rcfilters.HighlightColors.js
resources/src/mediawiki.rcfilters/mw.rcfilters.UriProcessor.js
resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
resources/src/mediawiki.rcfilters/mw.rcfilters.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesLimitPopupWidget.less [new file with mode: 0644]
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterTagMultiselectWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterWrapperWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.LiveUpdateButtonWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.less
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesLimitButtonWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesLimitPopupWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.DateButtonWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemHighlightButton.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterMenuHeaderWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterMenuSectionOptionWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.LiveUpdateButtonWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js [new file with mode: 0644]
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListItemWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ValuePickerWidget.js
resources/src/mediawiki.skinning/content.parsoid.less
resources/src/mediawiki.skinning/interface.css
resources/src/mediawiki.special/mediawiki.special.block.js
resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js
resources/src/mediawiki.special/mediawiki.special.preferences.styles.css
resources/src/mediawiki.special/mediawiki.special.search.interwikiwidget.styles.less
resources/src/mediawiki.special/mediawiki.special.search.styles.css
resources/src/mediawiki.special/mediawiki.special.watchlist.css [new file with mode: 0644]
resources/src/mediawiki.special/mediawiki.special.watchlist.js
resources/src/mediawiki.toolbar/toolbar.js
resources/src/mediawiki.ui/components/checkbox.less
resources/src/mediawiki.ui/components/images/checkbox-checked.png [new file with mode: 0644]
resources/src/mediawiki.ui/components/images/checkbox-checked.svg [new file with mode: 0644]
resources/src/mediawiki.ui/components/images/checked_disabled.png [deleted file]
resources/src/mediawiki.ui/components/images/checked_disabled.svg [deleted file]
resources/src/mediawiki.ui/components/images/radio_checked.png [deleted file]
resources/src/mediawiki.ui/components/images/radio_checked.svg [deleted file]
resources/src/mediawiki.ui/components/images/radio_disabled.png [deleted file]
resources/src/mediawiki.ui/components/images/radio_disabled.svg [deleted file]
resources/src/mediawiki.ui/components/radio.less
resources/src/mediawiki.widgets.visibleByteLimit/mediawiki.widgets.visibleByteLimit.js
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
resources/src/mediawiki/htmlform/selectorother.js
resources/src/mediawiki/mediawiki.checkboxtoggle.js
resources/src/mediawiki/mediawiki.hlist-allskins.less [new file with mode: 0644]
resources/src/mediawiki/mediawiki.hlist.css
resources/src/mediawiki/mediawiki.toc.print.css
resources/src/mediawiki/mediawiki.util.js
resources/src/mediawiki/page/gallery.css
resources/src/mediawiki/page/gallery.print.css
resources/src/mediawiki/page/watch.js
resources/src/oojs-ui-local.css
tests/common/TestsAutoLoader.php
tests/parser/ParserTestRunner.php
tests/parser/parserTests.txt
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/ResourceLoaderTestCase.php
tests/phpunit/data/media/say-test-mpeg1.mp3 [new file with mode: 0644]
tests/phpunit/data/media/say-test-mpeg2.5.mp3 [new file with mode: 0644]
tests/phpunit/data/media/say-test-mpeg2.mp3 [new file with mode: 0644]
tests/phpunit/data/media/say-test-with-id3.mp3 [new file with mode: 0644]
tests/phpunit/includes/DeprecatedGlobalTest.php
tests/phpunit/includes/GitInfoTest.php
tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
tests/phpunit/includes/PreferencesTest.php
tests/phpunit/includes/RevisionStorageTest.php
tests/phpunit/includes/SanitizerTest.php
tests/phpunit/includes/SiteStatsTest.php [new file with mode: 0644]
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/WatchedItemQueryServiceUnitTest.php
tests/phpunit/includes/WatchedItemStoreUnitTest.php
tests/phpunit/includes/api/ApiErrorFormatterTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/auth/LegacyHookPreAuthenticationProviderTest.php
tests/phpunit/includes/changes/ChangesListFilterTest.php
tests/phpunit/includes/changes/EnhancedChangesListTest.php
tests/phpunit/includes/changes/OldChangesListTest.php
tests/phpunit/includes/changetags/ChangeTagsTest.php [new file with mode: 0644]
tests/phpunit/includes/config/ConfigFactoryTest.php
tests/phpunit/includes/config/EtcdConfigTest.php
tests/phpunit/includes/content/WikitextContentTest.php
tests/phpunit/includes/content/WikitextStructureTest.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php [deleted file]
tests/phpunit/includes/db/DatabaseSQLTest.php [deleted file]
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/db/DatabaseTest.php [deleted file]
tests/phpunit/includes/db/LBFactoryTest.php
tests/phpunit/includes/db/LoadBalancerTest.php [new file with mode: 0644]
tests/phpunit/includes/interwiki/ClassicInterwikiLookupTest.php
tests/phpunit/includes/libs/CSSMinTest.php
tests/phpunit/includes/libs/mime/MimeAnalyzerTest.php
tests/phpunit/includes/libs/objectcache/MultiWriteBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseDomainTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/xmp/XMPTest.php
tests/phpunit/includes/media/FakeDimensionFile.php
tests/phpunit/includes/page/WikiPageTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
tests/phpunit/includes/search/SearchIndexFieldTest.php
tests/phpunit/includes/site/TestSites.php
tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php
tests/phpunit/includes/specials/SpecialRecentchangesTest.php
tests/phpunit/includes/specials/SpecialShortpagesTest.php [new file with mode: 0644]
tests/phpunit/includes/specials/SpecialWatchlistTest.php
tests/phpunit/languages/LanguageCodeTest.php
tests/phpunit/mocks/MockWebRequest.php
tests/phpunit/mocks/media/MockMediaHandlerFactory.php [deleted file]
tests/phpunit/mocks/media/MockOggHandler.php [deleted file]
tests/phpunit/structure/DatabaseIntegrationTest.php [new file with mode: 0644]
tests/phpunit/suite.xml
tests/qunit/QUnitTestResources.php
tests/qunit/data/load.mock.php
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js [deleted file]
tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js

index 09f86a3..f230c60 100644 (file)
@@ -1,3 +1,4 @@
 *.sh eol=lf
 *.icc binary
 *.webp binary
+*.mp3 binary
\ No newline at end of file
index a82ae21..388f354 100644 (file)
@@ -48,8 +48,8 @@ node_modules/
 # Composer
 /vendor
 /composer.lock
-/composer.json
 /composer.local.json
+/composer.phar
 
 # MediaWiki UI documentation
 /docs/kss/static
index 2134fc5..5a76fb9 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -63,6 +63,7 @@ aude <aude.wiki@gmail.com>
 Audrey Tang <audreyt@audreyt.org>
 Audrey Tang <audreyt@audreyt.org> <au@localhost>
 ayush_garg <ayush.ce13@iitp.ac.in>
+Bae Junehyeon <devunt@gmail.com>
 Bahodir Mansurov <bmansurov@wikimedia.org>
 Bartosz Dziewoński <matma.rex@gmail.com>
 Bartosz Dziewoński <matma.rex@gmail.com> <bdziewonski@wikimedia.org>
@@ -227,7 +228,6 @@ Jon Robson <jrobson@wikimedia.org>
 Jon Robson <jrobson@wikimedia.org> <jdlrobson@gmail.com>
 Juliusz Gonera <jgonera@gmail.com>
 Juliusz Gonera <jgonera@gmail.com> <jgonera@wikimedia.org>
-JuneHyeon Bae <devunt@gmail.com>
 Jure Kajzer <freak@drajv.si>
 Jure Kajzer <freak@drajv.si> <freakolowsky@users.mediawiki.org>
 Justin Du <justin.d128@gmail.com>
diff --git a/.stylelintrc b/.stylelintrc
deleted file mode 100644 (file)
index 27e289d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-       "extends": "stylelint-config-wikimedia",
-       "rules": {
-               "no-descending-specificity": null,
-
-               "selector-no-id": null
-       }
-}
diff --git a/.stylelintrc.json b/.stylelintrc.json
new file mode 100644 (file)
index 0000000..27e289d
--- /dev/null
@@ -0,0 +1,8 @@
+{
+       "extends": "stylelint-config-wikimedia",
+       "rules": {
+               "no-descending-specificity": null,
+
+               "selector-no-id": null
+       }
+}
index 5e2c7a0..cde7193 100644 (file)
@@ -7,11 +7,12 @@
 # complement that setup by testing MediaWiki on travis
 #
 language: php
-# Use the slower sudo-enabled VMs instead of fast containers:
-# - Package 'djvulibre-bin' is not yet whitelisted for trusty containers.
-#   https://github.com/travis-ci/apt-package-whitelist/issues/4036
-sudo: required
-# Use Trusty instead of Travis default (precise)
+
+
+# Use fast containers instead of the slower sudo-enabled VMs:
+sudo: false
+# Use Ubuntu 14 Trusty (not Ubuntu 12 Precise)
+# <https://docs.travis-ci.com/user/reference/trusty/>
 # - Required in order to use HHVM 3.6 or higher.
 # - Required for non-buggy xml library for XmlTypeCheck/UploadBaseTest (T75176).
 dist: trusty
@@ -25,10 +26,11 @@ matrix:
       php: 5.5
     - env: dbtype=postgres dbuser=travis
       php: 5.5
+    # https://docs.travis-ci.com/user/languages/php#HHVM-versions
     - env: dbtype=mysql dbuser=root
-      # https://docs.travis-ci.com/user/languages/php#HHVM-versions
-      # https://github.com/travis-ci/travis-ci/issues/7368
       php: hhvm-3.12
+    - env: dbtype=mysql dbuser=root
+      php: hhvm-3.18
     - env: dbtype=mysql dbuser=root
       php: 7
 
diff --git a/CREDITS b/CREDITS
index 14c454e..c38c3fc 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -78,6 +78,7 @@ The following list can be found parsed under Special:Version/Credits -->
 * awu42
 * ayush_garg
 * Azliq7
+* Bae Junehyeon
 * Bagariavivek
 * Bahodir Mansurov
 * balloonguy
@@ -312,7 +313,6 @@ The following list can be found parsed under Special:Version/Credits -->
 * Julian Ostrow
 * Juliano F. Ravasi
 * Juliusz Gonera
-* JuneHyeon Bae
 * Jure Kajzer
 * Justin Du
 * Kai Nissen
index 811d2c0..dbbfcb8 100644 (file)
@@ -44,8 +44,6 @@ module.exports = function ( grunt ) {
                                '!extensions/**/*.js',
                                '!skins/**/*.js',
                                // Skip functions aren't even parseable
-                               '!resources/src/dom-level2-skip.js',
-                               '!resources/src/es5-skip.js',
                                '!resources/src/mediawiki.hidpi-skip.js'
                        ]
                },
index 51f9764..dd39561 100644 (file)
@@ -26,6 +26,13 @@ section).
   array. This allows dependency injection to be used for ResourceLoader modules.
 * $wgExceptionHooks has been removed.
 * (T45547) $wgUsePigLatinVariant added (off by default).
+* (T152540) MediaWiki now supports a section ID escaping style that allows to display
+  non-Latin characters verbatim on many modern browsers. This is controlled by the
+  new configuration setting, $wgFragmentMode.
+* $wgExperimentalHtmlIds is now deprecated and will be removed in a future version,
+  use $wgFragmentMode to migrate off it to a modern alternative.
+* $wgExternalInterwikiFragmentMode was introduced to control how fragments in
+  sinterwikis going outside of current wiki farm are encoded.
 
 === New features in 1.30 ===
 * (T37247) Output from Parser::parse() will now be wrapped in a div with
@@ -42,10 +49,17 @@ section).
 * Added RecentChangesPurgeRows hook to allow extensions to purge data that
   depends on the recentchanges table.
 * Added JS config values wgDiffOldId/wgDiffNewId to the output of diff pages.
+* (T2424) Added direct unwatch links to entries in Special:Watchlist (if the
+  'watchlistunwatchlinks' preference option is enabled). With JavaScript
+  enabled, these links toggle so the user can also re-watch pages that have
+  just been unwatched.
+* Added $wgParserTestMediaHandlers, where mock media handlers can be passed to
+  MediaHandlerFactory for parser tests.
 
 === Languages updated in 1.30 ===
 
 * Support for kbp (Kabɩyɛ / Kabiyè) was added.
+* Support for skr (Saraiki, سرائیکی) was added.
 
 === External library changes in 1.30 ===
 
@@ -142,6 +156,21 @@ changes to languages because of Phabricator reports.
   MediaWikiServices instead. Access to the underlying BagOStuff is possible
   through the new ParserCache::getCacheStorage() method.
 * .mw-ui-constructive CSS class (deprecated in 1.27) was removed.
+* Sanitizer::escapeId() was deprecated, use escapeIdForAttribute(),
+  escapeIdForLink() or escapeIdForExternalInterwiki() instead.
+* Title::escapeFragmentForURL() was deprecated, use one of the aforementioned
+  Sanitizer functions or, if possible, Title::getFragmentForURL().
+* Second parameter to Sanitizer::escapeIdReferenceList() ($options) now does
+  nothing and is deprecated.
+* mw.util.escapeId() was deprecated, use escapeIdForAttribute() or
+  escapeIdForLink().
+* MagicWord::replaceMultiple() (deprecated in 1.25) was removed.
+* WikiImporter now requires the second parameter to be an instance of the Config,
+  class. Prior to that, the Config parameter was optional (a behavior deprecated in
+  1.25).
+* Removed 'jquery.mwExtension' module. (deprecated since 1.26)
+* mediawiki.ui: Deprecate greys, which are not part of WikimediaUI color palette
+  any more.
 
 == Compatibility ==
 MediaWiki 1.30 requires PHP 5.5.9 or later. There is experimental support for
index a6128a4..d9e85bd 100644 (file)
@@ -193,6 +193,7 @@ $wgAutoloadLocalClasses = [
        'BenchmarkDeleteTruncate' => __DIR__ . '/maintenance/benchmarks/bench_delete_truncate.php',
        'BenchmarkHooks' => __DIR__ . '/maintenance/benchmarks/benchmarkHooks.php',
        'BenchmarkJSMinPlus' => __DIR__ . '/maintenance/benchmarks/benchmarkJSMinPlus.php',
+       'BenchmarkLruHash' => __DIR__ . '/maintenance/benchmarks/benchmarkLruHash.php',
        'BenchmarkParse' => __DIR__ . '/maintenance/benchmarks/benchmarkParse.php',
        'BenchmarkPurge' => __DIR__ . '/maintenance/benchmarks/benchmarkPurge.php',
        'BenchmarkTidy' => __DIR__ . '/maintenance/benchmarks/benchmarkTidy.php',
@@ -290,7 +291,7 @@ $wgAutoloadLocalClasses = [
        'Config' => __DIR__ . '/includes/config/Config.php',
        'ConfigException' => __DIR__ . '/includes/config/ConfigException.php',
        'ConfigFactory' => __DIR__ . '/includes/config/ConfigFactory.php',
-       'ConfiguredReadOnlyMode' => __DIR__ . '/includes/ReadOnlyMode.php',
+       'ConfiguredReadOnlyMode' => __DIR__ . '/includes/ConfiguredReadOnlyMode.php',
        'ConstantDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'Content' => __DIR__ . '/includes/content/Content.php',
        'ContentHandler' => __DIR__ . '/includes/content/ContentHandler.php',
@@ -679,6 +680,7 @@ $wgAutoloadLocalClasses = [
        'JobQueueMemory' => __DIR__ . '/includes/jobqueue/JobQueueMemory.php',
        'JobQueueReadOnlyError' => __DIR__ . '/includes/jobqueue/JobQueue.php',
        'JobQueueRedis' => __DIR__ . '/includes/jobqueue/JobQueueRedis.php',
+       'JobQueueSecondTestQueue' => __DIR__ . '/includes/jobqueue/JobQueueSecondTestQueue.php',
        'JobRunner' => __DIR__ . '/includes/jobqueue/JobRunner.php',
        'JobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php',
        'JpegHandler' => __DIR__ . '/includes/media/Jpeg.php',
@@ -1118,6 +1120,7 @@ $wgAutoloadLocalClasses = [
        'PopulateInterwiki' => __DIR__ . '/maintenance/populateInterwiki.php',
        'PopulateLogSearch' => __DIR__ . '/maintenance/populateLogSearch.php',
        'PopulateLogUsertext' => __DIR__ . '/maintenance/populateLogUsertext.php',
+       'PopulatePPSortKey' => __DIR__ . '/maintenance/populatePPSortKey.php',
        'PopulateParentId' => __DIR__ . '/maintenance/populateParentId.php',
        'PopulateRecentChangesSource' => __DIR__ . '/maintenance/populateRecentChangesSource.php',
        'PopulateRevisionLength' => __DIR__ . '/maintenance/populateRevisionLength.php',
@@ -1177,7 +1180,7 @@ $wgAutoloadLocalClasses = [
        'RangeChronologicalPager' => __DIR__ . '/includes/pager/RangeChronologicalPager.php',
        'RangeDifference' => __DIR__ . '/includes/diff/DiffEngine.php',
        'RawAction' => __DIR__ . '/includes/actions/RawAction.php',
-       'RawMessage' => __DIR__ . '/includes/Message.php',
+       'RawMessage' => __DIR__ . '/includes/RawMessage.php',
        'ReadOnlyError' => __DIR__ . '/includes/exception/ReadOnlyError.php',
        'ReadOnlyMode' => __DIR__ . '/includes/ReadOnlyMode.php',
        'ReassignEdits' => __DIR__ . '/maintenance/reassignEdits.php',
@@ -1228,6 +1231,7 @@ $wgAutoloadLocalClasses = [
        'ResourceLoaderJqueryMsgModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderJqueryMsgModule.php',
        'ResourceLoaderLanguageDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageDataModule.php',
        'ResourceLoaderLanguageNamesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageNamesModule.php',
+       'ResourceLoaderMediaWikiUtilModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderMediaWikiUtilModule.php',
        'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php',
        'ResourceLoaderOOUIFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIFileModule.php',
        'ResourceLoaderOOUIImageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIImageModule.php',
index 83fcda0..32933e6 100644 (file)
@@ -25,7 +25,7 @@
                "ext-xml": "*",
                "liuggio/statsd-php-client": "1.0.18",
                "mediawiki/at-ease": "1.1.0",
-               "oojs/oojs-ui": "0.22.3",
+               "oojs/oojs-ui": "0.22.4",
                "oyejorge/less.php": "1.7.0.14",
                "php": ">=5.5.9",
                "psr/log": "1.0.2",
@@ -37,7 +37,7 @@
                "wikimedia/html-formatter": "1.0.1",
                "wikimedia/ip-set": "1.1.0",
                "wikimedia/php-session-serializer": "1.0.4",
-               "wikimedia/relpath": "1.0.3",
+               "wikimedia/relpath": "2.0.0",
                "wikimedia/remex-html": "1.0.1",
                "wikimedia/running-stat": "1.1.0",
                "wikimedia/scoped-callback": "1.0.0",
@@ -53,7 +53,7 @@
                "jakub-onderka/php-parallel-lint": "0.9.2",
                "jetbrains/phpstorm-stubs": "dev-master#1b9906084d6635456fcf3f3a01f0d7d5b99a578a",
                "justinrainbow/json-schema": "~5.2",
-               "mediawiki/mediawiki-codesniffer": "0.8.1",
+               "mediawiki/mediawiki-codesniffer": "0.11.0",
                "monolog/monolog": "~1.22.1",
                "nikic/php-parser": "2.1.0",
                "nmred/kafka-php": "0.1.5",
index 44ec764..dbc9204 100644 (file)
@@ -17,7 +17,7 @@ description of the tables and their contents, please see:
 
 To make a read query, something like this usually suffices:
 
-$dbr = wfGetDB( DB_SLAVE );
+$dbr = wfGetDB( DB_REPLICA );
 $res = $dbr->select( /* ...see docs... */ );
 foreach ( $res as $row ) {
        ...
index 3ff3365..8912b82 100644 (file)
@@ -2764,9 +2764,10 @@ configuration variables to JavaScript. Things that depend on the current page
 or request state must be added through MakeGlobalVariablesScript instead.
 &$vars: array( variable name => value )
 
-'ResourceLoaderGetLessVars': Called in ResourceLoader::getLessVars after
-variables from $wgResourceLoaderLESSVars are added. Can be used to add
-context-based variables.
+'ResourceLoaderGetLessVars': DEPRECATED! Called in ResourceLoader::getLessVars
+to add global LESS variables. Loaded after $wgResourceLoaderLESSVars is added.
+Global LESS variables are deprecated. Use ResourceLoaderModule::getLessVars()
+instead to expose variables only in modules that need them.
 &$lessVars: array of variables already added
 
 'ResourceLoaderJqueryMsgModuleMagicWords': Called in
index b85e1d6..b73ecbd 100644 (file)
@@ -73,8 +73,8 @@ class AuthPlugin {
        /**
         * Modify options in the login template.
         *
-        * @param BaseTemplate $template
-        * @param string $type 'signup' or 'login'. Added in 1.16.
+        * @param BaseTemplate &$template
+        * @param string &$type 'signup' or 'login'. Added in 1.16.
         */
        public function modifyUITemplate( &$template, &$type ) {
                # Override this!
@@ -124,7 +124,7 @@ class AuthPlugin {
         *
         * @deprecated since 1.26, use the UserLoggedIn hook instead. And assigning
         *  a different User object to $user is no longer supported.
-        * @param User $user
+        * @param User &$user
         * @return bool
         */
        public function updateUser( &$user ) {
@@ -286,7 +286,7 @@ class AuthPlugin {
         *
         * @deprecated since 1.26, use the UserLoggedIn hook instead. And assigning
         *  a different User object to $user is no longer supported.
-        * @param User $user
+        * @param User &$user
         * @param bool $autocreate True if user is being autocreated on login
         */
        public function initUser( &$user, $autocreate = false ) {
@@ -306,7 +306,7 @@ class AuthPlugin {
        /**
         * Get an instance of a User object
         *
-        * @param User $user
+        * @param User &$user
         *
         * @return AuthPluginUser
         */
@@ -359,6 +359,7 @@ class AuthPluginUser {
 
        /**
         * @deprecated since 1.28, use SessionManager::invalidateSessionForUser() instead.
+        * @return bool
         */
        public function resetAuthToken() {
                # Override this!
index 2c935df..5066038 100644 (file)
@@ -44,40 +44,40 @@ class Block {
        public $mParentBlockId;
 
        /** @var int */
-       protected $mId;
+       private $mId;
 
        /** @var bool */
-       protected $mFromMaster;
+       private $mFromMaster;
 
        /** @var bool */
-       protected $mBlockEmail;
+       private $mBlockEmail;
 
        /** @var bool */
-       protected $mDisableUsertalk;
+       private $mDisableUsertalk;
 
        /** @var bool */
-       protected $mCreateAccount;
+       private $mCreateAccount;
 
        /** @var User|string */
-       protected $target;
+       private $target;
 
        /** @var int Hack for foreign blocking (CentralAuth) */
-       protected $forcedTargetID;
+       private $forcedTargetID;
 
        /** @var int Block::TYPE_ constant. Can only be USER, IP or RANGE internally */
-       protected $type;
+       private $type;
 
        /** @var User */
-       protected $blocker;
+       private $blocker;
 
        /** @var bool */
-       protected $isHardblock;
+       private $isHardblock;
 
        /** @var bool */
-       protected $isAutoblocking;
+       private $isAutoblocking;
 
        /** @var string|null */
-       protected $systemBlockType;
+       private $systemBlockType;
 
        # TYPE constants
        const TYPE_USER = 1;
@@ -485,7 +485,7 @@ class Block {
 
                # Periodic purge via commit hooks
                if ( mt_rand( 0, 9 ) == 0 ) {
-                       Block::purgeExpired();
+                       self::purgeExpired();
                }
 
                $row = $this->getDatabaseArray();
@@ -778,12 +778,12 @@ class Block {
                # It's okay to autoblock. Go ahead and insert/update the block...
 
                # Do not add a *new* block if the IP is already blocked.
-               $ipblock = Block::newFromTarget( $autoblockIP );
+               $ipblock = self::newFromTarget( $autoblockIP );
                if ( $ipblock ) {
                        # Check if the block is an autoblock and would exceed the user block
                        # if renewed. If so, do nothing, otherwise prolong the block time...
                        if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
-                               $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
+                               $this->mExpiry > self::getAutoblockExpiry( $ipblock->mTimestamp )
                        ) {
                                # Reset block timestamp to now and its expiry to
                                # $wgAutoblockExpiry in the future
@@ -810,11 +810,11 @@ class Block {
 
                if ( $this->mExpiry == 'infinity' ) {
                        # Original block was indefinite, start an autoblock now
-                       $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
+                       $autoblock->mExpiry = self::getAutoblockExpiry( $timestamp );
                } else {
                        # If the user is already blocked with an expiry date, we don't
                        # want to pile on top of that.
-                       $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
+                       $autoblock->mExpiry = min( $this->mExpiry, self::getAutoblockExpiry( $timestamp ) );
                }
 
                # Insert the block...
@@ -870,7 +870,7 @@ class Block {
        public function updateTimestamp() {
                if ( $this->mAuto ) {
                        $this->mTimestamp = wfTimestamp();
-                       $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
+                       $this->mExpiry = self::getAutoblockExpiry( $this->mTimestamp );
 
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->update( 'ipblocks',
@@ -958,6 +958,7 @@ class Block {
 
        /**
         * Get the system block type, if any
+        * @since 1.29
         * @return string|null
         */
        public function getSystemBlockType() {
@@ -1111,8 +1112,8 @@ class Block {
         */
        public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
                list( $target, $type ) = self::parseTarget( $specificTarget );
-               if ( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ) {
-                       return Block::newFromID( $target );
+               if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
+                       return self::newFromID( $target );
 
                } elseif ( $target === null && $vagueTarget == '' ) {
                        # We're not going to find anything useful here
@@ -1122,7 +1123,7 @@ class Block {
 
                } elseif ( in_array(
                        $type,
-                       [ Block::TYPE_USER, Block::TYPE_IP, Block::TYPE_RANGE, null ] )
+                       [ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
                ) {
                        $block = new Block();
                        $block->fromMaster( $fromMaster );
@@ -1189,7 +1190,7 @@ class Block {
                }
                $selectFields = array_merge(
                        [ 'ipb_range_start', 'ipb_range_end' ],
-                       Block::selectFields()
+                       self::selectFields()
                );
                $rows = $db->select( 'ipblocks',
                        $selectFields,
@@ -1350,12 +1351,12 @@ class Block {
                        # off validation checking (which would exclude IP addresses)
                        return [
                                User::newFromName( IP::sanitizeIP( $target ), false ),
-                               Block::TYPE_IP
+                               self::TYPE_IP
                        ];
 
                } elseif ( IP::isValidBlock( $target ) ) {
                        # Can't create a User from an IP range
-                       return [ IP::sanitizeRange( $target ), Block::TYPE_RANGE ];
+                       return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
                }
 
                # Consider the possibility that this is not a username at all
@@ -1370,11 +1371,11 @@ class Block {
                        # Note that since numbers are valid usernames, a $target of "12345" will be
                        # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
                        # since hash characters are not valid in usernames or titles generally.
-                       return [ $userObj, Block::TYPE_USER ];
+                       return [ $userObj, self::TYPE_USER ];
 
                } elseif ( preg_match( '/^#\d+$/', $target ) ) {
                        # Autoblock reference in the form "#12345"
-                       return [ substr( $target, 1 ), Block::TYPE_AUTO ];
+                       return [ substr( $target, 1 ), self::TYPE_AUTO ];
 
                } else {
                        # WTF?
@@ -1450,6 +1451,8 @@ class Block {
         * Set the 'BlockID' cookie to this block's ID and expiry time. The cookie's expiry will be
         * the same as the block's, to a maximum of 24 hours.
         *
+        * @since 1.29
+        *
         * @param WebResponse $response The response on which to set the cookie.
         */
        public function setCookie( WebResponse $response ) {
@@ -1472,6 +1475,8 @@ class Block {
        /**
         * Unset the 'BlockID' cookie.
         *
+        * @since 1.29
+        *
         * @param WebResponse $response The response on which to unset the cookie.
         */
        public static function clearCookie( WebResponse $response ) {
@@ -1482,6 +1487,9 @@ class Block {
         * Get the BlockID cookie's value for this block. This is usually the block ID concatenated
         * with an HMAC in order to avoid spoofing (T152951), but if wgSecretKey is not set will just
         * be the block ID.
+        *
+        * @since 1.29
+        *
         * @return string The block ID, probably concatenated with "!" and the HMAC.
         */
        public function getCookieValue() {
@@ -1493,15 +1501,19 @@ class Block {
                        return $id;
                }
                $hmac = MWCryptHash::hmac( $id, $secretKey, false );
-               $cookieValue =  $id . '!' . $hmac;
+               $cookieValue = $id . '!' . $hmac;
                return $cookieValue;
        }
 
        /**
         * Get the stored ID from the 'BlockID' cookie. The cookie's value is usually a combination of
         * the ID and a HMAC (see Block::setCookie), but will sometimes only be the ID.
+        *
+        * @since 1.29
+        *
         * @param string $cookieValue The string in which to find the ID.
-        * @return integer|null The block ID, or null if the HMAC is present and invalid.
+        *
+        * @return int|null The block ID, or null if the HMAC is present and invalid.
         */
        public static function getIdFromCookieValue( $cookieValue ) {
                // Extract the ID prefix from the cookie value (may be the whole value, if no bang found).
index c22ea64..629962d 100644 (file)
@@ -48,7 +48,7 @@ class Category {
 
        /**
         * Set up all member variables using a database query.
-        * @param integer $mode
+        * @param int $mode
         * @throws MWException
         * @return bool True on success, false on failure.
         */
diff --git a/includes/ConfiguredReadOnlyMode.php b/includes/ConfiguredReadOnlyMode.php
new file mode 100644 (file)
index 0000000..af7c7cb
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * A read-only mode service which does not depend on LoadBalancer.
+ * To obtain an instance, use MediaWikiServices::getConfiguredReadOnlyMode().
+ *
+ * @since 1.29
+ */
+class ConfiguredReadOnlyMode {
+       /** @var Config */
+       private $config;
+
+       /** @var string|bool|null */
+       private $fileReason;
+
+       /** @var string|null */
+       private $overrideReason;
+
+       public function __construct( Config $config ) {
+               $this->config = $config;
+       }
+
+       /**
+        * Check whether the wiki is in read-only mode.
+        *
+        * @return bool
+        */
+       public function isReadOnly() {
+               return $this->getReason() !== false;
+       }
+
+       /**
+        * Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
+        *
+        * @return string|bool String when in read-only mode; false otherwise
+        */
+       public function getReason() {
+               if ( $this->overrideReason !== null ) {
+                       return $this->overrideReason;
+               }
+               $confReason = $this->config->get( 'ReadOnly' );
+               if ( $confReason !== null ) {
+                       return $confReason;
+               }
+               if ( $this->fileReason === null ) {
+                       // Cache for faster access next time
+                       $readOnlyFile = $this->config->get( 'ReadOnlyFile' );
+                       if ( is_file( $readOnlyFile ) && filesize( $readOnlyFile ) > 0 ) {
+                               $this->fileReason = file_get_contents( $readOnlyFile );
+                       } else {
+                               $this->fileReason = false;
+                       }
+               }
+               return $this->fileReason;
+       }
+
+       /**
+        * Set the read-only mode, which will apply for the remainder of the
+        * request or until a service reset.
+        *
+        * @param string|null $msg
+        */
+       public function setReason( $msg ) {
+               $this->overrideReason = $msg;
+       }
+
+       /**
+        * Clear the cache of the read only file
+        */
+       public function clearCache() {
+               $this->fileReason = null;
+       }
+}
index ac6e558..2613889 100644 (file)
@@ -959,6 +959,23 @@ $wgTrustedMediaFormats = [
  */
 $wgMediaHandlers = [];
 
+/**
+ * Media handler overrides for parser tests (they don't need to generate actual
+ * thumbnails, so a mock will do)
+ */
+$wgParserTestMediaHandlers = [
+       'image/jpeg' => 'MockBitmapHandler',
+       'image/png' => 'MockBitmapHandler',
+       'image/gif' => 'MockBitmapHandler',
+       'image/tiff' => 'MockBitmapHandler',
+       'image/webp' => 'MockBitmapHandler',
+       'image/x-ms-bmp' => 'MockBitmapHandler',
+       'image/x-bmp' => 'MockBitmapHandler',
+       'image/x-xcf' => 'MockBitmapHandler',
+       'image/svg+xml' => 'MockSvgHandler',
+       'image/vnd.djvu' => 'MockDjVuHandler',
+];
+
 /**
  * Plugins for page content model handling.
  * Each entry in the array maps a model id to a class name or callback
@@ -1304,7 +1321,7 @@ $wgMimeInfoFile = 'includes/mime.info';
  * Sets an external MIME detector program. The command must print only
  * the MIME type to standard output.
  * The name of the file to process will be appended to the command given here.
- * If not set or NULL, PHP's fileinfo extension will be used if available.
+ * If not set or NULL, PHP's mime_content_type function will be used.
  *
  * @par Example:
  * @code
@@ -3372,16 +3389,56 @@ $wgApiFrameOptions = 'DENY';
 $wgDisableOutputCompression = false;
 
 /**
- * Should we allow a broader set of characters in id attributes, per HTML5?  If
- * not, use only HTML 4-compatible IDs.  This option is for testing -- when the
- * functionality is ready, it will be on by default with no option.
+ * Abandoned experiment with HTML5-style ID escaping. Normalized IDs a bit
+ * too aggressively, breaking preexisting content (particularly Cite).
+ * See T29733, T29694, T29474.
  *
- * Currently this appears to work fine in all browsers, but it's disabled by
- * default because it normalizes id's a bit too aggressively, breaking preexisting
- * content (particularly Cite).  See T29733, T29694, T29474.
+ * @deprecated since 1.30, use $wgFragmentMode
  */
 $wgExperimentalHtmlIds = false;
 
+/**
+ * How should section IDs be encoded?
+ * This array can contain 1 or 2 elements, each of them can be one of:
+ * - 'html5'  is modern HTML5 style encoding with minimal escaping. Allows to
+ *            display Unicode characters in many browsers' address bars.
+ * - 'legacy' is old MediaWiki-style encoding, e.g. 啤酒 turns into .E5.95.A4.E9.85.92
+ * - 'html5-legacy' corresponds to DEPRECATED $wgExperimentalHtmlIds mode. DO NOT use
+ *            it for anything but migration off that mode (see below).
+ *
+ * The first element of this array specifies the primary mode of escaping IDs. This
+ * is what users will see when they e.g. follow an [[#internal link]] to a section of
+ * a page.
+ *
+ * The optional second element defines a fallback mode, useful for migrations.
+ * If present, it will direct MediaWiki to add empty <span>s to every section with its
+ * id attribute set to fallback encoded title so that links using the previous encoding
+ * would still work.
+ *
+ * Example: you want to migrate your wiki from 'legacy' to 'html5'
+ *
+ * On the first step, set this variable to [ 'legacy', 'html5' ]. After a while, when
+ * all caches (parser, HTTP, etc.) contain only pages generated with this setting,
+ * flip the value to [ 'html5', 'legacy' ]. This will result in all internal links being
+ * generated in the new encoding while old links (both external and cached internal) will
+ * still work. After a long time, you might want to ditch backwards compatibility and
+ * set it to [ 'html5' ]. After all, pages get edited, breaking incoming links no matter which
+ * fragment mode is used.
+ *
+ * @since 1.30
+ */
+$wgFragmentMode = [ 'legacy' ];
+
+/**
+ * Which ID escaping mode should be used for external interwiki links? See documentation
+ * for $wgFragmentMode above for details of each mode. Because you can't control external sites,
+ * this setting should probably always be 'legacy', unless every wiki you link to has converted
+ * to 'html5'.
+ *
+ * @since 1.30
+ */
+$wgExternalInterwikiFragmentMode = 'legacy';
+
 /**
  * Abstract list of footer icons for skins in place of old copyrightico and poweredbyico code
  * You can add new icons to the built in copyright or poweredby, or you can create
@@ -3754,20 +3811,18 @@ $wgResourceLoaderValidateStaticJS = false;
  * at the beginning of all your .less files, with all the consequences.
  * In particular, string values must be escaped and quoted.
  *
- * Changes to LESS variables do not trigger cache invalidation.
- *
- * If the LESS variables need to be dynamic, you can use the
- * ResourceLoaderGetLessVars hook (since 1.25).
+ * Changes to this configuration do NOT trigger cache invalidation.
  *
  * @par Example:
  * @code
  *   $wgResourceLoaderLESSVars = [
- *     'baseFontSize'  => '1em',
- *     'smallFontSize' => '0.75em',
- *     'WikimediaBlue' => '#006699',
+ *     'exampleFontSize'  => '1em',
+ *     'exampleBlue' => '#eee',
  *   ];
  * @endcode
  * @since 1.22
+ * @deprecated since 1.30 Use ResourceLoaderModule::getLessVars() instead to
+ *  add variables to individual modules that need them.
  */
 $wgResourceLoaderLESSVars = [
        /**
@@ -4091,6 +4146,14 @@ $wgTrackingCategories = [];
  */
 $wgContentNamespaces = [ NS_MAIN ];
 
+/**
+ * Optional array of namespaces which should be blacklisted from Special:ShortPages
+ * Only pages inside $wgContentNamespaces but not $wgShortPagesNamespaceBlacklist will
+ * be shown on that page.
+ * @since 1.30
+ */
+$wgShortPagesNamespaceBlacklist = [];
+
 /**
  * Array of namespaces, in addition to the talk namespaces, where signatures
  * (~~~~) are likely to be used. This determines whether to display the
@@ -4887,6 +4950,7 @@ $wgDefaultUserOptions = [
        'watchlisthidepatrolled' => 0,
        'watchlisthidecategorization' => 1,
        'watchlistreloadautomatically' => 0,
+       'watchlistunwatchlinks' => 0,
        'watchmoves' => 0,
        'watchrollback' => 0,
        'wllimit' => 250,
@@ -5751,7 +5815,7 @@ $wgPasswordAttemptThrottle = [
        // Long term limit. We need to balance the risk
        // of somebody using this as a DoS attack to lock someone
        // out of their account, and someone doing a brute force attack.
-       [ 'count' => 150, 'seconds' => 60*60*48 ],
+       [ 'count' => 150, 'seconds' => 60 * 60 * 48 ],
 ];
 
 /**
@@ -6771,11 +6835,6 @@ $wgRCWatchCategoryMembership = false;
  */
 $wgUseRCPatrol = true;
 
-/**
- * Whether to allow users to save their RecentChanges filters
- */
-$wgStructuredChangeFiltersEnableSaving = true;
-
 /**
  * Whether to show the new experimental views (like namespaces, tags, and users) in
  * RecentChanges filters
@@ -6787,6 +6846,11 @@ $wgStructuredChangeFiltersEnableExperimentalViews = false;
  */
 $wgStructuredChangeFiltersEnableLiveUpdate = false;
 
+/**
+ * Whether to enable RCFilters app on Special:Watchlist
+ */
+$wgStructuredChangeFiltersOnWatchlist = false;
+
 /**
  * Use new page patrolling to check new pages on Special:Newpages
  */
@@ -8238,10 +8302,15 @@ $wgHTTPProxy = false;
  * Local virtual hosts.
  *
  * This lists domains that are configured as virtual hosts on the same machine.
- * If a request is to be made to a domain listed here, or any subdomain thereof,
- * then no proxy will be used.
- * Command-line scripts are not affected by this setting and will always use
- * proxy if it is configured.
+ *
+ * This affects the following:
+ * - MWHttpRequest: If a request is to be made to a domain listed here, or any
+ *   subdomain thereof, then no proxy will be used.
+ *   Command-line scripts are not affected by this setting and will always use
+ *   the proxy if it is configured.
+ * - ChronologyProtector: Decide to shutdown LBFactory asynchronously instead
+ *   synchronously if the current response redirects to a local virtual host.
+ *
  * @since 1.25
  */
 $wgLocalVirtualHosts = [];
index 973327b..914e7aa 100644 (file)
@@ -336,7 +336,7 @@ class EditPage {
        /** @var string */
        public $edittime = '';
 
-       /** @var integer */
+       /** @var int */
        private $editRevId = null;
 
        /** @var string */
@@ -852,7 +852,7 @@ class EditPage {
 
        /**
         * This function collects the form data and uses it to populate various member variables.
-        * @param WebRequest $request
+        * @param WebRequest &$request
         * @throws ErrorPageError
         */
        public function importFormData( &$request ) {
@@ -1080,7 +1080,7 @@ class EditPage {
         * this method should be overridden and return the page text that will be used
         * for saving, preview parsing and so on...
         *
-        * @param WebRequest $request
+        * @param WebRequest &$request
         * @return string|null
         */
        protected function importContentFormData( &$request ) {
@@ -1432,7 +1432,7 @@ class EditPage {
        /**
         * Make sure the form isn't faking a user's credentials.
         *
-        * @param WebRequest $request
+        * @param WebRequest &$request
         * @return bool
         * @private
         */
@@ -1475,7 +1475,7 @@ class EditPage {
 
        /**
         * Attempt submission
-        * @param array|bool $resultDetails See docs for $result in internalAttemptSave
+        * @param array|bool &$resultDetails See docs for $result in internalAttemptSave
         * @throws UserBlockedError|ReadOnlyError|ThrottledError|PermissionsError
         * @return Status The resulting status object.
         */
@@ -1698,7 +1698,7 @@ class EditPage {
                global $wgParser;
 
                if ( $this->sectiontitle !== '' ) {
-                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
+                       $sectionanchor = $this->guessSectionName( $this->sectiontitle );
                        // If no edit summary was specified, create one automatically from the section
                        // title and have it link to the new section. Otherwise, respect the summary as
                        // passed.
@@ -1708,7 +1708,7 @@ class EditPage {
                                        ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
                        }
                } elseif ( $this->summary !== '' ) {
-                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
+                       $sectionanchor = $this->guessSectionName( $this->summary );
                        # This is a new section, so create a link to the new section
                        # in the revision summary.
                        $cleanSummary = $wgParser->stripSectionName( $this->summary );
@@ -1721,12 +1721,12 @@ class EditPage {
        /**
         * Attempt submission (no UI)
         *
-        * @param array $result Array to add statuses to, currently with the
+        * @param array &$result Array to add statuses to, currently with the
         *   possible keys:
         *   - spam (string): Spam string from content if any spam is detected by
         *     matchSpamRegex.
         *   - sectionanchor (string): Section anchor for a section save.
-        *   - nullEdit (boolean): Set if doEditContent is OK.  True if null edit,
+        *   - nullEdit (bool): Set if doEditContent is OK.  True if null edit,
         *     false otherwise.
         *   - redirect (bool): Set if doEditContent is OK. True if resulting
         *     revision is a redirect.
@@ -1743,7 +1743,7 @@ class EditPage {
         * time.
         */
        public function internalAttemptSave( &$result, $bot = false ) {
-               global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
+               global $wgUser, $wgRequest, $wgMaxArticleSize;
                global $wgContentHandlerUseDB;
 
                $status = Status::newGood();
@@ -2117,7 +2117,7 @@ class EditPage {
                                # We can't deal with anchors, includes, html etc in the header for now,
                                # headline would need to be parsed to improve this.
                                if ( $hasmatch && strlen( $matches[2] ) > 0 ) {
-                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $matches[2] );
+                                       $sectionanchor = $this->guessSectionName( $matches[2] );
                                }
                        }
                        $result['sectionanchor'] = $sectionanchor;
@@ -2783,7 +2783,7 @@ class EditPage {
                $wgOut->addHTML( $this->editFormTextBeforeContent );
 
                if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
-                       $wgOut->addHTML( EditPage::getEditToolbar( $this->mTitle ) );
+                       $wgOut->addHTML( self::getEditToolbar( $this->mTitle ) );
                }
 
                if ( $this->blankArticle ) {
@@ -3076,7 +3076,7 @@ class EditPage {
                        'tabindex' => 1,
                        'size' => 60,
                        'spellcheck' => 'true',
-               ] + Linker::tooltipAndAccesskeyAttribs( 'summary' );
+               ];
        }
 
        /**
@@ -3097,6 +3097,7 @@ class EditPage {
                $inputAttrs = null, $spanLabelAttrs = null
        ) {
                $inputAttrs = $this->getSummaryInputAttributes( $inputAttrs );
+               $inputAttrs += Linker::tooltipAndAccesskeyAttribs( 'summary' );
 
                $spanLabelAttrs = ( is_array( $spanLabelAttrs ) ? $spanLabelAttrs : [] ) + [
                        'class' => $this->missingSummary ? 'mw-summarymissed' : 'mw-summary',
@@ -3132,6 +3133,10 @@ class EditPage {
                $inputAttrs = OOUI\Element::configFromHtmlAttributes(
                        $this->getSummaryInputAttributes( $inputAttrs )
                );
+               $inputAttrs += [
+                       'title' => Linker::titleAttrib( 'summary' ),
+                       'accessKey' => Linker::accesskey( 'summary' ),
+               ];
 
                // For compatibility with old scripts and extensions, we want the legacy 'id' on the `<input>`
                $inputAttrs['inputId'] = $inputAttrs['id'];
@@ -3220,16 +3225,13 @@ class EditPage {
 
        protected function showFormBeforeText() {
                global $wgOut;
-               $section = htmlspecialchars( $this->section );
-               $wgOut->addHTML( <<<HTML
-<input type='hidden' value="{$section}" name="wpSection"/>
-<input type='hidden' value="{$this->starttime}" name="wpStarttime" />
-<input type='hidden' value="{$this->edittime}" name="wpEdittime" />
-<input type='hidden' value="{$this->editRevId}" name="editRevId" />
-<input type='hidden' value="{$this->scrolltop}" name="wpScrolltop" id="wpScrolltop" />
-
-HTML
-               );
+
+               $wgOut->addHTML( Html::hidden( 'wpSection', htmlspecialchars( $this->section ) ) );
+               $wgOut->addHTML( Html::hidden( 'wpStarttime', $this->starttime ) );
+               $wgOut->addHTML( Html::hidden( 'wpEdittime', $this->edittime ) );
+               $wgOut->addHTML( Html::hidden( 'editRevId', $this->editRevId ) );
+               $wgOut->addHTML( Html::hidden( 'wpScrolltop', $this->scrolltop ) );
+
                if ( !$this->checkUnicodeCompliantBrowser() ) {
                        $wgOut->addHTML( Html::hidden( 'safemode', '1' ) );
                }
@@ -3492,6 +3494,10 @@ HTML
                }
        }
 
+       /**
+        * Inserts optional text shown below edit and upload forms. Can be used to offer special
+        * characters not present on most keyboards for copying/pasting.
+        */
        protected function showEditTools() {
                global $wgOut;
                $wgOut->addHTML( '<div class="mw-editTools">' .
@@ -4196,7 +4202,7 @@ HTML
         * Returns an array of html code of the following checkboxes old style:
         * minor and watch
         *
-        * @param int $tabindex Current tabindex
+        * @param int &$tabindex Current tabindex
         * @param array $checked See getCheckboxesDefinition()
         * @return array
         */
@@ -4254,7 +4260,7 @@ HTML
         * Returns an array of html code of the following checkboxes:
         * minor and watch
         *
-        * @param int $tabindex Current tabindex
+        * @param int &$tabindex Current tabindex
         * @param array $checked Array of checkbox => bool, where bool indicates the checked
         *                 status of the checkbox
         *
@@ -4273,7 +4279,7 @@ HTML
                        $accesskey = null;
                        if ( isset( $options['tooltip'] ) ) {
                                $accesskey = $this->context->msg( "accesskey-{$options['tooltip']}" )->text();
-                               $title = Linker::titleAttrib( $options['tooltip'], 'withaccess' );
+                               $title = Linker::titleAttrib( $options['tooltip'] );
                        }
                        if ( isset( $options['title-message'] ) ) {
                                $title = $this->context->msg( $options['title-message'] )->text();
@@ -4327,7 +4333,7 @@ HTML
                $newPage = !$this->mTitle->exists();
 
                if ( $labelAsPublish ) {
-                       $buttonLabelKey =  $newPage ? 'publishpage' : 'publishchanges';
+                       $buttonLabelKey = $newPage ? 'publishpage' : 'publishchanges';
                } else {
                        $buttonLabelKey = $newPage ? 'savearticle' : 'savechanges';
                }
@@ -4339,7 +4345,7 @@ HTML
         * Returns an array of html code of the following buttons:
         * save, diff and preview
         *
-        * @param int $tabindex Current tabindex
+        * @param int &$tabindex Current tabindex
         *
         * @return array
         */
@@ -4351,8 +4357,7 @@ HTML
                $attribs = [
                        'name' => 'wpSave',
                        'tabindex' => ++$tabindex,
-               ] + Linker::tooltipAndAccesskeyAttribs( 'save' );
-
+               ];
                if ( $this->oouiEnabled ) {
                        $saveConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['save'] = new OOUI\ButtonInputWidget( [
@@ -4364,11 +4369,13 @@ HTML
                                'label' => $buttonLabel,
                                'infusable' => true,
                                'type' => 'submit',
+                               'title' => Linker::titleAttrib( 'save' ),
+                               'accessKey' => Linker::accesskey( 'save' ),
                        ] + $saveConfig );
                } else {
                        $buttons['save'] = Html::submitButton(
                                $buttonLabel,
-                               $attribs + [ 'id' => 'wpSave' ],
+                               $attribs + Linker::tooltipAndAccesskeyAttribs( 'save' ) + [ 'id' => 'wpSave' ],
                                [ 'mw-ui-progressive' ]
                        );
                }
@@ -4376,7 +4383,7 @@ HTML
                $attribs = [
                        'name' => 'wpPreview',
                        'tabindex' => ++$tabindex,
-               ] + Linker::tooltipAndAccesskeyAttribs( 'preview' );
+               ];
                if ( $this->oouiEnabled ) {
                        $previewConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['preview'] = new OOUI\ButtonInputWidget( [
@@ -4386,18 +4393,20 @@ HTML
                                'useInputTag' => true,
                                'label' => $this->context->msg( 'showpreview' )->text(),
                                'infusable' => true,
-                               'type' => 'submit'
+                               'type' => 'submit',
+                               'title' => Linker::titleAttrib( 'preview' ),
+                               'accessKey' => Linker::accesskey( 'preview' ),
                        ] + $previewConfig );
                } else {
                        $buttons['preview'] = Html::submitButton(
                                $this->context->msg( 'showpreview' )->text(),
-                               $attribs + [ 'id' => 'wpPreview' ]
+                               $attribs + Linker::tooltipAndAccesskeyAttribs( 'preview' ) + [ 'id' => 'wpPreview' ]
                        );
                }
                $attribs = [
                        'name' => 'wpDiff',
                        'tabindex' => ++$tabindex,
-               ] + Linker::tooltipAndAccesskeyAttribs( 'diff' );
+               ];
                if ( $this->oouiEnabled ) {
                        $diffConfig = OOUI\Element::configFromHtmlAttributes( $attribs );
                        $buttons['diff'] = new OOUI\ButtonInputWidget( [
@@ -4408,11 +4417,13 @@ HTML
                                'label' => $this->context->msg( 'showdiff' )->text(),
                                'infusable' => true,
                                'type' => 'submit',
+                               'title' => Linker::titleAttrib( 'diff' ),
+                               'accessKey' => Linker::accesskey( 'diff' ),
                        ] + $diffConfig );
                } else {
                        $buttons['diff'] = Html::submitButton(
                                $this->context->msg( 'showdiff' )->text(),
-                               $attribs + [ 'id' => 'wpDiff' ]
+                               $attribs + Linker::tooltipAndAccesskeyAttribs( 'diff' ) + [ 'id' => 'wpDiff' ]
                        );
                }
 
@@ -4781,4 +4792,27 @@ HTML
                }
                return $wikitext;
        }
+
+       /**
+        * Turns section name wikitext into anchors for use in HTTP redirects. Various
+        * versions of Microsoft browsers misinterpret fragment encoding of Location: headers
+        * resulting in mojibake in address bar. Redirect them to legacy section IDs,
+        * if possible. All the other browsers get HTML5 if the wiki is configured for it, to
+        * spread the new style links more efficiently.
+        *
+        * @param string $text
+        * @return string
+        */
+       private function guessSectionName( $text ) {
+               global $wgParser;
+
+               // Detect Microsoft browsers
+               $userAgent = $this->context->getRequest()->getHeader( 'User-Agent' );
+               if ( $userAgent && preg_match( '/MSIE|Edge/', $userAgent ) ) {
+                       // ...and redirect them to legacy encoding, if available
+                       return $wgParser->guessLegacySectionNameFromWikiText( $text );
+               }
+               // Meanwhile, real browsers get real anchors
+               return $wgParser->guessSectionNameFromWikiText( $text );
+       }
 }
index 3b2283b..2f7f75b 100644 (file)
@@ -126,7 +126,7 @@ class FauxRequest extends WebRequest {
 
        /**
         * @since 1.26
-        * @param string $name Unprefixed name of the cookie to set
+        * @param string $key Unprefixed name of the cookie to set
         * @param string|null $value Value of the cookie to set
         * @param string|null $prefix Cookie prefix. Defaults to $wgCookiePrefix
         */
@@ -152,6 +152,7 @@ class FauxRequest extends WebRequest {
 
        /**
         * @since 1.25
+        * @param string $url
         */
        public function setRequestURL( $url ) {
                $this->requestUrl = $url;
@@ -160,6 +161,7 @@ class FauxRequest extends WebRequest {
        /**
         * @since 1.25 MWException( "getRequestURL not implemented" )
         * no longer thrown.
+        * @return string
         */
        public function getRequestURL() {
                if ( $this->requestUrl === null ) {
index 189fd9f..f76a634 100644 (file)
@@ -54,8 +54,6 @@ class FeedItem {
        public $rssIsPermalink = false;
 
        /**
-        * Constructor
-        *
         * @param string|Title $title Item's title
         * @param string $description
         * @param string $url URL uniquely designating the item.
index e7b4a1f..8c843c4 100644 (file)
@@ -47,8 +47,6 @@ class FileDeleteForm {
        private $oldimage = '';
 
        /**
-        * Constructor
-        *
         * @param File $file File object we're deleting
         */
        public function __construct( $file ) {
@@ -145,9 +143,9 @@ class FileDeleteForm {
        /**
         * Really delete the file
         *
-        * @param Title $title
-        * @param File $file
-        * @param string $oldimage Archive name
+        * @param Title &$title
+        * @param File &$file
+        * @param string &$oldimage Archive name
         * @param string $reason Reason of the deletion
         * @param bool $suppress Whether to mark all deleted versions as restricted
         * @param User $user User object performing the request
@@ -400,8 +398,8 @@ class FileDeleteForm {
         * value was provided, does it correspond to an
         * existing, local, old version of this file?
         *
-        * @param File $file
-        * @param File $oldfile
+        * @param File &$file
+        * @param File &$oldfile
         * @param File $oldimage
         * @return bool
         */
index 92cb8d8..49159ed 100644 (file)
@@ -241,7 +241,7 @@ function wfArrayFilterByKey( array $arr, callable $callback ) {
  * @param string|int $key
  * @param mixed $value
  * @param mixed $default
- * @param array $changed Array to alter
+ * @param array &$changed Array to alter
  * @throws MWException
  */
 function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) {
@@ -1750,7 +1750,7 @@ function wfEscapeWikiText( $text ) {
  * If source is NULL, it just returns the value, it doesn't set the variable
  * If force is true, it will set the value even if source is NULL
  *
- * @param mixed $dest
+ * @param mixed &$dest
  * @param mixed $source
  * @param bool $force
  * @return mixed
@@ -1766,7 +1766,7 @@ function wfSetVar( &$dest, $source, $force = false ) {
 /**
  * As for wfSetVar except setting a bit
  *
- * @param int $dest
+ * @param int &$dest
  * @param int $bit
  * @param bool $state
  *
@@ -2234,7 +2234,8 @@ function wfIniGetBool( $setting ) {
  * (https://bugs.php.net/bug.php?id=26285) and the locale problems on Linux in
  * PHP 5.2.6+ (bug backported to earlier distro releases of PHP).
  *
- * @param string ... strings to escape and glue together, or a single array of strings parameter
+ * @param string $args,... strings to escape and glue together,
+ *  or a single array of strings parameter
  * @return string
  */
 function wfEscapeShellArg( /*...*/ ) {
@@ -2618,7 +2619,7 @@ function wfShellWikiCmd( $script, array $parameters = [], array $options = [] )
  * @param string $old
  * @param string $mine
  * @param string $yours
- * @param string $result
+ * @param string &$result
  * @return bool
  */
 function wfMerge( $old, $mine, $yours, &$result ) {
@@ -3617,6 +3618,7 @@ function wfCanIPUseHTTPS( $ip ) {
  * @since 1.25
  */
 function wfIsInfinity( $str ) {
+       // These are hardcoded elsewhere in MediaWiki (e.g. mediawiki.special.block.js).
        $infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ];
        return in_array( $str, $infinityValues );
 }
index 56cf815..51bd7a9 100644 (file)
@@ -76,9 +76,6 @@ class ConcatenatedGzipHistoryBlob implements HistoryBlob {
        public $mMaxSize = 10000000;
        public $mMaxCount = 100;
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                if ( !function_exists( 'gzdeflate' ) ) {
                        throw new MWException( "Need zlib support to read or write this "
index da1a8da..6467777 100644 (file)
@@ -92,7 +92,7 @@ class Licenses extends HTMLFormField {
        }
 
        /**
-        * @param array $list
+        * @param array &$list
         * @param array $path
         * @param mixed $item
         */
index 2f50558..790e2be 100644 (file)
@@ -50,7 +50,7 @@ class LinkFilter {
 
                $text = $content->getNativeData();
 
-               $regex = LinkFilter::makeRegex( $filterEntry );
+               $regex = self::makeRegex( $filterEntry );
                return preg_match( $regex, $text );
        }
 
index f2e4ac4..d55f0e0 100644 (file)
@@ -154,6 +154,11 @@ class Linker {
         * @since 1.16.3
         * @deprecated since 1.28, use MediaWiki\Linker\LinkRenderer instead
         * @see Linker::link
+        * @param Title $target
+        * @param string $html
+        * @param array $customAttribs
+        * @param array $query
+        * @param string|array $options
         * @return string
         */
        public static function linkKnown(
@@ -1328,7 +1333,7 @@ class Linker {
                Title $title, $text, $wikiId = null, $options = []
        ) {
                if ( $wikiId !== null && !$title->isExternal() ) {
-                       $link = Linker::makeExternalLink(
+                       $link = self::makeExternalLink(
                                WikiMap::getForeignURL(
                                        $wikiId,
                                        $title->getNamespace() === 0
@@ -1341,7 +1346,7 @@ class Linker {
                                /* escape = */ false // Already escaped
                        );
                } else {
-                       $link = Linker::link( $title, $text, [], [], $options );
+                       $link = self::link( $title, $text, [], [], $options );
                }
 
                return $link;
@@ -1350,7 +1355,7 @@ class Linker {
        /**
         * @param Title $contextTitle
         * @param string $target
-        * @param string $text
+        * @param string &$text
         * @return string
         */
        public static function normalizeSubpageLink( $contextTitle, $target, &$text ) {
@@ -1608,22 +1613,24 @@ class Linker {
         *   a space and ending with '>'
         *   This *must* be at least '>' for no attribs
         * @param string $anchor The anchor to give the headline (the bit after the #)
-        * @param string $html Html for the text of the header
+        * @param string $html HTML for the text of the header
         * @param string $link HTML to add for the section edit link
-        * @param bool|string $legacyAnchor A second, optional anchor to give for
+        * @param string|bool $fallbackAnchor A second, optional anchor to give for
         *   backward compatibility (false to omit)
         *
         * @return string HTML headline
         */
        public static function makeHeadline( $level, $attribs, $anchor, $html,
-               $link, $legacyAnchor = false
+               $link, $fallbackAnchor = false
        ) {
+               $anchorEscaped = htmlspecialchars( $anchor );
                $ret = "<h$level$attribs"
-                       . "<span class=\"mw-headline\" id=\"$anchor\">$html</span>"
+                       . "<span class=\"mw-headline\" id=\"$anchorEscaped\">$html</span>"
                        . $link
                        . "</h$level>";
-               if ( $legacyAnchor !== false ) {
-                       $ret = "<div id=\"$legacyAnchor\"></div>$ret";
+               if ( $fallbackAnchor !== false && $fallbackAnchor !== $anchor ) {
+                       $fallbackAnchor = htmlspecialchars( $fallbackAnchor );
+                       $ret = "<div id=\"$fallbackAnchor\"></div>$ret";
                }
                return $ret;
        }
@@ -2021,7 +2028,7 @@ class Linker {
                }
 
                if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
-                       return Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
+                       return self::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
                } else {
                        if ( $rev->getId() ) {
                                // RevDelete links using revision ID are stable across
@@ -2040,7 +2047,7 @@ class Linker {
                                        'ids' => $rev->getTimestamp()
                                ];
                        }
-                       return Linker::revDeleteLink( $query,
+                       return self::revDeleteLink( $query,
                                $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
                }
        }
index 2c87b8b..7a5fd9a 100644 (file)
@@ -42,7 +42,7 @@ class ListToggle {
        private function checkboxLink( $checkboxType ) {
                return Html::element(
                        // CSS classes: mw-checkbox-all, mw-checkbox-none, mw-checkbox-invert
-                       'a', [ 'href' => '#', 'class' => 'mw-checkbox-' . $checkboxType ],
+                       'a', [ 'class' => 'mw-checkbox-' . $checkboxType, 'role' => 'button', 'tabindex' => 0 ],
                        $this->output->msg( 'checkbox-' . $checkboxType )->text()
                );
        }
index 89cb616..97dba26 100644 (file)
@@ -370,7 +370,7 @@ class MWNamespace {
         */
        public static function getSubjectNamespaces() {
                return array_filter(
-                       MWNamespace::getValidNamespaces(),
+                       self::getValidNamespaces(),
                        'MWNamespace::isSubject'
                );
        }
@@ -383,7 +383,7 @@ class MWNamespace {
         */
        public static function getTalkNamespaces() {
                return array_filter(
-                       MWNamespace::getValidNamespaces(),
+                       self::getValidNamespaces(),
                        'MWNamespace::isTalk'
                );
        }
index ee95918..6e7799a 100644 (file)
@@ -518,7 +518,7 @@ class MagicWord {
         * Returns true if the text matches the word, and alters the
         * input string, removing all instances of the word
         *
-        * @param string $text
+        * @param string &$text
         *
         * @return bool
         */
@@ -534,7 +534,7 @@ class MagicWord {
        }
 
        /**
-        * @param string $text
+        * @param string &$text
         * @return bool
         */
        public function matchStartAndRemove( &$text ) {
@@ -646,38 +646,11 @@ class MagicWord {
                return $this->mModified;
        }
 
-       /**
-        * $magicarr is an associative array of (magic word ID => replacement)
-        * This method uses the php feature to do several replacements at the same time,
-        * thereby gaining some efficiency. The result is placed in the out variable
-        * $result. The return value is true if something was replaced.
-        * @deprecated since 1.25, unused
-        *
-        * @param array $magicarr
-        * @param string $subject
-        * @param string $result
-        *
-        * @return bool
-        */
-       public function replaceMultiple( $magicarr, $subject, &$result ) {
-               wfDeprecated( __METHOD__, '1.25' );
-               $search = [];
-               $replace = [];
-               foreach ( $magicarr as $id => $replacement ) {
-                       $mw = MagicWord::get( $id );
-                       $search[] = $mw->getRegex();
-                       $replace[] = $replacement;
-               }
-
-               $result = preg_replace( $search, $replace, $subject );
-               return $result !== $subject;
-       }
-
        /**
         * Adds all the synonyms of this MagicWord to an array, to allow quick
         * lookup in a list of magic words
         *
-        * @param array $array
+        * @param array &$array
         * @param string $value
         */
        public function addToArray( &$array, $value ) {
index 6a9ead5..7461191 100644 (file)
@@ -260,7 +260,7 @@ class MagicWordArray {
         * Returns an associative array, ID => param value, for all items that match
         * Removes the matched items from the input string (passed by reference)
         *
-        * @param string $text
+        * @param string &$text
         *
         * @return array
         */
@@ -304,7 +304,7 @@ class MagicWordArray {
         * Return false if no match found and $text is not modified.
         * Does not match parameters.
         *
-        * @param string $text
+        * @param string &$text
         *
         * @return int|bool False on failure
         */
index 4df4d76..10b9e2b 100644 (file)
@@ -609,6 +609,7 @@ class MediaWiki {
                        $lbFactory->hasOrMadeRecentMasterChanges( INF )
                ) ? self::getUrlDomainDistance( $output->getRedirect(), $context ) : false;
 
+               $allowHeaders = !( $output->isDisabled() || headers_sent() );
                if ( $urlDomainDistance === 'local' || $urlDomainDistance === 'remote' ) {
                        // OutputPage::output() will be fast; $postCommitWork will not be useful for
                        // masking the latency of syncing DB positions accross all datacenters synchronously.
@@ -616,7 +617,7 @@ class MediaWiki {
                        $flags = $lbFactory::SHUTDOWN_CHRONPROT_ASYNC;
                        $cpPosTime = microtime( true );
                        // Client's next request should see 1+ positions with this DBMasterPos::asOf() time
-                       if ( $urlDomainDistance === 'local' ) {
+                       if ( $urlDomainDistance === 'local' && $allowHeaders ) {
                                // Client will stay on this domain, so set an unobtrusive cookie
                                $expires = time() + ChronologyProtector::POSITION_TTL;
                                $options = [ 'prefix' => '' ];
@@ -633,7 +634,7 @@ class MediaWiki {
                        // OutputPage::output() is fairly slow; run it in $postCommitWork to mask
                        // the latency of syncing DB positions accross all datacenters synchronously
                        $flags = $lbFactory::SHUTDOWN_CHRONPROT_SYNC;
-                       if ( $lbFactory->hasOrMadeRecentMasterChanges( INF ) ) {
+                       if ( $lbFactory->hasOrMadeRecentMasterChanges( INF ) && $allowHeaders ) {
                                $cpPosTime = microtime( true );
                                // Set a cookie in case the DB position store cannot sync accross datacenters.
                                // This will at least cover the common case of the user staying on the domain.
@@ -969,7 +970,7 @@ class MediaWiki {
        }
 
        /**
-        * @param integer $n Number of jobs to try to run
+        * @param int $n Number of jobs to try to run
         * @param LoggerInterface $runJobsLogger
         */
        private function triggerSyncJobs( $n, LoggerInterface $runJobsLogger ) {
@@ -978,7 +979,7 @@ class MediaWiki {
        }
 
        /**
-        * @param integer $n Number of jobs to try to run
+        * @param int $n Number of jobs to try to run
         * @param LoggerInterface $runJobsLogger
         * @return bool Success
         */
index 48ff97b..9d63869 100644 (file)
@@ -56,7 +56,7 @@ class MergeHistory {
        /** @var MWTimestamp|bool Timestamp upto which history from the source will be merged */
        protected $timestampLimit;
 
-       /** @var integer Number of revisions merged (for Special:MergeHistory success message) */
+       /** @var int Number of revisions merged (for Special:MergeHistory success message) */
        protected $revisionsMerged;
 
        /**
index be6b0af..0240fa7 100644 (file)
@@ -488,7 +488,7 @@ class Message implements MessageSpecifier, Serializable {
         *
         * @since 1.17
         *
-        * @param mixed ... Parameters as strings or arrays from
+        * @param mixed $args,... Parameters as strings or arrays from
         *  Message::numParam() and the like, or a single array of parameters.
         *
         * @return Message $this
@@ -1344,56 +1344,3 @@ class Message implements MessageSpecifier, Serializable {
                return $this->extractParam( new RawMessage( $vars, $params ), $format );
        }
 }
-
-/**
- * Variant of the Message class.
- *
- * Rather than treating the message key as a lookup
- * value (which is passed to the MessageCache and
- * translated as necessary), a RawMessage key is
- * treated as the actual message.
- *
- * All other functionality (parsing, escaping, etc.)
- * is preserved.
- *
- * @since 1.21
- */
-class RawMessage extends Message {
-
-       /**
-        * Call the parent constructor, then store the key as
-        * the message.
-        *
-        * @see Message::__construct
-        *
-        * @param string $text Message to use.
-        * @param array $params Parameters for the message.
-        *
-        * @throws InvalidArgumentException
-        */
-       public function __construct( $text, $params = [] ) {
-               if ( !is_string( $text ) ) {
-                       throw new InvalidArgumentException( '$text must be a string' );
-               }
-
-               parent::__construct( $text, $params );
-
-               // The key is the message.
-               $this->message = $text;
-       }
-
-       /**
-        * Fetch the message (in this case, the key).
-        *
-        * @return string
-        */
-       public function fetchMessage() {
-               // Just in case the message is unset somewhere.
-               if ( $this->message === null ) {
-                       $this->message = $this->key;
-               }
-
-               return $this->message;
-       }
-
-}
index 8670729..a2a44bb 100644 (file)
@@ -35,7 +35,7 @@ class MimeMagic extends MimeAnalyzer {
                $instance = MediaWikiServices::getInstance()->getMimeAnalyzer();
                Assert::postcondition(
                        $instance instanceof MimeMagic,
-                       __METHOD__ . ' should return an instance of ' . MimeMagic::class
+                       __METHOD__ . ' should return an instance of ' . self::class
                );
                return $instance;
        }
index 8d0c33d..39dc642 100644 (file)
@@ -511,7 +511,7 @@ class MovePage {
                $logEntry->setComment( $reason );
                $logEntry->setParameters( [
                        '4::target' => $nt->getPrefixedText(),
-                       '5::noredir' => $redirectContent ? '0': '1',
+                       '5::noredir' => $redirectContent ? '0' : '1',
                ] );
 
                $formatter = LogFormatter::newFromEntry( $logEntry );
index 969171d..dd21194 100644 (file)
@@ -571,6 +571,7 @@ class OutputPage extends ContextSource {
         * @param bool $filter Whether to filter out insufficiently trustworthy modules
         * @param string|null $position If not null, only return modules with this position
         * @param string $param
+        * @param string $type
         * @return array Array of module names
         */
        public function getModules( $filter = false, $position = null, $param = 'mModules',
@@ -688,7 +689,7 @@ class OutputPage extends ContextSource {
         * Add one or more head items to the output
         *
         * @since 1.28
-        * @param string|string[] $value Raw HTML
+        * @param string|string[] $values Raw HTML
         */
        public function addHeadItems( $values ) {
                $this->mHeadItems = array_merge( $this->mHeadItems, (array)$values );
@@ -1715,7 +1716,7 @@ class OutputPage extends ContextSource {
         * Add wikitext with a custom Title object
         *
         * @param string $text Wikitext
-        * @param Title $title
+        * @param Title &$title
         * @param bool $linestart Is this the start of a line?
         */
        public function addWikiTextWithTitle( $text, &$title, $linestart = true ) {
@@ -1726,7 +1727,7 @@ class OutputPage extends ContextSource {
         * Add wikitext with a custom Title object and tidy enabled.
         *
         * @param string $text Wikitext
-        * @param Title $title
+        * @param Title &$title
         * @param bool $linestart Is this the start of a line?
         */
        function addWikiTextTitleTidy( $text, &$title, $linestart = true ) {
@@ -1899,7 +1900,7 @@ class OutputPage extends ContextSource {
        /**
         * Add the output of a QuickTemplate to the output buffer
         *
-        * @param QuickTemplate $template
+        * @param QuickTemplate &$template
         */
        public function addTemplate( &$template ) {
                $this->addHTML( $template->getHTML() );
@@ -1963,7 +1964,7 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * @param $maxage
+        * @param int $maxage
         * @deprecated since 1.27 Use setCdnMaxage() instead
         */
        public function setSquidMaxage( $maxage ) {
@@ -1997,10 +1998,10 @@ class OutputPage extends ContextSource {
         * the TTL is higher the older the $mtime timestamp is. Essentially, the
         * TTL is 90% of the age of the object, subject to the min and max.
         *
-        * @param string|integer|float|bool|null $mtime Last-Modified timestamp
-        * @param integer $minTTL Mimimum TTL in seconds [default: 1 minute]
-        * @param integer $maxTTL Maximum TTL in seconds [default: $wgSquidMaxage]
-        * @return integer TTL in seconds
+        * @param string|int|float|bool|null $mtime Last-Modified timestamp
+        * @param int $minTTL Mimimum TTL in seconds [default: 1 minute]
+        * @param int $maxTTL Maximum TTL in seconds [default: $wgSquidMaxage]
+        * @return int TTL in seconds
         * @since 1.28
         */
        public function adaptCdnTTL( $mtime, $minTTL = 0, $maxTTL = 0 ) {
@@ -2908,6 +2909,18 @@ class OutputPage extends ContextSource {
                $pieces[] = $this->buildExemptModules();
                $pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
                $pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
+
+               $min = ResourceLoader::inDebugMode() ? '' : '.min';
+               // Use an IE conditional comment to serve the script only to old IE
+               $pieces[] = '<!--[if lt IE 9]>' .
+                       Html::element( 'script', [
+                               'src' => self::transformResourcePath(
+                                       $this->getConfig(),
+                                       "/resources/lib/html5shiv/html5shiv{$min}.js"
+                               ),
+                       ] ) .
+                       '<![endif]-->';
+
                $pieces[] = Html::closeElement( 'head' );
 
                $bodyClasses = [];
@@ -3785,7 +3798,7 @@ class OutputPage extends ContextSource {
         * Caller is responsible for ensuring the file exists. Emits a PHP warning otherwise.
         *
         * @since 1.27
-        * @param string $remotePath URL path prefix that points to $localPath
+        * @param string $remotePathPrefix URL path prefix that points to $localPath
         * @param string $localPath File directory exposed at $remotePath
         * @param string $file Path to target file relative to $localPath
         * @return string URL
index 5a440c4..cd5bf54 100644 (file)
@@ -36,6 +36,7 @@ class PHPVersionCheck {
                'ctype_digit' => 'ctype',
                'json_decode' => 'json',
                'iconv'       => 'iconv',
+               'mime_content_type' => 'fileinfo',
        );
 
        /**
@@ -230,9 +231,9 @@ HTML;
        /**
         * Returns an error page, which is suitable for output to the end user via a web browser.
         *
-        * @param $title
-        * @param $longHtml
-        * @param $shortText
+        * @param string $title
+        * @param string $longHtml
+        * @param string $shortText
         * @return string
         */
        function getIndexErrorOutput( $title, $longHtml, $shortText ) {
index c572373..2f3b954 100644 (file)
@@ -109,7 +109,7 @@ class Preferences {
         * @throws MWException
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences Array to load values for
+        * @param array &$defaultPreferences Array to load values for
         * @return array|null
         */
        static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
@@ -202,7 +202,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         * @return void
         */
        static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
@@ -599,7 +599,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         * @return void
         */
        static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
@@ -650,7 +650,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function filesPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                # # Files #####################################
@@ -671,7 +671,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         * @return void
         */
        static function datetimePreferences( $user, IContextSource $context, &$defaultPreferences ) {
@@ -749,7 +749,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function renderingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                # # Diffs ####################################
@@ -811,7 +811,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                # # Editing #####################################
@@ -884,7 +884,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                $config = $context->getConfig();
@@ -901,6 +901,8 @@ class Preferences {
                ];
                $defaultPreferences['rclimit'] = [
                        'type' => 'int',
+                       'min' => 0,
+                       'max' => 1000,
                        'label-message' => 'recentchangescount',
                        'help-message' => 'prefs-help-recentchangescount',
                        'section' => 'rc/displayrc',
@@ -918,6 +920,12 @@ class Preferences {
                $defaultPreferences['rcfilters-saved-queries'] = [
                        'type' => 'api',
                ];
+               $defaultPreferences['rcfilters-wl-saved-queries'] = [
+                       'type' => 'api',
+               ];
+               $defaultPreferences['rcfilters-rclimit'] = [
+                       'type' => 'api',
+               ];
 
                if ( $config->get( 'RCWatchCategoryMembership' ) ) {
                        $defaultPreferences['hidecategorization'] = [
@@ -955,7 +963,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function watchlistPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                $config = $context->getConfig();
@@ -1039,6 +1047,11 @@ class Preferences {
                        'section' => 'watchlist/advancedwatchlist',
                        'label-message' => 'tog-watchlistreloadautomatically',
                ];
+               $defaultPreferences['watchlistunwatchlinks'] = [
+                       'type' => 'toggle',
+                       'section' => 'watchlist/advancedwatchlist',
+                       'label-message' => 'tog-watchlistunwatchlinks',
+               ];
 
                if ( $config->get( 'RCWatchCategoryMembership' ) ) {
                        $defaultPreferences['watchlisthidecategorization'] = [
@@ -1105,7 +1118,7 @@ class Preferences {
        /**
         * @param User $user
         * @param IContextSource $context
-        * @param array $defaultPreferences
+        * @param array &$defaultPreferences
         */
        static function searchPreferences( $user, IContextSource $context, &$defaultPreferences ) {
                foreach ( MWNamespace::getValidNamespaces() as $n ) {
@@ -1117,6 +1130,9 @@ class Preferences {
 
        /**
         * Dummy, kept for backwards-compatibility.
+        * @param User $user
+        * @param IContextSource $context
+        * @param array &$defaultPreferences
         */
        static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) {
        }
@@ -1316,7 +1332,7 @@ class Preferences {
                $formClass = 'PreferencesForm',
                array $remove = []
        ) {
-               $formDescriptor = Preferences::getPreferences( $user, $context );
+               $formDescriptor = self::getPreferences( $user, $context );
                if ( count( $remove ) ) {
                        $removeKeys = array_flip( $remove );
                        $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
index a68c36f..53608e8 100644 (file)
@@ -616,7 +616,7 @@ class ProtectionForm {
        /**
         * Show protection long extracts for this page
         *
-        * @param OutputPage $out
+        * @param OutputPage &$out
         * @access private
         */
        function showLogExtract( &$out ) {
diff --git a/includes/RawMessage.php b/includes/RawMessage.php
new file mode 100644 (file)
index 0000000..9a0d947
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Variant of the Message class.
+ *
+ * Rather than treating the message key as a lookup
+ * value (which is passed to the MessageCache and
+ * translated as necessary), a RawMessage key is
+ * treated as the actual message.
+ *
+ * All other functionality (parsing, escaping, etc.)
+ * is preserved.
+ *
+ * @since 1.21
+ */
+class RawMessage extends Message {
+
+       /**
+        * Call the parent constructor, then store the key as
+        * the message.
+        *
+        * @see Message::__construct
+        *
+        * @param string $text Message to use.
+        * @param array $params Parameters for the message.
+        *
+        * @throws InvalidArgumentException
+        */
+       public function __construct( $text, $params = [] ) {
+               if ( !is_string( $text ) ) {
+                       throw new InvalidArgumentException( '$text must be a string' );
+               }
+
+               parent::__construct( $text, $params );
+
+               // The key is the message.
+               $this->message = $text;
+       }
+
+       /**
+        * Fetch the message (in this case, the key).
+        *
+        * @return string
+        */
+       public function fetchMessage() {
+               // Just in case the message is unset somewhere.
+               if ( $this->message === null ) {
+                       $this->message = $this->key;
+               }
+
+               return $this->message;
+       }
+
+}
index 592d495..547c2d5 100644 (file)
@@ -66,75 +66,3 @@ class ReadOnlyMode {
                $this->configuredReadOnly->clearCache();
        }
 }
-
-/**
- * A read-only mode service which does not depend on LoadBalancer.
- * To obtain an instance, use MediaWikiServices::getConfiguredReadOnlyMode().
- *
- * @since 1.29
- */
-class ConfiguredReadOnlyMode {
-       /** @var Config */
-       private $config;
-
-       /** @var string|bool|null */
-       private $fileReason;
-
-       /** @var string|null */
-       private $overrideReason;
-
-       public function __construct( Config $config ) {
-               $this->config = $config;
-       }
-
-       /**
-        * Check whether the wiki is in read-only mode.
-        *
-        * @return bool
-        */
-       public function isReadOnly() {
-               return $this->getReason() !== false;
-       }
-
-       /**
-        * Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
-        *
-        * @return string|bool String when in read-only mode; false otherwise
-        */
-       public function getReason() {
-               if ( $this->overrideReason !== null ) {
-                       return $this->overrideReason;
-               }
-               $confReason = $this->config->get( 'ReadOnly' );
-               if ( $confReason !== null ) {
-                       return $confReason;
-               }
-               if ( $this->fileReason === null ) {
-                       // Cache for faster access next time
-                       $readOnlyFile = $this->config->get( 'ReadOnlyFile' );
-                       if ( is_file( $readOnlyFile ) && filesize( $readOnlyFile ) > 0 ) {
-                               $this->fileReason = file_get_contents( $readOnlyFile );
-                       } else {
-                               $this->fileReason = false;
-                       }
-               }
-               return $this->fileReason;
-       }
-
-       /**
-        * Set the read-only mode, which will apply for the remainder of the
-        * request or until a service reset.
-        *
-        * @param string|null $msg
-        */
-       public function setReason( $msg ) {
-               $this->overrideReason = $msg;
-       }
-
-       /**
-        * Clear the cache of the read only file
-        */
-       public function clearCache() {
-               $this->fileReason = null;
-       }
-}
index c3782ba..e457beb 100644 (file)
@@ -559,8 +559,6 @@ class Revision implements IDBAccessObject {
        }
 
        /**
-        * Constructor
-        *
         * @param object|array $row Either a database row or an array
         * @throws MWException
         * @access private
@@ -754,7 +752,7 @@ class Revision implements IDBAccessObject {
         * This should only be used for proposed revisions that turn out to be null edits
         *
         * @since 1.28
-        * @param integer $id User ID
+        * @param int $id User ID
         * @param string $name User name
         */
        public function setUserIdAndName( $id, $name ) {
@@ -862,7 +860,7 @@ class Revision implements IDBAccessObject {
         *   Revision::FOR_PUBLIC       to be displayed to all users
         *   Revision::FOR_THIS_USER    to be displayed to the given user
         *   Revision::RAW              get the ID regardless of permissions
-        * @param User $user User object to check for, only if FOR_THIS_USER is passed
+        * @param User|null $user User object to check for, only if FOR_THIS_USER is passed
         *   to the $audience parameter
         * @return int
         */
@@ -896,7 +894,7 @@ class Revision implements IDBAccessObject {
         *   Revision::FOR_PUBLIC       to be displayed to all users
         *   Revision::FOR_THIS_USER    to be displayed to the given user
         *   Revision::RAW              get the text regardless of permissions
-        * @param User $user User object to check for, only if FOR_THIS_USER is passed
+        * @param User|null $user User object to check for, only if FOR_THIS_USER is passed
         *   to the $audience parameter
         * @return string
         */
@@ -940,7 +938,7 @@ class Revision implements IDBAccessObject {
         *   Revision::FOR_PUBLIC       to be displayed to all users
         *   Revision::FOR_THIS_USER    to be displayed to the given user
         *   Revision::RAW              get the text regardless of permissions
-        * @param User $user User object to check for, only if FOR_THIS_USER is passed
+        * @param User|null $user User object to check for, only if FOR_THIS_USER is passed
         *   to the $audience parameter
         * @return string
         */
@@ -1004,7 +1002,7 @@ class Revision implements IDBAccessObject {
 
                return RecentChange::newFromConds(
                        [
-                               'rc_user_text' => $this->getUserText( Revision::RAW ),
+                               'rc_user_text' => $this->getUserText( self::RAW ),
                                'rc_timestamp' => $dbr->timestamp( $this->getTimestamp() ),
                                'rc_this_oldid' => $this->getId()
                        ],
@@ -1309,7 +1307,7 @@ class Revision implements IDBAccessObject {
         * data is compressed, and 'utf-8' if we're saving in UTF-8
         * mode.
         *
-        * @param mixed $text Reference to a text
+        * @param mixed &$text Reference to a text
         * @return string
         */
        public static function compressRevisionText( &$text ) {
@@ -1468,7 +1466,7 @@ class Revision implements IDBAccessObject {
                                ? $this->getPreviousRevisionId( $dbw )
                                : $this->mParentId,
                        'rev_sha1'       => $this->mSha1 === null
-                               ? Revision::base36Sha1( $this->mText )
+                               ? self::base36Sha1( $this->mText )
                                : $this->mSha1,
                ];
 
@@ -1557,7 +1555,7 @@ class Revision implements IDBAccessObject {
                        }
                }
 
-               $content = $this->getContent( Revision::RAW );
+               $content = $this->getContent( self::RAW );
                $prefixedDBkey = $title->getPrefixedDBkey();
                $revId = $this->mId;
 
@@ -1586,7 +1584,7 @@ class Revision implements IDBAccessObject {
         * Get the text cache TTL
         *
         * @param WANObjectCache $cache
-        * @return integer
+        * @return int
         */
        private static function getCacheTTL( WANObjectCache $cache ) {
                global $wgRevisionCacheExpiry;
index ccdedb8..b0bc60a 100644 (file)
@@ -116,7 +116,7 @@ abstract class RevisionListBase extends ContextSource implements Iterator {
        }
 
        public function key() {
-               return $this->res ? $this->res->key(): 0;
+               return $this->res ? $this->res->key() : 0;
        }
 
        public function valid() {
index b08bc69..ed09701 100644 (file)
@@ -56,6 +56,21 @@ class Sanitizer {
        const EVIL_URI_PATTERN = '!(^|\s|\*/\s*)(javascript|vbscript)([^\w]|$)!i';
        const XMLNS_ATTRIBUTE_PATTERN = "/^xmlns:[:A-Z_a-z-.0-9]+$/";
 
+       /**
+        * Tells escapeUrlForHtml() to encode the ID using the wiki's primary encoding.
+        *
+        * @since 1.30
+        */
+       const ID_PRIMARY = 0;
+
+       /**
+        * Tells escapeUrlForHtml() to encode the ID using the fallback encoding, or return false
+        * if no fallback is configured.
+        *
+        * @since 1.30
+        */
+       const ID_FALLBACK = 1;
+
        /**
         * List of all named character entities defined in HTML 4.01
         * https://www.w3.org/TR/html4/sgml/entities.html
@@ -465,7 +480,7 @@ class Sanitizer {
                extract( self::getRecognizedTagData( $extratags, $removetags ) );
 
                # Remove HTML comments
-               $text = Sanitizer::removeHTMLcomments( $text );
+               $text = self::removeHTMLcomments( $text );
                $bits = explode( '<', $text );
                $text = str_replace( '>', '&gt;', array_shift( $bits ) );
                if ( !MWTidy::isEnabled() ) {
@@ -583,12 +598,12 @@ class Sanitizer {
                                                        call_user_func_array( $processCallback, [ &$params, $args ] );
                                                }
 
-                                               if ( !Sanitizer::validateTag( $params, $t ) ) {
+                                               if ( !self::validateTag( $params, $t ) ) {
                                                        $badtag = true;
                                                }
 
                                                # Strip non-approved attributes from the tag
-                                               $newparams = Sanitizer::fixTagAttributes( $params, $t );
+                                               $newparams = self::fixTagAttributes( $params, $t );
                                        }
                                        if ( !$badtag ) {
                                                $rest = str_replace( '>', '&gt;', $rest );
@@ -629,11 +644,11 @@ class Sanitizer {
                                                                call_user_func_array( $warnCallback, [ 'deprecated-self-close-category' ] );
                                                        }
                                                }
-                                               if ( !Sanitizer::validateTag( $params, $t ) ) {
+                                               if ( !self::validateTag( $params, $t ) ) {
                                                        $badtag = true;
                                                }
 
-                                               $newparams = Sanitizer::fixTagAttributes( $params, $t );
+                                               $newparams = self::fixTagAttributes( $params, $t );
                                                if ( !$badtag ) {
                                                        if ( $brace === '/>' && !isset( $htmlsingleonly[$t] ) ) {
                                                                # Interpret self-closing tags as empty tags even when
@@ -710,7 +725,7 @@ class Sanitizer {
         * @return bool
         */
        static function validateTag( $params, $element ) {
-               $params = Sanitizer::decodeTagAttributes( $params );
+               $params = self::decodeTagAttributes( $params );
 
                if ( $element == 'meta' || $element == 'link' ) {
                        if ( !isset( $params['itemprop'] ) ) {
@@ -746,8 +761,8 @@ class Sanitizer {
         * @todo Check for unique id attribute :P
         */
        static function validateTagAttributes( $attribs, $element ) {
-               return Sanitizer::validateAttributes( $attribs,
-                       Sanitizer::attributeWhitelist( $element ) );
+               return self::validateAttributes( $attribs,
+                       self::attributeWhitelist( $element ) );
        }
 
        /**
@@ -795,12 +810,12 @@ class Sanitizer {
                        # Strip javascript "expression" from stylesheets.
                        # https://msdn.microsoft.com/en-us/library/ms537634.aspx
                        if ( $attribute == 'style' ) {
-                               $value = Sanitizer::checkCss( $value );
+                               $value = self::checkCss( $value );
                        }
 
                        # Escape HTML id attributes
                        if ( $attribute === 'id' ) {
-                               $value = Sanitizer::escapeId( $value, 'noninitial' );
+                               $value = self::escapeIdForAttribute( $value, self::ID_PRIMARY );
                        }
 
                        # Escape HTML id reference lists
@@ -809,7 +824,7 @@ class Sanitizer {
                                || $attribute === 'aria-labelledby'
                                || $attribute === 'aria-owns'
                        ) {
-                               $value = Sanitizer::escapeIdReferenceList( $value, 'noninitial' );
+                               $value = self::escapeIdReferenceList( $value, 'noninitial' );
                        }
 
                        // RDFa and microdata properties allow URLs, URIs and/or CURIs.
@@ -907,7 +922,7 @@ class Sanitizer {
         */
        public static function normalizeCss( $value ) {
                // Decode character references like &#123;
-               $value = Sanitizer::decodeCharReferences( $value );
+               $value = self::decodeCharReferences( $value );
 
                // Decode escape sequences and line continuation
                // See the grammar in the CSS 2 spec, appendix D.
@@ -1087,14 +1102,14 @@ class Sanitizer {
                        return '';
                }
 
-               $decoded = Sanitizer::decodeTagAttributes( $text );
-               $stripped = Sanitizer::validateTagAttributes( $decoded, $element );
+               $decoded = self::decodeTagAttributes( $text );
+               $stripped = self::validateTagAttributes( $decoded, $element );
 
                if ( $sorted ) {
                        ksort( $stripped );
                }
 
-               return Sanitizer::safeEncodeTagAttributes( $stripped );
+               return self::safeEncodeTagAttributes( $stripped );
        }
 
        /**
@@ -1124,7 +1139,7 @@ class Sanitizer {
         * @return string HTML-encoded text fragment
         */
        static function safeEncodeAttribute( $text ) {
-               $encValue = Sanitizer::encodeAttribute( $text );
+               $encValue = self::encodeAttribute( $text );
 
                # Templates and links may be expanded in later parsing,
                # creating invalid or dangerous output. Suppress this.
@@ -1164,6 +1179,8 @@ class Sanitizer {
         * ambiguous if it's part of something that looks like a percent escape
         * (which don't work reliably in fragments cross-browser).
         *
+        * @deprecated since 1.30, use one of this class' escapeIdFor*() functions
+        *
         * @see https://www.w3.org/TR/html401/types.html#type-name Valid characters
         *   in the id and name attributes
         * @see https://www.w3.org/TR/html401/struct/links.html#h-12.2.3 Anchors with
@@ -1186,7 +1203,7 @@ class Sanitizer {
                global $wgExperimentalHtmlIds;
                $options = (array)$options;
 
-               $id = Sanitizer::decodeCharReferences( $id );
+               $id = self::decodeCharReferences( $id );
 
                if ( $wgExperimentalHtmlIds && !in_array( 'legacy', $options ) ) {
                        $id = preg_replace( '/[ \t\n\r\f_\'"&#%]+/', '_', $id );
@@ -1215,21 +1232,146 @@ class Sanitizer {
                return $id;
        }
 
+       /**
+        * Given a section name or other user-generated or otherwise unsafe string, escapes it to be
+        * a valid HTML id attribute.
+        *
+        * WARNING: unlike escapeId(), the output of this function is not guaranteed to be HTML safe,
+        * be sure to use proper escaping.
+        *
+        * @param string $id String to escape
+        * @param int $mode One of ID_* constants, specifying whether the primary or fallback encoding
+        *     should be used.
+        * @return string|bool Escaped ID or false if fallback encoding is requested but it's not
+        *     configured.
+        *
+        * @since 1.30
+        */
+       public static function escapeIdForAttribute( $id, $mode = self::ID_PRIMARY ) {
+               global $wgFragmentMode;
+
+               if ( !isset( $wgFragmentMode[$mode] ) ) {
+                       if ( $mode === self::ID_PRIMARY ) {
+                               throw new UnexpectedValueException( '$wgFragmentMode is configured with no primary mode' );
+                       }
+                       return false;
+               }
+
+               $internalMode = $wgFragmentMode[$mode];
+
+               return self::escapeIdInternal( $id, $internalMode );
+       }
+
+       /**
+        * Given a section name or other user-generated or otherwise unsafe string, escapes it to be
+        * a valid URL fragment.
+        *
+        * WARNING: unlike escapeId(), the output of this function is not guaranteed to be HTML safe,
+        * be sure to use proper escaping.
+        *
+        * @param string $id String to escape
+        * @return string Escaped ID
+        *
+        * @since 1.30
+        */
+       public static function escapeIdForLink( $id ) {
+               global $wgFragmentMode;
+
+               if ( !isset( $wgFragmentMode[self::ID_PRIMARY] ) ) {
+                       throw new UnexpectedValueException( '$wgFragmentMode is configured with no primary mode' );
+               }
+
+               $mode = $wgFragmentMode[self::ID_PRIMARY];
+
+               $id = self::escapeIdInternal( $id, $mode );
+               $id = self::urlEscapeId( $id, $mode );
+
+               return $id;
+       }
+
+       /**
+        * Given a section name or other user-generated or otherwise unsafe string, escapes it to be
+        * a valid URL fragment for external interwikis.
+        *
+        * @param string $id String to escape
+        * @return string Escaped ID
+        *
+        * @since 1.30
+        */
+       public static function escapeIdForExternalInterwiki( $id ) {
+               global $wgExternalInterwikiFragmentMode;
+
+               $id = self::escapeIdInternal( $id, $wgExternalInterwikiFragmentMode );
+               $id = self::urlEscapeId( $id, $wgExternalInterwikiFragmentMode );
+
+               return $id;
+       }
+
+       /**
+        * Helper for escapeIdFor*() functions. URL-escapes the ID if needed.
+        *
+        * @param string $id String to escape
+        * @param string $mode One of modes from $wgFragmentMode
+        * @return string
+        */
+       private static function urlEscapeId( $id, $mode ) {
+               if ( $mode === 'html5' ) {
+                       $id = urlencode( $id );
+                       $id = str_replace( '%3A', ':', $id );
+               }
+
+               return $id;
+       }
+
+       /**
+        * Helper for escapeIdFor*() functions. Performs most of the actual escaping.
+        *
+        * @param string $id String to escape
+        * @param string $mode One of modes from $wgFragmentMode
+        * @return string
+        */
+       private static function escapeIdInternal( $id, $mode ) {
+               $id = self::decodeCharReferences( $id );
+
+               switch ( $mode ) {
+                       case 'html5':
+                               $id = str_replace( ' ', '_', $id );
+                               break;
+                       case 'legacy':
+                               // This corresponds to 'noninitial' mode of the old escapeId()
+                               static $replace = [
+                                       '%3A' => ':',
+                                       '%' => '.'
+                               ];
+
+                               $id = urlencode( str_replace( ' ', '_', $id ) );
+                               $id = strtr( $id, $replace );
+                               break;
+                       case 'html5-legacy':
+                               $id = preg_replace( '/[ \t\n\r\f_\'"&#%]+/', '_', $id );
+                               $id = trim( $id, '_' );
+                               if ( $id === '' ) {
+                                       // Must have been all whitespace to start with.
+                                       $id = '_';
+                               }
+                               break;
+                       default:
+                               throw new InvalidArgumentException( "Invalid mode '$mode' passed to '" . __METHOD__ );
+               }
+
+               return $id;
+       }
+
        /**
         * Given a string containing a space delimited list of ids, escape each id
         * to match ids escaped by the escapeId() function.
         *
+        * @todo wfDeprecated() uses of $options in 1.31, remove completely in 1.32
+        *
         * @since 1.27
         *
         * @param string $referenceString Space delimited list of ids
-        * @param string|array $options String or array of strings (default is array()):
-        *   'noninitial': This is a non-initial fragment of an id, not a full id,
-        *       so don't pay attention if the first character isn't valid at the
-        *       beginning of an id.  Only matters if $wgExperimentalHtmlIds is
-        *       false.
-        *   'legacy': Behave the way the old HTML 4-based ID escaping worked even
-        *       if $wgExperimentalHtmlIds is used, so we can generate extra
-        *       anchors and links won't break.
+        * @param string|array $options Deprecated and does nothing.
         * @return string
         */
        static function escapeIdReferenceList( $referenceString, $options = [] ) {
@@ -1238,7 +1380,7 @@ class Sanitizer {
 
                # Escape each token as an id
                foreach ( $references as &$ref ) {
-                       $ref = Sanitizer::escapeId( $ref, $options );
+                       $ref = self::escapeIdForAttribute( $ref );
                }
 
                # Merge the array back to a space delimited list string
@@ -1275,7 +1417,7 @@ class Sanitizer {
         * @return string Escaped input
         */
        static function escapeHtmlAllowEntities( $html ) {
-               $html = Sanitizer::decodeCharReferences( $html );
+               $html = self::decodeCharReferences( $html );
                # It seems wise to escape ' as well as ", as a matter of course.  Can't
                # hurt. Use ENT_SUBSTITUTE so that incorrectly truncated multibyte characters
                # don't cause the entire string to disappear.
@@ -1317,14 +1459,14 @@ class Sanitizer {
 
                foreach ( $pairs as $set ) {
                        $attribute = strtolower( $set[1] );
-                       $value = Sanitizer::getTagAttributeCallback( $set );
+                       $value = self::getTagAttributeCallback( $set );
 
                        // Normalize whitespace
                        $value = preg_replace( '/[\t\r\n ]+/', ' ', $value );
                        $value = trim( $value );
 
                        // Decode character references
-                       $attribs[$attribute] = Sanitizer::decodeCharReferences( $value );
+                       $attribs[$attribute] = self::decodeCharReferences( $value );
                }
                return $attribs;
        }
@@ -1340,7 +1482,7 @@ class Sanitizer {
                $attribs = [];
                foreach ( $assoc_array as $attribute => $value ) {
                        $encAttribute = htmlspecialchars( $attribute );
-                       $encValue = Sanitizer::safeEncodeAttribute( $value );
+                       $encValue = self::safeEncodeAttribute( $value );
 
                        $attribs[] = "$encAttribute=\"$encValue\"";
                }
@@ -1427,11 +1569,11 @@ class Sanitizer {
        static function normalizeCharReferencesCallback( $matches ) {
                $ret = null;