Index: branches/RL2/extensions/Gadgets/GadgetHooks.php |
— | — | @@ -1,431 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Gadgets extension - lets users select custom javascript gadgets |
5 | | - * |
6 | | - * |
7 | | - * For more info see http://mediawiki.org/wiki/Extension:Gadgets |
8 | | - * |
9 | | - * @file |
10 | | - * @ingroup Extensions |
11 | | - * @author Daniel Kinzler, brightbyte.de |
12 | | - * @copyright © 2007 Daniel Kinzler |
13 | | - * @license GNU General Public Licence 2.0 or later |
14 | | - */ |
15 | | - |
16 | | -class GadgetHooks { |
17 | | - /** |
18 | | - * Get the gadget ID from a title |
19 | | - * @param $title Title object |
20 | | - * @return string Gadget id or null if not a gadget definition page |
21 | | - */ |
22 | | - public static function getIDFromTitle( Title $title ) { |
23 | | - $id = $title->getText(); |
24 | | - if ( $title->getNamespace() !== NS_GADGET_DEFINITION || !preg_match( '!\.js$!u', $id ) ) { |
25 | | - // Not a gadget definition page |
26 | | - return null; |
27 | | - } |
28 | | - // Trim .js from the page name to obtain the gadget ID |
29 | | - return substr( $id, 0, -3 ); |
30 | | - } |
31 | | - |
32 | | - /** |
33 | | - * Get a Title object of the gadget definition page from a gadget id |
34 | | - * @param $is String |
35 | | - * @return Title|null |
36 | | - */ |
37 | | - public static function getDefinitionTitleFromID( $id ) { |
38 | | - return Title::makeTitleSafe( NS_GADGET_DEFINITION, $id . '.js' ); |
39 | | - } |
40 | | - |
41 | | - /** |
42 | | - * ArticleDeleteComplete hook handler. |
43 | | - * |
44 | | - * @param $article Article |
45 | | - * @param $user User |
46 | | - * @param $reason String: Deletion summary |
47 | | - * @param $id Int: Page ID |
48 | | - */ |
49 | | - public static function gadgetDefinitionDelete( $article, $user, $reason, $id ) { |
50 | | - $id = self::getIDFromTitle( $article->getTitle() ); |
51 | | - if ( !$id ) { |
52 | | - return true; |
53 | | - } |
54 | | - |
55 | | - $repo = LocalGadgetRepo::singleton(); |
56 | | - $repo->deleteGadget( $id ); |
57 | | - // deleteGadget() may return an error if the Gadget didn't exist, but we don't care here |
58 | | - return true; |
59 | | - } |
60 | | - |
61 | | - /** |
62 | | - * ArticleSaveComplete hook handler. |
63 | | - * |
64 | | - * @param $article Article |
65 | | - * @param $user User |
66 | | - * @param $text String: New page text |
67 | | - * @param $summary String: Edit summary |
68 | | - * @param $isMinor Bool: Whether this was a minor edit |
69 | | - * @param $isWatch unused |
70 | | - * @param $section unused |
71 | | - * @param $flags: Int: Bitmap of flags passed to WikiPage::doEdit() |
72 | | - * @param $revision: Revision object for the new revision |
73 | | - */ |
74 | | - public static function gadgetDefinitionSave( $article, $user, $text, $summary, $isMinor, |
75 | | - $isWatch, $section, $flags, $revision ) |
76 | | - { |
77 | | - $id = self::getIDFromTitle( $article->getTitle() ); |
78 | | - if ( !$id ) { |
79 | | - return true; |
80 | | - } |
81 | | - |
82 | | - $previousRev = $revision->getPrevious(); |
83 | | - $prevTs = $previousRev instanceof Revision ? $previousRev->getTimestamp() : wfTimestampNow(); |
84 | | - |
85 | | - // Update the database entry for this gadget |
86 | | - $repo = LocalGadgetRepo::singleton(); |
87 | | - // TODO: Timestamp in the constructor is ugly |
88 | | - $gadget = new Gadget( $id, $repo, $text, $prevTs ); |
89 | | - $repo->modifyGadget( $gadget, $revision->getTimestamp() ); |
90 | | - |
91 | | - // modifyGadget() returns a Status object with an error if there was a conflict, |
92 | | - // but we don't care. If a conflict occurred, that must be because a newer edit's |
93 | | - // DB update occurred before ours, in which case the right thing to do is to occu |
94 | | - |
95 | | - return true; |
96 | | - } |
97 | | - |
98 | | - /** |
99 | | - * Update the database entry for a gadget if the description page is |
100 | | - * newer than the database entry. |
101 | | - * @param $title Title object |
102 | | - */ |
103 | | - public static function gadgetDefinitionUpdateIfChanged( $title ) { |
104 | | - $id = self::getIDFromTitle( $title ); |
105 | | - if ( !$id ) { |
106 | | - return; |
107 | | - } |
108 | | - |
109 | | - // Check whether this undeletion changed the latest revision of the page, by comparing |
110 | | - // the timestamp of the latest revision with the timestamp in the DB |
111 | | - $repo = LocalGadgetRepo::singleton(); |
112 | | - $gadget = $repo->getGadget( $id ); |
113 | | - $gadgetTS = $gadget ? $gadget->getTimestamp() : 0; |
114 | | - |
115 | | - $rev = Revision::newFromTitle( $title ); |
116 | | - if ( wfTimestamp( TS_MW, $rev->getTimestamp() ) === |
117 | | - wfTimestamp( TS_MW, $gadgetTS ) ) { |
118 | | - // The latest rev didn't change. Someone must've undeleted an older revision |
119 | | - return; |
120 | | - } |
121 | | - |
122 | | - // Update the database entry for this gadget |
123 | | - $newGadget = new Gadget( $id, $repo, $rev->getRawText(), $gadgetTS ); |
124 | | - $repo->modifyGadget( $newGadget, $rev->getTimestamp() ); |
125 | | - |
126 | | - // modifyGadget() returns a Status object with an error if there was a conflict, |
127 | | - // but we do't care, see similar comment in articleSaveComplete() |
128 | | - return; |
129 | | - } |
130 | | - |
131 | | - /** |
132 | | - * ArticleUndelete hook handler |
133 | | - * @param $title Title object |
134 | | - * @param $created Bool: Whether this undeletion recreated the page |
135 | | - * @param $comment String: Undeletion summary |
136 | | - */ |
137 | | - public static function gadgetDefinitionUndelete( $title, $created, $comment ) { |
138 | | - self::gadgetDefinitionUpdateIfChanged( $title ); |
139 | | - return true; |
140 | | - } |
141 | | - |
142 | | - public static function gadgetDefinitionImport( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) { |
143 | | - self::gadgetDefinitionUpdateIfChanged( $title ); |
144 | | - return true; |
145 | | - } |
146 | | - |
147 | | - /** |
148 | | - * ArticleDeleteComplete hook handler. |
149 | | - * |
150 | | - * @param $article Article |
151 | | - * @param $user User |
152 | | - * @param $reason String: Deletion summary |
153 | | - * @param $id Int: Page ID |
154 | | - */ |
155 | | - public static function cssJsPageDelete( $article, $user, $reason, $id ) { |
156 | | - GadgetPageList::delete( $article->getTitle() ); |
157 | | - return true; |
158 | | - } |
159 | | - |
160 | | - /** |
161 | | - * ArticleSaveComplete hook handler. |
162 | | - * |
163 | | - * @param $article Article |
164 | | - * @param $user User |
165 | | - * @param $text String: New page text |
166 | | - * @param $summary String: Edit summary |
167 | | - * @param $isMinor Bool: Whether this was a minor edit |
168 | | - * @param $isWatch unused |
169 | | - * @param $section unused |
170 | | - * @param $flags: Int: Bitmap of flags passed to WikiPage::doEdit() |
171 | | - * @param $revision: Revision object for the new revision |
172 | | - */ |
173 | | - public static function cssOrJsPageSave( $article, $user, $text, $summary, $isMinor, |
174 | | - $isWatch, $section, $flags, $revision ) |
175 | | - { |
176 | | - $title = $article->getTitle(); |
177 | | - GadgetPageList::updatePageStatus( $title ); |
178 | | - return true; |
179 | | - } |
180 | | - |
181 | | - /** |
182 | | - * ArticleUndelete hook handler |
183 | | - * @param $title Title object |
184 | | - * @param $created Bool: Whether this undeletion recreated the page |
185 | | - * @param $comment String: Undeletion summary |
186 | | - */ |
187 | | - public static function cssOrJsPageUndelete( $title, $created, $comment ) { |
188 | | - GadgetPageList::updatePageStatus( $title ); |
189 | | - return true; |
190 | | - } |
191 | | - |
192 | | - public static function cssOrJsPageMove( $oldTitle, $newTitle, $user, $pageid, $redirid ) { |
193 | | - // Delete the old title from the list. Even if it still exists after the move, |
194 | | - // it'll be a redirect and we don't want those in there |
195 | | - GadgetPageList::delete( $oldTitle ); |
196 | | - |
197 | | - GadgetPageList::updatePageStatus( $newTitle ); |
198 | | - return true; |
199 | | - } |
200 | | - |
201 | | - /** |
202 | | - * UserGetDefaultOptions hook handler |
203 | | - * @param $defaultOptions Array of default preference keys and values |
204 | | - */ |
205 | | - public static function userGetDefaultOptions( &$defaultOptions ) { |
206 | | - $repo = LocalGadgetRepo::singleton(); |
207 | | - $gadgetIds = $repo->getGadgetIds(); |
208 | | - foreach ( $gadgetIds as $gadgetId ) { |
209 | | - $gadget = $repo->getGadget( $gadgetId ); |
210 | | - if ( $gadget->isEnabledByDefault() ) { |
211 | | - $defaultOptions['gadget-' . $gadget->getId()] = 1; |
212 | | - } |
213 | | - } |
214 | | - return true; |
215 | | - } |
216 | | - |
217 | | - /** |
218 | | - * GetPreferences hook handler. |
219 | | - * @param $user User |
220 | | - * @param $preferences Array: Preference descriptions |
221 | | - */ |
222 | | - public static function getPreferences( $user, &$preferences ) { |
223 | | - $repo = LocalGadgetRepo::singleton(); |
224 | | - $gadgets = $repo->getGadgetIds(); |
225 | | - $categories = array(); // array( category => array( desc => title ) ) |
226 | | - $default = array(); // array of Gadget ids |
227 | | - foreach ( $gadgets as $id ) { |
228 | | - $gadget = $repo->getGadget( $id ); |
229 | | - if ( !$gadget->isAllowed( $user ) || $gadget->isHidden() ) { |
230 | | - continue; |
231 | | - } |
232 | | - $category = $gadget->getCategory(); |
233 | | - |
234 | | - // Add the Gadget to the right category |
235 | | - $title = htmlspecialchars( $gadget->getTitleMessage() ); |
236 | | - $description = $gadget->getDescriptionMessage(); // Is parsed, doesn't need escaping |
237 | | - if ( $description === '' ) { |
238 | | - // Empty description, just use the title |
239 | | - $text = $title; |
240 | | - } else { |
241 | | - $text = wfMessage( 'gadgets-preference-description' )->rawParams( $title, $description )->parse(); |
242 | | - } |
243 | | - $categories[$category][$text] = $id; |
244 | | - // Add the Gadget to the default list if enabled |
245 | | - if ( $gadget->isEnabledForUser( $user ) ) { |
246 | | - $default[] = $id; |
247 | | - } |
248 | | - } |
249 | | - |
250 | | - $options = array(); // array( desc1 => gadget1, category1 => array( desc2 => gadget2 ) ) |
251 | | - foreach ( $categories as $category => $gadgets ) { |
252 | | - if ( $category !== '' ) { |
253 | | - $categoryMsg = htmlspecialchars( $repo->getCategoryTitle( $category ) ); |
254 | | - $options[$categoryMsg] = $gadgets; |
255 | | - } else { |
256 | | - $options += $gadgets; |
257 | | - } |
258 | | - } |
259 | | - |
260 | | - $preferences['gadgets-intro'] = |
261 | | - array( |
262 | | - 'type' => 'info', |
263 | | - 'label' => ' ', |
264 | | - 'default' => Xml::tags( 'tr', array(), |
265 | | - Xml::tags( 'td', array( 'colspan' => 2 ), |
266 | | - wfMsgExt( 'gadgets-prefstext', 'parse' ) ) ), |
267 | | - 'section' => 'gadgets', |
268 | | - 'raw' => 1, |
269 | | - 'rawrow' => 1, |
270 | | - ); |
271 | | - $preferences['gadgets'] = |
272 | | - array( |
273 | | - 'type' => 'multiselect', |
274 | | - 'options' => $options, |
275 | | - 'section' => 'gadgets', |
276 | | - 'label' => ' ', |
277 | | - 'prefix' => 'gadget-', |
278 | | - 'default' => $default, |
279 | | - ); |
280 | | - |
281 | | - // Add tab for shared gadgets |
282 | | - $preferences['gadgets-intro-shared'] = |
283 | | - array( |
284 | | - 'type' => 'info', |
285 | | - 'label' => ' ', |
286 | | - 'default' => Xml::tags( 'tr', array(), |
287 | | - Xml::tags( 'td', array( 'colspan' => 2 ), |
288 | | - wfMsgExt( 'gadgets-sharedprefstext', 'parse' ) ) ), |
289 | | - 'section' => 'gadgets-shared', |
290 | | - 'raw' => 1, |
291 | | - 'rawrow' => 1, |
292 | | - ); |
293 | | - $preferences['gadgets-shared'] = |
294 | | - array( |
295 | | - 'type' => 'multiselect', |
296 | | - 'options' => array(), // TODO: Maybe fill in stuff anyway? The backend may need that |
297 | | - 'section' => 'gadgets-shared', |
298 | | - 'label' => ' ', |
299 | | - 'prefix' => 'gadget-', |
300 | | - 'default' => array(), |
301 | | - ); |
302 | | - return true; |
303 | | - } |
304 | | - |
305 | | - /** |
306 | | - * ResourceLoaderRegisterModules hook handler. |
307 | | - * @param $resourceLoader ResourceLoader |
308 | | - */ |
309 | | - public static function registerModules( &$resourceLoader ) { |
310 | | - $gadgets = GadgetRepo::getAllGadgets(); |
311 | | - foreach ( $gadgets as $gadget ) { |
312 | | - $resourceLoader->register( $gadget->getModuleName(), $gadget->getModule() ); |
313 | | - } |
314 | | - return true; |
315 | | - } |
316 | | - |
317 | | - /** |
318 | | - * BeforePageDisplay hook handler. |
319 | | - * @param $out OutputPage |
320 | | - */ |
321 | | - public static function beforePageDisplay( $out ) { |
322 | | - wfProfileIn( __METHOD__ ); |
323 | | - |
324 | | - $user = $out->getUser(); |
325 | | - $gadgets = GadgetRepo::getAllGadgets(); |
326 | | - foreach ( $gadgets as $gadget ) { |
327 | | - if ( $gadget->isEnabledForUser( $user ) && $gadget->isAllowed( $user ) ) { |
328 | | - $out->addModules( $gadget->getModuleName() ); |
329 | | - } |
330 | | - } |
331 | | - |
332 | | - // Add preferences JS if we're on Special:Preferences |
333 | | - if ( $out->getTitle()->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) { |
334 | | - $out->addModules( 'ext.gadgets.preferences' ); |
335 | | - } |
336 | | - |
337 | | - wfProfileOut( __METHOD__ ); |
338 | | - return true; |
339 | | - } |
340 | | - |
341 | | - /** |
342 | | - * MakeGlobalVariablesScript hook handler |
343 | | - * @param $vars Array: Key/value pars for mw.config.set on this page. |
344 | | - * @param $out OutputPage |
345 | | - */ |
346 | | - public static function makeGlobalVariablesScript( &$vars, $out ) { |
347 | | - $title = $out->getTitle(); |
348 | | - $user = $out->getUser(); |
349 | | - // FIXME: This is not a nice way to do it. Maybe we should check for the presence |
350 | | - // of a module instead or something. |
351 | | - if ( $title->equals( SpecialPage::getTitleFor( 'Gadgets' ) ) || |
352 | | - $title->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) |
353 | | - { |
354 | | - global $wgGadgetEnableSharing; |
355 | | - |
356 | | - // Pass the source data for each source that is used by a repository |
357 | | - $repos = GadgetRepo::getAllRepos(); |
358 | | - $sources = $out->getResourceLoader()->getSources(); |
359 | | - $repoData = array(); |
360 | | - foreach ( $repos as $repo ) { |
361 | | - $repoData[$repo->getSource()] = $sources[$repo->getSource()]; |
362 | | - } |
363 | | - |
364 | | - $vars['gadgetsConf'] = array( |
365 | | - 'enableSharing' => $wgGadgetEnableSharing, |
366 | | - 'allRights' => User::getAllRights(), |
367 | | - 'repos' => $repoData, |
368 | | - 'userIsAllowed' => array( |
369 | | - 'editinterface' => $user->isAllowed( 'editinterface' ), |
370 | | - 'gadgets-definition-create' => $user->isAllowed( 'gadgets-definition-create' ), |
371 | | - 'gadgets-definition-edit' => $user->isAllowed( 'gadgets-definition-edit' ), |
372 | | - 'gadgets-definition-delete' => $user->isAllowed( 'gadgets-definition-delete' ), |
373 | | - ), |
374 | | - ); |
375 | | - } |
376 | | - return true; |
377 | | - } |
378 | | - |
379 | | - /** |
380 | | - * UnitTestsList hook handler |
381 | | - * @param $files Array: List of extension test files |
382 | | - */ |
383 | | - public static function unitTestsList( &$files ) { |
384 | | - $files[] = dirname( __FILE__ ) . '/tests/GadgetsTest.php'; |
385 | | - return true; |
386 | | - } |
387 | | - |
388 | | - public static function loadExtensionSchemaUpdates( $updater ) { |
389 | | - $dir = dirname( __FILE__ ); |
390 | | - $updater->addExtensionUpdate( array( 'addtable', 'gadgets', "$dir/sql/gadgets.sql", true ) ); |
391 | | - $updater->addExtensionUpdate( array( 'addtable', 'gadgetpagelist', "$dir/sql/patch-gadgetpagelist.sql", true ) ); |
392 | | - return true; |
393 | | - } |
394 | | - |
395 | | - public static function canonicalNamespaces( &$list ) { |
396 | | - $list[NS_GADGET] = 'Gadget'; |
397 | | - $list[NS_GADGET_TALK] = 'Gadget_talk'; |
398 | | - $list[NS_GADGET_DEFINITION] = 'Gadget_definition'; |
399 | | - $list[NS_GADGET_DEFINITION_TALK] = 'Gadget_definition_talk'; |
400 | | - return true; |
401 | | - } |
402 | | - |
403 | | - public static function titleIsCssOrJsPage( $title, &$result ) { |
404 | | - if ( ( $title->getNamespace() == NS_GADGET || $title->getNamespace() == NS_GADGET_DEFINITION ) && |
405 | | - preg_match( '!\.(css|js)$!u', $title->getText() ) ) |
406 | | - { |
407 | | - $result = true; |
408 | | - } |
409 | | - return true; |
410 | | - } |
411 | | - |
412 | | - public static function titleIsMovable( $title, &$result ) { |
413 | | - if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
414 | | - $result = false; |
415 | | - } |
416 | | - return true; |
417 | | - } |
418 | | - |
419 | | - public static function getUserPermissionsErrors( $title, $user, $action, &$result ) { |
420 | | - if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
421 | | - // Enforce restrictions on the Gadget_definition namespace |
422 | | - if ( $action == 'create' && !$user->isAllowed( 'gadgets-definition-create' ) ) { |
423 | | - $result[] = array( 'gadgets-cant-create' ); |
424 | | - return false; |
425 | | - } elseif ( $action == 'delete' && !$user->isAllowed( 'gadgets-definition-delete' ) ) { |
426 | | - $result[] = array( 'gadgets-cant-delete' ); |
427 | | - return false; |
428 | | - } |
429 | | - } |
430 | | - return true; |
431 | | - } |
432 | | -} |
Index: branches/RL2/extensions/Gadgets/tests/GadgetsTest.php |
— | — | @@ -68,7 +68,7 @@ |
69 | 69 | * baz [rights=embezzle] |baz.js |
70 | 70 | ==keep-section2== |
71 | 71 | * quux [rights=read] | quux.js' ); |
72 | | - $this->assertTrue( GadgetHooks::getPreferences( $wgUser, $prefs ), 'GetPrefences hook should return true' ); |
| 72 | + $this->assertTrue( GadgetsHooks::getPreferences( $wgUser, $prefs ), 'GetPrefences hook should return true' ); |
73 | 73 | |
74 | 74 | $options = $prefs['gadgets']['options']; |
75 | 75 | $this->assertFalse( isset( $options['<gadget-section-remove-section>'] ), 'Must not show empty sections' ); |
Index: branches/RL2/extensions/Gadgets/Gadgets.php |
— | — | @@ -95,25 +95,25 @@ |
96 | 96 | #$wgGroupPermissions['gadgetmanagers']['gadgets-definition-edit'] = true; |
97 | 97 | #$wgGroupPermissions['gadgetmanagers']['gadgets-definition-delete'] = true; |
98 | 98 | |
99 | | -$wgHooks['AfterImportPage'][] = 'GadgetHooks::gadgetDefinitionImport'; |
100 | | -$wgHooks['ArticleDeleteComplete'][] = 'GadgetHooks::gadgetDefinitionDelete'; |
101 | | -$wgHooks['ArticleDeleteComplete'][] = 'GadgetHooks::cssJsPageDelete'; |
102 | | -$wgHooks['ArticleSaveComplete'][] = 'GadgetHooks::gadgetDefinitionSave'; |
103 | | -$wgHooks['ArticleSaveComplete'][] = 'GadgetHooks::cssOrJsPageSave'; |
104 | | -$wgHooks['ArticleUndelete'][] = 'GadgetHooks::gadgetDefinitionUndelete'; |
105 | | -$wgHooks['ArticleUndelete'][] = 'GadgetHooks::cssOrJsPageUndelete'; |
106 | | -$wgHooks['BeforePageDisplay'][] = 'GadgetHooks::beforePageDisplay'; |
107 | | -$wgHooks['MakeGlobalVariablesScript'][] = 'GadgetHooks::makeGlobalVariablesScript'; |
108 | | -$wgHooks['CanonicalNamespaces'][] = 'GadgetHooks::canonicalNamespaces'; |
109 | | -$wgHooks['GetPreferences'][] = 'GadgetHooks::getPreferences'; |
110 | | -$wgHooks['UserGetDefaultOptions'][] = 'GadgetHooks::userGetDefaultOptions'; |
111 | | -$wgHooks['LoadExtensionSchemaUpdates'][] = 'GadgetHooks::loadExtensionSchemaUpdates'; |
112 | | -$wgHooks['ResourceLoaderRegisterModules'][] = 'GadgetHooks::registerModules'; |
113 | | -$wgHooks['TitleIsCssOrJsPage'][] = 'GadgetHooks::titleIsCssOrJsPage'; |
114 | | -$wgHooks['TitleIsMovable'][] = 'GadgetHooks::titleIsMovable'; |
115 | | -$wgHooks['TitleMoveComplete'][] = 'GadgetHooks::cssOrJsPageMove'; |
116 | | -$wgHooks['getUserPermissionsErrors'][] = 'GadgetHooks::getUserPermissionsErrors'; |
117 | | -#$wgHooks['UnitTestsList'][] = 'GadgetHooks::unitTestsList'; // FIXME: broken |
| 99 | +$wgHooks['AfterImportPage'][] = 'GadgetsHooks::gadgetDefinitionImport'; |
| 100 | +$wgHooks['ArticleDeleteComplete'][] = 'GadgetsHooks::gadgetDefinitionDelete'; |
| 101 | +$wgHooks['ArticleDeleteComplete'][] = 'GadgetsHooks::cssJsPageDelete'; |
| 102 | +$wgHooks['ArticleSaveComplete'][] = 'GadgetsHooks::gadgetDefinitionSave'; |
| 103 | +$wgHooks['ArticleSaveComplete'][] = 'GadgetsHooks::cssOrJsPageSave'; |
| 104 | +$wgHooks['ArticleUndelete'][] = 'GadgetsHooks::gadgetDefinitionUndelete'; |
| 105 | +$wgHooks['ArticleUndelete'][] = 'GadgetsHooks::cssOrJsPageUndelete'; |
| 106 | +$wgHooks['BeforePageDisplay'][] = 'GadgetsHooks::beforePageDisplay'; |
| 107 | +$wgHooks['MakeGlobalVariablesScript'][] = 'GadgetsHooks::makeGlobalVariablesScript'; |
| 108 | +$wgHooks['CanonicalNamespaces'][] = 'GadgetsHooks::canonicalNamespaces'; |
| 109 | +$wgHooks['GetPreferences'][] = 'GadgetsHooks::getPreferences'; |
| 110 | +$wgHooks['UserGetDefaultOptions'][] = 'GadgetsHooks::userGetDefaultOptions'; |
| 111 | +$wgHooks['LoadExtensionSchemaUpdates'][] = 'GadgetsHooks::loadExtensionSchemaUpdates'; |
| 112 | +$wgHooks['ResourceLoaderRegisterModules'][] = 'GadgetsHooks::registerModules'; |
| 113 | +$wgHooks['TitleIsCssOrJsPage'][] = 'GadgetsHooks::titleIsCssOrJsPage'; |
| 114 | +$wgHooks['TitleIsMovable'][] = 'GadgetsHooks::titleIsMovable'; |
| 115 | +$wgHooks['TitleMoveComplete'][] = 'GadgetsHooks::cssOrJsPageMove'; |
| 116 | +$wgHooks['getUserPermissionsErrors'][] = 'GadgetsHooks::getUserPermissionsErrors'; |
| 117 | +#$wgHooks['UnitTestsList'][] = 'GadgetsHooks::unitTestsList'; // FIXME: broken |
118 | 118 | |
119 | 119 | $dir = dirname(__FILE__) . '/'; |
120 | 120 | $wgExtensionMessagesFiles['Gadgets'] = $dir . 'Gadgets.i18n.php'; |
— | — | @@ -125,7 +125,7 @@ |
126 | 126 | $wgAutoloadClasses['ApiQueryGadgets'] = $dir . 'api/ApiQueryGadgets.php'; |
127 | 127 | $wgAutoloadClasses['ForeignDBGadgetRepo'] = $dir . 'backend/ForeignDBGadgetRepo.php'; |
128 | 128 | $wgAutoloadClasses['Gadget'] = $dir . 'backend/Gadget.php'; |
129 | | -$wgAutoloadClasses['GadgetHooks'] = $dir . 'GadgetHooks.php'; |
| 129 | +$wgAutoloadClasses['GadgetsHooks'] = $dir . 'Gadgets.hooks.php'; |
130 | 130 | $wgAutoloadClasses['GadgetPageList'] = $dir . 'backend/GadgetPageList.php'; |
131 | 131 | $wgAutoloadClasses['GadgetRepo'] = $dir . 'backend/GadgetRepo.php'; |
132 | 132 | $wgAutoloadClasses['GadgetResourceLoaderModule'] = $dir . 'backend/GadgetResourceLoaderModule.php'; |
Index: branches/RL2/extensions/Gadgets/SpecialGadgets.php |
— | — | @@ -124,7 +124,7 @@ |
125 | 125 | ); |
126 | 126 | if ( $user->isAllowed( 'gadgets-definition-edit' ) ) { |
127 | 127 | $extra[] = Linker::link( |
128 | | - GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ), |
| 128 | + GadgetsHooks::getDefinitionTitleFromID( $gadget->getId() ), |
129 | 129 | wfMessage( 'gadgets-gadget-modify' )->escaped(), |
130 | 130 | array( |
131 | 131 | 'title' => wfMessage( 'gadgets-gadget-modify-tooltip' )->plain(), |
— | — | @@ -136,7 +136,7 @@ |
137 | 137 | |
138 | 138 | if ( $user->isAllowed( 'gadgets-definition-delete' ) ) { |
139 | 139 | $extra[] = Linker::link( |
140 | | - GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ), |
| 140 | + GadgetsHooks::getDefinitionTitleFromID( $gadget->getId() ), |
141 | 141 | wfMessage( 'gadgets-gadget-delete' )->escaped(), |
142 | 142 | array( |
143 | 143 | 'title' => wfMessage( 'gadgets-gadget-delete-tooltip' )->plain(), |
— | — | @@ -327,7 +327,7 @@ |
328 | 328 | $exportTitles = array(); |
329 | 329 | |
330 | 330 | // NS_GADGET_DEFINITION page of this gadget |
331 | | - $exportTitles[] = GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ); |
| 331 | + $exportTitles[] = GadgetsHooks::getDefinitionTitleFromID( $gadget->getId() ); |
332 | 332 | |
333 | 333 | // Title message in NS_MEDIAWIKI |
334 | 334 | $exportTitles[] = Title::makeTitleSafe( NS_MEDIAWIKI, $gadget->getTitleMessageKey() ); |
Index: branches/RL2/extensions/Gadgets/Gadgets.hooks.php |
— | — | @@ -0,0 +1,431 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Gadgets extension - lets users select custom javascript gadgets |
| 5 | + * |
| 6 | + * |
| 7 | + * For more info see http://mediawiki.org/wiki/Extension:Gadgets |
| 8 | + * |
| 9 | + * @file |
| 10 | + * @ingroup Extensions |
| 11 | + * @author Daniel Kinzler, brightbyte.de |
| 12 | + * @copyright © 2007 Daniel Kinzler |
| 13 | + * @license GNU General Public Licence 2.0 or later |
| 14 | + */ |
| 15 | + |
| 16 | +class GadgetsHooks { |
| 17 | + /** |
| 18 | + * Get the gadget ID from a title |
| 19 | + * @param $title Title object |
| 20 | + * @return string Gadget id or null if not a gadget definition page |
| 21 | + */ |
| 22 | + public static function getIDFromTitle( Title $title ) { |
| 23 | + $id = $title->getText(); |
| 24 | + if ( $title->getNamespace() !== NS_GADGET_DEFINITION || !preg_match( '!\.js$!u', $id ) ) { |
| 25 | + // Not a gadget definition page |
| 26 | + return null; |
| 27 | + } |
| 28 | + // Trim .js from the page name to obtain the gadget ID |
| 29 | + return substr( $id, 0, -3 ); |
| 30 | + } |
| 31 | + |
| 32 | + /** |
| 33 | + * Get a Title object of the gadget definition page from a gadget id |
| 34 | + * @param $is String |
| 35 | + * @return Title|null |
| 36 | + */ |
| 37 | + public static function getDefinitionTitleFromID( $id ) { |
| 38 | + return Title::makeTitleSafe( NS_GADGET_DEFINITION, $id . '.js' ); |
| 39 | + } |
| 40 | + |
| 41 | + /** |
| 42 | + * ArticleDeleteComplete hook handler. |
| 43 | + * |
| 44 | + * @param $article Article |
| 45 | + * @param $user User |
| 46 | + * @param $reason String: Deletion summary |
| 47 | + * @param $id Int: Page ID |
| 48 | + */ |
| 49 | + public static function gadgetDefinitionDelete( $article, $user, $reason, $id ) { |
| 50 | + $id = self::getIDFromTitle( $article->getTitle() ); |
| 51 | + if ( !$id ) { |
| 52 | + return true; |
| 53 | + } |
| 54 | + |
| 55 | + $repo = LocalGadgetRepo::singleton(); |
| 56 | + $repo->deleteGadget( $id ); |
| 57 | + // deleteGadget() may return an error if the Gadget didn't exist, but we don't care here |
| 58 | + return true; |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * ArticleSaveComplete hook handler. |
| 63 | + * |
| 64 | + * @param $article Article |
| 65 | + * @param $user User |
| 66 | + * @param $text String: New page text |
| 67 | + * @param $summary String: Edit summary |
| 68 | + * @param $isMinor Bool: Whether this was a minor edit |
| 69 | + * @param $isWatch unused |
| 70 | + * @param $section unused |
| 71 | + * @param $flags: Int: Bitmap of flags passed to WikiPage::doEdit() |
| 72 | + * @param $revision: Revision object for the new revision |
| 73 | + */ |
| 74 | + public static function gadgetDefinitionSave( $article, $user, $text, $summary, $isMinor, |
| 75 | + $isWatch, $section, $flags, $revision ) |
| 76 | + { |
| 77 | + $id = self::getIDFromTitle( $article->getTitle() ); |
| 78 | + if ( !$id ) { |
| 79 | + return true; |
| 80 | + } |
| 81 | + |
| 82 | + $previousRev = $revision->getPrevious(); |
| 83 | + $prevTs = $previousRev instanceof Revision ? $previousRev->getTimestamp() : wfTimestampNow(); |
| 84 | + |
| 85 | + // Update the database entry for this gadget |
| 86 | + $repo = LocalGadgetRepo::singleton(); |
| 87 | + // TODO: Timestamp in the constructor is ugly |
| 88 | + $gadget = new Gadget( $id, $repo, $text, $prevTs ); |
| 89 | + $repo->modifyGadget( $gadget, $revision->getTimestamp() ); |
| 90 | + |
| 91 | + // modifyGadget() returns a Status object with an error if there was a conflict, |
| 92 | + // but we don't care. If a conflict occurred, that must be because a newer edit's |
| 93 | + // DB update occurred before ours, in which case the right thing to do is to occu |
| 94 | + |
| 95 | + return true; |
| 96 | + } |
| 97 | + |
| 98 | + /** |
| 99 | + * Update the database entry for a gadget if the description page is |
| 100 | + * newer than the database entry. |
| 101 | + * @param $title Title object |
| 102 | + */ |
| 103 | + public static function gadgetDefinitionUpdateIfChanged( $title ) { |
| 104 | + $id = self::getIDFromTitle( $title ); |
| 105 | + if ( !$id ) { |
| 106 | + return; |
| 107 | + } |
| 108 | + |
| 109 | + // Check whether this undeletion changed the latest revision of the page, by comparing |
| 110 | + // the timestamp of the latest revision with the timestamp in the DB |
| 111 | + $repo = LocalGadgetRepo::singleton(); |
| 112 | + $gadget = $repo->getGadget( $id ); |
| 113 | + $gadgetTS = $gadget ? $gadget->getTimestamp() : 0; |
| 114 | + |
| 115 | + $rev = Revision::newFromTitle( $title ); |
| 116 | + if ( wfTimestamp( TS_MW, $rev->getTimestamp() ) === |
| 117 | + wfTimestamp( TS_MW, $gadgetTS ) ) { |
| 118 | + // The latest rev didn't change. Someone must've undeleted an older revision |
| 119 | + return; |
| 120 | + } |
| 121 | + |
| 122 | + // Update the database entry for this gadget |
| 123 | + $newGadget = new Gadget( $id, $repo, $rev->getRawText(), $gadgetTS ); |
| 124 | + $repo->modifyGadget( $newGadget, $rev->getTimestamp() ); |
| 125 | + |
| 126 | + // modifyGadget() returns a Status object with an error if there was a conflict, |
| 127 | + // but we do't care, see similar comment in articleSaveComplete() |
| 128 | + return; |
| 129 | + } |
| 130 | + |
| 131 | + /** |
| 132 | + * ArticleUndelete hook handler |
| 133 | + * @param $title Title object |
| 134 | + * @param $created Bool: Whether this undeletion recreated the page |
| 135 | + * @param $comment String: Undeletion summary |
| 136 | + */ |
| 137 | + public static function gadgetDefinitionUndelete( $title, $created, $comment ) { |
| 138 | + self::gadgetDefinitionUpdateIfChanged( $title ); |
| 139 | + return true; |
| 140 | + } |
| 141 | + |
| 142 | + public static function gadgetDefinitionImport( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) { |
| 143 | + self::gadgetDefinitionUpdateIfChanged( $title ); |
| 144 | + return true; |
| 145 | + } |
| 146 | + |
| 147 | + /** |
| 148 | + * ArticleDeleteComplete hook handler. |
| 149 | + * |
| 150 | + * @param $article Article |
| 151 | + * @param $user User |
| 152 | + * @param $reason String: Deletion summary |
| 153 | + * @param $id Int: Page ID |
| 154 | + */ |
| 155 | + public static function cssJsPageDelete( $article, $user, $reason, $id ) { |
| 156 | + GadgetPageList::delete( $article->getTitle() ); |
| 157 | + return true; |
| 158 | + } |
| 159 | + |
| 160 | + /** |
| 161 | + * ArticleSaveComplete hook handler. |
| 162 | + * |
| 163 | + * @param $article Article |
| 164 | + * @param $user User |
| 165 | + * @param $text String: New page text |
| 166 | + * @param $summary String: Edit summary |
| 167 | + * @param $isMinor Bool: Whether this was a minor edit |
| 168 | + * @param $isWatch unused |
| 169 | + * @param $section unused |
| 170 | + * @param $flags: Int: Bitmap of flags passed to WikiPage::doEdit() |
| 171 | + * @param $revision: Revision object for the new revision |
| 172 | + */ |
| 173 | + public static function cssOrJsPageSave( $article, $user, $text, $summary, $isMinor, |
| 174 | + $isWatch, $section, $flags, $revision ) |
| 175 | + { |
| 176 | + $title = $article->getTitle(); |
| 177 | + GadgetPageList::updatePageStatus( $title ); |
| 178 | + return true; |
| 179 | + } |
| 180 | + |
| 181 | + /** |
| 182 | + * ArticleUndelete hook handler |
| 183 | + * @param $title Title object |
| 184 | + * @param $created Bool: Whether this undeletion recreated the page |
| 185 | + * @param $comment String: Undeletion summary |
| 186 | + */ |
| 187 | + public static function cssOrJsPageUndelete( $title, $created, $comment ) { |
| 188 | + GadgetPageList::updatePageStatus( $title ); |
| 189 | + return true; |
| 190 | + } |
| 191 | + |
| 192 | + public static function cssOrJsPageMove( $oldTitle, $newTitle, $user, $pageid, $redirid ) { |
| 193 | + // Delete the old title from the list. Even if it still exists after the move, |
| 194 | + // it'll be a redirect and we don't want those in there |
| 195 | + GadgetPageList::delete( $oldTitle ); |
| 196 | + |
| 197 | + GadgetPageList::updatePageStatus( $newTitle ); |
| 198 | + return true; |
| 199 | + } |
| 200 | + |
| 201 | + /** |
| 202 | + * UserGetDefaultOptions hook handler |
| 203 | + * @param $defaultOptions Array of default preference keys and values |
| 204 | + */ |
| 205 | + public static function userGetDefaultOptions( &$defaultOptions ) { |
| 206 | + $repo = LocalGadgetRepo::singleton(); |
| 207 | + $gadgetIds = $repo->getGadgetIds(); |
| 208 | + foreach ( $gadgetIds as $gadgetId ) { |
| 209 | + $gadget = $repo->getGadget( $gadgetId ); |
| 210 | + if ( $gadget->isEnabledByDefault() ) { |
| 211 | + $defaultOptions['gadget-' . $gadget->getId()] = 1; |
| 212 | + } |
| 213 | + } |
| 214 | + return true; |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + * GetPreferences hook handler. |
| 219 | + * @param $user User |
| 220 | + * @param $preferences Array: Preference descriptions |
| 221 | + */ |
| 222 | + public static function getPreferences( $user, &$preferences ) { |
| 223 | + $repo = LocalGadgetRepo::singleton(); |
| 224 | + $gadgets = $repo->getGadgetIds(); |
| 225 | + $categories = array(); // array( category => array( desc => title ) ) |
| 226 | + $default = array(); // array of Gadget ids |
| 227 | + foreach ( $gadgets as $id ) { |
| 228 | + $gadget = $repo->getGadget( $id ); |
| 229 | + if ( !$gadget->isAllowed( $user ) || $gadget->isHidden() ) { |
| 230 | + continue; |
| 231 | + } |
| 232 | + $category = $gadget->getCategory(); |
| 233 | + |
| 234 | + // Add the Gadget to the right category |
| 235 | + $title = htmlspecialchars( $gadget->getTitleMessage() ); |
| 236 | + $description = $gadget->getDescriptionMessage(); // Is parsed, doesn't need escaping |
| 237 | + if ( $description === '' ) { |
| 238 | + // Empty description, just use the title |
| 239 | + $text = $title; |
| 240 | + } else { |
| 241 | + $text = wfMessage( 'gadgets-preference-description' )->rawParams( $title, $description )->parse(); |
| 242 | + } |
| 243 | + $categories[$category][$text] = $id; |
| 244 | + // Add the Gadget to the default list if enabled |
| 245 | + if ( $gadget->isEnabledForUser( $user ) ) { |
| 246 | + $default[] = $id; |
| 247 | + } |
| 248 | + } |
| 249 | + |
| 250 | + $options = array(); // array( desc1 => gadget1, category1 => array( desc2 => gadget2 ) ) |
| 251 | + foreach ( $categories as $category => $gadgets ) { |
| 252 | + if ( $category !== '' ) { |
| 253 | + $categoryMsg = htmlspecialchars( $repo->getCategoryTitle( $category ) ); |
| 254 | + $options[$categoryMsg] = $gadgets; |
| 255 | + } else { |
| 256 | + $options += $gadgets; |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | + $preferences['gadgets-intro'] = |
| 261 | + array( |
| 262 | + 'type' => 'info', |
| 263 | + 'label' => ' ', |
| 264 | + 'default' => Xml::tags( 'tr', array(), |
| 265 | + Xml::tags( 'td', array( 'colspan' => 2 ), |
| 266 | + wfMsgExt( 'gadgets-prefstext', 'parse' ) ) ), |
| 267 | + 'section' => 'gadgets', |
| 268 | + 'raw' => 1, |
| 269 | + 'rawrow' => 1, |
| 270 | + ); |
| 271 | + $preferences['gadgets'] = |
| 272 | + array( |
| 273 | + 'type' => 'multiselect', |
| 274 | + 'options' => $options, |
| 275 | + 'section' => 'gadgets', |
| 276 | + 'label' => ' ', |
| 277 | + 'prefix' => 'gadget-', |
| 278 | + 'default' => $default, |
| 279 | + ); |
| 280 | + |
| 281 | + // Add tab for shared gadgets |
| 282 | + $preferences['gadgets-intro-shared'] = |
| 283 | + array( |
| 284 | + 'type' => 'info', |
| 285 | + 'label' => ' ', |
| 286 | + 'default' => Xml::tags( 'tr', array(), |
| 287 | + Xml::tags( 'td', array( 'colspan' => 2 ), |
| 288 | + wfMsgExt( 'gadgets-sharedprefstext', 'parse' ) ) ), |
| 289 | + 'section' => 'gadgets-shared', |
| 290 | + 'raw' => 1, |
| 291 | + 'rawrow' => 1, |
| 292 | + ); |
| 293 | + $preferences['gadgets-shared'] = |
| 294 | + array( |
| 295 | + 'type' => 'multiselect', |
| 296 | + 'options' => array(), // TODO: Maybe fill in stuff anyway? The backend may need that |
| 297 | + 'section' => 'gadgets-shared', |
| 298 | + 'label' => ' ', |
| 299 | + 'prefix' => 'gadget-', |
| 300 | + 'default' => array(), |
| 301 | + ); |
| 302 | + return true; |
| 303 | + } |
| 304 | + |
| 305 | + /** |
| 306 | + * ResourceLoaderRegisterModules hook handler. |
| 307 | + * @param $resourceLoader ResourceLoader |
| 308 | + */ |
| 309 | + public static function registerModules( &$resourceLoader ) { |
| 310 | + $gadgets = GadgetRepo::getAllGadgets(); |
| 311 | + foreach ( $gadgets as $gadget ) { |
| 312 | + $resourceLoader->register( $gadget->getModuleName(), $gadget->getModule() ); |
| 313 | + } |
| 314 | + return true; |
| 315 | + } |
| 316 | + |
| 317 | + /** |
| 318 | + * BeforePageDisplay hook handler. |
| 319 | + * @param $out OutputPage |
| 320 | + */ |
| 321 | + public static function beforePageDisplay( $out ) { |
| 322 | + wfProfileIn( __METHOD__ ); |
| 323 | + |
| 324 | + $user = $out->getUser(); |
| 325 | + $gadgets = GadgetRepo::getAllGadgets(); |
| 326 | + foreach ( $gadgets as $gadget ) { |
| 327 | + if ( $gadget->isEnabledForUser( $user ) && $gadget->isAllowed( $user ) ) { |
| 328 | + $out->addModules( $gadget->getModuleName() ); |
| 329 | + } |
| 330 | + } |
| 331 | + |
| 332 | + // Add preferences JS if we're on Special:Preferences |
| 333 | + if ( $out->getTitle()->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) { |
| 334 | + $out->addModules( 'ext.gadgets.preferences' ); |
| 335 | + } |
| 336 | + |
| 337 | + wfProfileOut( __METHOD__ ); |
| 338 | + return true; |
| 339 | + } |
| 340 | + |
| 341 | + /** |
| 342 | + * MakeGlobalVariablesScript hook handler |
| 343 | + * @param $vars Array: Key/value pars for mw.config.set on this page. |
| 344 | + * @param $out OutputPage |
| 345 | + */ |
| 346 | + public static function makeGlobalVariablesScript( &$vars, $out ) { |
| 347 | + $title = $out->getTitle(); |
| 348 | + $user = $out->getUser(); |
| 349 | + // FIXME: This is not a nice way to do it. Maybe we should check for the presence |
| 350 | + // of a module instead or something. |
| 351 | + if ( $title->equals( SpecialPage::getTitleFor( 'Gadgets' ) ) || |
| 352 | + $title->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) |
| 353 | + { |
| 354 | + global $wgGadgetEnableSharing; |
| 355 | + |
| 356 | + // Pass the source data for each source that is used by a repository |
| 357 | + $repos = GadgetRepo::getAllRepos(); |
| 358 | + $sources = $out->getResourceLoader()->getSources(); |
| 359 | + $repoData = array(); |
| 360 | + foreach ( $repos as $repo ) { |
| 361 | + $repoData[$repo->getSource()] = $sources[$repo->getSource()]; |
| 362 | + } |
| 363 | + |
| 364 | + $vars['gadgetsConf'] = array( |
| 365 | + 'enableSharing' => $wgGadgetEnableSharing, |
| 366 | + 'allRights' => User::getAllRights(), |
| 367 | + 'repos' => $repoData, |
| 368 | + 'userIsAllowed' => array( |
| 369 | + 'editinterface' => $user->isAllowed( 'editinterface' ), |
| 370 | + 'gadgets-definition-create' => $user->isAllowed( 'gadgets-definition-create' ), |
| 371 | + 'gadgets-definition-edit' => $user->isAllowed( 'gadgets-definition-edit' ), |
| 372 | + 'gadgets-definition-delete' => $user->isAllowed( 'gadgets-definition-delete' ), |
| 373 | + ), |
| 374 | + ); |
| 375 | + } |
| 376 | + return true; |
| 377 | + } |
| 378 | + |
| 379 | + /** |
| 380 | + * UnitTestsList hook handler |
| 381 | + * @param $files Array: List of extension test files |
| 382 | + */ |
| 383 | + public static function unitTestsList( &$files ) { |
| 384 | + $files[] = dirname( __FILE__ ) . '/tests/GadgetsTest.php'; |
| 385 | + return true; |
| 386 | + } |
| 387 | + |
| 388 | + public static function loadExtensionSchemaUpdates( $updater ) { |
| 389 | + $dir = dirname( __FILE__ ); |
| 390 | + $updater->addExtensionUpdate( array( 'addtable', 'gadgets', "$dir/sql/gadgets.sql", true ) ); |
| 391 | + $updater->addExtensionUpdate( array( 'addtable', 'gadgetpagelist', "$dir/sql/patch-gadgetpagelist.sql", true ) ); |
| 392 | + return true; |
| 393 | + } |
| 394 | + |
| 395 | + public static function canonicalNamespaces( &$list ) { |
| 396 | + $list[NS_GADGET] = 'Gadget'; |
| 397 | + $list[NS_GADGET_TALK] = 'Gadget_talk'; |
| 398 | + $list[NS_GADGET_DEFINITION] = 'Gadget_definition'; |
| 399 | + $list[NS_GADGET_DEFINITION_TALK] = 'Gadget_definition_talk'; |
| 400 | + return true; |
| 401 | + } |
| 402 | + |
| 403 | + public static function titleIsCssOrJsPage( $title, &$result ) { |
| 404 | + if ( ( $title->getNamespace() == NS_GADGET || $title->getNamespace() == NS_GADGET_DEFINITION ) && |
| 405 | + preg_match( '!\.(css|js)$!u', $title->getText() ) ) |
| 406 | + { |
| 407 | + $result = true; |
| 408 | + } |
| 409 | + return true; |
| 410 | + } |
| 411 | + |
| 412 | + public static function titleIsMovable( $title, &$result ) { |
| 413 | + if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
| 414 | + $result = false; |
| 415 | + } |
| 416 | + return true; |
| 417 | + } |
| 418 | + |
| 419 | + public static function getUserPermissionsErrors( $title, $user, $action, &$result ) { |
| 420 | + if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
| 421 | + // Enforce restrictions on the Gadget_definition namespace |
| 422 | + if ( $action == 'create' && !$user->isAllowed( 'gadgets-definition-create' ) ) { |
| 423 | + $result[] = array( 'gadgets-cant-create' ); |
| 424 | + return false; |
| 425 | + } elseif ( $action == 'delete' && !$user->isAllowed( 'gadgets-definition-delete' ) ) { |
| 426 | + $result[] = array( 'gadgets-cant-delete' ); |
| 427 | + return false; |
| 428 | + } |
| 429 | + } |
| 430 | + return true; |
| 431 | + } |
| 432 | +} |
Property changes on: branches/RL2/extensions/Gadgets/Gadgets.hooks.php |
___________________________________________________________________ |
Added: svn:mergeinfo |
1 | 433 | Merged /branches/Gadgets-work/Gadgets_body.php:r73145-76526 |
2 | 434 | Merged /branches/wmf/1.17wmf1/extensions/Gadgets/Gadgets_body.php:r81884 |
Added: svn:eol-style |
3 | 435 | + native |
Added: svn:keywords |
4 | 436 | + LastChangedDate LastChangedRevision |