Index: trunk/extensions/Gadgets/README |
— | — | @@ -33,7 +33,7 @@ |
34 | 34 | Each line in MediaWiki:Gadgets-definition that start with one or more "*" |
35 | 35 | (asterisk) characters defines a gadget; it must have the following form: |
36 | 36 | |
37 | | - * mygadget|mygadget.js|mygadget.css |
| 37 | + * mygadget|mygadget.js|mygadget.css[option1|option2] |
38 | 38 | |
39 | 39 | That is, each line consists of fields separated by a "|" (pipe) character. |
40 | 40 | The first field ("mygadget" in the example) is the gadgets internal name, |
— | — | @@ -65,7 +65,27 @@ |
66 | 66 | This would define a new section, with the title defined on the page |
67 | 67 | MediaWiki:Gadget-section-editing-gadgets |
68 | 68 | |
| 69 | +== Options == |
| 70 | +Options are optionally appended to the end of the gadget declaration. |
| 71 | +They are enclosed in square brackets ("[...]") and are separated by pipe |
| 72 | +character ("|"). |
| 73 | + |
| 74 | +Currently, there are two options: rights required to use the gadget, and |
| 75 | +whether the gadget should be enaled for everyone by default. |
69 | 76 | |
| 77 | +The rights option looks like "[rights:delete,userrights]". Note that it |
| 78 | +requires specific rights, not groups the user belongs to. This option is |
| 79 | +case-sensitive, but ignores whitespace, i.e. "[ rights: foo , bar ]" is a |
| 80 | +valid declaration, but not "[Rights:Foo]". |
| 81 | + |
| 82 | +The "default" option, if present, makes this gadget enabled for every |
| 83 | +eligible user who has not specifically opted out of it by unchecking it in |
| 84 | +their preferences. The option looks like that: "[default]". |
| 85 | + |
| 86 | +Options may be combined in any number or order, i.e. "[rights:foo, bar]", |
| 87 | +"[default]", "[rights:boz|default]" and "[default|rights:quux]" are all valid |
| 88 | +declarations. |
| 89 | + |
70 | 90 | == Caveats == |
71 | 91 | |
72 | 92 | * Requires MediaWiki 1.11alpha, revision 24477 or later. |
Index: trunk/extensions/Gadgets/Gadgets.i18n.php |
— | — | @@ -32,6 +32,8 @@ |
33 | 33 | 'gadgets-pagetext' => "Below is a list of special gadgets users can enable on their preferences page, as defined by [[MediaWiki:Gadgets-definition]]. |
34 | 34 | This overview provides easy access to the system message pages that define each gadget's description and code.", |
35 | 35 | 'gadgets-uses' => 'Uses', |
| 36 | + 'gadgets-rights' => 'Requires the following rights', |
| 37 | + 'gadgets-default' => 'Enabled by default', |
36 | 38 | ); |
37 | 39 | |
38 | 40 | /** Amharic (አማርኛ) |
— | — | @@ -894,7 +896,6 @@ |
895 | 897 | * @author Illusion |
896 | 898 | * @author Siebrand |
897 | 899 | * @author Александр Сигачёв |
898 | | - * @author Ahonc |
899 | 900 | */ |
900 | 901 | $messages['ru'] = array( |
901 | 902 | 'gadgets-desc' => 'Позволяет участникам выбирать в [[Special:Preferences|настройках]] CSS- и JavaScript-гаджеты, которые они хотят подключить', |
— | — | @@ -1160,3 +1161,4 @@ |
1161 | 1162 | 'gadgets-uses' => '使用', |
1162 | 1163 | ); |
1163 | 1164 | |
| 1165 | + |
Index: trunk/extensions/Gadgets/Gadgets.php |
— | — | @@ -38,6 +38,23 @@ |
39 | 39 | $wgAutoloadClasses['SpecialGadgets'] = $dir . 'SpecialGadgets.php'; |
40 | 40 | $wgSpecialPages['Gadgets'] = 'SpecialGadgets'; |
41 | 41 | |
| 42 | +class Gadget { |
| 43 | + const CACHE_VERSION = 1; |
| 44 | + /** |
| 45 | + * This gadget option contains rights the user must have to use this gadget |
| 46 | + */ |
| 47 | + const RIGHTS = 666; |
| 48 | + |
| 49 | + /** |
| 50 | + * This gadget should be enabled by default |
| 51 | + */ |
| 52 | + const ON_BY_DEFAULT = 667; |
| 53 | + |
| 54 | + var $name = ''; |
| 55 | + var $modules = array(); |
| 56 | + var $options = array(); |
| 57 | +} |
| 58 | + |
42 | 59 | function wfGadgetsArticleSaveComplete( &$article, &$wgUser, &$text ) { |
43 | 60 | //update cache if MediaWiki:Gadgets-definition was edited |
44 | 61 | $title = $article->mTitle; |
— | — | @@ -77,7 +94,10 @@ |
78 | 95 | if ( $forceNewText === NULL ) { |
79 | 96 | //cached? |
80 | 97 | $gadgets = $wgMemc->get( $key ); |
81 | | - if ( is_array($gadgets) ) return $gadgets; |
| 98 | + if ( is_array( $gadgets ) && isset( $gadgets['version'] ) && $gadgets['version'] == Gadget::CACHE_VERSION ) { |
| 99 | + unset( $gadgets['version'] ); |
| 100 | + return $gadgets; |
| 101 | + } |
82 | 102 | |
83 | 103 | $g = wfMsgForContentNoTrans( "gadgets-definition" ); |
84 | 104 | if ( wfEmptyMsg( "gadgets-definition", $g ) ) { |
— | — | @@ -97,29 +117,48 @@ |
98 | 118 | foreach ( $g as $line ) { |
99 | 119 | if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', $line, $m ) ) { |
100 | 120 | $section = $m[1]; |
101 | | - } |
102 | | - else if ( preg_match( '/^\*+ *([a-zA-Z](?:[-_:.\w\d ]*[a-zA-Z0-9])?)\s*((\|[^|]*)+)\s*$/', $line, $m ) ) { |
| 121 | + } else if ( preg_match( '/^\*+ *([a-zA-Z](?:[-_:.\w\d ]*[a-zA-Z0-9])?)\s*((\|[^|[]*)+)\s*(|\[(.*)\])\s*$/', $line, $m ) ) { |
| 122 | + $gadget = new Gadget(); |
| 123 | + |
103 | 124 | //NOTE: the gadget name is used as part of the name of a form field, |
104 | 125 | // and must follow the rules defined in http://www.w3.org/TR/html4/types.html#type-cdata |
105 | 126 | // Also, title-normalization applies. |
106 | | - $name = str_replace(' ', '_', $m[1] ); |
| 127 | + $gadget->name = str_replace(' ', '_', $m[1] ); |
107 | 128 | |
108 | | - $code = preg_split( '/\s*\|\s*/', $m[2], -1, PREG_SPLIT_NO_EMPTY ); |
| 129 | + $gadget->modules = preg_split( '/\s*\|\s*/', $m[2], -1, PREG_SPLIT_NO_EMPTY ); |
109 | 130 | |
110 | | - if ( $code ) { |
111 | | - $gadgets[$section][$name] = $code; |
| 131 | + if( !empty( $m[5] ) && $gadget->modules ) |
| 132 | + $gadget->options = wfProcessGadgetOptions( $m[5] ); |
| 133 | + |
| 134 | + if ( $gadget->modules ) { |
| 135 | + $gadgets[$section][$gadget->name] = $gadget; |
112 | 136 | } |
113 | 137 | } |
114 | 138 | } |
115 | 139 | |
116 | 140 | //cache for a while. gets purged automatically when MediaWiki:Gadgets-definition is edited |
117 | | - $wgMemc->set( $key, $gadgets, 60*60*24 ); |
| 141 | + $gadgets['version'] = Gadget::CACHE_VERSION; |
| 142 | + $wgMemc->set( $key, $gadgets, 60*60*24 ); |
118 | 143 | $source = $forceNewText !== NULL ? 'input text' : 'MediaWiki:Gadgets-definition'; |
119 | 144 | wfDebug( __METHOD__ . ": $source parsed, cache entry $key updated\n"); |
120 | 145 | |
| 146 | + unset( $gadgets['version'] ); |
121 | 147 | return $gadgets; |
122 | 148 | } |
123 | 149 | |
| 150 | +function wfProcessGadgetOptions( $options ) { |
| 151 | + $out = array(); |
| 152 | + foreach( preg_split( '/\s*\|\s*/', $options, -1, PREG_SPLIT_NO_EMPTY ) as $option ) { |
| 153 | + if( preg_match( '/^rights\s*:\s*([\w\s,]+)$/', $option, $m ) ) { |
| 154 | + $out[Gadget::RIGHTS] = preg_split( '/\s*,\s*/', $m[1], -1, PREG_SPLIT_NO_EMPTY ); |
| 155 | + } elseif( preg_match( '/^default$/', $option ) ) { |
| 156 | + $out[Gadget::ON_BY_DEFAULT] = true; |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + return $out; |
| 161 | +} |
| 162 | + |
124 | 163 | function wfGadgetsInitPreferencesForm( &$prefs, &$request ) { |
125 | 164 | $gadgets = wfLoadGadgets(); |
126 | 165 | if ( !$gadgets ) return true; |
— | — | @@ -132,6 +171,18 @@ |
133 | 172 | return true; |
134 | 173 | } |
135 | 174 | |
| 175 | +function wfGadgetAllowed( $options ) { |
| 176 | + global $wgUser; |
| 177 | + |
| 178 | + if( isset( $options[Gadget::RIGHTS] ) ) |
| 179 | + foreach( $options[Gadget::RIGHTS] as $right ) { |
| 180 | + if( !in_array( $right, $wgUser->getRights() ) ) |
| 181 | + return FALSE; |
| 182 | + } |
| 183 | + |
| 184 | + return TRUE; |
| 185 | +} |
| 186 | + |
136 | 187 | function wfGadgetsResetPreferences( &$prefs, &$user ) { |
137 | 188 | $gadgets = wfLoadGadgets(); |
138 | 189 | if ( !$gadgets ) return true; |
— | — | @@ -145,6 +196,8 @@ |
146 | 197 | } |
147 | 198 | |
148 | 199 | function wfGadgetsRenderPreferencesForm( &$prefs, &$out ) { |
| 200 | + global $wgUser; |
| 201 | + |
149 | 202 | $gadgets = wfLoadGadgetsStructured(); |
150 | 203 | if ( !$gadgets ) return true; |
151 | 204 | |
— | — | @@ -157,22 +210,39 @@ |
158 | 211 | $msgOpt = array( 'parseinline' ); |
159 | 212 | |
160 | 213 | foreach ( $gadgets as $section => $entries ) { |
161 | | - if ( $section !== false && $section !== '' ) { |
162 | | - $ttext = wfMsgExt( "gadget-section-$section", $msgOpt ); |
163 | | - $out->addHtml( "\n<h2 id=\"".htmlspecialchars("gadget-section-$section")."\">" . $ttext . "</h2>\n" ); |
164 | | - } |
| 214 | + $first = true; |
165 | 215 | |
166 | | - foreach ( $entries as $gname => $code ) { |
| 216 | + foreach ( $entries as $gname => $gadget ) { |
167 | 217 | $tname = "gadget-$gname"; |
168 | 218 | $ttext = wfMsgExt( $tname, $msgOpt ); |
169 | | - $checked = @$prefs->mToggles[$tname] == 1 ? ' checked="checked"' : ''; |
| 219 | + |
| 220 | + if( ( ( $prefs->mToggles[$tname] != '' ) && ($prefs->mToggles[$tname] == 1) ) |
| 221 | + || ( ( $prefs->mToggles[$tname] === '' ) && isset( $gadget->options[Gadget::ON_BY_DEFAULT] ) ) ) |
| 222 | + $checked = ' checked="checked"'; |
| 223 | + else |
| 224 | + $checked = ''; |
| 225 | + |
170 | 226 | $disabled = ''; |
171 | 227 | |
172 | | - # NOTE: No label for checkmarks as this causes the checks to toggle |
173 | | - # when clicking a link in the describing text. |
174 | | - $out->addHtml( "<div class='toggle'><input type='checkbox' value='1' " . |
175 | | - "id=\"$tname\" name=\"wpOp$tname\"$checked$disabled />" . |
176 | | - " <span class='toggletext'>$ttext</span></div>\n" ); |
| 228 | + if( wfGadgetAllowed( $gadget->options ) ) { |
| 229 | + // draw section heading |
| 230 | + if ($first && $section !== false && $section !== '' ) { |
| 231 | + $stext = wfMsgExt( "gadget-section-$section", $msgOpt ); |
| 232 | + $out->addHtml( "\n<h2 id=\"".htmlspecialchars("gadget-section-$section")."\">" . $stext . "</h2>\n" ); |
| 233 | + $first = false; |
| 234 | + } |
| 235 | + |
| 236 | + if( isset( $gadget->options[Gadget::ON_BY_DEFAULT] ) ) |
| 237 | + $extra = ' (' . wfMsg( 'gadgets-default' ) . ')'; |
| 238 | + else |
| 239 | + $extra = ''; |
| 240 | + |
| 241 | + # NOTE: No label for checkmarks as this causes the checks to toggle |
| 242 | + # when clicking a link in the describing text. |
| 243 | + $out->addHtml( "<div class='toggle'><input type='checkbox' value='1' " . |
| 244 | + "id=\"$tname\" name=\"wpOp$tname\"$checked$disabled />" . |
| 245 | + " <span class='toggletext'>$ttext</span>$extra</div>\n" ); |
| 246 | + } |
177 | 247 | } |
178 | 248 | } |
179 | 249 | |
— | — | @@ -196,10 +266,13 @@ |
197 | 267 | |
198 | 268 | $done = array(); |
199 | 269 | |
200 | | - foreach ( $gadgets as $gname => $code ) { |
201 | | - $tname = "gadget-$gname"; |
202 | | - if ( $wgUser->getOption( $tname ) ) { |
203 | | - wfApplyGadgetCode( $code, $out, $done ); |
| 270 | + foreach ( $gadgets as $gname => $gadget ) { |
| 271 | + if( wfGadgetAllowed( $gadget->options ) ) { |
| 272 | + $tname = "gadget-$gname"; |
| 273 | + $default = isset( $gadget->options[Gadget::ON_BY_DEFAULT] ); |
| 274 | + if ( $wgUser->getOption( $tname, $default ) ) { |
| 275 | + wfApplyGadgetCode( $gadget->modules, $out, $done ); |
| 276 | + } |
204 | 277 | } |
205 | 278 | } |
206 | 279 | |
Index: trunk/extensions/Gadgets/SpecialGadgets.php |
— | — | @@ -59,24 +59,33 @@ |
60 | 60 | $wgOut->addHTML( "\n<h2>$ttext [$lnk]</h2>\n" ); |
61 | 61 | } |
62 | 62 | |
63 | | - foreach ( $entries as $gname => $code ) { |
| 63 | + foreach ( $entries as $gname => $gadget ) { |
64 | 64 | $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-$gname" ); |
65 | 65 | if ( !$t ) continue; |
66 | 66 | |
67 | 67 | $lnk = $skin->makeLinkObj( $t, wfMsgHTML("edit"), 'action=edit' ); |
68 | 68 | $ttext = wfMsgExt( "gadget-$gname", $msgOpt ); |
69 | | - |
| 69 | + |
70 | 70 | if( !$listOpen ) { |
71 | 71 | $listOpen = true; |
72 | 72 | $wgOut->addHTML( '<ul>' ); |
73 | 73 | } |
74 | 74 | $wgOut->addHTML( "<li>" ); |
75 | 75 | $wgOut->addHTML( "$ttext [$lnk]<br />" ); |
| 76 | + |
| 77 | + if( isset( $gadget->options[Gadget::RIGHTS] ) && !empty( $gadget->options[Gadget::RIGHTS] ) ) { |
| 78 | + $wgOut->addHTML( wfMsgHTML( 'gadgets-rights' ) . ": " ); |
| 79 | + $wgOut->addHTML( htmlspecialchars( implode( ', ', $gadget->options[Gadget::RIGHTS] ) ) . '<br />' ); |
| 80 | + } |
| 81 | + |
| 82 | + if( isset( $gadget->options[Gadget::ON_BY_DEFAULT] ) ) |
| 83 | + $wgOut->addHTML( wfMsgHTML( "gadgets-default" ) . "<br />" ); |
| 84 | + |
76 | 85 | |
77 | 86 | $wgOut->addHTML( wfMsgHTML("gadgets-uses") . ": " ); |
78 | 87 | |
79 | 88 | $first = true; |
80 | | - foreach ( $code as $codePage ) { |
| 89 | + foreach ( $gadget->modules as $codePage ) { |
81 | 90 | $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-$codePage" ); |
82 | 91 | if ( !$t ) continue; |
83 | 92 | |