- 'skins/**/*'
- 'tests/frontend/node_modules/**/*'
- 'vendor/**/*'
+
+Metrics/LineLength:
+ Max: 100
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 1
-Lint/AmbiguousRegexpLiteral:
- Enabled: false
-
# Offense count: 2
# Cop supports --auto-correct.
Lint/UnusedMethodArgument:
Enabled: false
-# Offense count: 19
-# Configuration parameters: AllowURI, URISchemes.
-Metrics/LineLength:
- Max: 94
-
# Offense count: 10
Style/Documentation:
Enabled: false
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/EmptyLines:
- Enabled: false
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/EmptyLinesAroundBody:
- Enabled: false
-
# Offense count: 1
# Configuration parameters: Exclude.
Style/FileName:
Style/HashSyntax:
Enabled: false
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/LeadingCommentSpace:
- Enabled: false
-
# Offense count: 4
# Cop supports --auto-correct.
Style/PerlBackrefs:
Enabled: false
-# Offense count: 4
-# Cop supports --auto-correct.
-Style/SpaceAroundOperators:
- Enabled: false
-
-# Offense count: 1
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
-Style/SpaceInsideBlockBraces:
- Enabled: true
-
-# Offense count: 6
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
-Style/SpaceInsideHashLiteralBraces:
- Enabled: false
-
# Offense count: 89
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/StringLiterals:
Enabled: false
-
-# Offense count: 11
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
-Style/TrailingBlankLines:
- Enabled: false
-#ruby=ruby-2.1.2
-#ruby-gemset=core
+# ruby=ruby-2.1.2
+# ruby-gemset=core
source "https://rubygems.org"
dynamically-compiled Mustache templates (currently uses lightncandy library).
* Clickable anchors for each section heading in the content are now generated
and appear in the gutter on hovering over the heading.
+* Added 'CategoryViewer::doCategoryQuery' and 'CategoryViewer::generateLink' hooks
+ to allow extensions to override how links to pages are rendered within NS_CATEGORY
==== External libraries ====
* MediaWiki now requires certain external libraries to be installed. In the past
'CategoryPageView': Before viewing a categorypage in CategoryPage::view.
$catpage: CategoryPage instance
+'CategoryViewer::doCategoryQuery': After querying for pages to be displayed
+in a Category page. Gives extensions the opportunity to batch load any
+related data about the pages.
+$type: The category type. Either 'page', 'file' or 'subcat'
+$res: Query result from DatabaseBase::select()
+
+'CategoryViewer::generateLink': Before generating an output link allow
+extensions opportunity to generate a more specific or relevant link.
+$type: The category type. Either 'page', 'img' or 'subcat'
+$title: Title object for the categorized page
+$html: Requested html content of anchor
+&$link: Returned value. When set to a non-null value by a hook subscriber
+this value will be used as the anchor instead of Linker::link
+
'ChangePasswordForm': For extensions that need to add a field to the
ChangePassword form via the Preferences form.
&$extraFields: An array of arrays that hold fields like would be passed to the
// Subcategory; strip the 'Category' namespace from the link text.
$title = $cat->getTitle();
- $link = Linker::link( $title, htmlspecialchars( $title->getText() ) );
- if ( $title->isRedirect() ) {
- // This didn't used to add redirect-in-category, but might
- // as well be consistent with the rest of the sections
- // on a category page.
- $link = '<span class="redirect-in-category">' . $link . '</span>';
- }
- $this->children[] = $link;
+ $this->children[] = $this->generateLink(
+ 'subcat',
+ $title,
+ $title->isRedirect(),
+ htmlspecialchars( $title->getText() )
+ );
$this->children_start_char[] =
$this->getSubcategorySortChar( $cat->getTitle(), $sortkey );
}
+ function generateLink( $type, Title $title, $isRedirect, $html = null ) {
+ $link = null;
+ Hooks::run( 'CategoryViewer::generateLink', array( $type, $title, $html, &$link ) );
+ if ( $link === null ) {
+ $link = Linker::link( $title, $html );
+ }
+ if ( $isRedirect ) {
+ $link = '<span class="redirect-in-category">' . $link . '</span>';
+ }
+
+ return $link;
+ }
+
/**
* Get the character to be used for sorting subcategories.
* If there's a link from Category:A to Category:B, the sortkey of the resulting
$this->gallery->add( $title );
}
} else {
- $link = Linker::link( $title );
- if ( $isRedirect ) {
- // This seems kind of pointless given 'mw-redirect' class,
- // but keeping for back-compatibility with user css.
- $link = '<span class="redirect-in-category">' . $link . '</span>';
- }
- $this->imgsNoGallery[] = $link;
+ $this->imgsNoGallery[] = $this->generateLink( 'image', $title, $isRedirect );
$this->imgsNoGallery_start_char[] = $wgContLang->convert(
$this->collation->getFirstLetter( $sortkey ) );
function addPage( $title, $sortkey, $pageLength, $isRedirect = false ) {
global $wgContLang;
- $link = Linker::link( $title );
- if ( $isRedirect ) {
- // This seems kind of pointless given 'mw-redirect' class,
- // but keeping for back-compatibility with user css.
- $link = '<span class="redirect-in-category">' . $link . '</span>';
- }
- $this->articles[] = $link;
+ $this->articles[] = $this->generateLink( 'page', $title, $isRedirect );
$this->articles_start_char[] = $wgContLang->convert(
$this->collation->getFirstLetter( $sortkey ) );
)
);
+ Hooks::run( 'CategoryViewer::doCategoryQuery', array( $type, $res ) );
+
$count = 0;
foreach ( $res as $row ) {
$title = Title::newFromRow( $row );
'PublishStashedFile' => 'PublishStashedFileJob',
'ThumbnailRender' => 'ThumbnailRenderJob',
'recentChangesUpdate' => 'RecentChangesUpdateJob',
- 'refreshLinksPrioritized' => 'RefreshLinksJob', // for cascading protection
'null' => 'NullJob'
);
return array( 'numRows' => $numRows, 'batches' => $batches );
}
-
- /**
- * Get a Title iterator for cascade-protected template/file use backlinks
- *
- * @return TitleArray
- * @since 1.25
- */
- public function getCascadeProtectedLinks() {
- // This method is used to make redudant jobs anyway, so its OK to use
- // a slave. Also, the set of cascade protected pages tends to be stable.
- $dbr = $this->getDB();
-
- $queries = array();
- // @note: UNION filters any duplicate pages
- $queries[] = $dbr->selectSQLText(
- array( 'templatelinks', 'page_restrictions', 'page' ),
- array( 'page_namespace', 'page_title', 'page_id' ),
- array(
- 'tl_namespace' => $this->title->getNamespace(),
- 'tl_title' => $this->title->getDBkey(),
- 'tl_from = pr_page',
- 'pr_cascade' => 1,
- 'page_id = tl_from'
- )
- );
- $queries[] = $dbr->selectSQLText(
- array( 'imagelinks', 'page_restrictions', 'page' ),
- array( 'page_namespace', 'page_title', 'page_id' ),
- array(
- 'il_to' => $this->title->getDBkey(),
- 'il_from = pr_page',
- 'pr_cascade' => 1,
- 'page_id = il_from'
- )
- );
-
- return TitleArray::newFromResult( $dbr->query(
- $dbr->unionQueries( $queries, false ),
- __METHOD__
- ) );
- }
}
}
public function doUpdate() {
+
$job = new HTMLCacheUpdateJob(
$this->mTitle,
array(
$job->run(); // just do the purge query now
} );
}
+
}
}
* Which means do LinksUpdate on all pages that include the current page,
* using the job queue.
*/
- protected function queueRecursiveJobs() {
+ function queueRecursiveJobs() {
self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
if ( $this->mTitle->getNamespace() == NS_FILE ) {
// Process imagelinks in case the title is or was a redirect
self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
}
-
- $bc = $this->mTitle->getBacklinkCache();
- // Get jobs for cascade-protected backlinks for a high priority queue.
- // If meta-templates change to using a new template, the new template
- // should be implicitly protected as soon as possible, if applicable.
- // These jobs duplicate a subset of the above ones, but can run sooner.
- // Which ever runs first generally no-ops the other one.
- $jobs = array();
- foreach ( $bc->getCascadeProtectedLinks() as $title ) {
- $jobs[] = new RefreshLinksJob( $title, array( 'prioritize' => true ) );
- }
- JobQueueGroup::singleton()->push( $jobs );
}
/**
"refreshlinks:{$table}:{$title->getPrefixedText()}"
)
);
-
JobQueueGroup::singleton()->push( $job );
JobQueueGroup::singleton()->deduplicateRootJob( $job );
}
function __construct( $title, $params = '' ) {
parent::__construct( 'refreshLinks', $title, $params );
- // A separate type is used just for cascade-protected backlinks
- if ( !empty( $this->params['prioritize'] ) ) {
- $this->command .= 'Prioritized';
- }
// Base backlink update jobs and per-title update jobs can be de-duplicated.
// If template A changes twice before any jobs run, a clean queue will have:
// (A base, A base)
return true;
}
- /**
- * @param Title $title
- * @return bool
- */
protected function runForTitle( Title $title = null ) {
$linkCache = LinkCache::singleton();
$linkCache->clear();
}
# Get the ParserOutput actually *displayed* here.
- # Note that $this->mParserOutput is the *current*/oldid version output.
+ # Note that $this->mParserOutput is the *current* version output.
$pOutput = ( $outputDone instanceof ParserOutput )
? $outputDone // object fetched by hook
: $this->mParserOutput;
}
/**
- * Opportunistically enqueue link update jobs given fresh parser output if useful
+ * Updates cascading protections
*
- * @param ParserOutput $parserOutput Current version page output
- * @return bool Whether a job was pushed
- * @since 1.25
+ * @param ParserOutput $parserOutput ParserOutput object for the current version
*/
- public function triggerOpportunisticLinksUpdate( ParserOutput $parserOutput ) {
- if ( wfReadOnly() ) {
- return false;
+ public function doCascadeProtectionUpdates( ParserOutput $parserOutput ) {
+ if ( wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) {
+ return;
}
- if ( $this->mTitle->areRestrictionsCascading() ) {
- // If the page is cascade protecting, the links should really be up-to-date
- $params = array( 'prioritize' => true );
- } elseif ( $parserOutput->hasDynamicContent() ) {
- // Assume the output contains time/random based magic words
- $params = array();
- } else {
- // If the inclusions are deterministic, the edit-triggered link jobs are enough
- return false;
+ // templatelinks or imagelinks tables may have become out of sync,
+ // especially if using variable-based transclusions.
+ // For paranoia, check if things have changed and if
+ // so apply updates to the database. This will ensure
+ // that cascaded protections apply as soon as the changes
+ // are visible.
+
+ // Get templates from templatelinks and images from imagelinks
+ $id = $this->getId();
+
+ $dbLinks = array();
+
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( array( 'templatelinks' ),
+ array( 'tl_namespace', 'tl_title' ),
+ array( 'tl_from' => $id ),
+ __METHOD__
+ );
+
+ foreach ( $res as $row ) {
+ $dbLinks["{$row->tl_namespace}:{$row->tl_title}"] = true;
}
- // Check if the last link refresh was before page_touched
- if ( $this->getLinksTimestamp() < $this->getTouched() ) {
- JobQueueGroup::singleton()->push( new RefreshLinksJob( $this->mTitle, $params ) );
- return true;
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( array( 'imagelinks' ),
+ array( 'il_to' ),
+ array( 'il_from' => $id ),
+ __METHOD__
+ );
+
+ foreach ( $res as $row ) {
+ $dbLinks[NS_FILE . ":{$row->il_to}"] = true;
}
- return false;
+ // Get templates and images from parser output.
+ $poLinks = array();
+ foreach ( $parserOutput->getTemplates() as $ns => $templates ) {
+ foreach ( $templates as $dbk => $id ) {
+ $poLinks["$ns:$dbk"] = true;
+ }
+ }
+ foreach ( $parserOutput->getImages() as $dbk => $id ) {
+ $poLinks[NS_FILE . ":$dbk"] = true;
+ }
+
+ // Get the diff
+ $links_diff = array_diff_key( $poLinks, $dbLinks );
+
+ if ( count( $links_diff ) > 0 ) {
+ // Whee, link updates time.
+ // Note: we are only interested in links here. We don't need to get
+ // other DataUpdate items from the parser output.
+ $u = new LinksUpdate( $this->mTitle, $parserOutput, false );
+ $u->doUpdate();
+ }
}
/**
$this->mLimitReportData[$key] = $value;
}
- /**
- * Check whether the cache TTL was lowered due to dynamic content
- *
- * When content is determined by more than hard state (e.g. page edits),
- * such as template/file transclusions based on the current timestamp or
- * extension tags that generate lists based on queries, this return true.
- *
- * @return bool
- * @since 1.25
- */
- public function hasDynamicContent() {
- global $wgParserCacheExpireTime;
-
- return $this->getCacheExpiry() < $wgParserCacheExpireTime;
- }
-
/**
* Get or set the prevent-clickjacking flag
*
}
if ( $isCurrent ) {
- $this->page->triggerOpportunisticLinksUpdate( $this->parserOutput );
+ $this->page->doCascadeProtectionUpdates( $this->parserOutput );
}
return true;
doc = $2 ? ': ' + $2 : ''
return formatter.format("{@link #{name}} #{doc}")
else
- JsDuck::Logger.warn(nil, 'Unexpected @see argument: "'+tag+'"', position)
+ JsDuck::Logger.warn(nil, 'Unexpected @see argument: "' + tag + '"', position)
return tag
end
end
name = $1
return formatter.format("`context` : {@link #{name}}")
else
- JsDuck::Logger.warn(nil, 'Unexpected @context argument: "'+tag+'"', position)
+ JsDuck::Logger.warn(nil, 'Unexpected @context argument: "' + tag + '"', position)
return tag
end
end
};
$( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
- $preftoc = $( '<ul id="preftoc"></ul>' )
- .attr( 'role', 'tablist' );
+ $preftoc = $( '<ul>' )
+ .attr( {
+ id: 'preftoc',
+ role: 'tablist'
+ } );
$preferences = $( '#preferences' )
.addClass( 'jsprefs' )
.before( $preftoc );
# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
#
Given(/^I go to Create account page at (.+)$/) do |path|
- visit(CreateAccountPage, :using_params => {:page_title => path})
+ visit(CreateAccountPage, :using_params => { :page_title => path })
end
Then(/^form has Create account button$/) do
Given(/^I am on the (.+) page$/) do |article|
article = article.gsub(/ /, '_')
- visit(ZtargetPage, :using_params => {:article_name => article})
+ visit(ZtargetPage, :using_params => { :article_name => article })
end
Given(/^I create page "(.*?)" with content "(.*?)"$/) do |page_title, page_content|
on(APIPage).create page_title, page_content
end
-
When(/^I click the Link Target link$/) do
on(ZtargetPage).link_target_page_link
end
Then(/^I should be on the Link Target Test Page$/) do
- @browser.url.should match /Link_Target_Test_Page/
+ @browser.url.should match(/Link_Target_Test_Page/)
end
Then(/^the page content should contain "(.*?)"$/) do |content|
on(ZtargetPage).page_content.should match content
end
-
Then(/^the edited page content should contain "(.*?)"$/) do |content|
on(MainPage).page_content.should match(content + @random_string)
end
-
# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
#
Given(/^I am at file that does not exist$/) do
- visit(FileDoesNotExistPage, using_params: {page_name: @random_string})
+ visit(FileDoesNotExistPage, using_params: { page_name: @random_string })
end
Then(/^page should show that no such file exists$/) do
page.auto_number_check_element.should exist
end
end
-
-
Then(/^I can see my signature$/) do
on(PreferencesUserProfilePage).signature_table_element.should exist
end
-
Then(/^I should see a link to a previous version of the page$/) do
on(ViewHistoryPage).old_version_link_element.should be_visible
end
-
button(:preview_button, id: "wpPreview")
button(:show_changes_button, id: "wpDiff")
button(:save_button, id: "wpSave")
-end
\ No newline at end of file
+end
include PageObject
div(:error_box, class: "errorbox")
-end
\ No newline at end of file
+end
li(:special_pages_link, id: "t-specialpages")
a(:view_history_link, href: /action=history/)
li(:what_links_here_link, id: "t-whatlinkshere")
-end
\ No newline at end of file
+end
radio_button(:vector, id: "mw-input-wpskin-vector")
radio_button(:year_mo_day_radio, id: "mw-input-wpdate-ymd")
end
-
a(:view_history_link, href: /action=history/)
a(:old_version_link, href: /oldid=/)
-
-end
\ No newline at end of file
+end
include PageObject
a(:link_target_page_link, text: "link to the test target page")
-end
\ No newline at end of file
+end