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