Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 128 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
SpecialMobileEditWatchlist | |
0.00% |
0 / 128 |
|
0.00% |
0 / 11 |
600 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
outputSubtitle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getLineHtml | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
12 | |||
execute | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getPageOffset | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getPagesToDisplay | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getEmptyListHtml | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
12 | |||
getNextPage | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
executeViewEditWatchlist | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
42 | |||
getViewHtml | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getAssociatedNavigationLinks | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | use MediaWiki\Html\Html; |
4 | use MediaWiki\Language\Language; |
5 | use MediaWiki\MediaWikiServices; |
6 | use MediaWiki\SpecialPage\SpecialPage; |
7 | use MediaWiki\Specials\SpecialEditWatchlist; |
8 | use MediaWiki\Title\Title; |
9 | use MobileFrontend\Hooks\HookRunner; |
10 | use MobileFrontend\Models\MobileCollection; |
11 | use MobileFrontend\Models\MobilePage; |
12 | |
13 | /** |
14 | * The mobile version of the watchlist editing page. |
15 | * @deprecated in future this should be the core SpecialEditWatchlist page (T109277) |
16 | */ |
17 | class SpecialMobileEditWatchlist extends SpecialEditWatchlist { |
18 | private const WATCHLIST_TAB_PATHS = [ |
19 | 'Special:Watchlist', |
20 | 'Special:EditWatchlist' |
21 | ]; |
22 | private const LIMIT = 50; |
23 | |
24 | /** @var string The name of the title to begin listing the watchlist from */ |
25 | protected $offsetTitle; |
26 | |
27 | public function __construct() { |
28 | $req = $this->getRequest(); |
29 | $this->offsetTitle = $req->getVal( 'from', '' ); |
30 | $watchStoreItem = MediaWikiServices::getInstance()->getWatchedItemStore(); |
31 | parent::__construct( $watchStoreItem ); |
32 | } |
33 | |
34 | /** |
35 | * Renders the subheader. |
36 | */ |
37 | protected function outputSubtitle() { |
38 | $user = $this->getUser(); |
39 | } |
40 | |
41 | /** |
42 | * Gets the HTML fragment for a watched page. The client uses a very different |
43 | * structure for client-rendered items in PageListItem.hogan. |
44 | * |
45 | * @param MobilePage $mp a definition of the page to be rendered. |
46 | * @return string |
47 | */ |
48 | protected function getLineHtml( MobilePage $mp ) { |
49 | $thumb = $mp->getSmallThumbnailHtml( true ); |
50 | $title = $mp->getTitle(); |
51 | if ( !$thumb ) { |
52 | $thumb = Html::rawElement( 'div', [ |
53 | 'class' => 'list-thumb list-thumb-placeholder' |
54 | ], Html::element( 'span', [ |
55 | 'class' => 'mf-icon-image' |
56 | ] ) |
57 | ); |
58 | } |
59 | $timestamp = $mp->getLatestTimestamp(); |
60 | $user = $this->getUser(); |
61 | $titleText = $title->getPrefixedText(); |
62 | if ( $timestamp ) { |
63 | $className = 'title'; |
64 | } else { |
65 | $className = 'title new'; |
66 | } |
67 | |
68 | $html = |
69 | Html::openElement( 'li', [ |
70 | 'class' => 'page-summary', |
71 | 'title' => $titleText, |
72 | 'data-id' => $title->getArticleID() |
73 | ] ) . |
74 | Html::openElement( 'a', [ 'href' => $title->getLocalURL(), 'class' => $className ] ); |
75 | $html .= $thumb; |
76 | $html .= |
77 | Html::element( 'h3', [], $titleText ); |
78 | |
79 | $html .= Html::closeElement( 'a' ) . |
80 | Html::closeElement( 'li' ); |
81 | |
82 | return $html; |
83 | } |
84 | |
85 | /** |
86 | * The main entry point for the page. |
87 | * |
88 | * @param string|null $mode Whether the user is viewing, editing, or clearing their |
89 | * watchlist |
90 | */ |
91 | public function execute( $mode ) { |
92 | // Anons don't get a watchlist edit |
93 | $this->requireLogin( 'mobile-frontend-watchlist-purpose' ); |
94 | |
95 | $out = $this->getOutput(); |
96 | $out->addBodyClasses( 'mw-mf-special-page' ); |
97 | parent::execute( $mode ); |
98 | $out->setPageTitleMsg( $this->msg( 'watchlist' ) ); |
99 | } |
100 | |
101 | /** |
102 | * Finds the offset of the page given in this->offsetTitle |
103 | * If doesn't exist returns 0 to show from beginning of array of pages. |
104 | * |
105 | * @param array $pages |
106 | * @return int where the index of the next page to be shown. |
107 | */ |
108 | private function getPageOffset( $pages ) { |
109 | // Deal with messiness of mediawiki |
110 | $pages = array_keys( $pages ); |
111 | |
112 | if ( $this->offsetTitle ) { |
113 | // PHP is stupid. strict test to avoid issues when page '0' is watched. |
114 | $offset = array_search( $this->offsetTitle, $pages, true ); |
115 | // Deal with cases where invalid title given |
116 | if ( $offset === false ) { |
117 | $offset = 0; |
118 | } |
119 | } else { |
120 | $offset = 0; |
121 | } |
122 | return $offset; |
123 | } |
124 | |
125 | /** |
126 | * Create paginated view of entire watchlist |
127 | * |
128 | * @param array $pages |
129 | * @return array of pages that should be displayed in current view |
130 | */ |
131 | private function getPagesToDisplay( $pages ) { |
132 | $offset = $this->getPageOffset( $pages ); |
133 | // Get the slice we are going to display and display it |
134 | return array_slice( $pages, $offset, self::LIMIT, true ); |
135 | } |
136 | |
137 | /** |
138 | * Get the HTML needed to show if a user doesn't watch any page, show information |
139 | * how to watch pages where no pages have been watched. |
140 | * @param bool $feed Render as feed (true) or list (false) view? |
141 | * @param Language $lang The language of the current mode |
142 | * @return string |
143 | */ |
144 | public static function getEmptyListHtml( $feed, $lang ) { |
145 | $dir = $lang->isRTL() ? 'rtl' : 'ltr'; |
146 | |
147 | $config = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Config' ); |
148 | $imgUrl = $config->get( 'ExtensionAssetsPath' ) . |
149 | "/MobileFrontend/images/emptywatchlist-page-actions-$dir.png"; |
150 | |
151 | if ( $feed ) { |
152 | $msg = Html::element( 'p', [], wfMessage( 'mobile-frontend-watchlist-feed-empty' )->plain() ); |
153 | } else { |
154 | $msg = Html::element( 'p', [], |
155 | wfMessage( 'mobile-frontend-watchlist-a-z-empty-howto' )->plain() |
156 | ); |
157 | $msg .= Html::element( 'img', [ |
158 | 'src' => $imgUrl, |
159 | 'alt' => wfMessage( 'mobile-frontend-watchlist-a-z-empty-howto-alt' )->plain(), |
160 | ] ); |
161 | } |
162 | |
163 | return Html::openElement( 'div', [ 'class' => 'info empty-page' ] ) . |
164 | $msg . |
165 | Html::element( 'a', |
166 | [ 'class' => 'button', 'href' => Title::newMainPage()->getLocalURL() ], |
167 | wfMessage( 'mobile-frontend-watchlist-back-home' )->plain() |
168 | ) . |
169 | Html::closeElement( 'div' ); |
170 | } |
171 | |
172 | /** |
173 | * Identify the next page to be shown |
174 | * |
175 | * @param array $pages |
176 | * @return string|bool representing title of next page to show or |
177 | * false if there isn't another page to show. |
178 | */ |
179 | private function getNextPage( $pages ) { |
180 | $total = count( $pages ); |
181 | $offset = $this->getPageOffset( $pages ); |
182 | $limit = self::LIMIT; |
183 | |
184 | // Work out if we need a more button and where to start from |
185 | if ( $total > $offset + $limit ) { |
186 | $pageKeys = array_keys( $pages ); |
187 | $from = $pageKeys[$offset + $limit]; |
188 | } else { |
189 | $from = false; |
190 | } |
191 | return $from; |
192 | } |
193 | |
194 | /** |
195 | * Renders the view/edit (normal) mode of the watchlist. |
196 | */ |
197 | protected function executeViewEditWatchlist() { |
198 | $ns = NS_MAIN; |
199 | $images = []; |
200 | |
201 | $watchlist = $this->getWatchlistInfo(); |
202 | |
203 | if ( isset( $watchlist[$ns] ) ) { |
204 | $allPages = $watchlist[$ns]; |
205 | $from = $this->getNextPage( $allPages ); |
206 | $allPages = $this->getPagesToDisplay( $allPages ); |
207 | } else { |
208 | $allPages = []; |
209 | $from = false; |
210 | } |
211 | |
212 | // Begin rendering of watchlist. |
213 | $watchlist = [ $ns => $allPages ]; |
214 | $services = MediaWikiServices::getInstance(); |
215 | ( new HookRunner( $services->getHookContainer() ) ) |
216 | ->onSpecialMobileEditWatchlist__images( |
217 | $this->getContext(), $watchlist, $images |
218 | ); |
219 | |
220 | // create list of pages |
221 | $mobilePages = new MobileCollection(); |
222 | $pageKeys = array_keys( $watchlist[$ns] ); |
223 | $repoGroup = $services->getRepoGroup(); |
224 | foreach ( $pageKeys as $dbkey ) { |
225 | if ( isset( $images[$ns][$dbkey] ) ) { |
226 | $page = new MobilePage( |
227 | Title::makeTitleSafe( $ns, $dbkey ), |
228 | $repoGroup->findFile( $images[$ns][$dbkey] ) |
229 | ); |
230 | } else { |
231 | $page = new MobilePage( Title::makeTitleSafe( $ns, $dbkey ) ); |
232 | } |
233 | $mobilePages->add( $page ); |
234 | } |
235 | |
236 | if ( $mobilePages->isEmpty() ) { |
237 | $html = self::getEmptyListHtml( false, $this->getLanguage() ); |
238 | } else { |
239 | $html = $this->getViewHtml( $mobilePages ); |
240 | } |
241 | if ( $from ) { |
242 | // show more link if there are more items to show |
243 | $qs = [ 'from' => $from ]; |
244 | $html .= Html::element( 'a', |
245 | [ |
246 | 'class' => 'mw-mf-watchlist-more', |
247 | 'href' => SpecialPage::getTitleFor( 'EditWatchlist' )->getLocalURL( $qs ), |
248 | ], |
249 | $this->msg( 'mobile-frontend-watchlist-more' )->text() ); |
250 | } |
251 | $out = $this->getOutput(); |
252 | $out->addHTML( $html ); |
253 | $out->addModules( 'mobile.special.watchlist.scripts' ); |
254 | $out->addModuleStyles( |
255 | [ |
256 | 'mobile.pagelist.styles', |
257 | 'mobile.pagesummary.styles' |
258 | ] |
259 | ); |
260 | } |
261 | |
262 | /** |
263 | * @param MobileCollection $collection Collection of pages to get view for |
264 | * @return string html representation of collection in watchlist view |
265 | */ |
266 | protected function getViewHtml( MobileCollection $collection ) { |
267 | $html = Html::openElement( 'ul', [ 'class' => 'content-unstyled mw-mf-page-list thumbs' |
268 | . ' page-summary-list mw-mf-watchlist-page-list' ] ); |
269 | foreach ( $collection as $mobilePage ) { |
270 | $html .= $this->getLineHtml( $mobilePage ); |
271 | } |
272 | $html .= Html::closeElement( 'ul' ); |
273 | return $html; |
274 | } |
275 | |
276 | /** |
277 | * @inheritDoc |
278 | */ |
279 | public function getAssociatedNavigationLinks() { |
280 | return self::WATCHLIST_TAB_PATHS; |
281 | } |
282 | } |