User:Nx/Extensions/bestof/bestof.php

From RationalWiki
Jump to navigation Jump to search
<?php

# This extension requires a table in the database, create it with the following mysql command:
# replace varbinary with varchar depending on wiki setup
# create table /*$wgDBprefix*/wigotext (vote_id varbinary(255) NOT NULL, text mediumblob, is_cp boolean default false, PRIMARY KEY (vote_id)) /*$wgDBTableOptions*/;

//version 3.5 database addition:
//alter table wigotext add column is_cp boolean default false;

// Extension credits that show up on Special:Version
$wgExtensionCredits['parserhook'][] = array(
        'name' => 'Best of display system',
        'author' => '[http://rationalwiki.com/wiki/User:Tmtoulouse Trent Toulouse], [http://rationalwiki.com/wiki/User:Nx Nx]',
        'url' => 'http://rationalwiki.com/',
        'description' => 'Displays WIGO items sorted by votes, with custom settings.',
        'version' => '3.5'
);

$wgBestofIP = dirname( __FILE__ );
$wgExtensionMessagesFiles['bestof'] = "$wgBestofIP/bestof.i18n.php";

//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
	$wgHooks['ParserFirstCallInit'][] = 'bestofinit';
} else { // Otherwise do things the old fashioned way
	$wgExtensionFunctions[] = 'bestofinit';
}

$wgHooks['ArticleSaveComplete'][] = 'bestofharvest';

global $wgUseAjax;
if ($wgUseAjax)
{
  $wgAjaxExportList[] = "bestofget";
}

function bestofinit()
{
  global $wgParser;
  wfLoadExtensionMessages('bestof');  
  $wgParser->setHook('bestof','bestofrender');
  return true;  
}

function image(&$input,$pollid) {
  $input = preg_replace('/\[[^\]]*conservapedia\.com[^\]]*\]/i',
                        "$0<sup>[[:Image:{$pollid}_x.png|img]]</sup>",$input);
  $x = 0;
  do {
    $input = preg_replace('/(<sup>\[\[:Image:' . $pollid . '_)x(\.png\|img\]\]<\/sup>)/',
                        "$1 {$x}$2", $input,1,$count);
    ++$x;
  } while ($count);
}

function imagecp(&$output, $parser) {
  $matchi = preg_match_all('/(<a[^>]*href="([^"]*conservapedia\.com[^"]*)"[^>]*>(?:[^<]|<[^\/]|<\/[^a]|<\/a[^>])*<\/a>)(?!<span class="wigocapture">)/i', $output,$matches,PREG_OFFSET_CAPTURE);
  if ($matchi > 0) $newoutput = substr($output,0,$matches[1][0][1]);
  for ($i=0; $i<$matchi;++$i) {
    $imgname = 'capture_' /*. $args['poll'] . '_'*/ . /*crc32*/ /*md5*/ sha1($matches[2][$i][0]) . '.png';
    $text = $matches[1][$i][0];    
    $img =  $parser->recursiveTagParse("<span class=\"wigocapture\"><sup>[[:Image:$imgname|img]]</sup></span>");
    $nextlength = (($i == $matchi-1) ? (strlen($output) - ($matches[1][$i][1] + strlen($text))) : ($matches[1][$i+1][1] - ($matches[1][$i][1] + strlen($text))));
    $newoutput .= substr($output,$matches[1][$i][1],strlen($text)) . $img . 
                  substr($output,$matches[1][$i][1]+strlen($text),$nextlength);
  }
  if ($matchi > 0) $output = $newoutput;
}

function bestofharvest( &$article, &$user, $text, $summary, &$minoredit, $watchthis, $sectionanchor, &$flags ) {
  Sanitizer::removeHTMLcomments($text);
  $matchnum = preg_match_all('/<vote(cp|)[^>]*poll=([^ >]*|"[^"]*")[^>]*>(.*?)<\/vote(?:cp|)>/',$text,$matches,PREG_SET_ORDER);
  $dbw = wfGetDB(DB_MASTER);
  foreach ($matches as $match) {
    $hasimg = ( (strpos($match[0],'img="on"') !== false) || (strpos($match[0],'img="expanded"') !== false) );
    $hasimgcp = ( $match[1] == "cp" );
    $voteid = $match[2];
    $wtext = $match[3];
    if ($hasimg) {
      image($wtext,$voteid);
    }
    $dbw->replace('wigotext','vote_id',array('vote_id' => $voteid, 'text' => $wtext, 'is_cp' => $hasimgcp),__METHOD__);
  }
  $dbw->commit();
  return true;
}

function bestofrender($input, $args, $parser)
{
  $parser->disableCache();
  if ($args['dynamic']) {
    global $wgRequest;
    global $wgTitle;
    $cutoff = $wgRequest->getVal('bfcutoff', array_key_exists('cutoff',$args) ? $args['cutoff'] : null);
    $year = $wgRequest->getVal('bfyear', array_key_exists('year',$args) ? $args['yar'] : null);
    $month = $wgRequest->getVal('bfmonth', array_key_exists('month',$args) ? $args['month'] : null);
    $keyword = $wgRequest->getVal('bfsearch', array_key_exists('keyword',$args) ? $args['keyword'] : null);
    
    wfLoadExtensionMessages('bestof');
    
    global $wgLang;
    $selected = $month === null ? 'all' : intval($month);
    $monthopts[] = Xml::option(wfMsg('monthsall'),'all',$selected === 'all');
    for ($i = 1; $i < 13; ++$i)
    {
      $monthopts[] = Xml::option($wgLang->getMonthName($i),$i, $selected === $i);
    }
    $forminside = Xml::openElement('table',array('cellpadding' => 8)) .
                  Xml::openElement('tr') .
                    Xml::openElement('td') .
                      Xml::label(wfMsg('bestof-cutoff'),'bfcutoff') .
                    Xml::closeElement('td') .
                    Xml::openElement('td') .                  
                      Xml::label(wfMsg('bestof-month'),'bfmonth') .
                    Xml::closeElement('td') .
                    Xml::openElement('td') .
                      Xml::label(wfMsg('bestof-filter'),'bfsearch') .
                    Xml::closeElement('td') .
                  Xml::closeElement('tr') . "\n" .
                  Xml::openElement('tr') .
                    Xml::openElement('td') .
                      Xml::input( 'bfcutoff', 3, $cutoff, array('maxlength' => 3) ) . ' '.
                    Xml::closeElement('td') .
                    Xml::openElement('td') . 
                      Xml::input( 'bfyear', 4, $year, array('maxlength' => 4) ) . ' '.
                      Xml::openElement('select',array('name' => 'bfmonth','class' => 'mw-month-selector')) .
                        implode("\n",$monthopts) .
                      Xml::closeElement('select') .
                    Xml::closeElement('td') .
                    Xml::openElement('td') .
                      Xml::input( 'bfsearch', 25, $keyword ) . ' '.
                    Xml::closeElement('td') .
                    Xml::openElement('td') .
                      Xml::submitButton(wfMsg('bestof-submit')) .
                    Xml::closeElement('td') .
                  Xml::closeElement('tr') .
                  Xml::closeElement('table');
    foreach ($wgRequest->getValues() as $key => $value)
    {
      if ($key != 'bfcutoff' && $key != 'bfyear' && $key != 'bfmonth' && $key != 'bfsearch') {
        $forminside .= "\n" . Xml::hidden($key,$value);
      }
    }
    $form = Xml::openElement('form', array( 'id' => 'bestofoption', 
                                            'action' => '',
                                            'method' => $wgRequest->wasPosted() ? 'POST' : 'GET' ) ) .
            Xml::fieldset(wfMsg('bestof-legend'),$forminside) .
            Xml::closeElement('form');
    $output = $form;
  } else {
    $cutoff = $args['cutoff'];
    $year = $args['year'];
    $month = $args['month'];
    $keyword = $args['keyword'];
  }
  $list = bestofget($args['poll'],$cutoff,$month === 'all' ? null : $month,$year,$keyword,$parser);          
  $output .= $list;
  return $output;
}

function bestofget($pollid, $cutoff, $month, $year, $keyword, $parser)
{
  $dbr = wfGetDB(DB_SLAVE);
  $conds = array("vote_id LIKE \"$pollid%\"");
  $options = array('GROUP BY' => 'vote_id','ORDER BY' => 'total DESC');
  if ($cutoff != null)
  {
    $options['HAVING'] = "total >= {$cutoff}";
  }
  if ($month != null && $year != null)
  {
    $month = str_pad($month,2,'0',STR_PAD_LEFT);
    $conds[] = "timestamp LIKE \"{$year}{$month}%\"";
  } elseif ($month == null && $year != null) {
    $conds[] = "timestamp LIKE \"{$year}%\"";
  } elseif ($month != null && $year == null) {
    $month = str_pad($month,2,'0',STR_PAD_LEFT);
    $conds[] = "timestamp LIKE \"____{$month}%\"";
  }
  if ($keyword != null) {
    $conds[] = "text LIKE \"%{$keyword}%\"";
  }
  $res = $dbr->select(array('wigovote','wigotext'),
                      array('sum(case vote when 1 then 1 else 0 end) as plus',
                            'sum(case vote when -1 then 1 else 0 end) as minus',
                            'sum(case vote when 0 then 1 else 0 end) as zero',
                            'ifnull(sum(vote),0) as total',
                            'vote_id', 'text','is_cp'),
                      $conds,
                      __METHOD__,
                      $options,
                      array('wigotext' => array('RIGHT JOIN','id=vote_id')));
  $output="<table cellspacing=\"2\" cellpadding=\"2\" border=\"0\">";
  wfLoadExtensionMessages('wigo3');
  static $sep = null;
  if (is_null($sep)) $sep = wfMsg('bestof-tooltipseparator');
  while ($row = $res->fetchRow()) {
    $plus = $row['plus'];
    $minus = $row['minus'];
    $zero = $row['zero'];
    $numvotes = $plus+$minus+$zero;
    $total = $plus - $minus;
    //wfMsgExt resets the parser state if the message contains a parser function, breaking for example references. recursiveTagParse doesn't.
    //$totalvotes = htmlspecialchars($row['vote_id']) . " &bull; " . wfMsgExt('wigovotestotald',array('parsemag'),array($numvotes,$plus,$zero,$minus));
    $totalvotes = htmlspecialchars($row['vote_id']) . $sep . $parser->recursiveTagParse(wfMsgNoTrans('wigovotestotald',array($numvotes,$plus,$zero,$minus)));
    $text = $parser->recursiveTagParse($row['text']);
    if ($row['is_cp']) {
      imagecp($text,$parser);
    }
    $output .= "<tr><td width=20px valign=top title=\"{$totalvotes}\">{$total}</td><td>{$text}</td></tr>";
  }
  $output.="</table>";
  $res->free();  
  return "$output";
}