Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
25.00% |
18 / 72 |
|
50.00% |
3 / 6 |
CRAP | |
0.00% |
0 / 1 |
RevisionSliderHooks | |
25.00% |
18 / 72 |
|
50.00% |
3 / 6 |
109.92 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
onDifferenceEngineViewHeader | |
19.23% |
5 / 26 |
|
0.00% |
0 / 1 |
18.17 | |||
isDisabled | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
isSamePage | |
33.33% |
2 / 6 |
|
0.00% |
0 / 1 |
8.74 | |||
getContainerHtml | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
6 | |||
onGetPreferences | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\RevisionSlider; |
4 | |
5 | use MediaWiki\Config\Config; |
6 | use MediaWiki\Config\ConfigFactory; |
7 | use MediaWiki\Diff\Hook\DifferenceEngineViewHeaderHook; |
8 | use MediaWiki\Html\Html; |
9 | use MediaWiki\MainConfigNames; |
10 | use MediaWiki\Message\Message; |
11 | use MediaWiki\Preferences\Hook\GetPreferencesHook; |
12 | use MediaWiki\Revision\RevisionRecord; |
13 | use MediaWiki\User\Options\UserOptionsLookup; |
14 | use MediaWiki\User\User; |
15 | use OOUI\ButtonWidget; |
16 | use Wikimedia\Stats\Metrics\CounterMetric; |
17 | use Wikimedia\Stats\StatsFactory; |
18 | |
19 | /** |
20 | * RevisionSlider extension hooks |
21 | * |
22 | * @file |
23 | * @ingroup Extensions |
24 | * @license GPL-2.0-or-later |
25 | */ |
26 | class RevisionSliderHooks implements DifferenceEngineViewHeaderHook, GetPreferencesHook { |
27 | |
28 | private Config $config; |
29 | private UserOptionsLookup $userOptionsLookup; |
30 | private CounterMetric $eventsCounter; |
31 | |
32 | public function __construct( |
33 | ConfigFactory $configFactory, |
34 | UserOptionsLookup $userOptionsLookup, |
35 | StatsFactory $statsFactory |
36 | ) { |
37 | $this->config = $configFactory->makeConfig( 'revisionslider' ); |
38 | $this->userOptionsLookup = $userOptionsLookup; |
39 | $this->eventsCounter = $statsFactory->getCounter( 'RevisionSlider_events_total' ) |
40 | ->setLabel( 'event', 'n/a' ); |
41 | } |
42 | |
43 | /** |
44 | * @inheritDoc |
45 | */ |
46 | public function onDifferenceEngineViewHeader( $differenceEngine ) { |
47 | $oldRevRecord = $differenceEngine->getOldRevision(); |
48 | $newRevRecord = $differenceEngine->getNewRevision(); |
49 | |
50 | /** |
51 | * If the user is logged in and has explictly requested to disable the extension don't load. |
52 | */ |
53 | $user = $differenceEngine->getUser(); |
54 | if ( $this->isDisabled( $user ) || !$this->isSamePage( $oldRevRecord, $newRevRecord ) ) { |
55 | return; |
56 | } |
57 | |
58 | $this->eventsCounter->setLabel( 'event', 'hookinit' ) |
59 | ->copyToStatsdAt( 'RevisionSlider.event.hookinit' ) |
60 | ->increment(); |
61 | |
62 | $timeOffset = 0; |
63 | if ( $this->config->get( MainConfigNames::Localtimezone ) !== null ) { |
64 | $timeOffset = $this->config->get( MainConfigNames::LocalTZoffset ) ?? 0; |
65 | } |
66 | |
67 | $autoExpand = $this->userOptionsLookup->getBoolOption( $user, 'userjs-revslider-autoexpand' ); |
68 | |
69 | $out = $differenceEngine->getOutput(); |
70 | // Load styles on page load to avoid FOUC |
71 | $out->addModuleStyles( 'ext.RevisionSlider.lazyCss' ); |
72 | if ( $autoExpand ) { |
73 | $out->addModules( 'ext.RevisionSlider.init' ); |
74 | $this->eventsCounter->setLabel( 'event', 'load' ) |
75 | ->copyToStatsdAt( 'RevisionSlider.event.load' ) |
76 | ->increment(); |
77 | } else { |
78 | $out->addModules( 'ext.RevisionSlider.lazyJs' ); |
79 | $this->eventsCounter->setLabel( 'event', 'lazyload' ) |
80 | ->copyToStatsdAt( 'RevisionSlider.event.lazyload' ) |
81 | ->increment(); |
82 | } |
83 | $out->addJsConfigVars( 'extRevisionSliderTimeOffset', $timeOffset ); |
84 | $out->enableOOUI(); |
85 | |
86 | $out->prependHTML( $this->getContainerHtml( $autoExpand ) ); |
87 | } |
88 | |
89 | public function isDisabled( User $user ): bool { |
90 | return $user->isNamed() && |
91 | $this->userOptionsLookup->getBoolOption( $user, 'revisionslider-disable' ); |
92 | } |
93 | |
94 | private function isSamePage( ?RevisionRecord $oldRevRecord, ?RevisionRecord $newRevRecord ): bool { |
95 | // sometimes the old revision can be null (e.g. missing rev), and perhaps also the |
96 | // new one (T167359) |
97 | if ( !$oldRevRecord || !$newRevRecord ) { |
98 | return false; |
99 | } |
100 | |
101 | /** |
102 | * Do not show the RevisionSlider when revisions from two different pages are being compared |
103 | * |
104 | * Since RevisionRecord::getPageAsLinkTarget only returns a LinkTarget, which doesn't |
105 | * have an equals method, compare manually by namespace and text |
106 | */ |
107 | $oldTitle = $oldRevRecord->getPageAsLinkTarget(); |
108 | $newTitle = $newRevRecord->getPageAsLinkTarget(); |
109 | return $oldTitle->getNamespace() === $newTitle->getNamespace() && |
110 | $oldTitle->getDBKey() === $newTitle->getDBKey(); |
111 | } |
112 | |
113 | private function getContainerHtml( bool $autoExpand ): string { |
114 | $toggleButton = new ButtonWidget( [ |
115 | 'label' => ( new Message( 'revisionslider-toggle-label' ) )->text(), |
116 | 'indicator' => 'down', |
117 | 'classes' => [ 'mw-revslider-toggle-button' ], |
118 | 'infusable' => true, |
119 | 'framed' => false, |
120 | 'title' => ( new Message( 'revisionslider-toggle-title-expand' ) )->text(), |
121 | ] ); |
122 | $toggleButton->setAttributes( [ 'style' => 'width: 100%; text-align: center;' ] ); |
123 | |
124 | $loadingSpinner = Html::rawElement( |
125 | 'div', [ 'class' => 'mw-revslider-spinner' ], |
126 | Html::element( |
127 | 'div', [ 'class' => 'mw-revslider-bounce' ] |
128 | ) |
129 | ); |
130 | |
131 | return Html::rawElement( 'div', |
132 | [ 'class' => 'mw-revslider-container' ], |
133 | $toggleButton . |
134 | Html::rawElement( 'div', |
135 | [ |
136 | 'class' => 'mw-revslider-slider-wrapper', |
137 | 'style' => $autoExpand ? null : 'display: none;', |
138 | ], |
139 | Html::rawElement( 'div', |
140 | [ 'class' => 'mw-revslider-placeholder' ], |
141 | $loadingSpinner |
142 | ) |
143 | ) |
144 | ); |
145 | } |
146 | |
147 | /** |
148 | * @inheritDoc |
149 | */ |
150 | public function onGetPreferences( $user, &$preferences ) { |
151 | $preferences['revisionslider-disable'] = [ |
152 | 'type' => 'toggle', |
153 | 'label-message' => 'revisionslider-preference-disable', |
154 | 'section' => 'rendering/diffs', |
155 | ]; |
156 | } |
157 | |
158 | } |