r95572 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95571‎ | r95572 | r95573 >
Date:20:12, 26 August 2011
Author:johnduhart
Status:resolved (Comments)
Tags:
Comment:
Adds ResourceLoader support to AbuseFilter
Rewrote javascript to use jQuery
Added API modules to replace sajax_* calls
Solves bug 29714
Modified paths:
  • /trunk/extensions/AbuseFilter/AbuseFilter.class.php (modified) (history)
  • /trunk/extensions/AbuseFilter/AbuseFilter.hooks.php (modified) (history)
  • /trunk/extensions/AbuseFilter/AbuseFilter.php (modified) (history)
  • /trunk/extensions/AbuseFilter/Views/AbuseFilterViewEdit.php (modified) (history)
  • /trunk/extensions/AbuseFilter/Views/AbuseFilterViewExamine.php (modified) (history)
  • /trunk/extensions/AbuseFilter/Views/AbuseFilterViewTools.php (modified) (history)
  • /trunk/extensions/AbuseFilter/Views/examine.js (deleted) (history)
  • /trunk/extensions/AbuseFilter/Views/tools.js (deleted) (history)
  • /trunk/extensions/AbuseFilter/abusefilter.css (deleted) (history)
  • /trunk/extensions/AbuseFilter/api/ApiCheckFilterMatch.php (added) (history)
  • /trunk/extensions/AbuseFilter/api/ApiCheckFilterSyntax.php (added) (history)
  • /trunk/extensions/AbuseFilter/api/ApiEvalFilterExpression.php (added) (history)
  • /trunk/extensions/AbuseFilter/api/ApiQueryAbuseFilters.php (modified) (history)
  • /trunk/extensions/AbuseFilter/api/ApiQueryAbuseLog.php (modified) (history)
  • /trunk/extensions/AbuseFilter/api/ApiUnblockAutopromote.php (added) (history)
  • /trunk/extensions/AbuseFilter/edit.js (deleted) (history)
  • /trunk/extensions/AbuseFilter/modules (added) (history)
  • /trunk/extensions/AbuseFilter/modules/ext.abuseFilter.css (added) (history)
  • /trunk/extensions/AbuseFilter/modules/ext.abuseFilter.edit.js (added) (history)
  • /trunk/extensions/AbuseFilter/modules/ext.abuseFilter.examine.js (added) (history)
  • /trunk/extensions/AbuseFilter/modules/ext.abuseFilter.tools.js (added) (history)
  • /trunk/extensions/AbuseFilter/special/SpecialAbuseFilter.php (modified) (history)
  • /trunk/extensions/AbuseFilter/special/SpecialAbuseLog.php (modified) (history)

Diff [purge]

Index: trunk/extensions/AbuseFilter/abusefilter.css
@@ -1,123 +0,0 @@
2 -/* This code was stolen shamelessly from enwikipedia's Common.css */
3 -table.mw-abuselog-details {
4 - margin: 1em 1em 1em 0;
5 - background: #f9f9f9;
6 - border: 1px #aaa solid;
7 - border-collapse: collapse;
8 - width: 80%;
9 -}
10 -
11 -table.mw-abuselog-details th, table.mw-abuselog-details td {
12 - border: 1px #aaa solid;
13 - padding: 0.2em;
14 -}
15 -
16 -table.mw-abuselog-details th {
17 - background: #f2f2f2;
18 - text-align: center;
19 -}
20 -
21 -table.mw-abuselog-details caption {
22 - font-weight: bold;
23 -}
24 -
25 -.mw-abusefilter-history-changed {
26 - background: #ffe0e0;
27 - font-weight: bold;
28 -}
29 -
30 -.mw-abuselog-var-value {
31 - white-space: pre-wrap;
32 - font-family: monospace;
33 -}
34 -
35 -div.mw-abuselog-var-value {
36 - max-height: 10em;
37 - max-width: 100%;
38 - overflow: auto;
39 -}
40 -
41 -td.mw-abuselog-var {
42 - width: 30%;
43 -}
44 -
45 -tr.mw-abusefilter-list-disabled, tr.mw-abusefilter-list-disabled td {
46 - color: #666666;
47 -}
48 -
49 -tr.mw-abusefilter-list-deleted, tr.mw-abusefilter-list-deleted td {
50 - color: #aaaaaa;
51 -}
52 -
53 -.mw-abusefilter-examine-match,
54 -.mw-abusefilter-syntaxresult-ok,
55 -li.mw-abusefilter-changeslist-match {
56 - background-image: url(yes_check.png);
57 -}
58 -
59 -.mw-abusefilter-examine-nomatch,
60 -.mw-abusefilter-examine-syntaxerror,
61 -.mw-abusefilter-syntaxresult-error,
62 -li.mw-abusefilter-changeslist-nomatch {
63 - background-image: url(red_x.png);
64 -}
65 -
66 -#mw-abusefilter-syntaxresult,
67 -li.mw-abusefilter-changeslist-nomatch,
68 -li.mw-abusefilter-changeslist-match {
69 - background: no-repeat left center;
70 - padding-left: 25px;
71 -}
72 -
73 -table.mw-abusefilter-diff {
74 - width: 80%;
75 - border-collapse: collapse;
76 -}
77 -
78 -table.mw-abusefilter-diff td,
79 -table.mw-abusefilter-diff th {
80 - border: 1px solid #888888;
81 -}
82 -
83 -.mw-abusefilter-diff-added,
84 -.mw-abusefilter-diff-multiline .diff-addedline {
85 - background: #cfc;
86 -}
87 -
88 -.mw-abusefilter-diff-removed,
89 -.mw-abusefilter-diff-multiline .diff-deletedline {
90 - background: #ffa;
91 -}
92 -
93 -.mw-abusefilter-diff-context,
94 -.mw-abusefilter-diff-multiline .diff-context {
95 - background: #eee;
96 -}
97 -
98 -.mw-abusefilter-diff-multiline {
99 - width: 100%;
100 -}
101 -
102 -.mw-abusefilter-diff-multiline td {
103 - border: none !important;
104 -}
105 -
106 -.mw-abusefilter-diff-multiline .diff-marker {
107 - font-size: 0.8em;
108 -}
109 -
110 -.mw-abusefilter-diff-multiline td.diff-addedline,
111 -.mw-abusefilter-diff-multiline td.diff-deletedline {
112 - width: 50%;
113 -}
114 -
115 -/* Rules are in English */
116 -/* @noflip */textarea#wpFilterRules { direction: ltr; }
117 -
118 -/* Name is in site content language */
119 -/* @noflip */.sitedir-ltr .TablePager_col_af_public_comments {
120 - direction: ltr;
121 -}
122 -/* @noflip */.sitedir-rtl .TablePager_col_af_public_comments {
123 - direction: rtl;
124 -}
\ No newline at end of file
Index: trunk/extensions/AbuseFilter/edit.js
@@ -1,182 +0,0 @@
2 -function doSyntaxCheck() {
3 - var filter = document.getElementById(wgFilterBoxName).value;
4 - injectSpinner( document.getElementById( 'mw-abusefilter-syntaxcheck' ), 'abusefilter-syntaxcheck' );
5 - document.getElementById( 'mw-abusefilter-syntaxcheck' ).disabled = true;
6 - sajax_do_call( 'AbuseFilter::ajaxCheckSyntax', [filter], processSyntaxResult );
7 -}
8 -
9 -function processSyntaxResult( request ) {
10 - var response = request.responseText;
11 -
12 - removeSpinner( 'abusefilter-syntaxcheck' );
13 - document.getElementById( 'mw-abusefilter-syntaxcheck' ).disabled = false;
14 -
15 - var el = document.getElementById( 'mw-abusefilter-syntaxresult' );
16 - el.style.display = 'block';
17 -
18 - if ( response.match( /OK/ ) ) {
19 - // Successful
20 - changeText( el, wgAbuseFilterMessages['abusefilter-edit-syntaxok'] );
21 - el.syntaxOk = true;
22 - el.className = 'mw-abusefilter-syntaxresult-ok';
23 - } else {
24 - var errorData = eval(response.substr(4));
25 - var msg = wgAbuseFilterMessages['abusefilter-edit-syntaxerr'];
26 - msg = msg.replace( '$1', errorData[0] );
27 - changeText( el, msg );
28 - el.syntaxOk = false;
29 - el.className = 'mw-abusefilter-syntaxresult-error';
30 -
31 - var position = errorData[1];
32 - var textArea = document.getElementById( wgFilterBoxName );
33 -
34 - textArea.focus();
35 - if ( document.selection ) {
36 - var sel = document.selection.createRange();
37 - sel.moveStart( 'character', -textArea.value.length );
38 - sel.moveStart( 'character', position );
39 - sel.select();
40 - } else if (textArea.selectionStart && textArea.selectionEnd) {
41 - textArea.selectionStart = position;
42 - textArea.selectionEnd = position;
43 - }
44 - }
45 -}
46 -
47 -function addText() {
48 - if ( document.getElementById('wpFilterBuilder').selectedIndex == 0 ) {
49 - return;
50 - }
51 -
52 - insertAtCursor(document.getElementById(wgFilterBoxName), document.getElementById('wpFilterBuilder').value + " ");
53 - document.getElementById('wpFilterBuilder').selectedIndex = 0;
54 -}
55 -
56 -function fetchFilter() {
57 - var filter = document.getElementById( 'mw-abusefilter-load-filter' ).value;
58 -
59 - sajax_do_call( 'AbuseFilter::ajaxGetFilter', [filter], function(request) {
60 - var filter = request.responseText;
61 - document.getElementById( wgFilterBoxName ).value = filter;
62 - } );
63 -}
64 -
65 -//From http://clipmarks.com/clipmark/CEFC94CB-94D6-4495-A7AA-791B7355E284/
66 -function insertAtCursor( myField, myValue ) {
67 - //IE support
68 - if ( document.selection ) {
69 - myField.focus();
70 - sel = document.selection.createRange();
71 - sel.text = myValue;
72 - }
73 - //MOZILLA/NETSCAPE support
74 - else if (myField.selectionStart || myField.selectionStart == '0') {
75 - var startPos = myField.selectionStart;
76 - var endPos = myField.selectionEnd;
77 - myField.value = myField.value.substring(0, startPos)
78 - + myValue
79 - + myField.value.substring(endPos, myField.value.length);
80 - } else {
81 - myField.value += myValue;
82 - }
83 -}
84 -
85 -function setupActions() {
86 - var checkboxen = getElementsByClassName( document, 'input', 'mw-abusefilter-action-checkbox' );
87 -
88 - for( var i=0; i<checkboxen.length; i++ ) {
89 - var checkbox = checkboxen[i];
90 -
91 - addHandler( checkbox, 'click', hideDeselectedActions );
92 - }
93 - // A second loop, so sue me.
94 - hideDeselectedActions();
95 -}
96 -
97 -function hideDeselectedActions() {
98 - var checkboxen = getElementsByClassName( document, 'input', 'mw-abusefilter-action-checkbox' );
99 -
100 - for( var i=0; i<checkboxen.length; i++ ) {
101 - // ID format is mw-abusefilter-action-checkbox-$action
102 - // We want substr(31)
103 - var checkbox = checkboxen[i];
104 - var action = checkbox.id.substr(31);
105 - var params = document.getElementById( "mw-abusefilter-"+action+"-parameters" );
106 -
107 - if ( params && checkbox.checked ) {
108 - params.style.display = 'block';
109 - } else if ( params ) {
110 - params.style.display = 'none';
111 - }
112 - }
113 -}
114 -
115 -function previewWarnMessage() {
116 - var message = document.getElementById( 'mw-abusefilter-warn-message-existing' ).value;
117 -
118 - if ( message == 'other' ) {
119 - message = document.getElementById( 'mw-abusefilter-warn-message-other' ).value;
120 - }
121 -
122 - var xmlHttp = sajax_init_object();
123 -
124 - xmlHttp.open( 'GET', wgScript + '?title=MediaWiki:' + encodeURIComponent( message ) + '&action=render', true );
125 -
126 - xmlHttp.onreadystatechange = function() {
127 - if ( xmlHttp.readyState != 4 )
128 - return;
129 -
130 - var responseText = xmlHttp.responseText;
131 -
132 - // Beware of raptors.
133 - document.getElementById( 'mw-abusefilter-warn-preview' ).innerHTML = responseText;
134 - };
135 -
136 - xmlHttp.send( null );
137 -}
138 -
139 -function editWarnMessage() {
140 - var message = document.getElementById( 'mw-abusefilter-warn-message-existing' ).value;
141 -
142 - if ( message == 'other' ) {
143 - message = document.getElementById( 'mw-abusefilter-warn-message-other' ).value;
144 - }
145 -
146 - window.location = wgScript + '?title=MediaWiki:'+encodeURIComponent( message )+'&action=edit';
147 -}
148 -
149 -function afShowExport() {
150 - document.getElementById( 'mw-abusefilter-export' ).style.display = 'block';
151 -}
152 -
153 -addOnloadHook( function() {
154 - addHandler( document.getElementById( wgFilterBoxName ), 'keyup', function() {
155 - el = document.getElementById( 'mw-abusefilter-syntaxresult' );
156 - if ( el.syntaxOk ) {
157 - el.style.display = 'none';
158 - }
159 - } );
160 -
161 - var loader = document.getElementById( 'mw-abusefilter-load' );
162 - if ( loader ) {
163 - addHandler( loader, 'click', fetchFilter );
164 - }
165 -
166 - var warnMsgPreview = document.getElementById( 'mw-abusefilter-warn-preview-button' );
167 - if ( warnMsgPreview ) {
168 - addHandler( warnMsgPreview, 'click', previewWarnMessage );
169 - }
170 -
171 - var warnMsgEdit = document.getElementById( 'mw-abusefilter-warn-edit-button' );
172 - if ( warnMsgEdit ) {
173 - addHandler( warnMsgEdit, 'click', editWarnMessage );
174 - }
175 -
176 - setupActions();
177 -
178 - var exporter = document.getElementById( 'mw-abusefilter-export' );
179 -
180 - if ( exporter ) {
181 - exporter.style.display = 'none';
182 - }
183 -} );
Index: trunk/extensions/AbuseFilter/special/SpecialAbuseLog.php
@@ -22,7 +22,7 @@
2323 }
2424
2525 public function execute( $parameter ) {
26 - global $wgUser, $wgOut, $wgRequest, $wgAbuseFilterStyleVersion;
 26+ global $wgUser, $wgOut, $wgRequest;
2727
2828 AbuseFilter::addNavigationLinks( $wgOut, $wgUser->getSkin(), 'log' );
2929
@@ -35,9 +35,7 @@
3636 $wgOut->setArticleRelated( false );
3737 $wgOut->enableClientCache( false );
3838
39 - global $wgScriptPath;
40 - $wgOut->addExtensionStyle( $wgScriptPath .
41 - "/extensions/AbuseFilter/abusefilter.css?$wgAbuseFilterStyleVersion" );
 39+ $wgOut->addModuleStyles( 'ext.abuseFilter' );
4240
4341 // Are we allowed?
4442 $errors = $this->getTitle()->getUserPermissionsErrors(
Index: trunk/extensions/AbuseFilter/special/SpecialAbuseFilter.php
@@ -11,10 +11,9 @@
1212 }
1313
1414 public function execute( $subpage ) {
15 - global $wgUser, $wgOut, $wgRequest, $wgAbuseFilterStyleVersion, $wgScriptPath;
 15+ global $wgUser, $wgOut, $wgRequest;
1616
17 - $wgOut->addExtensionStyle( "{$wgScriptPath}/extensions/AbuseFilter/abusefilter.css?" .
18 - $wgAbuseFilterStyleVersion );
 17+ $wgOut->addModuleStyles( 'ext.abuseFilter' );
1918 $view = 'AbuseFilterViewList';
2019
2120 $this->setHeaders();
Index: trunk/extensions/AbuseFilter/AbuseFilter.php
@@ -58,6 +58,14 @@
5959 $wgAPIListModules['abuselog'] = 'ApiQueryAbuseLog';
6060 $wgAutoloadClasses['ApiQueryAbuseFilters'] = "$dir/api/ApiQueryAbuseFilters.php";
6161 $wgAPIListModules['abusefilters'] = 'ApiQueryAbuseFilters';
 62+$wgAutoloadClasses['ApiCheckFilterSyntax'] = "$dir/api/ApiCheckFilterSyntax.php";
 63+$wgAPIModules['checkfiltersyntax'] = 'ApiCheckFilterSyntax';
 64+$wgAutoloadClasses['ApiEvalFilterExpression'] = "$dir/api/ApiEvalFilterExpression.php";
 65+$wgAPIModules['evalfilterexpression'] = 'ApiEvalFilterExpression';
 66+$wgAutoloadClasses['ApiUnblockAutopromote'] = "$dir/api/ApiUnblockAutopromote.php";
 67+$wgAPIModules['unblockautopromote'] = 'ApiUnblockAutopromote';
 68+$wgAutoloadClasses['ApiCheckFilterMatch'] = "$dir/api/ApiCheckFilterMatch.php";
 69+$wgAPIModules['checkfiltermatch'] = 'ApiCheckFilterMatch';
6270
6371 $wgHooks['EditFilterMerged'][] = 'AbuseFilterHooks::onEditFilterMerged';
6472 $wgHooks['GetAutoPromoteGroups'][] = 'AbuseFilterHooks::onGetAutoPromoteGroups';
@@ -69,6 +77,7 @@
7078 $wgHooks['LoadExtensionSchemaUpdates'][] = 'AbuseFilterHooks::onLoadExtensionSchemaUpdates';
7179 $wgHooks['ContributionsToolLinks'][] = 'AbuseFilterHooks::onContributionsToolLinks';
7280 $wgHooks['UploadVerification'][] = 'AbuseFilterHooks::onUploadVerification';
 81+$wgHooks['MakeGlobalVariablesScript'][] = 'AbuseFilterHooks::onMakeGlobalVariablesScript';
7382
7483 $wgAvailableRights[] = 'abusefilter-modify';
7584 $wgAvailableRights[] = 'abusefilter-log-detail';
@@ -88,6 +97,49 @@
8998 $wgLogActions['suppress/hide-afl'] = 'abusefilter-logentry-suppress';
9099 $wgLogActions['suppress/unhide-afl'] = 'abusefilter-logentry-unsuppress';
91100
 101+$commonModuleInfo = array(
 102+ 'localBasePath' => dirname( __FILE__ ) . '/modules',
 103+ 'remoteExtPath' => 'AbuseFilter/modules',
 104+);
 105+
 106+$wgResourceModules['ext.abuseFilter'] = array(
 107+ 'styles' => 'ext.abuseFilter.css',
 108+) + $commonModuleInfo;
 109+
 110+$wgResourceModules['ext.abuseFilter.edit'] = array(
 111+ 'scripts' => 'ext.abuseFilter.edit.js',
 112+ 'messages' => array(
 113+ 'abusefilter-edit-syntaxok',
 114+ 'abusefilter-edit-syntaxerr'
 115+ ),
 116+ 'dependencies' => array(
 117+ 'jquery.textSelection',
 118+ 'jquery.spinner',
 119+ ),
 120+) + $commonModuleInfo;
 121+
 122+$wgResourceModules['ext.abuseFilter.tools'] = array(
 123+ 'scripts' => 'ext.abuseFilter.tools.js',
 124+ 'messages' => array(
 125+ 'abusefilter-reautoconfirm-notallowed',
 126+ 'abusefilter-reautoconfirm-none',
 127+ 'abusefilter-reautoconfirm-done',
 128+ ),
 129+ 'dependencies' => array(
 130+ 'jquery.spinner'
 131+ ),
 132+) + $commonModuleInfo;
 133+
 134+$wgResourceModules['ext.abuseFilter.examine'] = array(
 135+ 'scripts' => 'ext.abuseFilter.examine.js',
 136+ 'messages' => array(
 137+ 'abusefilter-examine-match',
 138+ 'abusefilter-examine-nomatch',
 139+ 'abusefilter-examine-syntaxerror',
 140+ 'abusefilter-examine-notfound',
 141+ ),
 142+) + $commonModuleInfo;
 143+
92144 $wgAbuseFilterAvailableActions = array( 'flag', 'throttle', 'warn', 'disallow', 'blockautopromote', 'block', 'degroup', 'tag' );
93145
94146 $wgAbuseFilterConditionLimit = 1000;
@@ -106,9 +158,6 @@
107159 $wgAjaxExportList[] = 'AbuseFilter::ajaxGetFilter';
108160 $wgAjaxExportList[] = 'AbuseFilter::ajaxCheckFilterWithVars';
109161
110 -// Bump the version number every time you change any of the .css/.js files
111 -$wgAbuseFilterStyleVersion = 9;
112 -
113162 $wgAbuseFilterRestrictedActions = array( 'block', 'degroup' );
114163
115164 // UDP configuration
Index: trunk/extensions/AbuseFilter/Views/examine.js
@@ -1,31 +0,0 @@
2 -/** Scripts for Examiner */
3 -
4 -function examinerCheckFilter() {
5 - var filter = document.getElementById( 'wpTestFilter' ).value;
6 -
7 - // The vars are too much for a GET.
8 - sajax_request_type = 'POST';
9 -
10 - sajax_do_call( 'AbuseFilter::ajaxCheckFilterWithVars', [filter, wgExamineVars], function( request ) {
11 - var response = request.responseText;
12 - var el = document.getElementById( 'mw-abusefilter-syntaxresult' );
13 -
14 - el.style.display = 'block';
15 -
16 - if ( response == 'MATCH' ) {
17 - changeText( el, wgMessageMatch );
18 - el.className = 'mw-abusefilter-examine-match';
19 - } else if ( response == 'NOMATCH' ) {
20 - changeText( el, wgMessageNomatch );
21 - el.className = 'mw-abusefilter-examine-nomatch';
22 - } else if ( response == 'SYNTAXERROR' ) {
23 - el.className = 'mw-abusefilter-examine-syntaxerror';
24 - changeText( el, wgMessageError );
25 - }
26 - } );
27 -}
28 -
29 -addOnloadHook( function() {
30 - var el = document.getElementById( 'mw-abusefilter-examine-test' );
31 - addHandler( el, 'click', examinerCheckFilter );
32 -} );
\ No newline at end of file
Index: trunk/extensions/AbuseFilter/Views/tools.js
@@ -1,30 +0,0 @@
2 -function doExprSubmit() {
3 - var expr = document.getElementById('wpTestExpr').value;
4 - injectSpinner( document.getElementById( 'mw-abusefilter-submitexpr' ), 'abusefilter-expr' );
5 - sajax_do_call( 'AbuseFilter::ajaxEvaluateExpression', [expr], processExprResult );
6 -}
7 -
8 -function processExprResult( request ) {
9 - var response = request.responseText;
10 -
11 - removeSpinner( 'abusefilter-expr' );
12 -
13 - var el = document.getElementById( 'mw-abusefilter-expr-result' );
14 - el.innerHTML = response;
15 -}
16 -
17 -function doReautoSubmit() {
18 - var name = document.getElementById('reautoconfirm-user').value;
19 - injectSpinner( document.getElementById( 'mw-abusefilter-reautoconfirmsubmit' ), 'abusefilter-reautoconfirm' );
20 - sajax_do_call( 'AbuseFilter::ajaxReAutoconfirm', [name], processReautoconfirm );
21 -}
22 -
23 -function processReautoconfirm( request ) {
24 - var response = request.responseText;
25 -
26 - if ( response && response.length ) {
27 - jsMsg( response );
28 - }
29 -
30 - removeSpinner( 'abusefilter-reautoconfirm' );
31 -}
Index: trunk/extensions/AbuseFilter/Views/AbuseFilterViewTools.php
@@ -20,7 +20,6 @@
2121 array(
2222 'type' => 'button',
2323 'id' => 'mw-abusefilter-submitexpr',
24 - 'onclick' => 'doExprSubmit();',
2524 'value' => wfMsg( 'abusefilter-tools-submitexpr' ) )
2625 )
2726 );
@@ -29,13 +28,8 @@
3029 $eval = Xml::fieldset( wfMsg( 'abusefilter-tools-expr' ), $eval );
3130 $wgOut->addHTML( $eval );
3231
33 - // Associated script
34 - $exprScript = file_get_contents( dirname( __FILE__ ) . '/tools.js' );
 32+ $wgOut->addModules( 'ext.abuseFilter.tools' );
3533
36 - $wgOut->addInlineScript( $exprScript );
37 -
38 - global $wgUser;
39 -
4034 if ( $wgUser->isAllowed( 'abusefilter-modify' ) ) {
4135 // Hacky little box to re-enable autoconfirmed if it got disabled
4236 $rac = '';
@@ -51,7 +45,6 @@
5246 array(
5347 'type' => 'button',
5448 'id' => 'mw-abusefilter-reautoconfirmsubmit',
55 - 'onclick' => 'doReautoSubmit();',
5649 'value' => wfMsg( 'abusefilter-tools-reautoconfirm-submit' )
5750 )
5851 );
Index: trunk/extensions/AbuseFilter/Views/AbuseFilterViewEdit.php
@@ -417,7 +417,7 @@
418418
419419 // Add export
420420 $exportText = json_encode( array( 'row' => $row, 'actions' => $actions ) );
421 - $tools .= Xml::tags( 'a', array( 'href' => 'javascript:afShowExport();' ),
 421+ $tools .= Xml::tags( 'a', array( 'href' => '#', 'id' => 'mw-abusefilter-export-link' ),
422422 wfMsgExt( 'abusefilter-edit-export', 'parseinline' ) );
423423 $tools .= Xml::element( 'textarea',
424424 array( 'readonly' => 'readonly', 'id' => 'mw-abusefilter-export' ),
Index: trunk/extensions/AbuseFilter/Views/AbuseFilterViewExamine.php
@@ -4,6 +4,9 @@
55 }
66
77 class AbuseFilterViewExamine extends AbuseFilterView {
 8+ public static $examineType = null;
 9+ public static $examineId = null;
 10+
811 function show() {
912 global $wgOut;
1013
@@ -89,6 +92,9 @@
9093 return;
9194 }
9295
 96+ self::$examineType = 'rc';
 97+ self::$examineId = $rcid;
 98+
9399 $vars = AbuseFilter::getVarsFromRCRow( $row );
94100
95101 $this->showExaminer( $vars );
@@ -106,6 +112,9 @@
107113 return;
108114 }
109115
 116+ self::$examineType = 'log';
 117+ self::$examineId = $logid;
 118+
110119 $vars = AbuseFilter::loadVarDump( $row->afl_var_dump );
111120
112121 $this->showExaminer( $vars );
@@ -125,22 +134,8 @@
126135
127136 $output = '';
128137
129 - // Send armoured as JSON -- I totally give up on trying to send it as a proper object.
130 - $wgOut->addInlineScript( 'var wgExamineVars = ' .
131 - Xml::encodeJsVar( json_encode( $vars ) ) . ';' );
132 - $wgOut->addInlineScript( file_get_contents( dirname( __FILE__ ) . '/examine.js' ) );
 138+ $wgOut->addModules( 'ext.abuseFilter.examine' );
133139
134 - // Add messages
135 - $msg = array();
136 - $msg['match'] = wfMsg( 'abusefilter-examine-match' );
137 - $msg['nomatch'] = wfMsg( 'abusefilter-examine-nomatch' );
138 - $msg['syntaxerror'] = wfMsg( 'abusefilter-examine-syntaxerror' );
139 - $wgOut->addInlineScript(
140 - 'var wgMessageMatch = ' . Xml::encodeJsVar( $msg['match'] ) . ";\n" .
141 - 'var wgMessageNomatch = ' . Xml::encodeJsVar( $msg['nomatch'] ) . ";\n" .
142 - 'var wgMessageError = ' . Xml::encodeJsVar( $msg['syntaxerror'] ) . ";\n"
143 - );
144 -
145140 // Add test bit
146141 if ( $wgUser->isAllowed( 'abusefilter-modify' ) ) {
147142 $tester = Xml::tags( 'h2', null, wfMsgExt( 'abusefilter-examine-test', 'parseinline' ) );
Index: trunk/extensions/AbuseFilter/AbuseFilter.class.php
@@ -117,6 +117,7 @@
118118 'file_sha1' => 'file-sha1',
119119 ),
120120 );
 121+ public static $editboxName = null;
121122
122123 public static function addNavigationLinks( $out, $sk, $pageType ) {
123124 global $wgLang, $wgUser;
@@ -204,44 +205,6 @@
205206 return $realValues;
206207 }
207208
208 - public static function ajaxCheckSyntax( $filter ) {
209 - global $wgUser;
210 - if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
211 - return false;
212 - }
213 -
214 - $result = self::checkSyntax( $filter );
215 -
216 - $ok = ( $result === true );
217 -
218 - if ( $ok ) {
219 - return 'OK';
220 - } else {
221 - return 'ERR: ' . json_encode( $result );
222 - }
223 - }
224 -
225 - public static function ajaxGetFilter( $filter ) {
226 - global $wgUser;
227 - if ( !$wgUser->isAllowed( 'abusefilter-view' ) ) {
228 - return false;
229 - }
230 -
231 - $dbr = wfGetDB( DB_SLAVE );
232 - $row = $dbr->selectRow(
233 - 'abuse_filter',
234 - '*',
235 - array( 'af_id' => $filter ),
236 - __METHOD__
237 - );
238 -
239 - if ( $row->af_hidden && !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
240 - return false;
241 - }
242 -
243 - return strval( $row->af_pattern );
244 - }
245 -
246209 public static function filterHidden( $filter ) {
247210 $dbr = wfGetDB( DB_SLAVE );
248211 $hidden = $dbr->selectField(
@@ -253,25 +216,6 @@
254217 return $hidden ? true : false;
255218 }
256219
257 - public static function ajaxCheckFilterWithVars( $filter, $vars ) {
258 - global $wgUser;
259 -
260 - // Anti-DoS
261 - if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
262 - return false;
263 - }
264 -
265 - // If we have a syntax error.
266 - if ( self::checkSyntax( $filter ) !== true ) {
267 - return 'SYNTAXERROR';
268 - }
269 -
270 - $vars = json_decode( $vars, true );
271 - $result = self::checkConditions( $filter, $vars );
272 -
273 - return $result ? 'MATCH' : 'NOMATCH';
274 - }
275 -
276220 public static function triggerLimiter( $val = 1 ) {
277221 self::$condCount += $val;
278222
@@ -348,36 +292,6 @@
349293 return $parser->evaluateExpression( $expr );
350294 }
351295
352 - public static function ajaxReAutoconfirm( $username ) {
353 - global $wgUser;
354 -
355 - if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
356 - // Don't allow it.
357 - return wfMsg( 'abusefilter-reautoconfirm-notallowed' );
358 - }
359 -
360 - $u = User::newFromName( $username );
361 -
362 - global $wgMemc;
363 - $k = AbuseFilter::autoPromoteBlockKey( $u );
364 -
365 - if ( !$wgMemc->get( $k ) ) {
366 - return wfMsgExt( 'abusefilter-reautoconfirm-none', array( 'parsemag' ), $username );
367 - }
368 -
369 - $wgMemc->delete( $k );
370 -
371 - return wfMsgExt( 'abusefilter-reautoconfirm-done', array( 'parsemag' ), $username );
372 - }
373 -
374 - public static function ajaxEvaluateExpression( $expr ) {
375 - global $wgUser;
376 - if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
377 - return false;
378 - }
379 - return htmlspecialchars( self::evaluateExpression( $expr ) );
380 - }
381 -
382296 public static function checkConditions( $conds, $vars, $ignoreError = true,
383297 $keepVars = 'resetvars' ) {
384298 global $wgAbuseFilterParserClass;
@@ -1402,7 +1316,7 @@
14031317 $rules .=
14041318 Xml::tags(
14051319 'select',
1406 - array( 'id' => 'wpFilterBuilder', 'onchange' => 'addText();' ),
 1320+ array( 'id' => 'wpFilterBuilder', ),
14071321 $builder
14081322 ) . ' ';
14091323
@@ -1410,7 +1324,6 @@
14111325 $rules .= Xml::element( 'input',
14121326 array(
14131327 'type' => 'button',
1414 - 'onclick' => 'doSyntaxCheck()',
14151328 'value' => wfMsg( 'abusefilter-edit-check' ),
14161329 'id' => 'mw-abusefilter-syntaxcheck'
14171330 ) + $noTestAttrib );
@@ -1421,19 +1334,9 @@
14221335 '&#160;' );
14231336
14241337 // Add script
1425 - $editScript = file_get_contents( dirname( __FILE__ ) . '/edit.js' );
1426 - $editScript = "var wgFilterBoxName = " . Xml::encodeJSVar( $textName ) . ";\n$editScript";
 1338+ $wgOut->addModules( 'ext.abuseFilter.edit' );
 1339+ self::$editboxName = $textName;
14271340
1428 - // Import localisation.
1429 - $importMessages = array( 'abusefilter-edit-syntaxok', 'abusefilter-edit-syntaxerr' );
1430 - $msgData = array();
1431 - foreach ( $importMessages as $msg ) {
1432 - $msgData[$msg] = wfMsg( $msg );
1433 - }
1434 - $editScript .= "\nvar wgAbuseFilterMessages = " . json_encode( $msgData ) . ";\n";
1435 -
1436 - $wgOut->addInlineScript( $editScript );
1437 -
14381341 return $rules;
14391342 }
14401343
Index: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.edit.js
@@ -0,0 +1,227 @@
 2+/**
 3+ * AbuseFilter editing stuff
 4+ */
 5+new ( function( $, mw ) {
 6+ /**
 7+ * Filter textarea
 8+ *
 9+ * @var {jQuery}
 10+ */
 11+ var $filterBox = $( '#' + mw.config.get( 'wgFilterBoxName' ) );
 12+
 13+ /**
 14+ * Reference to this
 15+ *
 16+ * @var {this}
 17+ */
 18+ var that = this;
 19+
 20+ /**
 21+ * Returns the currently selected warning message
 22+ *
 23+ * @returns {String} current warning message
 24+ */
 25+ var getCurrentWarningMessage = function() {
 26+ var message = $('#mw-abusefilter-warn-message-existing').val();
 27+
 28+ if ( message == 'other' ) {
 29+ message = $('#mw-abusefilter-warn-message-other').val();
 30+ }
 31+
 32+ return message;
 33+ };
 34+
 35+ /**
 36+ * Sends the current filter text to be checked for syntax issues
 37+ */
 38+ this.doSyntaxCheck = function() {
 39+ var filter = $filterBox.val();
 40+ $( this ).injectSpinner( 'abusefilter-syntaxcheck' );
 41+ this.disabled = true;
 42+ $.getJSON(
 43+ mw.util.wikiScript( 'api' ), {
 44+ action: 'checkfiltersyntax',
 45+ filter: filter,
 46+ format: 'json'
 47+ }, that.processSyntaxResult
 48+ );
 49+ };
 50+
 51+ /**
 52+ * Takes the data retrieved in doSyntaxCheck and processes it
 53+ *
 54+ * @param {Object} data Data returned from the AJAX request
 55+ */
 56+ this.processSyntaxResult = function( data ) {
 57+ data = data.checkfiltersyntax;
 58+ $.removeSpinner( 'abusefilter-syntaxcheck' );
 59+ $( '#mw-abusefilter-syntaxcheck' ).removeAttr("disabled");
 60+
 61+ var $el = $( '#mw-abusefilter-syntaxresult' )
 62+ .show()
 63+ .removeClass('mw-abusefilter-syntaxresult-ok mw-abusefilter-syntaxresult-error');
 64+
 65+ if ( data.status == 'ok' ) {
 66+ // Successful
 67+ $el.text( mw.msg( 'abusefilter-edit-syntaxok' ) )
 68+ .attr( 'class', 'mw-abusefilter-syntaxresult-ok' )
 69+ .data( 'syntaxOk', true );
 70+ } else {
 71+ var msg = mw.message( 'abusefilter-edit-syntaxerr', data.message ).toString();
 72+ $el.text( msg )
 73+ .attr( 'class', 'mw-abusefilter-syntaxresult-error' )
 74+ .data( 'syntaxOk', false );
 75+
 76+ $filterBox
 77+ .focus()
 78+ .textSelection( 'setSelection', { start: data.character } );
 79+ }
 80+ };
 81+
 82+ /**
 83+ * Adds text to the filter textarea
 84+ *
 85+ * Fired by a change event rom the #wpFilterBuilder dropdown
 86+ */
 87+ this.addText = function() {
 88+ var $filterBuilder = $( '#wpFilterBuilder' );
 89+ if ( $filterBuilder.prop( 'selectedIndex' ) == 0 ) {
 90+ return;
 91+ }
 92+
 93+ $filterBox.insertAtCaret( $filterBuilder.val() + " " );
 94+ $filterBuilder.prop( 'selectedIndex', 0 );
 95+ };
 96+
 97+ /**
 98+ * Fetches a filter from the API and inserts it into the filter box
 99+ */
 100+ this.fetchFilter = function() {
 101+ var filterId = $( '#mw-abusefilter-load-filter' ).val();
 102+
 103+ if ( filterId == '' ) {
 104+ return;
 105+ }
 106+
 107+ $( this ).injectSpinner( 'fetch-spinner' );
 108+ $.getJSON(
 109+ mw.util.wikiScript( 'api' ), {
 110+ action: 'query',
 111+ format: 'json',
 112+ list: 'abusefilters',
 113+ abfprop: 'pattern',
 114+ abfstartid: filterId,
 115+ abfendid: filterId,
 116+ abflimit: 1
 117+ }, function ( data ) {
 118+ $.removeSpinner( 'fetch-spinner' );
 119+ $filterBox.text( data.query.abusefilters[0].pattern );
 120+ }
 121+ );
 122+ };
 123+
 124+ /**
 125+ * Cycles through all action checkboxes and hides parameter divs
 126+ * that don't have checked boxes
 127+ */
 128+ this.hideDeselectedActions = function() {
 129+ $( 'input.mw-abusefilter-action-checkbox' ).each( function() {
 130+ var action = this.id.substr( 31 );
 131+ var $params = $( '#mw-abusefilter-' + action + '-parameters' );
 132+
 133+ if ( $params.length ) {
 134+ if ( this.checked ) {
 135+ $params.show();
 136+ } else {
 137+ $params.hide();
 138+ }
 139+ }
 140+ } );
 141+ };
 142+
 143+ /**
 144+ * Fetches the warning message selected for previewing
 145+ */
 146+ this.previewWarnMessage = function() {
 147+ var message = getCurrentWarningMessage();
 148+
 149+ $.get( mw.config.get('wgScript'), {
 150+ title: 'MediaWiki:' + message,
 151+ action: 'render'
 152+ }, function( data ) {
 153+ $( '#mw-abusefilter-warn-preview' ).html( data )
 154+ } );
 155+ };
 156+
 157+ /**
 158+ * Redirects browser to the warning message for editing
 159+ */
 160+ this.editWarnMessage = function() {
 161+ var message = getCurrentWarningMessage();
 162+
 163+ window.location = mw.config.get( 'wgScript' ) + '?title=MediaWiki:' + mw.util.wikiUrlencode( message ) + '&action=edit';
 164+ };
 165+
 166+ // From http://stackoverflow.com/questions/946534/insert-text-into-textarea-with-jquery/2819568#2819568
 167+ $.fn.extend({
 168+ /**
 169+ * Inserts a string in a textarea at the current caret position
 170+ *
 171+ * @param {String} myValue String to insert
 172+ * @returns {jQuery}
 173+ */
 174+ insertAtCaret: function(myValue){
 175+ return this.each( function() {
 176+ if ( document.selection ) {
 177+ this.focus();
 178+ sel = document.selection.createRange();
 179+ sel.text = myValue;
 180+ this.focus();
 181+ } else if ( this.selectionStart || this.selectionStart == '0' ) {
 182+ var startPos = this.selectionStart;
 183+ var endPos = this.selectionEnd;
 184+ var scrollTop = this.scrollTop;
 185+ this.value = this.value.substring( 0, startPos )
 186+ + myValue
 187+ + this.value.substring( endPos, this.value.length );
 188+ this.focus();
 189+ this.selectionStart = startPos + myValue.length;
 190+ this.selectionEnd = startPos + myValue.length;
 191+ this.scrollTop = scrollTop;
 192+ } else {
 193+ this.value += myValue;
 194+ this.focus();
 195+ }
 196+ } );
 197+ }
 198+ });
 199+
 200+ /*
 201+ * On ready initialization
 202+ */
 203+ $( function( $ ) {
 204+ // Hide the syntax ok message when the text changes
 205+ $filterBox.keyup( function() {
 206+ var $el = $( '#mw-abusefilter-syntaxresult' );
 207+ if ( $el.data( 'syntaxOk' ) ) {
 208+ $el.hide();
 209+ }
 210+ } );
 211+
 212+ $( '#mw-abusefilter-load' ).click( that.fetchFilter );
 213+ $( '#mw-abusefilter-warn-preview-button' ).click( that.previewWarnMessage );
 214+ $( '#mw-abusefilter-warn-edit-button' ).click( that.editWarnMessage );
 215+ $( 'input.mw-abusefilter-action-checkbox' ).click( that.hideDeselectedActions );
 216+ that.hideDeselectedActions();
 217+
 218+ $( '#mw-abusefilter-syntaxcheck' ).click( that.doSyntaxCheck );
 219+ $( '#wpFilterBuilder' ).change( that.addText );
 220+
 221+ var $exportBox = $( '#mw-abusefilter-export' );
 222+ $( '#mw-abusefilter-export-link' ).toggle( function() {
 223+ $exportBox.show()
 224+ }, function() {
 225+ $exportBox.hide();
 226+ } );
 227+ } );
 228+})( jQuery, mediaWiki );
Property changes on: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.edit.js
___________________________________________________________________
Added: svn:eol-style
1229 + native
Index: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.examine.js
@@ -0,0 +1,88 @@
 2+/**
 3+ * Filter checking for examine
 4+ */
 5+new ( function( $, mw ) {
 6+ /**
 7+ * Reference to this
 8+ */
 9+ var that = this;
 10+
 11+ /**
 12+ * Syntax result div
 13+ *
 14+ * @type {jQuery}
 15+ */
 16+ var $syntaxResult = $( '#mw-abusefilter-syntaxresult' );
 17+
 18+ /**
 19+ * Tests the filter against an rc event or abuse log entry
 20+ */
 21+ this.examinerTestFilter = function() {
 22+ var filter = $( '#wpTestFilter' ).val(),
 23+ params = {};
 24+ $( this ).injectSpinner( 'filter-check' );
 25+
 26+ if ( mw.config.get( 'wgExamineType' ) == 'rc' ) {
 27+ params = {
 28+ rcid: mw.config.get( 'wgExamineId' )
 29+ }
 30+ } else {
 31+ params = {
 32+ logid: mw.config.get( 'wgExamineId' )
 33+ }
 34+ }
 35+
 36+ // Large amount of data
 37+ $.post(
 38+ mw.util.wikiScript( 'api' ), $.extend( params, {
 39+ action: 'checkfiltermatch',
 40+ filter: filter,
 41+ format: 'json'
 42+ } ), that.examinerTestProcess, 'json'
 43+ );
 44+ };
 45+
 46+ /**
 47+ * Processes the results of the filter test
 48+ *
 49+ * @param {Object} data
 50+ */
 51+ this.examinerTestProcess = function( data ) {
 52+ var msg;
 53+ $.removeSpinner( 'filter-check' );
 54+
 55+ if ( data.error !== undefined ) {
 56+ // Hmm, something went awry
 57+ if ( data.error.code == 'badsyntax' ) {
 58+ $syntaxResult.attr(
 59+ 'class', 'mw-abusefilter-examine-syntaxerror'
 60+ );
 61+ msg = 'abusefilter-examine-syntaxerror';
 62+ } else if ( data.error.code == 'nosuchrcid'
 63+ || data.error.code == 'nosuchlogid'
 64+ ) {
 65+ msg = 'abusefilter-examine-notfound';
 66+ } else if ( data.error.code == 'nopermission' ) {
 67+ return;
 68+ }
 69+ } else {
 70+ var exClass;
 71+ if ( data.checkfiltermatch.result ) {
 72+ exClass = 'mw-abusefilter-examine-match';
 73+ msg = 'abusefilter-examine-match';
 74+ } else {
 75+ exClass = 'mw-abusefilter-examine-nomatch';
 76+ msg = 'abusefilter-examine-nomatch';
 77+ }
 78+ $syntaxResult.attr( 'class', exClass );
 79+ }
 80+
 81+ $syntaxResult
 82+ .text( mw.msg( msg ) )
 83+ .show();
 84+ };
 85+
 86+ $( function( $ ) {
 87+ $( '#mw-abusefilter-examine-test' ).click( that.examinerTestFilter );
 88+ } );
 89+} )( jQuery, mediaWiki );
\ No newline at end of file
Property changes on: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.examine.js
___________________________________________________________________
Added: svn:eol-style
190 + native
Index: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.css
@@ -0,0 +1,132 @@
 2+/* This code was stolen shamelessly from enwikipedia's Common.css */
 3+table.mw-abuselog-details {
 4+ margin: 1em 1em 1em 0;
 5+ background: #f9f9f9;
 6+ border: 1px #aaa solid;
 7+ border-collapse: collapse;
 8+ width: 80%;
 9+}
 10+
 11+table.mw-abuselog-details th, table.mw-abuselog-details td {
 12+ border: 1px #aaa solid;
 13+ padding: 0.2em;
 14+}
 15+
 16+table.mw-abuselog-details th {
 17+ background: #f2f2f2;
 18+ text-align: center;
 19+}
 20+
 21+table.mw-abuselog-details caption {
 22+ font-weight: bold;
 23+}
 24+
 25+.mw-abusefilter-history-changed {
 26+ background: #ffe0e0;
 27+ font-weight: bold;
 28+}
 29+
 30+.mw-abuselog-var-value {
 31+ white-space: pre-wrap;
 32+ font-family: monospace;
 33+}
 34+
 35+div.mw-abuselog-var-value {
 36+ max-height: 10em;
 37+ max-width: 100%;
 38+ overflow: auto;
 39+}
 40+
 41+td.mw-abuselog-var {
 42+ width: 30%;
 43+}
 44+
 45+tr.mw-abusefilter-list-disabled, tr.mw-abusefilter-list-disabled td {
 46+ color: #666666;
 47+}
 48+
 49+tr.mw-abusefilter-list-deleted, tr.mw-abusefilter-list-deleted td {
 50+ color: #aaaaaa;
 51+}
 52+
 53+.mw-abusefilter-examine-match,
 54+.mw-abusefilter-syntaxresult-ok,
 55+li.mw-abusefilter-changeslist-match {
 56+ background-image: url(yes_check.png);
 57+}
 58+
 59+.mw-abusefilter-examine-nomatch,
 60+.mw-abusefilter-examine-syntaxerror,
 61+.mw-abusefilter-syntaxresult-error,
 62+li.mw-abusefilter-changeslist-nomatch {
 63+ background-image: url(red_x.png);
 64+}
 65+
 66+#mw-abusefilter-syntaxresult,
 67+li.mw-abusefilter-changeslist-nomatch,
 68+li.mw-abusefilter-changeslist-match {
 69+ background: no-repeat left center;
 70+ padding-left: 25px;
 71+}
 72+
 73+table.mw-abusefilter-diff {
 74+ width: 80%;
 75+ border-collapse: collapse;
 76+}
 77+
 78+table.mw-abusefilter-diff td,
 79+table.mw-abusefilter-diff th {
 80+ border: 1px solid #888888;
 81+}
 82+
 83+.mw-abusefilter-diff-added,
 84+.mw-abusefilter-diff-multiline .diff-addedline {
 85+ background: #cfc;
 86+}
 87+
 88+.mw-abusefilter-diff-removed,
 89+.mw-abusefilter-diff-multiline .diff-deletedline {
 90+ background: #ffa;
 91+}
 92+
 93+.mw-abusefilter-diff-context,
 94+.mw-abusefilter-diff-multiline .diff-context {
 95+ background: #eee;
 96+}
 97+
 98+.mw-abusefilter-diff-multiline {
 99+ width: 100%;
 100+}
 101+
 102+.mw-abusefilter-diff-multiline td {
 103+ border: none !important;
 104+}
 105+
 106+.mw-abusefilter-diff-multiline .diff-marker {
 107+ font-size: 0.8em;
 108+}
 109+
 110+.mw-abusefilter-diff-multiline td.diff-addedline,
 111+.mw-abusefilter-diff-multiline td.diff-deletedline {
 112+ width: 50%;
 113+}
 114+
 115+/* Rules are in English */
 116+/* @noflip */textarea#wpFilterRules { direction: ltr; }
 117+
 118+/* Name is in site content language */
 119+/* @noflip */.sitedir-ltr .TablePager_col_af_public_comments {
 120+ direction: ltr;
 121+}
 122+/* @noflip */.sitedir-rtl .TablePager_col_af_public_comments {
 123+ direction: rtl;
 124+}
 125+
 126+#mw-abusefilter-filter-tools {
 127+ display: inline;
 128+}
 129+
 130+.client-nojs #mw-abusefilter-export-link,
 131+.client-js #mw-abusefilter-export {
 132+ display: none;
 133+}
\ No newline at end of file
Property changes on: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.css
___________________________________________________________________
Added: svn:eol-style
1134 + native
Index: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.tools.js
@@ -0,0 +1,89 @@
 2+/**
 3+ * AbuseFilter tools JS
 4+ */
 5+new ( function( $, mw ) {
 6+ /**
 7+ * Reference to this
 8+ */
 9+ var that = this;
 10+
 11+ /**
 12+ * Submits the expression to be evaluated
 13+ */
 14+ this.doExprSubmit = function() {
 15+ var expr = $( '#wpTestExpr' ).val();
 16+ $( this ).injectSpinner( 'abusefilter-expr' );
 17+ $.getJSON(
 18+ mw.util.wikiScript( 'api' ), {
 19+ action: 'evalfilterexpression',
 20+ expression: expr,
 21+ format: 'json'
 22+ }, that.processExprResult
 23+ );
 24+ };
 25+
 26+ /**
 27+ * Processes the result of the evaluation
 28+ *
 29+ * @param {Object} data
 30+ */
 31+ this.processExprResult = function( data ) {
 32+ $.removeSpinner( 'abusefilter-expr' );
 33+
 34+ $( '#mw-abusefilter-expr-result' )
 35+ .html( mw.html.escape( data.evalfilterexpression.result ) );
 36+ };
 37+
 38+ /**
 39+ * Submits a call to unblock autopromotions for a user
 40+ */
 41+ this.doReautoSubmit = function() {
 42+ var name = $( '#reautoconfirm-user' ).val();
 43+
 44+ if ( name == '' ) {
 45+ return;
 46+ }
 47+
 48+ $( this ).injectSpinner( 'abusefilter-reautoconfirm' );
 49+ $.post(
 50+ mw.util.wikiScript( 'api' ), {
 51+ action: 'unblockautopromote',
 52+ user: name,
 53+ token: mw.user.tokens.get( 'editToken' ),
 54+ format: 'json'
 55+ }, that.processReautoconfirm, 'json'
 56+ );
 57+ };
 58+
 59+ /**
 60+ * Processes the result of the unblocking autopromotions for a user
 61+ *
 62+ * @param {Object} data
 63+ */
 64+ this.processReautoconfirm = function( data ) {
 65+ var msg;
 66+
 67+ if ( data.error !== undefined ) {
 68+ switch ( data.error.code ) {
 69+ case 'permissiondenied':
 70+ msg = mw.msg( 'abusefilter-reautoconfirm-notallowed' );
 71+ break;
 72+ case 'notsuspended':
 73+ msg = data.error.info;
 74+ break;
 75+ }
 76+ } else {
 77+ msg = mw.message( 'abusefilter-reautoconfirm-done', data.unblockautopromote.user ).toString();
 78+ }
 79+
 80+ mw.util.jsMessage( msg );
 81+
 82+ $.removeSpinner( 'abusefilter-reautoconfirm' );
 83+ };
 84+
 85+ $( function( $ ) {
 86+ $( '#mw-abusefilter-submitexpr' ).click( that.doExprSubmit );
 87+ $( '#mw-abusefilter-reautoconfirmsubmit' ).click( that.doReautoSubmit );
 88+ } );
 89+
 90+})( jQuery, mediaWiki );
\ No newline at end of file
Property changes on: trunk/extensions/AbuseFilter/modules/ext.abuseFilter.tools.js
___________________________________________________________________
Added: svn:eol-style
191 + native
Index: trunk/extensions/AbuseFilter/api/ApiCheckFilterMatch.php
@@ -0,0 +1,106 @@
 2+<?php
 3+
 4+class ApiCheckFilterMatch extends ApiBase {
 5+ public function execute() {
 6+ global $wgUser;
 7+ $params = $this->extractRequestParams();
 8+ $this->requireOnlyOneParameter( $params, 'vars', 'rcid', 'logid' );
 9+
 10+ // "Anti-DoS"
 11+ if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
 12+ $this->dieUsageMsg( 'permissiondenied' );
 13+ }
 14+
 15+ if ( $params['vars'] ) {
 16+ $vars = json_decode( $params['vars'], true );
 17+ } elseif ( $params['rcid'] ) {
 18+ $dbr = wfGetDB( DB_SLAVE );
 19+ $row = $dbr->selectRow( 'recentchanges', '*',
 20+ array( 'rc_id' => $params['rcid'] ), __METHOD__
 21+ );
 22+
 23+ if ( !$row ) {
 24+ $this->dieUsageMsg( array( 'nosuchrcid', $params['rcid'] ) );
 25+ }
 26+
 27+ $vars = AbuseFilter::getVarsFromRCRow( $row );
 28+ } elseif ( $params['logid'] ) {
 29+ $dbr = wfGetDB( DB_SLAVE );
 30+ $row = $dbr->selectRow( 'abuse_filter_log', '*',
 31+ array( 'afl_id' => $params['logid'] ), __METHOD__
 32+ );
 33+
 34+ if ( !$row ) {
 35+ $this->dieUsage(
 36+ "There is no abuselog entry with the id ``{$params['logid']}''",
 37+ 'nosuchlogid'
 38+ );
 39+ }
 40+
 41+ $vars = AbuseFilter::loadVarDump( $row->afl_var_dump );
 42+ }
 43+
 44+ if ( AbuseFilter::checkSyntax( $params[ 'filter' ] ) !== true ) {
 45+ $this->dieUsage( 'The filter has invalid syntax', 'badsyntax' );
 46+ }
 47+
 48+ $result = AbuseFilter::checkConditions( $params['filter'], $vars );
 49+ $this->getResult()->addValue(
 50+ null,
 51+ $this->getModuleName(),
 52+ array( 'result' => $result )
 53+ );
 54+ }
 55+
 56+ public function getAllowedParams() {
 57+ return array(
 58+ 'filter' => array(
 59+ ApiBase::PARAM_REQUIRED => true,
 60+ ),
 61+ 'vars' => null,
 62+ 'rcid' => array(
 63+ ApiBase::PARAM_TYPE => 'integer'
 64+ ),
 65+ 'logid' => array(
 66+ ApiBase::PARAM_TYPE => 'integer'
 67+ ),
 68+ );
 69+ }
 70+
 71+ public function getParamDescription() {
 72+ return array(
 73+ 'filter' => 'The full filter text to check for a match',
 74+ 'vars' => 'JSON encoded array of variables to test against',
 75+ 'rcid' => 'Recent change ID to check against',
 76+ 'logid' => 'Abuse filter log ID to check against',
 77+ );
 78+ }
 79+
 80+ public function getDescription() {
 81+ return array(
 82+ 'Check to see if an AbuseFilter matches a set of variables, edit'
 83+ . 'or logged AbuseFilter event.',
 84+ 'vars, rcid or logid is required however only one may be used',
 85+ );
 86+ }
 87+
 88+ public function getPossibleErrors() {
 89+ return array_merge( parent::getPossibleErrors(),
 90+ $this->getRequireOnlyOneParameterErrorMessages( array( 'vars', 'rcid', 'logid' ) ), array(
 91+ array( 'permissiondenied' ),
 92+ array( 'nosuchrcid' ),
 93+ array( 'code' => 'nosuchlogid', 'info' => 'There is no abuselog entry with the id given' ),
 94+ array( 'code' => 'badsyntax', 'info' => 'The filter has invalid syntax' ),
 95+ ) );
 96+ }
 97+
 98+ public function getExamples() {
 99+ return array(
 100+ 'api.php?action=checkfiltermatch&filter=!("autoconfirmed"%20in%20user_groups)&rcid=15'
 101+ );
 102+ }
 103+
 104+ public function getVersion() {
 105+ return __CLASS__ . ': $Id$';
 106+ }
 107+}
Property changes on: trunk/extensions/AbuseFilter/api/ApiCheckFilterMatch.php
___________________________________________________________________
Added: svn:eol-style
1108 + native
Index: trunk/extensions/AbuseFilter/api/ApiQueryAbuseLog.php
@@ -231,7 +231,7 @@
232232 ) );
233233 }
234234
235 - protected function getExamples() {
 235+ public function getExamples() {
236236 return array(
237237 'api.php?action=query&list=abuselog',
238238 'api.php?action=query&list=abuselog&afltitle=API'
Index: trunk/extensions/AbuseFilter/api/ApiCheckFilterSyntax.php
@@ -0,0 +1,67 @@
 2+<?php
 3+
 4+class ApiCheckFilterSyntax extends ApiBase {
 5+
 6+ public function execute() {
 7+ global $wgUser;
 8+ $params = $this->extractRequestParams();
 9+
 10+ // "Anti-DoS"
 11+ if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
 12+ $this->dieUsageMsg( 'permissiondenied' );
 13+ }
 14+
 15+ $result = AbuseFilter::checkSyntax( $params[ 'filter' ] );
 16+
 17+ $r = array();
 18+ if ( $result === true ) {
 19+ // Everything went better than expected :)
 20+ $r['status'] = 'ok';
 21+ } else {
 22+ $r = array(
 23+ 'status' => 'error',
 24+ 'message' => $result[0],
 25+ 'character' => $result[1],
 26+ );
 27+ }
 28+
 29+ $this->getResult()->addValue( null, $this->getModuleName(), $r );
 30+ }
 31+
 32+ public function getAllowedParams() {
 33+ return array(
 34+ 'filter' => array(
 35+ ApiBase::PARAM_REQUIRED => true,
 36+ ),
 37+ );
 38+ }
 39+
 40+ public function getParamDescription() {
 41+ return array(
 42+ 'filter' => 'The full filter text to check syntax on',
 43+ );
 44+ }
 45+
 46+ public function getDescription() {
 47+ return array(
 48+ 'Check syntax of an AbuseFilter filter'
 49+ );
 50+ }
 51+
 52+ public function getPossibleErrors() {
 53+ return array_merge( parent::getPossibleErrors(), array(
 54+ array( 'permissiondenied' ),
 55+ ) );
 56+ }
 57+
 58+ public function getExamples() {
 59+ return array(
 60+ 'api.php?action=checkfiltersyntax&filter="foo"',
 61+ 'api.php?action=checkfiltersyntax&filter="bar"%20bad_variable',
 62+ );
 63+ }
 64+
 65+ public function getVersion() {
 66+ return __CLASS__ . ': $Id$';
 67+ }
 68+}
\ No newline at end of file
Property changes on: trunk/extensions/AbuseFilter/api/ApiCheckFilterSyntax.php
___________________________________________________________________
Added: svn:eol-style
169 + native
Index: trunk/extensions/AbuseFilter/api/ApiUnblockAutopromote.php
@@ -0,0 +1,88 @@
 2+<?php
 3+
 4+class ApiUnblockAutopromote extends ApiBase {
 5+ public function execute() {
 6+ global $wgUser;
 7+ $params = $this->extractRequestParams();
 8+ $res = array();
 9+
 10+ if ( !$wgUser->isAllowed( 'abusefilter-modify' ) ) {
 11+ $this->dieUsage( 'You do not have permissions to unblock autopromotion', 'permissiondenied' );
 12+ }
 13+
 14+ $user = User::newFromName( $params['user'] );
 15+
 16+ if ( $user === false ) {
 17+ // Same as below
 18+ $msg = wfMsgExt( 'abusefilter-reautoconfirm-none', array( 'parsemag' ), $params['user'] );
 19+ $this->dieUsage( $msg, 'notsuspended' );
 20+ }
 21+
 22+ global $wgMemc;
 23+ $key = AbuseFilter::autoPromoteBlockKey( $user );
 24+
 25+ if ( !$wgMemc->get( $key ) ) {
 26+ // Oh god this is so bad but this message uses GENDER
 27+ $msg = wfMsgExt( 'abusefilter-reautoconfirm-none', array( 'parsemag' ), $params['user'] );
 28+ $this->dieUsage( $msg, 'notsuspended' );
 29+ }
 30+
 31+ $wgMemc->delete( $key );
 32+
 33+ $res = array( 'user' => $params['user'] );
 34+ $this->getResult()->addValue( null, $this->getModuleName(), $res );
 35+ }
 36+
 37+ public function mustBePosted() {
 38+ return true;
 39+ }
 40+
 41+ public function isWriteMode() {
 42+ return true;
 43+ }
 44+
 45+ public function getAllowedParams() {
 46+ return array(
 47+ 'user' => array(
 48+ ApiBase::PARAM_REQUIRED => true
 49+ ),
 50+ 'token' => null,
 51+ );
 52+ }
 53+
 54+ public function getParamDescription() {
 55+ return array(
 56+ 'user' => 'Username of the user you want to unblock',
 57+ 'token' => 'An edit token',
 58+ );
 59+ }
 60+
 61+ public function getDescription() {
 62+ return 'Unblocks a user from receiving autopromotions due to an abusefilter consequence';
 63+ }
 64+
 65+ public function getPossibleErrors() {
 66+ return array_merge( parent::getPossibleErrors(), array(
 67+ array( 'code' => 'notsuspended', 'info' => 'That user has not had their autoconfirmed status suspended'),
 68+ array( 'code' => 'permissiondenied', 'info' => 'You do not have permissions to unblock autopromotion' ),
 69+ ) );
 70+ }
 71+
 72+ public function needsToken() {
 73+ return true;
 74+ }
 75+
 76+ public function getTokenSalt() {
 77+ return '';
 78+ }
 79+
 80+ public function getExamples() {
 81+ return array(
 82+ 'api.php?action=unblockautopromote&user=Bob'
 83+ );
 84+ }
 85+
 86+ public function getVersion() {
 87+ return __CLASS__ . ': $Id$';
 88+ }
 89+}
Property changes on: trunk/extensions/AbuseFilter/api/ApiUnblockAutopromote.php
___________________________________________________________________
Added: svn:eol-style
190 + native
Index: trunk/extensions/AbuseFilter/api/ApiEvalFilterExpression.php
@@ -0,0 +1,41 @@
 2+<?php
 3+
 4+class ApiEvalFilterExpression extends ApiBase {
 5+ public function execute() {
 6+ $params = $this->extractRequestParams();
 7+
 8+ $result = AbuseFilter::evaluateExpression( $params['expression'] );
 9+
 10+ $this->getResult()->addValue( null, $this->getModuleName(), array( 'result' => $result ) );
 11+ }
 12+
 13+ public function getAllowedParams() {
 14+ return array(
 15+ 'expression' => array(
 16+ ApiBase::PARAM_REQUIRED => true,
 17+ ),
 18+ );
 19+ }
 20+
 21+ public function getParamDescription() {
 22+ return array(
 23+ 'expression' => 'The expression to evaluate',
 24+ );
 25+ }
 26+
 27+ public function getDescription() {
 28+ return array(
 29+ 'Evaluates an AbuseFilter expression'
 30+ );
 31+ }
 32+
 33+ public function getExamples() {
 34+ return array(
 35+ 'api.php?action=evalfilterexpression&expression=lcase("FOO")'
 36+ );
 37+ }
 38+
 39+ public function getVersion() {
 40+ return __CLASS__ . ': $Id$';
 41+ }
 42+}
Property changes on: trunk/extensions/AbuseFilter/api/ApiEvalFilterExpression.php
___________________________________________________________________
Added: svn:eol-style
143 + native
Index: trunk/extensions/AbuseFilter/api/ApiQueryAbuseFilters.php
@@ -225,7 +225,7 @@
226226 ) );
227227 }
228228
229 - protected function getExamples() {
 229+ public function getExamples() {
230230 return array(
231231 'api.php?action=query&list=abusefilters&abfshow=enabled|!private',
232232 'api.php?action=query&list=abusefilters&abfprop=id|description|pattern'
Index: trunk/extensions/AbuseFilter/AbuseFilter.hooks.php
@@ -4,8 +4,8 @@
55 }
66
77 class AbuseFilterHooks {
8 -// So far, all of the error message out-params for these hooks accept HTML.
9 -// Hooray!
 8+ // So far, all of the error message out-params for these hooks accept HTML.
 9+ // Hooray!
1010
1111 /**
1212 * @param $editor
@@ -275,4 +275,22 @@
276276
277277 return $filter_result == '' || $filter_result === true;
278278 }
 279+
 280+ /**
 281+ * Adds global variables to the Javascript as needed
 282+ *
 283+ * @param array $vars
 284+ * @return bool
 285+ */
 286+ public static function onMakeGlobalVariablesScript( array &$vars ) {
 287+ if ( AbuseFilter::$editboxName !== null ) {
 288+ $vars['wgFilterBoxName'] = AbuseFilter::$editboxName;
 289+ }
 290+
 291+ if ( AbuseFilterViewExamine::$examineType !== null ) {
 292+ $vars['wgExamineType'] = AbuseFilterViewExamine::$examineType;
 293+ $vars['wgExamineId'] = AbuseFilterViewExamine::$examineId;
 294+ }
 295+ return true;
 296+ }
279297 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r95573Followup r95572 to change variable names and use an associative array per Kri...johnduhart20:26, 26 August 2011
r95576syn:keywords Id for r95572reedy21:22, 26 August 2011
r95578Follow-up to r95572, remove $wgAjaxExportListjohnduhart23:06, 26 August 2011
r95588Followup r95572...reedy23:52, 26 August 2011
r98490Followup r95572, rename API modules to reduce chance of collisions per CRjohnduhart23:30, 29 September 2011
r98495Followup r95572, minor tweaks per CRjohnduhart00:48, 30 September 2011
r98499Followup r95572, replace insertAtCaret with textSelection per CRjohnduhart01:57, 30 September 2011
r101756* (bug 31870) Fix regression in AbuseFilter: pass/fail checkmark images for s...brion00:13, 3 November 2011
r108852Fix action= examples from r95572, need abusefilter prefixreedy21:36, 13 January 2012
r108853() are valid in URLs, not sure why we're using them as a finishing point in A...reedy21:42, 13 January 2012

Comments

#Comment by Catrope (talk | contribs)   15:13, 31 August 2011
+$wgAPIModules['checkfiltersyntax'] = 'ApiCheckFilterSyntax';

I would feel safer if API module names like these were prefixed to make naming conflicts less likely. Something like 'abusefilterchecksyntax' or 'checkabusefiltersyntax' (such that 'abusefilter' as a whole is mentioned).

The way information is passed in static member variables of AbuseFilter and AbuseFilterViewExamine is undocumented and kind of scary, but offhand I wouldn't know a better way. Maybe you can avoid passing the information instead; it looks like filterBoxName doesn't need to be passed around if you can make it so that the box always has the same ID.

+		data = data.checkfiltersyntax;
...
+		if ( data.status == 'ok' ) {

You need to check whether the first assignment didn't set data to undefined; this may happen if the API module throws an error.

+				$filterBox.text( data.query.abusefilters[0].pattern );

Same here, check that these elements are present in these objects or you'll get a ReferenceError and your entire script dies.

+			var action = this.id.substr( 31 );

Please add a comment explaining where the number 31 came from.

+			}, function( data ) {
+			$( '#mw-abusefilter-warn-preview' ).html( data )

Second line should be indented one tab more.

+		insertAtCaret: function(myValue){

Does $.textSelection's encapsulateSelection functionality not do what you want?

+		$( '#mw-abusefilter-expr-result' )
+			.html( mw.html.escape( data.evalfilterexpression.result ) );

Huh? Can't you just use .text() here?

+			$vars = json_decode( $params['vars'], true );

Use FormatJson::decode(). This wraps around json_decode() except when the JSON module isn't present or a version with a known bug is present, if which case it falls back to a PHP implementation.

+			// Same as below
...
+			// Oh god this is so bad but this message uses GENDER

It seems you refactored this and changed the order, so these comments are confusing at first, then amusing :)

Looks very good otherwise, thanks!

#Comment by Johnduhart (talk | contribs)   01:56, 30 September 2011

Alright, that should be everything.

#Comment by Reedy (talk | contribs)   15:51, 27 December 2011

You API examples seem to have broken links

Example:
  api.php?action=checkfiltermatch&filter=!("autoconfirmed"%20in%20user_groups)&rcid=15

But the link is only

[http://192.168.0.190/w/api.php?action=checkfiltermatch&filter=! http://192.168.0.190/w/api.php?action=checkfiltermatch&filter=!]

Seems to be the () in the urls

action=abusefiltercheckmatch and action=abusefilterevalexpression seem to be the affected modules

#Comment by Reedy (talk | contribs)   15:54, 27 December 2011

(which obviously means the whole url isn't clickable, and has to be manually copied into the URL box....)

#Comment by Reedy (talk | contribs)   16:11, 27 December 2011

(which obviously means the whole url isn't clickable, and has to be manually copied into the URL box....)

Status & tagging log