User:Nx/Extensions/wigo3/wigo3.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*/wigovote (id varbinary(255) NOT NULL, voter_name varbinary(255) NOT NULL, vote int NOT NULL default 0, timestamp varbinary(14), PRIMARY KEY (id,voter_name)) /*$wgDBTableOptions*/;

if ( !defined( 'MEDIAWIKI' ) ) {
	exit;
}

# store ips instead of usernames for logged in users too
$wgWigo3ConfigStoreIPs = true;

$wgExtensionCredits['parserhook'][] = array(
        'name' => 'WIGO Voting Extension',
        'author' => '[http://rationalwiki.com/wiki/User:Nx Nx]',
        'url' => 'http://rationalwiki.com/',
        'description' => 'Up/down voting system.',
        'version' => '3.5'
);

$wgWigoIP = dirname( __FILE__ );
$wgExtensionMessagesFiles['wigo3'] = "$wgWigoIP/wigo3.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'][] = 'wigo3init';
} else { // Otherwise do things the old fashioned way
	$wgExtensionFunctions[] = 'wigo3init';
}

$wgHooks['AjaxAddScript'][] = 'wigo3addjs';

global $wgUseAjax;
if ($wgUseAjax)
{
  $wgAjaxExportList[] = "wigovote";
  $wgAjaxExportList[] = "wigovote2";
  $wgAjaxExportList[] = "wigoinvalidate";
}

function wigo3init() {
  global $wgParser;
  wfLoadExtensionMessages('wigo3');
  $wgParser->setHook('vote','wigo3render');
  $wgParser->setHook('votecp','wigo3rendercp');
  $wgParser->setHook('capture','wigo3rendercapture');
  return true;
}

function wigo3addjs($out) {
  global $wgJsMimeType, $wgScriptPath;
  $out->addScript("<script type=\"{$wgJsMimeType}\" src=\"{$wgScriptPath}/extensions/wigo3/js/wigo3.js\"></script>");
  return true;
}

function wigoinvalidate($pagename)
{
  //$pagename is wgPageName from javascript  
  $title = Title::newFromText($pagename);
  if ($title->invalidateCache() === true) {
    $dbw = wfGetDB(DB_MASTER);
    $dbw->commit();
    return "ok";
  } else {
    return "notok";
  }
}

/*
kept for compatibility
*/
function wigovote($pollid, $vote, $min=-1, $max=1)
{
  $dbw = wfGetDB(DB_MASTER);
  global $wgUser, $wgWigo3ConfigStoreIPs;
  $voter = $wgWigo3ConfigStoreIPs ? getenv ("REMOTE_ADDR") : $wgUser->getName();
  $result = $dbw->replace('wigovote',array('id','voter_name'),array('id' => $pollid, 'voter_name' => $voter, 'vote' => $vote, 'timestamp' => wfTimestampNow()),'wigovote');
  $res = $dbw->select('wigovote',array('sum(vote)','count(vote)'),array('id' => $pollid, "vote >= {$min}", "vote <= {$max}"),'wigovote',array('GROUP BY' => 'id'));
  $row = $res->fetchRow();
  $vote = $row['sum(vote)'];
  $countvotes = $row['count(vote)'];
  wfLoadExtensionMessages('wigo3');
  $totalvotes = wfMsgExt('wigovotestotal',array('parsemag'),array($countvotes));
  $res->free();
  $dbw->commit();
  $dbw->close();
  return "$pollid:$vote:$countvotes:$totalvotes:$result";
}

/*
voting function for up-down wigo only
*/
function wigovote2($pollid, $vote)
{
  /*store the vote*/
  $dbw = wfGetDB(DB_MASTER);
  global $wgUser, $wgWigo3ConfigStoreIPs;
  $voter = $wgWigo3ConfigStoreIPs ? getenv ("REMOTE_ADDR") : $wgUser->getName();
  $result = $dbw->replace('wigovote',array('id','voter_name'),array('id' => $pollid, 'voter_name' => $voter, 'vote' => $vote, 'timestamp' => wfTimestampNow()),'wigovote');
  $dbw->commit();
  
  /*get updated data to update page*/
  $plus = 0;
  $minus = 0;
  $zero = 0;
  $myvote = -2;

  wigo3getvotes($pollid, $plus, $minus, $zero,$voter,$myvote);
  
  wfLoadExtensionMessages('wigo3');
  $totalvotes = $plus + $minus + $zero;
  $totaltooltip = wfMsgExt('wigovotestotald',array('parsemag'),array($totalvotes,$plus,$zero,$minus));
/*  $totalup = wfMsgExt('wigovotestotal',array('parsemag'),array($plus));
  $totaldown = wfMsgExt('wigovotestotal',array('parsemag'),array($minus));
  $totalneutral = wfMsgExt('wigovotestotal',array('parsemag'),array($zero));*/
  $distribtitle = wfMsgExt('wigovotedistrib',array('parsemag'),array($plus,$zero,$minus));
  return "$pollid:$plus:$minus:$zero:$totalvotes:$totaltooltip:$distribtitle:$myvote:$result";
}

function wigo3getvotes($voteid, &$plus, &$minus, &$zero, $voter, &$myvote) {
  $dbr = wfGetDB(DB_SLAVE);
  $res = $dbr->select('wigovote',
                      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'),
                      array('id' => $voteid),__FUNCTION__);
  if ($row = $res->fetchRow())
  {
    $plus = $row['plus'];
    $minus = $row['minus'];
    $zero = $row['zero'];
  }
  if ($plus == null) {
    $plus = 0;
  }
  if ($minus == null) {
    $minus = 0;
  }
  if ($zero == null) {
    $zero = 0;
  }
  $res->free();
  //myvote does not work with caching
/*  $myvote = $dbr->selectField('wigovote','vote',array('id' => $voteid, 'voter_name' => $voter),__FUNCTION__);
  if ($myvote === false) {
    $myvote = -2;
  }*/
  $myvote = -2;
}

function wigo3rendercp($input, $args, $parser) {
  return wigo3render($input, $args, $parser,true);
}

function wigo3render($input, $args, $parser, $cp = false) {
  //disabled to improve performance
  //$parser->disableCache();
  $voteid = $args['poll'];
  if (!$voteid)
  {
    static $err = null;
    if (is_null($err)) {
      wfLoadExtensionMessages('wigo3');
      $err = wfMsg('wigoerror');
    }
    $output = $parser->recursiveTagParse($input);
    return "<p><span style='color:red;'>{$err}</span> {$output}</p>";
  }
  
  $plus = 0;
  $minus = 0;
  $zero = 0;
  $myvote = -2;
  global $wgUser, $wgWigo3ConfigStoreIPs;
  $voter = $wgWigo3ConfigStoreIPs ? getenv ("REMOTE_ADDR") : $wgUser->getName();
  wigo3getvotes($voteid,$plus,$minus,$zero,$voter,$myvote);
  $votes = $plus - $minus;
  $countvotes = $plus + $minus + $zero;

  //backwards compatible img tag handling
  if (!$cp && array_key_exists('img',$args) && (!strcmp($args['img'],'on') || !strcmp($args['img'],'expanded'))) {
    $input = preg_replace('/\[[^\]]*conservapedia\.com[^\]]*\]/i',
                          "$0<sup>[[:Image:{$args['poll']}_x.png|img]]</sup>",$input);
    $x = 0;
    do {
      $input = preg_replace('/(<sup>\[\[:Image:' . $args['poll'] . '_)x(\.png\|img\]\]<\/sup>)/',
                          "$1 {$x}$2", $input,1,$count);
      ++$x;
    } while ($count);
  }

  $output = $parser->recursiveTagParse($input);  
  //votecp img tag handling
  if ($cp)
  {
    $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) {
      //performance impact of sha1 is 1.2x
      $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;  
  }  

  //wfMsgExt resets the parser state if the message contains a parser function, breaking for example references. recursiveTagParse doesn't.
  wfLoadExtensionMessages('wigo3');
  //$totalvotes = wfMsgExt('wigovotestotald',array('parsemag'),array($countvotes,$plus,$zero,$minus));
  $totalvotes = htmlspecialchars($parser->recursiveTagParse(wfMsgNoTrans('wigovotestotald',array($countvotes,$plus,$zero,$minus))));
/*  $totalup = wfMsgExt('wigovotestotal',array('parsemag'),array($plus));
  $totaldown = wfMsgExt('wigovotestotal',array('parsemag'),array($minus));
  $totalneutral = wfMsgExt('wigovotestotal',array('parsemag'),array($zero));*/
  //$distribtitle = wfMsgExt('wigovotedistrib',array('parsemag'),array($plus,$zero,$minus));
  $distribtitle = htmlspecialchars($parser->recursiveTagParse(wfMsgNoTrans('wigovotedistrib',array($plus,$zero,$minus))));
  if ($countvotes != 0) {
    $uppercent = ($plus / $countvotes) * 100;
    $downpercent = ($minus / $countvotes) * 100;
    $neutralpercent = ($zero / $countvotes) * 100;
  } else {
    $uppercent = 0;
    $downpercent = 0;
    $neutralpercent = 0;
  }
  
  if ($uppercent != 0) {
    $uppercent .= "%";
  }
  if ($neutralpercent != 0) {
    $neutralpercent .= "%";
  }
  if ($downpercent != 0) {
    $downpercent .= "%";
  }
  
  if (array_key_exists('closed',$args) && strcasecmp($args['closed'],"yes") === 0) {
    return "<table class=\"vote\" cellspacing=\"2\" cellpadding=\"2\" border=\"0\">" .
              "<tr>" .
                "<td style=\"white-space:nowrap;\">" .
                    "<table id=\"{$voteid}-dist\" class=\"wigodistribution\" style=\"width:48px; height:6px; border:1px solid grey; margin:0; padding:0; border-spacing:0;\" title=\"{$distribtitle}\">" .
                      "<tr>" .
                        "<td class=\"wigodist-up\" style=\"border:none; background-color:limegreen; margin:0; padding:0; width:{$uppercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                        "<td class=\"wigodist-neutral\" style=\"border:none; background-color:orange; margin:0; padding:0; width:{$neutralpercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                        "<td class=\"wigodist-down\" style=\"border:none; background-color:red; margin:0; padding:0; width:{$downpercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                    "</tr></table>" .
                "</td>" .
                "<td style=\"min-width:25px; text-align:center;\">" .
                  "<span id=\"{$voteid}\" title=\"{$totalvotes}\">{$votes}</span>" .
                "</td>" .
                "<td style=\"vertical-align:middle;\">" .
                  "<!--$voteid-->$output" .
                "</td>" .
              "</tr>" .
            "</table>";
  } else {
    //get up-down images
    //static improves performance a bit
    static $up = null;
    static $down = null;
    static $reset = null;
    static $altup = null;
    static $altdown = null;
    static $altreset = null;
    static $titleup = null;
    static $titledown = null;
    static $titlereset = null;

    if ( is_null($up) || is_null($down) || is_null($reset) 
         || is_null($altup) || is_null($altdown) || is_null($altreset) 
         || is_null($titleup) || is_null($titledown) || is_null($titlereset) ) {
      wfLoadExtensionMessages('wigo3');
      $up = wfFindFile(wfMsg('wigouparrow'));
      $up = $up ? $up->getFullUrl() : '';
      $down = wfFindFile(wfMsg('wigodownarrow'));
      $down = $down ? $down->getFullUrl() : '';
      $reset = wfFindFile(wfMsg('wigoresetvote'));
      $reset = $reset ? $reset->getFullUrl() : '';
      $altup = wfMsgHtml('wigoaltup');
      $altdown = wfMsgHtml('wigoaltdown');
      $altreset = wfMsgHtml('wigoaltreset');
      $titleup = wfMsgHtml('wigotitleup');
      $titledown = wfMsgHtml('wigotitledown');
      $titlereset = wfMsgHtml('wigotitlereset');
    }

    return "<table class=\"vote\" cellspacing=\"2\" cellpadding=\"2\" border=\"0\">" .
              "<tr>" .
                "<td style=\"white-space:nowrap;\">" .
                  "<a " . "href=\"javascript:wigovoteup('{$voteid}')\" id=\"{$voteid}-up\" class=\"wigobutton wigoupbutton " . ($myvote == 1 ? "myvotebutton" : "") . " \">" .
                    "<img alt=\"{$altup}\" title=\"{$titleup}\" src=\"$up\"></img></a>" .
                  "<a " . "href=\"javascript:wigovotereset('{$voteid}')\" id=\"{$voteid}-neutral\" class=\"wigobutton wigoneutralbutton " . ($myvote == 0 ? "myvotebutton" : "") . " \">" .
                    "<img alt=\"{$altreset}\" title=\"{$titlereset}\" src=\"$reset\"></img></a>" .
                  "<a " . "href=\"javascript:wigovotedown('{$voteid}')\" id=\"{$voteid}-down\" class=\"wigobutton wigodownbutton " . ($myvote == -1 ? "myvotebutton" : "") . " \">" .
                    "<img alt=\"{$altdown}\" title=\"{$titledown}\" src=\"$down\"></img></a>" .
                    "<table id=\"{$voteid}-dist\" class=\"wigodistribution\" style=\"width:100%; height:6px; border:1px solid grey; margin:0; padding:0; border-spacing:0;\" title=\"{$distribtitle}\">" .
                      "<tr>" .
                        "<td class=\"wigodist-up\" style=\"border:none; background-color:limegreen; margin:0; padding:0; width:{$uppercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                        "<td class=\"wigodist-neutral\" style=\"border:none; background-color:orange; margin:0; padding:0; width:{$neutralpercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                        "<td class=\"wigodist-down\" style=\"border:none; background-color:red; margin:0; padding:0; width:{$downpercent}; height:100%; " . ($totalvotes == 0 ? "display:none;" : "") . "\"></td>" . 
                    "</tr></table>" .
                "</td>" .
                "<td style=\"min-width:25px; text-align:center;\">" .
                  "<span id=\"{$voteid}\" title=\"{$totalvotes}\">{$votes}</span>" .
                "</td>" .
                "<td style=\"vertical-align:middle;\">" .
                  "<!--$voteid-->$output" .
                "</td>" .
              "</tr>" .
            "</table>";
  }
}

function wigo3rendercapture($input, $args, $parser) {
  $output = $parser->recursiveTagParse($input);
  $matchi = preg_match_all('/(<a[^>]*href="([^"]*)"[^>]*>(?:[^<]|<[^\/]|<\/[^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;
  return $output;
}