MediaWiki\Linker\LinkRenderer. In addition, the LinkBegin and LinkEnd hooks
were replaced by HtmlPageLinkRendererBegin and HtmlPageLinkRendererEnd
respectively. See docs/hooks.txt for the specific changes needed for those hooks.
+* Aliases for Linker methods, deprecated since 1.21, were removed from Skin:
+ * Skin::commentBlock() (use Linker::commentBlock() instead)
+ * Skin::generateRollback() (use Linker::generateRollback() instead)
+ * Skin::link() (use MediaWiki\Linker\LinkRenderer instead)
+ * Skin::linkKnown() (use MediaWiki\Linker\LinkRenderer instead)
+ * Skin::userLink() (use Linker::userLink() instead)
+ * Skin::userToolLinks() (use Linker::userToolLinks() instead)
* The 'ParserLimitReportFormat' hook was removed.
* Disabled "bug 2702" HTML tidying of parsed UI messages on wikis where Tidy is
disabled.
* DifferenceEngine::generateDiffBody() was removed (deprecated since 1.21).
+* UploadBase::stashFileGetKey() and UploadBase::stashSession() were deprecated.
+ Use ...->stashFile()->getFileKey() instead.
== Compatibility ==
'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
'McTest' => __DIR__ . '/maintenance/mctest.php',
'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
+ 'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformOutput.php',
'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
+ 'ResourceLoaderUserStylesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserStylesModule.php',
'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
'ResourceLoaderWikiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderWikiModule.php',
'RestbaseVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/RestbaseVirtualRESTService.php',
'WikiReference' => __DIR__ . '/includes/WikiMap.php',
'WikiRevision' => __DIR__ . '/includes/import/WikiRevision.php',
'WikiStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
+ 'WikiTextStructure' => __DIR__ . '/includes/content/WikiTextStructure.php',
'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
"ext-xml": "*",
"liuggio/statsd-php-client": "1.0.18",
"mediawiki/at-ease": "1.1.0",
- "oojs/oojs-ui": "0.17.6",
+ "oojs/oojs-ui": "0.17.7",
"oyejorge/less.php": "1.7.0.10",
"php": ">=5.5.9",
"psr/log": "1.0.0",
"type": "string",
"description": "Group with which this module should be loaded"
},
+ "deprecated": {
+ "type": ["object", "boolean"],
+ "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message."
+ },
"position": {
"type": "string",
"description": "Position on the page to load this module at",
"type": "string",
"description": "Group which this module should be loaded together with"
},
+ "deprecated": {
+ "type": ["object", "boolean"],
+ "description": "Whether the module is deprecated and usage is discouraged. Either a boolean or an object with key message can be used to customise deprecation message."
+ },
"position": {
"type": "string",
"description": "Position on the page to load this module at",
$id: id of the article that was deleted
$content: the Content of the deleted page
$logEntry: the ManualLogEntry used to record the deletion
+$archivedRevisionCount: the number of revisions archived during the deletion
'ArticleEditUpdateNewTalk': Before updating user_newtalk when a user talk page
was changed.
$title: Current Title object being displayed in search results.
&$id: Revision ID (default is false, for latest)
+'SearchIndexFields': Add fields to search index mapping.
+&$fields: Array of fields, all implement SearchIndexField
+$engine: SearchEngine instance for which mapping is being built.
+
+'SearchDataForIndex': Add data to search document. Allows to add any data to
+the field map used to index the document.
+&$fields: Array of name => value pairs for fields
+$handler: ContentHandler for the content being indexed
+$page: WikiPage that is being indexed
+$output: ParserOutput that is produced from the page
+$engine: SearchEngine for which the indexing is intended
+
'SecondaryDataUpdates': Allows modification of the list of DataUpdates to
perform when page content is modified. Currently called by
AbstractContent::getSecondaryDataUpdates.
/**
* Plugins for media file type handling.
* Each entry in the array maps a MIME type to a class name
+ *
+ * Core media handlers are listed in MediaHandlerFactory,
+ * and extensions should use extension.json.
*/
-$wgMediaHandlers = [
- 'image/jpeg' => 'JpegHandler',
- 'image/png' => 'PNGHandler',
- 'image/gif' => 'GIFHandler',
- 'image/tiff' => 'TiffHandler',
- 'image/webp' => 'WebPHandler',
- 'image/x-ms-bmp' => 'BmpHandler',
- 'image/x-bmp' => 'BmpHandler',
- 'image/x-xcf' => 'XCFHandler',
- 'image/svg+xml' => 'SvgHandler', // official
- 'image/svg' => 'SvgHandler', // compat
- 'image/vnd.djvu' => 'DjVuHandler', // official
- 'image/x.djvu' => 'DjVuHandler', // compat
- 'image/x-djvu' => 'DjVuHandler', // compat
-];
+$wgMediaHandlers = [];
/**
* Plugins for page content model handling.
/**
* Kept for extension compatibility; see $wgParserCacheType
- * @deprecated 1.26
+ * @deprecated since 1.26
*/
$wgEnableParserCache = true;
* Supports base 2 through 36; digit values 10-36 are represented
* as lowercase letters a-z. Input is case-insensitive.
*
- * @deprecated 1.27 Use Wikimedia\base_convert() directly
+ * @deprecated since 1.27 Use Wikimedia\base_convert() directly
*
* @param string $input Input number
* @param int $sourceBase Base of the input number
* @param string|null $deprecatedVersion Optionally mark hook as deprecated with version number
*
* @return bool True if no handler aborted the hook
- * @deprecated 1.25 - use Hooks::run
+ * @deprecated since 1.25 - use Hooks::run
*/
function wfRunHooks( $event, array $args = [], $deprecatedVersion = null ) {
return Hooks::run( $event, $args, $deprecatedVersion );
use LinkCache;
use Liuggio\StatsdClient\Factory\StatsdDataFactory;
use LoadBalancer;
+use MediaHandlerFactory;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Linker\LinkRendererFactory;
use MediaWiki\Services\SalvageableService;
return $this->getService( 'WatchedItemQueryService' );
}
+ /**
+ * @since 1.28
+ * @return MediaHandlerFactory
+ */
+ public function getMediaHandlerFactory() {
+ return $this->getService( 'MediaHandlerFactory' );
+ }
+
/**
* @since 1.28
* @return GenderCache
}
/**
- * Add or replace an header item to the output
+ * Add or replace a head item to the output
*
* Whenever possible, use more specific options like ResourceLoader modules,
* OutputPage::addLink(), OutputPage::addMetaLink() and OutputPage::addFeedLink()
$this->mHeadItems[$name] = $value;
}
+ /**
+ * Add one or more head items to the output
+ *
+ * @since 1.28
+ * @param string|string[] $value Raw HTML
+ */
+ public function addHeadItems( $values ) {
+ $this->mHeadItems = array_merge( $this->mHeadItems, (array)$values );
+ }
+
/**
* Check if the header item $name is already set
*
) {
// We're on a preview of a CSS subpage
// Exclude this page from the user module in case it's in there (bug 26283)
- $link = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES,
+ $link = $this->makeResourceLoaderLink( 'user.styles', ResourceLoaderModule::TYPE_STYLES,
[ 'excludepage' => $this->getTitle()->getPrefixedDBkey() ]
);
$otherTags = array_merge( $otherTags, $link['html'] );
$otherTags[] = Html::inlineStyle( $previewedCSS );
} else {
// Load the user styles normally
- $moduleStyles[] = 'user';
+ $moduleStyles[] = 'user.styles';
}
// Per-user preference styles
* <https://github.com/wikimedia/mediawiki-extensions-EventLogging/
* blob/7e5fe4f1ef/includes/EventLogging.php#L32-L74>
*
- * @param data Pingback data as an associative array
+ * @param array $data Pingback data as an associative array
* @return bool true on success, false on failure
*/
private function postPingback( array $data ) {
return new WatchedItemQueryService( $services->getDBLoadBalancer() );
},
+ 'MediaHandlerFactory' => function( MediaWikiServices $services ) {
+ return new MediaHandlerFactory(
+ $services->getMainConfig()->get( 'MediaHandlers' )
+ );
+ },
+
'LinkCache' => function( MediaWikiServices $services ) {
return new LinkCache(
$services->getTitleFormatter()
*
* @return array A list in which each entry is an array with a message key as its first element.
* The remaining array elements are the message parameters.
- * @deprecated 1.25
+ * @deprecated since 1.25
*/
public function getErrorsArray() {
return $this->getStatusArray( 'error' );
*
* @return array A list in which each entry is an array with a message key as its first element.
* The remaining array elements are the message parameters.
- * @deprecated 1.25
+ * @deprecated since 1.25
*/
public function getWarningsArray() {
return $this->getStatusArray( 'warning' );
"apihelp-parse-paramvalue-prop-sections": "Devolve as seccións do texto wiki analizado.",
"apihelp-parse-paramvalue-prop-revid": "Engade o identificador de edición do texto wiki analizado.",
"apihelp-parse-paramvalue-prop-displaytitle": "Engade o título do texto wiki analizado.",
- "apihelp-parse-paramvalue-prop-headitems": "Devolve os elementos a poñer na <code><cabeceira></code> da páxina.",
+ "apihelp-parse-paramvalue-prop-headitems": "<span class=\"apihelp-deprecated\">Obsoleto.</span> Devolve os elementos a poñer na <code><cabeceira></code> da páxina.",
"apihelp-parse-paramvalue-prop-headhtml": "Devolve <code><cabeceira></code> analizada da páxina.",
- "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitados xunto con <kbd>modules</kbd>.",
- "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina.",
+ "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina. Para cargar, use <code>mw.loader.using()</code>. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitados xunto con <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina. Para aplicalo, use <code>mw.config.set()</code>.",
"apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina como unha cadea de texto JSON.",
"apihelp-parse-paramvalue-prop-indicators": "Devolve o HTML dos indicadores de estado de páxina usados na páxina.",
"apihelp-parse-paramvalue-prop-iwlinks": "Devolve as ligazóns interwiki do texto wiki analizado.",
"apihelp-protect-description": "Cambiar o nivel de protección dunha páxina.",
"apihelp-protect-param-title": "Título da páxina que quere (des)protexer. Non pode usarse xunto con $1pageid.",
"apihelp-protect-param-pageid": "Identificador da páxina que quere (des)protexer. Non pode usarse xunto con $1title.",
- "apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>).\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
+ "apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>). Un nivel de <kbd>all</kbd> quere dicir que todo o mundo ten permiso para realizar a acción, sen restricións.\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
"apihelp-protect-param-expiry": "Selos de tempo de caducidade. Se só se indica un selo de tempo, usarase para todas as proteccións. Use <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, ou <kbd>never</kbd>, para unha protección sen caducidade.",
"apihelp-protect-param-reason": "Razón para (des)protexer.",
"apihelp-protect-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de protección.",
"apihelp-protect-param-watch": "Se se define este parámetro, engadir a páxina que se (des)protexe á lista de vixilancia do usuario actual.",
"apihelp-protect-param-watchlist": "Engadir ou eliminar sen condicións a páxina da lista de vixiancia do usuario actual, use as preferencias ou non cambie a vixiancia.",
"apihelp-protect-example-protect": "Protexer unha páxina",
- "apihelp-protect-example-unprotect": "Desprotexer unha páxina poñendo as restricións a <kbd>all</kbd>.",
+ "apihelp-protect-example-unprotect": "Desprotexer unha páxina poñendo as restricións a <kbd>all</kbd>. (isto quere dicir que todo o mundo pode realizar a acción).",
"apihelp-protect-example-unprotect2": "Desprotexer unha páxina quitando as restricións.",
"apihelp-purge-description": "Borrar a caché para os títulos indicados.\n\nPrecisa dunha petición POST se o usuario non está conectado.",
"apihelp-purge-param-forcelinkupdate": "Actualizar as táboas de ligazóns.",
}
$status = $this->checkPasswordValidity( $username, $req->password );
- if ( !$status->isOk() ) {
+ if ( !$status->isOK() ) {
// Fatal, can't log in
return AuthenticationResponse::newFail( $status->getMessage() );
}
*/
return [];
}
+
+ /**
+ * Add new field definition to array.
+ * @param SearchIndexField[] $fields
+ * @param SearchEngine $engine
+ * @param string $name
+ * @param int $type
+ * @return SearchIndexField[] new field defs
+ * @since 1.28
+ */
+ protected function addSearchField( &$fields, SearchEngine $engine, $name, $type ) {
+ $fields[$name] = $engine->makeSearchFieldMapping( $name, $type );
+ return $fields;
+ }
+
+ /**
+ * Return fields to be indexed by search engine
+ * as representation of this document.
+ * Overriding class should call parent function or take care of calling
+ * the SearchDataForIndex hook.
+ * @param WikiPage $page Page to index
+ * @param ParserOutput $output
+ * @param SearchEngine $engine Search engine for which we are indexing
+ * @return array Map of name=>value for fields
+ * @since 1.28
+ */
+ public function getDataForSearchIndex( WikiPage $page, ParserOutput $output,
+ SearchEngine $engine ) {
+ $fields = [];
+ $content = $page->getContent();
+ if ( $content ) {
+ $text = $content->getTextForSearchIndex();
+ $fields['text'] = $text;
+ $fields['source_text'] = $text;
+ $fields['text_bytes'] = $content->getSize();
+ }
+ Hooks::run( 'SearchDataForIndex', [ &$fields, $this, $page, $output, $engine ] );
+ return $fields;
+ }
+
+ /**
+ * Produce page output suitable for indexing.
+ *
+ * Specific content handlers may override it if they need different content handling.
+ *
+ * @param WikiPage $page
+ * @param ParserCache $cache
+ * @return ParserOutput
+ */
+ public function getParserOutputForIndexing( WikiPage $page, ParserCache $cache = null ) {
+ $parserOptions = $page->makeParserOptions( 'canonical' );
+ $revId = $page->getRevision()->getId();
+ if ( $cache ) {
+ $parserOutput = $cache->get( $page, $parserOptions );
+ }
+ if ( empty( $parserOutput ) ) {
+ $parserOutput =
+ $page->getContent()->getParserOutput( $page->getTitle(), $revId, $parserOptions );
+ if ( $cache ) {
+ $cache->save( $parserOutput, $page, $parserOptions );
+ }
+ }
+ return $parserOutput;
+ }
+
}
$engine->makeSearchFieldMapping( 'language', SearchIndexField::INDEX_TYPE_KEYWORD );
return $fields;
}
+
+ public function getDataForSearchIndex( WikiPage $page, ParserOutput $output,
+ SearchEngine $engine ) {
+ $fields = parent::getDataForSearchIndex( $page, $output, $engine );
+ $fields['language'] =
+ $this->getPageLanguage( $page->getTitle(), $page->getContent() )->getCode();
+ return $fields;
+ }
+
}
--- /dev/null
+<?php
+
+use HtmlFormatter\HtmlFormatter;
+use MediaWiki\Logger\LoggerFactory;
+
+/**
+ * Class allowing to explore structure of parsed wikitext.
+ */
+class WikiTextStructure {
+ /**
+ * @var string
+ */
+ private $openingText;
+ /**
+ * @var string
+ */
+ private $allText;
+ /**
+ * @var string[]
+ */
+ private $auxText = [];
+ /**
+ * @var ParserOutput
+ */
+ private $parserOutput;
+
+ /**
+ * @var string[] selectors to elements that are excluded entirely from search
+ */
+ private $excludedElementSelectors = [
+ 'audio', 'video', // "it looks like you don't have javascript enabled..."
+ // do not need to index
+ 'sup.reference', // The [1] for references
+ '.mw-cite-backlink', // The ↑ next to references in the references section
+ 'h1', 'h2', 'h3', // Headings are already indexed in their own field.
+ 'h5', 'h6', 'h4',
+ '.autocollapse', // Collapsed fields are hidden by default so we don't want them
+ // showing up.
+ ];
+
+ /**
+ * @var string[] selectors to elements that are considered auxiliary to article text for search
+ */
+ private $auxiliaryElementSelectors = [
+ '.thumbcaption', // Thumbnail captions aren't really part of the text proper
+ 'table', // Neither are tables
+ '.rellink', // Common style for "See also:".
+ '.dablink', // Common style for calling out helpful links at the top
+ // of the article.
+ '.searchaux', // New class users can use to mark stuff as auxiliary to searches.
+ ];
+
+ /**
+ * WikiTextStructure constructor.
+ * @param ParserOutput $parserOutput
+ */
+ public function __construct( ParserOutput $parserOutput ) {
+ $this->parserOutput = $parserOutput;
+ }
+
+ /**
+ * Get categories in the text.
+ * @return string[]
+ */
+ public function categories() {
+ $categories = [];
+ foreach ( array_keys( $this->parserOutput->getCategories() ) as $key ) {
+ $categories[] = Category::newFromName( $key )->getTitle()->getText();
+ }
+ return $categories;
+ }
+
+ /**
+ * Get outgoing links.
+ * @return string[]
+ */
+ public function outgoingLinks() {
+ $outgoingLinks = [];
+ foreach ( $this->parserOutput->getLinks() as $linkedNamespace => $namespaceLinks ) {
+ foreach ( array_keys( $namespaceLinks ) as $linkedDbKey ) {
+ $outgoingLinks[] =
+ Title::makeTitle( $linkedNamespace, $linkedDbKey )->getPrefixedDBkey();
+ }
+ }
+ return $outgoingLinks;
+ }
+
+ /**
+ * Get templates in the text.
+ * @return string[]
+ */
+ public function templates() {
+ $templates = [];
+ foreach ( $this->parserOutput->getTemplates() as $tNS => $templatesInNS ) {
+ foreach ( array_keys( $templatesInNS ) as $tDbKey ) {
+ $templateTitle = Title::makeTitleSafe( $tNS, $tDbKey );
+ if ( $templateTitle && $templateTitle->exists() ) {
+ $templates[] = $templateTitle->getPrefixedText();
+ }
+ }
+ }
+ return $templates;
+ }
+
+ /**
+ * Get headings on the page.
+ * @return string[]
+ * First strip out things that look like references. We can't use HTML filtering because
+ * the references come back as <sup> tags without a class. To keep from breaking stuff like
+ * ==Applicability of the strict mass–energy equivalence formula, ''E'' = ''mc''<sup>2</sup>==
+ * we don't remove the whole <sup> tag. We also don't want to strip the <sup> tag and remove
+ * everything that looks like [2] because, I dunno, maybe there is a band named Word [2] Foo
+ * or something. Whatever. So we only strip things that look like <sup> tags wrapping a
+ * reference. And since the data looks like:
+ * Reference in heading <sup>[1]</sup><sup>[2]</sup>
+ * we can not really use HtmlFormatter as we have no suitable selector.
+ */
+ public function headings() {
+ $headings = [];
+ $ignoredHeadings = $this->getIgnoredHeadings();
+ foreach ( $this->parserOutput->getSections() as $heading ) {
+ $heading = $heading[ 'line' ];
+
+ // Some wikis wrap the brackets in a span:
+ // http://en.wikipedia.org/wiki/MediaWiki:Cite_reference_link
+ $heading = preg_replace( '/<\/?span>/', '', $heading );
+ // Normalize [] so the following regexp would work.
+ $heading = preg_replace( [ '/[/', '/]/' ], [ '[', ']' ], $heading );
+ $heading = preg_replace( '/<sup>\s*\[\s*\d+\s*\]\s*<\/sup>/is', '', $heading );
+
+ // Strip tags from the heading or else we'll display them (escaped) in search results
+ $heading = trim( Sanitizer::stripAllTags( $heading ) );
+
+ // Note that we don't take the level of the heading into account - all headings are equal.
+ // Except the ones we ignore.
+ if ( !in_array( $heading, $ignoredHeadings ) ) {
+ $headings[] = $heading;
+ }
+ }
+ return $headings;
+ }
+
+ /**
+ * Parse a message content into an array. This function is generally used to
+ * parse settings stored as i18n messages (see search-ignored-headings).
+ *
+ * @param string $message
+ * @return string[]
+ */
+ public static function parseSettingsInMessage( $message ) {
+ $lines = explode( "\n", $message );
+ $lines = preg_replace( '/#.*$/', '', $lines ); // Remove comments
+ $lines = array_map( 'trim', $lines ); // Remove extra spaces
+ $lines = array_filter( $lines ); // Remove empty lines
+ return $lines;
+ }
+
+ /**
+ * Get list of heading to ignore.
+ * @return string[]
+ */
+ private function getIgnoredHeadings() {
+ static $ignoredHeadings = null;
+ if ( $ignoredHeadings === null ) {
+ // FIXME: will be renamed in next patches to search-ignored-headings
+ $source = wfMessage( 'cirrussearch-ignored-headings' )->inContentLanguage();
+ $ignoredHeadings = [];
+ if ( !$source->isDisabled() ) {
+ $lines = self::parseSettingsInMessage( $source->plain() );
+ $ignoredHeadings = $lines; // Now we just have headings!
+ }
+ }
+ return $ignoredHeadings;
+ }
+
+ /**
+ * Extract parts of the text - opening, main and auxiliary.
+ */
+ private function extractWikitextParts() {
+ if ( !is_null( $this->allText ) ) {
+ return;
+ }
+ $this->parserOutput->setEditSectionTokens( false );
+ $this->parserOutput->setTOCEnabled( false );
+ $text = $this->parserOutput->getText();
+ if ( strlen( $text ) == 0 ) {
+ $this->allText = "";
+ // empty text - nothing to seek here
+ return;
+ }
+ $opening = null;
+
+ $this->openingText = $this->extractHeadingBeforeFirstHeading( $text );
+
+ // Add extra spacing around break tags so text crammed together like<br>this
+ // doesn't make one word.
+ $text = str_replace( '<br', "\n<br", $text );
+
+ $formatter = new HtmlFormatter( $text );
+
+ // Strip elements from the page that we never want in the search text.
+ $formatter->remove( $this->excludedElementSelectors );
+ $formatter->filterContent();
+
+ // Strip elements from the page that are auxiliary text. These will still be
+ // searched but matches will be ranked lower and non-auxiliary matches will be
+ // preferred in highlighting.
+ $formatter->remove( $this->auxiliaryElementSelectors );
+ $auxiliaryElements = $formatter->filterContent();
+ $this->allText = trim( Sanitizer::stripAllTags( $formatter->getText() ) );
+ foreach ( $auxiliaryElements as $auxiliaryElement ) {
+ $this->auxText[] =
+ trim( Sanitizer::stripAllTags( $formatter->getText( $auxiliaryElement ) ) );
+ }
+ }
+
+ /**
+ * Get text before first heading.
+ * @param string $text
+ * @return string|null
+ */
+ private function extractHeadingBeforeFirstHeading( $text ) {
+ $matches = [];
+ if ( !preg_match( '/<h[123456]>/', $text, $matches, PREG_OFFSET_CAPTURE ) ) {
+ // There isn't a first heading so we interpret this as the article
+ // being entirely without heading.
+ return null;
+ }
+ $text = substr( $text, 0, $matches[ 0 ][ 1 ] );
+ if ( !$text ) {
+ // There isn't any text before the first heading so we declare there isn't
+ // a first heading.
+ return null;
+ }
+
+ $formatter = new HtmlFormatter( $text );
+ $formatter->remove( $this->excludedElementSelectors );
+ $formatter->remove( $this->auxiliaryElementSelectors );
+ $formatter->filterContent();
+ $text = trim( Sanitizer::stripAllTags( $formatter->getText() ) );
+
+ if ( !$text ) {
+ // There isn't any text after filtering before the first heading so we declare
+ // that there isn't a first heading.
+ return null;
+ }
+
+ return $text;
+ }
+
+ /**
+ * Get opening text
+ * @return string
+ */
+ public function getOpeningText() {
+ $this->extractWikitextParts();
+ return $this->openingText;
+ }
+
+ /**
+ * Get main text
+ * @return string
+ */
+ public function getMainText() {
+ $this->extractWikitextParts();
+ return $this->allText;
+ }
+
+ /**
+ * Get auxiliary text
+ * @return string[]
+ */
+ public function getAuxiliaryText() {
+ $this->extractWikitextParts();
+ return $this->auxText;
+ }
+}
return $fields;
}
+ /**
+ * Extract text of the file
+ * TODO: probably should go to file handler?
+ * @param Title $title
+ * @return string|null
+ */
+ protected function getFileText( Title $title ) {
+ $file = wfLocalFile( $title );
+ if ( $file && $file->exists() ) {
+ return $file->getHandler()->getEntireText( $file );
+ }
+
+ return null;
+ }
+
+ public function getDataForSearchIndex( WikiPage $page, ParserOutput $parserOutput,
+ SearchEngine $engine ) {
+ $fields = parent::getDataForSearchIndex( $page, $parserOutput, $engine );
+
+ $structure = new WikiTextStructure( $parserOutput );
+ $fields['external_link'] = array_keys( $parserOutput->getExternalLinks() );
+ $fields['category'] = $structure->categories();
+ $fields['heading'] = $structure->headings();
+ $fields['outgoing_link'] = $structure->outgoingLinks();
+ $fields['template'] = $structure->templates();
+ // text fields
+ $fields['opening_text'] = $structure->getOpeningText();
+ $fields['text'] = $structure->getMainText(); // overwrites one from ContentHandler
+ $fields['auxiliary_text'] = $structure->getAuxiliaryText();
+
+ $title = $page->getTitle();
+ if ( NS_FILE == $title->getNamespace() ) {
+ $fileText = $this->getFileText( $title );
+ if ( $fileText ) {
+ $fields['file_text'] = $fileText;
+ }
+ }
+ return $fields;
+ }
+
}
/**
* @param Title $title
* @return CdnCacheUpdate
- * @deprecated 1.27
+ * @deprecated since 1.27
*/
public static function newSimplePurge( Title $title ) {
return new CdnCacheUpdate( $title->getCdnUrls() );
/**
* Generic operation result class for FileRepo-related operations
* @ingroup FileRepo
- * @deprecated 1.25
+ * @deprecated since 1.25
*/
class FileRepoStatus extends Status {
}
/**
* Creates a temp FS file with the same extension and the thumbnail
* @param string $thumbPath Thumbnail path
- * @return TempFSFile
+ * @return TempFSFile|null
*/
protected function makeTransformTmpFile( $thumbPath ) {
$thumbExt = FileBackend::extensionFromPath( $thumbPath );
"config-subscribe-help": "Esta é unha lista de correos de baixo volume usada para anuncios sobre lanzamentos de novas versións, incluíndo avisos de seguridade importantes.\nDebería subscribirse a ela e actualizar a súa instalación MediaWiki cando saian as novas versións.",
"config-subscribe-noemail": "Intentou subscribirse á lista de correo dos anuncios de novos lanzamentos sen proporcionar o enderezo de correo electrónico.\nDea un enderezo de correo electrónico se quere efectuar a subscrición á lista de correo.",
"config-pingback": "Compartir datos de esta instalación cos desenvolvedores de MediaWiki",
- "config-pingback-help": "Se seleccionas esta opción, MediaWiki enviará periodicamente unha mensaxe a https://www.mediawiki.org con datos básicos sobre esta instancia Mediawiki. Estos datos inclúen, por exemplo, o tipo de sistema, versión de PHP e a base de datos escollida. A Fundación Wikimedia comparte estos datos cos desenvolvedores de MediaWiki para axudar a guiar o traballo futuro de desenvolvemento.",
+ "config-pingback-help": "Se seleccionas esta opción, MediaWiki enviará periodicamente unha mensaxe a https://www.mediawiki.org con datos básicos sobre esta instancia Mediawiki. Estos datos inclúen, por exemplo, o tipo de sistema, versión de PHP e a base de datos escollida. A Fundación Wikimedia comparte estos datos cos desenvolvedores de MediaWiki para axudar a guiar o traballo futuro de desenvolvemento. Serán enviados os seguintes datos do seu sistemaː\n<pre>$1</pre>",
"config-almost-done": "Xa case rematou!\nNeste paso pode saltar o resto da configuración e instalar o wiki agora mesmo.",
"config-optional-continue": "Facédeme máis preguntas.",
"config-optional-skip": "Xa estou canso. Instalade o wiki.",
* @file
* @ingroup Media
*/
+use MediaWiki\MediaWikiServices;
/**
* Base media handler class
*/
const MAX_ERR_LOG_SIZE = 65535;
- /** @var MediaHandler[] Instance cache with array of MediaHandler */
- protected static $handlers = [];
-
/**
* Get a MediaHandler for a given MIME type from the instance cache
*
* @return MediaHandler|bool
*/
static function getHandler( $type ) {
- global $wgMediaHandlers;
- if ( !isset( $wgMediaHandlers[$type] ) ) {
- wfDebug( __METHOD__ . ": no handler found for $type.\n" );
-
- return false;
- }
- $class = $wgMediaHandlers[$type];
- if ( !isset( self::$handlers[$class] ) ) {
- self::$handlers[$class] = new $class;
- if ( !self::$handlers[$class]->isEnabled() ) {
- wfDebug( __METHOD__ . ": $class is not enabled\n" );
- self::$handlers[$class] = false;
- }
- }
-
- return self::$handlers[$class];
- }
-
- /**
- * Resets all static caches
- */
- public static function resetCache() {
- self::$handlers = [];
+ return MediaWikiServices::getInstance()
+ ->getMediaHandlerFactory()->getHandler( $type );
}
/**
--- /dev/null
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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
+ * @ingroup Media
+ */
+
+/**
+ * Class to construct MediaHandler objects
+ *
+ * @since 1.28
+ */
+class MediaHandlerFactory {
+
+ /**
+ * Default, MediaWiki core media handlers
+ *
+ * @var array
+ */
+ private static $coreHandlers = [
+ 'image/jpeg' => JpegHandler::class,
+ 'image/png' => PNGHandler::class,
+ 'image/gif' => GIFHandler::class,
+ 'image/tiff' => TiffHandler::class,
+ 'image/webp' => WebPHandler::class,
+ 'image/x-ms-bmp' => BmpHandler::class,
+ 'image/x-bmp' => BmpHandler::class,
+ 'image/x-xcf' => XCFHandler::class,
+ 'image/svg+xml' => SvgHandler::class, // official
+ 'image/svg' => SvgHandler::class, // compat
+ 'image/vnd.djvu' => DjVuHandler::class, // official
+ 'image/x.djvu' => DjVuHandler::class, // compat
+ 'image/x-djvu' => DjVuHandler::class, // compat
+ ];
+
+ /**
+ * @var array
+ */
+ private $registry;
+
+ /**
+ * Instance cache of MediaHandler objects by mimetype
+ *
+ * @var MediaHandler[]
+ */
+ private $handlers;
+
+ public function __construct( array $registry ) {
+ $this->registry = $registry + self::$coreHandlers;
+ }
+
+ protected function getHandlerClass( $type ) {
+ if ( isset( $this->registry[$type] ) ) {
+ return $this->registry[$type];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param string $type mimetype
+ * @return bool|MediaHandler
+ */
+ public function getHandler( $type ) {
+ if ( isset( $this->handlers[$type] ) ) {
+ return $this->handlers[$type];
+ }
+
+ $class = $this->getHandlerClass( $type );
+ if ( $class !== false ) {
+ /** @var MediaHandler $handler */
+ $handler = new $class;
+ if ( !$handler->isEnabled() ) {
+ wfDebug( __METHOD__ . ": $class is not enabled\n" );
+ $handler = false;
+ }
+ } else {
+ wfDebug( __METHOD__ . ": no handler found for $type.\n" );
+ $handler = false;
+ }
+
+ $this->handlers[$type] = $handler;
+ return $handler;
+ }
+}
* @param array $params [optional] Array key 'fallback' for $fallback.
* @param int|string $fallback Fallback cache, e.g. (CACHE_NONE, "hash") (since 1.24)
* @return BagOStuff
- * @deprecated 1.27
+ * @deprecated since 1.27
*/
public static function newAccelerator( $params = [], $fallback = null ) {
if ( $fallback === null ) {
: 'revision-info';
$outputPage = $context->getOutput();
- $outputPage->addSubtitle( "<div id=\"mw-{$infomsg}\">" .
+ $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
$context->msg( $infomsg, $td )
->rawParams( $userlinks )
->params( $revision->getId(), $tddate, $tdtime, $revision->getUserText() )
->rawParams( Linker::revComment( $revision, true, true ) )
->parse() .
- "</div>"
- );
+ "</div>";
$lnk = $current
? $context->msg( 'currentrevisionlink' )->escaped()
$cdel .= ' ';
}
- $outputPage->addSubtitle( "<div id=\"mw-revision-nav\">" . $cdel .
+ // the outer div is need for styling the revision info and nav in MobileFrontend
+ $outputPage->addSubtitle( "<div class=\"mw-revision\">" . $revisionInfo .
+ "<div id=\"mw-revision-nav\">" . $cdel .
$context->msg( 'revision-nav' )->rawParams(
$prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
- )->escaped() . "</div>" );
+ )->escaped() . "</div></div>" );
}
/**
*
* @since 1.19
* @param ParserOptions $parserOptions ParserOptions to use for the parse operation
- * @param null|int $oldid Revision ID to get the text from, passing null or 0 will
- * get the current revision (default value)
- *
- * @return ParserOutput|bool ParserOutput or false if the revision was not found
+ * @param null|int $oldid Revision ID to get the text from, passing null or 0 will
+ * get the current revision (default value)
+ * @param bool $forceParse Force reindexing, regardless of cache settings
+ * @return bool|ParserOutput ParserOutput or false if the revision was not found
*/
- public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
+ public function getParserOutput( ParserOptions $parserOptions, $oldid = null,
+ $forceParse = false ) {
- $useParserCache = $this->shouldCheckParserCache( $parserOptions, $oldid );
+ $useParserCache =
+ ( !$forceParse ) && $this->shouldCheckParserCache( $parserOptions, $oldid );
wfDebug( __METHOD__ .
': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
if ( $parserOptions->getStubThreshold() ) {
],
__METHOD__
);
+ // Save this so we can pass it to the ArticleDeleteComplete hook.
+ $archivedRevisionCount = $dbw->affectedRows();
// Now that it's safely backed up, delete it
$dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
$this->doDeleteUpdates( $id, $content );
Hooks::run( 'ArticleDeleteComplete',
- [ &$this, &$user, $reason, $id, $content, $logEntry ] );
+ [ &$this, &$user, $reason, $id, $content, $logEntry, $archivedRevisionCount ] );
$status->value = $logid;
// Show log excerpt on 404 pages rather than just a link
* Class for handling function-scope profiling
*
* @since 1.22
- * @deprecated 1.25 No-op now
+ * @deprecated since 1.25 No-op now
*/
class ProfileSection {
/**
/**
* Begin profiling of a function
* @param string $functionname Name of the function we will profile
- * @deprecated 1.25
+ * @deprecated since 1.25
*/
function wfProfileIn( $functionname ) {
}
/**
* Stop profiling of a function
* @param string $functionname Name of the function we have profiled
- * @deprecated 1.25
+ * @deprecated since 1.25
*/
function wfProfileOut( $functionname = 'missing' ) {
}
$this->{$member}[$key] = (array)$value;
}
break;
+ case 'deprecated':
+ $this->deprecated = $option;
+ break;
// Lists of strings
case 'dependencies':
case 'messages':
*/
public function getScript( ResourceLoaderContext $context ) {
$files = $this->getScriptFiles( $context );
- return $this->readScriptFiles( $files );
+ return $this->getDeprecationInformation() . $this->readScriptFiles( $files );
}
/**
*/
protected $config;
+ /**
+ * @var array|bool
+ */
+ protected $deprecated = false;
+
/**
* @var LoggerInterface
*/
return $wgContLang->getDir() !== $context->getDirection();
}
+ /**
+ * Get JS representing deprecation information for the current module if available
+ *
+ * @return string JavaScript code
+ */
+ protected function getDeprecationInformation() {
+ $deprecationInfo = $this->deprecated;
+ if ( $deprecationInfo ) {
+ $name = $this->getName();
+ $warning = 'This page is using the deprecated ResourceLoader module "' . $name . '".';
+ if ( !is_bool( $deprecationInfo ) && isset( $deprecationInfo['message'] ) ) {
+ $warning .= "\n" . $deprecationInfo['message'];
+ }
+ return Xml::encodeJsCall(
+ 'mw.log.warn',
+ [ $warning ]
+ );
+ } else {
+ return '';
+ }
+ }
+
/**
* Get all JS for this module for a given language and skin.
* Includes all relevant JS except loader scripts.
<?php
/**
- * ResourceLoader module for user customizations.
- *
* 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
*/
/**
- * Module for user customizations
+ * Module for user customizations scripts
*/
class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
protected $targets = [ 'desktop', 'mobile' ];
/**
- * Get list of pages used by this module
- *
* @param ResourceLoaderContext $context
* @return array List of pages
*/
$pages["$userPage/" . $context->getSkin() . '.js'] = [ 'type' => 'script' ];
}
- if ( $config->get( 'AllowUserCss' ) ) {
- $pages["$userPage/common.css"] = [ 'type' => 'style' ];
- $pages["$userPage/" . $context->getSkin() . '.css'] = [ 'type' => 'style' ];
- }
-
- $useSiteJs = $config->get( 'UseSiteJs' );
- $useSiteCss = $config->get( 'UseSiteCss' );
// User group pages are maintained site-wide and enabled with site JS/CSS.
- if ( $useSiteJs || $useSiteCss ) {
+ if ( $config->get( 'UseSiteJs' ) ) {
foreach ( $user->getEffectiveGroups() as $group ) {
if ( $group == '*' ) {
continue;
}
- if ( $useSiteJs ) {
- $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
- }
- if ( $useSiteCss ) {
- $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
- }
+ $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
}
}
- // Hack for bug 26283: if we're on a preview page for a CSS/JS page,
- // we need to exclude that page from this module. In that case, the excludepage
- // parameter will be set to the name of the page we need to exclude.
+ // Hack for T28283: Allow excluding pages for preview on a CSS/JS page.
+ // The excludepage parameter is set by OutputPage.
$excludepage = $context->getRequest()->getVal( 'excludepage' );
if ( isset( $pages[$excludepage] ) ) {
- // This works because $excludepage is generated with getPrefixedDBkey(),
- // just like the keys in $pages[] above
unset( $pages[$excludepage] );
}
public function getGroup() {
return 'user';
}
+
+ /**
+ * @return array
+ */
+ public function getDependencies( ResourceLoaderContext $context = null ) {
+ return [ 'user.styles' ];
+ }
}
--- /dev/null
+<?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
+ * @author Trevor Parscal
+ * @author Roan Kattouw
+ */
+
+/**
+ * Module for user customizations styles
+ */
+class ResourceLoaderUserStylesModule extends ResourceLoaderWikiModule {
+
+ protected $origin = self::ORIGIN_USER_INDIVIDUAL;
+ protected $targets = [ 'desktop', 'mobile' ];
+
+ /**
+ * @param ResourceLoaderContext $context
+ * @return array List of pages
+ */
+ protected function getPages( ResourceLoaderContext $context ) {
+ $config = $this->getConfig();
+ $user = $context->getUserObj();
+ if ( $user->isAnon() ) {
+ return [];
+ }
+
+ // Use localised/normalised variant to ensure $excludepage matches
+ $userPage = $user->getUserPage()->getPrefixedDBkey();
+ $pages = [];
+
+ if ( $config->get( 'AllowUserCss' ) ) {
+ $pages["$userPage/common.css"] = [ 'type' => 'style' ];
+ $pages["$userPage/" . $context->getSkin() . '.css'] = [ 'type' => 'style' ];
+ }
+
+ // User group pages are maintained site-wide and enabled with site JS/CSS.
+ if ( $config->get( 'UseSiteCss' ) ) {
+ foreach ( $user->getEffectiveGroups() as $group ) {
+ if ( $group == '*' ) {
+ continue;
+ }
+ $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
+ }
+ }
+
+ // Hack for T28283: Allow excluding pages for preview on a CSS/JS page.
+ // The excludepage parameter is set by OutputPage.
+ $excludepage = $context->getRequest()->getVal( 'excludepage' );
+ if ( isset( $pages[$excludepage] ) ) {
+ unset( $pages[$excludepage] );
+ }
+
+ return $pages;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType() {
+ return self::LOAD_STYLES;
+ }
+
+ /**
+ * Get group name
+ *
+ * @return string
+ */
+ public function getGroup() {
+ return 'user';
+ }
+}
* Create a search field definition.
* Specific search engines should override this method to create search fields.
* @param string $name
- * @param int $type
+ * @param int $type One of the types in SearchIndexField::INDEX_TYPE_*
* @return SearchIndexField
* @since 1.28
*/
* @note This does not return an instance of SiteSQLStore!
*
* @since 1.21
- * @deprecated 1.27 use MediaWikiServices::getSiteStore() or MediaWikiServices::getSiteLookup()
- * instead.
+ * @deprecated since 1.27 use MediaWikiServices::getSiteStore()
+ * or MediaWikiServices::getSiteLookup() instead.
*
* @param null $sitesTable IGNORED
* @param null $cache IGNORED
return $result;
}
- /** @deprecated in 1.21 */
- public function commentBlock( $comment, $title = null, $local = false, $wikiId = null ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::commentBlock( $comment, $title, $local, $wikiId );
- }
-
- /** @deprecated in 1.21 */
- public function generateRollback(
- $rev,
- IContextSource $context = null,
- $options = [ 'verify' ]
- ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::generateRollback( $rev, $context, $options );
- }
-
- /** @deprecated in 1.21 */
- public function link( $target, $html = null, $customAttribs = [], $query = [], $options = [] ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::link( $target, $html, $customAttribs, $query, $options );
- }
-
- /** @deprecated in 1.21 */
- public function linkKnown(
- $target,
- $html = null,
- $customAttribs = [],
- $query = [],
- $options = [ 'known', 'noclasses' ]
- ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::linkKnown( $target, $html, $customAttribs, $query, $options );
- }
-
- /** @deprecated in 1.21 */
- public function userLink( $userId, $userName, $altUserName = false ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::userLink( $userId, $userName, $altUserName );
- }
-
- /** @deprecated in 1.21 */
- public function userToolLinks(
- $userId,
- $userText,
- $redContribsWhenNoEdits = false,
- $flags = 0,
- $edits = null
- ) {
- wfDeprecated( __METHOD__, '1.21' );
- return Linker::userToolLinks( $userId, $userText, $redContribsWhenNoEdits, $flags, $edits );
- }
-
}
* Let users reset tokens like the watchlist token.
*
* @ingroup SpecialPage
- * @deprecated 1.26
+ * @deprecated since 1.26
*/
class SpecialResetTokens extends FormSpecialPage {
private $tokensList;
* @param string $message HTML message to be passed to mainUploadForm
*/
protected function showRecoverableUploadError( $message ) {
- $sessionKey = $this->mUpload->stashSession();
+ $sessionKey = $this->mUpload->stashFile()->getFileKey();
$message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . "</h2>\n" .
'<div class="error">' . $message . "</div>\n";
return false;
}
- $sessionKey = $this->mUpload->stashSession();
+ $sessionKey = $this->mUpload->stashFile()->getFileKey();
// Add styles for the warning, reused from the live preview
$this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
* @return UploadStashFile Stashed file
*/
public function stashFile( User $user = null ) {
- // was stashSessionFile
-
$stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $user );
$file = $stash->stashFile( $this->mTempPath, $this->getSourceType() );
$this->mLocalFile = $file;
* Stash a file in a temporary directory, returning a key which can be used
* to find the file again. See stashFile().
*
+ * @deprecated since 1.28
* @return string File key
*/
public function stashFileGetKey() {
+ wfDeprecated( __METHOD__, '1.28' );
return $this->stashFile()->getFileKey();
}
/**
* alias for stashFileGetKey, for backwards compatibility
*
+ * @deprecated since 1.28
* @return string File key
*/
public function stashSession() {
- return $this->stashFileGetKey();
+ wfDeprecated( __METHOD__, '1.28' );
+ return $this->stashFile()->getFileKey();
}
/**
return $this->mLocalFile;
}
- /**
- * This should return the key instead of the UploadStashFile instance, for backward compatibility.
- * @return string
- */
- public function stashSession() {
- return $this->stashFile()->getFileKey();
- }
-
/**
* Remove a temporarily kept file stashed by saveTempUploadedFile().
* @return bool Success
* @return string|bool User's current value for the option, or false if this option is disabled.
* @see resetTokenFromOption()
* @see getOption()
- * @deprecated 1.26 Applications should use the OAuth extension
+ * @deprecated since 1.26 Applications should use the OAuth extension
*/
public function getTokenFromOption( $oname ) {
global $wgHiddenPrefs;
* $gen->generateAutoload();
*/
class AutoloadGenerator {
+ const FILETYPE_JSON = 'json';
+ const FILETYPE_PHP = 'php';
+
/**
* @var string Root path of the project being scanned for classes
*/
* Updates the AutoloadClasses field at the given
* filename.
*
- * @param {string} $filename Filename of JSON
+ * @param string $filename Filename of JSON
* extension/skin registration file
+ * @return string Updated Json of the file given as the $filename parameter
*/
protected function generateJsonAutoload( $filename ) {
- require_once __DIR__ . '/../../includes/json/FormatJson.php';
$key = 'AutoloadClasses';
$json = FormatJson::decode( file_get_contents( $filename ), true );
unset( $json[$key] );
// Sorting the list of autoload classes.
ksort( $json[$key] );
- // Update file, using constants for the required
- // formatting.
- file_put_contents( $filename,
- FormatJson::encode( $json, true ) . "\n" );
+ // Return the whole JSON file
+ return FormatJson::encode( $json, true ) . "\n";
}
/**
}
$output = implode( "\n\t", $content );
- file_put_contents(
- $filename,
+ return
<<<EOD
<?php
// This file is generated by $commandName, do not adjust manually
{$output}
];
-EOD
- );
+EOD;
}
/**
- * Write out all known classes to autoload.php, extension.json, or skin.json in
- * the provided basedir
+ * Returns all known classes as a string, which can be used to put into a target
+ * file (e.g. extension.json, skin.json or autoload.php)
*
* @param string $commandName Value used in file comment to direct
* developers towards the appropriate way to update the autoload.
+ * @return string
*/
- public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+ public function getAutoload( $commandName = 'AutoloadGenerator' ) {
// We need to check whether an extenson.json or skin.json exists or not, and
// incase it doesn't, update the autoload.php file.
- $jsonFilename = null;
- if ( file_exists( $this->basepath . "/extension.json" ) ) {
- $jsonFilename = $this->basepath . "/extension.json";
- } elseif ( file_exists( $this->basepath . "/skin.json" ) ) {
- $jsonFilename = $this->basepath . "/skin.json";
- }
+ $fileinfo = $this->getTargetFileinfo();
- if ( $jsonFilename !== null ) {
- $this->generateJsonAutoload( $jsonFilename );
+ if ( $fileinfo['type'] === AutoloadGenerator::FILETYPE_JSON ) {
+ return $this->generateJsonAutoload( $fileinfo['filename'] );
} else {
- $this->generatePHPAutoload( $commandName, $this->basepath . '/autoload.php' );
+ return $this->generatePHPAutoload( $commandName, $fileinfo['filename'] );
+ }
+ }
+
+ /**
+ * Returns the filename of the extension.json of skin.json, if there's any, or
+ * otherwise the path to the autoload.php file in an array as the "filename"
+ * key and with the type (AutoloadGenerator::FILETYPE_JSON or AutoloadGenerator::FILETYPE_PHP)
+ * of the file as the "type" key.
+ *
+ * @return array
+ */
+ public function getTargetFileinfo() {
+ $fileinfo = [
+ 'filename' => $this->basepath . '/autoload.php',
+ 'type' => AutoloadGenerator::FILETYPE_PHP
+ ];
+ if ( file_exists( $this->basepath . '/extension.json' ) ) {
+ $fileinfo = [
+ 'filename' => $this->basepath . '/extension.json',
+ 'type' => AutoloadGenerator::FILETYPE_JSON
+ ];
+ } elseif ( file_exists( $this->basepath . '/skin.json' ) ) {
+ $fileinfo = [
+ 'filename' => $this->basepath . '/skin.json',
+ 'type' => AutoloadGenerator::FILETYPE_JSON
+ ];
}
+
+ return $fileinfo;
}
+
/**
* Ensure that Unix-style path separators ("/") are used in the path.
*
protected static function normalizePathSeparator( $path ) {
return str_replace( '\\', '/', $path );
}
+
+ /**
+ * Initialize the source files and directories which are used for the MediaWiki default
+ * autoloader in {mw-base-dir}/autoload.php including:
+ * * includes/
+ * * languages/
+ * * maintenance/
+ * * mw-config/
+ * * /*.php
+ */
+ public function initMediaWikiDefault() {
+ foreach ( [ 'includes', 'languages', 'maintenance', 'mw-config' ] as $dir ) {
+ $this->readDir( $this->basepath . '/' . $dir );
+ }
+ foreach ( glob( $this->basepath . '/*.php' ) as $file ) {
+ $this->readFile( $file );
+ }
+ }
}
/**
"Jdforrester",
"Alaa",
"Izoozo",
- "علاء"
+ "علاء",
+ "Hhaboh162002"
]
},
"tog-underline": "سطر تحت الوصلات:",
"savearticle": "احفظ الصفحة",
"savechanges": "احفظ التغييرات",
"publishpage": "نشر الصفحة",
- "publishchanges": "انشر التغييرات",
+ "publishchanges": "نشر التغييرات",
"preview": "عرض مسبق",
"showpreview": "أظهر معاينة",
"showdiff": "عرض التغييرات",
"whatlinkshere-prev": "{{PLURAL:$1|السابق|ال$1 السابقة}}",
"whatlinkshere-next": "{{PLURAL:$1|التالية|ال$1 التالية}}",
"whatlinkshere-links": "وصلات",
- "whatlinkshere-hideredirs": "$1 اÙ\84تØÙ\88Ù\8aÙ\84ات",
- "whatlinkshere-hidetrans": "$1 اÙ\84تضÙ\85Ù\8aÙ\86ات",
- "whatlinkshere-hidelinks": "$1 الوصلات",
+ "whatlinkshere-hideredirs": "$1 تحويلات",
+ "whatlinkshere-hidetrans": "$1 تضمينات",
+ "whatlinkshere-hidelinks": "$1 وصلات",
"whatlinkshere-hideimages": "$1 وصلات الملفات",
"whatlinkshere-filters": "مرشحات",
"whatlinkshere-submit": "اذهب",
"action-applychangetags": "дадаваньне метак пры рэдагаваньні",
"action-changetags": "дадаваньне і выдаленьне адвольных метак да асобных вэрсіяў і запісаў у журнале падзеяў",
"action-deletechangetags": "выдаленьне метак з базы зьвестак",
+ "action-purge": "ачыстку кэшу гэтай старонкі",
"nchanges": "$1 {{PLURAL:$1|зьмена|зьмены|зьменаў}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|з апошняга візыту}}",
"enhancedrc-history": "гісторыя",
"randomrootpage": "Выпадковая карэнная старонка",
"log-action-filter-block": "Тып блякаваньня:",
"log-action-filter-delete": "Тып выдаленьня:",
+ "log-action-filter-import": "Тып імпарту:",
"changecredentials": "Зьмена ўліковых зьвестак",
"removecredentials": "Выдаленьне ўліковых зьвестак",
"removecredentials-submit": "Выдаліць уліковыя зьвесткі",
"action-applychangetags": "přidávat značky k vlastním změnám",
"action-changetags": "přidávat libovolné značky na jednotlivé revize a protokolovací záznamy a odebírat je",
"action-deletechangetags": "mazat značky z databáze",
+ "action-purge": "vyčistit vyrovnávací paměť této stránky",
"nchanges": "$1 {{PLURAL:$1|změna|změny|změn}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od poslední návštěvy}}",
"enhancedrc-history": "historie",
"april": "Nisane",
"may_long": "Gulane",
"june": "Heziran",
- "july": "Temuz",
+ "july": "Temuze",
"august": "Tebaxe",
"september": "Keşkelun",
- "october": "Cetan",
- "november": "Kelverdan",
+ "october": "Tışrino Verên",
+ "november": "Tışrino Peyên",
"december": "Kanun",
"january-gen": "Çele",
"february-gen": "Sıbate",
"morenotlisted": "Vêşi lista nêbi...",
"mypage": "Pele",
"mytalk": "Mesac",
- "anontalk": "Vatenayış",
+ "anontalk": "Werênayış",
"navigation": "Pusula",
"and": " u",
"qbfind": "Bıvêne",
"history": "Tarixê pele",
"history_short": "Tarix",
"updatedmarker": "cıkewtena mına peyêne ra dıme biyo rocane",
- "printableversion": "Versiyonê nusterin",
+ "printableversion": "Asayışê çapkerdışi",
"permalink": "Gıreyo daimi",
"print": "Çap ke",
"view": "Bıvêne",
"copyright": "Zerrekacı $1 bındı not biya.",
"copyrightpage": "{{ns:project}}:Heqa telifi",
"currentevents": "Hediseyê rocaneyi",
- "currentevents-url": "Project:Rocani hadisey",
+ "currentevents-url": "Project:Hediseyê rocaneyi",
"disclaimers": "Redê mesuliyeti",
"disclaimerpage": "Project:Reddê mesuliyetê bıngey",
"edithelp": "Peştdariya vurnayışi",
"policy-url": "Project:Terzê hereketi",
"portal": "Portalê cemaeti",
"portal-url": "Project:Portalê cemaeti",
- "privacy": "Politikay Nımnayışi",
- "privacypage": "Project:Xısusiyetê nımtışi",
+ "privacy": "Politikaya nımıteyiye",
+ "privacypage": "Project:Xısusiyetê nımıtışi",
"badaccess": "Xeta mısadey",
"badaccess-group0": "Heqa şıma çıniya, karo ke şıma waşt, bıkerê.",
"badaccess-groups": "No fealiyeto ke şıma waşt, tenya karberanê {{PLURAL:$2|grubi|gruban ra yewi}} rê akerdeyo: $1.",
"categoriesfrom": "Kategoriyê ke be ninan dest pêkenê, bımocne:",
"deletedcontributions": "İştırakê karberi esterdi",
"deletedcontributions-title": "İştırakê karberi esterdi",
- "sp-deletedcontributions-contribs": "iştıraqi",
+ "sp-deletedcontributions-contribs": "iştiraki",
"linksearch": "Gıreyê teberi cı geyrê",
"linksearch-pat": "bıgêr motif:",
"linksearch-ns": "Heruna nameyi:",
"blanknamespace": "(Ser)",
"contributions": "İştiraqê {{GENDER:$1|karber}}i",
"contributions-title": "Dekerdenê karber de $1",
- "mycontris": "İştıraqi",
- "anoncontribs": "İştıraqi",
+ "mycontris": "İştıraki",
+ "anoncontribs": "İştıraki",
"contribsub2": "Qandê {{GENDER:$3|$1}} ($2)",
"contributions-userdoesnotexist": "Hesabê karberi \"$1\" qeyd nêbiyo.",
"nocontribs": "Ena kriteriya de vurnayîş çini yo.",
"sp-contributions-deleted": "iştırakê karberi esterdi",
"sp-contributions-uploads": "barkerdey",
"sp-contributions-logs": "qeydi",
- "sp-contributions-talk": "Vacenayış",
+ "sp-contributions-talk": "werênayış",
"sp-contributions-userrights": "idareyê heqanê karberan",
"sp-contributions-blocked-notice": "verniyê no/na karber/e geriyayo/a\nqê referansi qeydê vernigrewtışi cêr de eşkera biyo:",
"sp-contributions-blocked-notice-anon": "Eno adresê IPi bloke biyo.\nCıkewtışo tewr peyêno ke bloke biyo, cêr seba referansi belikerdeyo:",
"ipb-unblock-addr": "$1 a bik",
"ipb-unblock": "Yew adresê IPî ya zi nameyê karberî blok bike",
"ipb-blocklist": "Blokî ke hama estê ey bivîne",
- "ipb-blocklist-contribs": "Qandê {{GENDER:$1|}} ra iştıraqi",
+ "ipb-blocklist-contribs": "İştirakê {{GENDER:$1|$1}}`i",
"ipb-blocklist-duration-left": "$1 vet",
"unblockip": "Hesabê karberî a bike",
"unblockiptext": "Cıreştışê nuştışê IP ya zi karberio ke ver ra gêriyayo, seba peyser barkerdışi dey rê formê cêrêni bıgurenên.",
"blocklink": "kılit ke",
"unblocklink": "bloki wedare",
"change-blocklink": "kılitkerdışi bıvurne",
- "contribslink": "iştıraqi",
+ "contribslink": "iştıraki",
"emaillink": "e-poste bırışe",
"autoblocker": "Şıma otomatikmen kılit biy, çıke adresa şımaya ''IP''y terefê \"[[User:$1|$1]]\" gureniyena.\nSebebê kılitbiyayışê $1'i \"$2\"o",
"blocklogpage": "Qeydê astengi",
"tooltip-n-portal": "Heqa proceyi de, çı şenay bıkerê, çı koti vêniyeno",
"tooltip-n-currentevents": "Vurnayışanê peyênan de melumatê pey bıvêne",
"tooltip-n-recentchanges": "Wiki de lista vurnayışanê peyênan",
- "tooltip-n-randompage": "Perake raşt amé",
+ "tooltip-n-randompage": "Pelê da raştameyiye bar ke",
"tooltip-n-help": "Cayê peştigırewtışi",
"tooltip-t-whatlinkshere": "Lista pelanê wikiya pêroina ke tiya gırê bena",
"tooltip-t-recentchangeslinked": "Vurnayışê peyênê pelanê ke ena pela ra gırê biyê",
"logdelete-selected": "{{PLURAL:$1|Événement d'historique sélectionné|Événements d'historique sélectionnés}} :",
"revdelete-text-text": "Les révisions supprimées continueront à apparaître dans l’historique de la page, mais une partie de leur contenu sera inaccessible au public.",
"revdelete-text-file": "Les versions de fichier supprimées continueront à apparaître dans l’historique des fichiers, mais une partie de leur contenu sera indisponible au public.",
- "logdelete-text": "Les évènements du journal supprimés continueront à apparaître dans les journaux, mais une partie de leur contenu sera indisponible au public.",
+ "logdelete-text": "Les évènements supprimés du journal continueront à apparaître dans les journaux, mais une partie de leur contenu sera indisponible au public.",
"revdelete-text-others": "Les autres administrateurs seront toujours en mesure d'accéder au contenu caché et le restaurer, à moins que des restrictions supplémentaires soient fixées.",
"revdelete-confirm": "Confirmez que vous voulez effectuer cette action, que vous en comprenez les conséquences, et que vous le faites en accord avec [[{{MediaWiki:Policy-url}}|les règles]].",
"revdelete-suppress-text": "La suppression ne doit être utilisée <strong>que</strong> dans les cas suivants :\n* informations potentiellement diffamatoires\n* informations personnelles inappropriées\n*: <em>adresse, numéro de téléphone, numéro de sécurité sociale, …</em>",
"revdelete-radio-same": "(ne pas changer)",
"revdelete-radio-set": "Masqué",
"revdelete-radio-unset": "Visible",
- "revdelete-suppress": "Masquer également les données pour les administrateurs",
+ "revdelete-suppress": "Supprimer également les données des administrateurs",
"revdelete-unsuppress": "Enlever les restrictions sur les versions restaurées",
"revdelete-log": "Motif :",
"revdelete-submit": "Appliquer {{PLURAL:$1|à la révision sélectionnée|aux révisions sélectionnées}}",
"revdelete-no-change": "'''Attention :''' L'élément daté du $1 à $2 a déjà les paramètres de visibilité demandés.",
"revdelete-concurrent-change": "Erreur lors de la modification de l'élément daté du $1 à $2 : son statut a été changé par quelqu'un d'autre pendant que vous le modifiez.\nVérifiez les journaux.",
"revdelete-only-restricted": "Erreur lors de la suppression de l'entrée datée du $1 à $2 : vous ne pouvez pas supprimer ces éléments aux administrateurs sans également sélectionner les autres options de suppression.",
- "revdelete-reason-dropdown": "* Raisons courantes de suppression :\n** Violation des droits d'auteurs ;\n** Commentaires ou renseignements personnels inappropriés ;\n** Informations potentiellement diffamatoires.",
+ "revdelete-reason-dropdown": "* Raisons courantes de suppression \n** Violation des droits d'auteurs \n** Commentaires ou renseignements personnels inappropriés \n** Nom d'utilisateur inapproprié\n** Informations potentiellement diffamatoires",
"revdelete-otherreason": "Autre raison / raison supplémentaire :",
"revdelete-reasonotherlist": "Autre raison",
"revdelete-edit-reasonlist": "Modifier les motifs fréquents de suppression",
"prefs-editwatchlist-clear": "Effacer la liste de suivi",
"prefs-watchlist-days": "Nombre de jours à afficher dans la liste de suivi :",
"prefs-watchlist-days-max": "(maximum $1 jour{{PLURAL:$1||s}})",
- "prefs-watchlist-edits": "Nombre de modifications à afficher dans la liste de suivi étendue :",
+ "prefs-watchlist-edits": "Nombre maximum de modifications à afficher dans la liste de suivi étendue :",
"prefs-watchlist-edits-max": "Nombre maximum : 1000",
"prefs-watchlist-token": "Jeton pour la liste de suivi :",
"prefs-misc": "Préférences diverses",
"action-applychangetags": "appliquer les balises avec vos modifications",
"action-changetags": "ajouter et supprimer de façon arbitraire des balises sur des révisions individuelles et des entrées de journal",
"action-deletechangetags": "supprimer des balises de la base de données",
+ "action-purge": "purger cette page",
"nchanges": "$1 modification{{PLURAL:$1||s}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|depuis la dernière visite}}",
"enhancedrc-history": "historique",
"action-applychangetags": "aplicar etiquetas xunto cos cambios",
"action-changetags": "engadir e quitar etiquetas arbitrarias a revisións individuais e entradas do rexistro",
"action-deletechangetags": "borrar etiquetas da base de datos",
+ "action-purge": "purgar esta páxina",
"nchanges": "$1 {{PLURAL:$1|modificación|modificacións}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
"enhancedrc-history": "historial",
"notvisiblerev": "A revisión foi borrada",
"watchlist-details": "Hai {{PLURAL:$1|unha páxina|$1 páxinas}} na súa lista de vixilancia, sen contar as de conversa.",
"wlheader-enotif": "A notificación por correo electrónico está activada.",
- "wlheader-showupdated": "As páxinas que cambiaron desde a súa última visita móstranse en '''negra'''.",
+ "wlheader-showupdated": "As páxinas que cambiaron desde a súa última visita móstranse en <strong>letra grosa</strong>.",
"wlnote": "A continuación {{PLURAL:$1|está a última modificación|están as últimas <strong>$1</strong> modificacións}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} ata o $3 ás $4.",
"wlshowlast": "Mostrar as últimas $1 horas e os últimos $2 días",
"watchlist-hide": "Agochar",
"right-reupload-own": "העלאת גרסאות חדשות של קבצים קיימים שהועלו על־ידי המשתמש עצמו",
"right-reupload-shared": "דריסה מקומית של קבצים מאתר קובצי המדיה המשותף",
"right-upload_by_url": "העלאת קבצים מכתובת אינטרנט (URL)",
- "right-purge": "×¨×¢× ×\95×\9f ×\96×\99×\9bר×\95×\9f ×\94×\9e×\98×\9e×\95×\9f ש×\9c ×\94×\90תר ללא מעבר בדף אישור",
+ "right-purge": "× ×\99ק×\95×\99 ×\96×\99×\9bר×\95×\9f ×\94×\9e×\98×\9e×\95×\9f ש×\9c ×\93×£ ללא מעבר בדף אישור",
"right-autoconfirmed": "עקיפת ההגבלה על קצב הפעולות שניתן לבצע מכתובת IP מסוימת",
"right-bot": "התייחסות לעריכות כאוטומטיות",
"right-nominornewtalk": "ביטול שליחת התראה על הודעה חדשה למשתמש בעת עריכה משנית בדף השיחה שלו",
"action-applychangetags": "להחיל תגיות יחד עם שינויים",
"action-changetags": "להוסיף או להסיר תגיות מגרסאות ומרשומות יומן",
"action-deletechangetags": "למחוק תגיות מבסיס הנתונים",
+ "action-purge": "לנקות את זיכרון המטמון של דף זה",
"nchanges": "{{PLURAL:$1|שינוי אחד|$1 שינויים}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|מאז ביקורך האחרון}}",
"enhancedrc-history": "היסטוריה",
"blanknamespace": "(Ser)",
"contributions": "İştıraqê {{GENDER:$1|karber}}i",
"contributions-title": "$1 de iştırakê karberi",
- "mycontris": "İştıraqi",
+ "mycontris": "İştıraki",
"contribsub2": "Serba $1 ($2)",
"uctop": "(rocane)",
"month": "Asme ra (u ravêr):",
"blocklink": "kilıt ke",
"unblocklink": "ra ke",
"change-blocklink": "mani bıvurne",
- "contribslink": "iştıraqi",
+ "contribslink": "iştıraki",
"emaillink": "e-poste bırusne",
"autoblocker": "Sıma otomatikmen kılit biy, çıke adresa sımawa ''IP''y terefê \"[[User:$1|$1]]\" gurenina.\nSebebê kılitbiyaena $1'i \"$2\"o",
"blocklogpage": "Protokolê kilıti",
"right-applychangetags": "자신이 편집할 때 [[Special:Tags|태그]]를 적용하기",
"right-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 [[Special:Tags|태그]]를 추가하거나 제거하기",
"right-deletechangetags": "데이터베이스에서 [[Special:Tags|태그]]를 지우기",
- "grant-generic": "\"$1\" ê¶\8cí\95\9c ë²\88ë\93¤",
+ "grant-generic": "\"$1\" ê¶\8cí\95\9c 묶ì\9d\8c",
"grant-group-page-interaction": "문서로 상호 작용",
"grant-group-file-interaction": "미디어로 상호 작용",
"grant-group-watchlist-interaction": "당신의 주시문서로 상호작용",
"action-viewmyprivateinfo": "Är privat Informatioune kucken",
"action-editmyprivateinfo": "Är privat Informatiounen änneren",
"action-editcontentmodel": "de Modell vum Inhalt vun enger Säit änneren",
+ "action-purge": "dës Säit eidelzemaachen",
"nchanges": "$1 {{PLURAL:$1|Ännerung|Ännerungen}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|zanter dem leschte Passage}}",
"enhancedrc-history": "Versiounen",
"tog-watchdefault": "Pridėti puslapius, kuriuos aš redaguoju, į stebimų sąrašą",
"tog-watchmoves": "Pridėti puslapius, kuriuos aš perkeliu, į stebimų sąrašą",
"tog-watchdeletion": "Pridėti puslapius, kuriuos aš ištrinu, į stebimų sąrašą",
+ "tog-watchuploads": "Pridėti naujus failus, kurios aš įkeliu, į mano stebimųjų sąrašą",
"tog-watchrollback": "Pridėti puslapius, kuriuose aš atlikau atmetimus į mano stebėjimo sąrašą",
"tog-minordefault": "Pagal nutylėjimą pažymėti redagavimus kaip smulkius",
"tog-previewontop": "Rodyti peržiūrą virš redagavimo lauko",
"userlogin-resetpassword-link": "Pamiršote savo slaptažodį?",
"userlogin-helplink2": "Padėti prisijungti",
"userlogin-loggedin": "Jūs jau prisijungęs kaip {{GENDER:$1|$1}}.\nNaudokite žemiau pateiktą pavidalą, kad prisijungtumėte kaip kitas naudotojas.",
+ "userlogin-reauth": "Turite vėl prisijungti patvirtinimui, kad esate {{GENDER:$1|$1}}.",
"userlogin-createanother": "Sukurti kitą paskyrą",
"createacct-emailrequired": "Elektroninio pašto adresas",
"createacct-emailoptional": "Elektroninio pašto adresas (neprivaloma)",
"createacct-email-ph": "Įveskite savo elektroninio pašto adresą",
"createacct-another-email-ph": "Įveskite elektroninio pašto adresą",
"createaccountmail": "Naudokite laikiną atsitiktinį slaptažodį ir nusiųskite jį į elektroninį paštą, nurodytą žemiau.",
+ "createaccountmail-help": "Gali būti naudojamas paskyros sukūrimui kitam asmeniui, neatskleidžiant slaptažodžio.",
"createacct-realname": "Vardas (neprivaloma)",
"createaccountreason": "Priežastis:",
"createacct-reason": "Priežastis",
"createacct-reason-ph": "Kodėl kuriate kitą paskyrą",
+ "createacct-reason-help": "Pranešimas rodomas paskyros sukūrimo žurnale",
"createacct-submit": "Sukurkite savo paskyrą",
"createacct-another-submit": "Sukurti paskyrą",
"createacct-continue-submit": "Tęsti paskyros kūrimą",
"nocookiesnew": "Naudotojo paskyra buvo sukurta, bet jūs nesate prisijungęs. {{SITENAME}} naudoja slapukus, kad prijungtų naudotojus. Jūs esate išjungę slapukus. Prašome įjungti juos, tada prisijunkite su savo naujuoju naudotojo vardu ir slaptažodžiu.",
"nocookieslogin": "{{SITENAME}} naudoja slapukus, kad prijungtų naudotojus. Jūs esate išjungę slapukus. Prašome įjungti juos ir pamėginkite vėl.",
"nocookiesfornew": "Paskyra nebuvo sukurta, nes mums nepavyko nustatyti jos šaltinio.\nĮsitikinkite, kad įjungti slapukai (angl. cookies) ir tada bandykite dar kartą.",
+ "createacct-loginerror": "Paskyra buvo sėkmingai sukurta, bet nepavyko jūsų automatiškai prijungti. Prašome tęsti [[Special:UserLogin|prisijungiant rankiniu būdu]].",
"noname": "Jūs nesate nurodęs teisingo naudotojo vardo.",
"loginsuccesstitle": "Sėkmingai prisijungėte",
"loginsuccess": "'''Dabar jūs prisijungęs prie {{SITENAME}} kaip „$1“.'''",
"noemail": "Nėra jokio el. pašto adreso įvesto naudotojui „$1“.",
"noemailcreate": "Jūs turite nurodyti veikiantį el. pašto adresą",
"passwordsent": "Naujas slaptažodis buvo nusiųstas į el. pašto adresą,\nužregistruotą naudotojo „$1“.\nPrašome prisijungti vėl, kai jūs jį gausite.",
- "blocked-mailpassword": "Jūsų IP adresas yra užblokuotas nuo redagavimo, taigi neleidžiama naudoti slaptažodžio priminimo funkcijos, kad apsisaugotume nuo piktnaudžiavimo.",
+ "blocked-mailpassword": "Jūsų IP adresas yra užblokuotas nuo redagavimo. Kad užkirstume kelią piktnaudžiavimui neleidžiama naudoti slaptažodžio priminimo funkcijos iš šio IP adreso.",
"eauthentsent": "Patvirtinimo laiškas buvo nusiųstas į paskirtąjį el. pašto adresą.\nPrieš išsiunčiant kitą laišką į jūsų dėžutę, jūs turite vykdyti nurodymus laiške, kad patvirtintumėte, kad dėžutė tikrai yra jūsų.",
"throttled-mailpassword": "Slaptažodžio priminimas jau buvo išsiųstas, per {{PLURAL:$1|$1 paskutinę valandą|$1 paskutines valandas|$1 paskutinių valandų}}.\n\nNorint apsisaugoti nuo piktnaudžiavimo, slaptažodžio priminimas gali būti išsiųstas tik kas {{PLURAL:$1|$1 valandą|$1 valandas|$1 valandų}}.",
"mailerror": "Klaida siunčiant laišką: $1",
"createaccount-title": "{{SITENAME}} paskyros kūrimas",
"createaccount-text": "Projekte {{SITENAME}} ($4) kažkas sukūrė paskyrą „$2“ su slaptažodžiu „$3“ panaudodamas jūsų el. pašto adresą.\nJūs turėtumėte prisijungti ir pasikeisti savo slaptažodį.\n\nJūs galite nekreipti dėmesio į laišką, jei ši paskyra buvo sukurta per klaidą.",
"login-throttled": "Jūs pernelyg daug kartų bandėte prisijungti.\nPalaukite $1 prieš bandant vėl.",
- "login-abort-generic": "Jūsų prisijungimas buvo nesėkmingas - Nutraukta",
+ "login-abort-generic": "Jūsų prisijungimas nepavyko - Nutraukta",
"login-migrated-generic": "Jūsų paskyra buvo perkelta ir jūsų naudotojo vardo šioje wiki daugiau nebėra.",
"loginlanguagelabel": "Kalba: $1",
"suspicious-userlogout": "Jūsų prašymas atsijungti buvo atmestas, nes, atrodo, jį klaidingai išsiuntė naršyklė arba spartinantysis tarpinis serveris.",
"resetpass-no-info": "Jūs turite būti prisijungęs, kad pasiektumėte puslapį tiesiogiai.",
"resetpass-submit-loggedin": "Keisti slaptažodį",
"resetpass-submit-cancel": "Atšaukti",
- "resetpass-wrong-oldpass": "Klaidingas laikinas ar esamas slaptažodis.\nJūs galbūt jau sėkmingai pakeitėte savo slaptažodį ar gavote naują laikiną slaptažodį.",
+ "resetpass-wrong-oldpass": "Klaidingas laikinas ar esamas slaptažodis.\nJūs galbūt jau sėkmingai pakeitėte savo slaptažodį ar jau prašėte naujo laikino slaptažodžio.",
"resetpass-recycled": "Atkurkite savo slaptažodį kitokiu, nei buvo prieš tai.",
"resetpass-temp-emailed": "Jūs prisijungęs laikinu slaptažodžiu, gautu per elektroninį paštą. Kad baigtumėte jungtis, čia turite nustatyti naują slaptažodį:",
"resetpass-temp-password": "Laikinas slaptažodis:",
"passwordreset-emailsentusername": "Jeigu buvo el. paštas susietas su šiuo naudotojo vardu, tai slaptažodžio atkūrimo el. laiškas bus išsiųstas.",
"passwordreset-emailsent-capture": "Slaptažodžio priminimo laiškas bus išsiųstas, toks koks parodytas.",
"passwordreset-emailerror-capture": "Priminimo elektroninis laiškas buvo sukurtas, toks, koks parodytas žemiau, bet pasiuntimas naudotojui buvo nesėkmingas: $1",
+ "passwordreset-emailsent-capture2": "Slaptažodžio keitimo {{PLURAL:$1|el. laiškas buvo išsiųstas|el. laiškai buvo išsiųsti}}. {{PLURAL:$1|vartotojo vardas ir slaptažodis rodomi|vartotojų vardų ir slaptažodžių sąrašas rodomas}} žemiau.",
+ "passwordreset-emailerror-capture2": "El. laiško siuntimas {{GENDER:$2|vartotojui}} nepavyko: $1 {{PLURAL:$3|vartotojo vardas ir slaptažodis rodomi|vartotojų vardų ir slaptažodžių sąrašas rodomas}} žemiau.",
+ "passwordreset-nocaller": "Skambinantysis turi būti nurodytas",
+ "passwordreset-nosuchcaller": "Skambinantysis neegzistuoja: $1",
"passwordreset-invalideamil": "Neteisingas el. pašto adresas",
"passwordreset-nodata": "Vartotojo vardas ir el. paštas buvo nepateikti",
"changeemail": "Pakeisti ar pašalinti el. pašto adresą",
"authprovider-confirmlink-ok-help": "Tęsti po susiejimo klaidos žinutės parodymo.",
"authprovider-resetpass-skip-label": "Praleisti",
"authprovider-resetpass-skip-help": "Praleisti slaptažodžio perstatymą.",
- "specialpage-securitylevel-not-allowed-title": "Neleidžiama"
+ "specialpage-securitylevel-not-allowed-title": "Neleidžiama",
+ "cannotauth-not-allowed-title": "Teisė nesuteikta",
+ "cannotauth-not-allowed": "Jūs negalite naudotis šiuo puslapiu",
+ "linkaccounts": "Susieti paskyras",
+ "linkaccounts-success-text": "Paskyra buvo susieta.",
+ "linkaccounts-submit": "Susieti paskyras",
+ "unlinkaccounts": "Atsieti paskyras",
+ "unlinkaccounts-success": "Paskyra buvo atsieta."
}
"minoredit": "Marcar como edição menor",
"watchthis": "Vigiar esta página",
"savearticle": "Salvar página",
+ "publishpage": "Publicar página",
+ "publishchanges": "Publicar alterações",
"preview": "Pré-visualização",
"showpreview": "Mostrar previsão",
"showdiff": "Mostrar alterações",
"action-managechangetags": "criar e (des)ativar etiquetas",
"action-applychangetags": "aplicar etiquetas juntamente com as suas alterações",
"action-changetags": "adicionar e remover etiquetas arbitrárias em revisões e entradas de registo individuais",
+ "action-purge": "recarregar esta página",
"nchanges": "$1 {{PLURAL:$1|alteração|alterações}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
"enhancedrc-history": "histórico",
"action-applychangetags": " применять теги наряду с Вашими изменениями",
"action-changetags": "Добавлять и удалять произвольные теги на отдельных изменениях и записях в журнале",
"action-deletechangetags": "удаление меток из базы данных",
+ "action-purge": "очистку кэша этой страницы",
"nchanges": "$1 {{PLURAL:$1|изменение|изменения|изменений}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|с последнего посещения}}",
"enhancedrc-history": "история",
"action-applychangetags": "uveljavitev oznak skupaj z vašimi spremembami",
"action-changetags": "dodajanje in odstranjevanje poljubnih oznak na posameznih redakcijah in dnevniških vnosih",
"action-deletechangetags": "izbris oznak iz zbirke podatkov",
+ "action-purge": "počiščenje strani",
"nchanges": "$1 {{PLURAL:$1|sprememba|spremembi|spremembe|sprememb|sprememb}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od zadnjega obiska}}",
"enhancedrc-history": "zgodovina",
"watchthis": "Theo dõi trang này",
"savearticle": "Lưu trang",
"savechanges": "Lưu các thay đổi",
- "publishpage": "Xuất bản trang",
- "publishchanges": "Xuất bản các thay đổi",
+ "publishpage": "Đăng trang",
+ "publishchanges": "Đăng thay đổi",
"preview": "Xem trước",
"showpreview": "Xem trước",
"showdiff": "Xem thay đổi",
"content-json-empty-object": "Đối tượng trống",
"content-json-empty-array": "Mảng trống",
"deprecated-self-close-category": "Trang có thẻ HTML tự đóng không hợp lệ",
+ "deprecated-self-close-category-desc": "Trang này chứa thẻ HTML tự đóng không hợp lệ, ví dụ <code><b/></code> hoặc <code><span/></code>. Tí nữa cách trình bày các thẻ này sẽ thay đổi để tuân theo tiêu chuẩn HTML5, nên sự sử dụng chúng trong mã wiki bị phản đối.",
"duplicate-args-warning": "<strong>Cảnh báo:</strong> [[:$1]] đang gọi [[:$2]] với nhiều hơn một giá trị cho thông số “$3”. Chỉ giá trị cuối cùng mới được sử dụng.",
"duplicate-args-category": "Trang đưa đối số thừa vào bản mẫu",
"duplicate-args-category-desc": "Trang đưa một đối số nhiều lần vào một bản mẫu được nhúng, thí dụ <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> hoặc <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"action-applychangetags": "áp dụng các thẻ cùng với những thay đổi của bạn",
"action-changetags": "thêm và loại bỏ các thẻ tùy ý trên các phiên bản riêng và các mục nhật trình",
"action-deletechangetags": "xóa thẻ khỏi cơ sở dữ liệu",
+ "action-purge": "làm mới trang này",
"nchanges": "$1 thay đổi",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sau lần truy cập vừa rồi}}",
"enhancedrc-history": "lịch sử",
"log-action-filter-patrol": "Kiểu tuần tra:",
"log-action-filter-protect": "Loại bảo vệ:",
"log-action-filter-rights": "Kiểu thay đổi quyền:",
- "log-action-filter-suppress": "Kiểu ẩn giấu",
+ "log-action-filter-suppress": "Kiểu ẩn giấu:",
"log-action-filter-upload": "Loại tải lên:",
"log-action-filter-all": "Tất cả",
"log-action-filter-block-block": "Khối",
"content-json-empty-object": "ליידיגער אביעקט",
"content-json-empty-array": "ליידיגער אריי",
"duplicate-args-warning": "<strong>ווארענונג:</strong> [[:$1]] רופט [[:$2]] מיט מער ווי איין ווערט פארן פאראמעטער \"$3\". נאר דעם לעצטן ווערט וועט מען ניצן.",
- "duplicate-args-category": "×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f ×\92×¢×\98×\90פ×\9c×\98×¢ ×\90ר×\92×\95×\9e×¢× ×\98×\9f ×\90×\99×\9f ×\9e×\95ס×\98ער ר×\95פ×\9f",
+ "duplicate-args-category": "×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f ×\92×¢×\98×\90פ×\9c×\98×¢ ×\90ר×\92×\95×\9e×¢× ×\98×\9f ×\90×\99×\9f ×\90 ×\9e×\95ס×\98ער־ר×\95×£",
"duplicate-args-category-desc": "דער בלאט אנטהאלט מוסטער־אויפרופן וואס ניצן דופליקאטן פון ארגומענטן, ווי למשל <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> or <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"expensive-parserfunction-warning": "'''אזהרה:''' דער בלאט אנטהאלט צופיל טייערע פארזירער רופן.\n\nער דארף האבן ווינציגער פון $2 {{PLURAL:$2|רוף|רופן}}, אבער אצינד {{PLURAL:$1|איז דא $1 רוף|זענען דא $1 רופן}}.",
"expensive-parserfunction-category": "בלעטער מיט צופֿיל טייערע פאַרזער פֿונקציאן רופֿן",
"action-applychangetags": "连同您的更改应用标签",
"action-changetags": "在个别修订和日志记录中添加和移除任意标签",
"action-deletechangetags": "从数据库删除标签",
+ "action-purge": "刷新此页面",
"nchanges": "$1次更改",
"enhancedrc-since-last-visit": "{{PLURAL:$1|上次访问后}}$1个",
"enhancedrc-history": "历史",
"Zerng07",
"Reke",
"Kly",
- "Cosine02"
+ "Cosine02",
+ "一個正常人"
]
},
"tog-underline": "底線標示連結:",
"action-applychangetags": "連同您的變更一起套用標籤",
"action-changetags": "加入與移除任何於各別修訂與日誌項目的標籤",
"action-deletechangetags": "從資料庫刪除標籤",
+ "action-purge": "刷新此頁面",
"nchanges": "$1 次變更",
"enhancedrc-since-last-visit": "{{PLURAL:$1|自上次拜訪}}已有 $1",
"enhancedrc-history": "歷史",
$base = dirname( __DIR__ );
$generator = new AutoloadGenerator( $base, 'local' );
-foreach ( [ 'includes', 'languages', 'maintenance', 'mw-config' ] as $dir ) {
- $generator->readDir( $base . '/' . $dir );
-}
-foreach ( glob( $base . '/*.php' ) as $file ) {
- $generator->readFile( $file );
-}
+$generator->initMediaWikiDefault();
// Write out the autoload
-$generator->generateAutoload( 'maintenance/generateLocalAutoload.php' );
+$fileinfo = $generator->getTargetFileinfo();
+file_put_contents(
+ $fileinfo['filename'],
+ $generator->getAutoload( 'maintenance/generateLocalAutoload.php' )
+);
// Scripts managed by the current user (stored in their user space)
'user' => [ 'class' => 'ResourceLoaderUserModule' ],
+ 'user.styles' => [ 'class' => 'ResourceLoaderUserStylesModule' ],
// Scripts generated based on the current user's preferences
'user.cssprefs' => [ 'class' => 'ResourceLoaderUserCSSPrefsModule' ],
'jquery.arrowSteps' => [
'scripts' => 'resources/src/jquery/jquery.arrowSteps.js',
'styles' => 'resources/src/jquery/jquery.arrowSteps.css',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'jquery.async' => [
'scripts' => 'resources/lib/jquery/jquery.async.js',
'jquery.spinner' => [
'scripts' => 'resources/src/jquery/jquery.spinner.js',
'styles' => 'resources/src/jquery/jquery.spinner.css',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'jquery.jStorage' => [
'scripts' => 'resources/lib/jquery/jquery.jStorage.js',
'dependencies' => [
'mediawiki.api',
],
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.api.rollback' => [
'scripts' => 'resources/src/mediawiki/api/rollback.js',
'feedback-thanks-title',
'feedback-useragent'
],
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.feedlink' => [
'position' => 'top',
],
'mediawiki.icon' => [
'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.inspect' => [
'scripts' => 'resources/src/mediawiki/mediawiki.inspect.js',
'mediawiki.libs.jpegmeta' => [
'scripts' => 'resources/src/mediawiki.libs/mediawiki.libs.jpegmeta.js',
+ 'targets' => [ 'desktop', 'mobile' ],
],
/* MediaWiki Page */
"Lloffiwr",
"Robin Owain",
"ОйЛ",
- "DChan (WMF)"
+ "DChan (WMF)",
+ "Jdforrester"
]
},
"ooui-outline-control-move-down": "Symud yr eitem i lawr",
"ooui-outline-control-move-up": "Symud yr eitem i fyny",
"ooui-outline-control-remove": "Tynnu'r eitem",
- "ooui-toolbar-more": "Rhagor"
+ "ooui-toolbar-more": "Rhagor",
+ "ooui-toolgroup-expand": "Mwy",
+ "ooui-toolgroup-collapse": "Llai",
+ "ooui-dialog-message-accept": "Iawn",
+ "ooui-dialog-message-reject": "Canslo",
+ "ooui-dialog-process-error": "Aeth rhywbeth o’i le",
+ "ooui-dialog-process-dismiss": "Gadael",
+ "ooui-dialog-process-retry": "Ailgeisio",
+ "ooui-dialog-process-continue": "Parhau",
+ "ooui-selectfile-button-select": "Dewis ffeil",
+ "ooui-selectfile-not-supported": "Nid oes modd dewis ffeil",
+ "ooui-selectfile-placeholder": "Dim ffeil wedi'i dewis",
+ "ooui-selectfile-dragdrop-placeholder": "Gollwng ffeil yma"
}
"ooui-dialog-message-accept": "Sobib",
"ooui-dialog-message-reject": "Loobu",
"ooui-dialog-process-error": "Midagi läks valesti",
- "ooui-dialog-process-dismiss": "Hülga",
+ "ooui-dialog-process-dismiss": "Sule",
"ooui-dialog-process-retry": "Proovi uuesti",
"ooui-dialog-process-continue": "Jätka",
"ooui-selectfile-button-select": "Vali fail",
"Hwangjy9"
]
},
- "ooui-outline-control-move-down": "í\95목ì\9d\84 ì\95\84ë\9e\98ë¡\9c ì\98®ê¸°ê¸°",
- "ooui-outline-control-move-up": "í\95목ì\9d\84 ì\9c\84ë¡\9c ì\98®ê¸°ê¸°",
+ "ooui-outline-control-move-down": "í\95목ì\9d\84 ì\95\84ë\9e\98ë¡\9c ì\9d´ë\8f\99",
+ "ooui-outline-control-move-up": "í\95목ì\9d\84 ì\9c\84ë¡\9c ì\9d´ë\8f\99",
"ooui-outline-control-remove": "항목 제거",
"ooui-toolbar-more": "더 보기",
"ooui-toolgroup-expand": "더 보기",
"Elioqoshi",
"GretaDoci",
"Gertakapllani",
- "Techlik"
+ "Techlik",
+ "Liridon"
]
},
"ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
"ooui-dialog-process-dismiss": "Largoje",
"ooui-dialog-process-retry": "Provo përsëri",
"ooui-dialog-process-continue": "Vazhdo",
+ "ooui-selectfile-button-select": "Përzgjidhni një skedë",
"ooui-selectfile-not-supported": "Skedari i përzgjedhur nuk përkrahet",
- "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar"
+ "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar",
+ "ooui-selectfile-dragdrop-placeholder": "Vendose skedën këtu"
}
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-element-hidden {
display: none !important;
+ /* stylelint-disable-line declaration-no-important */
}
.oo-ui-buttonElement > .oo-ui-buttonElement-button {
cursor: pointer;
overflow: auto;
resize: none;
}
+.oo-ui-textInputWidget [type="number"] {
+ -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
+.oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
.oo-ui-textInputWidget [type="search"] {
-webkit-appearance: textfield;
}
.oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
cursor: pointer;
}
-.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
- opacity: 0 !important;
+.oo-ui-comboBoxInputWidget-php ::-webkit-calendar-picker-indicator {
+ opacity: 0;
position: absolute;
right: 0;
top: 0;
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-element-hidden {
display: none !important;
+ /* stylelint-disable-line declaration-no-important */
}
.oo-ui-buttonElement > .oo-ui-buttonElement-button {
cursor: pointer;
margin-bottom: 1.25em;
}
.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding: 0.25em 0.25em 0.25em 1em;
+ padding: 0.25em 0.25em 0.25em 0.5em;
}
.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
padding-top: 0.25em;
margin-top: 2em;
}
.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
- font-size: 1.1em;
margin-bottom: 0.5em;
- padding: 0.25em 0;
+ font-size: 1.1em;
font-weight: bold;
}
.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
background-color: transparent;
}
.oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
- padding: 0.25em 0.25em 0.25em 1em;
+ padding: 0.25em 0.25em 0.25em 0.5em;
}
.oo-ui-radioOptionWidget .oo-ui-radioInputWidget {
margin-right: 0;
background-position: center center;
background-origin: border-box;
background-size: 0 0;
- border: 1px solid #777777;
+ border: 1px solid #767676;
border-radius: 2px;
}
.oo-ui-checkboxInputWidget [type="checkbox"]:checked + span {
background-size: 100% 100%;
}
.oo-ui-checkboxInputWidget [type="checkbox"]:active + span {
- background-color: #cccccc;
- border-color: #cccccc;
+ background-color: #767676;
+ border-color: #767676;
}
.oo-ui-checkboxInputWidget [type="checkbox"]:focus + span {
border-width: 2px;
background-position: center center;
background-origin: border-box;
background-size: 0 0;
- border: 1px solid #777777;
+ border: 1px solid #767676;
border-radius: 100%;
}
.oo-ui-radioInputWidget [type="radio"]:checked + span {
background-size: 100% 100%;
}
.oo-ui-radioInputWidget [type="radio"]:active + span {
- background-color: #cccccc;
- border-color: #cccccc;
+ background-color: #767676;
+ border-color: #767676;
}
.oo-ui-radioInputWidget [type="radio"]:focus + span {
border-width: 2px;
overflow: auto;
resize: none;
}
+.oo-ui-textInputWidget [type="number"] {
+ -moz-appearance: textfield;
+}
+.oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
+.oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
.oo-ui-textInputWidget [type="search"] {
-webkit-appearance: textfield;
}
-moz-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:hover {
+ border-color: #aaaaaa;
+}
.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
outline: 0;
color: #777777;
text-shadow: 0 1px 1px #ffffff;
}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:hover {
+ border-color: #cccccc;
+}
.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:focus,
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:focus {
border-color: #cccccc;
.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea {
border-color: #ff0000;
}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:hover,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:hover {
+ border-color: #ff0000;
+}
.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:focus,
.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:focus {
border-color: #ff0000;
.oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
cursor: pointer;
}
-.oo-ui-comboBoxInputWidget-php input::-webkit-calendar-picker-indicator {
- opacity: 0 !important;
+.oo-ui-comboBoxInputWidget-php ::-webkit-calendar-picker-indicator {
+ opacity: 0;
position: absolute;
right: 0;
top: 0;
vertical-align: middle;
}
.oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
- padding: 0.25em 0.25em 0.25em 1em;
+ padding: 0.25em 0.25em 0.25em 0.5em;
}
.oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
margin-right: 0;
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
* @param {jQuery.Event} e
*/
OO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {
- var $options, checked,
+ var $options, lastClickedIndex, nowClickedIndex, i, direction, wasSelected, items,
$lastClicked = this.$lastClicked,
$nowClicked = $( e.target ).closest( '.oo-ui-checkboxMultioptionWidget' )
.not( '.oo-ui-widget-disabled' );
// Allow selecting multiple options at once by Shift-clicking them
if ( $lastClicked && $nowClicked.length && e.shiftKey ) {
$options = this.$group.find( '.oo-ui-checkboxMultioptionWidget' );
- checked = $nowClicked.find( 'input' ).prop( 'checked' );
-
- $options
- .slice(
- Math.min( $options.index( $lastClicked ), $options.index( $nowClicked ) ),
- Math.max( $options.index( $lastClicked ), $options.index( $nowClicked ) ) + 1
- )
- .find( 'input' )
- .filter( function () {
- return !this.disabled;
- } )
- .prop( 'checked', checked )
- .trigger( 'change' );
+ lastClickedIndex = $options.index( $lastClicked );
+ nowClickedIndex = $options.index( $nowClicked );
+ // If it's the same item, either the user is being silly, or it's a fake event generated by the
+ // browser. In either case we don't need custom handling.
+ if ( nowClickedIndex !== lastClickedIndex ) {
+ items = this.items;
+ wasSelected = items[ nowClickedIndex ].isSelected();
+ direction = nowClickedIndex > lastClickedIndex ? 1 : -1;
+
+ // This depends on the DOM order of the items and the order of the .items array being the same.
+ for ( i = lastClickedIndex; i !== nowClickedIndex; i += direction ) {
+ if ( !items[ i ].isDisabled() ) {
+ items[ i ].setSelected( !wasSelected );
+ }
+ }
+ // For the now-clicked element, use immediate timeout to allow the browser to do its own
+ // handling first, then set our value. The order in which events happen is different for
+ // clicks on the <input> and on the <label> and there are additional fake clicks fired for
+ // non-click actions that change the checkboxes.
+ e.preventDefault();
+ setTimeout( function () {
+ if ( !items[ nowClickedIndex ].isDisabled() ) {
+ items[ nowClickedIndex ].setSelected( !wasSelected );
+ }
+ } );
+ }
}
if ( $nowClicked.length ) {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
.oo-ui-toolGroup {
display: inline-block;
vertical-align: middle;
+ border-right: 1px solid #cccccc;
border-radius: 0;
- border-right: 1px solid #dddddd;
}
.oo-ui-toolGroup-empty {
display: none;
.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
margin-left: 0;
}
-.oo-ui-toolGroup .oo-ui-toolGroup .oo-ui-widget-enabled {
- border-right: 0 !important;
-}
.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
.oo-ui-barToolGroup > .oo-ui-labelElement-label {
display: none;
padding: 0 0.4em;
}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
background-color: #eeeeee;
}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
color: #555555;
}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.2);
box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
background-color: #e5e5e5;
}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled:hover {
background-color: #eeeeee;
}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-left-color: rgba(0, 0, 0, 0.1);
-}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title {
color: #cccccc;
}
}
.oo-ui-popupToolGroup .oo-ui-tool-link {
padding: 0.4em 0.625em;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
height: 2.5em;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
- border-color: rgba(0, 0, 0, 0.2);
-}
.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
background-color: #eeeeee;
}
.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
opacity: 0.9;
}
.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
background-color: #e5e5e5;
}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-top-color: rgba(0, 0, 0, 0.1);
-}
.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
background-color: #eeeeee;
}
.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-draggableElement-handle,
.oo-ui-draggableElement-handle.oo-ui-widget {
left: 0;
right: 0;
bottom: 0;
+ /* stylelint-disable declaration-no-important */
+ /* stylelint-enable declaration-no-important */
}
.oo-ui-menuLayout-menu,
.oo-ui-menuLayout-content {
.oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
z-index: 2;
}
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
cursor: default;
height: 5.5em;
padding: 0;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
display: none;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
height: 5.5em;
width: 5.5em;
position: absolute;
background-size: cover;
background-position: center center;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
background-size: auto;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
opacity: 0.4;
background-color: #cccccc;
height: 5.5em;
width: 5.5em;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
border: 0;
background: none;
display: block;
width: auto;
margin-left: 5.5em;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
position: relative;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
display: block;
padding-right: 2.375em;
overflow: hidden;
text-overflow: ellipsis;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
display: block;
float: none;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
position: absolute;
right: 0.5em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
display: none;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
display: block;
margin: 0.7em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
text-align: center;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
margin: 0;
}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
display: block;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
cursor: no-drop;
}
.oo-ui-selectFileWidget:last-child {
.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
right: 2em;
}
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
background-color: #e1f3ff;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
border-color: #dddddd;
background-color: #f3f3f3;
}
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
background-color: #ffffff;
border: 1px solid #aaaaaa;
margin-bottom: 0.5em;
vertical-align: middle;
border-radius: 0.25em;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
border-radius: 0.25em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
border-style: dashed;
}
.oo-ui-outlineOptionWidget {
.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
width: 100%;
}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
- -webkit-appearance: none;
- margin: 0;
-}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"] {
- -moz-appearance: textfield;
-}
.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
white-space: nowrap;
}
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-draggableElement-handle,
.oo-ui-draggableElement-handle.oo-ui-widget {
left: 0;
right: 0;
bottom: 0;
+ /* stylelint-disable declaration-no-important */
+ /* stylelint-enable declaration-no-important */
}
.oo-ui-menuLayout-menu,
.oo-ui-menuLayout-content {
transform: translateZ(0);
height: 2em;
width: 3.5em;
- border: 1px solid #777777;
+ border: 1px solid #767676;
border-radius: 1em;
background-color: #ffffff;
margin-right: 0.5em;
min-height: 16px;
height: 1.2em;
border-radius: 1.2em;
- background-color: #555555;
-webkit-transition: left 100ms, margin-left 100ms;
-moz-transition: left 100ms, margin-left 100ms;
transition: left 100ms, margin-left 100ms;
left: 1.9em;
margin-left: -2px;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on {
- background-color: #347bff;
- border-color: #347bff;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- background-color: #ffffff;
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled .oo-ui-toggleSwitchWidget-grip {
+ border: 1px solid #767676;
}
.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover {
border-color: #2962cc;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover.oo-ui-toggleWidget-on {
- background-color: #2962cc;
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover .oo-ui-toggleSwitchWidget-grip {
border-color: #2962cc;
}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover {
+ background-color: #767676;
+ border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active .oo-ui-toggleSwitchWidget-grip,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover .oo-ui-toggleSwitchWidget-grip {
+ background-color: #ffffff;
+ border-color: #ffffff;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+}
.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus {
border-color: #347bff;
box-shadow: inset 0 0 0 1px #347bff;
outline: 0;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus .oo-ui-toggleSwitchWidget-grip {
border-color: #347bff;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on:before {
- border-color: #ffffff;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on {
background-color: #347bff;
border-color: #347bff;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active .oo-ui-toggleSwitchWidget-grip,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:active:hover .oo-ui-toggleSwitchWidget-grip {
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
background-color: #ffffff;
+ border-color: #ffffff;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:hover {
+ background-color: #2962cc;
+ border-color: #2962cc;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:active,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:active:hover {
+ background-color: #1f4999;
+ border-color: #1f4999;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:focus {
+ border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on:focus:before {
+ border-color: #ffffff;
+}
.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
background-color: #dddddd;
border-color: #dddddd;
.oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
z-index: 2;
}
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
cursor: default;
height: 5.5em;
padding: 0;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
display: none;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
height: 5.5em;
width: 5.5em;
position: absolute;
background-size: cover;
background-position: center center;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
background-size: auto;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
opacity: 0.4;
background-color: #cccccc;
height: 5.5em;
width: 5.5em;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
border: 0;
background: none;
display: block;
width: auto;
margin-left: 5.5em;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
position: relative;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
display: block;
padding-right: 2.375em;
overflow: hidden;
text-overflow: ellipsis;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
display: block;
float: none;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
position: absolute;
right: 0.5em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
display: none;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
display: block;
margin: 0.7em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
text-align: center;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
margin: 0;
}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
display: block;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
cursor: no-drop;
}
.oo-ui-selectFileWidget:last-child {
right: 2em;
padding-left: 0;
}
-.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
background-color: #ebf2ff;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
border-color: #dddddd;
background-color: #f3f3f3;
}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
}
-.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
background-color: #ffffff;
border: 1px solid #cccccc;
margin-bottom: 0.5em;
overflow: hidden;
border-radius: 2px;
}
-.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
border-radius: 2px;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
background-color: #eeeeee;
border-style: dashed;
}
.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
width: 100%;
}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-outer-spin-button,
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"]::-webkit-inner-spin-button {
- -webkit-appearance: none;
- margin: 0;
-}
-.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget [type="number"] {
- -moz-appearance: textfield;
-}
.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
white-space: nowrap;
}
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
this.selectButton.setIcon( 'upload' );
this.$thumbnail = $( '<div>' ).addClass( 'oo-ui-selectFileWidget-thumbnail' );
this.setPendingElement( this.$thumbnail );
- this.$dropTarget = $( '<div>' )
- .addClass( 'oo-ui-selectFileWidget-dropTarget' )
+ this.$element
+ .addClass( 'oo-ui-selectFileWidget-dropTarget oo-ui-selectFileWidget' )
.on( {
click: this.onDropTargetClick.bind( this )
} )
.addClass( 'oo-ui-selectFileWidget-dropLabel' )
.text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )
);
- this.$element.append( this.$dropTarget );
} else {
this.$element
.addClass( 'oo-ui-selectFileWidget' )
}.bind( this ) ).always( function () {
this.popPending();
}.bind( this ) );
- this.$dropTarget.off( 'click' );
+ this.$element.off( 'click' );
}
} else {
if ( this.showDropTarget ) {
- this.$dropTarget.off( 'click' );
- this.$dropTarget.on( {
+ this.$element.off( 'click' );
+ this.$element.on( {
click: this.onDropTargetClick.bind( this )
} );
this.$thumbnail
this.minusButton = new OO.ui.ButtonWidget( $.extend(
{
disabled: this.isDisabled(),
- tabIndex: -1
- },
- config.minusButton,
- {
+ tabIndex: -1,
classes: [ 'oo-ui-numberInputWidget-minusButton' ],
label: '−'
- }
+ },
+ config.minusButton
) );
this.plusButton = new OO.ui.ButtonWidget( $.extend(
{
disabled: this.isDisabled(),
- tabIndex: -1
- },
- config.plusButton,
- {
+ tabIndex: -1,
classes: [ 'oo-ui-numberInputWidget-plusButton' ],
label: '+'
- }
+ },
+ config.plusButton
) );
}
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-actionWidget.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:07Z
+ * Date: 2016-08-03T16:38:27Z
*/
.oo-ui-window {
background: transparent;
text-align: left;
}
.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- border-right: 1px solid #e5e5e5;
+ border-right: 1px solid #cccccc;
margin: 0;
}
.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
border-right-width: 0;
}
.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- border-bottom: 1px solid #e5e5e5;
+ border-bottom: 1px solid #cccccc;
margin: 0;
}
.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
/*!
- * OOjs UI v0.17.6
+ * OOjs UI v0.17.7
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-07-12T20:26:03Z
+ * Date: 2016-08-03T16:38:22Z
*/
( function ( OO ) {
--- /dev/null
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "bell": { "file": "images/icons/bell.svg" },
+ "bellOn": { "file": {
+ "ltr": "images/icons/bellOn-ltr.svg",
+ "rtl": "images/icons/bellOn-rtl.svg"
+ } },
+ "eye": { "file": "images/icons/eye.svg" },
+ "eyeClosed": { "file": "images/icons/eyeClosed.svg" },
+ "message": { "file": {
+ "ltr": "images/icons/message-ltr.svg",
+ "rtl": "images/icons/message-rtl.svg"
+ } },
+ "signature": { "file": {
+ "ltr": "images/icons/signature-ltr.svg",
+ "rtl": "images/icons/signature-rtl.svg"
+ } },
+ "speechBubble": { "file": {
+ "ltr": "images/icons/speechBubble-ltr.svg",
+ "rtl": "images/icons/speechBubble-rtl.svg"
+ } },
+ "speechBubbleAdd": { "file": {
+ "ltr": "images/icons/speechBubbleAdd-ltr.svg",
+ "rtl": "images/icons/speechBubbleAdd-rtl.svg"
+ } },
+ "speechBubbles": { "file": {
+ "ltr": "images/icons/speechBubbles-ltr.svg",
+ "rtl": "images/icons/speechBubbles-rtl.svg"
+ } },
+ "tray": { "file": "images/icons/tray.svg" }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
+ <circle cx="12" cy="14" r="2"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19.4 12.7c.7-.8 1.2-1.7 1.4-2.7h-1.6c-.9 2.5-3.9 4.4-7.7 4.6h-.1c-3.7-.2-6.8-2.1-7.7-4.6H2.2c.2 1 .8 1.9 1.4 2.7l-2 2 .7.7 2-2c.8.6 1.7 1.2 2.7 1.7l-1 2.8.9.3 1-2.8c1 .3 2 .6 3.1.6v3h1v-3c1.1-.1 2.2-.3 3.1-.6l1 2.8.9-.3-1-2.8c1-.4 1.9-1 2.6-1.7l2 2 .7-.7-1.9-2z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M21 9c0-1.7-1.3-3-3-3H3v3l9 4 9-4zM3 11v6c0 1.7 1.3 3 3 3h15v-9l-9 4-9-4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3H3v-9l9 4 9-4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M0 20h24v1H0v-1zm6-8l-1-1-2 2-2-2-1 1 2 2-2 2 1 1 2-2 2 2 1-1-2-2zm15.6 3.7c-.9-.5-1.9-.5-2.7 0-1.5.9-3.1.4-3.1.4-.4-.2-.8-.4-1.1-.6 2.2-.6 4.4-1.8 6-3.9 1.1-1.2 2.5-3.9.4-6-.7-.7-1.6-1.1-2.7-1-1.4.1-2.8.9-3.9 2.1-.9 1.1-3.1 4.5-2.3 7.5 0 .1 0 .2.1.3-2.3.3-4.2.2-4.4.1v1.5c.7.1 2.7.2 5.1-.2.5.7 1.3 1.2 2.3 1.6.1 0 2.4.8 4.5-.6.5-.3.9-.1 1.1 0 .4.2.7.6.7 1H23c0-.8-.6-1.7-1.4-2.2zm-8-1.7c-.5-2.2 1.1-5.1 2-6.2.8-.9 1.8-1.5 2.8-1.6h.1c.6 0 1.1.2 1.5.6 1.6 1.6-.4 3.9-.5 4-1.5 2-3.7 3-5.8 3.5l-.1-.3z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M24 20H0v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zM2.4 15.7c.9-.5 1.9-.5 2.7 0 1.5.9 3.1.4 3.1.4.4-.2.8-.4 1.1-.6-2.2-.6-4.4-1.8-6-3.9-1.1-1.2-2.5-3.9-.4-6 .7-.7 1.6-1.1 2.7-1 1.4.1 2.8.9 3.9 2.1.9 1.1 3.1 4.5 2.3 7.5 0 .1 0 .2-.1.3 2.3.3 4.2.2 4.4.1v1.5c-.7.1-2.7.2-5.1-.2-.5.7-1.3 1.2-2.3 1.6-.1 0-2.4.8-4.5-.6-.5-.3-.9-.1-1.1 0-.4.2-.7.6-.7 1H1c0-.8.6-1.7 1.4-2.2zm8-1.7c.5-2.2-1.1-5.1-2-6.2-.8-.9-1.8-1.5-2.8-1.6h-.1c-.6 0-1.1.2-1.5.6-1.6 1.6.4 3.9.5 4 1.5 2 3.7 3 5.8 3.5l.1-.3z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19 20H2l3-3V6h17v11c0 1.7-1.3 3-3 3z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3V6H5zm8 3h1v3h3v1h-3v3h-1v-3h-3v-1h3V9z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M2 6v11c0 1.7 1.3 3 3 3h17l-3-3V6H2zm8 3h1v3h3v1h-3v3h-1v-3H7v-1h3V9z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M20 9v9l2 2H8V9h12zM3 4h12v4H7v7H1l2-2V4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 9v9l-2 2h14V9H3zm17-5H8v4h8v7h6l-2-2V4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
"speechBubbles": { "file": {
"ltr": "images/icons/speechBubbles-ltr.svg",
"rtl": "images/icons/speechBubbles-rtl.svg"
- } }
+ } },
+ "tray": { "file": "images/icons/tray.svg" }
}
}
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
- <path d="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+ <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+ <path d="M17.5 13V8c0-3-2.3-5-5.5-5S6.5 5 6.5 8v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 19H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
- <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 19.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+ <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 19.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+ <path d="M17.8 13.7L19.5 9c1-2.8-.5-5.5-3.5-6.6-3-1.1-5.9 0-6.9 2.8L7.4 9.9c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zM12 18.8l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
- <path d="M6.21 14.7L4.51 10c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+ <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6.21 14.7L4.51 10c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
+ <path d="M6.21 13.7L4.51 9c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z"/>
</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #ffffff }</style>
+ <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 13.35l1.8-7.2c.2-.996.81-1.8 1.8-1.8h10.8c.99 0 1.6.867 1.8 1.8l1.8 7.2v4.5c0 .99-.81 1.8-1.8 1.8H4.8c-.99 0-1.8-.81-1.8-1.8v-4.5zm6.96 1.8h4.08c-.49.557-1.212.9-2.04.9a2.68 2.68 0 0 1-2.04-.9h4.08c.414-.472.66-1.098.66-1.8h4.14l-1.44-7.2H6.6l-1.44 7.2H9.3c0 .702.246 1.328.66 1.8z" id="tray"/>
+</svg>
* getAccessKeyPrefix
*
* @method updateTooltipAccessKeys_getAccessKeyPrefix
- * @deprecated 1.27 Use #getAccessKeyModifiers
+ * @deprecated since 1.27 Use #getAccessKeyModifiers
*/
$.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
return getAccessKeyModifiers( ua ).join( '-' ) + '-';
#mw-revision-info-current,
#mw-revision-nav {
direction: ltr;
- display: inline;
}
/* Images */
'MockSvgHandler' => "$testDir/phpunit/mocks/media/MockSvgHandler.php",
'MockDjVuHandler' => "$testDir/phpunit/mocks/media/MockDjVuHandler.php",
'MockOggHandler' => "$testDir/phpunit/mocks/media/MockOggHandler.php",
+ 'MockMediaHandlerFactory' => "$testDir/phpunit/mocks/media/MockMediaHandlerFactory.php",
'MockWebRequest' => "$testDir/phpunit/mocks/MockWebRequest.php",
'MediaWiki\\Session\\DummySessionBackend'
=> "$testDir/phpunit/mocks/session/DummySessionBackend.php",
// TODO: move global state into MediaWikiServices
RequestContext::resetMain();
- MediaHandler::resetCache();
if ( session_id() !== '' ) {
session_write_close();
session_id( '' );
// TODO: move global state into MediaWikiServices
RequestContext::resetMain();
- MediaHandler::resetCache();
if ( session_id() !== '' ) {
session_write_close();
session_id( '' );
return $buffer;
}
+ /**
+ * Create a temporary hook handler which will be reset by tearDown.
+ * This replaces other handlers for the same hook.
+ * @param string $hookName Hook name
+ * @param mixed $handler Value suitable for a hook handler
+ * @since 1.28
+ */
+ protected function setTemporaryHook( $hookName, $handler ) {
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [ $hookName => [ $handler ] ] );
+ }
+
}
[ 300, 225 ],
[ 800, 600 ],
],
- 'wgMediaHandlers' => [
- 'unknown/unknown' => 'MockBitmapHandler',
- ],
] );
}
* @dataProvider provideThumbParams
*/
public function testIsStandard( $message, $expected, $params ) {
+ $this->setService( 'MediaHandlerFactory', new MockMediaHandlerFactory() );
$this->assertSame(
$expected,
wfThumbIsStandard( new FakeDimensionFile( [ 2000, 1800 ] ), $params ),
'DBLoadBalancer' => [ 'DBLoadBalancer', 'LoadBalancer' ],
'WatchedItemStore' => [ 'WatchedItemStore', WatchedItemStore::class ],
'WatchedItemQueryService' => [ 'WatchedItemQueryService', WatchedItemQueryService::class ],
+ 'MediaHandlerFactory' => [ 'MediaHandlerFactory', MediaHandlerFactory::class ],
'GenderCache' => [ 'GenderCache', GenderCache::class ],
'LinkCache' => [ 'LinkCache', LinkCache::class ],
'LinkRenderer' => [ 'LinkRenderer', LinkRenderer::class ],
/**
* @group ContentHandler
+ * @group Database
*/
class ContentHandlerTest extends MediaWikiTestCase {
parent::tearDown();
}
+ public function addDBDataOnce() {
+ $this->insertPage( 'Not_Main_Page', 'This is not a main page' );
+ $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]' );
+ }
+
public static function dataGetDefaultModelFor() {
return [
[ 'Help:Foo', CONTENT_MODEL_WIKITEXT ],
$this->assertInstanceOf( $handlerClass, $handler );
}
+ /**
+ * @covers ContentHandler::getDataForSearchIndex
+ */
+ public function testDataIndexFields() {
+ $mockEngine = $this->getMock( 'SearchEngine' );
+ $title = Title::newFromText( 'Not_Main_Page', NS_MAIN );
+ $page = new WikiPage( $title );
+
+ $this->setTemporaryHook( 'SearchDataForIndex',
+ function ( &$fields, ContentHandler $handler, WikiPage $page, ParserOutput $output,
+ SearchEngine $engine ) {
+ $fields['testDataField'] = 'test content';
+ } );
+
+ $output = $page->getContent()->getParserOutput( $title );
+ $data = $page->getContentHandler()->getDataForSearchIndex( $page, $output, $mockEngine );
+ $this->assertArrayHasKey( 'text', $data );
+ $this->assertArrayHasKey( 'text_bytes', $data );
+ $this->assertArrayHasKey( 'language', $data );
+ $this->assertArrayHasKey( 'testDataField', $data );
+ $this->assertEquals( 'test content', $data['testDataField'] );
+ }
+
+ /**
+ * @covers ContentHandler::getParserOutputForIndexing
+ */
+ public function testParserOutputForIndexing() {
+ $title = Title::newFromText( 'Smithee', NS_MAIN );
+ $page = new WikiPage( $title );
+
+ $out = $page->getContentHandler()->getParserOutputForIndexing( $page );
+ $this->assertInstanceOf( ParserOutput::class, $out );
+ $this->assertContains( 'one who smiths', $out->getRawText() );
+ }
+
}
$this->assertEquals( 'test', $mappedFields['language']['testData'] );
$this->assertEquals( 'language', $mappedFields['language']['name'] );
}
-
}
) {
}
*/
+
+ public function testDataIndexFieldsFile() {
+ $mockEngine = $this->getMock( 'SearchEngine' );
+ $title = Title::newFromText( 'Somefile.jpg', NS_FILE );
+ $page = new WikiPage( $title );
+
+ $handler = $this->getMockBuilder( WikitextContentHandler::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'getFileText' ] )
+ ->getMock();
+ $handler->method( 'getFileText' )->will( $this->returnValue( 'This is file content' ) );
+
+ $data = $handler->getDataForSearchIndex( $page, new ParserOutput(), $mockEngine );
+ $this->assertArrayHasKey( 'file_text', $data );
+ $this->assertEquals( 'This is file content', $data['file_text'] );
+ }
}
--- /dev/null
+<?php
+
+class WikitextStructureTest extends MediaWikiLangTestCase {
+
+ private function getMockTitle() {
+ return Title::newFromText( "TestTitle" );
+ }
+
+ /**
+ * Get parser output for Wiki text
+ * @param $text
+ * @return ParserOutput
+ */
+ private function getParserOutput( $text ) {
+ $content = new WikitextContent( $text );
+ return $content->getParserOutput( $this->getMockTitle() );
+ }
+
+ /**
+ * Get WikitextStructure for given text
+ * @param $text
+ * @return WikiTextStructure
+ */
+ private function getStructure( $text ) {
+ return new WikiTextStructure( $this->getParserOutput( $text ) );
+ }
+
+ public function testCategories() {
+ $text = <<<END
+We also have a {{Template}} and an {{Another template}} in addition.
+This text also has [[Category:Some Category| ]] and then [[Category:Yet another category]].
+And [[Category:Some Category| this category]] is repeated.
+END;
+ $struct = $this->getStructure( $text );
+ $cats = $struct->categories();
+ $this->assertCount( 2, $cats );
+ $this->assertContains( "Some Category", $cats );
+ $this->assertContains( "Yet another category", $cats );
+ }
+
+ public function testOutgoingLinks() {
+ $text = <<<END
+Here I add link to [[Some Page]]. And [[Some Page|This same page]] gets linked twice.
+We also have [[File:Image.jpg|image]].
+We also have a {{Template}} and an {{Another template}} in addition.
+Some templates are {{lowercase}}.
+And [[Some_Page]] is linked again.
+It also has [[Category:Some Category| ]] and then [[Category:Yet another category]].
+Also link to a [[Talk:TestTitle|talk page]] is here.
+END;
+ $struct = $this->getStructure( $text );
+ $links = $struct->outgoingLinks();
+ $this->assertContains( "Some_Page", $links );
+ $this->assertContains( "Template:Template", $links );
+ $this->assertContains( "Template:Another_template", $links );
+ $this->assertContains( "Template:Lowercase", $links );
+ $this->assertContains( "Talk:TestTitle", $links );
+ $this->assertCount( 5, $links );
+ }
+
+ public function testTemplates() {
+ $text = <<<END
+We have a {{Template}} and an {{Another template}} in addition.
+Some templates are {{lowercase}}. And this {{Template}} is repeated.
+Here is {{another_template|with=argument}}.
+This is a template that {{Xdoes not exist}}.
+END;
+ $this->setTemporaryHook( 'TitleExists', function ( Title $title, &$exists ) {
+ $txt = $title->getBaseText();
+ if ( $txt[0] != 'X' ) {
+ $exists = true;
+ }
+ return true;
+ } );
+ $struct = $this->getStructure( $text );
+ $templates = $struct->templates();
+ $this->assertCount( 3, $templates );
+ $this->assertContains( "Template:Template", $templates );
+ $this->assertContains( "Template:Another template", $templates );
+ $this->assertContains( "Template:Lowercase", $templates );
+ }
+
+ public function testHeadings() {
+ $text = <<<END
+Some text here
+== Heading one ==
+Some text
+==== heading two ====
+More text
+=== Applicability of the strict mass-energy equivalence formula, ''E'' = ''mc''<sup>2</sup> ===
+and more text
+== Wikitext '''in''' [[Heading]] and also <b>html</b> ==
+more text
+END;
+// FIXME: add test for ==== See also ==== after cirrussearch-ignored-headings is renamed
+ $struct = $this->getStructure( $text );
+ $headings = $struct->headings();
+ $this->assertCount( 4, $headings );
+ $this->assertContains( "Heading one", $headings );
+ $this->assertContains( "heading two", $headings );
+ $this->assertContains( "Applicability of the strict mass-energy equivalence formula, E = mc2",
+ $headings );
+ $this->assertContains( "Wikitext in Heading and also html", $headings );
+ }
+
+ public function testHeadingsFirst() {
+ $text = <<<END
+== Heading one ==
+Some text
+==== heading two ====
+END;
+ $struct = $this->getStructure( $text );
+ $headings = $struct->headings();
+ $this->assertCount( 2, $headings );
+ $this->assertContains( "Heading one", $headings );
+ $this->assertContains( "heading two", $headings );
+ }
+
+ public function testHeadingsNone() {
+ $text = "This text is completely devoid of headings.";
+ $struct = $this->getStructure( $text );
+ $headings = $struct->headings();
+ $this->assertArrayEquals( [], $headings );
+ }
+
+ public function testTexts() {
+ $text = <<<END
+Opening text is opening.
+== Then comes header ==
+Then we got more<br>text
+=== And more headers ===
+{| class="wikitable"
+|-
+! Header table
+|-
+| row in table
+|-
+| another row in table
+|}
+END;
+ $struct = $this->getStructure( $text );
+ $this->assertEquals( "Opening text is opening.", $struct->getOpeningText() );
+ $this->assertEquals( "Opening text is opening. Then we got more text",
+ $struct->getMainText() );
+ $this->assertEquals( [ "Header table row in table another row in table" ],
+ $struct->getAuxiliaryText() );
+ }
+}
<?php
+
+use MediaWiki\MediaWikiServices;
+
/**
* Although marked as a stub, can work independently.
*
$tmpGlobals['wgStyleDirectory'] = "$IP/skins";
}
- # Replace all media handlers with a mock. We do not need to generate
- # actual thumbnails to do parser testing, we only care about receiving
- # a ThumbnailImage properly initialized.
- global $wgMediaHandlers;
- foreach ( $wgMediaHandlers as $type => $handler ) {
- $tmpGlobals['wgMediaHandlers'][$type] = 'MockBitmapHandler';
- }
- // Vector images have to be handled slightly differently
- $tmpGlobals['wgMediaHandlers']['image/svg+xml'] = 'MockSvgHandler';
-
- // DjVu images have to be handled slightly differently
- $tmpGlobals['wgMediaHandlers']['image/vnd.djvu'] = 'MockDjVuHandler';
-
- // Ogg video/audio increasingly more differently
- $tmpGlobals['wgMediaHandlers']['application/ogg'] = 'MockOggHandler';
-
$tmpHooks = $wgHooks;
$tmpHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
$tmpHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
ParserTest::resetTitleServices();
+ MediaWikiServices::getInstance()->disableService( 'MediaHandlerFactory' );
+ MediaWikiServices::getInstance()->redefineService(
+ 'MediaHandlerFactory',
+ function() {
+ return new MockMediaHandlerFactory();
+ }
+ );
}
protected function tearDown() {
// Restore message cache (temporary pages and $wgUseDatabaseMessages)
MessageCache::destroyInstance();
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'MediaHandlerFactory' );
parent::tearDown();
return [
'noTemplateModule' => [],
+ 'deprecatedModule' => $base + [
+ 'deprecated' => true,
+ ],
+ 'deprecatedTomorrow' => $base + [
+ 'deprecated' => [
+ 'message' => 'Will be removed tomorrow.'
+ ],
+ ],
+
'htmlTemplateModule' => $base + [
'templates' => [
'templates/template.html',
$this->assertEquals( $rl->getDependencies(), $expected );
}
+ public static function providerDeprecatedModules() {
+ return [
+ [
+ 'deprecatedModule',
+ 'mw.log.warn("This page is using the deprecated ResourceLoader module \"deprecatedModule\".");',
+ ],
+ [
+ 'deprecatedTomorrow',
+ 'mw.log.warn(' .
+ '"This page is using the deprecated ResourceLoader module \"deprecatedTomorrow\".\\n' .
+ "Will be removed tomorrow." .
+ '");'
+ ]
+ ];
+ }
+
+ /**
+ * @dataProvider providerDeprecatedModules
+ * @covers ResourceLoaderFileModule::getScripts
+ */
+ public function testDeprecatedModules( $name, $expected ) {
+ $modules = self::getModules();
+ $rl = new ResourceLoaderFileModule( $modules[$name] );
+ $rl->setName( $name );
+ $ctx = $this->getResourceLoaderContext( 'en', 'ltr' );
+ $this->assertEquals( $rl->getScript( $ctx ), $expected );
+ }
+
/**
* @covers ResourceLoaderFileModule::getAllStyleFiles
* @covers ResourceLoaderFileModule::getAllSkinStyleFiles
->willReturnCallback( $mockFieldBuilder );
// Not using mock since PHPUnit mocks do not work properly with references in params
- $this->mergeMwGlobalArrayValue( 'wgHooks',
- [ 'SearchIndexFields' => [ [ $this, 'hookSearchIndexFields', $mockFieldBuilder ] ] ] );
+ $this->setTemporaryHook( 'SearchIndexFields',
+ function ( &$fields, SearchEngine $engine ) use ( $mockFieldBuilder ) {
+ $fields['testField'] =
+ $mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
+ return true;
+ } );
$fields = $mockEngine->getSearchIndexFields();
$this->assertArrayHasKey( 'language', $fields );
$this->assertArrayHasKey( 'testData', $mapping );
$this->assertEquals( 'test', $mapping['testData'] );
}
-
- public function hookSearchIndexFields( $mockFieldBuilder, &$fields, SearchEngine $engine ) {
- $fields['testField'] = $mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
- return true;
- }
}
--- /dev/null
+<?php
+/**
+ * Media-handling base classes and generic functionality.
+ *
+ * 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
+ * @ingroup Media
+ */
+
+/**
+ * Replace all media handlers with a mock. We do not need to generate
+ * actual thumbnails to do parser testing, we only care about receiving
+ * a ThumbnailImage properly initialized.
+ *
+ * @since 1.28
+ */
+class MockMediaHandlerFactory extends MediaHandlerFactory {
+
+ private static $overrides = [
+ 'image/svg+xml' => MockSvgHandler::class,
+ 'image/vnd.djvu' => MockDjVuHandler::class,
+ 'application/ogg' => MockOggHandler::class,
+ ];
+
+ public function __construct() {
+ // override parent
+ }
+
+ protected function getHandlerClass( $type ) {
+ if ( isset( self::$overrides[$type] ) ) {
+ return self::$overrides[$type];
+ }
+
+ return MockBitmapHandler::class;
+ }
+
+}
$this->assertFalse( $uncerealized instanceof __PHP_Incomplete_Class,
"unserialize() can load classes case-insensitively." );
}
+
+ function testAutoloadOrder() {
+ $path = realpath( __DIR__ . '/../../..' );
+ $oldAutoload = file_get_contents( $path . '/autoload.php' );
+ $generator = new AutoloadGenerator( $path, 'local' );
+ $generator->initMediaWikiDefault();
+ $newAutoload = $generator->getAutoload( 'maintenance/generateLocalAutoload.php' );
+
+ $this->assertEquals( $oldAutoload, $newAutoload, 'autoload.php does not match' .
+ ' output of generateLocalAutoload.php script.' );
+ }
}
class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite {
public function __construct() {
parent::__construct();
+
$paths = [];
+ // Autodiscover extension unit tests
+ $registry = ExtensionRegistry::getInstance();
+ foreach ( $registry->getAllThings() as $info ) {
+ $paths[] = dirname( $info['path'] ) . '/tests/phpunit';
+ }
// Extensions can return a list of files or directories
Hooks::run( 'UnitTestsList', [ &$paths ] );
- foreach ( $paths as $path ) {
+ foreach ( array_unique( $paths ) as $path ) {
if ( is_dir( $path ) ) {
// If the path is a directory, search for test cases.
// @since 1.24
$fileIterator = new File_Iterator_Facade();
$matchingFiles = $fileIterator->getFilesAsArray( $path, $suffixes );
$this->addTestFiles( $matchingFiles );
- } else {
+ } elseif ( file_exists( $path ) ) {
// Add a single test case or suite class
$this->addTestFile( $path );
}