Index: branches/RL2/extensions/Gadgets/Gadgets.i18n.php |
— | — | @@ -15,41 +15,64 @@ |
16 | 16 | */ |
17 | 17 | $messages['en'] = array( |
18 | 18 | # For Special:Version |
19 | | - 'gadgets-desc' => 'Lets users select custom [[Special:Gadgets|CSS and JavaScript gadgets]] in their [[Special:Preferences#mw-prefsection-gadgets|preferences]].', |
| 19 | + 'gadgets-desc' => 'Lets users select custom [[Special:Gadgets|CSS and JavaScript gadgets]] in their [[Special:Preferences#mw-prefsection-gadgets|preferences]].', |
20 | 20 | |
21 | 21 | # For Special:Preferences |
22 | | - 'prefs-gadgets' => 'Gadgets', |
| 22 | + 'prefs-gadgets' => 'Gadgets', |
23 | 23 | 'prefs-gadgets-shared' => 'Shared gadgets', |
24 | 24 | 'gadgets-prefstext' => 'Below is a list of gadgets you can enable for your account. |
25 | 25 | These gadgets are mostly based on JavaScript, so JavaScript has to be enabled in your browser for them to work. |
26 | 26 | Note that these gadgets will have no effect on this preferences page. |
27 | 27 | |
28 | 28 | Also note that these gadgets are not part of the MediaWiki software, and are usually developed and maintained by users of the wiki. |
29 | | -Administrators manage to the [[Special:GadgetManager|gadget definitions]] and the [[Special:Gadgets|titles and descriptions]] of available gadgets.', |
| 29 | +Administrators manage the [[Special:Gadgets|gadget definitions, titles and descriptions]] of available gadgets.', |
30 | 30 | 'gadgets-preference-description' => '$1: $2', |
31 | 31 | 'gadgets-sharedprefstext' => 'Below is a list of gadgets from other wikis. TODO: This needs more text', |
32 | 32 | |
33 | 33 | # For Special:Gadgets |
34 | | - 'gadgets' => 'Gadgets', |
35 | | - 'gadgets-title' => 'Gadgets', |
36 | | - 'gadgets-pagetext' => "Below is a list of gadgets available on this wiki. Users can enable or disable these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]]. |
37 | | -This overview provides easy access to the system message pages that define each gadget's description and title. Welcome to the gadget management interface. Below is an overview of all the configurable options for this gadget. defined on this wiki. Users can opt in or opt out of these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]]. All modifications to gadget definitions can be followed in the [$1 recent changes]", |
| 34 | + // General |
| 35 | + 'gadgets' => 'Gadgets', |
| 36 | + 'gadgets-title' => 'Gadgets', |
| 37 | + 'gadgets-not-found' => 'Gadget "$1" not found.', |
| 38 | + 'gadgets-nosuchaction' => 'No such action', |
| 39 | + |
| 40 | + // Main page |
| 41 | + 'gadgets-pagetext' => "Below is a list of gadgets available on this wiki. Users can enable or disable these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]]. |
| 42 | +This overview provides easy access to the gadget defintions and system message pages that define each gadget's description and title. |
| 43 | + |
| 44 | +* [[$1|recent changes]]", // @todo FIXME: Make the 'recent changes' link more integrated (a tab perhaps) |
38 | 45 | 'gadgets-nogadgets' => 'This wiki currently has no gadgets defined.', |
39 | | - 'gadgets-uses' => 'Uses', |
40 | | - 'gadgets-required-rights' => 'Requires the {{PLURAL:$2|$1 right|following rights: $1}}.', |
41 | | - 'gadgets-default' => 'Enabled for everyone by default.', |
42 | | - 'gadgets-export' => 'Export', |
43 | | - 'gadgets-export-title' => 'Gadget export', |
44 | | - 'gadgets-not-found' => 'Gadget "$1" not found.', |
45 | | - 'gadgets-export-text' => 'To export the $1 gadget, click on "{{int:gadgets-export-download}}" button, save the downloaded file, |
46 | | -go to Special:Import on destination wiki and upload it. You must have appropriate permissions on the destination wiki (including the right to edit in the {{ns:Gadget}} and {{ns:Gadget definition}} namespaces) and the import from file uploads must be enabled.', |
| 46 | + 'gadgets-uncategorized' => 'Uncategorized', |
| 47 | + 'gadgets-message-edit' => 'Edit', |
| 48 | + 'gadgets-message-edit-tooltip' => 'Edit this message at $1', |
| 49 | + 'gadgets-desc-edit' => 'Edit description', |
| 50 | + 'gadgets-desc-edit-tooltip' => 'Edit the description at $1', |
| 51 | + 'gadgets-desc-add' => 'Add description', |
| 52 | + 'gadgets-desc-add-tooltip' => 'Add a description at $1', |
| 53 | + 'gadgets-gadget-permalink' => 'Permalink', |
| 54 | + 'gadgets-gadget-permalink-tooltip' => 'Permalink to the definition of this gadget', |
| 55 | + 'gadgets-gadget-export' => 'Export', |
| 56 | + 'gadgets-gadget-export-tooltip' => 'Export this gadget', |
| 57 | + 'gadgets-gadget-modify' => 'Modify gadget', |
| 58 | + 'gadgets-gadget-modify-tooltip' => 'Open the edit form for the gadget definition of $1', |
| 59 | + 'gadgets-gadget-delete' => 'Delete gadget', |
| 60 | + 'gadgets-gadget-delete-tooltip' => 'Delete this gadget', |
| 61 | + |
| 62 | + // Single gadget page |
| 63 | + 'gadgets-gadget-title' => 'Gadget "$1"', |
| 64 | + 'gadgets-prop-default-on' => 'This gadget is enabled for everyone by default.', |
| 65 | + 'gadgets-prop-hidden-on' => 'This is a hidden gadget.', |
| 66 | + 'gadgets-prop-shared-on' => 'This gadget is shared.', |
| 67 | + |
| 68 | + // Export page |
| 69 | + 'gadgets-export-title' => 'Exporting gadget "$1"', |
| 70 | + 'gadgets-export-text' => 'To export this gadget, click on "{{int:gadgets-export-download}}" button, save the downloaded file, |
| 71 | +go to Special:Import on destination wiki and upload it. You must have appropriate permissions on the destination wiki ($3) including the right to edit in the {{ns:Gadget}} and {{ns:Gadget_definition}} namespaces.', |
47 | 72 | 'gadgets-export-download' => 'Download', |
48 | 73 | |
49 | 74 | # For the ext.gadgets.gadgetmanager module |
50 | | - 'gadgetmanager-title' => 'Gadget management', |
51 | | - 'gadgetmanager-uncategorized' => 'Uncategorized', |
52 | | - 'gadgetmanager-tablehead-lastmod' => 'Last modified', |
53 | | - 'gadgetmanager-tablecell-lastmod' => '$1 by $2', |
| 75 | + 'gadgets-gadget-create' => 'Create', |
| 76 | + 'gadgets-gadget-create-tooltip' => 'Create new gadget', |
54 | 77 | 'gadgetmanager-editor-title' => 'Editing $1:', |
55 | 78 | 'gadgetmanager-editor-removeprop-tooltip' => 'Remove this item', |
56 | 79 | 'gadgetmanager-editor-save' => 'Save gadget', |
— | — | @@ -62,14 +85,11 @@ |
63 | 86 | 'gadgetmanager-prop-messages' => 'Messages', |
64 | 87 | 'gadgetmanager-prop-category' => 'Category', |
65 | 88 | 'gadgetmanager-prop-rights' => 'Required user rights', |
66 | | - 'gadgetmanager-prop-default' => 'Enable for everyone by default', |
| 89 | + 'gadgetmanager-prop-default' => 'Enable by default', |
67 | 90 | 'gadgetmanager-prop-hidden' => 'Hide gadget', |
68 | 91 | 'gadgetmanager-prop-shared' => 'Share gadget', |
69 | | - 'gadgetmanager-prop-default-yes' => 'This gadget is loaded by default.', |
70 | | - 'gadgetmanager-prop-hidden-yes' => 'This is a hidden gadget.', |
71 | | - 'gadgetmanager-prop-shared-yes' => 'This gadget is shared.', |
72 | | - 'gadgetmanager-comment-modify' => 'Modified definition of gadget [[Special:GadgetManager/$1|$1]]', |
73 | | - |
| 92 | + 'gadgetmanager-comment-modify' => 'Modified definition of gadget [[Special:Gadgets/$1|$1]]', |
| 93 | + |
74 | 94 | # Validation error messages |
75 | 95 | 'gadget-validate-invalidjson' => 'The gadget definition page contents are not a valid JSON object.', |
76 | 96 | 'gadget-validate-notset' => 'The property $1 is not set.', |
— | — | @@ -112,34 +132,37 @@ |
113 | 133 | |
114 | 134 | # For Special:Gadgets |
115 | 135 | 'gadgets-title' => '{{Identical|Gadgets}}', |
116 | | - 'gadgets-uses' => "This is used as a verb in third-person singular. It appears in front of a script name. Example: \"''Uses: Gadget-UTCLiveClock.js''\" |
| 136 | + 'gadgets-export' => 'Used on [[Special:Gadgets]]. This is a verb, not noun. |
117 | 137 | |
118 | | -See [http://mediawiki.org/wiki/Special:Gadgets Gadgets overview on mediawiki.org]", |
119 | | - 'gadgets-required-rights' => 'Parameters: |
120 | | -* $1 - a list. |
121 | | -* $2 - the number of items in list $1 for PLURAL use.', |
122 | | - 'gadgets-export' => 'Used on [[Special:Gadgets]]. This is a verb, not noun. |
123 | 138 | {{Identical|Export}}', |
124 | 139 | 'gadgets-export-download' => 'Use the verb for this message. Submit button. |
| 140 | + |
125 | 141 | {{Identical|Download}}', |
| 142 | + 'gadgets-message-edit' => 'Used as linktext for the link to edit the cateogory title, gadget title or gadget description. |
126 | 143 | |
| 144 | +{{Identical|Edit}}', |
| 145 | + 'gadgets-message-edit-tooltip' => 'Parameters: |
| 146 | +* $1: Page name in the MediaWiki namespace where this message is defined.', |
| 147 | + 'gadgets-desc-add' => 'Used as linktext for the link to create gadget description. |
| 148 | + |
| 149 | +{{Identical|Add}}.', |
| 150 | + 'gadgets-desc-add-tooltip' => 'Parameters: |
| 151 | +* $1: Page name in the MediaWiki namespace where this message is defined.', |
| 152 | + 'gadgets-nosuchaction' => 'Identical to core: |
| 153 | +* {{mw-msg|nosuchaction}}.', |
| 154 | + 'gadgets-gadget-create' => 'Identical to core: |
| 155 | +* {{mw-msg|vector-view-create}} |
| 156 | +* {{mw-msg|create}}', |
| 157 | + |
| 158 | + # For the ext.gadgets.gadgetmanager module |
| 159 | + 'gadgetmanager-comment-modify' => 'Edit summary used when editing definitions from [[Special:Gadgets]].', |
| 160 | + |
127 | 161 | # Validation error messages |
128 | 162 | 'gadget-validate-notset' => '$1 is the name of the property, e.g. settings.rights .', |
129 | 163 | 'gadget-validate-wrongtype' => '* $1 is the name of the property, e.g. settings.rights or module.messages[3]. |
130 | 164 | * $2 is the type that this property is expected to have |
131 | 165 | * $3 is the type it actually had', |
132 | 166 | |
133 | | - # For Special:GadgetManager |
134 | | - 'gadgetmanager-tablehead-lastmodified' => '{{Identical|Last modified}} |
135 | | -{{Output|plain}}', |
136 | | - 'gadgetmanager-tablecell-lastmod' => 'This message is used on Special:GadgetManager to indicate the last modified date, time and user for gadget definitions. |
137 | | -* $1 is a time and date (duplicated in $3 and $4) |
138 | | -* $2 is a link to a user page with a user name as link text, followed by a series of related links |
139 | | -* $3 is the date |
140 | | -* $4 is the time |
141 | | -* $5 is the user name which can be used with GENDER', |
142 | | - 'gadgetmanager-comment-modify' => 'Edit summary used when editing definitions from [[Special:GadgetManager]].', |
143 | | - |
144 | 167 | # User rights |
145 | 168 | 'right-gadgets-edit' => '{{doc-right}}', |
146 | 169 | 'right-gadgets-definition-create' => '{{doc-right}}', |
Index: branches/RL2/extensions/Gadgets/Gadgets.php |
— | — | @@ -33,7 +33,7 @@ |
34 | 34 | |
35 | 35 | /** |
36 | 36 | * Add gadget repositories here. |
37 | | - * |
| 37 | + * |
38 | 38 | * For foreign DB-based gadget repositories, use: |
39 | 39 | * // TODO: Document better by looking at WMF ForeignFileRepo config |
40 | 40 | * $wgGadgetRepositories[] = array( |
— | — | @@ -49,7 +49,7 @@ |
50 | 50 | * 'tablePrefix' => 'mw_', // Table prefix for the foreign wiki's database, or '' if no prefix |
51 | 51 | * 'hasSharedCache' => true, // Whether the foreign wiki's cache is accessible through $wgMemc |
52 | 52 | * ); |
53 | | - * |
| 53 | + * |
54 | 54 | * For foreign API-based gadget repositories, use: |
55 | 55 | * $wgGadgetRepositories[] = array( |
56 | 56 | * 'class' => 'ForeignAPIGadgetRepo', |
— | — | @@ -122,13 +122,10 @@ |
123 | 123 | $wgAutoloadClasses['GadgetRepo'] = $dir . 'backend/GadgetRepo.php'; |
124 | 124 | $wgAutoloadClasses['GadgetResourceLoaderModule'] = $dir . 'backend/GadgetResourceLoaderModule.php'; |
125 | 125 | $wgAutoloadClasses['LocalGadgetRepo'] = $dir . 'backend/LocalGadgetRepo.php'; |
126 | | -$wgAutoloadClasses['SpecialGadgetManager'] = $dir . 'SpecialGadgetManager.php'; |
127 | 126 | $wgAutoloadClasses['SpecialGadgets'] = $dir . 'SpecialGadgets.php'; |
128 | 127 | |
129 | 128 | $wgSpecialPages['Gadgets'] = 'SpecialGadgets'; |
130 | 129 | $wgSpecialPageGroups['Gadgets'] = 'wiki'; |
131 | | -#$wgSpecialPages['GadgetManager'] = 'SpecialGadgetManager'; |
132 | | -#$wgSpecialPageGroups['GadgetManager'] = 'wiki'; |
133 | 130 | |
134 | 131 | $wgAPIListModules['gadgetcategories'] = 'ApiQueryGadgetCategories'; |
135 | 132 | $wgAPIListModules['gadgets'] = 'ApiQueryGadgets'; |
— | — | @@ -168,6 +165,8 @@ |
169 | 166 | 'jquery.json', |
170 | 167 | ), |
171 | 168 | 'messages' => array( |
| 169 | + 'gadgets-gadget-create', |
| 170 | + 'gadgets-gadget-create-tooltip', |
172 | 171 | 'gadgetmanager-editor-title', |
173 | 172 | 'gadgetmanager-editor-prop-remove', |
174 | 173 | 'gadgetmanager-editor-removeprop-tooltip', |
Index: branches/RL2/extensions/Gadgets/GadgetHooks.php |
— | — | @@ -29,8 +29,17 @@ |
30 | 30 | } |
31 | 31 | |
32 | 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 | + /** |
33 | 42 | * ArticleDeleteComplete hook handler. |
34 | | - * |
| 43 | + * |
35 | 44 | * @param $article Article |
36 | 45 | * @param $user User |
37 | 46 | * @param $reason String: Deletion summary |
— | — | @@ -41,7 +50,7 @@ |
42 | 51 | if ( !$id ) { |
43 | 52 | return true; |
44 | 53 | } |
45 | | - |
| 54 | + |
46 | 55 | $repo = LocalGadgetRepo::singleton(); |
47 | 56 | $repo->deleteGadget( $id ); |
48 | 57 | // deleteGadget() may return an error if the Gadget didn't exist, but we don't care here |
— | — | @@ -50,7 +59,7 @@ |
51 | 60 | |
52 | 61 | /** |
53 | 62 | * ArticleSaveComplete hook handler. |
54 | | - * |
| 63 | + * |
55 | 64 | * @param $article Article |
56 | 65 | * @param $user User |
57 | 66 | * @param $text String: New page text |
— | — | @@ -68,23 +77,23 @@ |
69 | 78 | if ( !$id ) { |
70 | 79 | return true; |
71 | 80 | } |
72 | | - |
| 81 | + |
73 | 82 | $previousRev = $revision->getPrevious(); |
74 | 83 | $prevTs = $previousRev instanceof Revision ? $previousRev->getTimestamp() : wfTimestampNow(); |
75 | | - |
| 84 | + |
76 | 85 | // Update the database entry for this gadget |
77 | 86 | $repo = LocalGadgetRepo::singleton(); |
78 | 87 | // TODO: Timestamp in the constructor is ugly |
79 | 88 | $gadget = new Gadget( $id, $repo, $text, $prevTs ); |
80 | 89 | $repo->modifyGadget( $gadget, $revision->getTimestamp() ); |
81 | | - |
| 90 | + |
82 | 91 | // modifyGadget() returns a Status object with an error if there was a conflict, |
83 | 92 | // but we don't care. If a conflict occurred, that must be because a newer edit's |
84 | 93 | // DB update occurred before ours, in which case the right thing to do is to occu |
85 | | - |
| 94 | + |
86 | 95 | return true; |
87 | 96 | } |
88 | | - |
| 97 | + |
89 | 98 | /** |
90 | 99 | * Update the database entry for a gadget if the description page is |
91 | 100 | * newer than the database entry. |
— | — | @@ -95,24 +104,24 @@ |
96 | 105 | if ( !$id ) { |
97 | 106 | return; |
98 | 107 | } |
99 | | - |
| 108 | + |
100 | 109 | // Check whether this undeletion changed the latest revision of the page, by comparing |
101 | 110 | // the timestamp of the latest revision with the timestamp in the DB |
102 | 111 | $repo = LocalGadgetRepo::singleton(); |
103 | 112 | $gadget = $repo->getGadget( $id ); |
104 | 113 | $gadgetTS = $gadget ? $gadget->getTimestamp() : 0; |
105 | | - |
| 114 | + |
106 | 115 | $rev = Revision::newFromTitle( $title ); |
107 | 116 | if ( wfTimestamp( TS_MW, $rev->getTimestamp() ) === |
108 | 117 | wfTimestamp( TS_MW, $gadgetTS ) ) { |
109 | 118 | // The latest rev didn't change. Someone must've undeleted an older revision |
110 | 119 | return; |
111 | 120 | } |
112 | | - |
| 121 | + |
113 | 122 | // Update the database entry for this gadget |
114 | 123 | $newGadget = new Gadget( $id, $repo, $rev->getRawText(), $gadgetTS ); |
115 | 124 | $repo->modifyGadget( $newGadget, $rev->getTimestamp() ); |
116 | | - |
| 125 | + |
117 | 126 | // modifyGadget() returns a Status object with an error if there was a conflict, |
118 | 127 | // but we do't care, see similar comment in articleSaveComplete() |
119 | 128 | return; |
— | — | @@ -128,7 +137,7 @@ |
129 | 138 | self::gadgetDefinitionUpdateIfChanged( $title ); |
130 | 139 | return true; |
131 | 140 | } |
132 | | - |
| 141 | + |
133 | 142 | public static function gadgetDefinitionImport( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) { |
134 | 143 | self::gadgetDefinitionUpdateIfChanged( $title ); |
135 | 144 | return true; |
— | — | @@ -136,7 +145,7 @@ |
137 | 146 | |
138 | 147 | /** |
139 | 148 | * ArticleDeleteComplete hook handler. |
140 | | - * |
| 149 | + * |
141 | 150 | * @param $article Article |
142 | 151 | * @param $user User |
143 | 152 | * @param $reason String: Deletion summary |
— | — | @@ -146,10 +155,10 @@ |
147 | 156 | GadgetPageList::delete( $article->getTitle() ); |
148 | 157 | return true; |
149 | 158 | } |
150 | | - |
| 159 | + |
151 | 160 | /** |
152 | 161 | * ArticleSaveComplete hook handler. |
153 | | - * |
| 162 | + * |
154 | 163 | * @param $article Article |
155 | 164 | * @param $user User |
156 | 165 | * @param $text String: New page text |
— | — | @@ -160,7 +169,7 @@ |
161 | 170 | * @param $flags: Int: Bitmap of flags passed to WikiPage::doEdit() |
162 | 171 | * @param $revision: Revision object for the new revision |
163 | 172 | */ |
164 | | - public static function cssOrJsPageSave( $article, $user, $text, $summary, $isMinor, |
| 173 | + public static function cssOrJsPageSave( $article, $user, $text, $summary, $isMinor, |
165 | 174 | $isWatch, $section, $flags, $revision ) |
166 | 175 | { |
167 | 176 | $title = $article->getTitle(); |
— | — | @@ -183,7 +192,7 @@ |
184 | 193 | // Delete the old title from the list. Even if it still exists after the move, |
185 | 194 | // it'll be a redirect and we don't want those in there |
186 | 195 | GadgetPageList::delete( $oldTitle ); |
187 | | - |
| 196 | + |
188 | 197 | GadgetPageList::updatePageStatus( $newTitle ); |
189 | 198 | return true; |
190 | 199 | } |
— | — | @@ -220,7 +229,7 @@ |
221 | 230 | continue; |
222 | 231 | } |
223 | 232 | $category = $gadget->getCategory(); |
224 | | - |
| 233 | + |
225 | 234 | // Add the Gadget to the right category |
226 | 235 | $title = htmlspecialchars( $gadget->getTitleMessage() ); |
227 | 236 | $description = $gadget->getDescriptionMessage(); // Is parsed, doesn't need escaping |
— | — | @@ -236,7 +245,7 @@ |
237 | 246 | $default[] = $id; |
238 | 247 | } |
239 | 248 | } |
240 | | - |
| 249 | + |
241 | 250 | $options = array(); // array( desc1 => gadget1, category1 => array( desc2 => gadget2 ) ) |
242 | 251 | foreach ( $categories as $category => $gadgets ) { |
243 | 252 | if ( $category !== '' ) { |
— | — | @@ -246,7 +255,7 @@ |
247 | 256 | $options += $gadgets; |
248 | 257 | } |
249 | 258 | } |
250 | | - |
| 259 | + |
251 | 260 | $preferences['gadgets-intro'] = |
252 | 261 | array( |
253 | 262 | 'type' => 'info', |
— | — | @@ -258,7 +267,7 @@ |
259 | 268 | 'raw' => 1, |
260 | 269 | 'rawrow' => 1, |
261 | 270 | ); |
262 | | - $preferences['gadgets'] = |
| 271 | + $preferences['gadgets'] = |
263 | 272 | array( |
264 | 273 | 'type' => 'multiselect', |
265 | 274 | 'options' => $options, |
— | — | @@ -267,7 +276,7 @@ |
268 | 277 | 'prefix' => 'gadget-', |
269 | 278 | 'default' => $default, |
270 | 279 | ); |
271 | | - |
| 280 | + |
272 | 281 | // Add tab for shared gadgets |
273 | 282 | $preferences['gadgets-intro-shared'] = |
274 | 283 | array( |
— | — | @@ -318,12 +327,12 @@ |
319 | 328 | $out->addModules( $gadget->getModuleName() ); |
320 | 329 | } |
321 | 330 | } |
322 | | - |
| 331 | + |
323 | 332 | // Add preferences JS if we're on Special:Preferences |
324 | 333 | if ( $out->getTitle()->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) { |
325 | 334 | $out->addModules( 'ext.gadgets.preferences' ); |
326 | 335 | } |
327 | | - |
| 336 | + |
328 | 337 | wfProfileOut( __METHOD__ ); |
329 | 338 | return true; |
330 | 339 | } |
— | — | @@ -335,13 +344,14 @@ |
336 | 345 | */ |
337 | 346 | public static function makeGlobalVariablesScript( &$vars, $out ) { |
338 | 347 | $title = $out->getTitle(); |
| 348 | + $user = $out->getUser(); |
339 | 349 | // FIXME: This is not a nice way to do it. Maybe we should check for the presence |
340 | 350 | // of a module instead or something. |
341 | | - if ( $title->equals( SpecialPage::getTitleFor( 'GadgetManager' ) ) || |
| 351 | + if ( $title->equals( SpecialPage::getTitleFor( 'Gadgets' ) ) || |
342 | 352 | $title->equals( SpecialPage::getTitleFor( 'Preferences' ) ) ) |
343 | 353 | { |
344 | 354 | global $wgGadgetEnableSharing; |
345 | | - |
| 355 | + |
346 | 356 | // Pass the source data for each source that is used by a repository |
347 | 357 | $repos = GadgetRepo::getAllRepos(); |
348 | 358 | $sources = $out->getResourceLoader()->getSources(); |
— | — | @@ -353,7 +363,13 @@ |
354 | 364 | $vars['gadgetsConf'] = array( |
355 | 365 | 'enableSharing' => $wgGadgetEnableSharing, |
356 | 366 | 'allRights' => User::getAllRights(), |
357 | | - 'repos' => $repoData |
| 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 | + ), |
358 | 374 | ); |
359 | 375 | } |
360 | 376 | return true; |
— | — | @@ -382,7 +398,7 @@ |
383 | 399 | $list[NS_GADGET_DEFINITION_TALK] = 'Gadget_definition_talk'; |
384 | 400 | return true; |
385 | 401 | } |
386 | | - |
| 402 | + |
387 | 403 | public static function titleIsCssOrJsPage( $title, &$result ) { |
388 | 404 | if ( ( $title->getNamespace() == NS_GADGET || $title->getNamespace() == NS_GADGET_DEFINITION ) && |
389 | 405 | preg_match( '!\.(css|js)$!u', $title->getText() ) ) |
— | — | @@ -391,14 +407,14 @@ |
392 | 408 | } |
393 | 409 | return true; |
394 | 410 | } |
395 | | - |
| 411 | + |
396 | 412 | public static function titleIsMovable( $title, &$result ) { |
397 | 413 | if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
398 | 414 | $result = false; |
399 | 415 | } |
400 | 416 | return true; |
401 | 417 | } |
402 | | - |
| 418 | + |
403 | 419 | public static function getUserPermissionsErrors( $title, $user, $action, &$result ) { |
404 | 420 | if ( $title->getNamespace() == NS_GADGET_DEFINITION ) { |
405 | 421 | // Enforce restrictions on the Gadget_definition namespace |
Index: branches/RL2/extensions/Gadgets/SpecialGadgets.php |
— | — | @@ -1,168 +1,469 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Special:Gadgets, provides a preview of MediaWiki:Gadgets. |
| 4 | + * SpecialPage for Gadgets. |
5 | 5 | * |
6 | 6 | * @file |
7 | | - * @ingroup SpecialPage |
8 | | - * @author Daniel Kinzler, brightbyte.de |
9 | | - * @copyright © 2007 Daniel Kinzler |
10 | | - * @license GNU General Public License 2.0 or later |
| 7 | + * @ingroup Extensions |
11 | 8 | */ |
12 | 9 | |
13 | | -if( !defined( 'MEDIAWIKI' ) ) { |
14 | | - echo( "not a valid entry point.\n" ); |
15 | | - die( 1 ); |
16 | | -} |
17 | | - |
18 | | -/** |
19 | | - * |
20 | | - */ |
21 | 10 | class SpecialGadgets extends SpecialPage { |
22 | 11 | |
23 | 12 | /** |
24 | | - * Constructor |
| 13 | + * @var $par Array: Parameters passed to the page. |
| 14 | + * - gadget String: Gadget id |
| 15 | + * - action String: Action ('view', 'export') |
25 | 16 | */ |
26 | | - function __construct() { |
27 | | - parent::__construct( 'Gadgets', '', true ); |
| 17 | + protected $params = array( |
| 18 | + 'gadget' => null, |
| 19 | + 'action' => 'view', |
| 20 | + ); |
| 21 | + |
| 22 | + public function __construct() { |
| 23 | + parent::__construct( 'Gadgets' ); |
28 | 24 | } |
29 | 25 | |
30 | 26 | /** |
31 | | - * Main execution function |
32 | | - * @param $par Parameters passed to the page |
| 27 | + * Main execution function. |
| 28 | + * @todo: Add canonical links to <head> to avoid indexing of link variations and stuff like |
| 29 | + * [[Special:Gadgets/id/export/bablabla]]. Those should either redirect and/or have a canonical |
| 30 | + * link in the <head> ($out->addLink). |
| 31 | + * @param $par String: Parameters passed to the page. |
33 | 32 | */ |
34 | | - function execute( $par ) { |
35 | | - $parts = explode( '/', $par ); |
36 | | - if ( count( $parts ) == 2 && $parts[0] == 'export' ) { |
37 | | - $this->showExportForm( $parts[1] ); |
38 | | - } else { |
39 | | - $this->showMainForm(); |
| 33 | + public function execute( $par ) { |
| 34 | + $this->par = $par; |
| 35 | + $out = $this->getOutput(); |
| 36 | + $out->addModuleStyles( 'ext.gadgets.prejs' ); |
| 37 | + |
| 38 | + // Map title parts to query string |
| 39 | + if ( is_string( $par ) ) { |
| 40 | + $parts = explode( '/', $par, 3 ); |
| 41 | + $this->params['gadget'] = $parts[0]; |
| 42 | + if ( isset( $parts[1] ) ) { |
| 43 | + $this->params['action'] = $parts[1]; |
| 44 | + } |
40 | 45 | } |
| 46 | + |
| 47 | + // Parameters (overrides title parts) |
| 48 | + $this->params['gadget'] = $this->getRequest()->getVal( 'gadget', $this->params['gadget'] ); |
| 49 | + $this->params['action'] = $this->getRequest()->getVal( 'action', $this->params['action'] ); |
| 50 | + |
| 51 | + // Get instance of Gadget |
| 52 | + $gadget = false; |
| 53 | + if ( !is_null( $this->params['gadget'] ) ) { |
| 54 | + $repo = LocalGadgetRepo::singleton(); |
| 55 | + $gadget = $repo->getGadget( $this->params['gadget'] ); |
| 56 | + if ( !is_object( $gadget ) ) { |
| 57 | + $out->showErrorPage( 'error', 'gadgets-not-found', array( $this->params['gadget'] ) ); |
| 58 | + return; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + // Handle the the query |
| 63 | + switch( $this->params['action'] ) { |
| 64 | + case 'view': |
| 65 | + if ( $gadget ) { |
| 66 | + $this->showSingleGadget( $gadget ); |
| 67 | + } else { |
| 68 | + $this->showAllGadgets(); |
| 69 | + } |
| 70 | + break; |
| 71 | + case 'export': |
| 72 | + if ( $gadget ) { |
| 73 | + $this->showExportForm( $gadget ); |
| 74 | + } else { |
| 75 | + $out->showErrorPage( 'error', 'gadgets-nosuchaction' ); |
| 76 | + } |
| 77 | + break; |
| 78 | + default: |
| 79 | + $out->showErrorPage( 'error', 'gadgets-nosuchaction' ); |
| 80 | + break; |
| 81 | + } |
41 | 82 | } |
42 | | - |
| 83 | + |
43 | 84 | /** |
44 | | - * Displays form showing the list of installed gadgets |
| 85 | + * Returns one <div class="mw-gadgets-gadget">..</div> |
| 86 | + * for the given Gadget object. |
45 | 87 | */ |
46 | | - public function showMainForm() { |
47 | | - global $wgOut, $wgUser, $wgLang, $wgContLang; |
| 88 | + protected function getGadgetHtml( Gadget $gadget ) { |
| 89 | + global $wgContLang; |
| 90 | + $user = $this->getUser(); |
| 91 | + $userlang = $this->getLang(); |
48 | 92 | |
49 | | - $skin = $wgUser->getSkin(); |
| 93 | + // Suffix needed after page names in links to NS_MEDIAWIKI, |
| 94 | + // e.g. to link to [[MediaWiki:Foo/nl]] instead of [[MediaWiki:Foo]] |
| 95 | + $suffix = ''; |
| 96 | + if ( $userlang->getCode() !== $wgContLang->getCode() ) { |
| 97 | + $suffix = '/' . $userlang->getCode(); |
| 98 | + } |
50 | 99 | |
| 100 | + $html = Html::openElement( 'div', array( |
| 101 | + 'class' => 'mw-gadgets-gadget', |
| 102 | + 'data-gadget-id' => $gadget->getId(), |
| 103 | + ) ); |
| 104 | + |
| 105 | + // Gadgetlinks section in the Gadget title heading |
| 106 | + $extra = array(); |
| 107 | + |
| 108 | + $extra[] = Linker::link( |
| 109 | + $this->getTitle( $gadget->getId() ), |
| 110 | + wfMessage( 'gadgets-gadget-permalink' )->escaped(), |
| 111 | + array( |
| 112 | + 'title' => wfMessage( 'gadgets-gadget-permalink-tooltip' )->plain(), |
| 113 | + 'class' => 'mw-gadgets-permalink', |
| 114 | + ) |
| 115 | + ); |
| 116 | + |
| 117 | + $extra[] = Linker::link( |
| 118 | + $this->getTitle( "{$gadget->getId()}/export" ), |
| 119 | + wfMessage( 'gadgets-gadget-export' )->escaped(), |
| 120 | + array( |
| 121 | + 'title' => wfMessage( 'gadgets-gadget-export-tooltip' )->plain(), |
| 122 | + 'class' => 'mw-gadgets-export', |
| 123 | + ) |
| 124 | + |
| 125 | + ); |
| 126 | + if ( $user->isAllowed( 'gadgets-definition-edit' ) ) { |
| 127 | + $extra[] = Linker::link( |
| 128 | + GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ), |
| 129 | + wfMessage( 'gadgets-gadget-modify' )->escaped(), |
| 130 | + array( |
| 131 | + 'title' => wfMessage( 'gadgets-gadget-modify-tooltip' )->plain(), |
| 132 | + 'class' => 'mw-gadgets-modify', |
| 133 | + ), |
| 134 | + array( 'action' => 'edit' ) |
| 135 | + ); |
| 136 | + } |
| 137 | + |
| 138 | + if ( $user->isAllowed( 'gadgets-definition-delete' ) ) { |
| 139 | + $extra[] = Linker::link( |
| 140 | + GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ), |
| 141 | + wfMessage( 'gadgets-gadget-delete' )->escaped(), |
| 142 | + array( |
| 143 | + 'title' => wfMessage( 'gadgets-gadget-delete-tooltip' )->plain(), |
| 144 | + 'class' => 'mw-gadgets-delete', |
| 145 | + ), |
| 146 | + array( 'action' => 'delete' ) |
| 147 | + ); |
| 148 | + } |
| 149 | + |
| 150 | + // Edit interface (gadget title and description) |
| 151 | + $editTitle = $editDescription = ''; |
| 152 | + if ( $user->isAllowed( 'editinterface' ) ) { |
| 153 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, $gadget->getTitleMessageKey() . $suffix ); |
| 154 | + $editLink = Linker::link( |
| 155 | + $t, |
| 156 | + wfMessage( 'gadgets-message-edit' )->escaped(), |
| 157 | + array( 'title' => wfMessage( 'gadgets-message-edit-tooltip', $t->getPrefixedText() ) ), |
| 158 | + array( 'action' => 'edit' ) |
| 159 | + ); |
| 160 | + $editTitle = '<span class="mw-gadgets-messagelink">' . $editLink . '</span>'; |
| 161 | + |
| 162 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, $gadget->getDescriptionMessageKey() . $suffix ); |
| 163 | + $editLink = Linker::link( |
| 164 | + $t, |
| 165 | + wfMessage( $t->isKnown() ? 'gadgets-desc-edit' : 'gadgets-desc-add' )->escaped(), |
| 166 | + array( 'title' => wfMessage( $t->isKnown() ? 'gadgets-desc-edit-tooltip' : 'gadgets-desc-add-tooltip', $t->getPrefixedText() ) ), |
| 167 | + array( 'action' => 'edit' ) |
| 168 | + ); |
| 169 | + $editDescription = '<span class="mw-gadgets-messagelink">' . $editLink . '</span>'; |
| 170 | + } |
| 171 | + |
| 172 | + // Gadget heading |
| 173 | + $html .= '<div class="mw-gadgets-title">' |
| 174 | + . htmlspecialchars( $gadget->getTitleMessage() ) |
| 175 | + . '   ' . $editTitle |
| 176 | + . Html::rawElement( 'span', array( |
| 177 | + 'class' => 'mw-gadgets-gadgetlinks', |
| 178 | + 'data-gadget-id' => $gadget->getId() |
| 179 | + ), implode( '', $extra ) |
| 180 | + ) |
| 181 | + . '</div>'; |
| 182 | + |
| 183 | + // Description |
| 184 | + $html .= Html::rawElement( 'p', array( |
| 185 | + 'class' => 'mw-gadgets-description' |
| 186 | + ), $gadget->getDescriptionMessage() . ' ' . $editDescription ); |
| 187 | + |
| 188 | + $html .= '</div>'; |
| 189 | + return $html; |
| 190 | + } |
| 191 | + |
| 192 | + /** |
| 193 | + * Handles [[Special:Gadgets]]. |
| 194 | + * Displays form showing the list of installed gadgets. |
| 195 | + */ |
| 196 | + public function showAllGadgets() { |
| 197 | + global $wgContLang; |
| 198 | + $out = $this->getOutput(); |
| 199 | + $user = $this->getUser(); |
| 200 | + $userlang = $this->getLang(); |
| 201 | + |
51 | 202 | $this->setHeaders(); |
52 | | - $wgOut->setPagetitle( wfMsg( "gadgets-title" ) ); |
53 | | - $wgOut->addWikiMsg( 'gadgets-pagetext' ); |
| 203 | + $out->setPagetitle( wfMsg( 'gadgets-title' ) ); |
54 | 204 | |
55 | | - $gadgets = Gadget::loadStructuredList(); |
56 | | - if ( !$gadgets ) return; |
| 205 | + $repo = LocalGadgetRepo::singleton(); |
| 206 | + $gadgetsByCategory = $repo->getGadgetsByCategory(); |
57 | 207 | |
58 | | - $lang = ""; |
59 | | - if ( $wgLang->getCode() != $wgContLang->getCode() ) { |
60 | | - $lang = "/" . $wgLang->getCode(); |
| 208 | + // If there there are no gadgets at all, exit early. |
| 209 | + if ( !count( $gadgetsByCategory ) ) { |
| 210 | + $noGadgetsMsgHtml = Html::element( 'p', |
| 211 | + array( |
| 212 | + 'class' => 'mw-gadgets-nogadgets' |
| 213 | + ), wfMessage( 'gadgets-nogadgets' )->plain() |
| 214 | + ); |
| 215 | + $this->getOutput()->addHtml( $noGadgetsMsgHtml ); |
| 216 | + return; |
61 | 217 | } |
62 | 218 | |
63 | | - $listOpen = false; |
| 219 | + // There is atleast one gadget, let's get started. |
| 220 | + $out->addWikiMsg( 'gadgets-pagetext', |
| 221 | + Title::newFromText( 'Special:Recentchanges/namespace=' . NS_GADGET_DEFINITION )->getPrefixedText() |
| 222 | + ); |
64 | 223 | |
65 | | - $msgOpt = array( 'parseinline', 'parsemag' ); |
66 | | - $editInterfaceAllowed = $wgUser->isAllowed( 'editinterface' ); |
67 | | - |
68 | | - foreach ( $gadgets as $section => $entries ) { |
69 | | - if ( $section !== false && $section !== '' ) { |
70 | | - $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-section-$section$lang" ); |
71 | | - if ( $editInterfaceAllowed ) { |
72 | | - $lnkTarget = $t |
73 | | - ? $skin->link( $t, wfMsgHTML( 'edit' ), array(), array( 'action' => 'edit' ) ) |
74 | | - : htmlspecialchars( $section ); |
75 | | - $lnk = "    [$lnkTarget]"; |
76 | | - } else { |
77 | | - $lnk = ''; |
78 | | - } |
79 | | - $ttext = wfMsgExt( "gadget-section-$section", $msgOpt ); |
| 224 | + // Only load the gadget manager module if needed |
| 225 | + if ( $user->isAllowed( 'gadgets-definition-delete' ) |
| 226 | + || $user->isAllowed( 'gadgets-definition-edit' ) |
| 227 | + || $user->isAllowed( 'gadgets-definition-create' ) |
| 228 | + ) { |
| 229 | + $out->addModules( 'ext.gadgets.gadgetmanager' ); |
| 230 | + } |
80 | 231 | |
81 | | - if( $listOpen ) { |
82 | | - $wgOut->addHTML( Xml::closeElement( 'ul' ) . "\n" ); |
83 | | - $listOpen = false; |
84 | | - } |
85 | | - $wgOut->addHTML( Html::rawElement( 'h2', array(), $ttext . $lnk ) . "\n" ); |
86 | | - } |
| 232 | + // Sort categories alphabetically |
| 233 | + ksort( $gadgetsByCategory ); |
87 | 234 | |
88 | | - foreach ( $entries as $gadget ) { |
89 | | - $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-{$gadget->getId()}$lang" ); |
90 | | - if ( !$t ) continue; |
| 235 | + // ksort causes key "''" to be sorted on top, we want it to be at the bottom, |
| 236 | + // removing and re-adding the value. |
| 237 | + if ( isset( $gadgetsByCategory[''] ) ) { |
| 238 | + $uncat = $gadgetsByCategory['']; |
| 239 | + unset( $gadgetsByCategory[''] ); |
| 240 | + $gadgetsByCategory[''] = $uncat; |
| 241 | + } |
91 | 242 | |
92 | | - $links = array(); |
93 | | - if ( $editInterfaceAllowed ) { |
94 | | - $links[] = $skin->link( $t, wfMsgHTML( 'edit' ), array(), array( 'action' => 'edit' ) ); |
95 | | - } |
96 | | - $links[] = $skin->link( $this->getTitle( "export/{$gadget->getId()}" ), wfMsgHtml( 'gadgets-export' ) ); |
97 | | - |
98 | | - $ttext = wfMsgExt( "gadget-{$gadget->getId()}", $msgOpt ); |
| 243 | + // Suffix needed after page names in links to NS_MEDIAWIKI, |
| 244 | + // e.g. to link to [[MediaWiki:Foo/nl]] instead of [[MediaWiki:Foo]] |
| 245 | + $suffix = ''; |
| 246 | + if ( $userlang->getCode() !== $wgContLang->getCode() ) { |
| 247 | + $suffix = '/' . $userlang->getCode(); |
| 248 | + } |
99 | 249 | |
100 | | - if( !$listOpen ) { |
101 | | - $listOpen = true; |
102 | | - $wgOut->addHTML( Xml::openElement( 'ul' ) ); |
103 | | - } |
104 | | - $lnk = '  ' . wfMsg( 'parentheses', $wgLang->pipeList( $links ) ); |
105 | | - $wgOut->addHTML( Xml::openElement( 'li' ) . |
106 | | - $ttext . $lnk . "<br />" . |
107 | | - wfMsgHTML( 'gadgets-uses' ) . wfMsg( 'colon-separator' ) |
| 250 | + |
| 251 | + $html = ''; |
| 252 | + |
| 253 | + foreach ( $gadgetsByCategory as $category => $gadgets ) { |
| 254 | + |
| 255 | + // Avoid broken or empty headings. Fallback to a special message |
| 256 | + // for uncategorized gadgets (e.g. gadgets with category '' ). |
| 257 | + if ( $category !== '' ) { |
| 258 | + $categoryTitle = $repo->getCategoryTitle( $category ); |
| 259 | + } else { |
| 260 | + $categoryTitle = wfMessage( 'gadgets-uncategorized' )->plain(); |
| 261 | + } |
| 262 | + |
| 263 | + $editLink = ''; |
| 264 | + if ( $user->isAllowed( 'editinterface' ) && $category !== '' ) { |
| 265 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, "gadgetcategory-{$category}{$suffix}" ); |
| 266 | + $editLink = Linker::link( |
| 267 | + $t, |
| 268 | + wfMessage( 'gadgets-message-edit' )->escaped(), |
| 269 | + array( 'title' => wfMessage( 'gadgets-message-edit-tooltip', $t->getPrefixedText() ) ), |
| 270 | + array( 'action' => 'edit' ) |
108 | 271 | ); |
| 272 | + $editLink = '<span class="mw-gadgets-messagelink">' . $editLink . '</span>'; |
| 273 | + } |
109 | 274 | |
110 | | - $lnk = array(); |
111 | | - foreach ( $gadget->getScriptsAndStyles() as $codePage ) { |
112 | | - $t = Title::makeTitleSafe( NS_MEDIAWIKI, $codePage ); |
113 | | - if ( !$t ) continue; |
| 275 | + // Category heading |
| 276 | + $html .= Html::rawElement( 'h2', array(), htmlspecialchars( $categoryTitle ) . '   ' . $editLink ); |
114 | 277 | |
115 | | - $lnk[] = $skin->link( $t, htmlspecialchars( $t->getText() ) ); |
116 | | - } |
117 | | - $wgOut->addHTML( $wgLang->commaList( $lnk ) ); |
118 | | - $rights = $gadget->getRequiredRights(); |
119 | | - if ( count( $rights ) ) { |
120 | | - $wgOut->addHTML( '<br />' . |
121 | | - wfMessage( 'gadgets-required-rights', $wgLang->commaList( $rights ), count( $rights ) )->parse() |
122 | | - ); |
123 | | - } |
124 | | - if ( $gadget->isOnByDefault() ) { |
125 | | - $wgOut->addHTML( '<br />' . wfMessage( 'gadgets-default' )->parse() ); |
126 | | - } |
127 | | - |
128 | | - $wgOut->addHTML( Xml::closeElement( 'li' ) . "\n" ); |
| 278 | + // Start gadgets list |
| 279 | + $html .= '<div class="mw-gadgets-list">'; |
| 280 | + |
| 281 | + foreach( $gadgets as $gadgetId => $gadget ) { |
| 282 | + $html .= $this->getGadgetHtml( $gadget ); |
| 283 | + |
129 | 284 | } |
| 285 | + |
| 286 | + $html .= '</div>'; |
130 | 287 | } |
131 | 288 | |
132 | | - if( $listOpen ) { |
133 | | - $wgOut->addHTML( Xml::closeElement( 'ul' ) . "\n" ); |
134 | | - } |
| 289 | + $out->addHtml( $html ); |
135 | 290 | } |
136 | 291 | |
137 | 292 | /** |
138 | | - * Exports a gadget with its dependencies in a serialized form |
139 | | - * @param $gadget String Name of gadget to export |
| 293 | + * Handles [[Special:Gadgets/id/export]]. |
| 294 | + * Exports a gadget with its dependencies in a serialized form. |
| 295 | + * Should not be called if the gadget does not exist. $gadget must be |
| 296 | + * an instance of Gadget, not null. |
| 297 | + * @param $gadget Gadget: Gadget object of gadget to export. |
140 | 298 | */ |
141 | 299 | public function showExportForm( $gadget ) { |
142 | | - global $wgOut, $wgScript; |
| 300 | + $this->doSubpageMode(); |
| 301 | + $out = $this->getOutput(); |
143 | 302 | |
144 | | - $gadgets = Gadget::loadList(); |
145 | | - if ( !isset( $gadgets[$gadget] ) ) { |
146 | | - $wgOut->showErrorPage( 'error', 'gadgets-not-found', array( $gadget ) ); |
147 | | - return; |
| 303 | + /** |
| 304 | + * @todo: Add note somewhere with link to mw.org help pages about gadget repos |
| 305 | + * if this is a shared gadget and the user owns the wiki, he is recommended |
| 306 | + * to instead pull from this repo natively. |
| 307 | + */ |
| 308 | + |
| 309 | + $rights = array( |
| 310 | + 'gadgets-definition-create', |
| 311 | + 'gadgets-definition-edit', |
| 312 | + 'gadgets-edit', |
| 313 | + 'importupload', |
| 314 | + ); |
| 315 | + $msg = array(); |
| 316 | + foreach( $rights as $right ) { |
| 317 | + $msg[] = Html::element( 'code', array( |
| 318 | + 'style' => 'white-space:nowrap', |
| 319 | + 'title' => wfMsg( "right-{$right}" ) |
| 320 | + ), $right |
| 321 | + ); |
148 | 322 | } |
149 | | - |
150 | | - $g = $gadgets[$gadget]; |
| 323 | + |
151 | 324 | $this->setHeaders(); |
152 | | - $wgOut->setPagetitle( wfMsg( "gadgets-export-title" ) ); |
153 | | - $wgOut->addWikiMsg( 'gadgets-export-text', $gadget, $g->getDefinition() ); |
| 325 | + $out->setPagetitle( wfMsg( 'gadgets-export-title', $gadget->getTitleMessage() ) ); |
154 | 326 | |
155 | | - $exportList = "MediaWiki:gadget-$gadget\n"; |
156 | | - foreach ( $g->getScriptsAndStyles() as $page ) { |
157 | | - $exportList .= "MediaWiki:$page\n"; |
| 327 | + // Make a list of all pagenames to be exported: |
| 328 | + $exportTitles = array(); |
| 329 | + |
| 330 | + // NS_GADGET_DEFINITION page of this gadget |
| 331 | + $exportTitles[] = GadgetHooks::getDefinitionTitleFromID( $gadget->getId() ); |
| 332 | + |
| 333 | + // Title message in NS_MEDIAWIKI |
| 334 | + $exportTitles[] = Title::makeTitleSafe( NS_MEDIAWIKI, $gadget->getTitleMessageKey() ); |
| 335 | + |
| 336 | + // Translation subpages of title message |
| 337 | + // @todo |
| 338 | + |
| 339 | + // Description message in NS_MEDIAWIKI |
| 340 | + $exportTitles[] = Title::makeTitleSafe( NS_MEDIAWIKI, $gadget->getDescriptionMessageKey() ); |
| 341 | + |
| 342 | + // Translation subpages of description message |
| 343 | + // @todo |
| 344 | + |
| 345 | + // Module script and styles in NS_GADGET |
| 346 | + foreach ( $gadget->getScripts() as $script ) { |
| 347 | + $exportTitles[] = Title::makeTitleSafe( NS_GADGET, $script ); |
| 348 | + } |
| 349 | + foreach ( $gadget->getStyles() as $style ) { |
| 350 | + $exportTitles[] = Title::makeTitleSafe( NS_GADGET, $style ); |
| 351 | + } |
| 352 | + |
| 353 | + $gadgetModule = $gadget->getModule(); |
| 354 | + |
| 355 | + // Module messages in NS_MEDIAWIKI |
| 356 | + foreach( $gadgetModule->getMessages() as $message ) { |
| 357 | + $exportTitles[] = Title::makeTitleSafe( NS_MEDIAWIKI, $message ); |
| 358 | + } |
| 359 | + |
| 360 | + // Translation subpages of module messages |
| 361 | + // @todo |
| 362 | + |
| 363 | + // Get prefixed strings separated by new lines |
| 364 | + $exportList = ''; |
| 365 | + foreach ( $exportTitles as $exportTitle ) { |
| 366 | + // Make sure it's not null (for inexisting or invalid title) |
| 367 | + // and addionally check exists() to avoid exporting messages |
| 368 | + // from NS_MEDIAWIKI that don't exist but are 'isAlwaysKnown' |
| 369 | + // due to their default value from PHP messages files |
| 370 | + // (which we don't want to export) |
| 371 | + if ( is_object( $exportTitle ) && $exportTitle->exists() ) { |
| 372 | + $exportList .= $exportTitle->getPrefixedDBkey() . "\n"; |
| 373 | + } |
158 | 374 | } |
159 | 375 | |
160 | | - $wgOut->addHTML( Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) |
| 376 | + global $wgScript; |
| 377 | + $form = |
| 378 | + Html::openElement( 'form', array( |
| 379 | + 'method' => 'get', |
| 380 | + 'action' => $wgScript, |
| 381 | + 'class' => 'mw-gadgets-exportform' |
| 382 | + ) ) |
| 383 | + . '<fieldset><p>' |
| 384 | + . wfMessage( 'gadgets-export-text' ) |
| 385 | + ->rawParams( |
| 386 | + htmlspecialchars( $gadget->getId() ), |
| 387 | + '', // $2 is no longer used. To avoid breaking backwards compatibility, skipped here and |
| 388 | + // $3 is used for the new message part |
| 389 | + $this->getLang()->listToText( $msg ) |
| 390 | + ) |
| 391 | + ->escaped() |
| 392 | + . '</p>' |
161 | 393 | . Html::hidden( 'title', SpecialPage::getTitleFor( 'Export' )->getPrefixedDBKey() ) |
162 | 394 | . Html::hidden( 'pages', $exportList ) |
163 | 395 | . Html::hidden( 'wpDownload', '1' ) |
164 | 396 | . Html::hidden( 'templates', '1' ) |
165 | 397 | . Xml::submitButton( wfMsg( 'gadgets-export-download' ) ) |
166 | | - . Html::closeElement( 'form' ) |
167 | | - ); |
| 398 | + . '</fieldset></form>'; |
| 399 | + |
| 400 | + $out->addHTML( $form ); |
168 | 401 | } |
| 402 | + |
| 403 | + /** |
| 404 | + * Exports a gadget with its dependencies in a serialized form. |
| 405 | + * Should not be called if the gadget does not exist. $gadget must be |
| 406 | + * an instance of Gadget, not null. |
| 407 | + * @param $gadget Gadget |
| 408 | + */ |
| 409 | + public function showSingleGadget( Gadget $gadget ) { |
| 410 | + $this->doSubpageMode(); |
| 411 | + $out = $this->getOutput(); |
| 412 | + |
| 413 | + $this->setHeaders(); |
| 414 | + $out->setPagetitle( wfMsg( 'gadgets-gadget-title', $gadget->getTitleMessage() ) ); |
| 415 | + |
| 416 | + $out->addHTML( '<div class="mw-gadgets-list">' . $this->getGadgetHtml( $gadget ) . '</div>' ); |
| 417 | + } |
| 418 | + |
| 419 | + |
| 420 | + /** |
| 421 | + * Call this method internally to include a breadcrumb navigation on top of the page. |
| 422 | + * Cannot be undone, should only be called once. |
| 423 | + * @return Boolean: True if added, false if not added because already added. |
| 424 | + */ |
| 425 | + public function doSubpageMode() { |
| 426 | + static $done = false; |
| 427 | + if ( $done ) { |
| 428 | + return false; |
| 429 | + } |
| 430 | + $done = true; |
| 431 | + |
| 432 | + // Would be nice if we wouldn't have to duplicate |
| 433 | + // this from Skin::subPageSubtitle. Slightly modified though |
| 434 | + $subpages = ''; |
| 435 | + $ptext = $this->getTitle( $this->par )->getPrefixedText(); |
| 436 | + if ( preg_match( '/\//', $ptext ) ) { |
| 437 | + $links = explode( '/', $ptext ); |
| 438 | + array_pop( $links ); |
| 439 | + $growinglink = ''; |
| 440 | + $display = ''; |
| 441 | + $c = 0; |
| 442 | + |
| 443 | + foreach ( $links as $link ) { |
| 444 | + $growinglink .= $link; |
| 445 | + $display .= $link; |
| 446 | + $linkObj = Title::newFromText( $growinglink ); |
| 447 | + |
| 448 | + if ( is_object( $linkObj ) ) { |
| 449 | + $getlink = Linker::link( $linkObj, htmlspecialchars( $display ) ); |
| 450 | + |
| 451 | + $c++; |
| 452 | + if ( $c > 1 ) { |
| 453 | + $subpages .= wfMessage( 'pipe-separator' )->escaped(); |
| 454 | + } else { |
| 455 | + // First iteration |
| 456 | + $subpages .= '< '; |
| 457 | + } |
| 458 | + |
| 459 | + $subpages .= $getlink; |
| 460 | + $display = ''; |
| 461 | + } else { |
| 462 | + $display .= '/'; |
| 463 | + } |
| 464 | + $growinglink .= '/'; |
| 465 | + } |
| 466 | + } |
| 467 | + $this->getOutput()->setSubtitle( $subpages ); |
| 468 | + return true; |
| 469 | + } |
169 | 470 | } |
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.api.js |
— | — | @@ -15,12 +15,12 @@ |
16 | 16 | gadgetCache = {}, |
17 | 17 | /** |
18 | 18 | * @var {Object} Keyed by repo, array of category objects |
19 | | - * @example { repoName: [ {name: .., title: .., members: .. }, { .. }, { .. } ] } |
| 19 | + * @example { repoName: [ {name: .., title: .., members: .. }, { .. }, { .. } ] } |
20 | 20 | */ |
21 | 21 | gadgetCategoryCache = {}; |
22 | | - |
| 22 | + |
23 | 23 | /* Local functions */ |
24 | | - |
| 24 | + |
25 | 25 | /** |
26 | 26 | * For most returns from api.* functions, a clone is made when data from |
27 | 27 | * cache is used. This is to avoid situations where later modifications |
— | — | @@ -42,32 +42,32 @@ |
43 | 43 | */ |
44 | 44 | return $.extend( true /* recursive */, {}, obj ); |
45 | 45 | } |
46 | | - |
| 46 | + |
47 | 47 | function arrClone( arr ) { |
48 | 48 | return arr.slice(); |
49 | 49 | } |
50 | | - |
| 50 | + |
51 | 51 | /** |
52 | 52 | * Reformat an array of gadget objects, into an object keyed by the id. |
53 | 53 | * Note: Maintains object reference |
54 | 54 | * @param arr {Array} |
55 | 55 | * @return {Object} |
56 | | - */ |
| 56 | + */ |
57 | 57 | function gadgetArrToObj( arr ) { |
58 | | - for( var obj = {}, i = 0, g = arr[i], len = arr.length; i < len; g = arr[++i] ) { |
59 | | - obj[g.id] = g; |
60 | | - } |
61 | | - return obj; |
| 58 | + for( var obj = {}, i = 0, g = arr[i], len = arr.length; i < len; g = arr[++i] ) { |
| 59 | + obj[g.id] = g; |
| 60 | + } |
| 61 | + return obj; |
62 | 62 | } |
63 | | - |
| 63 | + |
64 | 64 | /** |
65 | 65 | * Write data to gadgetCache, taking into account that id may be null |
66 | 66 | * and working around JS's annoying refusal to just let us do |
67 | 67 | * var foo = {}; foo[bar][baz] = quux; |
68 | | - * |
| 68 | + * |
69 | 69 | * This sets gadgetCache[repoName][id] = data; if id is not null, |
70 | 70 | * or gadgetCache[repoName] = data; if id is null. |
71 | | - * |
| 71 | + * |
72 | 72 | * @param repoName {String} Repository name |
73 | 73 | * @param id {String|null} Gadget ID or null |
74 | 74 | * @param data {Object} Data to put in the cache |
— | — | @@ -82,7 +82,7 @@ |
83 | 83 | gadgetCache[repoName][id] = data; |
84 | 84 | } |
85 | 85 | } |
86 | | - |
| 86 | + |
87 | 87 | /** |
88 | 88 | * Call an asynchronous function for each repository, and merge |
89 | 89 | * their return values into an object keyed by repository name. |
— | — | @@ -98,7 +98,7 @@ |
99 | 99 | for ( repo in mw.gadgets.conf.repos ) { |
100 | 100 | numRepos++; |
101 | 101 | } |
102 | | - |
| 102 | + |
103 | 103 | // Use $.each instead of a for loop so we can access repoName in the success callback |
104 | 104 | // without annoying issues |
105 | 105 | $.each( mw.gadgets.conf.repos, function( repoName, repoData ) { |
— | — | @@ -114,9 +114,9 @@ |
115 | 115 | ); |
116 | 116 | } ); |
117 | 117 | } |
118 | | - |
| 118 | + |
119 | 119 | /* Public functions */ |
120 | | - |
| 120 | + |
121 | 121 | mw.gadgets = { |
122 | 122 | /** |
123 | 123 | * @todo: Add something derived from $wgGadgetRepositories to gadgetsConf |
— | — | @@ -126,7 +126,7 @@ |
127 | 127 | api: { |
128 | 128 | /** |
129 | 129 | * Get the gadget blobs for all gadgets from all repositories. |
130 | | - * |
| 130 | + * |
131 | 131 | * @param success {Function} To be called with an object of arrays of gadget objects, keyed by repository name, as first argument. |
132 | 132 | * @param error {Function} To be called with a string (error code) as first argument. |
133 | 133 | */ |
— | — | @@ -136,17 +136,18 @@ |
137 | 137 | success, error |
138 | 138 | ); |
139 | 139 | }, |
140 | | - |
| 140 | + |
141 | 141 | /** |
142 | 142 | * Get the gadget categories from all repositories. |
143 | | - * |
144 | | - * @param success {Function} To be called with an array |
| 143 | + * |
| 144 | + * @param success {Function} To be called with an array |
145 | 145 | * @param success {Function} To be called with an object of arrays of category objects, keyed by repository name, as first argument. |
146 | 146 | * @param error {Function} To be called with a string (error code) as the first argument. |
147 | 147 | */ |
148 | 148 | getForeignGadgetCategories: function( success, error ) { |
149 | 149 | mergeRepositoryData( mw.gadgets.api.getGadgetCategories, success, error ); |
150 | 150 | }, |
| 151 | + |
151 | 152 | /** |
152 | 153 | * Get gadget blob from the API (or from cache if available). |
153 | 154 | * |
— | — | @@ -212,9 +213,10 @@ |
213 | 214 | } |
214 | 215 | }); |
215 | 216 | }, |
| 217 | + |
216 | 218 | /** |
217 | 219 | * Get the gadget categories for a certain repository from the API. |
218 | | - * |
| 220 | + * |
219 | 221 | * @param success {Function} To be called with an array as first argument. |
220 | 222 | * @param error {Function} To be called with a string (error code) as first argument. |
221 | 223 | * @param repoName {String} Name of the repository, key in mw.gadgets.conf.repos . Defaults to 'local' |
— | — | @@ -264,6 +266,7 @@ |
265 | 267 | } |
266 | 268 | }); |
267 | 269 | }, |
| 270 | + |
268 | 271 | /** |
269 | 272 | * Creates or edits an existing gadget definition. |
270 | 273 | * |
— | — | @@ -319,6 +322,7 @@ |
320 | 323 | } |
321 | 324 | }); |
322 | 325 | }, |
| 326 | + |
323 | 327 | /** |
324 | 328 | * Deletes a gadget definition. |
325 | 329 | * |
Index: branches/RL2/extensions/Gadgets/modules/images/edit.png |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes on: branches/RL2/extensions/Gadgets/modules/images/edit.png |
___________________________________________________________________ |
Added: svn:mime-type |
326 | 330 | + application/octet-stream |
Index: branches/RL2/extensions/Gadgets/modules/images/edit-faded.png |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes on: branches/RL2/extensions/Gadgets/modules/images/edit-faded.png |
___________________________________________________________________ |
Added: svn:mime-type |
327 | 331 | + application/octet-stream |
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.prejs.css |
— | — | @@ -1,14 +1,60 @@ |
2 | | -.mw-gadgetmanager-gadgets.mw-datatable th { |
3 | | - padding: 2px 21px 2px 5px; |
| 2 | +/* Gadget list */ |
| 3 | +.mw-gadgets-list { |
| 4 | + width: 100%; |
| 5 | + border-bottom: 1px solid #ccc; |
4 | 6 | } |
5 | 7 | |
6 | | -.mw-gadgetmanager-gadgets.mw-datatable td { |
7 | | - padding: 2px 5px; |
| 8 | +.mw-gadgets-gadget { |
| 9 | + overflow: hidden; |
| 10 | + position: relative; |
| 11 | + padding: 0.5em; |
| 12 | + border: 1px solid #ccc; |
| 13 | + border-bottom: 0; |
8 | 14 | } |
9 | 15 | |
10 | | -.mw-gadgetmanager-gadgets-default, |
11 | | -.mw-gadgetmanager-gadgets-hidden, |
12 | | -.mw-gadgetmanager-gadgets-shared { |
13 | | - width: 4em; |
14 | | - text-align: center; |
| 16 | +.mw-gadgets-gadget:hover { |
| 17 | + background: #f9f9ff; |
15 | 18 | } |
| 19 | + |
| 20 | +.mw-gadgets-title { |
| 21 | + font-weight: bold; |
| 22 | + min-height: 1.6em; |
| 23 | +} |
| 24 | + |
| 25 | +/* Tool links */ |
| 26 | + |
| 27 | +.mw-gadgets-messagelink { |
| 28 | + font-size: 75%; |
| 29 | + font-weight: normal; |
| 30 | +} |
| 31 | + |
| 32 | +.mw-gadgets-messagelink a { |
| 33 | + padding-left: 18px; |
| 34 | + /* @embed */ |
| 35 | + background-image: url(images/edit-faded.png); |
| 36 | + background-position: left top; |
| 37 | + background-repeat: no-repeat; |
| 38 | +} |
| 39 | + |
| 40 | +.mw-gadgets-messagelink a:hover { |
| 41 | + /* @embed */ |
| 42 | + background-image: url(images/edit.png); |
| 43 | +} |
| 44 | + |
| 45 | +.mw-gadgets-gadgetlinks { |
| 46 | + position: absolute; |
| 47 | + top: 0; |
| 48 | + right: 0; |
| 49 | + height: 1.6em; |
| 50 | + padding: 9px; |
| 51 | + font-size: 75%; |
| 52 | + font-weight: normal; |
| 53 | +} |
| 54 | + |
| 55 | +.mw-gadgets-gadgetlinks { |
| 56 | + float: right; |
| 57 | +} |
| 58 | + |
| 59 | +.mw-gadgets-gadgetlinks a { |
| 60 | + margin: 0 9px; |
| 61 | +} |
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.preferences.js |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | /** |
3 | 3 | * JavaScript to populate the shared gadgets tab on the preferences page. |
4 | | - * |
| 4 | + * |
5 | 5 | * @author Roan Kattouw |
6 | 6 | * @copyright © 2011 Roan Kattouw |
7 | 7 | * @license GNU General Public Licence 2.0 or later |
— | — | @@ -19,14 +19,14 @@ |
20 | 20 | .text( text ); |
21 | 21 | return $div.append( $input ).append( ' ' ).append( $label ); |
22 | 22 | } |
23 | | - |
| 23 | + |
24 | 24 | function buildForm( gadgetsByCategory, categoryNames ) { |
25 | 25 | var $container = $( '#mw-prefsection-gadgets-shared .mw-input' ), |
26 | 26 | // Detach the container from the DOM, so we can fill it without visible build-up. |
27 | 27 | // This is faster, too. In order to put it back where it was, we need to store its parent. |
28 | 28 | $containerParent = $container.parent(); |
29 | 29 | $container.detach(); |
30 | | - |
| 30 | + |
31 | 31 | for ( var category in gadgetsByCategory ) { |
32 | 32 | if ( category !== '' ) { |
33 | 33 | $container.append( $( '<h1>' ).text( categoryNames[category] ) ); |
— | — | @@ -38,7 +38,7 @@ |
39 | 39 | // Re-attach the container |
40 | 40 | $containerParent.append( $container ); |
41 | 41 | } |
42 | | - |
| 42 | + |
43 | 43 | // Temporary testing data |
44 | 44 | var categoryNames = { |
45 | 45 | 'foo': 'The Foreign Category of Foo' |
— | — | @@ -55,7 +55,7 @@ |
56 | 56 | 'a': 'Gadget A' |
57 | 57 | } |
58 | 58 | }; |
59 | | - |
| 59 | + |
60 | 60 | $( function() { buildForm( gadgetsByCategory, categoryNames ) } ); |
61 | | - |
| 61 | + |
62 | 62 | } )( jQuery ); |
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.css |
— | — | @@ -13,6 +13,10 @@ |
14 | 14 | width: 100%; |
15 | 15 | } |
16 | 16 | |
| 17 | +.mw-gadgetmanager-label { |
| 18 | + width: 20%; |
| 19 | +} |
| 20 | + |
17 | 21 | .mw-gadgetmanager-form td, |
18 | 22 | .mw-gadgetmanager-form th { |
19 | 23 | vertical-align: top; |
— | — | @@ -27,8 +31,6 @@ |
28 | 32 | overflow: hidden; |
29 | 33 | } |
30 | 34 | |
31 | | -.mw-gadgetmanager-propcontainer {} |
32 | | - |
33 | 35 | .mw-gadgetmanager-prop { |
34 | 36 | float: left; |
35 | 37 | margin: 2px 5px 5px 2px; |
— | — | @@ -39,8 +41,6 @@ |
40 | 42 | line-height: 1; |
41 | 43 | } |
42 | 44 | |
43 | | -.mw-gadgetmanager-prop-label {} |
44 | | - |
45 | 45 | .mw-gadgetmanager-prop-delete { |
46 | 46 | display: inline-block; |
47 | 47 | width: 10px; |
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.js |
— | — | @@ -21,19 +21,19 @@ |
22 | 22 | <legend><html:msg key="gadgetmanager-propsgroup-module" /></legend>\ |
23 | 23 | <table>\ |
24 | 24 | <tr>\ |
25 | | - <td><label for="mw-gadgetmanager-input-scripts"><html:msg key="gadgetmanager-prop-scripts" /></label></td>\ |
| 25 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-scripts"><html:msg key="gadgetmanager-prop-scripts" /></label></td>\ |
26 | 26 | <td><input type="text" id="mw-gadgetmanager-input-scripts" /></td>\ |
27 | 27 | </tr>\ |
28 | 28 | <tr>\ |
29 | | - <td><label for="mw-gadgetmanager-input-styles"><html:msg key="gadgetmanager-prop-styles" /></label></td>\ |
| 29 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-styles"><html:msg key="gadgetmanager-prop-styles" /></label></td>\ |
30 | 30 | <td><input type="text" id="mw-gadgetmanager-input-styles" /></td>\ |
31 | 31 | </tr>\ |
32 | 32 | <tr>\ |
33 | | - <td><label for="mw-gadgetmanager-input-dependencies"><html:msg key="gadgetmanager-prop-dependencies" /></label></td>\ |
| 33 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-dependencies"><html:msg key="gadgetmanager-prop-dependencies" /></label></td>\ |
34 | 34 | <td><input type="text" id="mw-gadgetmanager-input-dependencies" /></td>\ |
35 | 35 | </tr>\ |
36 | 36 | <tr>\ |
37 | | - <td><label for="mw-gadgetmanager-input-messages"><html:msg key="gadgetmanager-prop-messages" /></label></td>\ |
| 37 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-messages"><html:msg key="gadgetmanager-prop-messages" /></label></td>\ |
38 | 38 | <td><input type="text" id="mw-gadgetmanager-input-messages" /></td>\ |
39 | 39 | </tr>\ |
40 | 40 | </table>\ |
— | — | @@ -42,23 +42,23 @@ |
43 | 43 | <legend><html:msg key="gadgetmanager-propsgroup-settings" /></legend>\ |
44 | 44 | <table>\ |
45 | 45 | <tr>\ |
46 | | - <td><label for="mw-gadgetmanager-input-category"><html:msg key="gadgetmanager-prop-category" /></label></td>\ |
| 46 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-category"><html:msg key="gadgetmanager-prop-category" /></label></td>\ |
47 | 47 | <td><select id="mw-gadgetmanager-input-category"></select></td>\ |
48 | 48 | </tr>\ |
49 | 49 | <tr>\ |
50 | | - <td><label for="mw-gadgetmanager-input-rights"><html:msg key="gadgetmanager-prop-rights" /></label></td>\ |
| 50 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-rights"><html:msg key="gadgetmanager-prop-rights" /></label></td>\ |
51 | 51 | <td><input type="text" id="mw-gadgetmanager-input-rights" /></td>\ |
52 | 52 | </tr>\ |
53 | 53 | <tr>\ |
54 | | - <td><label for="mw-gadgetmanager-input-default"><html:msg key="gadgetmanager-prop-default" /></label></td>\ |
| 54 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-default"><html:msg key="gadgetmanager-prop-default" /></label></td>\ |
55 | 55 | <td><input type="checkbox" id="mw-gadgetmanager-input-default" /></td>\ |
56 | 56 | </tr>\ |
57 | 57 | <tr>\ |
58 | | - <td><label for="mw-gadgetmanager-input-hidden"><html:msg key="gadgetmanager-prop-hidden"></label></td>\ |
| 58 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-hidden"><html:msg key="gadgetmanager-prop-hidden"></label></td>\ |
59 | 59 | <td><input type="checkbox" id="mw-gadgetmanager-input-hidden" /></td>\ |
60 | 60 | </tr>\ |
61 | 61 | ' + ( ga.conf.enableSharing ? '<tr>\ |
62 | | - <td><label for="mw-gadgetmanager-input-shared"><html:msg key="gadgetmanager-prop-shared" /></label></td>\ |
| 62 | + <td class="mw-gadgetmanager-label"><label for="mw-gadgetmanager-input-shared"><html:msg key="gadgetmanager-prop-shared" /></label></td>\ |
63 | 63 | <td><input type="checkbox" id="mw-gadgetmanager-input-shared" /></td>\ |
64 | 64 | </tr>\ |
65 | 65 | ' : '' ) + '</table>\ |
— | — | @@ -96,14 +96,14 @@ |
97 | 97 | * Utility function to pad a zero |
98 | 98 | * to single digit number. Used by ISODateString(). |
99 | 99 | * @param n {Number} |
100 | | - * @return {String} |
| 100 | + * @return {String|Number} |
101 | 101 | */ |
102 | 102 | function pad( n ) { |
103 | 103 | return n < 10 ? '0' + n : n; |
104 | 104 | } |
105 | 105 | /** |
106 | 106 | * Format a date in an ISO 8601 format using UTC. |
107 | | - * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date#Example:_ISO_8601_formatted_dates |
| 107 | + * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date#Example:_ISO_8601 |
108 | 108 | * |
109 | 109 | * @param d {Date} |
110 | 110 | * @return {String} |
— | — | @@ -125,12 +125,40 @@ |
126 | 126 | * to the anchor tags in the table. |
127 | 127 | */ |
128 | 128 | initUI: function() { |
129 | | - // Bind trigger to the links |
130 | | - $( '.mw-gadgetmanager-gadgets .mw-gadgetmanager-gadgets-title a' ) |
131 | | - .click( function( e ) { |
| 129 | + // Add ajax links |
| 130 | + $( '.mw-gadgets-gadgetlinks' ).each( function( i, el ) { |
| 131 | + var $el = $( el ); |
| 132 | + if ( ga.conf.userIsAllowed['gadgets-definition-edit'] ) { |
| 133 | + $el.find( '.mw-gadgets-modify' ).click( function( e ) { |
| 134 | + e.preventDefault(); |
| 135 | + ga.ui.startGadgetEditor( $el.data( 'gadget-id' ) ); |
| 136 | + }); |
| 137 | + } |
| 138 | + if ( ga.conf.userIsAllowed['gadgets-definition-delete'] ) { |
| 139 | + $el.find( '.mw-gadgets-modify' ).click( function( e ) { |
| 140 | + e.preventDefault(); |
| 141 | + // @todo: Show delete action form |
| 142 | + }); |
| 143 | + } |
| 144 | + } ); |
| 145 | + |
| 146 | + if ( ga.conf.userIsAllowed['gadgets-definition-create'] ) { |
| 147 | + var createTab = mw.util.addPortletLink( |
| 148 | + // Not all skins use the new separated tabs yet, |
| 149 | + // Fall back to the general 'p-cactions'. |
| 150 | + $( '#p-views' ).length ? 'p-views' : 'p-cactions', |
| 151 | + '#', |
| 152 | + mw.msg( 'gadgets-gadget-create' ), |
| 153 | + 'ca-create', // Use whatever core has for pages ? Or use gadget-create ? |
| 154 | + mw.msg( 'gadgets-gadget-create-tooltip' ), |
| 155 | + 'e' // Same as core for ca-edit |
| 156 | + ); |
| 157 | + $( createTab ).click( function( e ) { |
132 | 158 | e.preventDefault(); |
133 | | - ga.ui.startGadgetEditor( $( this ).data( 'gadget-id' ) ); |
134 | | - }); |
| 159 | + // @todo: Trigger edit form with editable field for gadget id. |
| 160 | + } ); |
| 161 | + } |
| 162 | + |
135 | 163 | }, |
136 | 164 | |
137 | 165 | /** |
— | — | @@ -232,6 +260,7 @@ |
233 | 261 | response( suggestCacheScripts[data.term] ); |
234 | 262 | return; |
235 | 263 | } |
| 264 | + |
236 | 265 | $.getJSON( mw.util.wikiScript( 'api' ), { |
237 | 266 | format: 'json', |
238 | 267 | action: 'query', |
— | — | @@ -394,7 +423,6 @@ |
395 | 424 | .prop( 'checked', metadata.settings.shared ) |
396 | 425 | .change( function() { metadata.settings.shared = this.checked; }); |
397 | 426 | |
398 | | - |
399 | 427 | return $form; |
400 | 428 | } |
401 | 429 | }; |
Index: branches/RL2/extensions/Gadgets/api/ApiQueryGadgetCategories.php |
— | — | @@ -54,7 +54,7 @@ |
55 | 55 | } |
56 | 56 | if ( isset( $this->props['title'] ) ) { |
57 | 57 | if ( $category === '' ) { |
58 | | - $row['title'] = wfMessage( 'gadgetmanager-uncategorized' )->plain(); |
| 58 | + $row['title'] = wfMessage( 'gadgets-uncategorized' )->plain(); |
59 | 59 | } else { |
60 | 60 | $row['title'] = $repo->getCategoryTitle( $category, $this->language ); |
61 | 61 | } |