* $wgResourceModuleSkinStyles no longer supports per-module local or remote paths. They
can only be set for the entire skin.
* Removed global function swap(). (deprecated since 1.24)
-* Deprecated the ".php5" file extension entry points. Refer to the ".php" files
- instead. If you want ".php5" URLs to continue to work, set up redirects. In
- Apache, this can be done by enabling mod_rewrite and adding the following
- rules to your configuration:
+* Deprecated the ".php5" file extension entry points and the $wgScriptExtension
+ configuration variable. Refer to the ".php" files instead. If you want
+ ".php5" URLs to continue to work, set up redirects. In Apache, this can be
+ done by enabling mod_rewrite and adding the following rules to your
+ configuration:
RewriteEngine On
RewriteBase /
"ext-iconv": "*",
"leafo/lessphp": "0.5.0",
"liuggio/statsd-php-client": "1.0.12",
- "oojs/oojs-ui": "0.11.1",
+ "oojs/oojs-ui": "0.11.2",
"php": ">=5.3.3",
"psr/log": "1.0.0",
"wikimedia/cdb": "1.0.1",
+ "wikimedia/assert": "0.2.2",
"wikimedia/composer-merge-plugin": "1.0.0",
"wikimedia/utfnormal": "1.0.2",
"zordius/lightncandy": "0.18"
( strpos( PHP_SAPI, 'isapi' ) === false );
/**
- * The extension to append to script names by default. This can either be .php
- * or .php5.
+ * The extension to append to script names by default.
+ *
+ * Some hosting providers used PHP 4 for *.php files, and PHP 5 for *.php5.
+ * This variable was provided to support those providers.
*
- * Some hosting providers use PHP 4 for *.php files, and PHP 5 for *.php5. This
- * variable is provided to support those providers.
* @since 1.11
+ * @deprecated since 1.25; support for '.php5' is being phased out of MediaWiki
+ * proper. Backward-compatibility can be maintained by configuring your web
+ * server to rewrite URLs. See RELEASE-NOTES for details.
*/
$wgScriptExtension = '.php';
$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
-if ( defined( 'MW_ENTRY_PHP5' ) ) {
- wfWarn( 'The ".php5" entry point files are deprecated. Use ".php" instead.' );
+if ( $wgScriptExtension !== '.php' || defined( 'MW_ENTRY_PHP5' ) ) {
+ wfWarn( 'Script extensions other than ".php" are deprecated.' );
}
if ( $wgCanonicalServer === false ) {
* @since 1.25
*/
public function touch() {
- global $wgMemc;
-
$this->load();
if ( $this->mId ) {
+ $this->mQuickTouched = $this->newTouchedTimestamp();
+
+ $cache = ObjectCache::getMainWANInstance();
$key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
- $timestamp = $this->newTouchedTimestamp();
- $wgMemc->set( $key, $timestamp );
- $this->mQuickTouched = $timestamp;
+ $cache->touchCheckKey( $key );
}
}
* @return string TS_MW Timestamp
*/
public function getTouched() {
- global $wgMemc;
-
$this->load();
if ( $this->mId ) {
if ( $this->mQuickTouched === null ) {
+ $cache = ObjectCache::getMainWANInstance();
$key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
- $timestamp = $wgMemc->get( $key );
+
+ $timestamp = $cache->getCheckKeyTime( $key );
if ( $timestamp ) {
- $this->mQuickTouched = $timestamp;
+ $this->mQuickTouched = wfTimestamp( TS_MW, $timestamp );
} else {
# Set the timestamp to get HTTP 304 cache hits
$this->touch();
class WebRequest {
protected $data, $headers = array();
+ /**
+ * Flag to make WebRequest::getHeader return an array of values.
+ * @since 1.26
+ */
+ const GETHEADER_LIST = 1;
+
/**
* Lazy-init response object
* @var WebResponse
}
/**
- * Get a request header, or false if it isn't set
- * @param string $name Case-insensitive header name
+ * Get a request header, or false if it isn't set.
*
- * @return string|bool False on failure
- */
- public function getHeader( $name ) {
+ * @param string $name Case-insensitive header name
+ * @param int $flags Bitwise combination of:
+ * WebRequest::GETHEADER_LIST Treat the header as a comma-separated list
+ * of values, as described in RFC 2616 § 4.2.
+ * (since 1.26).
+ * @return string|array|bool False if header is unset; otherwise the
+ * header value(s) as either a string (the default) or an array, if
+ * WebRequest::GETHEADER_LIST flag was set.
+ */
+ public function getHeader( $name, $flags = 0 ) {
$this->initHeaders();
$name = strtoupper( $name );
- if ( isset( $this->headers[$name] ) ) {
- return $this->headers[$name];
- } else {
+ if ( !isset( $this->headers[$name] ) ) {
return false;
}
+ $value = $this->headers[$name];
+ if ( $flags & self::GETHEADER_LIST ) {
+ $value = array_map( 'trim', explode( ',', $value ) );
+ }
+ return $value;
}
/**
return $this->protocol;
}
- /**
- * @param string $name The name of the header to get (case insensitive).
- * @return bool|string
- */
- public function getHeader( $name ) {
- $name = strtoupper( $name );
- return isset( $this->headers[$name] ) ? $this->headers[$name] : false;
+ private function initHeaders() {
+ return;
}
/**
return $this->base->checkSessionCookie();
}
- public function getHeader( $name ) {
- return $this->base->getHeader( $name );
+ public function getHeader( $name, $flags = 0 ) {
+ return $this->base->getHeader( $name, $flags );
}
public function getAllHeaders() {
$result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
}
+ if ( isset( $prop['jsconfigvars'] ) ) {
+ $result_array['jsconfigvars'] = $this->formatJsConfigVars( $p_result->getJsConfigVars() );
+ }
+
+ if ( isset( $prop['encodedjsconfigvars'] ) ) {
+ $result_array['encodedjsconfigvars'] = FormatJson::encode(
+ $p_result->getJsConfigVars(), false, FormatJson::ALL_OK
+ );
+ $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
+ }
+
if ( isset( $prop['indicators'] ) ) {
$result_array['indicators'] = (array)$p_result->getIndicators();
ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
return $result;
}
+ private function formatJsConfigVars( $vars, $forceHash = true ) {
+ // Process subarrays and determine if this is a JS [] or {}
+ $hash = $forceHash;
+ $maxKey = -1;
+ $bools = array();
+ foreach ( $vars as $k => $v ) {
+ if ( is_array( $v ) || is_object( $v ) ) {
+ $vars[$k] = $this->formatJsConfigVars( (array)$v, false );
+ } elseif ( is_bool( $v ) ) {
+ // Better here to use real bools even in BC formats
+ $bools[] = $k;
+ }
+ if ( is_string( $k ) ) {
+ $hash = true;
+ } elseif ( $k > $maxKey ) {
+ $maxKey = $k;
+ }
+ }
+ if ( !$hash && $maxKey !== count( $vars ) - 1 ) {
+ $hash = true;
+ }
+
+ // Get the list of keys we actually care about. Unfortunately, we can't support
+ // certain keys that conflict with ApiResult metadata.
+ $keys = array_diff( array_keys( $vars ), array(
+ ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
+ ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
+ ) );
+
+ // Set metadata appropriately
+ if ( $hash ) {
+ return array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => $keys,
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ ) + $vars;
+ } else {
+ return array(
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'value',
+ ) + $vars;
+ }
+ }
+
private function setIndexedTagNames( &$array, $mapping ) {
foreach ( $mapping as $key => $name ) {
if ( isset( $array[$key] ) ) {
'headitems',
'headhtml',
'modules',
+ 'jsconfigvars',
+ 'encodedjsconfigvars',
'indicators',
'iwlinks',
'wikitext',
'properties',
'limitreportdata',
'limitreporthtml',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'pst' => false,
'onlypst' => false,
"apihelp-parse-param-pageid": "Parse the content of this page. Overrides <var>$1page</var>.",
"apihelp-parse-param-redirects": "If <var>$1page</var> or <var>$1pageid</var> is set to a redirect, resolve it.",
"apihelp-parse-param-oldid": "Parse the content of this revision. Overrides <var>$1page</var> and <var>$1pageid</var>.",
- "apihelp-parse-param-prop": "Which pieces of information to get:\n;text:Gives the parsed text of the wikitext.\n;langlinks:Gives the language links in the parsed wikitext.\n;categories:Gives the categories in the parsed wikitext.\n;categorieshtml:Gives the HTML version of the categories.\n;links:Gives the internal links in the parsed wikitext.\n;templates:Gives the templates in the parsed wikitext.\n;images:Gives the images in the parsed wikitext.\n;externallinks:Gives the external links in the parsed wikitext.\n;sections:Gives the sections in the parsed wikitext.\n;revid:Adds the revision ID of the parsed page.\n;displaytitle:Adds the title of the parsed wikitext.\n;headitems:Gives items to put in the <head> of the page.\n;headhtml:Gives parsed <head> of the page.\n;modules:Gives the ResourceLoader modules used on the page.\n;indicators:Gives the HTML of page status indicators used on the page.\n;iwlinks:Gives interwiki links in the parsed wikitext.\n;wikitext:Gives the original wikitext that was parsed.\n;properties:Gives various properties defined in the parsed wikitext.\n;limitreportdata:Gives the limit report in a structured way. Gives no data, when $1disablepp is set.\n;limitreporthtml:Gives the HTML version of the limit report. Gives no data, when $1disablepp is set.",
+ "apihelp-parse-param-prop": "Which pieces of information to get:",
+ "apihelp-parse-paramvalue-prop-text": "Gives the parsed text of the wikitext.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Gives the language links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categories": "Gives the categories in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Gives the HTML version of the categories.",
+ "apihelp-parse-paramvalue-prop-links": "Gives the internal links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-templates": "Gives the templates in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-images": "Gives the images in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Gives the external links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-sections": "Gives the sections in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-revid": "Adds the revision ID of the parsed page.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Adds the title of the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-headitems": "Gives items to put in the <code><head></code> of the page.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Gives parsed <code><head></code> of the page.",
+ "apihelp-parse-paramvalue-prop-modules": "Gives the ResourceLoader modules used on the page.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Gives the JavaScript configuration variables specific to the page.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Gives the JavaScript configuration variables specific to the page as a JSON string.",
+ "apihelp-parse-paramvalue-prop-indicators": "Gives the HTML of page status indicators used on the page.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Gives interwiki links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Gives the original wikitext that was parsed.",
+ "apihelp-parse-paramvalue-prop-properties": "Gives various properties defined in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Gives the limit report in a structured way. Gives no data, when <var>$1disablepp</var> is set.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Gives the HTML version of the limit report. Gives no data, when <var>$1disablepp</var> is set.",
"apihelp-parse-param-pst": "Do a pre-save transform on the input before parsing it. Only valid when used with text.",
"apihelp-parse-param-onlypst": "Do a pre-save transform (PST) on the input, but don't parse it. Returns the same wikitext, after a PST has been applied. Only valid when used with <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Includes language links supplied by extensions (for use with <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-pageid": "Analizar o contido desta páxina. Ignora <var>$1page</var>.",
"apihelp-parse-param-redirects": "Se <var>$1page</var> ou <var>$1pageid</var> apuntar a unha redirección, resólvea.",
"apihelp-parse-param-oldid": "Analizar o contido desta revisión. Ignora <var>$1page</var> e <var>$1pageid</var>.",
- "apihelp-parse-param-prop": "Que información obter:\n;text:Devolve o texto analizado do texto wiki.\n;langlinks:Devolve as ligazóns de idioma do texto wiki analizado\n;categories:Devolve as categorías do texto wiki analizado.\n;categorieshtml:Devolve a versión HTML das categorías.\n;links:Devolve as ligazóns internas do texto wiki analizado.\n;templates:Devolve os modelos no texto wiki analizado.\n;images:Devolve as imaxes no texto wiki analizado.\n;externallinks:Devolve as ligazóns externas no texto wiki analizado.\n;sections:Devolve as seccións no texto wiki analizado.\n;revid:Engade o identificador da revisión da páxina analizada.\n;displaytitle:Engade o título do texto wiki analizado.\n;headitems:Devolve os obxectos a poñer na <cabeceira> da páxina\n;headhtml:Devolve a <cabeceira> analizada da páxina.\n;modules:Devolve os módulos ResourceLoader usados na páxina.\n;indicators:Devolve o HTML dos indicadores de estado usados na páxina.\n;iwlinks:Devolve as ligazóns interwiki analizados no texto wiki.\n;wikitext:Devolve o texto wiki orixinal que foi analizado.\n;properties:Devolve varias propiedades definidas no texto wiki analizado.\n;limitreportdata:Devolve o informe de límite de forma estruturada. Non devolve datos cando está activo $1disablepp.\n;limitreporthtml:Devolve a versión HTML do informe de límite. Non devolve datos cando está activo $1disablepp.",
+ "apihelp-parse-param-prop": "Que información obter:",
+ "apihelp-parse-paramvalue-prop-text": "Devolve o texto analizado do texto wiki.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Devolve as interwikis do texto analizado.",
+ "apihelp-parse-paramvalue-prop-categories": "Devolve as categoría do texto analizado.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Devolve a versión HTML das categorías.",
+ "apihelp-parse-paramvalue-prop-links": "Devolve as ligazóns internas do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-templates": "Devolve os modelos do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-images": "Devolve as imaxes do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Devolve as ligazóns externas no texto wiki analizado.",
+ "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-headhtml": "Devolve <code><cabeceira></code> analizada da páxina.",
+ "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina.",
+ "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-parse-paramvalue-prop-wikitext": "Devolve o texto wiki orixinal que foi analizado.",
+ "apihelp-parse-paramvalue-prop-properties": "Obter varias propiedades definidas no texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Devolve o informe de límite de forma estruturada. Non devolve datos cando <var>$1disablepp</var> está fixado.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Devolve a versión HTML do informe de límite. Non devolve datos cando <var>$1disablepp</var> está fixado.",
"apihelp-parse-param-pst": "Fai unha transformación antes de gardar a entrada antes de analizala. Válida unicamente para usar con texto.",
"apihelp-parse-param-onlypst": "Facer unha transformación antes de gardar (PST) a entrada, pero sen analizala. Devolve o mesmo wikitexto, despois de que a PST foi aplicada. Só válida cando se usa con <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Inclúe ligazóns de idioma proporcionadas polas extensións (para usar con <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-pageid": "{{doc-apihelp-param|parse|pageid}}",
"apihelp-parse-param-redirects": "{{doc-apihelp-param|parse|redirects}}",
"apihelp-parse-param-oldid": "{{doc-apihelp-param|parse|oldid}}",
- "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop}}",
+ "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop|paramvalues=1}}",
+ "apihelp-parse-paramvalue-prop-text": "{{doc-apihelp-paramvalue|parse|prop|text}}",
+ "apihelp-parse-paramvalue-prop-langlinks": "{{doc-apihelp-paramvalue|parse|prop|langlinks}}",
+ "apihelp-parse-paramvalue-prop-categories": "{{doc-apihelp-paramvalue|parse|prop|categories}}",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "{{doc-apihelp-paramvalue|parse|prop|categorieshtml}}",
+ "apihelp-parse-paramvalue-prop-links": "{{doc-apihelp-paramvalue|parse|prop|links}}",
+ "apihelp-parse-paramvalue-prop-templates": "{{doc-apihelp-paramvalue|parse|prop|templates}}",
+ "apihelp-parse-paramvalue-prop-images": "{{doc-apihelp-paramvalue|parse|prop|images}}",
+ "apihelp-parse-paramvalue-prop-externallinks": "{{doc-apihelp-paramvalue|parse|prop|externallinks}}",
+ "apihelp-parse-paramvalue-prop-sections": "{{doc-apihelp-paramvalue|parse|prop|sections}}",
+ "apihelp-parse-paramvalue-prop-revid": "{{doc-apihelp-paramvalue|parse|prop|revid}}",
+ "apihelp-parse-paramvalue-prop-displaytitle": "{{doc-apihelp-paramvalue|parse|prop|displaytitle}}",
+ "apihelp-parse-paramvalue-prop-headitems": "{{doc-apihelp-paramvalue|parse|prop|headitems}}",
+ "apihelp-parse-paramvalue-prop-headhtml": "{{doc-apihelp-paramvalue|parse|prop|headhtml}}",
+ "apihelp-parse-paramvalue-prop-modules": "{{doc-apihelp-paramvalue|parse|prop|modules}}",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|jsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|encodedjsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-indicators": "{{doc-apihelp-paramvalue|parse|prop|indicators}}",
+ "apihelp-parse-paramvalue-prop-iwlinks": "{{doc-apihelp-paramvalue|parse|prop|iwlinks}}",
+ "apihelp-parse-paramvalue-prop-wikitext": "{{doc-apihelp-paramvalue|parse|prop|wikitext}}",
+ "apihelp-parse-paramvalue-prop-properties": "{{doc-apihelp-paramvalue|parse|prop|properties}}",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "{{doc-apihelp-paramvalue|parse|prop|limitreportdata}}",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "{{doc-apihelp-paramvalue|parse|prop|limitreporthtml}}",
"apihelp-parse-param-pst": "{{doc-apihelp-param|parse|pst}}",
"apihelp-parse-param-onlypst": "{{doc-apihelp-param|parse|onlypst}}",
"apihelp-parse-param-effectivelanglinks": "{{doc-apihelp-param|parse|effectivelanglinks}}",
"apihelp-parse-param-pageid": "解析此页的内容。覆盖<var>$1page</var>。",
"apihelp-parse-param-redirects": "如果<var>$1page</var>或<var>$1pageid</var>被设置为一个重定向,则解析它。",
"apihelp-parse-param-oldid": "解析该修订版本的内容。覆盖<var>$1page</var>和<var>$1pageid</var>。",
+ "apihelp-parse-paramvalue-prop-modules": "提供在页面中使用的ResourceLoader模块。",
"apihelp-parse-param-pst": "在解析输入前,对输入做一次保存前变换处理。仅当使用文本时有效。",
"apihelp-parse-param-effectivelanglinks": "包含由扩展提供的语言链接(用于与<kbd>$1prop=langlinks</kbd>一起使用)。",
"apihelp-parse-param-section": "只检索此段数的内容,或只当<kbd>new</kbd>生成新的段落时检索。\n\n<kbd>new</kbd>段落只当指定<var>text</var>时受尊重。",
* @since 1.25
*/
public static function listExtensionActivatedTags() {
- $cache = ObjectCache::getMainWANInstance();
-
- $key = wfMemcKey( 'active-tags' );
- $tags = $cache->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- // ask extensions which tags they consider active
- $extensionActive = array();
- Hooks::run( 'ChangeTagsListActive', array( &$extensionActive ) );
-
- // Short-term caching.
- $cache->set( $key, $extensionActive, 300 );
-
- return $extensionActive;
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'active-tags' ),
+ function() {
+ // Ask extensions which tags they consider active
+ $extensionActive = array();
+ Hooks::run( 'ChangeTagsListActive', array( &$extensionActive ) );
+ return $extensionActive;
+ },
+ 300,
+ array( wfMemcKey( 'active-tags' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
* @since 1.25
*/
public static function listExplicitlyDefinedTags() {
- $cache = ObjectCache::getMainWANInstance();
-
- $key = wfMemcKey( 'valid-tags-db' );
- $tags = $cache->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- $emptyTags = array();
-
- // Some DB stuff
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'valid_tag', 'vt_tag', array(), __METHOD__ );
- foreach ( $res as $row ) {
- $emptyTags[] = $row->vt_tag;
- }
-
- $emptyTags = array_filter( array_unique( $emptyTags ) );
-
- // Short-term caching.
- $cache->set( $key, $emptyTags, 300 );
-
- return $emptyTags;
+ $fname = __METHOD__;
+
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'valid-tags-db' ),
+ function() use ( $fname ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $tags = $dbr->selectFieldValues(
+ 'valid_tag', 'vt_tag', array(), $fname );
+
+ return array_filter( array_unique( $tags ) );
+ },
+ 300,
+ array( wfMemcKey( 'valid-tags-db' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
* @since 1.25
*/
public static function listExtensionDefinedTags() {
- $cache = ObjectCache::getMainWANInstance();
-
- $key = wfMemcKey( 'valid-tags-hook' );
- $tags = $cache->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- $emptyTags = array();
- Hooks::run( 'ListDefinedTags', array( &$emptyTags ) );
- $emptyTags = array_filter( array_unique( $emptyTags ) );
-
- // Short-term caching.
- $cache->set( $key, $emptyTags, 300 );
-
- return $emptyTags;
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'valid-tags-hook' ),
+ function() {
+ $tags = array();
+ Hooks::run( 'ListDefinedTags', array( &$tags ) );
+ return array_filter( array_unique( $tags ) );
+ },
+ 300,
+ array( wfMemcKey( 'valid-tags-hook' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
public static function purgeTagCacheAll() {
$cache = ObjectCache::getMainWANInstance();
- $cache->delete( wfMemcKey( 'active-tags' ) );
- $cache->delete( wfMemcKey( 'valid-tags-db' ) );
- $cache->delete( wfMemcKey( 'valid-tags-hook' ) );
+ $cache->touchCheckKey( wfMemcKey( 'active-tags' ) );
+ $cache->touchCheckKey( wfMemcKey( 'valid-tags-db' ) );
+ $cache->touchCheckKey( wfMemcKey( 'valid-tags-hook' ) );
self::purgeTagUsageCache();
}
* @return array Array of string => int
*/
public static function tagUsageStatistics() {
- $cache = ObjectCache::getMainWANInstance();
-
- $key = wfMemcKey( 'change-tag-statistics' );
- $stats = $cache->get( $key );
- if ( $stats ) {
- return $stats;
- }
-
- $out = array();
+ $fname = __METHOD__;
+
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'change-tag-statistics' ),
+ function() use ( $fname ) {
+ $out = array();
+
+ $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+ $res = $dbr->select(
+ 'change_tag',
+ array( 'ct_tag', 'hitcount' => 'count(*)' ),
+ array(),
+ $fname,
+ array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' )
+ );
- $dbr = wfGetDB( DB_SLAVE, 'vslow' );
- $res = $dbr->select(
- 'change_tag',
- array( 'ct_tag', 'hitcount' => 'count(*)' ),
- array(),
- __METHOD__,
- array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' )
+ foreach ( $res as $row ) {
+ $out[$row->ct_tag] = $row->hitcount;
+ }
+
+ foreach ( ChangeTags::listDefinedTags() as $tag ) {
+ if ( !isset( $out[$tag] ) ) {
+ $out[$tag] = 0;
+ }
+ }
+
+ return $out;
+ },
+ 300,
+ array( wfMemcKey( 'change-tag-statistics' ) ),
+ array( 'lockTSE' => INF )
);
-
- foreach ( $res as $row ) {
- $out[$row->ct_tag] = $row->hitcount;
- }
- foreach ( self::listDefinedTags() as $tag ) {
- if ( !isset( $out[$tag] ) ) {
- $out[$tag] = 0;
- }
- }
-
- // Cache for a very short time
- $cache->set( $key, $out, 300 );
-
- return $out;
}
/**
* @return bool
*/
function loadFromCache() {
- global $wgMemc;
-
$this->dataLoaded = false;
$this->extraDataLoaded = false;
$key = $this->getCacheKey();
if ( !$key ) {
-
return false;
}
- $cachedValues = $wgMemc->get( $key );
+ $cache = ObjectCache::getMainWANInstance();
+ $cachedValues = $cache->get( $key );
// Check if the key existed and belongs to this version of MediaWiki
- if ( isset( $cachedValues['version'] ) && $cachedValues['version'] == MW_FILE_VERSION ) {
+ if ( is_array( $cachedValues ) && $cachedValues['version'] == MW_FILE_VERSION ) {
wfDebug( "Pulling file metadata from cache key $key\n" );
$this->fileExists = $cachedValues['fileExists'];
if ( $this->fileExists ) {
* Save the file metadata to memcached
*/
function saveToCache() {
- global $wgMemc;
-
$this->load();
- $key = $this->getCacheKey();
+ $key = $this->getCacheKey();
if ( !$key ) {
return;
}
$fields = $this->getCacheFields( '' );
- $cache = array( 'version' => MW_FILE_VERSION );
- $cache['fileExists'] = $this->fileExists;
+ $cacheVal = array( 'version' => MW_FILE_VERSION );
+ $cacheVal['fileExists'] = $this->fileExists;
if ( $this->fileExists ) {
foreach ( $fields as $field ) {
- $cache[$field] = $this->$field;
+ $cacheVal[$field] = $this->$field;
}
}
// If the cache value gets to large it will not fit in memcached and nothing will
// get cached at all, causing master queries for any file access.
foreach ( $this->getLazyCacheFields( '' ) as $field ) {
- if ( isset( $cache[$field] ) && strlen( $cache[$field] ) > 100 * 1024 ) {
- unset( $cache[$field] ); // don't let the value get too big
+ if ( isset( $cacheVal[$field] ) && strlen( $cacheVal[$field] ) > 100 * 1024 ) {
+ unset( $cacheVal[$field] ); // don't let the value get too big
}
}
// Cache presence for 1 week and negatives for 1 day
- $wgMemc->set( $key, $cache, $this->fileExists ? 86400 * 7 : 86400 );
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->set( $key, $cacheVal, $this->fileExists ? 86400 * 7 : 86400 );
+ }
+
+ /**
+ * Purge the file object/metadata cache
+ */
+ function invalidateCache() {
+ $this->load();
+
+ $key = $this->getCacheKey();
+ if ( !$key ) {
+ return;
+ }
+
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->delete( $key );
}
/**
__METHOD__
);
- $this->saveToCache();
+ $this->invalidateCache();
$this->unlock(); // done
* Refresh metadata in memcached, but don't touch thumbnails or squid
*/
function purgeMetadataCache() {
- $this->loadFromDB( File::READ_LATEST );
- $this->saveToCache();
+ $this->invalidateCache();
}
/**
# to after $wikiPage->doEdit has been called.
$dbw->commit( __METHOD__ );
- # Save to memcache.
- # We shall not saveToCache before the commit since otherwise
- # in case of a rollback there is an usable file from memcached
- # which in fact doesn't really exist (bug 24978)
- $this->saveToCache();
+ # Update memcache after the commit
+ $this->invalidateCache();
if ( $exists ) {
# Invalidate the cache for the description page
array( 'img_sha1' => $this->sha1 ),
array( 'img_name' => $this->getName() ),
__METHOD__ );
- $this->saveToCache();
+ $this->invalidateCache();
}
$this->unlock(); // done
}
$msg = $job->toString() . " STARTING";
- $this->logger->info( $msg );
+ $this->logger->debug( $msg );
$this->debugCallback( $msg );
// Run the job...
class RefreshLinksJob extends Job {
const PARSE_THRESHOLD_SEC = 1.0;
+ const CLOCK_FUDGE = 10;
+
function __construct( $title, $params = '' ) {
parent::__construct( 'refreshLinks', $title, $params );
// A separate type is used just for cascade-protected backlinks
$parserOutput = false;
$parserOptions = $page->makeParserOptions( 'canonical' );
- // If page_touched changed after this root job (with a good slave lag skew factor),
- // then it is likely that any views of the pages already resulted in re-parses which
- // are now in cache. This can be reused to avoid expensive parsing in some cases.
+ // If page_touched changed after this root job, then it is likely that
+ // any views of the pages already resulted in re-parses which are now in
+ // cache. The cache can be reused to avoid expensive parsing in some cases.
if ( isset( $this->params['rootJobTimestamp'] ) ) {
- $skewedTimestamp = wfTimestamp( TS_UNIX, $this->params['rootJobTimestamp'] ) + 5;
- if ( $page->getLinksTimestamp() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
+ $opportunistic = !empty( $this->params['isOpportunistic'] );
+
+ $skewedTimestamp = $this->params['rootJobTimestamp'];
+ if ( $opportunistic ) {
+ // Neither clock skew nor DB snapshot/slave lag matter much for such
+ // updates; focus on reusing the (often recently updated) cache
+ } else {
+ // For transclusion updates, the template changes must be reflected
+ $skewedTimestamp = wfTimestamp( TS_MW,
+ wfTimestamp( TS_UNIX, $skewedTimestamp ) + self::CLOCK_FUDGE
+ );
+ }
+
+ if ( $page->getLinksTimestamp() > $skewedTimestamp ) {
// Something already updated the backlinks since this job was made
return true;
}
- if ( $page->getTouched() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
+
+ if ( $page->getTouched() >= $skewedTimestamp || $opportunistic ) {
+ // Something bumped page_touched since this job was made
+ // or the cache is otherwise suspected to be up-to-date
$parserOutput = ParserCache::singleton()->getDirty( $page, $parserOptions );
- if ( $parserOutput && $parserOutput->getCacheTime() <= $skewedTimestamp ) {
+ if ( $parserOutput && $parserOutput->getCacheTime() < $skewedTimestamp ) {
$parserOutput = false; // too stale
}
}
}
+
// Fetch the current revision and parse it if necessary...
if ( $parserOutput == false ) {
$start = microtime( true );
* @file
* @ingroup Cache
*/
+use Wikimedia\Assert\Assert;
/**
* Handles a simple LRU key/value map with a maximum number of entries
* @throws Exception When $maxCacheKeys is not an int or =< 0.
*/
public function __construct( $maxKeys ) {
- if ( !is_int( $maxKeys ) || $maxKeys < 1 ) {
- throw new Exception( __METHOD__ . " must be given an integer and >= 1" );
- }
+ Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
+ Assert::parameter( $maxKeys >= 1, '$maxKeys', 'must be >= 1' );
+
$this->maxCacheKeys = $maxKeys;
}
* @file
* @ingroup Cache
*/
+use Wikimedia\Assert\Assert;
/**
* Handles per process caching of items
* @throws UnexpectedValueException
*/
public function resize( $maxKeys ) {
- if ( !is_int( $maxKeys ) || $maxKeys < 1 ) {
- throw new UnexpectedValueException( __METHOD__ . " must be given an integer >= 1" );
- }
+ Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
+ Assert::parameter( $maxKeys >= 1, '$maxKeys', 'must be >= 1' );
+
$this->maxCacheKeys = $maxKeys;
while ( count( $this->cache ) > $this->maxCacheKeys ) {
reset( $this->cache );
* @ingroup Media
*/
class DjVuHandler extends ImageHandler {
+ const EXPENSIVE_SIZE_LIMIT = 10485760; // 10MiB
+
/**
* @return bool
*/
return true;
}
+ /**
+ * True if creating thumbnails from the file is large or otherwise resource-intensive.
+ * @param File $file
+ * @return bool
+ */
+ public function isExpensiveToThumbnail( $file ) {
+ return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
+ }
+
/**
* @param File $file
* @return bool
// Check if the last link refresh was before page_touched
if ( $this->getLinksTimestamp() < $this->getTouched() ) {
+ $params['isOpportunistic'] = true;
+ $params['rootJobTimestamp'] = $parserOutput->getCacheTime();
+
JobQueueGroup::singleton()->push( EnqueueJob::newFromLocalJobs(
new JobSpecification( 'refreshLinks', $params,
array( 'removeDuplicates' => true ), $this->mTitle )
$this->logger->info( "Detected no transaction for '$name' - out of sync." );
return;
}
+
+ $slow = false;
+
// Warn if too much time was spend writing...
if ( $writeTime > $this->expect['writeQueryTime'] ) {
$this->reportExpectationViolated( 'writeQueryTime',
"[transaction $id writes to {$server} ({$db})]" );
+ $slow = true;
}
// Fill in the last non-query period...
$lastQuery = end( $this->dbTrxMethodTimes[$name] );
}
}
// Check for any slow queries or non-query periods...
- $slow = false;
foreach ( $this->dbTrxMethodTimes[$name] as $info ) {
$elapsed = ( $info[2] - $info[1] );
if ( $elapsed >= $this->dbLockThreshold ) {
if ( $this->tryRespondLastModified( $context, $ts ) ) {
return false; // output handled (buffers cleared)
}
+ // Send content type and cache headers
+ $this->sendResponseHeaders( $context, $ts, false );
+ $response = $fileCache->fetchText();
// Capture any PHP warnings from the output buffer and append them to the
// response in a comment if we're in debug mode.
if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
- $response = "/*\n$warnings\n*/\n" . $response;
+ $response = self::makeComment( $warnings ) . $response;
}
- // Send content type and cache headers
- $this->sendResponseHeaders( $context, $ts, false );
- $response = $fileCache->fetchText();
// Remove the output buffer and output the response
ob_end_clean();
echo $response . "\n/* Cached {$ts} */";
* @license GPL 2+
* @author Daniel Kinzler
*/
+use Wikimedia\Assert\Assert;
/**
* Represents a page (or page fragment) title within %MediaWiki.
* @throws InvalidArgumentException
*/
public function __construct( $namespace, $dbkey, $fragment = '' ) {
- if ( !is_int( $namespace ) ) {
- throw new InvalidArgumentException( '$namespace must be an integer' );
- }
-
- if ( !is_string( $dbkey ) ) {
- throw new InvalidArgumentException( '$dbkey must be a string' );
- }
+ Assert::parameterType( 'integer', $namespace, '$namespace' );
+ Assert::parameterType( 'string', $dbkey, '$dbkey' );
+ Assert::parameterType( 'string', $fragment, '$fragment' );
// Sanity check, no full validation or normalization applied here!
- if ( preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ) ) {
- throw new InvalidArgumentException( '$dbkey must be a valid DB key: ' . $dbkey );
- }
-
- if ( !is_string( $fragment ) ) {
- throw new InvalidArgumentException( '$fragment must be a string' );
- }
-
- if ( $dbkey === '' ) {
- throw new InvalidArgumentException( '$dbkey must not be empty' );
- }
+ Assert::parameter( !preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ), '$dbkey', 'invalid DB key' );
+ Assert::parameter( $dbkey !== '', '$dbkey', 'should not be empty' );
$this->namespace = $namespace;
$this->dbkey = $dbkey;
* @file
* @author Aaron Schulz
*/
+use Wikimedia\Assert\Assert;
/**
* Class for getting statistically unique IDs
* @throws MWException
*/
public static function newTimestampedUID88( $base = 10 ) {
- if ( !is_integer( $base ) || $base > 36 || $base < 2 ) {
- throw new MWException( "Base must an integer be between 2 and 36" );
- }
+ Assert::parameterType( 'integer', $base, '$base' );
+ Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
+ Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
+
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile88', 1, 1024 );
* @throws MWException
*/
public static function newTimestampedUID128( $base = 10 ) {
- if ( !is_integer( $base ) || $base > 36 || $base < 2 ) {
- throw new MWException( "Base must be an integer between 2 and 36" );
- }
+ Assert::parameterType( 'integer', $base, '$base' );
+ Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
+ Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
+
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile128', 16384, 1048576 );
"title-invalid-utf8": "Запытаная назва старонкі ўтрымлівае няслушныя сымбалі UTF-8.",
"title-invalid-interwiki": "Назва ўтрымлівае інтэрвікі-спасылку",
"title-invalid-talk-namespace": "Запытаная назва старонкі адпавядае старонцы абмеркаваньня, якая ня можа існаваць.",
+ "title-invalid-characters": "Запытаная назва старонкі ўтрымлівае няслушныя сымбалі: «$1».",
+ "title-invalid-relative": "Назва мае адносны шлях. Адносныя назвы старонак (./, ../) няслушныя, бо яны часта робяцца недаступнымі, калі апрацоўваюцца браўзэрам карыстальніка.",
"perfcached": "Наступныя зьвесткі кэшаваныя і могуць быць састарэлымі. У кэшы {{PLURAL:$1|даступны|даступныя}} ня больш за $1 {{PLURAL:$1|вынік|вынікі|вынікаў}}.",
"perfcachedts": "Наступныя зьвесткі кэшаваныя і апошні раз былі абноўленыя $1. У кэшы {{PLURAL:$4|даступны|даступныя}} ня больш за $4 {{PLURAL:$4|вынік|вынікі|вынікаў}}.",
"querypage-no-updates": "Абнаўленьні гэтай старонкі цяпер адключаныя. Зьвесткі ня будуць абнаўляцца.",
"import-logentry-upload-detail": "$1 {{PLURAL:$1|Version|Versionen}} importiert",
"import-logentry-interwiki-detail": "$1 {{PLURAL:$1|Version|Versionen}} von $2 importiert",
"javascripttest": "JavaScript-Test",
- "javascripttest-pagetext-noframework": "Diese Seite ist JavaSkript-Tests vorbehalten.",
+ "javascripttest-pagetext-noframework": "Diese Seite ist JavaScript-Tests vorbehalten.",
"javascripttest-pagetext-unknownframework": "Unbekanntes Framework „$1“.",
"javascripttest-pagetext-unknownaction": "Unbekannte Aktion „$1“.",
"javascripttest-pagetext-frameworks": "Bitte wähle eine der folgenden Prüfumgebungen aus: $1",
"february-gen": "فوریهٔ",
"march-gen": "مارس",
"april-gen": "آوریل",
- "may-gen": "مهٔ",
+ "may-gen": "مه",
"june-gen": "ژوئن",
"july-gen": "ژوئیهٔ",
"august-gen": "اوت",
"viewsource-title": "$1 forrásának megtekintése",
"actionthrottled": "Művelet megszakítva",
"actionthrottledtext": "A spamek elleni védekezés miatt nem végezheted el a műveletet túl sokszor egy adott időn belül, és te átlépted a megengedett határt. Próbálkozz újra néhány perc múlva.",
- "protectedpagetext": "Ez egy védett lap, így nem végezhető rajta szerkesztés és más tevékenység",
+ "protectedpagetext": "Ez egy védett lap, így nem végezhető rajta szerkesztés és más tevékenység.",
"viewsourcetext": "Megtekintheted és másolhatod a lap forrását:",
"viewyourtext": "Megtekintheted és kimásolhatod a '''saját szerkesztéseidet''' az alábbi lapra:",
"protectedinterface": "Ez a lap a szoftver felületéhez szolgáltat szöveget, és a visszaélések elkerülése miatt le van zárva.",
"disclaimers": "Джууаблылыкъны унамау",
"disclaimerpage": "Project:Джууаблылыкъны унамау",
"edithelp": "Тюрлендириуню юсюнден болушлукъ",
+ "helppage-top-gethelp": "Ангылатыу",
"mainpage": "Баш бет",
"mainpage-description": "Баш бет",
"policy-url": "Project:Джорукъла",
"newpassword": "Şîfreya nû",
"retypenew": "Şîfreya nû careke din binîvîse",
"resetpass_submit": "Şîfreyê pêkbîne û têkeve",
- "changepassword-success": "Şîfreya te hate guherandin! Niha tu tê qeydkirin...",
+ "changepassword-success": "Guhertine şîfreya te serkeftî bû!",
"resetpass_forbidden": "Şîfre nikarin werin guhertin",
"resetpass-submit-loggedin": "Şîfre biguherîne",
"resetpass-submit-cancel": "Betal bike",
"passwordreset-text-one": "Ji bo ji nû ve sazkirina şîfreyê vê formê dagire.",
"passwordreset-legend": "Şîfreyê nû bike",
"passwordreset-username": "Navê bikarhêner:",
+ "passwordreset-domain": "Domain:",
"passwordreset-email": "Navnîşana E-nameyê:",
"passwordreset-emailtitle": "Hûragahiyên hesab li ser {{SITENAME}}",
"passwordreset-emailelement": "Navê bikarhêner:$1\nŞîfreya niha:$2",
"changeemail-newemail": "Navnîşana E-nameya nû:",
"changeemail-none": "(nîne)",
"changeemail-submit": "E-nameyê biguherîne",
+ "resettokens": "Mifteya jê bibe",
+ "resettokens-legend": "Mifteya jê bibe",
"bold_sample": "Nivîsa stûr",
"bold_tip": "Nivîsa stûr",
"italic_sample": "Nivîsa xwehr (îtalîk)",
"histlegend": "Rênîşan: ({{int:cur}}) = cudahiya nav vê û versiyona niha, ({{int:last}}) = cudahiya nav vê û ya berî vê, '''{{int:minoreditletter}}''' = guhertina biçûk",
"history-fieldset-title": "Li dîrokê bigere",
"history-show-deleted": "Tenê yên jêbirî",
- "histfirst": "Kevintirîn",
- "histlast": "Nûtirîn",
+ "histfirst": "kevintirîn",
+ "histlast": "nûtirîn",
"historysize": "({{PLURAL:$1|1 byte|$1 bytes}})",
"historyempty": "(vala)",
"history-feed-title": "Dîroka guhertoyê",
"uploadtext": "Berê tu wêneyên nû bar bikî, ji bo dîtin an vedîtina wêneyên ku ji xwe hene binêre: [[Special:FileList|lîsteya wêneyên barkirî]]. Herwisa wêneyên ku hatine barkirin an jî jê birin li vir dikarî bibînî: [[Special:Log/upload|reşahîya barkirîyan]].\n\nYek ji lînkên jêr ji bo bikarhînana wêne an file'ê di gotarê de bikar bihîne:\n'''<nowiki>[[</nowiki>{{ns:file}}:File.jpg<nowiki>]]</nowiki>''',\n'''<nowiki>[[</nowiki>{{ns:file}}:File.png|alt text<nowiki>]]</nowiki>''',\nanjî ji bo file'ên dengî '''<nowiki>[[</nowiki>{{ns:media}}:File.ogg<nowiki>]]</nowiki>'''",
"upload-permitted": "Cureyên pelan yên tên qebûlkirin: $1.",
"upload-preferred": "Cureyên pelan yên tên xwestin: $1.",
- "upload-prohibited": "Cureyên pelan yên qedexekirî: $1.",
+ "upload-prohibited": "{{PLURAL:$2|Cureyê|Cureyên}} pelan yên qedexekirî: $1.",
"uploadlogpage": "Barkirina belgeyan",
"filename": "Navê pelê",
"filedesc": "Danasîn",
"filetype-unwanted-type": "'''\".$1\"''' formatekî nexastî ye.\nFormat {{PLURAL:$3|yê tê|yên tên}} qebûlkirin {{PLURAL:$3|ev e|ev in}}: $2.",
"filetype-banned-type": "'''\".$1\"''' formatekî qedexe ye.\nFormat {{PLURAL:$3|yê tê|yên tên}} xwestin {{PLURAL:$3|ev e|ev in}}: $2.",
"filetype-missing": "Piştnavê pelê tune (wek \".jpg\").",
+ "filename-tooshort": "Navê dosyeye zêde kurte.",
+ "filetype-banned": "Dosyeyên bi vê cureye hatîye qedexekirin.",
+ "verification-error": "Ev dosye, rastandina dosyeye derbas nekir.",
"unknown-error": "Çewtiyeke nenas pêk hat.",
"large-file": "Mezinbûna pelê bila ji $1 ne mezintir be; ev pel $2 e.",
"emptyfile": "Data'ya barkirî vala ye. Sedemê valabûnê belkî şaşnivîsek di navê data'yê da ye. Xêra xwe seke, ku tu rast dixazê vê data'yê barbikê.",
"protectedpages-noredirect": "Beralîkirinan veşêre",
"protectedpagesempty": "Niha ti rûpelên ku bi vê parametreyê parastî ne, tine ne.",
"protectedpages-page": "Rûpel",
+ "protectedpages-reason": "Sedem",
"protectedpages-unknown-timestamp": "Nenas",
"protectedpages-unknown-performer": "Bikarhênera nenas",
"protectedtitles": "Sernavên parastî",
"no-null-revision": "سی بلگه$1 وانئری خنثی نه راس بکید",
"badtitle": "داسون گن",
"badtitletext": "داسون بلگه حاسته بیه معتور نی،یا یه گل مئن زونی یا مئن ویکی داسون غلطه.\nیه شایت د ور گرته یکی با یا بیشتر کاراکتریا نبوئه سی ای داسونیا وه کار گرته بوئن",
+ "title-invalid-empty": "داسون بلگه حاستنی حالیه یا فقط مینونه دار یه گل نوم یا نومجائه.",
+ "title-invalid-utf8": "داسون بلگه حاستنی مینونه دار یه گل نماجا UTF-8 نامعتوره.",
+ "title-invalid-interwiki": "داسون مینونه دار یه گل هوم پیوند مینجا ویکیه",
+ "title-invalid-talk-namespace": "داسون بلگه حاستنی وه یه گل بلگه چک چنه که نئیش هشاره میکه.",
+ "title-invalid-characters": "داسون بلگه حاستنی مینونه دار یه گل کاراکتر نامعتوره \"1$\" ه.",
+ "title-invalid-relative": "داسون یه گل مسیر هوم دنگ داره.داسون بلگه هوم دنگ(./, ../) نامعتوره، سی یه که ونو د گاتی که دوارته نیئر کاریار وه کار گرته بوئن نمیان د بلگه نمایشت دوارته نیئر.",
+ "title-invalid-magic-tilde": "داسون بلگه حاستنی مینونه دار یه گل نماجا جادویی نامعتوره(<nowiki>~~~</nowiki>).",
+ "title-invalid-too-long": "داسون بلگه حاستنی فره گپه. د حال و بار رازینه کاری UTF-8 انازه وه نواس د $1 بایت گپتر بوئه.",
+ "title-invalid-leading-colon": "داسون بلگه حاستنی مینونه دار یه گل کلون نامعتور د شرو کارشه.",
"perfcached": "رسینه یا نهایی د ویرگه نهونی موکشت بینه و شایت هنی وه هنگوم سازی نبینه.بیشترونه {{جمی:$4|یه گل نتیجه|$4 یه گل نتیجه}} د ویرگه نهونی هان د دسرس.",
"perfcachedts": "رسینه یا نهایی د ویرگه نهونی موکشت بینه و شایت هنی وه هنگوم سازی نبینه.بیشترونه {{جمی:$4|یه گل نتیجه|$4 یه گل نتیجه}} د ویرگه نهونی هان د دسرس.",
"querypage-no-updates": "نبوئه ای بلگه وه هنگوم سازی با.\nرسینه یا ایچه تازه نبیه.",
"import-interwiki-history": "ؤرداشتن ویرگار همه وانئریا سی ای بلگه",
"import-interwiki-templates": "همه چوئه یا",
"import-interwiki-submit": "وامین اوردن",
+ "import-mapping-default": "وامین اوردن جاگه یا پیش فرض",
+ "import-mapping-namespace": "وامین اوردن یه گل نومجا:",
+ "import-mapping-subpage": "وامین اوردن یه گل بلگه چی یه گل زیر بلگه:",
"import-upload-filename": "نوم جانیا:",
"import-comment": "ویر و باور:",
"importtext": "لطف بکیت جانیا نه د ویکی سرچشمه وا هومیاری [[Special:Export|اوزار وه در دئن]] بئریت.\nاوسه ونه د دسگایا خوتو اماییه کاری بکیت و ایچه ونه سوار بکیت.",
"no-null-revision": "Não foi possível criar uma nova revisão nula para a página \"$1\"",
"badtitle": "Título inválido",
"badtitletext": "O título de página solicitado era inválido, vazio, ou a ligação interlínguas estava incorreta.\nTalvez contenha um ou mais caracteres que não podem ser usados em títulos.",
+ "title-invalid-empty": "O título da página solicitada está vazio ou contém apenas o nome de um domínio.",
+ "title-invalid-utf8": "O título da página solicitada contém uma sequência UTF-8 inválida.",
+ "title-invalid-interwiki": "O título contém uma ligação interna",
+ "title-invalid-talk-namespace": "O título da página solicitada refere-se a uma página de discussão que não existe.",
+ "title-invalid-characters": "O título da página solicitada contém carateres inválidos: \"$1\".",
+ "title-invalid-too-long": "O título da página solicitada é demasiado longo. Não deverá ser maior que $1 bytes na codificação UTF-8.",
"perfcached": "Os seguintes dados encontram-se armazenados na ''cache'' e podem não estar atualizados. No máximo {{PLURAL:$1|um resultado é disponível|$1 resultados são disponíveis}} na ''cache''.",
"perfcachedts": "Os seguintes dados encontram-se armazenados na ''cache'' e foram atualizados pela última vez a $1. No máximo {{PLURAL:$4|um resultado está disponível|$4 resultados estão disponíveis}} na ''cache''.",
"querypage-no-updates": "As atualizações estão presentemente desativadas para esta página.\nPor enquanto, os dados aqui presentes não poderão ser atualizados.",
'displaytitle' => array( '1', 'MOSTRATITOLO', 'DISPLAYTITLE' ),
'language' => array( '0', '#LINGUA', '#LANGUAGE:' ),
'numberofadmins' => array( '1', 'NUMEROADMIN', 'NUMBEROFADMINS' ),
- 'special' => array( '0', 'speciale', 'special' ),
'tag' => array( '0', 'etichetta', 'tag' ),
'pagesincategory' => array( '1', 'PAGINEINCAT', 'PAGESINCATEGORY', 'PAGESINCAT' ),
'pagesize' => array( '1', 'DIMENSIONEPAGINA', 'PESOPAGINA', 'PAGESIZE' ),
'fullurl' => array( '0', 'URLEPLOTË', 'FULLURL:' ),
'language' => array( '0', '#GJUHA:', '#LANGUAGE:' ),
'numberofadmins' => array( '1', 'NUMRIIADMINISTRUESVE', 'NUMBEROFADMINS' ),
- 'special' => array( '0', 'speciale', 'special' ),
'hiddencat' => array( '1', '__KATEGORIEFSHEHUR__', '__HIDDENCAT__' ),
'pagesize' => array( '1', 'MADHËSIAEFAQES', 'PAGESIZE' ),
);
* Activate the profiler (assuming $wgProfiler is set)
*/
protected function activateProfiler() {
- global $wgProfiler, $wgTrxProfilerLimits;
+ global $wgProfiler, $wgProfileLimit, $wgTrxProfilerLimits;
$output = $this->getOption( 'profiler' );
if ( !$output ) {
if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
$class = $wgProfiler['class'];
$profiler = new $class(
- array( 'sampling' => 1, 'output' => $output ) + $wgProfiler
+ array( 'sampling' => 1, 'output' => array( $output ) )
+ + $wgProfiler
+ + array( 'threshold' => $wgProfileLimit )
);
$profiler->setTemplated( true );
Profiler::replaceStubInstance( $profiler );
}
function getDbType() {
- /* If we used the class constant PHP4 would give a parser error here */
- return 2; /* Maintenance::DB_ADMIN */
+ return Maintenance::DB_ADMIN;
}
function compatChecks() {
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "George Animal"
+ ]
+ },
+ "ooui-toolgroup-expand": "Bêhtir",
+ "ooui-toolgroup-collapse": "Kêmtir",
+ "ooui-dialog-message-accept": "Baş e",
+ "ooui-dialog-message-reject": "Betal bike",
+ "ooui-dialog-process-retry": "Dîsa hewl bide",
+ "ooui-dialog-process-continue": "Bidomîne"
+}
/*!
- * OOjs UI v0.11.1
+ * OOjs UI v0.11.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-05T00:40:57Z
+ * Date: 2015-05-11T17:24:34Z
*/
@-webkit-keyframes oo-ui-progressBarWidget-slide {
from {
margin-left: 1.25em;
}
.oo-ui-toolGroupTool > .oo-ui-popupToolGroup {
+ border: 0;
+ border-radius: 0;
margin: 0;
}
+.oo-ui-toolGroupTool > .oo-ui-toolGroup {
+ border-right: none;
+}
.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
- height: 1.875em;
+ height: 2.5em;
padding: 0.3125em;
}
.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- height: 1.875em;
+ height: 2.5em;
width: 1.875em;
- opacity: 0.8;
}
.oo-ui-toolGroupTool > .oo-ui-popupToolGroup.oo-ui-labelElement > .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
line-height: 2.1em;
.oo-ui-toolGroup {
display: inline-block;
vertical-align: middle;
- margin: 0.375em;
+ 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: none !important;
+}
.oo-ui-toolGroup.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-tool-title {
color: #000000;
}
-.oo-ui-toolGroup.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-tool-accel {
- color: #888888;
-}
.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
.oo-ui-barToolGroup > .oo-ui-labelElement-label {
display: none;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
height: 1.875em;
- padding: 0.3125em;
+ padding: 0.625em;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
height: 1.875em;
width: 1.875em;
- opacity: 0.8;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
line-height: 2.1em;
+ 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.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-iconElement-icon {
opacity: 0.2;
}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.8;
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled .oo-ui-iconElement-icon {
+ opacity: 0.7;
}
.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
+ opacity: 0.9;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
}
.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
opacity: 0.2;
}
.oo-ui-popupToolGroup {
position: relative;
- height: 2.5em;
- min-width: 2.5em;
+ height: 3.125em;
+ min-width: 2em;
}
.oo-ui-popupToolGroup-handle {
display: block;
margin-left: 2.5em;
}
.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 2.25em;
+ margin-right: 2em;
}
.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
margin-right: 1.75em;
}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:active {
+ background-color: #e5e5e5;
+}
+.oo-ui-popupToolGroup-handle {
+ padding: 0.3125em;
+ height: 2.5em;
+}
.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
width: 0.9375em;
- height: 0.9375em;
- margin: 0.78125em;
+ height: 1.625em;
+ margin: 0.78125em 0.5em;
top: 0;
right: 0;
+ opacity: 0.3;
}
.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
right: -0.3125em;
}
.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
width: 1.875em;
- height: 1.875em;
- margin: 0.3125em;
+ height: 2.6em;
+ margin: 0.25em;
top: 0;
left: 0.3125em;
+ opacity: 0.7;
}
.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
left: 0;
margin: 0 0.6em;
font-weight: bold;
}
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #eeeeee;
+}
.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- top: 2.5em;
- background-color: white;
+ top: 3.125em;
+ margin: 0 -1px;
+ border: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
+ min-width: 16em;
}
.oo-ui-popupToolGroup .oo-ui-tool-link {
- padding: 0.3125em 0 0.3125em 0.3125em;
+ padding: 0.4em 0.625em;
+ box-sizing: border-box;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 1.875em;
+ height: 2.5em;
width: 1.875em;
min-width: 1.875em;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
line-height: 2em;
}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
+ color: #888888;
+}
.oo-ui-listToolGroup .oo-ui-tool {
display: block;
-webkit-box-sizing: border-box;
.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
cursor: default;
}
-.oo-ui-listToolGroup .oo-ui-tool {
- padding: 0 0.9375em 0 0.3125em;
+.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-active.oo-ui-widget-enabled,
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
+ 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 {
- background-color: #d0d0d0;
+ 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 {
color: #cccccc;
.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
opacity: 0.2;
}
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
- padding: 0.3125em 0 0.3125em 0;
- border: 1px solid #aaaaaa;
- border-radius: 0.25em;
- box-shadow: inset 0 -0.25em 0 0 rgba(0, 0, 0, 0.2), 0 0.125em 0 0 rgba(0, 0, 0, 0.1);
-}
-.oo-ui-menuToolGroup {
- border: 1px solid #cccccc;
- border-radius: 0.125em;
-}
.oo-ui-menuToolGroup .oo-ui-tool {
display: block;
}
.oo-ui-toolbar-narrow .oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
min-width: 8.125em;
}
-.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
- margin-left: -1px;
- padding: 0.3125em 0 0.3125em 0;
- border: 1px solid #aaaaaa;
- border-radius: 0.25em;
- border-top-left-radius: 0;
- box-shadow: inset 0 -0.25em 0 0 rgba(0, 0, 0, 0.2), 0 0.125em 0 0 rgba(0, 0, 0, 0.1);
-}
-.oo-ui-menuToolGroup.oo-ui-widget-enabled:hover {
- border-color: #aaaaaa;
-}
-.oo-ui-menuToolGroup.oo-ui-popupToolGroup-active {
- border-color: #aaaaaa;
-}
-.oo-ui-menuToolGroup .oo-ui-tool {
- padding: 0 1.25em 0 0.3125em;
-}
.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
background-image: none;
}
}
.oo-ui-menuToolGroup.oo-ui-widget-disabled {
color: #cccccc;
- border-color: #cccccc;
}
.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
}
.oo-ui-toolbar-bar {
line-height: 1em;
+ position: relative;
}
.oo-ui-toolbar-actions {
float: right;
}
+.oo-ui-toolbar-actions .oo-ui-toolbar {
+ display: inline-block;
+}
.oo-ui-toolbar-tools {
display: inline;
white-space: nowrap;
pointer-events: none;
}
.oo-ui-toolbar-bar {
- border-bottom: 2px solid rgba(0, 0, 0, 0.15);
- background: #ffffff;
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ font-weight: 500;
+ color: #555555;
}
.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
border: none;
background: none;
}
-.oo-ui-toolbar-shadow {
- display: none;
-}
-.oo-ui-selectWidget {
- border-radius: 2px;
-}
-.oo-ui-selectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
+.oo-ui-toolbar-actions > .oo-ui-buttonElement {
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
}
-.oo-ui-selectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 2px;
- border-top-left-radius: 2px;
- margin-left: 0;
+.oo-ui-toolbar-actions > .oo-ui-toolbar,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement:last-child {
+ margin-right: 0.5em;
}
-.oo-ui-selectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 2px;
- border-top-right-radius: 2px;
+.oo-ui-toolbar-shadow {
+ background-image: /* @embed */ url(themes/mediawiki/images/toolbar-shadow.png);
+ bottom: -9px;
+ height: 9px;
+ opacity: 0.5;
}
.oo-ui-optionWidget {
position: relative;
display: block;
}
.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected {
- background-color: #999999;
- color: #ffffff;
+ background-color: #d8e6fe;
+ color: rgba(0, 0, 0, 0.8);
}
.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
display: none;
background-color: #eeeeee;
color: black;
}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: #d8e6fe;
+}
.oo-ui-menuSectionOptionWidget {
cursor: default;
padding: 0.33em 0.75em;
color: #666666;
font-weight: bold;
}
-.oo-ui-tabOptionWidget:hover {
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:hover {
background-color: rgba(255, 255, 255, 0.3);
}
-.oo-ui-tabOptionWidget:active {
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:active {
background-color: rgba(255, 255, 255, 0.8);
}
.oo-ui-tabOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
/*!
- * OOjs UI v0.11.1
+ * OOjs UI v0.11.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-05T00:40:50Z
+ * Date: 2015-05-11T17:24:27Z
*/
/**
* @class
/*!
- * OOjs UI v0.11.1
+ * OOjs UI v0.11.2
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-05T00:40:50Z
+ * Date: 2015-05-11T17:24:27Z
*/
( function ( OO ) {
*/
OO.ui.ButtonElement.prototype.onClick = function ( e ) {
if ( !this.isDisabled() && e.which === 1 ) {
- this.emit( 'click' );
+ if ( this.emit( 'click' ) ) {
+ return false;
+ }
}
- return false;
};
/**
*/
OO.ui.ButtonElement.prototype.onKeyPress = function ( e ) {
if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- this.emit( 'click' );
- return false;
+ if ( this.emit( 'click' ) ) {
+ return false;
+ }
}
};
};
/**
- * Select and highlight the first selectable item in the menu.
+ * Highlight the first selectable item in the menu.
*
* @private
* @chainable
*/
OO.ui.LookupElement.prototype.initializeLookupMenuSelection = function () {
if ( !this.lookupMenu.getSelectedItem() ) {
- this.lookupMenu.selectItem( this.lookupMenu.getFirstSelectableItem() );
+ this.lookupMenu.highlightItem( this.lookupMenu.getFirstSelectableItem() );
}
- this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
};
/**
/**
* Collection of tool groups.
*
- * @example
- * // Basic OOjs UI toolbar example
+ * The following is a minimal example using several tools and tool groups.
*
+ * @example
* // Create the toolbar
* var toolFactory = new OO.ui.ToolFactory();
* var toolGroupFactory = new OO.ui.ToolGroupFactory();
* // Create a class inheriting from OO.ui.Tool
* function PictureTool() {
* PictureTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( PictureTool, OO.ui.Tool );
+ * // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
+ * // of 'icon' and 'title' (displayed icon and text).
+ * PictureTool.static.name = 'picture';
+ * PictureTool.static.icon = 'picture';
+ * PictureTool.static.title = 'Insert picture';
+ * // Defines the action that will happen when this tool is selected (clicked).
+ * PictureTool.prototype.onSelect = function () {
+ * $area.text( 'Picture tool clicked!' );
+ * // Never display this tool as "active" (selected).
+ * this.setActive( false );
* };
+ * // Make this tool available in our toolFactory and thus our toolbar
+ * toolFactory.register( PictureTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function SettingsTool() {
+ * SettingsTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( SettingsTool, OO.ui.Tool );
+ * SettingsTool.static.name = 'settings';
+ * SettingsTool.static.icon = 'settings';
+ * SettingsTool.static.title = 'Change settings';
+ * SettingsTool.prototype.onSelect = function () {
+ * $area.text( 'Settings tool clicked!' );
+ * this.setActive( false );
+ * };
+ * toolFactory.register( SettingsTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function StuffTool() {
+ * StuffTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( StuffTool, OO.ui.Tool );
+ * StuffTool.static.name = 'stuff';
+ * StuffTool.static.icon = 'ellipsis';
+ * StuffTool.static.title = 'More stuff';
+ * StuffTool.prototype.onSelect = function () {
+ * $area.text( 'More stuff tool clicked!' );
+ * this.setActive( false );
+ * };
+ * toolFactory.register( StuffTool );
+ *
+ * // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a
+ * // little popup window (a PopupWidget).
+ * function HelpTool( toolGroup, config ) {
+ * OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {
+ * padded: true,
+ * label: 'Help',
+ * head: true
+ * } }, config ) );
+ * this.popup.$body.append( '<p>I am helpful!</p>' );
+ * }
+ * OO.inheritClass( HelpTool, OO.ui.PopupTool );
+ * HelpTool.static.name = 'help';
+ * HelpTool.static.icon = 'help';
+ * HelpTool.static.title = 'Help';
+ * toolFactory.register( HelpTool );
+ *
+ * // Finally define which tools and in what order appear in the toolbar. Each tool may only be
+ * // used once (but not all defined tools must be used).
+ * toolbar.setup( [
+ * {
+ * // 'bar' tool groups display tools' icons only, side-by-side.
+ * type: 'bar',
+ * include: [ 'picture', 'help' ]
+ * },
+ * {
+ * // 'list' tool groups display both the titles and icons, in a dropdown list.
+ * type: 'list',
+ * indicator: 'down',
+ * label: 'More',
+ * include: [ 'settings', 'stuff' ]
+ * }
+ * // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed
+ * // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here,
+ * // since it's more complicated to use. (See the next example snippet on this page.)
+ * ] );
+ *
+ * // Create some UI around the toolbar and place it in the document
+ * var frame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * framed: true
+ * } );
+ * var contentFrame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * padded: true
+ * } );
+ * frame.$element.append(
+ * toolbar.$element,
+ * contentFrame.$element.append( $area )
+ * );
+ * $( 'body' ).append( frame.$element );
+ *
+ * // Here is where the toolbar is actually built. This must be done after inserting it into the
+ * // document.
+ * toolbar.initialize();
+ *
+ * The following example extends the previous one to illustrate 'menu' tool groups and the usage of
+ * 'updateState' event.
+ *
+ * @example
+ * // Create the toolbar
+ * var toolFactory = new OO.ui.ToolFactory();
+ * var toolGroupFactory = new OO.ui.ToolGroupFactory();
+ * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
+ *
+ * // We will be placing status text in this element when tools are used
+ * var $area = $( '<p>' ).text( 'Toolbar example' );
+ *
+ * // Define the tools that we're going to place in our toolbar
+ *
+ * // Create a class inheriting from OO.ui.Tool
+ * function PictureTool() {
+ * PictureTool.super.apply( this, arguments );
+ * }
* OO.inheritClass( PictureTool, OO.ui.Tool );
* // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
* // of 'icon' and 'title' (displayed icon and text).
* // Defines the action that will happen when this tool is selected (clicked).
* PictureTool.prototype.onSelect = function () {
* $area.text( 'Picture tool clicked!' );
+ * // Never display this tool as "active" (selected).
* this.setActive( false );
* };
* // The toolbar can be synchronized with the state of some external stuff, like a text
* // editor's editing area, highlighting the tools (e.g. a 'bold' tool would be shown as active
* // when the text cursor was inside bolded text). Here we simply disable this feature.
* PictureTool.prototype.onUpdateState = function () {
- * this.setActive( false );
* };
* // Make this tool available in our toolFactory and thus our toolbar
* toolFactory.register( PictureTool );
* // Register two more tools, nothing interesting here
* function SettingsTool() {
* SettingsTool.super.apply( this, arguments );
- * };
+ * this.reallyActive = false;
+ * }
* OO.inheritClass( SettingsTool, OO.ui.Tool );
* SettingsTool.static.name = 'settings';
* SettingsTool.static.icon = 'settings';
* SettingsTool.static.title = 'Change settings';
* SettingsTool.prototype.onSelect = function () {
* $area.text( 'Settings tool clicked!' );
- * this.setActive( false );
+ * // Toggle the active state on each click
+ * this.reallyActive = !this.reallyActive;
+ * this.setActive( this.reallyActive );
+ * // To update the menu label
+ * this.toolbar.emit( 'updateState' );
* };
* SettingsTool.prototype.onUpdateState = function () {
- * this.setActive( false );
* };
* toolFactory.register( SettingsTool );
*
* // Register two more tools, nothing interesting here
* function StuffTool() {
* StuffTool.super.apply( this, arguments );
- * };
+ * this.reallyActive = false;
+ * }
* OO.inheritClass( StuffTool, OO.ui.Tool );
* StuffTool.static.name = 'stuff';
* StuffTool.static.icon = 'ellipsis';
* StuffTool.static.title = 'More stuff';
* StuffTool.prototype.onSelect = function () {
* $area.text( 'More stuff tool clicked!' );
- * this.setActive( false );
+ * // Toggle the active state on each click
+ * this.reallyActive = !this.reallyActive;
+ * this.setActive( this.reallyActive );
+ * // To update the menu label
+ * this.toolbar.emit( 'updateState' );
* };
* StuffTool.prototype.onUpdateState = function () {
- * this.setActive( false );
* };
* toolFactory.register( StuffTool );
*
* head: true
* } }, config ) );
* this.popup.$body.append( '<p>I am helpful!</p>' );
- * };
+ * }
* OO.inheritClass( HelpTool, OO.ui.PopupTool );
* HelpTool.static.name = 'help';
* HelpTool.static.icon = 'help';
* include: [ 'picture', 'help' ]
* },
* {
- * // 'list' tool groups display both the titles and icons, in a dropdown list.
- * type: 'list',
+ * // 'menu' tool groups display both the titles and icons, in a dropdown menu.
+ * // Menu label indicates which items are selected.
+ * type: 'menu',
* indicator: 'down',
- * label: 'More',
* include: [ 'settings', 'stuff' ]
* }
- * // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed
- * // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here.
* ] );
*
* // Create some UI around the toolbar and place it in the document
* @fires submit
*/
OO.ui.FormLayout.prototype.onFormSubmit = function () {
- this.emit( 'submit' );
- return false;
+ if ( this.emit( 'submit' ) ) {
+ return false;
+ }
};
/**
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.ClippableElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TabIndexedElement );
-/* Static Properties */
-
/* Methods */
/**
/* Static Properties */
-OO.ui.ListToolGroup.static.accelTooltips = true;
-
OO.ui.ListToolGroup.static.name = 'list';
/* Methods */
/* Static Properties */
-OO.ui.MenuToolGroup.static.accelTooltips = true;
-
OO.ui.MenuToolGroup.static.name = 'menu';
/* Methods */
return OO.ui.ButtonElement.prototype.onMouseUp.call( this, e );
};
-/**
- * @inheritdoc
- */
-OO.ui.ButtonWidget.prototype.onClick = function ( e ) {
- var ret = OO.ui.ButtonElement.prototype.onClick.call( this, e );
- if ( this.href ) {
- return true;
- }
- return ret;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
- var ret = OO.ui.ButtonElement.prototype.onKeyPress.call( this, e );
- if ( this.href ) {
- return true;
- }
- return ret;
-};
-
/**
* Get hyperlink location.
*
// Events
this.$input.on( {
keypress: this.onKeyPress.bind( this ),
- blur: this.setValidityFlag.bind( this )
+ blur: this.onBlur.bind( this )
} );
this.$input.one( {
focus: this.onElementAttach.bind( this )
}
if ( config.required ) {
this.$input.attr( 'required', 'required' );
+ this.$input.attr( 'aria-required', 'true' );
}
if ( this.label || config.autosize ) {
this.installParentChangeDetector();
}
};
+/**
+ * Handle blur events.
+ *
+ * @private
+ * @param {jQuery.Event} e Blur event
+ */
+OO.ui.TextInputWidget.prototype.onBlur = function () {
+ this.setValidityFlag();
+};
+
/**
* Handle element attach events.
*
/**
* Sets the 'invalid' flag appropriately.
+ *
+ * @param {boolean} [isValid] Optionally override validation result
*/
-OO.ui.TextInputWidget.prototype.setValidityFlag = function () {
- var widget = this;
- this.isValid().done( function ( valid ) {
- if ( !valid ) {
- widget.$input.attr( 'aria-invalid', 'true' );
- } else {
- widget.$input.removeAttr( 'aria-invalid' );
- }
- widget.setFlags( { invalid: !valid } );
- } );
+OO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {
+ var widget = this,
+ setFlag = function ( valid ) {
+ if ( !valid ) {
+ widget.$input.attr( 'aria-invalid', 'true' );
+ } else {
+ widget.$input.removeAttr( 'aria-invalid' );
+ }
+ widget.setFlags( { invalid: !valid } );
+ };
+
+ if ( isValid !== undefined ) {
+ setFlag( isValid );
+ } else {
+ this.isValid().done( setFlag );
+ }
};
/**
this.anchor = null;
this.width = config.width !== undefined ? config.width : 320;
this.height = config.height !== undefined ? config.height : null;
- // Validate alignment and transform deprecated values
- if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( config.align ) > -1 ) {
- this.align = { left: 'force-right', right: 'force-left' }[ config.align ] || config.align;
- } else {
- this.align = 'center';
- }
+ this.setAlignment( config.align );
this.closeButton = new OO.ui.ButtonWidget( { framed: false, icon: 'close' } );
this.onMouseDownHandler = this.onMouseDown.bind( this );
this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
return this;
};
+/**
+ * Set popup alignment
+ * @param {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
+ * `backwards` or `forwards`.
+ */
+OO.ui.PopupWidget.prototype.setAlignment = function ( align ) {
+ // Validate alignment and transform deprecated values
+ if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {
+ this.align = { left: 'force-right', right: 'force-left' }[ align ] || align;
+ } else {
+ this.align = 'center';
+ }
+};
+
+/**
+ * Get popup alignment
+ * @return {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
+ * `backwards` or `forwards`.
+ */
+OO.ui.PopupWidget.prototype.getAlignment = function () {
+ return this.align;
+};
+
/**
* Progress bars visually display the status of an operation, such as a download,
* and can be either determinate or indeterminate:
*
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*
+ * @abstract
* @class
* @extends OO.ui.Widget
* @mixins OO.ui.GroupElement
-<?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>
- <g id="arched-arrow-ltr">
- <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<path d="M-472.8,494.7l6.3,5.7l-6.3,5.7v-3.8h-1.3c-3.2,0-6.3,1.3-7.6,3.8c0-4.7,2.8-7.6,7.9-7.6h0.9V494.7z"/>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-ltr">
- <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">\r
+<path d="M-472.8,494.7l6.3,5.7l-6.3,5.7v-3.8h-1.3c-3.2,0-6.3,1.3-7.6,3.8c0-4.7,2.8-7.6,7.9-7.6h0.9V494.7z"/>\r
+</svg>\r
-<?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>
- <g id="arched-arrow-rtl">
- <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<path d="M-476.3,494.7l-6.3,5.7l6.3,5.7v-3.8h1.3c3.2,0,6.3,1.3,7.6,3.8c0-4.7-2.8-7.6-7.9-7.6h-0.9V494.7z"/>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-rtl">
- <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">\r
+<path d="M-476.3,494.7l-6.3,5.7l6.3,5.7v-3.8h1.3c3.2,0,6.3,1.3,7.6,3.8c0-4.7-2.8-7.6-7.9-7.6h-0.9V494.7z"/>\r
+</svg>\r
-<?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>
- <g>
- <path d="M15.8 3.6c-2.1 0-3.6 1.9-5.1 3.3.2 0 .5-.1.8-.1.5 0 1 .1 1.5.3.8-.8 1.6-1.7 2.8-1.7.6 0 1.3.3 1.8.7 1 1 1 2.6 0 3.6l-2.6 2.6c-.4.4-1.2.7-1.8.7-1.4 0-2.1-.9-2.6-2l-1.3 1.3c.8 1.5 2 2.6 3.8 2.6 1.2 0 2.3-.5 3-1.3l2.6-2.6c.9-.9 1.5-2 1.5-3.3-.2-2.2-2.2-4.1-4.4-4.1zm-4.3 12.1l-.9.9c-.4.4-1.2.7-1.8.7-.6 0-1.3-.3-1.8-.7-1-1-1-2.7 0-3.6l2.6-2.6c.4-.4 1.2-.7 1.8-.7 1.4 0 2.1 1 2.6 2l1.3-1.3c-.8-1.5-2-2.6-3.8-2.6-1.2 0-2.3.5-3 1.3l-2.6 2.6c-1.7 1.7-1.7 4.4 0 6 1.6 1.6 4.4 1.7 5.9 0l1.9-1.9c-.3.1-.6.1-.9.1-.5 0-.9 0-1.3-.2z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g>\r
+ <path d="M-471.2,493.6c-2.1,0-3.6,1.9-5.1,3.3c0.2,0,0.5-0.1,0.8-0.1c0.5,0,1,0.1,1.5,0.3c0.8-0.8,1.6-1.7,2.8-1.7\r
+ c0.6,0,1.3,0.3,1.8,0.7c1,1,1,2.6,0,3.6l-2.6,2.6c-0.4,0.4-1.2,0.7-1.8,0.7c-1.4,0-2.1-0.9-2.6-2l-1.3,1.3c0.8,1.5,2,2.6,3.8,2.6\r
+ c1.2,0,2.3-0.5,3-1.3l2.6-2.6c0.9-0.9,1.5-2,1.5-3.3C-467,495.5-469,493.6-471.2,493.6z M-475.5,505.7l-0.9,0.9\r
+ c-0.4,0.4-1.2,0.7-1.8,0.7c-0.6,0-1.3-0.3-1.8-0.7c-1-1-1-2.7,0-3.6l2.6-2.6c0.4-0.4,1.2-0.7,1.8-0.7c1.4,0,2.1,1,2.6,2l1.3-1.3\r
+ c-0.8-1.5-2-2.6-3.8-2.6c-1.2,0-2.3,0.5-3,1.3l-2.6,2.6c-1.7,1.7-1.7,4.4,0,6c1.6,1.6,4.4,1.7,5.9,0l1.9-1.9\r
+ c-0.3,0.1-0.6,0.1-0.9,0.1C-474.7,505.9-475.1,505.9-475.5,505.7z"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M15.8 3.6c-2.1 0-3.6 1.9-5.1 3.3.2 0 .5-.1.8-.1.5 0 1 .1 1.5.3.8-.8 1.6-1.7 2.8-1.7.6 0 1.3.3 1.8.7 1 1 1 2.6 0 3.6l-2.6 2.6c-.4.4-1.2.7-1.8.7-1.4 0-2.1-.9-2.6-2l-1.3 1.3c.8 1.5 2 2.6 3.8 2.6 1.2 0 2.3-.5 3-1.3l2.6-2.6c.9-.9 1.5-2 1.5-3.3-.2-2.2-2.2-4.1-4.4-4.1zm-4.3 12.1l-.9.9c-.4.4-1.2.7-1.8.7-.6 0-1.3-.3-1.8-.7-1-1-1-2.7 0-3.6l2.6-2.6c.4-.4 1.2-.7 1.8-.7 1.4 0 2.1 1 2.6 2l1.3-1.3c-.8-1.5-2-2.6-3.8-2.6-1.2 0-2.3.5-3 1.3l-2.6 2.6c-1.7 1.7-1.7 4.4 0 6 1.6 1.6 4.4 1.7 5.9 0l1.9-1.9c-.3.1-.6.1-.9.1-.5 0-.9 0-1.3-.2z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">\r
+<g>\r
+ <path d="M-471.2,493.6c-2.1,0-3.6,1.9-5.1,3.3c0.2,0,0.5-0.1,0.8-0.1c0.5,0,1,0.1,1.5,0.3c0.8-0.8,1.6-1.7,2.8-1.7\r
+ c0.6,0,1.3,0.3,1.8,0.7c1,1,1,2.6,0,3.6l-2.6,2.6c-0.4,0.4-1.2,0.7-1.8,0.7c-1.4,0-2.1-0.9-2.6-2l-1.3,1.3c0.8,1.5,2,2.6,3.8,2.6\r
+ c1.2,0,2.3-0.5,3-1.3l2.6-2.6c0.9-0.9,1.5-2,1.5-3.3C-467,495.5-469,493.6-471.2,493.6z M-475.5,505.7l-0.9,0.9\r
+ c-0.4,0.4-1.2,0.7-1.8,0.7c-0.6,0-1.3-0.3-1.8-0.7c-1-1-1-2.7,0-3.6l2.6-2.6c0.4-0.4,1.2-0.7,1.8-0.7c1.4,0,2.1,1,2.6,2l1.3-1.3\r
+ c-0.8-1.5-2-2.6-3.8-2.6c-1.2,0-2.3,0.5-3,1.3l-2.6,2.6c-1.7,1.7-1.7,4.4,0,6c1.6,1.6,4.4,1.7,5.9,0l1.9-1.9\r
+ c-0.3,0.1-0.6,0.1-0.9,0.1C-474.7,505.9-475.1,505.9-475.5,505.7z"/>\r
+</g>\r
+</svg>\r
-<?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>
- <g id="menu">
- <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g id="menu">\r
+ <path id="lines" d="M-481,505h12c0.6,0,1,0.4,1,1v1c0,0.6-0.4,1-1,1h-12c-0.6,0-1-0.4-1-1v-1C-482,505.4-481.6,505-481,505z\r
+ M-482,501v1c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,500-482,500.4-482,501z M-482,496v1\r
+ c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,495-482,495.4-482,496z"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="menu">
- <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">\r
+<g id="menu">\r
+ <path id="lines" d="M-481,505h12c0.6,0,1,0.4,1,1v1c0,0.6-0.4,1-1,1h-12c-0.6,0-1-0.4-1-1v-1C-482,505.4-481.6,505-481,505z\r
+ M-482,501v1c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,500-482,500.4-482,501z M-482,496v1\r
+ c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,495-482,495.4-482,496z"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
- <g id="down">
- <path id="arrow" d="M11 4l-.463-.467c-.45-.446-1.186-.445-1.637 0l-2.897 2.89-2.915-2.898c-.45-.446-1.176-.43-1.626.017L1 4l5.003 5v-.01V9L11 4"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g id="down">\r
+ <path id="arrow" d="M883.3,341H116.7L500,724.3l0,0l0,0L883.3,341"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="down">
- <path id="arrow" d="M11 4l-.463-.467c-.45-.446-1.186-.445-1.637 0l-2.897 2.89-2.915-2.898c-.45-.446-1.176-.43-1.626.017L1 4l5.003 5v-.01V9L11 4"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">\r
+<g id="down">\r
+ <path id="arrow" d="M883.3,341H116.7L500,724.3l0,0l0,0L883.3,341"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
- <g id="ltr">
- <path id="arrow" d="M4 1l-.47.463c-.444.45-.444 1.186 0 1.637L6.423 6l-2.9 2.91c-.444.45-.43 1.177.02 1.627L4 11l5-5h-.01H9L4 1"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g id="ltr">\r
+ <path id="arrow" d="M-489,496v10l5-5h0h0L-489,496"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="ltr">
- <path id="arrow" d="M4 1l-.47.463c-.444.45-.444 1.186 0 1.637L6.423 6l-2.9 2.91c-.444.45-.43 1.177.02 1.627L4 11l5-5h-.01H9L4 1"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">\r
+<g id="ltr">\r
+ <path id="arrow" d="M-489,496v10l5-5h0h0L-489,496"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
- <g id="rtl">
- <path id="arrow" d="M8 11l.47-.463c.444-.45.444-1.186 0-1.637L5.576 6l2.9-2.91c.444-.45.43-1.177-.02-1.627L8 1 3 6h.01H3l5 5"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g id="rtl">\r
+ <path id="arrow" d="M-485,506v-10l-5,5h0h0L-485,506"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="rtl">
- <path id="arrow" d="M8 11l.47-.463c.444-.45.444-1.186 0-1.637L5.576 6l2.9-2.91c.444-.45.43-1.177-.02-1.627L8 1 3 6h.01H3l5 5"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">\r
+<g id="rtl">\r
+ <path id="arrow" d="M-485,506v-10l-5,5h0h0L-485,506"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
- <g id="up">
- <path id="arrow" d="M1 8l.463.47c.45.444 1.186.444 1.637 0L6 5.567l2.91 2.91c.45.444 1.177.43 1.627-.02L11 8 6 2.99V3v-.01L1 8"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>\r
+<g id="up">\r
+ <path id="arrow" d="M-492,503h10l-5-5v0v0L-492,503"/>\r
+</g>\r
+</svg>\r
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="up">
- <path id="arrow" d="M1 8l.463.47c.45.444 1.186.444 1.637 0L6 5.567l2.91 2.91c.45.444 1.177.43 1.627-.02L11 8 6 2.99V3v-.01L1 8"/>
- </g>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">\r
+<g id="up">\r
+ <path id="arrow" d="M-492,503h10l-5-5v0v0L-492,503"/>\r
+</g>\r
+</svg>\r
$.extend( postData, {
pst: '',
preview: '',
- prop: 'text|displaytitle|modules|categorieshtml|templates|langlinks|limitreporthtml',
+ prop: 'text|displaytitle|modules|jsconfigvars|categorieshtml|templates|langlinks|limitreporthtml',
disableeditsection: true
} );
request = api.post( postData );
request.done( function ( response ) {
var li, newList, $displaytitle, $content, $parent, $list;
+ if ( response.parse.jsconfigvars ) {
+ mw.config.set( response.parse.jsconfigvars );
+ }
if ( response.parse.modules ) {
mw.loader.load( response.parse.modules.concat(
response.parse.modulescripts,
* @covers FauxRequest::getHeader
*/
public function testGetSetHeader() {
- $value = 'test/test';
+ $value = 'text/plain, text/html';
$request = new FauxRequest();
- $request->setHeader( 'Content-Type', $value );
+ $request->setHeader( 'Accept', $value );
- $this->assertEquals( $request->getHeader( 'Content-Type' ), $value );
- $this->assertEquals( $request->getHeader( 'CONTENT-TYPE' ), $value );
- $this->assertEquals( $request->getHeader( 'content-type' ), $value );
+ $this->assertEquals( $request->getHeader( 'Nonexistent' ), false );
+ $this->assertEquals( $request->getHeader( 'Accept' ), $value );
+ $this->assertEquals( $request->getHeader( 'ACCEPT' ), $value );
+ $this->assertEquals( $request->getHeader( 'accept' ), $value );
+ $this->assertEquals(
+ $request->getHeader( 'Accept', WebRequest::GETHEADER_LIST ),
+ array( 'text/plain', 'text/html' )
+ );
}
}
/**
* @dataProvider provideInvalidConstructorArg
- * @expectedException UnexpectedValueException
+ * @expectedException Wikimedia\Assert\ParameterAssertionException
* @covers ProcessCacheLRU::__construct
*/
public function testConstructorGivenInvalidValue( $maxSize ) {