Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/ArticleFeedbackv5.i18n.php |
— | — | @@ -39,13 +39,14 @@ |
40 | 40 | 'articlefeedbackv5-error-email' => 'That e-mail address is not valid.', |
41 | 41 | 'articlefeedbackv5-error-blocked' => 'Blocked users may not submit feedback.', |
42 | 42 | 'articlefeedbackv5-error-validation' => 'Validation error.', |
43 | | - 'articlefeedbackv5-error-abuse' => 'Your comment violates the $1. Please revise it.', |
44 | | - 'articlefeedbackv5-error-abuse-linktext' => 'feedback abuse policy', |
45 | | - 'articlefeedbackv5-error-abuse-link' => '#', // TODO: Build page and set link here |
| 43 | + 'articlefeedbackv5-error-abuse' => 'Your post has been rejected by a software filter that suggests it may have violated Wikipedia\'s $1. Please revise your post and try again.', |
| 44 | + 'articlefeedbackv5-error-abuse-linktext' => 'feedback guidelines', |
| 45 | + 'articlefeedbackv5-error-abuse-link' => '//en.wikipedia.org/wiki/Wikipedia:Feedback_guidelines', |
46 | 46 | 'articlefeedbackv5-error-unknown' => 'Unknown error.', |
47 | 47 | 'articlefeedbackv5-error-submit' => 'Form submission error.', |
48 | 48 | 'articlefeedbackv5-error-nofeedback' => 'Please enter your feedback.', |
49 | 49 | 'articlefeedbackv5-error-flagging' => 'Error flagging feedback.', |
| 50 | + 'articlefeedbackv5-warning-abuse' => 'Your comment has been automatically identified as harmful. If you believe this comment to be constructive, you may click the submit button again to confirm it. A brief description of the abuse rule which your action matched is: $1', |
50 | 51 | |
51 | 52 | /* Special Page */ |
52 | 53 | 'articlefeedbackv5-form-tools-label' => 'Tools', |
— | — | @@ -427,6 +428,13 @@ |
428 | 429 | 'articlefeedbackv5-disable-flyover-help-location' => 'My preferences > Appearance', |
429 | 430 | 'articlefeedbackv5-disable-flyover-prefbutton' => 'Go to my preferences', |
430 | 431 | |
| 432 | + /* Custom AbuseFilter actions */ |
| 433 | + 'abusefilter-edit-action-aftv5flagabuse' => '(Article Feedback) Auto-flag as abuse', |
| 434 | + 'articlefeedbackv5-abusefilter-note-aftv5flagabuse' => 'Automatically flagged as abuse. Rule: $1', |
| 435 | + 'abusefilter-edit-action-aftv5hide' => '(Article Feedback) Auto-hide', |
| 436 | + 'articlefeedbackv5-abusefilter-note-aftv5hide' => 'Automatically hidden. Rule: $1', |
| 437 | + 'abusefilter-edit-action-aftv5requestoversight' => '(Article Feedback) Auto-request oversight', |
| 438 | + 'articlefeedbackv5-abusefilter-note-aftv5requestoversight' => 'Oversight automatically requested. Rule: $1', |
431 | 439 | ); |
432 | 440 | |
433 | 441 | /** Message documentation (Message documentation) |
— | — | @@ -709,6 +717,13 @@ |
710 | 718 | 'articlefeedbackv5-disable-flyover-help-emphasis-text' => 'The emphasis text for {{msg-mw|articlefeedbackv5-disable-flyover-help}} (the name of the tool)', |
711 | 719 | 'articlefeedbackv5-disable-flyover-help-location' => 'A short indication of where to go to change your Article Feedback preferences, inside {{msg-mw|articlefeedbackv5-disable-flyover-help}}', |
712 | 720 | 'articlefeedbackv5-disable-flyover-prefbutton' => 'The text of the big glossy button used to send the user to their preferences in the tooltip that pops up when you click the close button on a feedback trigger link, explaining how to remove the Article Feedback tool', |
| 721 | + 'articlefeedbackv5-abusefilter-note-aftv5flagabuse' => 'The note to add to the activity log when auto-flagging a new feedback post as abuse (<code>$1</code> is the name of the filter)', |
| 722 | + 'abusefilter-edit-action-aftv5flagabuse' => 'The text for the checkbox used by Special:AbuseFilter to indicate that a rule should result in the feedback being auto-flagged as abuse', |
| 723 | + 'abusefilter-edit-action-aftv5hide' => 'The text for the checkbox used by Special:AbuseFilter to indicate that a rule should result in the feedback being auto-hidden', |
| 724 | + 'abusefilter-edit-action-aftv5requestoversight' => 'The text for the checkbox used by Special:AbuseFilter to indicate that a rule should result in oversight being automatically requested for the feedback', |
| 725 | + 'articlefeedbackv5-abusefilter-note-aftv5hide' => 'The note to add to the activity log when auto-hiding a new feedback post (<code>$1</code> is the name of the filter)', |
| 726 | + 'articlefeedbackv5-abusefilter-note-aftv5requestoversight' => 'The note to add to the activity log when automatically requesting oversight for a new feedback post (<code>$1</code> is the name of the filter)', |
| 727 | + 'articlefeedbackv5-warning-abuse' => 'A basic warning message that may be used by Special:AbuseFilter to let the user know their comment has violated policy (<code>$1</code> is the name of the filter)', |
713 | 728 | ); |
714 | 729 | |
715 | 730 | /** Afrikaans (Afrikaans) |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.js |
— | — | @@ -16,6 +16,8 @@ |
17 | 17 | * set foldlevel=0 |
18 | 18 | * set foldcolumn=0 |
19 | 19 | * |
| 20 | + * TODO: jam sort/filter options into URL anchors, and use them as defaults if present. |
| 21 | + * |
20 | 22 | * @package ArticleFeedback |
21 | 23 | * @subpackage Resources |
22 | 24 | * @author Greg Chiasson <gchiasson@omniti.com> |
— | — | @@ -26,8 +28,6 @@ |
27 | 29 | |
28 | 30 | // {{{ articleFeedbackv5special definition |
29 | 31 | |
30 | | - // TODO: jam sort/filter options into URL anchors, and use them as defaults if present. |
31 | | - |
32 | 32 | $.articleFeedbackv5special = {}; |
33 | 33 | |
34 | 34 | // {{{ Properties |
— | — | @@ -71,14 +71,14 @@ |
72 | 72 | * @var string |
73 | 73 | */ |
74 | 74 | $.articleFeedbackv5special.activityCookieName = 'activity-'; |
75 | | - |
| 75 | + |
76 | 76 | /** |
77 | 77 | * Currently displayed panel host element id attribute value |
78 | 78 | * |
79 | 79 | * @var string |
80 | 80 | */ |
81 | 81 | $.articleFeedbackv5special.currentPanelHostId = undefined; |
82 | | - |
| 82 | + |
83 | 83 | /** |
84 | 84 | * Action note flyover panel HTML template |
85 | 85 | * |
— | — | @@ -97,7 +97,7 @@ |
98 | 98 | <a class="articlefeedbackv5-flyover-help" id="articlefeedbackv5-noteflyover-help" href="#"></a>\ |
99 | 99 | </div>\ |
100 | 100 | </form>'; |
101 | | - |
| 101 | + |
102 | 102 | /** |
103 | 103 | * Mask HMTL template |
104 | 104 | */ |
— | — | @@ -108,7 +108,7 @@ |
109 | 109 | <span class="articleFeedbackv5-mask-postid"></span>\ |
110 | 110 | </div>\ |
111 | 111 | </div>'; |
112 | | - |
| 112 | + |
113 | 113 | // }}} |
114 | 114 | // {{{ Init methods |
115 | 115 | |
— | — | @@ -152,12 +152,12 @@ |
153 | 153 | title: 'title', // attribute/callback containing tooltip text |
154 | 154 | trigger: 'manual' // how tooltip is triggered - hover | focus | manual |
155 | 155 | }; |
156 | | - |
| 156 | + |
157 | 157 | // i18n, create action-specific tipsy panels from template |
158 | 158 | var container = $( '<div></div>' ); |
159 | 159 | container.html( $.articleFeedbackv5special.notePanelHtmlTemplate ); |
160 | | - for( var action in $.articleFeedbackv5special.actions ) { |
161 | | - if( $.articleFeedbackv5special.actions[action].hasTipsy && (undefined == $.articleFeedbackv5special.actions[action].tipsyHtml) ) { |
| 160 | + for ( var action in $.articleFeedbackv5special.actions ) { |
| 161 | + if ( $.articleFeedbackv5special.actions[action].hasTipsy && (undefined == $.articleFeedbackv5special.actions[action].tipsyHtml) ) { |
162 | 162 | container.find( '#articlefeedbackv5-noteflyover-caption' ).text( mw.msg( 'articlefeedbackv5-noteflyover-' + action + '-caption' ) ); |
163 | 163 | container.find( '#articlefeedbackv5-noteflyover-label' ).text( mw.msg( 'articlefeedbackv5-noteflyover-' + action + '-label' ) ); |
164 | 164 | container.find( '#articlefeedbackv5-noteflyover-submit' ).text( mw.msg( 'articlefeedbackv5-noteflyover-' + action + '-submit' ) ); |
— | — | @@ -168,7 +168,7 @@ |
169 | 169 | $.articleFeedbackv5special.actions[action].tipsyHtml = container.html(); |
170 | 170 | } |
171 | 171 | } |
172 | | - |
| 172 | + |
173 | 173 | // Initial load |
174 | 174 | $.articleFeedbackv5special.loadFeedback( true ); |
175 | 175 | }; |
— | — | @@ -198,7 +198,7 @@ |
199 | 199 | $.articleFeedbackv5special.listControls.continueId = null; |
200 | 200 | |
201 | 201 | // unless we're flipping the direction on the current sort. |
202 | | - if( id == oldId && $.articleFeedbackv5special.listControls.sortDirection == 'desc' ) { |
| 202 | + if ( id == oldId && $.articleFeedbackv5special.listControls.sortDirection == 'desc' ) { |
203 | 203 | $.articleFeedbackv5special.listControls.sortDirection = 'asc'; |
204 | 204 | } else { |
205 | 205 | $.articleFeedbackv5special.listControls.sortDirection = 'desc'; |
— | — | @@ -231,10 +231,10 @@ |
232 | 232 | } ); |
233 | 233 | |
234 | 234 | // Bind actions |
235 | | - for( var action in $.articleFeedbackv5special.actions ) { |
| 235 | + for ( var action in $.articleFeedbackv5special.actions ) { |
236 | 236 | $( '.articleFeedbackv5-' + action + '-link' ).live( 'click', $.articleFeedbackv5special.actions[action].click ); |
237 | 237 | } |
238 | | - |
| 238 | + |
239 | 239 | // Bind submit actions on flyover panels (flag actions) |
240 | 240 | $( '#articlefeedbackv5-noteflyover-submit' ).live( 'click', function( e ) { |
241 | 241 | e.preventDefault(); |
— | — | @@ -243,24 +243,24 @@ |
244 | 244 | $( e.target ).attr( 'action' ), |
245 | 245 | $( '#articlefeedbackv5-noteflyover-note' ).attr( 'value' ), |
246 | 246 | { } ); |
247 | | - |
| 247 | + |
248 | 248 | // hide tipsy |
249 | 249 | $( '#' + $.articleFeedbackv5special.currentPanelHostId ).tipsy( 'hide' ); |
250 | 250 | $.articleFeedbackv5special.currentPanelHostId = undefined; |
251 | 251 | } ); |
252 | | - |
| 252 | + |
253 | 253 | // bind flyover panel close button |
254 | 254 | $( '#articlefeedbackv5-noteflyover-close' ).live( 'click', function( e ) { |
255 | 255 | e.preventDefault(); |
256 | 256 | $( '#' + $.articleFeedbackv5special.currentPanelHostId ).tipsy( 'hide' ); |
257 | 257 | $.articleFeedbackv5special.currentPanelHostId = undefined; |
258 | 258 | } ); |
259 | | - |
| 259 | + |
260 | 260 | } |
261 | 261 | // }}} |
262 | 262 | // {{{ bindPanels |
263 | 263 | /** |
264 | | - * Bind panels to controls - that cannot be 'live' events due to jQuery.typsy |
| 264 | + * Bind panels to controls - that cannot be 'live' events due to jQuery.tipsy |
265 | 265 | * limitations. This function should be invoked after feedback posts are loaded, |
266 | 266 | * without parameters. The function should be invoked with the id parameter set |
267 | 267 | * after an action is executed and its link is replaced with reverse action. |
— | — | @@ -268,10 +268,10 @@ |
269 | 269 | * @param id post id to bind panels for. If none is supplied, bind entire list. |
270 | 270 | */ |
271 | 271 | $.articleFeedbackv5special.bindPanels = function( id ) { |
272 | | - // single post or entire list? |
| 272 | + // single post or entire list? |
273 | 273 | var $selector = !id ? $( '#articleFeedbackv5-show-feedback' ) : $( '.articleFeedbackv5-feedback[rel="' + id + '"]' ); |
274 | | - |
275 | | - for( var action in $.articleFeedbackv5special.actions ) { |
| 274 | + |
| 275 | + for ( var action in $.articleFeedbackv5special.actions ) { |
276 | 276 | $selector.find( '.articleFeedbackv5-' + action + '-link' ) |
277 | 277 | .attr( 'action', action ) |
278 | 278 | .tipsy( { |
— | — | @@ -282,13 +282,14 @@ |
283 | 283 | } |
284 | 284 | } |
285 | 285 | // }}} |
286 | | - |
| 286 | + |
287 | 287 | // }}} |
288 | 288 | // {{{ Utility methods |
289 | | - |
| 289 | + |
290 | 290 | // {{{ toggleTipsy |
| 291 | + |
291 | 292 | /** |
292 | | - * Toggles tipsy display for an action link |
| 293 | + * Utility method: Toggles tipsy display for an action link |
293 | 294 | * |
294 | 295 | * @param e event |
295 | 296 | * @returns true if showing tipsy, false if hiding |
— | — | @@ -297,7 +298,7 @@ |
298 | 299 | e.preventDefault(); |
299 | 300 | var $l = $( e.target ); |
300 | 301 | // are we hiding the current tipsy? |
301 | | - if( $l.attr( 'id' ) == $.articleFeedbackv5special.currentPanelHostId ) { |
| 302 | + if ( $l.attr( 'id' ) == $.articleFeedbackv5special.currentPanelHostId ) { |
302 | 303 | $l.tipsy( 'hide' ); |
303 | 304 | $.articleFeedbackv5special.currentPanelHostId = undefined; |
304 | 305 | return false; |
— | — | @@ -311,12 +312,17 @@ |
312 | 313 | return true; |
313 | 314 | } |
314 | 315 | } |
| 316 | + |
315 | 317 | // }}} |
| 318 | + // {{{ toggleComment |
316 | 319 | |
317 | | - // {{{ toggleComment |
318 | | - $.articleFeedbackv5special.toggleComment = function( id ) { |
319 | | - if( $( '#articleFeedbackv5-comment-toggle-' + id ).text() |
320 | | - == mw.msg( 'articlefeedbackv5-comment-more' ) ) { |
| 320 | + /** |
| 321 | + * Utility method: Toggles a comment between short and full displays |
| 322 | + * |
| 323 | + * @param id string the comment id |
| 324 | + */ |
| 325 | + $.articleFeedbackv5special.toggleComment = function( id ) { |
| 326 | + if ( $( '#articleFeedbackv5-comment-toggle-' + id ).text() == mw.msg( 'articlefeedbackv5-comment-more' ) ) { |
321 | 327 | $( '#articleFeedbackv5-comment-short-' + id ).hide(); |
322 | 328 | $( '#articleFeedbackv5-comment-full-' + id ).show(); |
323 | 329 | $( '#articleFeedbackv5-comment-toggle-' + id ).text( |
— | — | @@ -334,7 +340,11 @@ |
335 | 341 | // }}} |
336 | 342 | // {{{ drawSortArrow |
337 | 343 | |
338 | | - $.articleFeedbackv5special.drawSortArrow = function() { |
| 344 | + /** |
| 345 | + * Utility method: Resets the sort arrows according to the currently selected |
| 346 | + * sort and direction |
| 347 | + */ |
| 348 | + $.articleFeedbackv5special.drawSortArrow = function() { |
339 | 349 | var id = $.articleFeedbackv5special.listControls.sort, |
340 | 350 | dir = $.articleFeedbackv5special.listControls.sortDirection; |
341 | 351 | |
— | — | @@ -351,7 +361,9 @@ |
352 | 362 | // }}} |
353 | 363 | // {{{ stripID |
354 | 364 | |
355 | | - // Utility method for stripping long IDs down to the specific bits we care about. |
| 365 | + /** |
| 366 | + * Utility method: Strips long IDs down to the specific bits we care about |
| 367 | + */ |
356 | 368 | $.articleFeedbackv5special.stripID = function( object, toRemove ) { |
357 | 369 | return $( object ).attr( 'id' ).replace( toRemove, '' ); |
358 | 370 | }; |
— | — | @@ -464,12 +476,15 @@ |
465 | 477 | |
466 | 478 | // }}} |
467 | 479 | // {{{ markHidden |
| 480 | + |
468 | 481 | /** |
469 | 482 | * Utility method: Marks a feedback row hidden |
470 | 483 | * |
471 | | - * @param $row element the feedback row |
| 484 | + * @param $row element the feedback row |
| 485 | + * @param hide_user string the user's name, linked to their user page |
| 486 | + * @param hide_timestamp string the timestamp |
472 | 487 | */ |
473 | | - $.articleFeedbackv5special.markHidden = function ( $row, $hide_user, $hide_timestamp ) { |
| 488 | + $.articleFeedbackv5special.markHidden = function ( $row, hide_user, hide_timestamp ) { |
474 | 489 | if ( $row.data( 'deleted' ) ) { |
475 | 490 | $.articleFeedbackv5special.unmarkDeleted( $row ); |
476 | 491 | } |
— | — | @@ -480,13 +495,15 @@ |
481 | 496 | .data( 'hidden', true ); |
482 | 497 | $row.find( '.articleFeedbackv5-comment-wrap' ).addClass( 'articleFeedbackv5-h3-push'); |
483 | 498 | $( '<span class="articleFeedbackv5-feedback-hidden-marker"></span>' ) |
484 | | - // this is on purpose html not text- $hide_user is a link |
485 | | - .html( mw.msg( 'articlefeedbackv5-hidden', $hide_user, $hide_timestamp) ) |
| 499 | + // this is on purpose html not text- hide_user is a link |
| 500 | + .html( mw.msg( 'articlefeedbackv5-hidden', hide_user, hide_timestamp) ) |
486 | 501 | .insertBefore( $row.find( '.articleFeedbackv5-comment-wrap' ) ); |
487 | 502 | $.articleFeedbackv5special.maskPost( $row, 'hidden'); |
488 | 503 | }; |
| 504 | + |
489 | 505 | // }}} |
490 | 506 | // {{{ unmarkHidden |
| 507 | + |
491 | 508 | /** |
492 | 509 | * Utility method: Unmarks as hidden a feedback row |
493 | 510 | * |
— | — | @@ -498,14 +515,23 @@ |
499 | 516 | $row.find( '.articleFeedbackv5-feedback-hidden-marker' ).remove(); |
500 | 517 | $row.find( '.articleFeedbackv5-comment-wrap' ).removeClass( 'articleFeedbackv5-h3-push'); |
501 | 518 | }; |
| 519 | + |
502 | 520 | // }}} |
503 | 521 | // {{{ maskPost |
504 | | - $.articleFeedbackv5special.maskPost = function( $row, $type ) { |
| 522 | + |
| 523 | + /** |
| 524 | + * Utility method: Masks a comment that's been marked |
| 525 | + * hidden/oversighted/etc. |
| 526 | + * |
| 527 | + * @param $row element the feedback row |
| 528 | + * @param type string the mask type |
| 529 | + */ |
| 530 | + $.articleFeedbackv5special.maskPost = function( $row, type ) { |
505 | 531 | var $screen = $row.find( '.articleFeedbackv5-post-screen' ); |
506 | 532 | if( 0 == $screen.length ) { |
507 | 533 | $screen = $( $.articleFeedbackv5special.maskHtmlTemplate ); |
508 | 534 | $screen.find( '.articleFeedbackv5-mask-text' ) |
509 | | - .text( mw.msg( 'articlefeedbackv5-mask-text-' + $type ) ); |
| 535 | + .text( mw.msg( 'articlefeedbackv5-mask-text-' + type ) ); |
510 | 536 | $screen.find( '.articleFeedbackv5-mask-postid' ) |
511 | 537 | .text( mw.msg( 'articlefeedbackv5-mask-postnumber', $row.attr( 'rel' ) ) ); |
512 | 538 | $row.prepend( $screen ); |
— | — | @@ -518,14 +544,18 @@ |
519 | 545 | $screen.find( '.articleFeedbackv5-mask-text-wrapper') |
520 | 546 | .css( 'top', $screen.innerHeight() / 2 - 12 ); |
521 | 547 | } |
| 548 | + |
522 | 549 | // }}} |
523 | 550 | // {{{ markDeleted |
| 551 | + |
524 | 552 | /** |
525 | 553 | * Utility method: Marks a feedback row deleted |
526 | 554 | * |
527 | | - * @param $row element the feedback row |
| 555 | + * @param $row element the feedback row |
| 556 | + * @param oversight_user string the user's name, linked to their user page |
| 557 | + * @param oversight_timestamp string the timestamp |
528 | 558 | */ |
529 | | - $.articleFeedbackv5special.markDeleted = function ( $row , $oversight_user, $oversight_timestamp) { |
| 559 | + $.articleFeedbackv5special.markDeleted = function ( $row, oversight_user, oversight_timestamp ) { |
530 | 560 | if ( $row.data( 'deleted' ) ) { |
531 | 561 | $.articleFeedbackv5special.unmarkDeleted( $row ); |
532 | 562 | } |
— | — | @@ -535,8 +565,8 @@ |
536 | 566 | $row.addClass( 'articleFeedbackv5-feedback-deleted' ) |
537 | 567 | .data( 'deleted', true ); |
538 | 568 | var $marker = $( '<span class="articleFeedbackv5-feedback-deleted-marker"></span>' ) |
539 | | - // this is on purpose html not text- $oversight_user is a link |
540 | | - .html( mw.msg( 'articlefeedbackv5-deleted', $oversight_user, $oversight_timestamp ) ) |
| 569 | + // this is on purpose html not text- oversight_user is a link |
| 570 | + .html( mw.msg( 'articlefeedbackv5-deleted', oversight_user, oversight_timestamp ) ) |
541 | 571 | .insertBefore( $row.find( '.articleFeedbackv5-comment-wrap' ) ); |
542 | 572 | $row.find( '.articleFeedbackv5-comment-wrap' ).addClass( 'articleFeedbackv5-h3-push'); |
543 | 573 | $.articleFeedbackv5special.maskPost( $row, 'oversight' ); |
— | — | @@ -544,6 +574,7 @@ |
545 | 575 | |
546 | 576 | // }}} |
547 | 577 | // {{{ unmarkDeleted |
| 578 | + |
548 | 579 | /** |
549 | 580 | * Utility method: Unmarks as deleted a feedback row |
550 | 581 | * |
— | — | @@ -555,9 +586,17 @@ |
556 | 587 | $row.find( '.articleFeedbackv5-feedback-deleted-marker' ).remove(); |
557 | 588 | $row.find( '.articleFeedbackv5-comment-wrap' ).removeClass( 'articleFeedbackv5-h3-push'); |
558 | 589 | }; |
| 590 | + |
559 | 591 | // }}} |
560 | | - |
561 | 592 | // {{{ setActivityFlag |
| 593 | + |
| 594 | + /** |
| 595 | + * Utility method: Sets an activity flag |
| 596 | + * |
| 597 | + * @param id string the feedback id |
| 598 | + * @param flag string the flag name |
| 599 | + * @param value string the value |
| 600 | + */ |
562 | 601 | $.articleFeedbackv5special.setActivityFlag = function( id, flag, value ) { |
563 | 602 | // no activity for this post yet, create default structure |
564 | 603 | if ( !( id in $.articleFeedbackv5special.activity ) ) { |
— | — | @@ -565,9 +604,10 @@ |
566 | 605 | } |
567 | 606 | $.articleFeedbackv5special.activity[id][flag] = value; |
568 | 607 | $.articleFeedbackv5special.storeActivity(); |
569 | | - } |
| 608 | + }; |
| 609 | + |
570 | 610 | // }}} |
571 | | - |
| 611 | + |
572 | 612 | // }}} |
573 | 613 | // {{{ Process methods |
574 | 614 | |
— | — | @@ -584,22 +624,22 @@ |
585 | 625 | $.articleFeedbackv5special.flagFeedback = function ( id, action, note, options ) { |
586 | 626 | // default parameters |
587 | 627 | note = typeof note !== undefined ? note : ''; |
588 | | - |
| 628 | + |
589 | 629 | if( $.articleFeedbackv5special.listControls.disabled ) { |
590 | 630 | return false; |
591 | 631 | } |
592 | | - |
593 | | - // This was causing problems with eg 'clicking helpful when the cookie |
594 | | - // already says unhelpful', which is a case where two ajax requests |
| 632 | + |
| 633 | + // This was causing problems with eg 'clicking helpful when the cookie |
| 634 | + // already says unhelpful', which is a case where two ajax requests |
595 | 635 | // is perfectly legitimate. |
596 | 636 | // Check another global variable to not disable ajax in that case. |
597 | 637 | if( !$.articleFeedbackv5special.listControls.allowMultiple ) { |
598 | | - // Put a lock on ajax requests to prevent another one from going |
| 638 | + // Put a lock on ajax requests to prevent another one from going |
599 | 639 | // through while this is still running. Prevents manic link-clicking |
600 | 640 | // messing up the counts, and generally seems like a good idea. |
601 | 641 | $.articleFeedbackv5special.listControls.disabled = true; |
602 | 642 | } |
603 | | - |
| 643 | + |
604 | 644 | // Merge request data and options objects (flat) |
605 | 645 | var requestData = { |
606 | 646 | 'pageid' : $.articleFeedbackv5special.page, |
— | — | @@ -626,10 +666,10 @@ |
627 | 667 | if( undefined != $.articleFeedbackv5special.actions[action].onSuccess ) { |
628 | 668 | $.articleFeedbackv5special.actions[action].onSuccess( id, data ); |
629 | 669 | } |
630 | | - |
| 670 | + |
631 | 671 | // Re-enable ajax flagging. |
632 | 672 | $.articleFeedbackv5special.listControls.disabled = false; |
633 | | - |
| 673 | + |
634 | 674 | // re-bind panels (tipsies) |
635 | 675 | $.articleFeedbackv5special.bindPanels( id ); |
636 | 676 | return true; |
— | — | @@ -652,6 +692,7 @@ |
653 | 693 | |
654 | 694 | // }}} |
655 | 695 | // {{{ loadActivityLog |
| 696 | + |
656 | 697 | /** |
657 | 698 | * Load the activity log for a feedback post item |
658 | 699 | * |
— | — | @@ -695,10 +736,10 @@ |
696 | 737 | $( '#articlefeedbackv5-activity-log' ).text( mw.msg( 'articleFeedbackv5-view-activity-error' ) ); |
697 | 738 | } |
698 | 739 | } ); |
699 | | - |
| 740 | + |
700 | 741 | return false; |
701 | | - } |
702 | | - |
| 742 | + }; |
| 743 | + |
703 | 744 | // }}} |
704 | 745 | // {{{ loadFeedback |
705 | 746 | |
— | — | @@ -763,7 +804,7 @@ |
764 | 805 | } |
765 | 806 | $l.attr( 'id', 'articleFeedbackv5-unabuse-link-' + id ) |
766 | 807 | .removeClass( 'articleFeedbackv5-abuse-link' ) |
767 | | - .addClass( 'articleFeedbackv5-unabuse-link' ); |
| 808 | + .addClass( 'articleFeedbackv5-unabuse-link' ); |
768 | 809 | } |
769 | 810 | } |
770 | 811 | |
— | — | @@ -793,7 +834,7 @@ |
794 | 835 | } ); |
795 | 836 | |
796 | 837 | return false; |
797 | | - } |
| 838 | + }; |
798 | 839 | |
799 | 840 | // }}} |
800 | 841 | // {{{ loadActivity |
— | — | @@ -806,10 +847,11 @@ |
807 | 848 | if ( flatActivity ) { |
808 | 849 | $.articleFeedbackv5special.activity = $.articleFeedbackv5special.decodeActivity( flatActivity ); |
809 | 850 | } |
810 | | - } |
| 851 | + }; |
811 | 852 | |
812 | 853 | // }}} |
813 | 854 | // {{{ storeActivity |
| 855 | + |
814 | 856 | /** |
815 | 857 | * Stores the user activity to the cookie |
816 | 858 | */ |
— | — | @@ -820,23 +862,26 @@ |
821 | 863 | flatActivity, |
822 | 864 | { 'expires': 365, 'path': '/' } |
823 | 865 | ); |
824 | | - } |
| 866 | + }; |
| 867 | + |
825 | 868 | // }}} |
826 | 869 | // {{{ canBeFlagged |
| 870 | + |
827 | 871 | /** |
828 | 872 | * Returns true if the post can be flagged |
829 | 873 | */ |
830 | 874 | $.articleFeedbackv5special.canBeFlagged = function( $post ) { |
831 | 875 | return !$post.data( 'hidden' ) && !$post.data( 'deleted' ); |
832 | | - } |
| 876 | + }; |
| 877 | + |
833 | 878 | // }}} |
834 | 879 | |
835 | 880 | // }}} |
836 | | - |
837 | 881 | // {{{ Actions |
| 882 | + |
838 | 883 | /** |
839 | 884 | * Actions - available actions on the page. |
840 | | - * |
| 885 | + * |
841 | 886 | * Each action is an object with the following properties: |
842 | 887 | * hasTipsy - true if the action needs a flyover panel |
843 | 888 | * tipsyHtml - html for the corresponding flyover panel |
— | — | @@ -848,7 +893,7 @@ |
849 | 894 | * data - any data returned by the AJAX call |
850 | 895 | */ |
851 | 896 | $.articleFeedbackv5special.actions = { |
852 | | - |
| 897 | + |
853 | 898 | // Vote helpful |
854 | 899 | 'helpful': { |
855 | 900 | 'hasTipsy': false, |
— | — | @@ -881,7 +926,7 @@ |
882 | 927 | $.articleFeedbackv5special.setActivityFlag( id, 'helpful', true ); |
883 | 928 | } |
884 | 929 | }, |
885 | | - |
| 930 | + |
886 | 931 | // Un-vote helpful |
887 | 932 | 'reversehelpful': { |
888 | 933 | 'hasTipsy': false, |
— | — | @@ -905,7 +950,7 @@ |
906 | 951 | $.articleFeedbackv5special.setActivityFlag( id, 'helpful', false ); |
907 | 952 | } |
908 | 953 | }, |
909 | | - |
| 954 | + |
910 | 955 | // Vote unhelpful |
911 | 956 | 'unhelpful': { |
912 | 957 | 'hasTipsy': false, |
— | — | @@ -938,7 +983,7 @@ |
939 | 984 | $.articleFeedbackv5special.setActivityFlag( id, 'unhelpful', true ); |
940 | 985 | } |
941 | 986 | }, |
942 | | - |
| 987 | + |
943 | 988 | // Un-vote unhelpful |
944 | 989 | 'reverseunhelpful': { |
945 | 990 | 'hasTipsy': false, |
— | — | @@ -1001,7 +1046,7 @@ |
1002 | 1047 | $.articleFeedbackv5special.setActivityFlag( id, 'abuse', true ); |
1003 | 1048 | } |
1004 | 1049 | }, |
1005 | | - |
| 1050 | + |
1006 | 1051 | // Unflag post as abusive |
1007 | 1052 | 'unabuse': { |
1008 | 1053 | 'hasTipsy': false, |
— | — | @@ -1040,7 +1085,7 @@ |
1041 | 1086 | $.articleFeedbackv5special.setActivityFlag( id, 'abuse', false ); |
1042 | 1087 | } |
1043 | 1088 | }, |
1044 | | - |
| 1089 | + |
1045 | 1090 | // Hide post action |
1046 | 1091 | 'hide': { |
1047 | 1092 | 'hasTipsy': true, |
— | — | @@ -1062,7 +1107,7 @@ |
1063 | 1108 | $.articleFeedbackv5special.setActivityFlag( id, 'hide', true ); |
1064 | 1109 | } |
1065 | 1110 | }, |
1066 | | - |
| 1111 | + |
1067 | 1112 | // Show post action |
1068 | 1113 | 'show': { |
1069 | 1114 | 'hasTipsy': true, |
— | — | @@ -1081,7 +1126,7 @@ |
1082 | 1127 | $.articleFeedbackv5special.setActivityFlag( id, 'hide', false ); |
1083 | 1128 | } |
1084 | 1129 | }, |
1085 | | - |
| 1130 | + |
1086 | 1131 | // Request oversight action |
1087 | 1132 | 'requestoversight': { |
1088 | 1133 | 'hasTipsy': true, |
— | — | @@ -1112,7 +1157,7 @@ |
1113 | 1158 | } |
1114 | 1159 | } |
1115 | 1160 | }, |
1116 | | - |
| 1161 | + |
1117 | 1162 | // Cancel oversight request action |
1118 | 1163 | 'unrequestoversight': { |
1119 | 1164 | 'hasTipsy': true, |
— | — | @@ -1129,7 +1174,7 @@ |
1130 | 1175 | .addClass( 'articleFeedbackv5-requestoversight-link'); |
1131 | 1176 | } |
1132 | 1177 | }, |
1133 | | - |
| 1178 | + |
1134 | 1179 | // Oversight post action |
1135 | 1180 | 'oversight': { |
1136 | 1181 | 'hasTipsy': true, |
— | — | @@ -1162,7 +1207,7 @@ |
1163 | 1208 | $.articleFeedbackv5special.setActivityFlag( id, 'delete', true ); |
1164 | 1209 | } |
1165 | 1210 | }, |
1166 | | - |
| 1211 | + |
1167 | 1212 | // Un-oversight action |
1168 | 1213 | 'unoversight': { |
1169 | 1214 | 'hasTipsy': true, |
— | — | @@ -1184,7 +1229,7 @@ |
1185 | 1230 | $.articleFeedbackv5special.setActivityFlag( id, 'delete', false ); |
1186 | 1231 | } |
1187 | 1232 | }, |
1188 | | - |
| 1233 | + |
1189 | 1234 | // Decline oversight action |
1190 | 1235 | 'declineoversight': { |
1191 | 1236 | 'hasTipsy': true, |
— | — | @@ -1196,7 +1241,7 @@ |
1197 | 1242 | $( '#articleFeedbackv5-declineoversight-link-' + id ).remove(); |
1198 | 1243 | } |
1199 | 1244 | }, |
1200 | | - |
| 1245 | + |
1201 | 1246 | // View activity log action |
1202 | 1247 | 'activity': { |
1203 | 1248 | 'hasTipsy': true, |
— | — | @@ -1215,8 +1260,9 @@ |
1216 | 1261 | } |
1217 | 1262 | } |
1218 | 1263 | } |
1219 | | - |
| 1264 | + |
1220 | 1265 | }; |
| 1266 | + |
1221 | 1267 | // }}} |
1222 | 1268 | |
1223 | 1269 | // }}} |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.js |
— | — | @@ -77,7 +77,7 @@ |
78 | 78 | /** |
79 | 79 | * Are we in debug mode? |
80 | 80 | */ |
81 | | - $.articleFeedbackv5.debug = mw.config.get( 'wgArticleFeedbackv5Debug' ) ? true : ( mw.util.getParamValue( 'debug' ) ? true : false ); |
| 81 | + $.articleFeedbackv5.debug = mw.config.get( 'wgArticleFeedbackv5Debug' ) ? true : false; |
82 | 82 | |
83 | 83 | /** |
84 | 84 | * Are we tracking clicks? |
— | — | @@ -452,7 +452,7 @@ |
453 | 453 | $block.find( '.articleFeedbackv5-submit' ) |
454 | 454 | .click( function ( e ) { |
455 | 455 | e.preventDefault(); |
456 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-submit-' + |
| 456 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-submit-' + |
457 | 457 | ( $.articleFeedbackv5.inDialog ? 'overlay' : 'bottom' ) ); |
458 | 458 | $.articleFeedbackv5.submitForm(); |
459 | 459 | } ); |
— | — | @@ -506,1340 +506,6 @@ |
507 | 507 | |
508 | 508 | // }}} |
509 | 509 | |
510 | | - }, |
511 | | - |
512 | | - // }}} |
513 | | - // {{{ Bucket 2 |
514 | | - |
515 | | - /** |
516 | | - * Bucket 2: Help Improve This Article |
517 | | - */ |
518 | | - '2': { |
519 | | - |
520 | | - // {{{ properties |
521 | | - |
522 | | - /** |
523 | | - * The tags available for this bucket |
524 | | - */ |
525 | | - tagInfo: mw.config.get( 'wgArticleFeedbackv5Bucket2TagNames' ), |
526 | | - |
527 | | - /** |
528 | | - * The comment default text, by tag (filled by buildForm) |
529 | | - */ |
530 | | - commentDefault: {}, |
531 | | - |
532 | | - /** |
533 | | - * Currently displayed placeholder text. This is a workaround for Chrome/FF |
534 | | - * automatic focus in overlays. |
535 | | - */ |
536 | | - currentDefaultText: '', |
537 | | - |
538 | | - // }}} |
539 | | - // {{{ templates |
540 | | - |
541 | | - /** |
542 | | - * Pull out the markup so it's easy to find |
543 | | - */ |
544 | | - templates: { |
545 | | - |
546 | | - /** |
547 | | - * The template for the whole block |
548 | | - */ |
549 | | - block: '\ |
550 | | - <form>\ |
551 | | - <div class="articleFeedbackv5-top-error"></div>\ |
552 | | - <div>\ |
553 | | - <div class="articleFeedbackv5-tags">\ |
554 | | - <ul></ul>\ |
555 | | - <div class="clear"></div>\ |
556 | | - </div>\ |
557 | | - <div class="clear"></div>\ |
558 | | - </div>\ |
559 | | - <div class="articleFeedbackv5-comment">\ |
560 | | - <textarea id="articleFeedbackv5-find-feedback" class="feedback-text" name="comment"></textarea>\ |
561 | | - </div>\ |
562 | | - <div class="articleFeedbackv5-disclosure">\ |
563 | | - <!-- <p class="articlefeedbackv5-shared-on-feedback"></p> -->\ |
564 | | - <p class="articlefeedbackv5-transparency-terms"></p>\ |
565 | | - </div>\ |
566 | | - <button class="articleFeedbackv5-submit" type="submit" disabled="disabled" id="articleFeedbackv5-submit-bttn">\ |
567 | | - <html:msg key="bucket2-form-submit" />\ |
568 | | - </button>\ |
569 | | - <div class="clear"></div>\ |
570 | | - </form>\ |
571 | | - ', |
572 | | - |
573 | | - |
574 | | - /** |
575 | | - * The template for a single tag |
576 | | - */ |
577 | | - tag: '\ |
578 | | - <li>\ |
579 | | - <span class="tag-selector"></span>\ |
580 | | - <label class="articleFeedbackv5-tag-label"></label>\ |
581 | | - <input name="articleFeedbackv5-bucket2-tag" type="radio" class="articleFeedbackv5-tag-input" />\ |
582 | | - <span class="clear"></span>\ |
583 | | - </li>\ |
584 | | - ' |
585 | | - |
586 | | - }, |
587 | | - |
588 | | - // }}} |
589 | | - // {{{ getTitle |
590 | | - |
591 | | - /** |
592 | | - * Gets the title |
593 | | - * |
594 | | - * @return string the title |
595 | | - */ |
596 | | - getTitle: function () { |
597 | | - return mw.msg( 'articlefeedbackv5-bucket2-title' ); |
598 | | - }, |
599 | | - |
600 | | - // }}} |
601 | | - // {{{ buildForm |
602 | | - |
603 | | - /** |
604 | | - * Builds the empty form |
605 | | - * |
606 | | - * @return Element the form |
607 | | - */ |
608 | | - buildForm: function () { |
609 | | - |
610 | | - // Start up the block to return |
611 | | - var $block = $( $.articleFeedbackv5.currentBucket().templates.block ); |
612 | | - |
613 | | - // Add the tags from the options |
614 | | - $block.find( '.articleFeedbackv5-tags ul' ).each( function () { |
615 | | - var info = $.articleFeedbackv5.currentBucket().tagInfo; |
616 | | - var tabIndex = 1; |
617 | | - for ( var i = 0; i < info.length; i++ ) { |
618 | | - var key = info[i]; |
619 | | - var comm_def_msg = 'articlefeedbackv5-bucket2-' + key + '-comment-default'; |
620 | | - $.articleFeedbackv5.currentBucket().commentDefault[key] = mw.msg( comm_def_msg ); |
621 | | - var label_msg = 'articlefeedbackv5-bucket2-' + key + '-label'; |
622 | | - var tag_id = 'articleFeedbackv5-bucket2-' + key; |
623 | | - var $tag = $( $.articleFeedbackv5.currentBucket().templates.tag ); |
624 | | - $tag.attr( 'rel', key ); |
625 | | - $tag.find( '.articleFeedbackv5-tag-input' ) |
626 | | - .attr( 'id', tag_id ) |
627 | | - .attr( 'tabindex', tabIndex++) |
628 | | - .val( key ); |
629 | | - $tag.find( '.articleFeedbackv5-tag-label' ) |
630 | | - .addClass( 'articleFeedbackv5-bucket2-' + key + '-label' ) |
631 | | - .attr( 'for', tag_id ) |
632 | | - .text( mw.msg( label_msg ) ); |
633 | | - $tag.appendTo( $( this ) ); |
634 | | - } |
635 | | - $( $.articleFeedbackv5.templates.clear ).appendTo( $( this ) ); |
636 | | - } ); |
637 | | - |
638 | | - // Fill in the disclosure text |
639 | | - $block.find( '.articlefeedbackv5-shared-on-feedback' ) |
640 | | - .html( $.articleFeedbackv5.buildLink( |
641 | | - 'articlefeedbackv5-shared-on-feedback', |
642 | | - { |
643 | | - href: mw.config.get( 'wgScript' ) + '?' + $.param( { |
644 | | - title: mw.config.get( 'wgPageName' ), |
645 | | - action: 'feedback' |
646 | | - } ), |
647 | | - text: 'articlefeedbackv5-shared-on-feedback-linktext', |
648 | | - target: '_blank' |
649 | | - } ) ); |
650 | | - $block.find( '.articlefeedbackv5-transparency-terms' ) |
651 | | - .html( $.articleFeedbackv5.buildLink( |
652 | | - 'articlefeedbackv5-transparency-terms', |
653 | | - { |
654 | | - href: mw.config.get( 'wgArticleFeedbackv5TermsPage' ), |
655 | | - text: 'articlefeedbackv5-transparency-terms-linktext', |
656 | | - target: '_blank' |
657 | | - } ) ); |
658 | | - |
659 | | - // Turn the submit into a slick button |
660 | | - $block.find( '.articleFeedbackv5-submit' ) |
661 | | - .button() |
662 | | - .addClass( 'ui-button-blue' ) |
663 | | - |
664 | | - return $block; |
665 | | - }, |
666 | | - |
667 | | - // }}} |
668 | | - // {{{ bindEvents |
669 | | - |
670 | | - /** |
671 | | - * Binds any events |
672 | | - * |
673 | | - * @param $block element the form block |
674 | | - */ |
675 | | - bindEvents: function ( $block ) { |
676 | | - |
677 | | - // Enable submission and switch out the comment default on toggle selection |
678 | | - $block.find( '.articleFeedbackv5-tags li' ) |
679 | | - .click( function ( e ) { |
680 | | - var new_val = $( this ).attr( 'rel' ); |
681 | | - $.articleFeedbackv5.currentBucket().selectTag( new_val ); |
682 | | - $.articleFeedbackv5.enableSubmission( true ); |
683 | | - } ); |
684 | | - |
685 | | - // Clear out the question on focus |
686 | | - $block.find( '.articleFeedbackv5-comment textarea' ) |
687 | | - .focus( function () { |
688 | | - if ( $( this ).val() == $.articleFeedbackv5.currentBucket().currentDefaultText ) { |
689 | | - $( this ).val( '' ); |
690 | | - $(this).addClass( 'active' ); |
691 | | - } |
692 | | - }) |
693 | | - .keyup ( function () { |
694 | | - if( $( this ).val().length > 0 ) { |
695 | | - $.articleFeedbackv5.enableSubmission( true ); |
696 | | - } |
697 | | - } ) |
698 | | - .blur( function () { |
699 | | - var key = $.articleFeedbackv5.find( '.articleFeedbackv5-tags input[checked]' ).val(); |
700 | | - var def_msg = $.articleFeedbackv5.currentBucket().commentDefault[key]; |
701 | | - if ( $( this ).val() == '' ) { |
702 | | - $( this ).val( def_msg ); |
703 | | - $(this).removeClass( 'active' ); |
704 | | - } else { |
705 | | - $.articleFeedbackv5.enableSubmission( true ); |
706 | | - } |
707 | | - } ); |
708 | | - |
709 | | - // Attach the submit |
710 | | - $block.find( '.articleFeedbackv5-submit' ) |
711 | | - .click( function ( e ) { |
712 | | - e.preventDefault(); |
713 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-submit-' + |
714 | | - ( $.articleFeedbackv5.inDialog ? 'overlay' : 'bottom' ) ); |
715 | | - $.articleFeedbackv5.submitForm(); |
716 | | - } ); |
717 | | - |
718 | | - }, |
719 | | - |
720 | | - // }}} |
721 | | - // {{{ afterBuild |
722 | | - |
723 | | - /** |
724 | | - * Handles any setup that has to be done once the markup is in the |
725 | | - * holder |
726 | | - */ |
727 | | - afterBuild: function () { |
728 | | - // Default to 'suggestion' |
729 | | - $.articleFeedbackv5.currentBucket().selectTag( 'suggestion' ); |
730 | | - }, |
731 | | - |
732 | | - // }}} |
733 | | - // {{{ selectTag |
734 | | - |
735 | | - /** |
736 | | - * Selects a particular tag |
737 | | - * |
738 | | - * @param tag string the tag |
739 | | - */ |
740 | | - selectTag: function ( tag ) { |
741 | | - var $c = $.articleFeedbackv5.find( '.articleFeedbackv5-comment textarea' ); |
742 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-tags li' ).each( function () { |
743 | | - var key = $( this ).attr( 'rel' ); |
744 | | - if ( key == tag ) { |
745 | | - // Set checked |
746 | | - $( this ).find( 'input' ).attr( 'checked', 'checked' ); |
747 | | - // Set active |
748 | | - $( this ).addClass( 'active' ); |
749 | | - // Change out comment text |
750 | | - var empty = false; |
751 | | - if ( $c.val() == '') { |
752 | | - empty = true; |
753 | | - } else { |
754 | | - for ( var t in $.articleFeedbackv5.currentBucket().commentDefault ) { |
755 | | - if ( $c.val() == $.articleFeedbackv5.currentBucket().commentDefault[t] ) { |
756 | | - empty = true; |
757 | | - } |
758 | | - } |
759 | | - } |
760 | | - if ( empty ) { |
761 | | - $c.val( $.articleFeedbackv5.currentBucket().commentDefault[key] ); |
762 | | - // Store default text, workaround for overlay bug in Chrome/FF |
763 | | - $.articleFeedbackv5.currentBucket().currentDefaultText = $.articleFeedbackv5.currentBucket().commentDefault[key]; |
764 | | - } |
765 | | - } else { |
766 | | - // Clear checked |
767 | | - $( this ).find( 'input' ).removeAttr( 'checked' ); |
768 | | - // Remove active |
769 | | - $( this ).removeClass( 'active' ); |
770 | | - } |
771 | | - } ); |
772 | | - }, |
773 | | - |
774 | | - // }}} |
775 | | - // {{{ getFormData |
776 | | - |
777 | | - /** |
778 | | - * Pulls down form data |
779 | | - * |
780 | | - * @return object the form data |
781 | | - */ |
782 | | - getFormData: function () { |
783 | | - var data = {}; |
784 | | - data.tag = $.articleFeedbackv5.find( '.articleFeedbackv5-tags input[checked]' ).val(); |
785 | | - data.comment = $.articleFeedbackv5.find( '.articleFeedbackv5-comment textarea' ).val(); |
786 | | - for ( var t in $.articleFeedbackv5.currentBucket().commentDefault ) { |
787 | | - if ( data.comment == $.articleFeedbackv5.currentBucket().commentDefault[t] ) { |
788 | | - data.comment = ''; |
789 | | - } |
790 | | - } |
791 | | - return data; |
792 | | - }, |
793 | | - |
794 | | - // }}} |
795 | | - // {{{ localValidation |
796 | | - |
797 | | - /** |
798 | | - * Performs any local validation |
799 | | - * |
800 | | - * @param object formdata the form data |
801 | | - * @return mixed if ok, false; otherwise, an object as { 'field name' : 'message' } |
802 | | - */ |
803 | | - localValidation: function ( formdata ) { |
804 | | - var error = {}; |
805 | | - var ok = true; |
806 | | - if ( !( 'comment' in formdata ) || formdata.comment == '' ) { |
807 | | - $.articleFeedbackv5.enableSubmission( false ); |
808 | | - error.nofeedback = mw.msg( 'articlefeedbackv5-error-nofeedback' ); |
809 | | - ok = false; |
810 | | - } |
811 | | - return ok ? false : error; |
812 | | - } |
813 | | - |
814 | | - // }}} |
815 | | - |
816 | | - }, |
817 | | - |
818 | | - // }}} |
819 | | - // {{{ Bucket 3 |
820 | | - |
821 | | - /** |
822 | | - * Bucket 3: Help Improve This Article |
823 | | - */ |
824 | | - '3': { |
825 | | - |
826 | | - // {{{ templates |
827 | | - |
828 | | - /** |
829 | | - * Pull out the markup so it's easy to find |
830 | | - */ |
831 | | - templates: { |
832 | | - |
833 | | - /** |
834 | | - * The template for the whole block |
835 | | - */ |
836 | | - block: '\ |
837 | | - <form>\ |
838 | | - <div class="articleFeedbackv5-top-error"></div>\ |
839 | | - <div>\ |
840 | | - <p class="instructions-left"><html:msg key="bucket3-rating-question" /></p>\ |
841 | | - <div class="articleFeedbackv5-rating articleFeedbackv5-rating-new">\ |
842 | | - <input type="hidden" name="rating" value="0">\ |
843 | | - <div class="bucket3-rating">\ |
844 | | - <div class="articleFeedbackv5-rating-labels articleFeedbackv5-visibleWith-form">\ |
845 | | - <div class="articleFeedbackv5-rating-label" rel="1"></div>\ |
846 | | - <div class="articleFeedbackv5-rating-label" rel="2"></div>\ |
847 | | - <div class="articleFeedbackv5-rating-label" rel="3"></div>\ |
848 | | - <div class="articleFeedbackv5-rating-label" rel="4"></div>\ |
849 | | - <div class="articleFeedbackv5-rating-label" rel="5"></div>\ |
850 | | - <div class="articleFeedbackv5-rating-clear" style="display: none;"></div>\ |
851 | | - </div>\ |
852 | | - </div>\ |
853 | | - <div style="clear:both;"></div>\ |
854 | | - <div class="articleFeedbackv5-visibleWith-form">\ |
855 | | - <div class="articleFeedbackv5-rating-tooltip"></div>\ |
856 | | - </div>\ |
857 | | - </div>\ |
858 | | - <div class="clear"></div>\ |
859 | | - </div>\ |
860 | | - <div class="articleFeedbackv5-comment">\ |
861 | | - <textarea id="articleFeedbackv5-find-feedback" class="feedback-text" name="comment"></textarea>\ |
862 | | - </div>\ |
863 | | - <div class="articleFeedbackv5-disclosure">\ |
864 | | - <!-- <p class="articlefeedbackv5-shared-on-feedback"></p> -->\ |
865 | | - <p class="articlefeedbackv5-transparency-terms"></p>\ |
866 | | - </div>\ |
867 | | - <button class="articleFeedbackv5-submit" type="submit" disabled="disabled" id="articleFeedbackv5-submit-bttn"><html:msg key="bucket3-form-submit" /></button>\ |
868 | | - <div class="clear"></div>\ |
869 | | - </form>\ |
870 | | - ' |
871 | | - |
872 | | - }, |
873 | | - |
874 | | - // }}} |
875 | | - // {{{ getTitle |
876 | | - |
877 | | - /** |
878 | | - * Gets the title |
879 | | - * |
880 | | - * @return string the title |
881 | | - */ |
882 | | - getTitle: function () { |
883 | | - return mw.msg( 'articlefeedbackv5-bucket3-title' ); |
884 | | - }, |
885 | | - |
886 | | - // }}} |
887 | | - // {{{ buildForm |
888 | | - |
889 | | - /** |
890 | | - * Builds the empty form |
891 | | - * |
892 | | - * @return Element the form |
893 | | - */ |
894 | | - buildForm: function () { |
895 | | - |
896 | | - // Start up the block to return |
897 | | - var $block = $( $.articleFeedbackv5.currentBucket().templates.block ); |
898 | | - |
899 | | - // Fill in the rating clear title |
900 | | - var clear_msg = mw.msg( 'articlefeedbackv5-bucket3-clear-rating' ); |
901 | | - $block.find( '.articleFeedbackv5-rating-clear' ) |
902 | | - .attr( 'title', clear_msg ); |
903 | | - |
904 | | - // Activate tooltips |
905 | | - $block.find( '[title]' ) |
906 | | - .tipsy( { |
907 | | - 'gravity': 'sw', |
908 | | - 'center': false, |
909 | | - 'fade': true, |
910 | | - 'delayIn': 300, |
911 | | - 'delayOut': 100 |
912 | | - } ); |
913 | | - |
914 | | - // Fill in the disclosure text |
915 | | - $block.find( '.articlefeedbackv5-shared-on-feedback' ) |
916 | | - .html( $.articleFeedbackv5.buildLink( |
917 | | - 'articlefeedbackv5-shared-on-feedback', |
918 | | - { |
919 | | - href: mw.config.get( 'wgScript' ) + '?' + $.param( { |
920 | | - title: mw.config.get( 'wgPageName' ), |
921 | | - action: 'feedback' |
922 | | - } ), |
923 | | - text: 'articlefeedbackv5-shared-on-feedback-linktext', |
924 | | - target: '_blank' |
925 | | - } ) ); |
926 | | - $block.find( '.articlefeedbackv5-transparency-terms' ) |
927 | | - .html( $.articleFeedbackv5.buildLink( |
928 | | - 'articlefeedbackv5-transparency-terms', |
929 | | - { |
930 | | - href: mw.config.get( 'wgArticleFeedbackv5TermsPage' ), |
931 | | - text: 'articlefeedbackv5-transparency-terms-linktext', |
932 | | - target: '_blank' |
933 | | - } ) ); |
934 | | - |
935 | | - // Start with a default comment |
936 | | - $block.find( '.articleFeedbackv5-comment textarea' ) |
937 | | - .val( mw.msg( 'articlefeedbackv5-bucket3-comment-default' ) ); |
938 | | - |
939 | | - // Turn the submit into a slick button |
940 | | - $block.find( '.articleFeedbackv5-submit' ) |
941 | | - .button() |
942 | | - .addClass( 'ui-button-blue' ) |
943 | | - |
944 | | - return $block; |
945 | | - }, |
946 | | - |
947 | | - // }}} |
948 | | - // {{{ bindEvents |
949 | | - |
950 | | - /** |
951 | | - * Binds any events |
952 | | - * |
953 | | - * @param $block element the form block |
954 | | - */ |
955 | | - bindEvents: function ( $block ) { |
956 | | - |
957 | | - // Set up rating behavior |
958 | | - var rlabel = $block.find( '.articleFeedbackv5-rating-label' ); |
959 | | - rlabel.hover( function () { |
960 | | - // mouse on |
961 | | - var $el = $( this ); |
962 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
963 | | - $el.addClass( 'articleFeedbackv5-rating-label-hover-head' ); |
964 | | - $el.prevAll( '.articleFeedbackv5-rating-label' ) |
965 | | - .addClass( 'articleFeedbackv5-rating-label-hover-tail' ); |
966 | | - $rating.find( '.articleFeedbackv5-rating-tooltip' ) |
967 | | - .text( mw.msg( 'articlefeedbackv5-bucket3-rating-tooltip-' + $el.attr( 'rel' ) ) ) |
968 | | - .show(); |
969 | | - }, function () { |
970 | | - // mouse off |
971 | | - var $el = $( this ); |
972 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
973 | | - $el.removeClass( 'articleFeedbackv5-rating-label-hover-head' ); |
974 | | - $el.prevAll( '.articleFeedbackv5-rating-label' ) |
975 | | - .removeClass( 'articleFeedbackv5-rating-label-hover-tail' ); |
976 | | - $rating.find( '.articleFeedbackv5-rating-tooltip' ) |
977 | | - .hide(); |
978 | | - $.articleFeedbackv5.currentBucket().updateRating( $rating ); |
979 | | - }); |
980 | | - rlabel.mousedown( function () { |
981 | | - $.articleFeedbackv5.enableSubmission( true ); |
982 | | - var $ui = $.articleFeedbackv5.find( 'articleFeedbackv5-ui' ); |
983 | | - if ( $ui.hasClass( 'articleFeedbackv5-expired' ) ) { |
984 | | - // Changing one means the rest will get submitted too |
985 | | - $ui.removeClass( 'articleFeedbackv5-expired' ); |
986 | | - $ui.find( '.articleFeedbackv5-rating' ) |
987 | | - .addClass( 'articleFeedbackv5-rating-new' ); |
988 | | - } |
989 | | - var $el = $( this ); |
990 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
991 | | - $rating.addClass( 'articleFeedbackv5-rating-new' ); |
992 | | - $rating.find( 'input:hidden' ).val( $el.attr( 'rel' ) ); |
993 | | - $el.addClass( 'articleFeedbackv5-rating-label-down' ); |
994 | | - $el.nextAll() |
995 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
996 | | - $el.parent().find( '.articleFeedbackv5-rating-clear' ).show(); |
997 | | - } ); |
998 | | - rlabel.mouseup( function () { |
999 | | - $(this).removeClass( 'articleFeedbackv5-rating-label-down' ); |
1000 | | - } ); |
1001 | | - |
1002 | | - // Icon to clear out the ratings |
1003 | | - $block.find( '.articleFeedbackv5-rating-clear' ) |
1004 | | - .click( function () { |
1005 | | - $.articleFeedbackv5.enableSubmission( true ); |
1006 | | - $(this).hide(); |
1007 | | - var $rating = $(this).closest( '.articleFeedbackv5-rating' ); |
1008 | | - $rating.find( 'input:hidden' ).val( 0 ); |
1009 | | - $.articleFeedbackv5.currentBucket().updateRating( $rating ); |
1010 | | - } ); |
1011 | | - |
1012 | | - // Clear out the question on focus |
1013 | | - $block.find( '.articleFeedbackv5-comment textarea' ) |
1014 | | - .focus( function () { |
1015 | | - var def_msg = mw.msg( 'articlefeedbackv5-bucket3-comment-default' ); |
1016 | | - if ( $( this ).val() == def_msg ) { |
1017 | | - $( this ).val( '' ); |
1018 | | - $(this).addClass( 'active' ); |
1019 | | - } |
1020 | | - }) |
1021 | | - .keyup ( function () { |
1022 | | - if( $( this ).val().length > 0 ) { |
1023 | | - $.articleFeedbackv5.enableSubmission( true ); |
1024 | | - } |
1025 | | - } ) |
1026 | | - .blur( function () { |
1027 | | - var def_msg = mw.msg( 'articlefeedbackv5-bucket3-comment-default' ); |
1028 | | - if ( $( this ).val() == '' ) { |
1029 | | - $( this ).val( def_msg ); |
1030 | | - $(this).removeClass( 'active' ); |
1031 | | - } else { |
1032 | | - $.articleFeedbackv5.enableSubmission( true ); |
1033 | | - } |
1034 | | - } ); |
1035 | | - |
1036 | | - |
1037 | | - // Attach the submit |
1038 | | - $block.find( '.articleFeedbackv5-submit' ) |
1039 | | - .click( function ( e ) { |
1040 | | - e.preventDefault(); |
1041 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + 'submit-' + |
1042 | | - ( $.articleFeedbackv5.inDialog ? 'overlay' : 'bottom' ) ); |
1043 | | - $.articleFeedbackv5.submitForm(); |
1044 | | - } ); |
1045 | | - |
1046 | | - }, |
1047 | | - |
1048 | | - // }}} |
1049 | | - // {{{ updateRating |
1050 | | - |
1051 | | - /** |
1052 | | - * Updates the stars to match the associated hidden field |
1053 | | - * |
1054 | | - * @param $rating the rating block |
1055 | | - */ |
1056 | | - updateRating: function ( $rating ) { |
1057 | | - $rating.find( '.articleFeedbackv5-rating-label' ) |
1058 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
1059 | | - var val = $rating.find( 'input:hidden' ).val(); |
1060 | | - var $label = $rating.find( '.articleFeedbackv5-rating-label[rel="' + val + '"]' ); |
1061 | | - if ( $label.length ) { |
1062 | | - $label.prevAll( '.articleFeedbackv5-rating-label' ) |
1063 | | - .add( $label ) |
1064 | | - .addClass( 'articleFeedbackv5-rating-label-full' ); |
1065 | | - $label.nextAll( '.articleFeedbackv5-rating-label' ) |
1066 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
1067 | | - $rating.find( '.articleFeedbackv5-rating-clear' ).show(); |
1068 | | - } else { |
1069 | | - $rating.find( '.articleFeedbackv5-rating-clear' ).hide(); |
1070 | | - } |
1071 | | - }, |
1072 | | - |
1073 | | - // }}} |
1074 | | - // {{{ getFormData |
1075 | | - |
1076 | | - /** |
1077 | | - * Pulls down form data |
1078 | | - * |
1079 | | - * @return object the form data |
1080 | | - */ |
1081 | | - getFormData: function () { |
1082 | | - var data = {}; |
1083 | | - var rating = $.articleFeedbackv5.find( '.articleFeedbackv5-rating input:hidden' ).val(); |
1084 | | - if ( '0' != rating ) { |
1085 | | - data.rating = rating; |
1086 | | - } |
1087 | | - data.comment = $.articleFeedbackv5.find( '.articleFeedbackv5-comment textarea' ).val(); |
1088 | | - if ( data.comment == mw.msg( 'articlefeedbackv5-bucket3-comment-default' ) ) { |
1089 | | - data.comment = ''; |
1090 | | - } |
1091 | | - return data; |
1092 | | - }, |
1093 | | - |
1094 | | - // }}} |
1095 | | - // {{{ localValidation |
1096 | | - |
1097 | | - /** |
1098 | | - * Performs any local validation |
1099 | | - * |
1100 | | - * @param object formdata the form data |
1101 | | - * @return mixed if ok, false; otherwise, an object as { 'field name' : 'message' } |
1102 | | - */ |
1103 | | - localValidation: function ( formdata ) { |
1104 | | - var error = {}; |
1105 | | - var ok = true; |
1106 | | - if ( ( !( 'comment' in formdata ) || formdata.comment == '' ) |
1107 | | - && ( !( 'rating' in formdata ) || formdata.rating < 1 ) ) { |
1108 | | - $.articleFeedbackv5.enableSubmission( false ); |
1109 | | - error.nofeedback = mw.msg( 'articlefeedbackv5-error-nofeedback' ); |
1110 | | - ok = false; |
1111 | | - } |
1112 | | - return ok ? false : error; |
1113 | | - } |
1114 | | - |
1115 | | - // }}} |
1116 | | - |
1117 | | - }, |
1118 | | - |
1119 | | - // }}} |
1120 | | - // {{{ Bucket 4 |
1121 | | - |
1122 | | - /** |
1123 | | - * Bucket 4: Help Improve This Article |
1124 | | - */ |
1125 | | - '4': { |
1126 | | - |
1127 | | - // {{{ templates |
1128 | | - |
1129 | | - /** |
1130 | | - * Pull out the markup so it's easy to find |
1131 | | - */ |
1132 | | - templates: { |
1133 | | - |
1134 | | - /** |
1135 | | - * The template for the whole block |
1136 | | - */ |
1137 | | - block: '\ |
1138 | | - <div>\ |
1139 | | - <div class="form-row articleFeedbackv5-bucket4-toggle">\ |
1140 | | - <p class="sub-header"><strong><html:msg key="bucket4-subhead" /></strong></p>\ |
1141 | | - <p class="instructions-left"><html:msg key="bucket4-teaser-line1" /><br />\ |
1142 | | - <html:msg key="bucket4-teaser-line2" /></p>\ |
1143 | | - </div>\ |
1144 | | - <div class="articleFeedbackv5-disclosure">\ |
1145 | | - <p><a class="articleFeedbackv5-learn-to-edit" target="_blank"><html:msg key="bucket4-learn-to-edit" /> »</a></p>\ |
1146 | | - </div>\ |
1147 | | - <a class="articleFeedbackv5-submit" id="articleFeedbackv5-submit-bttn"><html:msg key="bucket4-form-submit" /></a>\ |
1148 | | - <div class="clear"></div>\ |
1149 | | - </div>\ |
1150 | | - ' |
1151 | | - |
1152 | | - }, |
1153 | | - |
1154 | | - // }}} |
1155 | | - // {{{ getTitle |
1156 | | - |
1157 | | - /** |
1158 | | - * Gets the title |
1159 | | - * |
1160 | | - * @return string the title |
1161 | | - */ |
1162 | | - getTitle: function () { |
1163 | | - return mw.msg( 'articlefeedbackv5-bucket4-title' ); |
1164 | | - }, |
1165 | | - |
1166 | | - // }}} |
1167 | | - // {{{ buildForm |
1168 | | - |
1169 | | - /** |
1170 | | - * Builds the empty form |
1171 | | - * |
1172 | | - * @return Element the form |
1173 | | - */ |
1174 | | - buildForm: function () { |
1175 | | - |
1176 | | - // Start up the block to return |
1177 | | - var $block = $( $.articleFeedbackv5.currentBucket().templates.block ); |
1178 | | - |
1179 | | - // Fill in the learn to edit link |
1180 | | - $block.find( '.articleFeedbackv5-learn-to-edit' ) |
1181 | | - .attr( 'href', mw.config.get( 'wgArticleFeedbackv5LearnToEdit' ) ); |
1182 | | - |
1183 | | - // Fill in the edit link |
1184 | | - var edit_track_id = $.articleFeedbackv5.bucketName() + '-button_click-' + |
1185 | | - ( $.articleFeedbackv5.inDialog ? 'overlay' : 'bottom' ); |
1186 | | - $block.find( '.articleFeedbackv5-cta-button' ) |
1187 | | - .attr( 'href', $.articleFeedbackv5.editUrl( edit_track_id ) ); |
1188 | | - |
1189 | | - // Turn the submit into a slick button |
1190 | | - $block.find( '.articleFeedbackv5-submit' ) |
1191 | | - .button() |
1192 | | - .addClass( 'ui-button-blue' ) |
1193 | | - |
1194 | | - return $block; |
1195 | | - }, |
1196 | | - |
1197 | | - // }}} |
1198 | | - // {{{ afterBuild |
1199 | | - |
1200 | | - /** |
1201 | | - * Handles any setup that has to be done once the markup is in the |
1202 | | - * holder |
1203 | | - */ |
1204 | | - afterBuild: function () { |
1205 | | - // Set a custom message |
1206 | | - $.articleFeedbackv5.$holder |
1207 | | - .add( $.articleFeedbackv5.$dialog) |
1208 | | - .find( '.articleFeedbackv5-tooltip-info' ) |
1209 | | - .text( mw.msg( 'articlefeedbackv5-bucket4-help-tooltip-info' ) ); |
1210 | | - } |
1211 | | - |
1212 | | - // }}} |
1213 | | - |
1214 | | - }, |
1215 | | - |
1216 | | - // }}} |
1217 | | - // {{{ Bucket 5 |
1218 | | - |
1219 | | - /** |
1220 | | - * Bucket 5: Old ratings form |
1221 | | - */ |
1222 | | - '5': { |
1223 | | - |
1224 | | - // {{{ properties |
1225 | | - |
1226 | | - /** |
1227 | | - * The ratings right now are coming from the config, but they really |
1228 | | - * can't be configured. Eventually, these should just be hardcoded. |
1229 | | - */ |
1230 | | - ratingInfo: mw.config.get( 'wgArticleFeedbackv5Bucket5RatingCategories' ), |
1231 | | - |
1232 | | - /** |
1233 | | - * Only certain users can see the expertise checkboxes and email |
1234 | | - * (bucketed on init) |
1235 | | - */ |
1236 | | - showOptions: false, |
1237 | | - |
1238 | | - /** |
1239 | | - * Whether we need to load the aggregate ratings the next time the button is |
1240 | | - * clicked. This is initially set to true, turned to false after the first |
1241 | | - * time, then turned back to true on form submission, in case the user wants |
1242 | | - * to go back and see the ratings with theirs included. |
1243 | | - */ |
1244 | | - loadAggregate: true, |
1245 | | - |
1246 | | - /** |
1247 | | - * Whether we're currently looking at the report |
1248 | | - */ |
1249 | | - inReport: false, |
1250 | | - |
1251 | | - // }}} |
1252 | | - // {{{ templates |
1253 | | - |
1254 | | - /** |
1255 | | - * Pull out the markup so it's easy to find |
1256 | | - */ |
1257 | | - templates: { |
1258 | | - |
1259 | | - /** |
1260 | | - * The template for the whole block |
1261 | | - */ |
1262 | | - block: '\ |
1263 | | - <form id="articleFeedbackv5-bucket5">\ |
1264 | | - <div class="articleFeedbackv5-switch articleFeedbackv5-switch-report articleFeedbackv5-visibleWith-form" rel="report"><html:msg key="bucket5-report-switch-label" /></div>\ |
1265 | | - <div class="articleFeedbackv5-switch articleFeedbackv5-switch-form articleFeedbackv5-visibleWith-report" rel="form"><html:msg key="bucket5-form-switch-label" /></div>\ |
1266 | | - <div class="articleFeedbackv5-explanation articleFeedbackv5-visibleWith-form"><a class="articleFeedbackv5-explanation-link"><html:msg key="bucket5-form-panel-explanation" /></a></div>\ |
1267 | | - <div class="articleFeedbackv5-description articleFeedbackv5-visibleWith-report"><html:msg key="bucket5-report-panel-description" /></div>\ |
1268 | | - <div style="clear:both;"></div>\ |
1269 | | - <div class="articleFeedbackv5-ratings"></div>\ |
1270 | | - <div style="clear:both;"></div>\ |
1271 | | - <div class="articleFeedbackv5-options">\ |
1272 | | - <div class="articleFeedbackv5-expertise articleFeedbackv5-visibleWith-form" >\ |
1273 | | - <input type="checkbox" value="general" disabled="disabled" /><label class="articleFeedbackv5-expertise-disabled"><html:msg key="bucket5-form-panel-expertise" /></label>\ |
1274 | | - <div class="articleFeedbackv5-expertise-options">\ |
1275 | | - <div><input type="checkbox" value="studies" /><label><html:msg key="bucket5-form-panel-expertise-studies" /></label></div>\ |
1276 | | - <div><input type="checkbox" value="profession" /><label><html:msg key="bucket5-form-panel-expertise-profession" /></label></div>\ |
1277 | | - <div><input type="checkbox" value="hobby" /><label><html:msg key="bucket5-form-panel-expertise-hobby" /></label></div>\ |
1278 | | - <div><input type="checkbox" value="other" /><label><html:msg key="bucket5-form-panel-expertise-other" /></label></div>\ |
1279 | | - <div class="articleFeedbackv5-helpimprove">\ |
1280 | | - <input type="checkbox" value="helpimprove-email" />\ |
1281 | | - <label><html:msg key="bucket5-form-panel-helpimprove" /></label>\ |
1282 | | - <input type="text" placeholder="" class="articleFeedbackv5-helpimprove-email" />\ |
1283 | | - <div class="articleFeedbackv5-helpimprove-note"></div>\ |
1284 | | - </div>\ |
1285 | | - </div>\ |
1286 | | - </div>\ |
1287 | | - <div style="clear:both;"></div>\ |
1288 | | - </div>\ |
1289 | | - <button class="articleFeedbackv5-submit articleFeedbackv5-visibleWith-form" id="articleFeedbackv5-submit-bttn5" type="submit" disabled="disabled"><html:msg key="bucket5-form-panel-submit" /></button>\ |
1290 | | - <div class="articleFeedbackv5-pending articleFeedbackv5-visibleWith-form"><span><html:msg key="bucket5-form-panel-pending" /></span></div>\ |
1291 | | - <div style="clear:both;"></div>\ |
1292 | | - <div class="articleFeedbackv5-notices articleFeedbackv5-visibleWith-form">\ |
1293 | | - <div class="articleFeedbackv5-expiry">\ |
1294 | | - <div class="articleFeedbackv5-expiry-title"><html:msg key="bucket5-form-panel-expiry-title" /></div>\ |
1295 | | - <div class="articleFeedbackv5-expiry-message"><html:msg key="bucket5-form-panel-expiry-message" /></div>\ |
1296 | | - </div>\ |
1297 | | - </div>\ |
1298 | | - </form>\ |
1299 | | - ', |
1300 | | - |
1301 | | - |
1302 | | - /** |
1303 | | - * The template for a single rating |
1304 | | - */ |
1305 | | - rating: '\ |
1306 | | - <div class="articleFeedbackv5-rating">\ |
1307 | | - <div class="articleFeedbackv5-label"></div>\ |
1308 | | - <input type="hidden" name="" />\ |
1309 | | - <div class="articleFeedbackv5-rating-labels articleFeedbackv5-visibleWith-form">\ |
1310 | | - <div class="articleFeedbackv5-rating-label" rel="1"></div>\ |
1311 | | - <div class="articleFeedbackv5-rating-label" rel="2"></div>\ |
1312 | | - <div class="articleFeedbackv5-rating-label" rel="3"></div>\ |
1313 | | - <div class="articleFeedbackv5-rating-label" rel="4"></div>\ |
1314 | | - <div class="articleFeedbackv5-rating-label" rel="5"></div>\ |
1315 | | - <div class="articleFeedbackv5-rating-clear"></div>\ |
1316 | | - </div>\ |
1317 | | - <div class="articleFeedbackv5-visibleWith-form">\ |
1318 | | - <div class="articleFeedbackv5-rating-tooltip"></div>\ |
1319 | | - </div>\ |
1320 | | - <div class="articleFeedbackv5-rating-average articleFeedbackv5-visibleWith-report"></div>\ |
1321 | | - <div class="articleFeedbackv5-rating-meter articleFeedbackv5-visibleWith-report"><div></div></div>\ |
1322 | | - <div class="articleFeedbackv5-rating-count articleFeedbackv5-visibleWith-report"></div>\ |
1323 | | - <div style="clear:both;"></div>\ |
1324 | | - </div>\ |
1325 | | - ' |
1326 | | - |
1327 | | - }, |
1328 | | - |
1329 | | - // }}} |
1330 | | - // {{{ init |
1331 | | - |
1332 | | - /** |
1333 | | - * Initializes the bucket |
1334 | | - */ |
1335 | | - init: function () { |
1336 | | - var opt = mw.user.bucket( 'ext.articleFeedbackv5-options', mw.config.get( 'wgArticleFeedbackv5Options' ) ) |
1337 | | - $.articleFeedbackv5.currentBucket().showOptions = ( 'show' === opt ); |
1338 | | - }, |
1339 | | - |
1340 | | - // }}} |
1341 | | - // {{{ getTitle |
1342 | | - |
1343 | | - /** |
1344 | | - * Gets the title |
1345 | | - * |
1346 | | - * @return string the title |
1347 | | - */ |
1348 | | - getTitle: function () { |
1349 | | - if ( $.articleFeedbackv5.buckets[5].inReport ) { |
1350 | | - return mw.msg( 'articlefeedbackv5-bucket5-report-panel-title' ); |
1351 | | - } else { |
1352 | | - return mw.msg( 'articlefeedbackv5-bucket5-form-panel-title' ); |
1353 | | - } |
1354 | | - }, |
1355 | | - |
1356 | | - // }}} |
1357 | | - // {{{ buildForm |
1358 | | - |
1359 | | - /** |
1360 | | - * Builds the empty form |
1361 | | - * |
1362 | | - * @return Element the form |
1363 | | - */ |
1364 | | - buildForm: function () { |
1365 | | - |
1366 | | - // Start up the block to return |
1367 | | - var $block = $( $.articleFeedbackv5.currentBucket().templates.block ); |
1368 | | - |
1369 | | - // Add the ratings from the options |
1370 | | - $block.find( '.articleFeedbackv5-ratings' ).each( function () { |
1371 | | - var info = $.articleFeedbackv5.currentBucket().ratingInfo; |
1372 | | - for ( var i = 0; i < info.length; i++ ) { |
1373 | | - var key = info[i]; |
1374 | | - var tip_msg = 'articlefeedbackv5-bucket5-' + key + '-tip'; |
1375 | | - var label_msg = 'articlefeedbackv5-bucket5-' + key + '-label'; |
1376 | | - var $rtg = $( $.articleFeedbackv5.currentBucket().templates.rating ); |
1377 | | - $rtg.attr( 'rel', key ); |
1378 | | - $rtg.find( '.articleFeedbackv5-label' ) |
1379 | | - .attr( 'title', mw.msg( tip_msg ) ) |
1380 | | - .text( mw.msg( label_msg ) ); |
1381 | | - $rtg.find( '.articleFeedbackv5-rating-clear' ) |
1382 | | - .attr( 'title', mw.msg( 'articlefeedbackv5-bucket5-form-panel-clear' ) ); |
1383 | | - $rtg.appendTo( $(this) ); |
1384 | | - } |
1385 | | - } ); |
1386 | | - |
1387 | | - // Fill in the link to the What's This page |
1388 | | - $block.find( '.articleFeedbackv5-explanation-link' ) |
1389 | | - .attr( |
1390 | | - 'href', |
1391 | | - mw.util.wikiGetlink( mw.config.get( 'wgArticleFeedbackv5WhatsThisPage' ) ) // TODO: Make this work |
1392 | | - ); |
1393 | | - |
1394 | | - // Fill in the Help Improve message and links |
1395 | | - $block.find( '.articleFeedbackv5-helpimprove-note' ) |
1396 | | - .html( $.articleFeedbackv5.buildLink( |
1397 | | - 'articlefeedbackv5-bucket5-form-panel-helpimprove-note', |
1398 | | - { |
1399 | | - href: mw.config.get( 'wgArticleFeedbackv5TermsPage' ), // TODO: Make this work |
1400 | | - text: 'articlefeedbackv5-bucket5-form-panel-helpimprove-privacy', |
1401 | | - target: '_blank' |
1402 | | - } |
1403 | | - ) ); |
1404 | | - |
1405 | | - $block.find( '.articleFeedbackv5-helpimprove-email' ) |
1406 | | - .attr( 'placeholder', mw.msg( 'articlefeedbackv5-bucket5-form-panel-helpimprove-email-placeholder' ) ) |
1407 | | - .placeholder(); // back. compat. for older browsers |
1408 | | - |
1409 | | - // Activate tooltips |
1410 | | - $block.find( '[title]' ) |
1411 | | - .tipsy( { |
1412 | | - 'gravity': 'sw', |
1413 | | - 'center': false, |
1414 | | - 'fade': true, |
1415 | | - 'delayIn': 300, |
1416 | | - 'delayOut': 100 |
1417 | | - } ); |
1418 | | - |
1419 | | - // Set id and for on expertise checkboxes |
1420 | | - $block.find( '.articleFeedbackv5-expertise input:checkbox' ) |
1421 | | - .each( function () { |
1422 | | - var id = 'articleFeedbackv5-expertise-' + $(this).attr( 'value' ); |
1423 | | - $(this).attr( 'id', id ); |
1424 | | - $(this).next().attr( 'for', id ); |
1425 | | - } ); |
1426 | | - $block.find( '.articleFeedbackv5-helpimprove > input:checkbox' ) |
1427 | | - .each( function () { |
1428 | | - var id = 'articleFeedbackv5-expertise-' + $(this).attr( 'value' ); |
1429 | | - $(this).attr( 'id', id ); |
1430 | | - $(this).next().attr( 'for', id ); |
1431 | | - }) |
1432 | | - |
1433 | | - // Turn the submit into a slick button |
1434 | | - $block.find( '.articleFeedbackv5-submit' ) |
1435 | | - .button() |
1436 | | - .addClass( 'ui-button-blue' ) |
1437 | | - |
1438 | | - // Hide report elements initially |
1439 | | - $block.find( '.articleFeedbackv5-visibleWith-report' ).hide(); |
1440 | | - |
1441 | | - // Name the hidden rating fields |
1442 | | - $block.find( '.articleFeedbackv5-rating' ) |
1443 | | - .each( function () { |
1444 | | - $(this).find( 'input:hidden' ) .attr( 'name', $(this).attr( 'rel' ) ); |
1445 | | - } ); |
1446 | | - |
1447 | | - // Hide the additional options, if the user's in a bucket that |
1448 | | - // requires it |
1449 | | - if ( !$.articleFeedbackv5.currentBucket().showOptions ) { |
1450 | | - $block.find( '.articleFeedbackv5-options' ).hide(); |
1451 | | - } |
1452 | | - |
1453 | | - return $block; |
1454 | | - }, |
1455 | | - |
1456 | | - // }}} |
1457 | | - // {{{ bindEvents |
1458 | | - |
1459 | | - /** |
1460 | | - * Binds any events |
1461 | | - * |
1462 | | - * @param $block element the form block |
1463 | | - */ |
1464 | | - bindEvents: function ( $block ) { |
1465 | | - |
1466 | | - // On-blur validity check for Help Improve email field |
1467 | | - $block.find( '.articleFeedbackv5-helpimprove-email' ) |
1468 | | - .one( 'blur', function () { |
1469 | | - var $el = $(this); |
1470 | | - var bucket = $.articleFeedbackv5.currentBucket(); |
1471 | | - bucket.updateMailValidityLabel( $el.val() ); |
1472 | | - $el.keyup( function () { |
1473 | | - bucket.updateMailValidityLabel( $el.val() ); |
1474 | | - } ); |
1475 | | - } ); |
1476 | | - |
1477 | | - // Slide-down for the expertise checkboxes |
1478 | | - $block.find( '.articleFeedbackv5-expertise > input:checkbox' ) |
1479 | | - .change( function () { |
1480 | | - var $options = $.articleFeedbackv5.find( '.articleFeedbackv5-expertise-options' ); |
1481 | | - if ( $(this).is( ':checked' ) ) { |
1482 | | - $options.slideDown( 'fast' ); |
1483 | | - } else { |
1484 | | - $options.slideUp( 'fast', function () { |
1485 | | - $options.find( 'input:checkbox' ).attr( 'checked', false ); |
1486 | | - } ); |
1487 | | - } |
1488 | | - } ); |
1489 | | - |
1490 | | - // Enable submission when at least one rating is set |
1491 | | - $block.find( '.articleFeedbackv5-expertise input:checkbox' ) |
1492 | | - .each( function () { |
1493 | | - var id = 'articleFeedbackv5-expertise-' + $(this).attr( 'value' ); |
1494 | | - $(this).click( function () { |
1495 | | - $.articleFeedbackv5.enableSubmission( true ); |
1496 | | - } ); |
1497 | | - } ); |
1498 | | - |
1499 | | - // Clicking on the email field checks the associted box |
1500 | | - $block.find( '.articleFeedbackv5-helpimprove-email' ) |
1501 | | - .bind( 'mousedown click', function ( e ) { |
1502 | | - $(this).closest( '.articleFeedbackv5-helpimprove' ) |
1503 | | - .find( 'input:checkbox' ) |
1504 | | - .attr( 'checked', true ); |
1505 | | - } ); |
1506 | | - |
1507 | | - // Attach the submit |
1508 | | - $block.find( '.articleFeedbackv5-submit' ) |
1509 | | - .click( function ( e ) { |
1510 | | - e.preventDefault(); |
1511 | | - $.articleFeedbackv5.submitForm(); |
1512 | | - } ); |
1513 | | - |
1514 | | - // Set up form/report switch behavior |
1515 | | - $block.find( '.articleFeedbackv5-switch' ) |
1516 | | - .click( function ( e ) { |
1517 | | - var which = $( this ).attr( 'rel' ); |
1518 | | - if ( which == 'report' && $.articleFeedbackv5.currentBucket().loadAggregate ) { |
1519 | | - $.articleFeedbackv5.currentBucket().loadAggregateRatings(); |
1520 | | - $.articleFeedbackv5.currentBucket().loadAggregate = false; |
1521 | | - } |
1522 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-visibleWith-' + which ).show(); |
1523 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-switch' ) |
1524 | | - .not( $( this ) ) |
1525 | | - .each( function () { |
1526 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-visibleWith-' + $( this ).attr( 'rel' ) ).hide(); |
1527 | | - } ); |
1528 | | - $.articleFeedbackv5.currentBucket().inReport = which == 'report'; |
1529 | | - e.preventDefault(); |
1530 | | - return false; |
1531 | | - } ); |
1532 | | - |
1533 | | - // Set up rating behavior |
1534 | | - var rlabel = $block.find( '.articleFeedbackv5-rating-label' ); |
1535 | | - rlabel.hover( function () { |
1536 | | - // mouse on |
1537 | | - var $el = $( this ); |
1538 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
1539 | | - $el.addClass( 'articleFeedbackv5-rating-label-hover-head' ); |
1540 | | - $el.prevAll( '.articleFeedbackv5-rating-label' ) |
1541 | | - .addClass( 'articleFeedbackv5-rating-label-hover-tail' ); |
1542 | | - $rating.find( '.articleFeedbackv5-rating-tooltip' ) |
1543 | | - .text( mw.msg( 'articlefeedbackv5-bucket5-' + $rating.attr( 'rel' ) + '-tooltip-' + $el.attr( 'rel' ) ) ) |
1544 | | - .show(); |
1545 | | - }, function () { |
1546 | | - // mouse off |
1547 | | - var $el = $( this ); |
1548 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
1549 | | - $el.removeClass( 'articleFeedbackv5-rating-label-hover-head' ); |
1550 | | - $el.prevAll( '.articleFeedbackv5-rating-label' ) |
1551 | | - .removeClass( 'articleFeedbackv5-rating-label-hover-tail' ); |
1552 | | - $rating.find( '.articleFeedbackv5-rating-tooltip' ) |
1553 | | - .hide(); |
1554 | | - var bucket = $.articleFeedbackv5.currentBucket(); |
1555 | | - bucket.updateRating( $rating ); |
1556 | | - }); |
1557 | | - rlabel.mousedown( function () { |
1558 | | - $.articleFeedbackv5.enableSubmission( true ); |
1559 | | - var $ui = $.articleFeedbackv5.find( '.articleFeedbackv5-ui' ); |
1560 | | - if ( $ui.hasClass( 'articleFeedbackv5-expired' ) ) { |
1561 | | - // Changing one means the rest will get submitted too |
1562 | | - $ui.removeClass( 'articleFeedbackv5-expired' ); |
1563 | | - $ui.find( '.articleFeedbackv5-rating' ) |
1564 | | - .addClass( 'articleFeedbackv5-rating-new' ); |
1565 | | - } |
1566 | | - $ui.find( '.articleFeedbackv5-expertise' ) |
1567 | | - .each( function () { |
1568 | | - $.articleFeedbackv5.currentBucket().enableExpertise( $(this) ); |
1569 | | - } ); |
1570 | | - var $el = $( this ); |
1571 | | - var $rating = $el.closest( '.articleFeedbackv5-rating' ); |
1572 | | - $rating.addClass( 'articleFeedbackv5-rating-new' ); |
1573 | | - $rating.find( 'input:hidden' ).val( $el.attr( 'rel' ) ); |
1574 | | - $el.addClass( 'articleFeedbackv5-rating-label-down' ); |
1575 | | - $el.nextAll() |
1576 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
1577 | | - $el.parent().find( '.articleFeedbackv5-rating-clear' ).show(); |
1578 | | - } ); |
1579 | | - rlabel.mouseup( function () { |
1580 | | - $(this).removeClass( 'articleFeedbackv5-rating-label-down' ); |
1581 | | - } ); |
1582 | | - |
1583 | | - // Icon to clear out the ratings |
1584 | | - $block.find( '.articleFeedbackv5-rating-clear' ) |
1585 | | - .click( function () { |
1586 | | - $.articleFeedbackv5.enableSubmission( true ); |
1587 | | - $(this).hide(); |
1588 | | - var $rating = $(this).closest( '.articleFeedbackv5-rating' ); |
1589 | | - $rating.find( 'input:hidden' ).val( 0 ); |
1590 | | - $.articleFeedbackv5.currentBucket().updateRating( $rating ); |
1591 | | - } ); |
1592 | | - |
1593 | | - }, |
1594 | | - |
1595 | | - // }}} |
1596 | | - // {{{ afterBuild |
1597 | | - |
1598 | | - /** |
1599 | | - * Handles any setup that has to be done once the markup is in the |
1600 | | - * holder |
1601 | | - */ |
1602 | | - afterBuild: function () { |
1603 | | - // Drop the tooltip trigger |
1604 | | - $.articleFeedbackv5.$holder |
1605 | | - .add( $.articleFeedbackv5.$dialog) |
1606 | | - .find( '.articleFeedbackv5-tooltip-trigger' ).hide(); |
1607 | | - }, |
1608 | | - |
1609 | | - // }}} |
1610 | | - // {{{ updateRating |
1611 | | - |
1612 | | - /** |
1613 | | - * Updates the stars to match the associated hidden field |
1614 | | - * |
1615 | | - * @param $rating the rating block |
1616 | | - */ |
1617 | | - updateRating: function ( $rating ) { |
1618 | | - $rating.find( '.articleFeedbackv5-rating-label' ) |
1619 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
1620 | | - var val = $rating.find( 'input:hidden' ).val(); |
1621 | | - var $label = $rating.find( '.articleFeedbackv5-rating-label[rel="' + val + '"]' ); |
1622 | | - if ( $label.length ) { |
1623 | | - $label.prevAll( '.articleFeedbackv5-rating-label' ) |
1624 | | - .add( $label ) |
1625 | | - .addClass( 'articleFeedbackv5-rating-label-full' ); |
1626 | | - $label.nextAll( '.articleFeedbackv5-rating-label' ) |
1627 | | - .removeClass( 'articleFeedbackv5-rating-label-full' ); |
1628 | | - $rating.find( '.articleFeedbackv5-rating-clear' ).show(); |
1629 | | - } else { |
1630 | | - $rating.find( '.articleFeedbackv5-rating-clear' ).hide(); |
1631 | | - } |
1632 | | - }, |
1633 | | - |
1634 | | - // }}} |
1635 | | - // {{{ enableSubmission |
1636 | | - |
1637 | | - /** |
1638 | | - * Enables or disables submission of the form |
1639 | | - * |
1640 | | - * @param state bool true to enable; false to disable |
1641 | | - */ |
1642 | | - enableSubmission: function ( state ) { |
1643 | | - if ( state ) { |
1644 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-pending span' ).fadeIn( 'fast' ); |
1645 | | - } else { |
1646 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-pending span' ).hide(); |
1647 | | - } |
1648 | | - $.articleFeedbackv5.submissionEnabled = state; |
1649 | | - }, |
1650 | | - |
1651 | | - // }}} |
1652 | | - // {{{ enableExpertise |
1653 | | - |
1654 | | - /** |
1655 | | - * Enables the expertise checkboxes |
1656 | | - * |
1657 | | - * @param element $el the element containing checkboxes to enable |
1658 | | - */ |
1659 | | - enableExpertise: function ( $el ) { |
1660 | | - $el.find( 'input:checkbox[value=general]' ) |
1661 | | - .attr( 'disabled', false ) |
1662 | | - $el.find( '.articleFeedbackv5-expertise-disabled' ) |
1663 | | - .removeClass( 'articleFeedbackv5-expertise-disabled' ); |
1664 | | - }, |
1665 | | - |
1666 | | - // }}} |
1667 | | - // {{{ updateMailValidityLabel |
1668 | | - |
1669 | | - /** |
1670 | | - * Given an email sting, gets validity status (true, false, null) and updates |
1671 | | - * the label's CSS class |
1672 | | - * |
1673 | | - * @param string mail the email address |
1674 | | - */ |
1675 | | - updateMailValidityLabel: function ( mail ) { |
1676 | | - var isValid = mw.util.validateEmail( mail ); |
1677 | | - var $label = $.articleFeedbackv5.find( '.articleFeedbackv5-helpimprove-email' ); |
1678 | | - if ( isValid === null ) { // empty address |
1679 | | - $label.removeClass( 'valid invalid' ); |
1680 | | - } else if ( isValid ) { |
1681 | | - $label.addClass( 'valid' ).removeClass( 'invalid' ); |
1682 | | - } else { |
1683 | | - $label.addClass( 'invalid' ).removeClass( 'valid' ); |
1684 | | - } |
1685 | | - }, |
1686 | | - |
1687 | | - // }}} |
1688 | | - // {{{ loadAggregateRatings |
1689 | | - |
1690 | | - /** |
1691 | | - * Pulls the aggregate ratings via ajax request |
1692 | | - * the label's CSS class |
1693 | | - */ |
1694 | | - loadAggregateRatings: function () { |
1695 | | - $.ajax( { |
1696 | | - 'url': $.articleFeedbackv5.apiUrl, |
1697 | | - 'type': 'GET', |
1698 | | - 'dataType': 'json', |
1699 | | - 'data': { |
1700 | | - 'action': 'query', |
1701 | | - 'format': 'json', |
1702 | | - 'list': 'articlefeedbackv5-view-ratings', |
1703 | | - 'afpageid': $.articleFeedbackv5.pageId, |
1704 | | - 'maxage': 0, |
1705 | | - 'smaxage': mw.config.get( 'wgArticleFeedbackv5SMaxage' ) |
1706 | | - }, |
1707 | | - 'success': function ( data ) { |
1708 | | - // Get data |
1709 | | - if ( |
1710 | | - !( 'query' in data ) |
1711 | | - || !( 'articlefeedbackv5-view-ratings' in data.query ) |
1712 | | - || !( 'rollup' in data.query['articlefeedbackv5-view-ratings'] ) |
1713 | | - ) { |
1714 | | - mw.log( mw.msg ( 'articlefeedbackv5-error-response' ) ); |
1715 | | - var msg = mw.msg ( 'articlefeedbackv5-error-response' ); |
1716 | | - if ( 'error' in data && 'info' in data.error ) { |
1717 | | - msg = data.error.info; |
1718 | | - } else { |
1719 | | - aft5_debug(data); |
1720 | | - } |
1721 | | - $.articleFeedbackv5.markShowstopperError( msg ); |
1722 | | - return; |
1723 | | - } |
1724 | | - var rollup = data.query['articlefeedbackv5-view-ratings'].rollup; |
1725 | | - |
1726 | | - // Ratings |
1727 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-rating' ).each( function () { |
1728 | | - var name = $(this).attr( 'rel' ); |
1729 | | - var rating = name in rollup ? rollup[name] : null; |
1730 | | - if ( |
1731 | | - rating !== null |
1732 | | - && 'total' in rating |
1733 | | - && 'count' in rating |
1734 | | - && rating.total > 0 |
1735 | | - ) { |
1736 | | - var average = Math.round( ( rating.total / rating.count ) * 10 ) / 10; |
1737 | | - $(this).find( '.articleFeedbackv5-rating-average' ) |
1738 | | - .text( mw.language.convertNumber( average + ( average % 1 === 0 ? '.0' : '' ) , false ) ); |
1739 | | - $(this).find( '.articleFeedbackv5-rating-meter div' ) |
1740 | | - .css( 'width', Math.round( average * 21 ) + 'px' ); |
1741 | | - $(this).find( '.articleFeedbackv5-rating-count' ) |
1742 | | - .text( mw.msg( 'articlefeedbackv5-bucket5-report-ratings', rating.count ) ); |
1743 | | - } else { |
1744 | | - // Special case for no ratings |
1745 | | - $(this).find( '.articleFeedbackv5-rating-average' ) |
1746 | | - .html( ' ' ); |
1747 | | - $(this).find( '.articleFeedbackv5-rating-meter div' ) |
1748 | | - .css( 'width', 0 ); |
1749 | | - $(this).find( '.articleFeedbackv5-rating-count' ) |
1750 | | - .text( mw.msg( 'articlefeedbackv5-bucket5-report-empty' ) ); |
1751 | | - } |
1752 | | - } ); |
1753 | | - |
1754 | | - // Status change - un-new the rating controls |
1755 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-rating-new' ) |
1756 | | - .removeClass( 'articleFeedbackv5-rating-new' ); |
1757 | | - }, |
1758 | | - 'error': function () { |
1759 | | - mw.log( 'Report loading error' ); |
1760 | | - $.articleFeedbackv5.currentBucket().markShowstopperError( 'Report loading error' ); |
1761 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-error' ).show(); |
1762 | | - } |
1763 | | - } ); |
1764 | | - |
1765 | | - }, |
1766 | | - |
1767 | | - // }}} |
1768 | | - // {{{ getFormData |
1769 | | - |
1770 | | - /** |
1771 | | - * Pulls down form data |
1772 | | - * |
1773 | | - * @return object the form data |
1774 | | - */ |
1775 | | - getFormData: function () { |
1776 | | - var data = {}; |
1777 | | - var info = $.articleFeedbackv5.currentBucket().ratingInfo; |
1778 | | - for ( var i = 0; i < info.length; i++ ) { |
1779 | | - var key = info[i]; |
1780 | | - var val = $.articleFeedbackv5.find( 'input[name="' + key + '"]' ).val(); |
1781 | | - if ( '0' != val ) { |
1782 | | - data[key] = val; |
1783 | | - } |
1784 | | - } |
1785 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-expertise input:checked' ).each( function () { |
1786 | | - data['expertise-' + $( this ).val()] = 1; |
1787 | | - } ); |
1788 | | - if ( $.articleFeedbackv5.find( '.articleFeedbackv5-helpimprove input:checked' ).length > 0 ) { |
1789 | | - data.email = $.articleFeedbackv5.find( '.articleFeedbackv5-helpimprove-email' ).val(); |
1790 | | - } |
1791 | | - return data; |
1792 | | - }, |
1793 | | - |
1794 | | - // }}} |
1795 | | - // {{{ localValidation |
1796 | | - |
1797 | | - /** |
1798 | | - * Performs any local validation |
1799 | | - * |
1800 | | - * @param object formdata the form data |
1801 | | - * @return mixed if ok, false; otherwise, an object as { 'field name' : 'message' } |
1802 | | - */ |
1803 | | - localValidation: function ( formdata ) { |
1804 | | - var error = {}; |
1805 | | - var ok = true; |
1806 | | - if ( $.articleFeedbackv5.find( '.articleFeedbackv5-helpimprove input:checked' ).length > 0 ) { |
1807 | | - if ( 'email' in formdata && !mw.util.validateEmail( formdata.email ) ) { |
1808 | | - error.helpimprove_email = mw.msg( 'articlefeedbackv5-error-email' ); |
1809 | | - ok = false; |
1810 | | - } |
1811 | | - } |
1812 | | - return ok ? false : error; |
1813 | | - }, |
1814 | | - |
1815 | | - // }}} |
1816 | | - // {{{ markFormErrors |
1817 | | - |
1818 | | - /** |
1819 | | - * Marks any errors on the form |
1820 | | - * |
1821 | | - * @param object errors errors, indexed by field name |
1822 | | - */ |
1823 | | - markFormErrors: function ( errors ) { |
1824 | | - if ( 'helpimprove_email' in errors ) { |
1825 | | - $.articleFeedbackv5.find( '.articleFeedbackv5-helpimprove-email' ) |
1826 | | - .addClass( 'invalid' ) |
1827 | | - .removeClass( 'valid' ); |
1828 | | - } |
1829 | | - }, |
1830 | | - |
1831 | | - // }}} |
1832 | | - // {{{ onSubmit |
1833 | | - |
1834 | | - /** |
1835 | | - * Sends off the email tracking request alongside the regular form |
1836 | | - * submit |
1837 | | - */ |
1838 | | - onSubmit: function () { |
1839 | | - $.articleFeedbackv5.currentBucket().loadAggregate = true; |
1840 | | - } |
1841 | | - |
1842 | | - // }}} |
1843 | | - |
1844 | 510 | } |
1845 | 511 | |
1846 | 512 | // }}} |
— | — | @@ -1958,7 +624,7 @@ |
1959 | 625 | .attr( 'href', mw.msg( 'articlefeedbackv5-cta1-learn-how-url' ) ); |
1960 | 626 | |
1961 | 627 | // Fill in the link |
1962 | | - var edit_track_id = $.articleFeedbackv5.bucketName() + '-' + |
| 628 | + var edit_track_id = $.articleFeedbackv5.experiment() + '-' + |
1963 | 629 | $.articleFeedbackv5.ctaName() + '-button_click-' + |
1964 | 630 | ( $.articleFeedbackv5.inDialog ? 'overlay': 'bottom' ); |
1965 | 631 | $block.find( '.articleFeedbackv5-cta-button' ) |
— | — | @@ -2025,7 +691,7 @@ |
2026 | 692 | |
2027 | 693 | // Fill in the button link |
2028 | 694 | var learn_url = mw.msg( 'articlefeedbackv5-cta1-learn-how-url' ); |
2029 | | - var learn_track_id = $.articleFeedbackv5.bucketName() + '-' + |
| 695 | + var learn_track_id = $.articleFeedbackv5.experiment() + '-' + |
2030 | 696 | $.articleFeedbackv5.ctaName() + '-button_click-' + |
2031 | 697 | ( $.articleFeedbackv5.inDialog ? 'overlay': 'bottom' ); |
2032 | 698 | $block.find( '.articleFeedbackv5-cta-button' ) |
— | — | @@ -2105,7 +771,7 @@ |
2106 | 772 | // Fill in the go-to-survey link |
2107 | 773 | var survey_url = $.articleFeedbackv5.currentCTA().getSurveyUrl(); |
2108 | 774 | if ( survey_url ) { |
2109 | | - var survey_track_id = $.articleFeedbackv5.bucketName() + '-' + |
| 775 | + var survey_track_id = $.articleFeedbackv5.experiment() + '-' + |
2110 | 776 | $.articleFeedbackv5.ctaName() + '-button_click-' + |
2111 | 777 | ( $.articleFeedbackv5.inDialog ? 'overlay': 'bottom' ); |
2112 | 778 | $block.find( '.articleFeedbackv5-cta-button' ) |
— | — | @@ -2723,6 +1389,11 @@ |
2724 | 1390 | $.articleFeedbackv5.init = function ( $el, config ) { |
2725 | 1391 | $.articleFeedbackv5.$holder = $el; |
2726 | 1392 | $.articleFeedbackv5.config = config; |
| 1393 | + // Debug mode |
| 1394 | + var reqDebug = mw.util.getParamValue( 'debug' ); |
| 1395 | + if ( reqDebug ) { |
| 1396 | + $.articleFeedbackv5.debug = reqDebug == 'false' ? false : true; |
| 1397 | + } |
2727 | 1398 | // Are we tracking clicks? |
2728 | 1399 | $.articleFeedbackv5.clickTracking = $.articleFeedbackv5.checkClickTracking(); |
2729 | 1400 | // Has the user already submitted ratings for this page at this revision? |
— | — | @@ -2737,7 +1408,7 @@ |
2738 | 1409 | $.articleFeedbackv5.$holder.appear( function () { |
2739 | 1410 | if ( !$.articleFeedbackv5.isLoaded ) { |
2740 | 1411 | $.articleFeedbackv5.load( 'auto', 'bottom' ); |
2741 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-impression-bottom' ); |
| 1412 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-impression-bottom' ); |
2742 | 1413 | } |
2743 | 1414 | } ); |
2744 | 1415 | // Keep track of links that must be removed after a successful submission |
— | — | @@ -2747,7 +1418,7 @@ |
2748 | 1419 | $.articleFeedbackv5.addTriggerLinks(); |
2749 | 1420 | // Track init at 1% |
2750 | 1421 | if ( Math.random() * 100 < 1 ) { |
2751 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-init' ); |
| 1422 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-init' ); |
2752 | 1423 | } |
2753 | 1424 | }; |
2754 | 1425 | |
— | — | @@ -2766,10 +1437,10 @@ |
2767 | 1438 | // 1. Requested in query string (debug only) |
2768 | 1439 | // 2. From cookie (see below) |
2769 | 1440 | // 3. Core bucketing |
2770 | | - var knownBuckets = { '0': true, '1': true, '2': true, '3': true, '4': true, '5': true }; |
2771 | | - var requested = mw.util.getParamValue( 'bucket' ); |
| 1441 | + var knownBuckets = { '0': true, '1': true }; |
| 1442 | + var requested = mw.util.getParamValue( 'aftv5_form' ); |
2772 | 1443 | var cookieval = $.cookie( $.articleFeedbackv5.prefix( 'display-bucket' ) ); |
2773 | | - if ( $.articleFeedbackv5.debug && requested in knownBuckets ) { |
| 1444 | + if ( requested in knownBuckets ) { |
2774 | 1445 | $.articleFeedbackv5.bucketId = requested; |
2775 | 1446 | } else if ( cookieval in knownBuckets ) { |
2776 | 1447 | $.articleFeedbackv5.bucketId = cookieval; |
— | — | @@ -2778,7 +1449,7 @@ |
2779 | 1450 | 'ext.articleFeedbackv5-display', |
2780 | 1451 | mw.config.get( 'wgArticleFeedbackv5DisplayBuckets' ) |
2781 | 1452 | ); |
2782 | | - var nameMap = { zero: '0', one: '1', two: '2', three: '3', four: '4', five: '5' }; |
| 1453 | + var nameMap = { zero: '0', one: '1' }; |
2783 | 1454 | $.articleFeedbackv5.bucketId = nameMap[bucketName]; |
2784 | 1455 | } |
2785 | 1456 | // Drop in a cookie to keep track of their display bucket; |
— | — | @@ -2835,14 +1506,14 @@ |
2836 | 1507 | if ( 'buckets' in cfg ) { |
2837 | 1508 | var knownBuckets = cfg.buckets; |
2838 | 1509 | var requested = mw.util.getParamValue( 'aftv5_link' ); |
2839 | | - if ( $.articleFeedbackv5.inDebug() && ( requested in knownBuckets || requested == 'X' ) ) { |
| 1510 | + if ( requested in knownBuckets || requested == 'X' ) { |
2840 | 1511 | bucketedLink = requested; |
2841 | 1512 | } else { |
2842 | 1513 | bucketedLink = mw.user.bucket( 'ext.articleFeedbackv5-links', cfg ); |
2843 | 1514 | } |
2844 | 1515 | } |
2845 | 1516 | } |
2846 | | - if ( $.articleFeedbackv5.inDebug() ) { |
| 1517 | + if ( $.articleFeedbackv5.debug ) { |
2847 | 1518 | aft5_debug( 'Using link option ' + bucketedLink ); |
2848 | 1519 | } |
2849 | 1520 | $.articleFeedbackv5.floatingLinkId = bucketedLink; |
— | — | @@ -3001,14 +1672,14 @@ |
3002 | 1673 | }; |
3003 | 1674 | |
3004 | 1675 | // }}} |
3005 | | - // {{{ bucketName |
| 1676 | + // {{{ experiment |
3006 | 1677 | |
3007 | 1678 | /** |
3008 | | - * Utility method: Gets the name of the current bucket |
| 1679 | + * Utility method: Gets the name of the current experiment |
3009 | 1680 | * |
3010 | | - * @return string the bucket name |
| 1681 | + * @return string the experiment (e.g. "option1A") |
3011 | 1682 | */ |
3012 | | - $.articleFeedbackv5.bucketName = function () { |
| 1683 | + $.articleFeedbackv5.experiment = function () { |
3013 | 1684 | return 'option' + $.articleFeedbackv5.bucketId + $.articleFeedbackv5.floatingLinkId; |
3014 | 1685 | }; |
3015 | 1686 | |
— | — | @@ -3290,6 +1961,7 @@ |
3291 | 1962 | 'pageid': $.articleFeedbackv5.pageId, |
3292 | 1963 | 'revid': $.articleFeedbackv5.revisionId, |
3293 | 1964 | 'bucket': $.articleFeedbackv5.bucketId, |
| 1965 | + 'experiment': $.articleFeedbackv5.experiment().replace( 'option', '' ), |
3294 | 1966 | 'link': $.articleFeedbackv5.submittedLinkId |
3295 | 1967 | } ); |
3296 | 1968 | |
— | — | @@ -3328,11 +2000,18 @@ |
3329 | 2001 | } else { |
3330 | 2002 | msg = mw.msg( data.error ); |
3331 | 2003 | } |
| 2004 | + } else if ( 'warning' in data ) { |
| 2005 | + // NB: Warnings come from the AbuseFilter and are |
| 2006 | + // already translated. |
| 2007 | + msg = data.warning; |
3332 | 2008 | } else { |
3333 | 2009 | msg = { info: mw.msg( 'articlefeedbackv5-error-unknown' ) }; |
3334 | 2010 | } |
3335 | 2011 | $.articleFeedbackv5.markFormErrors( { _api : msg } ); |
3336 | 2012 | $.articleFeedbackv5.unlockForm(); |
| 2013 | + if ( $.articleFeedbackv5.inDialog ) { |
| 2014 | + $.articleFeedbackv5.setDialogDimensions(); |
| 2015 | + } |
3337 | 2016 | } |
3338 | 2017 | }, |
3339 | 2018 | 'error': function () { |
— | — | @@ -3443,7 +2122,7 @@ |
3444 | 2123 | $.articleFeedbackv5.setDialogDimensions(); |
3445 | 2124 | |
3446 | 2125 | // Track the event |
3447 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-' + |
| 2126 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-' + |
3448 | 2127 | $.articleFeedbackv5.ctaName() + '-impression-' + from ); |
3449 | 2128 | |
3450 | 2129 | $.articleFeedbackv5.nowShowing = 'cta'; |
— | — | @@ -3567,7 +2246,7 @@ |
3568 | 2247 | var prefLink = mw.config.get( 'wgScript' ) + '?' + |
3569 | 2248 | $.param( { title: 'Special:Preferences' } ) + |
3570 | 2249 | '#mw-prefsection-rendering'; |
3571 | | - var prefTrackId = $.articleFeedbackv5.bucketName() + '-disable_gotoprefs_click'; |
| 2250 | + var prefTrackId = $.articleFeedbackv5.experiment() + '-disable_gotoprefs_click'; |
3572 | 2251 | $flyover.find( '.articleFeedbackv5-disable-flyover-button' ) |
3573 | 2252 | .attr( 'href', $.articleFeedbackv5.trackingUrl( prefLink, prefTrackId ) ) |
3574 | 2253 | .button() |
— | — | @@ -3577,7 +2256,7 @@ |
3578 | 2257 | .attr( 'href', '#hello' ) |
3579 | 2258 | .attr( 'rel', linkId ); |
3580 | 2259 | |
3581 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-disable_flyover-impression' ); |
| 2260 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-disable_flyover-impression' ); |
3582 | 2261 | return $flyover.html(); |
3583 | 2262 | } |
3584 | 2263 | } ) |
— | — | @@ -3591,7 +2270,7 @@ |
3592 | 2271 | } else { |
3593 | 2272 | $host.tipsy( 'show' ); |
3594 | 2273 | $wrap.addClass( 'articleFeedbackv5-tipsy-active' ); |
3595 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-disable_button_click' ); |
| 2274 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-disable_button_click' ); |
3596 | 2275 | } |
3597 | 2276 | } ); |
3598 | 2277 | }; |
— | — | @@ -3802,7 +2481,7 @@ |
3803 | 2482 | $.articleFeedbackv5.setLinkId( $link.data( 'linkId' ) ); |
3804 | 2483 | |
3805 | 2484 | // Track the impression |
3806 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-impression-overlay' ); |
| 2485 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-impression-overlay' ); |
3807 | 2486 | |
3808 | 2487 | // Hide the panel |
3809 | 2488 | $.articleFeedbackv5.$holder.hide(); |
— | — | @@ -3820,9 +2499,9 @@ |
3821 | 2500 | $.articleFeedbackv5.closeAsModal = function () { |
3822 | 2501 | if ( $.articleFeedbackv5.inDialog ) { |
3823 | 2502 | if ( 'form' == $.articleFeedbackv5.nowShowing ) { |
3824 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-close-overlay' ); |
| 2503 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-close-overlay' ); |
3825 | 2504 | } else if ('cta' == $.articleFeedbackv5.nowShowing ) { |
3826 | | - $.articleFeedbackv5.trackClick( $.articleFeedbackv5.bucketName() + '-' + |
| 2505 | + $.articleFeedbackv5.trackClick( $.articleFeedbackv5.experiment() + '-' + |
3827 | 2506 | $.articleFeedbackv5.ctaName() + '-close-overlay' ); |
3828 | 2507 | } |
3829 | 2508 | $.articleFeedbackv5.setLinkId( 'X' ); |
— | — | @@ -3931,7 +2610,7 @@ |
3932 | 2611 | * @param $link Element the trigger link |
3933 | 2612 | */ |
3934 | 2613 | $.articleFeedbackv5.clickTriggerLink = function( $link ) { |
3935 | | - var tracking_id = $.articleFeedbackv5.bucketName() + |
| 2614 | + var tracking_id = $.articleFeedbackv5.experiment() + |
3936 | 2615 | '-trigger' + $link.data( 'linkId' ) + |
3937 | 2616 | '-click-overlay'; |
3938 | 2617 | $.articleFeedbackv5.trackClick( tracking_id ); |
— | — | @@ -3960,7 +2639,7 @@ |
3961 | 2640 | inDebug: { args: 0, ret: true }, |
3962 | 2641 | nowShowing: { args: 0, ret: true }, |
3963 | 2642 | prefix: { args: 1, ret: true }, |
3964 | | - bucketName: { args: 0, ret: true }, |
| 2643 | + experiment: { args: 0, ret: true }, |
3965 | 2644 | addToRemovalQueue: { args: 1, ret: false }, |
3966 | 2645 | openAsModal: { args: 1, ret: false }, |
3967 | 2646 | closeAsModal: { args: 0, ret: true }, |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/ArticleFeedbackv5.php |
— | — | @@ -273,6 +273,7 @@ |
274 | 274 | $wgAutoloadClasses['ApiFlagFeedbackArticleFeedbackv5'] = $dir . 'api/ApiFlagFeedbackArticleFeedbackv5.php'; |
275 | 275 | $wgAutoloadClasses['ApiViewActivityArticleFeedbackv5'] = $dir . 'api/ApiViewActivityArticleFeedbackv5.php'; |
276 | 276 | $wgAutoloadClasses['ArticleFeedbackv5Hooks'] = $dir . 'ArticleFeedbackv5.hooks.php'; |
| 277 | +$wgAutoloadClasses['ArticleFeedbackv5Flagging'] = $dir . 'ArticleFeedbackv5.flagging.php'; |
277 | 278 | $wgAutoloadClasses['ArticleFeedbackv5MailerJob'] = $dir . 'ArticleFeedbackv5MailerJob.php'; |
278 | 279 | $wgAutoloadClasses['SpecialArticleFeedbackv5'] = $dir . 'SpecialArticleFeedbackv5.php'; |
279 | 280 | $wgExtensionMessagesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.i18n.php'; |
— | — | @@ -321,3 +322,10 @@ |
322 | 323 | $wgLogActions['suppress/unrequest'] = 'articlefeedbackv5-log-unrequest'; |
323 | 324 | $wgLogActions['articlefeedbackv5/flag'] = 'articlefeedbackv5-log-flag'; |
324 | 325 | $wgLogActions['articlefeedbackv5/unflag'] = 'articlefeedbackv5-log-unflag'; |
| 326 | + |
| 327 | +// Add custom action handlers for AbuseFilter |
| 328 | +// Not for this release |
| 329 | +// $wgAbuseFilterAvailableActions[] = 'aftv5flagabuse'; |
| 330 | +// $wgAbuseFilterAvailableActions[] = 'aftv5hide'; |
| 331 | +// $wgAbuseFilterAvailableActions[] = 'aftv5requestoversight'; |
| 332 | + |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/api/ApiFlagFeedbackArticleFeedbackv5.php |
— | — | @@ -30,394 +30,22 @@ |
31 | 31 | */ |
32 | 32 | public function execute() { |
33 | 33 | |
34 | | - // default values for information to be filled in |
35 | | - $filters = array(); |
36 | | - $update = array(); |
37 | | - $results = array(); |
38 | | - |
39 | 34 | // get important values from our parameters |
40 | 35 | $params = $this->extractRequestParams(); |
41 | 36 | $pageId = $params['pageid']; |
42 | 37 | $feedbackId = $params['feedbackid']; |
43 | 38 | $flag = $params['flagtype']; |
44 | 39 | $notes = $params['note']; |
45 | | - $toggle = $params['toggle']; |
46 | 40 | $direction = isset( $params['direction'] ) ? $params['direction'] : 'increase'; |
47 | | - $where = array( 'af_id' => $feedbackId ); |
| 41 | + $toggle = $params['toggle']; |
48 | 42 | |
49 | 43 | // woah, we were not checking for permissions (that could have been script kiddy bad) |
50 | 44 | global $wgUser; |
51 | 45 | |
52 | | - // we may not actually use this, but don't want to repeat this a million times |
53 | | - $default_user = wfMessage( 'articlefeedbackv5-default-user' )->text(); |
| 46 | + // Fire up the flagging object |
| 47 | + $flagger = new ArticleFeedbackv5Flagging( $wgUser, $pageId, $feedbackId ); |
| 48 | + $results = $flagger->run( $flag, $notes, $direction, $toggle ); |
54 | 49 | |
55 | | - // we use ONE db connection that talks to master |
56 | | - $dbw = wfGetDB( DB_MASTER ); |
57 | | - $dbw->begin(); |
58 | | - $timestamp = $dbw->timestamp(); |
59 | | - |
60 | | - // load feedback record, bail if we don't have one |
61 | | - $record = $this->fetchRecord( $dbw, $feedbackId ); |
62 | | - |
63 | | - if ( $record === false || !$record->af_id ) { |
64 | | - // no-op, because this is already broken |
65 | | - $error = 'articlefeedbackv5-invalid-feedback-id'; |
66 | | - |
67 | | - } elseif ( 'delete' == $flag && $wgUser->isAllowed( 'aftv5-delete-feedback' ) ) { |
68 | | - |
69 | | - // deleting means to "mark as oversighted" and "delete" it |
70 | | - // oversighting also auto-hides the item |
71 | | - |
72 | | - // increase means "oversight this" |
73 | | - if ( $direction == 'increase' ) { |
74 | | - $activity = 'oversight'; |
75 | | - |
76 | | - // delete |
77 | | - $update['af_is_deleted'] = true; |
78 | | - $update['af_is_undeleted'] = false; |
79 | | - // only store the oversighter on delete/oversight |
80 | | - $update['af_oversight_user_id'] = $wgUser->getId(); |
81 | | - $update['af_oversight_timestamp'] = $timestamp; |
82 | | - // delete specific filters |
83 | | - $filters['deleted'] = 1; |
84 | | - $filters['notdeleted'] = -1; |
85 | | - if ( true == $record->af_is_undeleted ) { |
86 | | - $filters['undeleted'] = -1; |
87 | | - } |
88 | | - |
89 | | - // This is data for the "hidden by, oversighted by" red line |
90 | | - $results['oversight-user'] = ApiArticleFeedbackv5Utils::getUserLink( $wgUser ); |
91 | | - $results['oversight-timestamp'] = wfTimestamp( TS_RFC2822, $timestamp ); |
92 | | - |
93 | | - // autohide if not hidden |
94 | | - if ( false == $record->af_is_hidden ) { |
95 | | - $update['af_is_hidden'] = true; |
96 | | - $update['af_is_unhidden'] = false; |
97 | | - $filters = $this->changeFilterCounts( $record, $filters, 'hide' ); |
98 | | - // 0 is used for "autohidden" purposes, we'll explicitly set it to overwrite last hider |
99 | | - $update['af_hide_user_id'] = 0; |
100 | | - $update['af_hide_timestamp'] = $timestamp; |
101 | | - $implicit_hide = true; // for logging |
102 | | - // tell front-end autohiding was done |
103 | | - $results['autohidden'] = 1; |
104 | | - // This is data for the "hidden by, oversighted by" red line |
105 | | - $results['hide-user'] = ApiArticleFeedbackv5Utils::getUserLink( null, $default_user ); |
106 | | - $results['hide-timestamp'] = wfTimestamp( TS_RFC2822, $timestamp ); |
107 | | - } |
108 | | - |
109 | | - } else { |
110 | | - // decrease means "unoversight this" but does NOT auto-unhide |
111 | | - $activity = 'unoversight'; |
112 | | - $update['af_is_deleted'] = false; |
113 | | - $update['af_is_undeleted'] = true; |
114 | | - // increment "undeleted", decrement "deleted" |
115 | | - // NOTE: we do not touch visible, since hidden controls visiblity |
116 | | - $filters['deleted'] = -1; |
117 | | - $filters['undeleted'] = 1; |
118 | | - // increment "notdeleted" for count of everything but oversighted |
119 | | - $filters['notdeleted'] = 1; |
120 | | - } |
121 | | - |
122 | | - } elseif ( 'hide' == $flag && $wgUser->isAllowed( 'aftv5-hide-feedback' ) ) { |
123 | | - |
124 | | - // increase means "hide this" |
125 | | - if ( $direction == 'increase' ) { |
126 | | - $activity = 'hidden'; |
127 | | - |
128 | | - // hide |
129 | | - $update['af_is_hidden'] = true; |
130 | | - $update['af_is_unhidden'] = false; |
131 | | - // only store the hider on hide not show |
132 | | - $update['af_hide_user_id'] = $wgUser->getId(); |
133 | | - $update['af_hide_timestamp'] = $timestamp; |
134 | | - $filters = $this->changeFilterCounts( $record, $filters, 'hide' ); |
135 | | - |
136 | | - // This is data for the "hidden by, oversighted by" red line |
137 | | - $results['hide-user'] = ApiArticleFeedbackv5Utils::getUserLink( $wgUser ); |
138 | | - $results['hide-timestamp'] = wfTimestamp( TS_RFC2822, $timestamp ); |
139 | | - |
140 | | - } else { |
141 | | - // decrease means "unhide this" |
142 | | - $activity = 'unhidden'; |
143 | | - |
144 | | - $update['af_is_hidden'] = false; |
145 | | - $update['af_is_unhidden'] = true; |
146 | | - |
147 | | - $filters = $this->changeFilterCounts( $record, $filters, 'show' ); |
148 | | - } |
149 | | - |
150 | | - } elseif ( 'resetoversight' === $flag && $wgUser->isAllowed( 'aftv5-delete-feedback' ) ) { |
151 | | - |
152 | | - $activity = 'decline'; |
153 | | - // oversight request count becomes 0 |
154 | | - $update['af_oversight_count'] = 0; |
155 | | - // declined oversight is flagged |
156 | | - $update['af_is_declined'] = true; |
157 | | - $filters['declined'] = 1; |
158 | | - // if the oversight count was greater then 1 |
159 | | - if ( 0 < $record->af_oversight_count ) { |
160 | | - $filters['needsoversight'] = -1; |
161 | | - } |
162 | | - |
163 | | - } elseif ( 'abuse' === $flag ) { |
164 | | - |
165 | | - // Conditional formatting for abuse flag |
166 | | - global $wgArticleFeedbackv5AbusiveThreshold, |
167 | | - $wgArticleFeedbackv5HideAbuseThreshold; |
168 | | - |
169 | | - $results['abuse_count'] = $record->af_abuse_count; |
170 | | - |
171 | | - // Make the abuse count in the result reflect this vote. |
172 | | - if ( $direction == 'increase' ) { |
173 | | - $results['abuse_count']++; |
174 | | - } else { |
175 | | - $results['abuse_count']--; |
176 | | - } |
177 | | - // no negative numbers |
178 | | - $results['abuse_count'] = max( 0, $results['abuse_count'] ); |
179 | | - |
180 | | - // Return a flag in the JSON, that turns the link red. |
181 | | - if ( $results['abuse_count'] >= $wgArticleFeedbackv5AbusiveThreshold ) { |
182 | | - $results['abusive'] = 1; |
183 | | - } |
184 | | - |
185 | | - // Adding a new abuse flag: abusive++ |
186 | | - if ( $direction == 'increase' ) { |
187 | | - $activity = 'flag'; |
188 | | - $filters['abusive'] = 1; |
189 | | - // NOTE: we are bypassing traditional sql escaping here |
190 | | - $update[] = "af_abuse_count = af_abuse_count + 1"; |
191 | | - |
192 | | - // Auto-hide after threshold flags |
193 | | - if ( $record->af_abuse_count > $wgArticleFeedbackv5HideAbuseThreshold |
194 | | - && false == $record->af_is_hidden ) { |
195 | | - // hide |
196 | | - $update['af_is_hidden'] = true; |
197 | | - $update['af_is_unhidden'] = false; |
198 | | - // 0 is used for "autohidden" purposes, we'll explicitly set it to overwrite last hider |
199 | | - $update['af_hide_user_id'] = 0; |
200 | | - $update['af_hide_timestamp'] = $timestamp; |
201 | | - |
202 | | - $filters = $this->changeFilterCounts( $record, $filters, 'hide' ); |
203 | | - $results['abuse-hidden'] = 1; |
204 | | - $implicit_hide = true; |
205 | | - |
206 | | - // tell front-end autohiding was done |
207 | | - $results['autohidden'] = 1; |
208 | | - // This is data for the "hidden by, oversighted by" red line |
209 | | - $results['hide-user'] = ApiArticleFeedbackv5Utils::getUserLink( null, $default_user ); |
210 | | - $results['hide-timestamp'] = wfTimestamp( TS_RFC2822, $timestamp ); |
211 | | - } |
212 | | - } |
213 | | - |
214 | | - // Removing the last abuse flag: abusive-- |
215 | | - elseif ( $direction == 'decrease' ) { |
216 | | - $activity = 'unflag'; |
217 | | - $filters['abusive'] = -1; |
218 | | - // NOTE: we are bypassing traditional sql escaping here |
219 | | - $update[] = "af_abuse_count = GREATEST(CONVERT(af_abuse_count, SIGNED) -1, 0)"; |
220 | | - |
221 | | - // Un-hide if we don't have 5 flags anymore |
222 | | - if ( $record->af_abuse_count == 5 && true == $record->af_is_hidden ) { |
223 | | - $update['af_is_hidden'] = false; |
224 | | - $update['af_is_unhidden'] = true; |
225 | | - |
226 | | - $filters = $this->changeFilterCounts( $record, $filters, 'show' ); |
227 | | - |
228 | | - $implicit_unhide = true; |
229 | | - } |
230 | | - } else { |
231 | | - // TODO: real error here? |
232 | | - $error = 'articlefeedbackv5-invalid-feedback-flag'; |
233 | | - } |
234 | | - |
235 | | - // NOTE: this is actually request/unrequest oversight and works similar to abuse |
236 | | - } elseif ( 'oversight' === $flag && $wgUser->isAllowed( 'aftv5-hide-feedback' ) ) { |
237 | | - |
238 | | - if ( $direction == 'increase' ) { |
239 | | - $activity = 'request'; |
240 | | - $filters['needsoversight'] = 1; |
241 | | - // NOTE: we are bypassing traditional sql escaping here |
242 | | - $update[] = "af_oversight_count = af_oversight_count + 1"; |
243 | | - |
244 | | - // autohide if not hidden |
245 | | - if ( false == $record->af_is_hidden ) { |
246 | | - $update['af_is_hidden'] = true; |
247 | | - $update['af_is_unhidden'] = false; |
248 | | - // 0 is used for "autohidden" purposes, we'll explicitly set it to overwrite last hider |
249 | | - $update['af_hide_user_id'] = 0; |
250 | | - $update['af_hide_timestamp'] = $timestamp; |
251 | | - |
252 | | - $filters = $this->changeFilterCounts( $record, $filters, 'hide' ); |
253 | | - $implicit_hide = true; // for logging |
254 | | - // tell front-end autohiding was done |
255 | | - $results['autohidden'] = 1; |
256 | | - // This is data for the "hidden by, oversighted by" red line |
257 | | - $results['hide-user'] = ApiArticleFeedbackv5Utils::getUserLink( null, $default_user ); |
258 | | - $results['hide-timestamp'] = wfTimestamp( TS_RFC2822, $timestamp ); |
259 | | - } |
260 | | - |
261 | | - // IF the previous setting was 0, send an email |
262 | | - if ( $record->af_oversight_count < 1 ) { |
263 | | - |
264 | | - $this->sendOversightEmail( $record->af_page_id , $feedbackId ); |
265 | | - |
266 | | - } |
267 | | - } elseif ( $direction == 'decrease' ) { |
268 | | - $activity = 'unrequest'; |
269 | | - $filters['needsoversight'] = -1; |
270 | | - // NOTE: we are bypassing traditional sql escaping here |
271 | | - $update[] = "af_oversight_count = GREATEST(CONVERT(af_oversight_count, SIGNED) - 1, 0)"; |
272 | | - } else { |
273 | | - // TODO: real error here? |
274 | | - $error = 'articlefeedbackv5-invalid-feedback-flag'; |
275 | | - } |
276 | | - |
277 | | - // helpful and unhelpful flagging |
278 | | - } elseif ( 'unhelpful' === $flag || 'helpful' === $flag ) { |
279 | | - |
280 | | - $results['toggle'] = $toggle; |
281 | | - $helpful = $record->af_helpful_count; |
282 | | - $unhelpful = $record->af_unhelpful_count; |
283 | | - |
284 | | - // if toggle is on, we are decreasing one and increasing the other atomically |
285 | | - // means one less http request and the counts don't mess up |
286 | | - if ( true == $toggle ) { |
287 | | - |
288 | | - if ( ( ( $flag == 'helpful' && $direction == 'increase' ) |
289 | | - || ( $flag == 'unhelpful' && $direction == 'decrease' ) ) |
290 | | - ) { |
291 | | - // NOTE: we are bypassing traditional sql escaping here |
292 | | - $update[] = "af_helpful_count = af_helpful_count + 1"; |
293 | | - $update[] = "af_unhelpful_count = GREATEST(0, CONVERT(af_unhelpful_count, SIGNED) - 1)"; |
294 | | - $helpful++; |
295 | | - $unhelpful--; |
296 | | - |
297 | | - } elseif ( ( ( $flag == 'unhelpful' && $direction == 'increase' ) |
298 | | - || ( $flag == 'helpful' && $direction == 'decrease' ) ) |
299 | | - ) { |
300 | | - // NOTE: we are bypassing traditional sql escaping here |
301 | | - $update[] = "af_unhelpful_count = af_unhelpful_count + 1"; |
302 | | - $update[] = "af_helpful_count = GREATEST(0, CONVERT(af_helpful_count, SIGNED) - 1)"; |
303 | | - $helpful--; |
304 | | - $unhelpful++; |
305 | | - } |
306 | | - |
307 | | - } else { |
308 | | - |
309 | | - if ( 'unhelpful' === $flag && $direction == 'increase' ) { |
310 | | - // NOTE: we are bypassing traditional sql escaping here |
311 | | - $update[] = "af_unhelpful_count = af_unhelpful_count + 1"; |
312 | | - $unhelpful++; |
313 | | - } elseif ( 'unhelpful' === $flag && $direction == 'decrease' ) { |
314 | | - // NOTE: we are bypassing traditional sql escaping here |
315 | | - $update[] = "af_unhelpful_count = GREATEST(0, CONVERT(af_unhelpful_count, SIGNED) - 1)"; |
316 | | - $unhelpful--; |
317 | | - } elseif ( $flag == 'helpful' && $direction == 'increase' ) { |
318 | | - // NOTE: we are bypassing traditional sql escaping here |
319 | | - $update[] = "af_helpful_count = af_helpful_count + 1"; |
320 | | - $helpful++; |
321 | | - } elseif ( $flag == 'helpful' && $direction == 'decrease' ) { |
322 | | - // NOTE: we are bypassing traditional sql escaping here |
323 | | - $update[] = "af_helpful_count = GREATEST(0, CONVERT(af_helpful_count, SIGNED) - 1)"; |
324 | | - $helpful--; |
325 | | - } |
326 | | - |
327 | | - } |
328 | | - |
329 | | - $netHelpfulness = $helpful - $unhelpful; |
330 | | - |
331 | | - // increase helpful OR decrease unhelpful |
332 | | - if ( ( ( $flag == 'helpful' && $direction == 'increase' ) |
333 | | - || ( $flag == 'unhelpful' && $direction == 'decrease' ) ) |
334 | | - ) { |
335 | | - // net was -1: no longer unhelpful |
336 | | - if ( $netHelpfulness == -1 ) { |
337 | | - $filters['unhelpful'] = -1; |
338 | | - } |
339 | | - |
340 | | - // net was 0: now helpful |
341 | | - if ( $netHelpfulness == 0 ) { |
342 | | - $filters['helpful'] = 1; |
343 | | - } |
344 | | - } |
345 | | - |
346 | | - // increase unhelpful OR decrease unhelpful |
347 | | - if ( ( ( $flag == 'unhelpful' && $direction == 'increase' ) |
348 | | - || ( $flag == 'helpful' && $direction == 'decrease' ) ) |
349 | | - ) { |
350 | | - // net was 1: no longer helpful |
351 | | - if ( $netHelpfulness == 1 ) { |
352 | | - $filters['helpful'] = -1; |
353 | | - } |
354 | | - |
355 | | - // net was 0: now unhelpful |
356 | | - if ( $netHelpfulness == 0 ) { |
357 | | - $filters['unhelpful'] = 1; |
358 | | - } |
359 | | - } |
360 | | - |
361 | | - } else { |
362 | | - $error = 'articlefeedbackv5-invalid-feedback-flag'; |
363 | | - } |
364 | | - |
365 | | - // we were valid |
366 | | - if ( !isset( $error ) ) { |
367 | | - |
368 | | - $success = $dbw->update( |
369 | | - 'aft_article_feedback', |
370 | | - $update, |
371 | | - $where, |
372 | | - __METHOD__ |
373 | | - ); |
374 | | - |
375 | | - // Update the filter count rollups. |
376 | | - ApiArticleFeedbackv5Utils::updateFilterCounts( $dbw, $pageId, $filters ); |
377 | | - |
378 | | - $dbw->commit(); // everything went well, so we commit our db changes |
379 | | - |
380 | | - // helpfulness counts are NOT logged, no activity is set |
381 | | - if ( isset( $activity ) ) { |
382 | | - ApiArticleFeedbackv5Utils::logActivity( $activity , $pageId, $feedbackId, $notes ); |
383 | | - } |
384 | | - |
385 | | - // handle implicit hide/show logging |
386 | | - if ( isset( $implicit_hide ) && $implicit_hide ) { |
387 | | - ApiArticleFeedbackv5Utils::logActivity( 'hidden' , $pageId, $feedbackId, '', true ); |
388 | | - } |
389 | | - |
390 | | - // Update helpful/unhelpful display count after submission. |
391 | | - if ( $flag == 'helpful' || $flag == 'unhelpful' ) { |
392 | | - |
393 | | - // no negative numbers please |
394 | | - $helpful = max( 0, $helpful ); |
395 | | - $unhelpful = max( 0, $unhelpful ); |
396 | | - |
397 | | - $results['helpful'] = wfMessage( |
398 | | - 'articlefeedbackv5-form-helpful-votes', |
399 | | - $helpful, $unhelpful |
400 | | - )->escaped(); |
401 | | - |
402 | | - // Update net_helpfulness after flagging as helpful/unhelpful. |
403 | | - $dbw->update( |
404 | | - 'aft_article_feedback', |
405 | | - array( 'af_net_helpfulness = CONVERT(af_helpful_count, SIGNED) - CONVERT(af_unhelpful_count, SIGNED)' ), |
406 | | - array( |
407 | | - 'af_id' => $params['feedbackid'], |
408 | | - ), |
409 | | - __METHOD__ |
410 | | - ); |
411 | | - } |
412 | | - } |
413 | | - |
414 | | - if ( $error ) { |
415 | | - $results['result'] = 'Error'; |
416 | | - $results['reason'] = $error; |
417 | | - } else { |
418 | | - $results['result'] = 'Success'; |
419 | | - $results['reason'] = null; |
420 | | - } |
421 | | - |
422 | 50 | $this->getResult()->addValue( |
423 | 51 | null, |
424 | 52 | $this->getModuleName(), |
— | — | @@ -426,87 +54,6 @@ |
427 | 55 | } |
428 | 56 | |
429 | 57 | /** |
430 | | - * Helper function to grab a record from the database with information |
431 | | - * about the current feedback row |
432 | | - * |
433 | | - * @param object $dbw connection to database |
434 | | - * @param int $id id of the feedback to fetch |
435 | | - * @return object database record |
436 | | - */ |
437 | | - private function fetchRecord( $dbw, $id ) { |
438 | | - $record = $dbw->selectRow( |
439 | | - 'aft_article_feedback', |
440 | | - array( |
441 | | - 'af_id', |
442 | | - 'af_page_id', |
443 | | - 'af_abuse_count', |
444 | | - 'af_is_hidden', |
445 | | - 'af_helpful_count', |
446 | | - 'af_unhelpful_count', |
447 | | - 'af_is_deleted', |
448 | | - 'af_net_helpfulness', |
449 | | - 'af_is_unhidden', |
450 | | - 'af_is_undeleted', |
451 | | - 'af_is_declined', |
452 | | - 'af_has_comment', |
453 | | - 'af_oversight_count' ), |
454 | | - array( 'af_id' => $id ) |
455 | | - ); |
456 | | - return $record; |
457 | | - } |
458 | | - |
459 | | - /** |
460 | | - * Helper function to manipulate all flags when hiding/showing a piece of feedback |
461 | | - * |
462 | | - * @param object $record existing feedback database record |
463 | | - * @param array $filters existing filters |
464 | | - * @param string $action 'hide' or 'show' |
465 | | - * @return array the filter array with new filter choices added |
466 | | - */ |
467 | | - protected function changeFilterCounts( $record, $filters, $action ) { |
468 | | - // only filters that hide shouldn't manipulate are |
469 | | - // all, deleted, undeleted, and notdeleted |
470 | | - |
471 | | - // use -1 (decrement) for hide, 1 for increment (show) - default is hide |
472 | | - switch( $action ) { |
473 | | - case 'show': |
474 | | - $int = 1; |
475 | | - // if we're showing, this will increment |
476 | | - $filters['unhidden'] = 1; |
477 | | - break; |
478 | | - default: |
479 | | - // if we're hiding, and was unhidden, decrement |
480 | | - if ( true == $record->af_is_unhidden ) { |
481 | | - $filters['unhidden'] = -1; |
482 | | - } |
483 | | - $int = -1; |
484 | | - break; |
485 | | - } |
486 | | - |
487 | | - // visible, invisible, unhidden |
488 | | - $filters['visible'] = $int; |
489 | | - $filters['invisible'] = -$int; // opposite of int |
490 | | - |
491 | | - // comment |
492 | | - if ( true == $record->af_has_comment ) { |
493 | | - $filters['comment'] = $int; |
494 | | - } |
495 | | - |
496 | | - // abusive |
497 | | - if ( $record->af_abuse_count > 1 ) { |
498 | | - $filters['abusive'] = $int; |
499 | | - } |
500 | | - // helpful and unhelpful |
501 | | - if ( $record->af_net_helpfulness > 1 ) { |
502 | | - $filters['helpful'] = $int; |
503 | | - } elseif ( $record->af_net_helpfulness < 1 ) { |
504 | | - $filters['unhelpful'] = $int; |
505 | | - } |
506 | | - |
507 | | - return $filters; |
508 | | - } |
509 | | - |
510 | | - /** |
511 | 58 | * Gets the allowed parameters |
512 | 59 | * |
513 | 60 | * @return array the params info, indexed by allowed key |
— | — | @@ -544,7 +91,7 @@ |
545 | 92 | ApiBase::PARAM_REQUIRED => false, |
546 | 93 | ApiBase::PARAM_ISMULTI => false, |
547 | 94 | ApiBase::PARAM_TYPE => 'boolean' |
548 | | - ) |
| 95 | + ), |
549 | 96 | ); |
550 | 97 | } |
551 | 98 | |
— | — | @@ -558,7 +105,7 @@ |
559 | 106 | 'feedbackid' => 'FeedbackID to flag', |
560 | 107 | 'type' => 'Type of flag to apply - hide or abuse', |
561 | 108 | 'note' => 'Information on why the feedback activity occurred', |
562 | | - 'toggle' => 'The flag is being toggled atomically, only useful for (un)helpful' |
| 109 | + 'toggle' => 'The flag is being toggled atomically, only useful for (un)helpful', |
563 | 110 | ); |
564 | 111 | } |
565 | 112 | |
— | — | @@ -607,52 +154,7 @@ |
608 | 155 | } |
609 | 156 | |
610 | 157 | public function isWriteMode() { return true; } |
| 158 | + |
611 | 159 | public function mustBePosted() { return true; } |
612 | 160 | |
613 | | - /** |
614 | | - * Helper function to dig out page url and title, feedback permalink, and |
615 | | - * requestor page url and name - if all this data can be retrieved properly |
616 | | - * it shoves an email job into the queue for sending to the oversighters' |
617 | | - * mailing list - only called for NEW oversight requests |
618 | | - * |
619 | | - * @param int $page_id page id to grab info on |
620 | | - * @param int $feedback_id identifier for the feedback item |
621 | | - */ |
622 | | - protected function sendOversightEmail( $page_id, $feedback_id ) { |
623 | | - global $wgUser; |
624 | | - |
625 | | - // jobs need a title object |
626 | | - $title_object = Title::newFromID( $page_id ); |
627 | | - |
628 | | - if ( !$title_object ) { |
629 | | - return; // no title object, no mail |
630 | | - } |
631 | | - |
632 | | - // get the string name of the page |
633 | | - $page_name = $title_object->getDBKey(); |
634 | | - |
635 | | - // make a title out of our user (sigh) |
636 | | - $user_page = Title::makeTitle( NS_USER, $wgUser->getName() ); |
637 | | - |
638 | | - if ( !$user_page ) { |
639 | | - return; // no user title object, no mail |
640 | | - } |
641 | | - |
642 | | - // to build our permalink, use the feedback entry key + the page name (isn't page name a title? but title is an object? confusing) |
643 | | - $permalink = SpecialPage::getTitleFor( 'ArticleFeedbackv5', "$page_name/$feedback_id" ); |
644 | | - |
645 | | - if ( !$permalink ) { |
646 | | - return; // no proper permalink? no mail |
647 | | - } |
648 | | - |
649 | | - // build our params |
650 | | - $params = array( 'user_name' => $wgUser->getName(), |
651 | | - 'user_url' => $user_page->getCanonicalUrl(), |
652 | | - 'page_name' => $title_object->getText(), |
653 | | - 'page_url' => $title_object->getCanonicalUrl(), |
654 | | - 'permalink' => $permalink->getCanonicalUrl() ); |
655 | | - |
656 | | - $job = new ArticleFeedbackv5MailerJob( $title_object, $params ); |
657 | | - $job->insert(); |
658 | | - } |
659 | 161 | } |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/api/ApiArticleFeedbackv5.php |
— | — | @@ -19,6 +19,12 @@ |
20 | 20 | // Cache this, so we don't have to look it up every time. |
21 | 21 | private $revision_limit = null; |
22 | 22 | |
| 23 | + // Allow auto-flagging of feedback |
| 24 | + private $autoFlag = array(); |
| 25 | + |
| 26 | + // Warn for abuse? |
| 27 | + private $warnForAbuse = false; |
| 28 | + |
23 | 29 | /** |
24 | 30 | * Constructor |
25 | 31 | */ |
— | — | @@ -41,7 +47,6 @@ |
42 | 48 | return; |
43 | 49 | } |
44 | 50 | |
45 | | - |
46 | 51 | // Anon token check |
47 | 52 | $token = $this->getAnonToken( $params ); |
48 | 53 | |
— | — | @@ -53,8 +58,10 @@ |
54 | 59 | $dbw = wfGetDB( DB_MASTER ); |
55 | 60 | $pageId = $params['pageid']; |
56 | 61 | $bucket = $params['bucket']; |
| 62 | + $experiment = $params['experiment']; |
57 | 63 | $revisionId = $params['revid']; |
58 | 64 | $error = null; |
| 65 | + $warning = null; |
59 | 66 | $userAnswers = array(); |
60 | 67 | $fields = ApiArticleFeedbackv5Utils::getFields(); |
61 | 68 | $emailData = array( |
— | — | @@ -81,7 +88,11 @@ |
82 | 89 | } |
83 | 90 | if ( $wgArticleFeedbackv5AbuseFiltering && 'text' == $type |
84 | 91 | && $this->findAbuse( $value, $pageId ) ) { |
85 | | - $error = 'articlefeedbackv5-error-abuse'; |
| 92 | + if ( $this->warnForAbuse ) { |
| 93 | + $warning = $this->warnForAbuse; |
| 94 | + } else { |
| 95 | + $error = 'articlefeedbackv5-error-abuse'; |
| 96 | + } |
86 | 97 | break; |
87 | 98 | } |
88 | 99 | $data = array( 'aa_field_id' => $field['afi_id'] ); |
— | — | @@ -96,6 +107,10 @@ |
97 | 108 | $this->getResult()->addValue( null, 'error', $error ); |
98 | 109 | return; |
99 | 110 | } |
| 111 | + if ( $warning ) { |
| 112 | + $this->getResult()->addValue( null, 'warning', $warning ); |
| 113 | + return; |
| 114 | + } |
100 | 115 | |
101 | 116 | // all write actions should be done under the same transaction |
102 | 117 | // or counts will be messed up |
— | — | @@ -138,6 +153,26 @@ |
139 | 154 | |
140 | 155 | wfRunHooks( 'ArticleFeedbackChangeRating', array( $params ) ); |
141 | 156 | |
| 157 | + // Are we set to auto-flag? |
| 158 | + $flagger = new ArticleFeedbackv5Flagging( 0, $pageId, $feedbackId ); |
| 159 | + foreach ( $this->autoFlag as $flag => $rule_desc ) { |
| 160 | + $msg = 'articlefeedbackv5-abusefilter-note-aftv5'; |
| 161 | + if ( $flag == 'abuse' ) { |
| 162 | + $msg .= 'flagabuse'; |
| 163 | + } elseif ( $flag == 'hide' ) { |
| 164 | + $msg .= 'hide'; |
| 165 | + } elseif ( $flag == 'oversight' ) { |
| 166 | + $msg .= 'requestoversight'; |
| 167 | + } else { |
| 168 | + continue; |
| 169 | + } |
| 170 | + $notes = wfMsgExt( $msg, 'parseinline', array( $rule_desc ) ); |
| 171 | + $res = $flagger->run( $flag, $notes ); |
| 172 | + if ( 'Error' == $res['result'] ) { |
| 173 | + // TODO: Log somewhere? |
| 174 | + } |
| 175 | + } |
| 176 | + |
142 | 177 | $this->getResult()->addValue( |
143 | 178 | null, |
144 | 179 | $this->getModuleName(), |
— | — | @@ -247,9 +282,6 @@ |
248 | 283 | } |
249 | 284 | } |
250 | 285 | |
251 | | - // Create a fake title so we can pretend this is an article edit |
252 | | - $title = Title::newFromText( '__article_feedback_5__' ); |
253 | | - |
254 | 286 | // Check SpamBlacklist, if installed |
255 | 287 | if ( function_exists( 'wfSpamBlacklistObject' ) ) { |
256 | 288 | $spam = wfSpamBlacklistObject(); |
— | — | @@ -257,6 +289,7 @@ |
258 | 290 | $spam = BaseBlacklist::getInstance( 'spam' ); |
259 | 291 | } |
260 | 292 | if ( $spam ) { |
| 293 | + $title = Title::newFromText( 'ArticleFeedbackv5_' . $pageId ); |
261 | 294 | $ret = $spam->filter( $title, $value, '' ); |
262 | 295 | if ( $ret !== false ) { |
263 | 296 | return true; |
— | — | @@ -266,21 +299,103 @@ |
267 | 300 | // Check AbuseFilter, if installed |
268 | 301 | if ( class_exists( 'AbuseFilter' ) ) { |
269 | 302 | global $wgUser; |
| 303 | + |
| 304 | + // Set up variables |
| 305 | + $title = Title::newFromID( $pageId ); |
270 | 306 | $vars = new AbuseFilterVariableHolder; |
271 | 307 | $vars->addHolder( AbuseFilter::generateUserVars( $wgUser ) ); |
272 | | - $vars->addHolder( AbuseFilter::generateTitleVars( $title, 'FEEDBACK' ) ); |
| 308 | + $vars->addHolder( AbuseFilter::generateTitleVars( $title , 'ARTICLE' ) ); |
273 | 309 | $vars->setVar( 'SUMMARY', 'Article Feedback 5' ); |
274 | 310 | $vars->setVar( 'ACTION', 'feedback' ); |
275 | | - $vars->setVar( 'old_wikitext', '' ); |
276 | 311 | $vars->setVar( 'new_wikitext', $value ); |
277 | | - $vars->addHolder( AbuseFilter::getEditVars( $title ) ); |
278 | | - $filter_result = AbuseFilter::filterAction( $vars, $title ); |
279 | | - return $filter_result != '' && $filter_result !== true; |
| 312 | + $vars->setLazyLoadVar( 'new_size', 'length', array( 'length-var' => 'new_wikitext' ) ); |
| 313 | + |
| 314 | + // Add custom action handlers |
| 315 | + global $wgAbuseFilterCustomActionsHandlers; |
| 316 | + $flagCallback = array( $this, 'callbackAbuseActionFlag' ); |
| 317 | + // Not for this release |
| 318 | + // $wgAbuseFilterCustomActionsHandlers['aftv5flagabuse'] = $flagCallback; |
| 319 | + // $wgAbuseFilterCustomActionsHandlers['aftv5hide'] = $flagCallback; |
| 320 | + // $wgAbuseFilterCustomActionsHandlers['aftv5requestoversight'] = $flagCallback; |
| 321 | + |
| 322 | + // Check the filters (mimics AbuseFilter::filterAction) |
| 323 | + $vars->setVar( 'context', 'filter' ); |
| 324 | + $vars->setVar( 'timestamp', time() ); |
| 325 | + $results = AbuseFilter::checkAllFilters( $vars ); |
| 326 | + if ( count( array_filter( $results ) ) == 0 ) { |
| 327 | + return false; |
| 328 | + } |
| 329 | + |
| 330 | + // Abuse filter consequences |
| 331 | + $matched = array_keys( array_filter( $results ) ); |
| 332 | + list( $actions_taken, $error_msg ) = AbuseFilter::executeFilterActions( |
| 333 | + $matched, $title, $vars ); |
| 334 | + |
| 335 | + // Send to the abuse filter log |
| 336 | + $dbr = wfGetDB( DB_SLAVE ); |
| 337 | + $log_template = array( |
| 338 | + 'afl_user' => $wgUser->getId(), |
| 339 | + 'afl_user_text' => $wgUser->getName(), |
| 340 | + 'afl_timestamp' => $dbr->timestamp( wfTimestampNow() ), |
| 341 | + 'afl_namespace' => $title->getNamespace(), |
| 342 | + 'afl_title' => $title->getDBkey(), |
| 343 | + 'afl_ip' => wfGetIP() |
| 344 | + ); |
| 345 | + $action = $vars->getVar( 'ACTION' )->toString(); |
| 346 | + AbuseFilter::addLogEntries( $actions_taken, $log_template, $action, $vars ); |
| 347 | + |
| 348 | + // Local consequences (right now: disallow only) |
| 349 | + $disallow = false; |
| 350 | + $warn = false; |
| 351 | + foreach ( $actions_taken as $id => $actions ) { |
| 352 | + foreach ( $actions as $action ) { |
| 353 | + if ( 'disallow' == $action) { |
| 354 | + $disallow = true; |
| 355 | + } |
| 356 | + if ( 'warn' == $action ) { |
| 357 | + $warn = true; |
| 358 | + } |
| 359 | + } |
| 360 | + } |
| 361 | + if ( $warn ) { |
| 362 | + $this->warnForAbuse = $error_msg; |
| 363 | + return true; |
| 364 | + } |
| 365 | + if ( $disallow ) { |
| 366 | + return true; |
| 367 | + } |
280 | 368 | } |
281 | 369 | |
282 | 370 | return false; |
283 | 371 | } |
284 | 372 | |
| 373 | + /** |
| 374 | + * AbuseFilter callback: flag feedback (abuse, oversight, hide, etc.) |
| 375 | + * |
| 376 | + * @param string $action the action name (AF) |
| 377 | + * @param array $parameters the action parameters (AF) |
| 378 | + * @param Title $title the title passed in |
| 379 | + * @param AbuseFilterVariableHolder $vars the variables passed in |
| 380 | + * @param string $rule_desc the rule description |
| 381 | + */ |
| 382 | + public function callbackAbuseActionFlag( $action, $parameters, |
| 383 | + $title, $vars, $rule_desc ) { |
| 384 | + switch ( $action ) { |
| 385 | + case 'aftv5flagabuse': |
| 386 | + $this->autoFlag['abuse'] = $rule_desc; |
| 387 | + break; |
| 388 | + case 'aftv5hide': |
| 389 | + $this->autoFlag['hide'] = $rule_desc; |
| 390 | + break; |
| 391 | + case 'aftv5requestoversight': |
| 392 | + $this->autoFlag['oversight'] = $rule_desc; |
| 393 | + break; |
| 394 | + default: |
| 395 | + // Fall through silently |
| 396 | + break; |
| 397 | + } |
| 398 | + } |
| 399 | + |
285 | 400 | public function updateFilterCounts( $dbw, $pageId, $answers ) { |
286 | 401 | |
287 | 402 | // a new item should be in all and visible by default, increment those counters |
— | — | @@ -566,13 +681,14 @@ |
567 | 682 | private function saveUserRatings( $dbw, $data, $bucket, $params ) { |
568 | 683 | global $wgUser, $wgArticleFeedbackv5LinkBuckets; |
569 | 684 | |
570 | | - $ctaId = $this->getCTAId( $data, $bucket ); |
571 | | - $revId = $params['revid']; |
572 | | - $bucket = $params['bucket']; |
573 | | - $linkName = $params['link']; |
574 | | - $token = $this->getAnonToken( $params ); |
575 | | - $timestamp = $dbw->timestamp(); |
576 | | - $ip = null; |
| 685 | + $ctaId = $this->getCTAId( $data, $bucket ); |
| 686 | + $revId = $params['revid']; |
| 687 | + $bucket = $params['bucket']; |
| 688 | + $experiment = $params['experiment']; |
| 689 | + $linkName = $params['link']; |
| 690 | + $token = $this->getAnonToken( $params ); |
| 691 | + $timestamp = $dbw->timestamp(); |
| 692 | + $ip = null; |
577 | 693 | |
578 | 694 | if ( !$wgUser ) { |
579 | 695 | $this->dieUsage( 'User info is missing', 'missinguser' ); |
— | — | @@ -618,7 +734,8 @@ |
619 | 735 | 'af_user_id' => $wgUser->getId(), |
620 | 736 | 'af_user_ip' => $ip, |
621 | 737 | 'af_user_anon_token' => $token, |
622 | | - 'af_bucket_id' => $bucket, |
| 738 | + 'af_form_id' => $bucket, |
| 739 | + 'af_experiment' => $experiment, |
623 | 740 | 'af_link_id' => $linkId, |
624 | 741 | 'af_has_comment' => $has_comment, |
625 | 742 | ) ); |
— | — | @@ -696,7 +813,6 @@ |
697 | 814 | ); |
698 | 815 | } |
699 | 816 | |
700 | | - |
701 | 817 | /** |
702 | 818 | * Picks a CTA to send the user to |
703 | 819 | * |
— | — | @@ -756,6 +872,9 @@ |
757 | 873 | ApiBase::PARAM_TYPE => 'string', |
758 | 874 | ApiBase::PARAM_REQUIRED => true, |
759 | 875 | ), |
| 876 | + 'experiment' => array( |
| 877 | + ApiBase::PARAM_TYPE => 'string', |
| 878 | + ), |
760 | 879 | 'email' => array( |
761 | 880 | ApiBase::PARAM_TYPE => 'string', |
762 | 881 | ) |
— | — | @@ -780,11 +899,12 @@ |
781 | 900 | */ |
782 | 901 | public function getParamDescription() { |
783 | 902 | $ret = array( |
784 | | - 'pageid' => 'Page ID to submit feedback for', |
785 | | - 'revid' => 'Revision ID to submit feedback for', |
786 | | - 'anontoken' => 'Token for anonymous users', |
787 | | - 'bucket' => 'Which feedback widget was shown to the user', |
788 | | - 'link' => 'Which link the user clicked on to get to the widget', |
| 903 | + 'pageid' => 'Page ID to submit feedback for', |
| 904 | + 'revid' => 'Revision ID to submit feedback for', |
| 905 | + 'anontoken' => 'Token for anonymous users', |
| 906 | + 'bucket' => 'Which feedback form was shown to the user', |
| 907 | + 'experiment' => 'Which experiment was shown to the user', |
| 908 | + 'link' => 'Which link the user clicked on to get to the widget', |
789 | 909 | ); |
790 | 910 | $fields = ApiArticleFeedbackv5Utils::getFields(); |
791 | 911 | foreach ( $fields as $f ) { |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/api/ApiViewFeedbackArticleFeedbackv5.php |
— | — | @@ -140,7 +140,7 @@ |
141 | 141 | $where[] = $continueSql; |
142 | 142 | } |
143 | 143 | // Only show bucket 1 (per Fabrice on 1/25) |
144 | | - $where['af_bucket_id'] = 1; |
| 144 | + $where['af_form_id'] = 1; |
145 | 145 | |
146 | 146 | // Fetch the feedback IDs we need. |
147 | 147 | /* I'd really love to do this in one big query, but MySQL |
— | — | @@ -204,7 +204,7 @@ |
205 | 205 | 'aft_article_field', |
206 | 206 | 'aft_article_field_option', 'user', 'page' |
207 | 207 | ), |
208 | | - array( 'af_id', 'af_bucket_id', 'afi_name', 'afo_name', |
| 208 | + array( 'af_id', 'af_form_id', 'afi_name', 'afo_name', |
209 | 209 | 'answer.aa_response_text', 'answer.aa_response_boolean', |
210 | 210 | 'answer.aa_response_rating', 'answer.aa_response_option_id', |
211 | 211 | 'afi_data_type', 'af_created', 'user_name', |
— | — | @@ -331,7 +331,7 @@ |
332 | 332 | global $wgUser, $wgLang; |
333 | 333 | $id = $record[0]->af_id; |
334 | 334 | |
335 | | - switch( $record[0]->af_bucket_id ) { |
| 335 | + switch( $record[0]->af_form_id ) { |
336 | 336 | case 1: $content .= $this->renderBucket1( $record ); break; |
337 | 337 | case 2: $content .= $this->renderBucket2( $record ); break; |
338 | 338 | case 3: $content .= $this->renderBucket3( $record ); break; |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/sql/ArticleFeedbackv5.sql |
— | — | @@ -26,12 +26,14 @@ |
27 | 27 | -- Foreign key to revision.rev_id |
28 | 28 | af_revision_id integer unsigned NOT NULL, |
29 | 29 | -- Which feedback widget the user was given. Default of 0 is "none". |
30 | | - af_bucket_id integer unsigned NOT NULL DEFAULT 0, |
| 30 | + af_form_id integer unsigned NOT NULL DEFAULT 0, |
31 | 31 | -- Which CTA widget was displayed to the user. 0 is "none", |
32 | 32 | -- Which would come up if they got the edit page CTA, and couldn't edit. |
33 | 33 | af_cta_id integer unsigned NOT NULL DEFAULT 0, |
34 | 34 | -- Which link the user clicked on to get to the widget. Default of 0 is "none". |
35 | 35 | af_link_id integer unsigned NOT NULL DEFAULT 0, |
| 36 | + -- Which experiment this feedback is a part of (matches clicktracking). |
| 37 | + af_experiment varchar(32) NULL, |
36 | 38 | -- Creation timetamp |
37 | 39 | af_created binary(14) NOT NULL DEFAULT '', |
38 | 40 | -- Number of times the feedback was hidden or marked as abusive. |
Index: branches/wmf/1.19wmf1/extensions/ArticleFeedbackv5/sql/alter.sql |
— | — | @@ -148,3 +148,13 @@ |
149 | 149 | -- make sure all old feedback has dates, even if they're wrong |
150 | 150 | UPDATE aft_article_feedback SET af_hide_timestamp = NOW() WHERE af_is_hidden IS TRUE AND af_hide_timestamp = ''; |
151 | 151 | UPDATE aft_article_feedback SET af_oversight_timestamp = NOW() WHERE af_is_deleted IS TRUE AND af_oversight_timestamp = ''; |
| 152 | + |
| 153 | +-- Added 3/29 (reha) |
| 154 | +ALTER TABLE /*_*/aft_article_feedback CHANGE COLUMN af_bucket_id af_form_id INTEGER UNSIGNED NOT NULL DEFAULT 0; |
| 155 | +ALTER TABLE /*_*/aft_article_feedback ADD COLUMN af_experiment varchar(32) NULL; |
| 156 | +CREATE INDEX /*_*/af_experiment ON /*_*/aft_article_feedback (af_experiment); |
| 157 | +UPDATE /*_*/aft_article_feedback SET af_experiment = af_form_id WHERE DATE(af_created) <= '2012-03-21'; |
| 158 | +UPDATE /*_*/aft_article_feedback SET af_experiment = CONCAT(af_form_id, 'A') WHERE DATE(af_created) > '2012-03-21' AND af_link_id = 1; |
| 159 | +UPDATE /*_*/aft_article_feedback SET af_experiment = CONCAT(af_form_id, 'E') WHERE DATE(af_created) > '2012-03-21' AND af_link_id = 5; |
| 160 | +UPDATE /*_*/aft_article_feedback SET af_experiment = CONCAT(af_form_id, '?') WHERE DATE(af_created) > '2012-03-21' AND af_link_id = 0; |
| 161 | + |