MediaWiki:Gadget-contribsrange.js

Fra Wikipedia, den frie encyklopedi

Merk: Etter publisering vil det kanskje være nødvendig å slette mellomlageret i nettleseren din for å se endringene.

  • Firefox / Safari: Hold Shift mens du klikker på Oppdater, eller trykk enten Ctrl+F5 eller Ctrl+R (⌘+R på Mac)
  • Google Chrome: Trykk Ctrl+Shift+R (⌘+Shift+R på Mac)
  • Internet Explorer / Edge: Hold Ctrl mens du trykker på Oppdater eller trykk Ctrl+F5
  • Opera: Ttrykk Ctrl+F5.
/* Special:Contributions Wildcard/CIDR lookup, version [0.2.13]
Originally from: http://en.wikipedia.org/wiki/User:Splarka/contribsrange.js

Notes:
* Uses the API which is faster than most CIDR contrib tools.
* Only currently works if submitted (or called by URL parameter, eg Special:Contributions/User).
** Checks namespace and date options in form.
** Also utilizes &ucstart and &ucend date parameters if supplied manually (not supported in the UI atm).
*** These parameter soverride the form date options.
* Uses: Submit any IP CIDR range /16 or from /24 to /32. Submit any string (at least 3 characters) with a suffixed asterisk.
** eg: [123.123.123.0/24 ] or [123.123.123.* ] or [Willy* ].
* Now keeps searching until it finds crMax (or forever with crshowall=true URI parameter).
** Puts them in a nice collapsed div stack, like enhanced recent changes.
* /25 and /26 ranges now disabled, since they are inaccurate (50 parameter limit), please use /24 (ucuserprefix) or /27 (32 parameters)

*/

(function contribsrange(){

  if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Contributions' ) { 
    return;
  }

  var apiQuery = {};  //query object for continuing later
  var crLimit = 500;  //limit for each query
  var crMax = 10000;  //bypass with &crshowall=true URI parameter
  var crImgHid = '//upload.wikimedia.org/wikipedia/commons/a/ad/Arr_r.png';
  var crImgSho = '//upload.wikimedia.org/wikipedia/commons/f/f0/Arr_d.png';

  function getMsg( msg ) {
    var s = {
      'header-text': 'Javascript-enhanced contributions lookup 0.2 enabled. You may enter a CIDR range or append an asterisk to do a prefix search.',
      'very-many-results': 'Whoa! Finding a lot. To load everything, click <a href="$1">here</a>. (Warning: May bog down browser!)',
      'no-results': 'No changes were found for this wildcard/CIDR range.',
      'toogle-all': 'toogle all',
      'searching': 'Searching',
      'talk': 'talk',
      'diff': 'diff',
      'n-contributions-found': '$1 contributions found'
    }[msg];
    if ( s === undefined ) return;
    var args = Array.prototype.slice.call(arguments, 1);
    $.each( args, function( key, val ) {
      s = s.replace( new RegExp( '\\$' + (key + 1) ), val );
    });
    return s;
  }
  
  mw.loader.using( ['jquery.spinner'], function init() {

    mw.util.addCSS( '.cr-list {padding-left:5px;}\n.cr-toggle-hidden {padding-left:16px;background: transparent no-repeat center left url("' + crImgHid + '")}' 
    + '\n.cr-toggle-shown {padding-left:16px;background: transparent no-repeat center left url("' + crImgSho + '")}\n.mw-mightexist {font-style:italic;}'
    + '\n#results-from-CIDR {border:1px solid black;padding:.5em}\n#prefixcontribs-tog {float:right;border:1px solid black;text-decoration:none;color:black;padding:0 5px;}' );

    $( '<div>' )
      .text( getMsg( 'header-text' ) )
      .appendTo( '#contentSub, #topbar' );

    var input = {
      target: $( 'input[name="target"]' ).val(),
      namespace: $( 'select[name="namespace"]' ).val(),
      year: $( 'input[name="year"]' ).val(),
      month: $( 'select[name="month"]' ).val()
    };

    //general optionlets independent of type of search.
    apiQuery = {
      action: 'query',
      format: 'json',
      list: 'usercontribs',
      ucprop: 'ids|title|timestamp|comment|size|sizediff',
      uclimit: parseInt( crLimit, 10 ),
      ucdir: 'older'
    };

    if ( parseInt( input.namespace, 10 ) > -1 ) {
      apiQuery.ucnamespace = input.namespace;
    }

    if ( input.month === '-1' ) {  // "all" (should be equivalent to December, shouldn't it?)
      input.month = '12';
    }

    if ( input.year.match( /^[0-9]{4}$/ ) ) {  // Looks like a year
      // By using 0 as day we get the last date of the previous month 
      apiQuery.ucstart = ( new Date( parseInt( input.year, 10 ), parseInt( input.month, 10 ), 0 ) ).toISOString();
    }

    // Override with values from query string if specified
    if ( queryString( 'ucstart' ) ) apiQuery.ucstart = queryString( 'ucstart' );
    if ( queryString( 'ucend') ) apiQuery.ucend = queryString( 'ucend' );
    
    // CIDR match
    var cidrMatches = input.target.match( /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(2[7-9]|3[0-2]|24|16)/i );
    if ( cidrMatches ) {

      prefixContribsStartbox();
      var cidr = cidrMatches[0];
      var range = cidr.match( /[^\/]\d{1,2}$/i )[0];

      if ( range === '24' || range === '16') {

        //prefixable CIDR, lets do-er
        if ( range === '24' ) {
          cidr = cidr.match( /\d{1,3}\.\d{1,3}\.\d{1,3}\./ )[0];
        } else {
          cidr = cidr.match( /\d{1,3}\.\d{1,3}\./ )[0];
        }
        apiQuery.ucuserprefix = cidr;

      } else {

        //complex CIDR, lets figure it out
        var oct3 = cidr.match( /\.\d{1,3}\//i )[0].replace( /(\.|\/)/g, '' );
        cidr = cidr.match( /\d{1,3}\.\d{1,3}\.\d{1,3}\./ )[0];
        var num = Math.pow( 2, 32 - range );
        var start = oct3 - oct3 % num;
        var ucuser = '';
        for ( var i = start; i <= start + num; i++ ) {
          ucuser += '' + cidr + i;
          if ( i !== start + num ) ucuser += '|';
        }
        apiQuery.ucuser = ucuser;

      }

    // Simple wildcard match
    } else if ( input.target.search( /^.{3,}\*$/i ) === 0 ) {

      prefixContribsStartbox();
      var prefix = input.target.replace( /\*$/, '' );
      prefix = prefix.substr( 0, 1 ).toUpperCase() + prefix.substr( 1 );
      apiQuery.ucuserprefix = prefix;

    }
    $.getJSON( mw.util.wikiScript( 'api' ), apiQuery, prefixContribs );

  });

  function prefixContribsStartbox() {
    var $div = $( '<div id="results-from-CIDR"></div>' ).appendTo( '#mw-content-text' );
    $( '<a href="#" id="prefixcontribs-tog">' + getMsg( 'toogle-all' ) + '</a>' ).appendTo( $div )
      .on( 'click', function ( e ) {
        e.preventDefault();
        prefixContribsToggleAll();
      });
    $div.append( '<span id="prefixcontribs-prog">' + getMsg( 'searching' ) + '</span>' );
    $( '#prefixcontribs-prog' ).injectSpinner( 'prefixcontribs-spin' );
  }

  function prefixContribs( obj ) {
    if ( !obj.query || !obj.query.usercontribs ) {
      return;
    }
    var res = $( '#results-from-CIDR' );
    if ( !obj.query.usercontribs.length ) {
      $.removeSpinner( 'prefixcontribs-spin' );
      res.html( getMsg( 'no-results' ) );
      return;
    }

    var $results;
    var $li;
 
    $.each( obj.query.usercontribs, function( i, contribution ) {

      var id = 'cr-' + escapeID( contribution.user );
      var etitle = encodeURIComponent( contribution.title.replace( / /g, '_' ))
          .replace( '%2F', '/' )
          .replace( '%3A', ':' );
      var euser = encodeURIComponent( contribution.user.replace( / /g, '_' ))
          .replace( '%2F', '/' )
          .replace( '%3A', ':' );

      // group each result set based on the user name, create new div for new names
      if ( !$( '#' + id ).length ) {
        $results = $( '<div id="d-' + id + '"></div>' ).appendTo( res );

        $( '<a href="#" id="m-' + id + '" class="cr-toggle-hidden">' + contribution.user + '</a>' )
          .appendTo( $results )
          .on( 'click', (function( id ) {
            return function( e ) {
              e.preventDefault();
              prefixContribsToggleDiv( id );
            };
          })( id ));

          $results.append( '<ul id="' + id + '" class="cr-list" style="display:none;"></ul>' );
      }

      $li = $( '<li> ' )
        //.append( '<a href="' + mw.util.wikiScript( 'index' ) + '?title=Special:Contributions/' + euser + '">' + contribution.user + '</a>' )
        //.append( ' (<a href="' + mw.util.wikiScript( 'index' ) + '?title=User_talk:' + euser + '" class="mw-mightexist">' + getMsg( 'talk' ) + '</a>)' )
        .append( ' <a href="' + mw.util.wikiScript( 'index' ) + '?title=' + etitle + '&oldid=' + contribution.revid + '">' + contribution.timestamp.replace( /[TZ]/g, ' ' ) + '</a>' )
        .append( ' (<a href="' + mw.util.wikiScript( 'index' ) + '?title=' + etitle + '&diff=prev&oldid=' + contribution.revid + '">' + getMsg( 'diff' ) + '</a>)' )
        .append( ' <a href="' + mw.util.wikiScript( 'index' ) + '?title=' + etitle + '">' + contribution.title + '</a>' );

      if ( contribution.comment ) {
        $li.append( ' (' + contribution.comment + ')' );
      }
      if ( contribution.sizediff ) {
        $li.append( ' [' + contribution.sizediff.toString().replace( /^(\d)/i,'+$1' ) + ']' );
      }

      $( '#' + id ).append( $li );
    });

    //continue?
    crMax = crMax - obj.query.usercontribs.length;

    var prog = $( '#prefixcontribs-prog' );
    if ( !obj['query-continue'] || !obj['query-continue'].usercontribs || !obj['query-continue'].usercontribs.uccontinue ) {
      $.removeSpinner( 'prefixcontribs-spin' );  
      prog.remove();
      prefixContribsNumerate();
      return;
    }

    apiQuery.uccontinue = obj['query-continue'].usercontribs.uccontinue;
    if ( crMax <= 0 && queryString( 'crshowall' ) !== 'true' ) {
      var gaurl = document.location.href;
      if ( gaurl.indexOf( '#' ) !== -1 ) gaurl = gaurl.substr( 0, gaurl.indexOf( '#' ) );
      if ( gaurl.indexOf( '?' ) === -1 ) gaurl += '?';
      gaurl += '&crshowall=true';

      prog.append( getMsg( 'very-many-results', gaurl ) );

      $.removeSpinner( 'prefixcontribs-spin' );
      prefixContribsNumerate();
    } else {
      prog.append( '.' );
      $.getJSON( mw.util.wikiScript( 'api' ), apiQuery, prefixContribs );
    }
  }

  function prefixContribsNumerate() {

    $( 'ul.cr-list' ).each( function( idx, itm ) {
      $( itm ).before( ', ' + getMsg( 'n-contributions-found', $( itm ).find( 'li' ).length));
    });

    if ( $( 'ul.cr-list' ).length === 1 ) {
      prefixContribsToggleDiv( $( 'ul.cr-list' )[0].id );
    }
  }

  function prefixContribsToggleAll() {
    $( 'ul.cr-list' ).each( function( key, itm ) {
      prefixContribsToggleDiv( $( itm ).prop( 'id' ));
    });
  }

  function prefixContribsToggleDiv( id ) {
    var i = $( '#' + id );
    var m = $( '#m-' + id );
    if ( i.length === 0 || m.length === 0 ) return;
    i.toggle();
    if ( i.is( ':visible' ) ) {
      m.removeClass( 'cr-toggle-hidden' ).addClass( 'cr-toggle-shown' );
    } else {
      m.removeClass( 'cr-toggle-shown' ).addClass( 'cr-toggle-hidden' );
    }
  }

  function escapeID( txt ) {
    var id = txt;
    id = id.replace( / /g, '_' );
    id = encodeURIComponent( id );
    id = id.replace( /\%3A/g, ':') ;
    id = id.replace( /\%/g, '.') ;
    id = id.replace( /\./g, '_' );
    return id;
  }

  function queryString( p ) {
    var re = new RegExp( '[&?#]' + p + '=([^&#]*)' );
    var matches = re.exec( document.location );
    if ( matches ) {
      try { 
        return decodeURI( matches[1] );
      } catch ( e ) {
      }
    }
    return null;
  }

  //Support for IE8 and older, via: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toISOString
  if ( !Date.prototype.toISOString ) {
    (function() {
      function pad(number) {
        var r = String(number);
        if (r.length === 1) {
          r = '0' + r;
        }
        return r;
      }
      Date.prototype.toISOString = function() {
        return this.getUTCFullYear()
          + '-' + pad(this.getUTCMonth() + 1)
          + '-' + pad(this.getUTCDate())
          + 'T' + pad(this.getUTCHours())
          + ':' + pad(this.getUTCMinutes())
          + ':' + pad(this.getUTCSeconds())
          + '.' + String((this.getUTCMilliseconds()/1000).toFixed(3)).slice(2,5)
          + 'Z';
      };
    }());
  }

})();