27use Wikimedia\Assert\Assert;
30use Wikimedia\Timestamp\ConvertibleTimestamp;
57 protected $origin = self::ORIGIN_USER_SITEWIDE;
88 if ( $options ===
null ) {
92 foreach ( $options as $member => $option ) {
98 $this->{$member} = $option;
127 foreach ( $this->scripts as $script ) {
128 $pages[$script] = [
'type' =>
'script' ];
133 foreach ( $this->styles as $style ) {
134 $pages[$style] = [
'type' =>
'style' ];
175 $title = Title::newFromText( $titleText );
185 $handler =
$content->getContentHandler();
194 return $content->serialize( $format );
209 $content = $overrideCallback ? call_user_func( $overrideCallback,
$title ) :
null;
213 'Bad content override for "{title}" in ' . __METHOD__,
214 [
'title' =>
$title->getPrefixedText() ]
219 $revision = MediaWikiServices::getInstance()
220 ->getRevisionLookup()
221 ->getKnownCurrentRevision(
$title );
225 $content = $revision->getContent( SlotRecord::MAIN, RevisionRecord::RAW );
229 'Failed to load content of JS/CSS page "{title}" in ' . __METHOD__,
230 [
'title' =>
$title->getPrefixedText() ]
237 if ( $maxRedirects ===
null ) {
238 $maxRedirects = $this->
getConfig()->get(
'MaxRedirects' ) ?: 0;
240 if ( $maxRedirects > 0 ) {
241 $newTitle =
$content->getRedirectTarget();
242 return $newTitle ? $this->
getContentObj( $newTitle, $context, $maxRedirects - 1 ) :
null;
255 if ( $overrideCallback && $this->
getSource() ===
'local' ) {
256 foreach ( $this->
getPages( $context ) as $page => $info ) {
257 $title = Title::newFromText( $page );
258 if (
$title && call_user_func( $overrideCallback,
$title ) !==
null ) {
264 return parent::shouldEmbedModule( $context );
273 foreach ( $this->
getPages( $context ) as $titleText => $options ) {
274 if ( $options[
'type'] !==
'script' ) {
277 $script = $this->
getContent( $titleText, $context );
278 if ( strval( $script ) !==
'' ) {
292 foreach ( $this->
getPages( $context ) as $titleText => $options ) {
293 if ( $options[
'type'] !==
'style' ) {
296 $media = $options[
'media'] ??
'all';
297 $style = $this->
getContent( $titleText, $context );
298 if ( strval( $style ) ===
'' ) {
301 if ( $this->
getFlip( $context ) ) {
302 $style = CSSJanus::transform( $style,
true,
false );
305 [ $style,
false, $this->
getConfig()->
get(
'ScriptPath' ),
true ] );
306 if ( !isset(
$styles[$media] ) ) {
334 $summary = parent::getDefinitionSummary( $context );
336 'pages' => $this->
getPages( $context ),
355 if ( $this->
getGroup() ===
'user' ) {
356 foreach ( $revisions as $revision ) {
357 if ( $revision[
'page_len'] > 0 ) {
368 return count( $revisions ) === 0;
372 $this->titleInfo[$batchKey] = $titleInfo;
377 return "{$title->getNamespace()}:{$title->getDBkey()}";
388 $pageNames = array_keys( $this->
getPages( $context ) );
390 $batchKey = implode(
'|', $pageNames );
391 if ( !isset( $this->titleInfo[$batchKey] ) ) {
392 $this->titleInfo[$batchKey] = static::fetchTitleInfo(
$dbr, $pageNames, __METHOD__ );
399 if ( $overrideCallback ) {
400 foreach ( $pageNames as $page ) {
401 $title = Title::newFromText( $page );
406 'page_latest' =>
'TBD',
407 'page_touched' => ConvertibleTimestamp::now( TS_MW ),
425 foreach ( $pages as $titleText ) {
426 $title = Title::newFromText( $titleText );
432 if ( !$batch->isEmpty() ) {
435 [
'page_namespace',
'page_title',
'page_touched',
'page_len',
'page_latest' ],
436 $batch->constructSet(
'page', $db ),
439 foreach (
$res as $row ) {
444 'page_len' => $row->page_len,
445 'page_latest' => $row->page_latest,
446 'page_touched' => $row->page_touched,
468 foreach ( $moduleNames as
$name ) {
469 $module = $rl->getModule( $name );
470 if ( $module instanceof
self ) {
471 $mDB = $module->getDB();
473 if ( $mDB->getDomainID() === $db->
getDomainID() ) {
474 $wikiModules[] = $module;
475 $allPages += $module->getPages( $context );
480 if ( !$wikiModules ) {
485 $pageNames = array_keys( $allPages );
487 $hash = sha1( implode(
'|', $pageNames ) );
490 $func = [ static::class,
'fetchTitleInfo' ];
493 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
494 $allInfo =
$cache->getWithSetCallback(
497 function ( $curVal, &$ttl, array &$setOpts ) use ( $func, $pageNames, $db, $fname ) {
498 $setOpts += Database::getCacheSetOptions( $db );
500 return call_user_func( $func, $db, $pageNames, $fname );
508 foreach ( $wikiModules as $wikiModule ) {
509 $pages = $wikiModule->getPages( $context );
512 foreach ( $pages as $pageName => $unused ) {
513 $title = Title::newFromText( $pageName );
515 $intersect[ self::makeTitleKey(
$title ) ] = 1;
518 $rl->getLogger()->info(
519 'Invalid wiki page title "{title}" in ' . __METHOD__,
520 [
'title' => $pageName ]
524 $info = array_intersect_key( $allInfo, $intersect );
525 $pageNames = array_keys( $pages );
527 $batchKey = implode(
'|', $pageNames );
528 $wikiModule->setTitleInfo( $batchKey, $info );
550 Assert::parameterType(
'string', $domain,
'$domain' );
556 $oldModel = $old->
getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel();
557 if ( in_array( $oldModel, $models ) ) {
562 if ( !$purge && $new ) {
563 $newModel = $new->
getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel();
564 if ( in_array( $newModel, $models ) ) {
570 $purge = (
$title->isSiteConfigPage() ||
$title->isUserConfigPage() );
574 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
575 $key =
$cache->makeGlobalKey(
'resourceloader-titleinfo', $domain );
576 $cache->touchCheckKey( $key );
588 return ( $this->styles && !$this->scripts ) ? self::LOAD_STYLES : self::LOAD_GENERAL;
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Class representing a list of titles The execute() method checks them all for existence and adds them ...
static call( $callable, array $args=[], $ttl=3600)
Shortcut method for creating a MemoizedCallable and invoking it with the specified arguments.
Context object that contains information about the state of a specific ResourceLoader web request.
getContentOverrideCallback()
Return the replaced-content mapping callback.
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
getDependencies(ResourceLoaderContext $context=null)
Get a list of modules this module depends on.
validateScriptFile( $fileName, $contents)
Validate a given script file; if valid returns the original source.
getFlip(ResourceLoaderContext $context)
string null $name
Module name.
getSource()
Get the source of this module.
Abstraction for ResourceLoader modules which pull from wiki pages.
getTitleInfo(ResourceLoaderContext $context)
Get the information about the wiki pages for a given context.
getDB()
Get the Database handle used for computing the module version.
__construct(array $options=null)
static preloadTitleInfo(ResourceLoaderContext $context, IDatabase $db, array $moduleNames)
enableModuleContentVersion()
Disable module content versioning.
getPages(ResourceLoaderContext $context)
Subclasses should return an associative array of resources in the module.
shouldEmbedModule(ResourceLoaderContext $context)
static fetchTitleInfo(IDatabase $db, array $pages, $fname=__METHOD__)
static makeTitleKey(LinkTarget $title)
getDefinitionSummary(ResourceLoaderContext $context)
setTitleInfo( $batchKey, array $titleInfo)
static invalidateModuleCache(Title $title, ?RevisionRecord $old, ?RevisionRecord $new, $domain)
Clear the preloadTitleInfo() cache for all wiki modules on this wiki on page change if it was a JS or...
getStyles(ResourceLoaderContext $context)
isKnownEmpty(ResourceLoaderContext $context)
getGroup()
Get group name.
getContent( $titleText, ResourceLoaderContext $context)
getContentObj(Title $title, ResourceLoaderContext $context, $maxRedirects=null)
getScript(ResourceLoaderContext $context)
static makeComment( $text)
Generate a CSS or JS comment block.
Represents a page (or page fragment) title within MediaWiki.
Represents a title within MediaWiki.
const CONTENT_FORMAT_JAVASCRIPT
const CONTENT_MODEL_JAVASCRIPT
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
Base interface for content objects.