b2evolution PHP Cross Reference Blogging Systems

Source: /inc/comments/model/_comment.class.php - 3603 lines - 104294 bytes - Summary - Text - Print

Description: This file implements the Comment class. This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}. See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file implements the Comment class.
   4   *
   5   * This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}.
   6   * See also {@link http://sourceforge.net/projects/evocms/}.
   7   *
   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}.
   9   * Parts of this file are copyright (c)2004-2005 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10   *
  11   * @license http://b2evolution.net/about/license.html GNU General Public License (GPL)
  12   *
  13   * {@internal Open Source relicensing agreement:
  14   * Daniel HAHLER grants Francois PLANQUE the right to license
  15   * Daniel HAHLER's contributions to this file and the b2evolution project
  16   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  17   * }}
  18   *
  19   * @package evocore
  20   *
  21   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  22   * @author blueyed: Daniel HAHLER.
  23   * @author fplanque: Francois PLANQUE
  24   *
  25   * @version $Id: _comment.class.php 6255 2014-03-19 05:58:21Z yura $
  26   */
  27  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  28  
  29  load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
  30  
  31  /**
  32   * Comment Class
  33   *
  34   * @package evocore
  35   */
  36  class Comment extends DataObject
  37  {
  38      /**
  39       * The item (parent) of this Comment (lazy-filled).
  40       * @see Comment::get_Item()
  41       * @see Comment::set_Item()
  42       * @access protected
  43       * @var Item
  44       */
  45      var $Item;
  46      /**
  47       * The ID of the comment's Item.
  48       * @var integer
  49       */
  50      var $item_ID;
  51      /**
  52       * The comment's user, this is NULL for (anonymous) visitors (lazy-filled).
  53       * @see Comment::get_author_User()
  54       * @see Comment::set_author_User()
  55       * @access protected
  56       * @var User
  57       */
  58      var $author_User;
  59      /**
  60       * The ID of the author's user. NULL for anonymous visitors.
  61       * @var integer
  62       */
  63      var $author_user_ID;
  64      /**
  65       * Comment type: 'comment', 'linkback', 'trackback' or 'pingback'
  66       * @var string
  67       */
  68      var $type;
  69      /**
  70       * Comment visibility status: 'published', 'deprecated', 'redirected', 'protected', 'private' or 'draft'
  71       * @var string
  72       */
  73      var $status;
  74      /**
  75       * Comment previous visibility status. It will be set only if the comment satus was changed.
  76       * @var string
  77       */
  78      var $previous_status;
  79      /**
  80       * Name of the (anonymous) visitor (if any).
  81       * @var string
  82       */
  83      var $author;
  84      /**
  85       * Email address of the (anonymous) visitor (if any).
  86       * @var string
  87       */
  88      var $author_email;
  89      /**
  90       * URL/Homepage of the (anonymous) visitor (if any).
  91       * @var string
  92       */
  93      var $author_url;
  94      /**
  95       * IP address of the comment's author (while posting).
  96       * @var string
  97       */
  98      var $author_IP;
  99      /**
 100       * Date of the comment (MySQL DATETIME - use e.g. {@link mysql2timestamp()}); local time ({@link $localtimenow})
 101       * @var string
 102       */
 103      var $date;
 104      /**
 105       * @var string
 106       */
 107      var $content;
 108      /**
 109       * @var string
 110       */
 111      var $renderers;
 112      /**
 113       * Spam karma of the comment (0-100), 0 being "probably no spam at all"
 114       * @var integer
 115       */
 116      var $spam_karma;
 117      /**
 118       * Does an anonymous commentator allow to send messages through a message form?
 119       * @var boolean
 120       */
 121      var $allow_msgform;
 122  
 123      var $nofollow;
 124      /**
 125       * @var string
 126       */
 127      var $secret;
 128      /**
 129       * Have post processing notifications been handled for this comment?
 130       * @var string
 131       */
 132      var $notif_status;
 133      /**
 134       * Which cron task is responsible for handling notifications for this comment?
 135       * @var integer
 136       */
 137      var $notif_ctsk_ID;
 138  
 139      /**
 140       * Is this comment a reply to another comment ?
 141       *
 142       * This can be used by plugins to display threaded comments.
 143       *
 144       * @var integer
 145       */
 146      var $in_reply_to_cmt_ID;
 147  
 148      /**
 149       * Voting result of all votes in system helpfulness
 150       *
 151       * @var integer
 152       */
 153      var $comment_helpful_addvotes;
 154      /**
 155       * A count of all votes in system helpfulness
 156       *
 157       * @var integer
 158       */
 159      var $comment_helpful_countvotes;
 160      /**
 161       * Voting result of all votes in system spam detecting
 162       *
 163       * @var integer
 164       */
 165      var $comment_spam_addvotes;
 166      /**
 167       * A count of all votes in system spam detecting
 168       *
 169       * @var integer
 170       */
 171      var $comment_spam_countvotes;
 172  
 173      /**
 174       * Constructor
 175       */
 176  	function Comment( $db_row = NULL )
 177      {
 178          // Call parent constructor:
 179          parent::DataObject( 'T_comments', 'comment_', 'comment_ID' );
 180  
 181          $this->delete_cascades = array(
 182                  array( 'table'=>'T_links', 'fk'=>'link_cmt_ID', 'msg'=>T_('%d links to destination comments') ),
 183                  array( 'table'=>'T_comments__votes', 'fk'=>'cmvt_cmt_ID', 'msg'=>T_('%d votes on comment') ),
 184              );
 185  
 186          if( $db_row == NULL )
 187          {
 188              // echo 'null comment';
 189              $this->rating = NULL;
 190              $this->featured = 0;
 191              $this->nofollow = 1;
 192              $this->notif_status = 'noreq';
 193              $this->in_reply_to_cmt_ID = 0;
 194              $this->set_renderers( array( 'default' ) );
 195          }
 196          else
 197          {
 198              $this->ID = $db_row->comment_ID;
 199              $this->item_ID = $db_row->comment_post_ID;
 200              if( ! empty($db_row->comment_author_ID) )
 201              {
 202                  $this->author_user_ID = $db_row->comment_author_ID;
 203              }
 204              $this->type = $db_row->comment_type;
 205              $this->status = $db_row->comment_status;
 206              $this->author = $db_row->comment_author;
 207              $this->author_email = $db_row->comment_author_email;
 208              $url = trim( $db_row->comment_author_url );
 209              if( ! empty($url) && ! preg_match( '~^\w+://~', $url ) )
 210              { // URL given and does not start with a protocol:
 211                  $url = 'http://'.$url;
 212              }
 213              $this->author_url = $url;
 214              $this->author_IP = $db_row->comment_author_IP;
 215              $this->IP_ctry_ID = $db_row->comment_IP_ctry_ID;
 216              $this->date = $db_row->comment_date;
 217              $this->content = $db_row->comment_content;
 218              $this->renderers = $db_row->comment_renderers;
 219              $this->rating = $db_row->comment_rating;
 220              $this->featured = $db_row->comment_featured;
 221              $this->nofollow = $db_row->comment_nofollow;
 222              $this->spam_karma = $db_row->comment_spam_karma;
 223              $this->allow_msgform = $db_row->comment_allow_msgform;
 224              $this->secret = $db_row->comment_secret;
 225              $this->notif_status = $db_row->comment_notif_status;
 226              $this->notif_ctsk_ID = $db_row->comment_notif_ctsk_ID;
 227              $this->in_reply_to_cmt_ID = $db_row->comment_in_reply_to_cmt_ID;
 228              $this->comment_helpful_addvotes = $db_row->comment_helpful_addvotes;
 229              $this->comment_helpful_countvotes = $db_row->comment_helpful_countvotes;
 230              $this->comment_spam_addvotes = $db_row->comment_spam_addvotes;
 231              $this->comment_spam_countvotes = $db_row->comment_spam_countvotes;
 232          }
 233      }
 234  
 235  
 236      /**
 237       * Get the author User of the comment. This is NULL for anonymous visitors.
 238       *
 239       * @return User
 240       */
 241      function & get_author_User()
 242      {
 243          if( isset($this->author_user_ID) && ! isset($this->author_User) )
 244          {
 245              $UserCache = & get_UserCache();
 246              $this->author_User = & $UserCache->get_by_ID( $this->author_user_ID );
 247          }
 248  
 249          return $this->author_User;
 250      }
 251  
 252  
 253      /**
 254       * Get the Item this comment relates to
 255       *
 256       * @return Item
 257       */
 258      function & get_Item()
 259      {
 260          if( ! isset($this->Item) )
 261          {
 262              $ItemCache = & get_ItemCache();
 263              $this->Item = & $ItemCache->get_by_ID( $this->item_ID, false );
 264          }
 265  
 266          return $this->Item;
 267      }
 268  
 269  
 270      /**
 271       * Get a member param by its name
 272       *
 273       * @param mixed Name of parameter
 274       * @return mixed Value of parameter
 275       */
 276  	function get( $parname )
 277      {
 278          switch( $parname )
 279          {
 280              case 't_status':
 281                  // Text status:
 282                  $visibility_statuses = get_visibility_statuses( '', array( 'redirected' ) );
 283                  return $visibility_statuses[ $this->status ];
 284          }
 285  
 286          return parent::get( $parname );
 287      }
 288  
 289  
 290      /**
 291       * Set param value
 292       *
 293       * @param string parameter name
 294       * @param mixed parameter value
 295       * @param boolean true to set to NULL if empty value
 296       * @return boolean true, if a value has been set; false if it has not changed
 297       */
 298  	function set( $parname, $parvalue, $make_null = false )
 299      {
 300          switch( $parname )
 301          {
 302              case 'rating':
 303                  // Save star rating with checking correct values
 304                  if( $parvalue < 1 )
 305                  { // cannot be less than 0
 306                      $parvalue = NULL;
 307                  }
 308                  elseif( $parvalue > 5 )
 309                  { // cannot be more than 5
 310                      $parvalue = 5;
 311                  }
 312                  return $this->set_param( $parname, 'number', $parvalue, true );
 313  
 314              case 'status':
 315                  // Save previous status temporarily to make some changes on dbinsert(), dbupdate() & dbdelete()
 316                  $this->previous_status = $this->get( 'status' );
 317  
 318              default:
 319                  return $this->set_param( $parname, 'string', $parvalue, $make_null );
 320          }
 321      }
 322  
 323  
 324      /**
 325       * Set Item this comment relates to
 326       * @param Item
 327       */
 328  	function set_Item( & $Item )
 329      {
 330          $this->Item = & $Item;
 331          $this->item_ID = $Item->ID;
 332          parent::set_param( 'post_ID', 'number', $Item->ID );
 333      }
 334  
 335  
 336      /**
 337       * Set author User of this comment
 338       */
 339  	function set_author_User( & $author_User )
 340      {
 341          $this->author_User = & $author_User;
 342          $this->author_user_ID = $author_User->ID;
 343          parent::set_param( 'author_ID', 'number', $author_User->ID );
 344      }
 345  
 346  
 347      /**
 348       * Set the spam karma, as a number.
 349       * @param integer Spam karma (-100 - 100)
 350       * @access protected
 351       */
 352  	function set_spam_karma( $spam_karma )
 353      {
 354          return $this->set_param( 'spam_karma', 'number', $spam_karma );
 355      }
 356  
 357  
 358      /**
 359       * Set the vote, as a number.
 360       *
 361       * @param string Vote type (spam, helpful)
 362       * @param string Vote value (spam, notsure, ok, yes, no)
 363       * @access protected
 364       */
 365  	function set_vote( $vote_type, $vote_value )
 366      {
 367          global $DB, $current_User;
 368  
 369          if( ! in_array( $vote_type, array( 'spam', 'helpful' ) ) )
 370          { // Restrict access for bad requests
 371              return;
 372          }
 373  
 374          switch ( $vote_value )
 375          { // Set a value for spam vote
 376              case "spam":
 377              case "yes":
 378                  $vote = '1';
 379                  break;
 380              case "notsure":
 381                  $vote = '0';
 382                  break;
 383              case "ok":
 384              case "no":
 385                  $vote = '-1';
 386                  break;
 387              default:
 388                  // $vote_value is not correct from ajax request
 389                  return;
 390          }
 391  
 392          if( empty( $this->ID ) )
 393          { // If comment doesn't exist
 394              return;
 395          }
 396  
 397          $DB->begin();
 398  
 399          $SQL = new SQL( 'Check if current user already voted on this comment' );
 400          $SQL->SELECT( 'cmvt_cmt_ID' );
 401          $SQL->FROM( 'T_comments__votes' );
 402          $SQL->WHERE( 'cmvt_cmt_ID = '.$DB->quote( $this->ID ) );
 403          $SQL->WHERE_and( 'cmvt_user_ID = '.$DB->quote( $current_User->ID ) );
 404          if( !$DB->get_row( $SQL->get() ) )
 405          { // Add a new vote for first time
 406              $DB->query( 'INSERT INTO T_comments__votes
 407                                       ( cmvt_cmt_ID, cmvt_user_ID, cmvt_'.$vote_type.' )
 408                                VALUES ( '.$DB->quote( $this->ID ).', '.$DB->quote( $current_User->ID ).', '.$DB->quote( $vote ).' )' );
 409          }
 410          else
 411          { // Update a vote
 412              $DB->query( 'UPDATE T_comments__votes
 413                              SET cmvt_'.$vote_type.' = '.$DB->quote( $vote ).'
 414                            WHERE cmvt_cmt_ID = '.$DB->quote( $this->ID ).'
 415                              AND cmvt_user_ID = '.$DB->quote( $current_User->ID ) );
 416          }
 417  
 418          $vote_SQL = new SQL( 'Get voting results of this comment' );
 419          $vote_SQL->SELECT( 'COUNT( cmvt_'.$vote_type.' ) AS c, SUM( cmvt_'.$vote_type.' ) AS s' );
 420          $vote_SQL->FROM( 'T_comments__votes' );
 421          $vote_SQL->WHERE( 'cmvt_cmt_ID = '.$DB->quote( $this->ID ) );
 422          $vote_SQL->WHERE_and( 'cmvt_'.$vote_type.' IS NOT NULL' );
 423          $vote = $DB->get_row( $vote_SQL->get() );
 424  
 425          // Update fields with vote counters for this comment
 426          $DB->query( 'UPDATE T_comments
 427                          SET comment_'.$vote_type.'_addvotes = '.$DB->quote( $vote->s ).',
 428                              comment_'.$vote_type.'_countvotes = '.$DB->quote( $vote->c ).'
 429                        WHERE comment_ID = '.$DB->quote( $this->ID ) );
 430          $this->{'comment_'.$vote_type.'_addvotes'} = $vote->s;
 431          $this->{'comment_'.$vote_type.'_countvotes'} = $vote->c;
 432  
 433          $DB->commit();
 434  
 435          return;
 436      }
 437  
 438  
 439      /**
 440       * Get the vote spam type disabled, as array.
 441       *
 442       * @param int User ID
 443       *
 444       * @return array Result:
 445       *               'is_voted' - TRUE if current user already voted on this comment
 446       *               'icons_statuses': array( 'spam', 'notsure', 'ok' )
 447       */
 448  	function get_vote_spam_disabled()
 449      {
 450          global $DB, $current_User;
 451  
 452          $result = array(
 453                  'is_voted' => false,
 454                  'icons_statuses' => array(
 455                      'ok' => 'disabled',
 456                      'notsure' => 'disabled',
 457                      'spam' => 'disabled',
 458              ) );
 459  
 460          $SQL = new SQL();
 461          $SQL->SELECT( 'cmvt_spam' );
 462          $SQL->FROM( 'T_comments__votes' );
 463          $SQL->WHERE( 'cmvt_cmt_ID = '.$DB->quote( $this->ID ) );
 464          $SQL->WHERE_and( 'cmvt_user_ID = '.$DB->quote( $current_User->ID ) );
 465          $SQL->WHERE_and( 'cmvt_spam IS NOT NULL' );
 466  
 467          if( $vote = $DB->get_row( $SQL->get() ) )
 468          {    // Get a spam vote for current comment and user
 469              $result['is_voted'] = true;
 470              $class_disabled = 'disabled';
 471              $class_voted = 'voted';
 472              switch ( $vote->cmvt_spam )
 473              {
 474                  case '1': // SPAM
 475                      $result['icons_statuses']['spam'] = $class_voted;
 476                      $result['icons_statuses']['notsure'] = $result['icons_statuses']['ok'] = $class_disabled;
 477                      break;
 478                  case '0': // NOT SURE
 479                      $result['icons_statuses']['notsure'] = $class_voted;
 480                      $result['icons_statuses']['spam'] = $result['icons_statuses']['ok'] = $class_disabled;
 481                      break;
 482                  case '-1': // OK
 483                      $result['icons_statuses']['ok'] = $class_voted;
 484                      $result['icons_statuses']['spam'] = $result['icons_statuses']['notsure'] = $class_disabled;
 485                      break;
 486              }
 487          }
 488  
 489          return $result;
 490      }
 491  
 492  
 493      /**
 494       * Get the vote helpful type disabled, as array.
 495       *
 496       * @return array Result:
 497       *               'is_voted' - TRUE if current user already voted on this comment
 498       *               'icons_statuses': array( 'yes', 'no' )
 499       */
 500  	function get_vote_helpful_disabled()
 501      {
 502          global $DB, $current_User;
 503  
 504          $result = array(
 505                  'is_voted' => false,
 506                  'icons_statuses' => array(
 507                      'yes' => '',
 508                      'no' => ''
 509              ) );
 510  
 511          $SQL = new SQL();
 512          $SQL->SELECT( 'cmvt_helpful' );
 513          $SQL->FROM( 'T_comments__votes' );
 514          $SQL->WHERE( 'cmvt_cmt_ID = '.$DB->quote( $this->ID ) );
 515          $SQL->WHERE_and( 'cmvt_user_ID = '.$DB->quote( $current_User->ID ) );
 516          $SQL->WHERE_and( 'cmvt_helpful IS NOT NULL' );
 517  
 518          if( $vote = $DB->get_row( $SQL->get() ) )
 519          {    // Get a spam vote for current comment and user
 520              $result['is_voted'] = true;
 521              $class_disabled = 'disabled';
 522              $class_voted = 'voted';
 523              switch ( $vote->cmvt_helpful )
 524              {
 525                  case '1': // YES
 526                      $result['icons_statuses']['yes'] = $class_voted;
 527                      $result['icons_statuses']['no'] = $class_disabled;
 528                      break;
 529                  case '-1': // NO
 530                      $result['icons_statuses']['no'] = $class_voted;
 531                      $result['icons_statuses']['yes'] = $class_disabled;
 532                      break;
 533              }
 534          }
 535  
 536          return $result;
 537      }
 538  
 539  
 540      /**
 541       * Get the vote summary, as a string.
 542       *
 543       * @param type Vote type (spam, helpful)
 544       * @param srray Params
 545       * @return string
 546       */
 547  	function get_vote_summary( $type, $params = array() )
 548      {
 549          $params = array_merge( array(
 550                  'result_title'           => '',
 551                  'result_title_undecided' => '',
 552                  'after_result'           => '',
 553              ), $params );
 554  
 555          if( ! in_array( $type, array( 'spam', 'helpful' ) ) )
 556          {    // Bad request
 557              return '';
 558          }
 559  
 560          if( $this->{'comment_'.$type.'_countvotes'} == 0 )
 561          {    // No votes for current comment
 562              return '';
 563          }
 564  
 565          // Calculate a vote summary
 566          $summary = ceil( $this->{'comment_'.$type.'_addvotes'} / $this->{'comment_'.$type.'_countvotes'} * 100 );
 567  
 568          if( $summary < -20 )
 569          {    // Comment is OK
 570              $summary = abs($summary).'% '.( $type == 'spam' ? T_('OK') : T_('not helpful') );
 571          }
 572          else if( $summary >= -20 && $summary <= 20 )
 573          {    // Comment is UNDECIDED
 574              $summary = T_('UNDECIDED');
 575              if( !empty( $params['result_title_undecided'] ) )
 576              {    // Display title before undecided results
 577                  $summary = $params['result_title_undecided'].' '.$summary;
 578              }
 579          }
 580          else if( $summary > 20 )
 581          {    // Comment is SPAM
 582              $summary .= '% '.( $type == 'spam' ? T_('SPAM') : T_('helpful') );
 583          }
 584  
 585          if( !empty( $params['result_title'] ) )
 586          {    // Display title before results
 587              $summary = $params['result_title'].' '.$summary;
 588          }
 589  
 590          return $summary.$params['after_result'].' ';
 591      }
 592  
 593  
 594      /**
 595       * Get the anchor-ID of the comment
 596       *
 597       * @return string
 598       */
 599  	function get_anchor()
 600      {
 601          return 'c'.$this->ID;
 602      }
 603  
 604  
 605      /**
 606       * Template function: display anchor for permalinks to refer to
 607       */
 608  	function anchor()
 609      {
 610          echo '<a id="'.$this->get_anchor().'"></a>';
 611      }
 612  
 613  
 614      /**
 615       * Get the comment author's name.
 616       *
 617       * @return string
 618       */
 619  	function get_author_name()
 620      {
 621          if( $this->get_author_User() )
 622          {
 623              return $this->author_User->get_preferred_name();
 624          }
 625          else
 626          {
 627              return $this->author;
 628          }
 629      }
 630  
 631  
 632      /**
 633       * Get the comment anonymous author's name with gender class.
 634       *
 635       * @param string format to display author
 636       * @param array Params
 637       * @return string
 638       */
 639  	function get_author_name_anonymous( $format = 'htmlbody', $params = array() )
 640      {
 641          // Make sure we are not missing any param:
 642          $params = array_merge( array(
 643                  'before' => '',
 644                  'after'  => '',
 645              ), $params );
 646  
 647          $gender_class = '';
 648          if( check_setting( 'gender_colored' ) )
 649          { // Set a gender class if the setting is ON
 650              $gender_class = ' nogender';
 651          }
 652  
 653          $author_name = $this->dget( 'author', $format );
 654  
 655          $author_name = '<span class="user anonymous'.$gender_class.'" rel="bubbletip_comment_'.$this->ID.'">'
 656              .$params['before']
 657              .$author_name
 658              .$params['after']
 659              .'</span>';
 660  
 661          return $author_name;
 662      }
 663  
 664  
 665      /**
 666       * Get the EMail of the comment's author.
 667       *
 668       * @return string
 669       */
 670  	function get_author_email()
 671      {
 672          if( $this->get_author_User() )
 673          { // Author is a user
 674              return $this->author_User->get('email');
 675          }
 676          else
 677          {
 678              return $this->author_email;
 679          }
 680      }
 681  
 682  
 683      /**
 684       * Get the URL of the comment's author.
 685       *
 686       * @return string
 687       */
 688  	function get_author_url()
 689      {
 690          if( $this->get_author_User() )
 691          { // Author is a user
 692              return $this->author_User->get('url');
 693          }
 694          else
 695          {
 696              return $this->author_url;
 697          }
 698      }
 699  
 700  
 701      /**
 702       * Template function: display the avatar of the comment's author.
 703       *
 704       */
 705  	function avatar( $size = 'crop-top-64x64', $class = 'bCommentAvatar', $params = array() )
 706      {
 707          if( $r = $this->get_avatar( $size, $class, $params ) )
 708          {
 709              echo $r;
 710          }
 711      }
 712  
 713  
 714      /**
 715       * Get the avatar of the comment's author.
 716       *
 717       * @param string Avatar thumb size
 718       * @param string Class name of avatar img tag
 719       * @param array Params
 720       * @return string
 721       */
 722  	function get_avatar( $size = 'crop-top-64x64', $class = 'bCommentAvatar', $params = array() )
 723      {
 724          // Make sure we are not missing any param:
 725          $params = array_merge( array(
 726                  'thumb_zoomable' => false,
 727              ), $params );
 728  
 729          global $Settings, $Plugins;
 730  
 731          if( ! $Settings->get('allow_avatars') )
 732          { // Avatars are not allowed generally, Exit here
 733              return;
 734          }
 735  
 736          $comment_Item = $this->get_Item();
 737          $comment_Item->load_Blog();
 738          if( !$this->Item->Blog->get_setting('comments_avatars') )
 739          { // Avatars are not allowe for this Blog, Exit here
 740              return;
 741          }
 742  
 743          $author_link = get_user_identity_url( $this->author_user_ID );
 744  
 745          if( $comment_author_User = & $this->get_author_User() )
 746          { // Author is a user
 747              if( $comment_author_User->has_avatar() )
 748              { // Get an image
 749                  $r = $comment_author_User->get_avatar_imgtag( $size, $class, '', $params['thumb_zoomable'] );
 750                  if( $author_link != '' && !$params['thumb_zoomable'] )
 751                  { // Add author link
 752                      $r = '<a href="'.$author_link.'">'.$r.'</a>';
 753                  }
 754                  return $r;
 755              }
 756          }
 757  
 758          // TODO> add new event
 759          // See if plugin supplies an image
 760          // $img_url = $Plugins->trigger_event( 'GetCommentAvatar', array( 'Comment' => & $this, 'size' => $size ) );
 761  
 762          // Get gravatar for anonymous users and for users without uploaded avatar
 763          return get_avatar_imgtag_default( $size, $class, '', array(
 764                  'email'    => $this->get_author_email(),
 765                  'username' => $this->get_author_name(),
 766              ) );
 767      }
 768  
 769  
 770      /**
 771       * Template function: display author of comment
 772       *
 773       * @deprecated use Comment::author2() instead
 774       * @param string String to display before author name if not a user
 775       * @param string String to display after author name if not a user
 776       * @param string String to display before author name if he's a user
 777       * @param string String to display after author name if he's a user
 778       * @param string Output format, see {@link format_to_output()}
 779       * @param boolean true for link, false if you want NO html link
 780       * @param string What show as user name: avatar | only_avatar | login | nickname | firstname | lastname | fullname | preferredname
 781       */
 782  	function author( $before = '', $after = '#', $before_user = '', $after_user = '#',
 783                                          $format = 'htmlbody', $makelink = false, $lint_text = 'login' )
 784      {
 785          echo $this->get_author( array(
 786                      'before'      => $before,
 787                      'after'       => $after,
 788                      'before_user' => $before_user,
 789                      'after_user'  => $after_user,
 790                      'format'      => $format,
 791                      'link_to'     => ( $makelink ? 'userurl>userpage' : '' ),
 792                      'link_text'   => $lint_text,
 793                  )
 794              );
 795      }
 796  
 797  
 798      /**
 799       * Template function: display author of comment
 800       *
 801       * @param array
 802       */
 803  	function author2( $params = array()  )
 804      {
 805          echo $this->get_author( $params );
 806      }
 807  
 808  
 809      /**
 810       * Get author of comment
 811       *
 812       * @param array
 813       * @return string
 814       */
 815  	function get_author( $params = array() )
 816      {
 817          // Make sure we are not missing any param:
 818          $params = array_merge( array(
 819                  'profile_tab'  => 'user',
 820                  'before'       => ' ',
 821                  'after'        => '#',
 822                  'before_user'  => '',
 823                  'after_user'   => '#',
 824                  'format'       => 'htmlbody',
 825                  'link_to'      => 'userurl>userpage', // 'userpage' or 'userurl' or 'userurl>userpage' 'userpage>userurl'
 826                  'link_text'    => 'preferredname', // avatar | only_avatar | login | nickname | firstname | lastname | fullname | preferredname
 827                  'link_rel'     => '',
 828                  'link_class'   => '',
 829                  'thumb_size'   => 'crop-top-32x32',
 830                  'thumb_class'  => '',
 831              ), $params );
 832  
 833          global $Plugins;
 834  
 835          global $Blog;
 836  
 837          if( empty( $Blog ) )
 838          { // Set Blog if it is still not defined
 839              $comment_Item = $this->get_Item();
 840              $Blog = $comment_Item->get_Blog();
 841          }
 842  
 843          if( $Blog->get_setting( 'allow_comments' ) != 'any' )
 844          { // The blog does not allow anonymous comments, Don't display a type of comment author
 845              $params['after_user'] = '';
 846              $params['after'] = '';
 847          }
 848  
 849          if( !$Blog->get_setting('comments_avatars') && $params['link_text'] == 'avatar' )
 850          { // If avatars are not allowed for this Blog
 851              $params['link_text'] = 'login';
 852          }
 853  
 854          if( $this->get_author_User() )
 855          { // Author is a registered user:
 856              if( $params['after_user'] == '#' ) $params['after_user'] = ' ['.T_('Member').']';
 857  
 858              $r = $this->author_User->get_identity_link( $params );
 859  
 860              $r = $params['before_user'].$r.$params['after_user'];
 861          }
 862          else
 863          { // Not a registered user, display info recorded at edit time:
 864              if( $params['after'] == '#' ) $params['after'] = ' ['.T_('Visitor').']';
 865  
 866              if( evo_strlen( $this->author_url ) <= 10 )
 867              { // URL is too short anyways...
 868                  $params['link_to'] = '';
 869              }
 870  
 871              $author_name_params = array();
 872              if( $params['link_text'] == 'avatar' )
 873              { // Get avatar for anonymous user
 874                  $author_name_params['before'] = $this->get_avatar( $params['thumb_size'], $params['thumb_class'] );
 875              }
 876              $author_name = $this->get_author_name_anonymous( $params['format'], $author_name_params );
 877  
 878              switch( $params['link_to'] )
 879              {
 880                  case 'userurl':
 881                  case 'userurl>userpage':
 882                  case 'userpage>userurl':
 883                      // Make a link:
 884                      $r = $this->get_author_url_link( $author_name, $params['before'], $params['after'], true );
 885                      break;
 886  
 887                  default:
 888                      // Display the name: (NOTE: get_author_url_link( with nolink option ) would NOT handle this correctly when url is empty
 889                      $r = $params['before'].$author_name.$params['after'];
 890                      break;
 891              }
 892          }
 893  
 894          $hook_params = array(
 895              'data' => & $r,
 896              'Comment' => & $this,
 897              'makelink' => ! empty($params['link_to']),
 898          );
 899  
 900          $Plugins->trigger_event( 'FilterCommentAuthor', $hook_params );
 901  
 902          return $r;
 903      }
 904  
 905  
 906      /**
 907       * Template function: display comment's author's IP
 908       *
 909       * @param string String to display before IP, if IP exists
 910       * @param string String to display after IP, if IP exists
 911       * @param boolean TRUE - create an url to filter by IP
 912       */
 913  	function author_ip( $before='', $after='', $filter_by_IP = false )
 914      {
 915          if( !empty( $this->author_IP ) )
 916          {
 917              global $Plugins, $CommentList;
 918  
 919              $author_IP = $this->author_IP;
 920              if( $filter_by_IP )
 921              {    // Add link to filter by IP
 922                  $filter_IP_url = regenerate_url( 'filter,ctrl,comments,cmnt_fullview_comments', 'cmnt_fullview_author_IP='.$author_IP.'&amp;ctrl=comments' );
 923                  $author_IP = '<a href="'.$filter_IP_url.'">'.$author_IP.'</a>';
 924              }
 925  
 926              echo $before;
 927              // Filter the IP by plugins for display, allowing e.g. the DNSBL plugin to add a link that displays info about the IP:
 928              echo $Plugins->get_trigger_event( 'FilterIpAddress', array(
 929                      'format'=>'htmlbody',
 930                      'data' => $author_IP ),
 931                  'data' );
 932              echo $after;
 933          }
 934      }
 935  
 936  
 937      /**
 938       * Template function: display link to comment author's provided email
 939       *
 940       * @param string String to display for link: leave empty to display email
 941       * @param string String to display before email, if email exists
 942       * @param string String to display after email, if email exists
 943       * @param boolean false if you want NO html link
 944       */
 945  	function author_email( $linktext='', $before='', $after='', $makelink = true )
 946      {
 947          $email = $this->get_author_email();
 948  
 949          if( strlen( $email ) > 5 )
 950          { // If email exists:
 951              echo $before;
 952              if( $makelink ) echo '<a href="mailto:'.$email.'">';
 953              echo ($linktext != '') ? $linktext : $email;
 954              if( $makelink ) echo '</a>';
 955              echo $after;
 956          }
 957      }
 958  
 959  
 960      /**
 961       * Template function: display comment's country that was detected by IP address
 962       *
 963       * @param string String to display before country, if country_ID is defined
 964       * @param string String to display after country, if country_ID is defined
 965       */
 966  	function ip_country( $before = '', $after = '' )
 967      {
 968          echo $this->get_ip_country( $before, $after );
 969      }
 970  
 971  
 972      /**
 973       * Get comment's country that was detected by IP address
 974       *
 975       * @param string String to display before country, if country_ID is defined
 976       * @param string String to display after country, if country_ID is defined
 977       * @return string Country with flag
 978       */
 979  	function get_ip_country( $before = '', $after = '' )
 980      {
 981          $country = '';
 982  
 983          if( !empty( $this->IP_ctry_ID ) )
 984          {    // Country ID is defined
 985              load_funcs( 'regional/model/_regional.funcs.php' );
 986              load_class( 'regional/model/_country.class.php', 'Country' );
 987  
 988              $CountryCache = & get_CountryCache();
 989              if( $Country = $CountryCache->get_by_ID( $this->IP_ctry_ID, false ) )
 990              {
 991                  $country .= $before;
 992  
 993                  $country .= country_flag( $Country->get( 'code' ), $Country->get_name(), 'w16px', 'flag', '', false );
 994                  $country .= ' '.$Country->get_name();
 995  
 996                  $country .= $after;
 997              }
 998          }
 999  
1000          return $country;
1001      }
1002  
1003  
1004      /**
1005       * Get link to comment author's provided URL
1006       *
1007       * @param string String to display for link: leave empty to display URL
1008       * @param string String to display before link, if link exists
1009       * @param string String to display after link, if link exists
1010       * @param boolean false if you want NO html link
1011       * @return boolean true if URL has been displayed
1012       */
1013  	function get_author_url_link( $linktext='', $before='', $after='', $makelink = true )
1014      {
1015          global $Plugins;
1016  
1017          $url = $this->get_author_url();
1018  
1019          if( evo_strlen( $url ) < 10 )
1020          {
1021              return false;
1022          }
1023  
1024          // If URL exists:
1025          $r = $before;
1026          if( $makelink )
1027          {
1028              $r .= '<a ';
1029              if( $this->nofollow )
1030              {
1031                  $r .= 'rel="nofollow" ';
1032              }
1033              $r .= 'href="'.$url.'">';
1034          }
1035          $r .= ( empty($linktext) ? $url : $linktext );
1036          if( $makelink ) $r .= '</a>';
1037          $r .= $after;
1038  
1039          $Plugins->trigger_event( 'FilterCommentAuthorUrl', array( 'data' => & $r, 'makelink' => $makelink, 'Comment' => $this ) );
1040  
1041          return $r;
1042      }
1043  
1044  
1045    /**
1046       * Template function: display link to comment author's provided URL
1047       *
1048       * @param string String to display for link: leave empty to display URL
1049       * @param string String to display before link, if link exists
1050       * @param string String to display after link, if link exists
1051       * @param boolean false if you want NO html link
1052       * @return boolean true if URL has been displayed
1053       */
1054  	function author_url( $linktext='', $before='', $after='', $makelink = true )
1055      {
1056          $r = $this->get_author_url_link( $linktext, $before, $after, $makelink );
1057          if( !empty( $r ) )
1058          {
1059              echo $r;
1060              return true;
1061          }
1062          return false;
1063      }
1064  
1065  
1066      /**
1067       * Display author url, delete icon and ban icon if user has proper rights
1068       *
1069       * @param boolean true to use ajax button
1070       * @param boolean true to check user permission to edit this comment and antispam screen
1071       */
1072  	function author_url_with_actions( $redirect_to = NULL, $ajax_button = false, $check_perms = true, $save_context = true )
1073      {
1074          global $current_User;
1075          if( $this->author_url( '', ' <span &bull; Url: id="commenturl_'.$this->ID.'" <span class="bUrl" >', '' ) )
1076          {
1077              if( $current_User->check_perm( 'comment!CURSTATUS', 'edit', false, $this ) )
1078              { // There is an URL and we have permission to edit this comment...
1079                  if( $redirect_to == NULL )
1080                  {
1081                      $redirect_to = rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1082                  }
1083                  $this->deleteurl_link( $redirect_to, $ajax_button, false, '&amp;', $save_context );
1084                  $this->banurl_link( $redirect_to, $ajax_button, true, '&amp;', $save_context );
1085              }
1086              echo '</span>';
1087          }
1088      }
1089  
1090  
1091      /**
1092       * Template function: display spam karma of the comment (in percent)
1093       *
1094       * "%s" gets replaced by the karma value
1095       *
1096       * @param string Template string to display, if we have a karma value
1097       * @param string Template string to display, if we have no karma value (pre-Phoenix)
1098       */
1099  	function spam_karma( $template = '%s%', $template_unknown = NULL )
1100      {
1101          if( isset($this->spam_karma) )
1102          {
1103              echo str_replace( '%s', $this->spam_karma, $template );
1104          }
1105          else
1106          {
1107              if( ! isset($template_unknown) )
1108              {
1109                  echo /* TRANS: "not available" */ T_('N/A');
1110              }
1111              else
1112              {
1113                  echo $template_unknown;
1114              }
1115          }
1116      }
1117  
1118  
1119      /**
1120       * Provide link to edit a comment if user has edit rights
1121       *
1122       * @param string to display before link
1123       * @param string to display after link
1124       * @param string link text
1125       * @param string link title
1126       * @param string class name
1127       * @param string Glue string for url params
1128       * @param boolean TRUE - to save context(memorized params)
1129       * @param string Redirect url
1130       * @return boolean
1131       */
1132  	function edit_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $glue = '&amp;', $save_context = true, $redirect_to = NULL )
1133      {
1134          global $current_User, $admin_url;
1135  
1136          if( ! is_logged_in( false ) ) return false;
1137  
1138          if( empty($this->ID) )
1139          {    // Happens in Preview
1140              return false;
1141          }
1142  
1143          if( ! $current_User->check_perm( 'comment!CURSTATUS', 'edit', false, $this ) )
1144          { // If User has no permission to edit this comment:
1145              return false;
1146          }
1147  
1148          if( $text == '#' ) $text = get_icon( 'edit' ).' '.T_('Edit...');
1149          if( $title == '#' ) $title = T_('Edit this comment');
1150  
1151          $this->get_Item();
1152          $item_Blog = & $this->Item->get_Blog();
1153          echo $before;
1154          if( $item_Blog->get_setting( 'in_skin_editing' ) && !is_admin_page() )
1155          {
1156              echo '<a href="'.url_add_param( $item_Blog->gen_blogurl(), 'disp=edit_comment'.$glue.'c='.$this->ID );
1157          }
1158          else
1159          {
1160              echo '<a href="'.$admin_url.'?ctrl=comments'.$glue.'action=edit'.$glue.'comment_ID='.$this->ID;
1161          }
1162          if( $save_context )
1163          {
1164              if( $redirect_to != NULL )
1165              {
1166                  echo $glue.'redirect_to='.$redirect_to;
1167              }
1168              else
1169              {
1170                  echo $glue.'redirect_to='.rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1171              }
1172          }
1173          echo '" title="'.$title.'"';
1174          if( !empty( $class ) ) echo ' class="'.$class.'"';
1175          echo '>'.$text.'</a>';
1176          echo $after;
1177  
1178          return true;
1179      }
1180  
1181  
1182      /**
1183       * Display delete icon for deleting author_url if user has proper rights
1184       * @param boolean true if create ajax button
1185       * @param boolean true if need permission check, because it wasn't checked before
1186       * @param glue between url params
1187       * @return link on success, false otherwise
1188       */
1189  	function deleteurl_link( $redirect_to, $ajax_button = false, $check_perm = true, $glue = '&amp;', $save_context = true )
1190      {
1191          global $current_User, $admin_url;
1192  
1193          if( ! is_logged_in( false ) ) return false;
1194  
1195          if( $check_perm && ! $current_User->check_perm( 'comment!CURSTATUS', 'delete', false, $this ) )
1196          { // If current user has no permission to edit this comment
1197              return false;
1198          }
1199  
1200          if( $save_context )
1201          {
1202              if( $redirect_to == NULL )
1203              {
1204                  $redirect_to = rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1205              }
1206              $redirect_to = $glue.'redirect_to='.$redirect_to;
1207          }
1208          else
1209          {
1210              $redirect_to = '';
1211          }
1212  
1213          $delete_url = $admin_url.'?ctrl=comments&amp;action=delete_url&amp;comment_ID='.$this->ID.'&amp;'.url_crumb('comment').$redirect_to;
1214          if( $ajax_button )
1215          {
1216              echo ' <a href="'.$delete_url.'" onclick="delete_comment_url('.$this->ID.'); return false;">'.get_icon( 'delete' ).'</a>';
1217          }
1218          else
1219          {
1220              echo ' <a href="'.$delete_url.'">'.get_icon( 'delete' ).'</a>';
1221          }
1222      }
1223  
1224  
1225      /**
1226       * Display ban icon, which goes to the antispam screen with keyword=author_url
1227       *
1228       * @param boolean true if create ajax button
1229       * @param boolean true if need permission check, because it wasn't check before
1230       * @param glue between url params
1231       * @return link on success, false otherwise
1232       */
1233  	function banurl_link( $redirect_to, $ajax_button = false, $check_perm = true, $glue = '&amp;', $save_context = true )
1234      {
1235          global $current_User, $admin_url;
1236  
1237          if( ! is_logged_in( false ) ) return false;
1238  
1239          //$Item = & $this->get_Item();
1240  
1241          if( $check_perm && ! $current_User->check_perm( 'spamblacklist', 'edit' ) )
1242          { // if current user has no permission to edit spams
1243              return false;
1244          }
1245  
1246          if( $save_context )
1247          {
1248              if( $redirect_to == NULL )
1249              {
1250                  $redirect_to = rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1251              }
1252              $redirect_to = $glue.'redirect_to='.$redirect_to;
1253          }
1254          else
1255          {
1256              $redirect_to = '';
1257          }
1258  
1259          // TODO: really ban the base domain! - not by keyword
1260          $authorurl = rawurlencode( get_ban_domain( $this->get_author_url() ) );
1261          $ban_url = $admin_url.'?ctrl=antispam&amp;action=ban&amp;keyword='.$authorurl.$redirect_to.'&amp;'.url_crumb('antispam');
1262  
1263          if( $ajax_button )
1264          {
1265              echo ' <a id="ban_url" href="'.$ban_url.'" onclick="ban_url(\''.$authorurl.'\'); return false;">'.get_icon( 'ban' ).'</a>';
1266          }
1267          else
1268          {
1269              echo ' <a href="'.$ban_url.'">'.get_icon( 'ban' ).'</a> ';
1270          }
1271      }
1272  
1273  
1274      /**
1275       * Displays button for deleting the Comment if user has proper rights
1276       *
1277       * @param string to display before link
1278       * @param string to display after link
1279       * @param string link text
1280       * @param string link title
1281       * @param string class name
1282       * @param boolean true to make this a button instead of a link
1283       * @param string glue between url params
1284       * @param boolean save context?
1285       * @param boolean true if create AJAX button
1286       * @param string confirmation text
1287       * @param string Redirect url
1288       */
1289  	function delete_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $button = false, $glue = '&amp;', $save_context = true, $ajax_button = false, $confirm_text = '#', $redirect_to = NULL )
1290      {
1291          global $current_User, $admin_url;
1292  
1293          if( ! is_logged_in( false ) ) return false;
1294  
1295          if( empty($this->ID) )
1296          {    // Happens in Preview
1297              return false;
1298          }
1299  
1300          $this->get_Item();
1301  
1302          if( ! $current_User->check_perm( 'comment!CURSTATUS', 'delete', false, $this ) )
1303          { // If User has no permission to delete a comments:
1304              return false;
1305          }
1306  
1307          if( $text == '#' )
1308          { // Use icon+text as default, if not displayed as button (otherwise just the text)
1309              $text = ( $this->status == 'trash' ) ? T_('Delete!') : T_('Recycle!');
1310              if( ! $button )
1311              {
1312                  $text = get_icon( 'delete' ).' '.$text;
1313              }
1314              else
1315              {
1316                  $text = $text;
1317              }
1318          }
1319          if( $title == '#' ) $title = ( $this->status == 'trash' ) ? T_('Delete this comment') : T_('Recycle this comment');
1320  
1321          $url = $admin_url.'?ctrl=comments'.$glue.'action=delete'.$glue.'comment_ID='.$this->ID.$glue.url_crumb('comment');
1322          if( $save_context )
1323          {
1324              if( $redirect_to != NULL )
1325              {
1326                  $url .= $glue.'redirect_to='.$redirect_to;
1327              }
1328              else
1329              {
1330                  $url .= $glue.'redirect_to='.rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1331              }
1332          }
1333  
1334          echo $before;
1335          if( $ajax_button && ( $this->status != 'trash' ) )
1336          {
1337              echo '<a href="'.$url.'" onclick="deleteComment('.$this->ID.'); return false;" title="'.$title.'"';
1338              if( !empty( $class ) ) echo ' class="'.$class.'"';
1339              echo '>'.$text.'</a>';
1340          }
1341          else
1342          {
1343              // JS confirm is required only when the comment is not in the recycle bin yet
1344              $display_js_confirm = ( $this->status == 'trash' );
1345              if( $display_js_confirm && ( $confirm_text == '#' ) )
1346              { // Set js confirm text on comment delete action
1347                  $confirm_text = TS_('You are about to delete this comment!\\nThis cannot be undone!');
1348              }
1349  
1350              if( $button )
1351              { // Display as button
1352                  echo '<input type="button"';
1353                  echo ' value="'.$text.'" title="'.$title.'"';
1354                  if( $display_js_confirm )
1355                  {
1356                      echo ' onclick="if ( confirm(\''.$confirm_text.'\') ) { document.location.href=\''.$url.'\' }"';
1357                  }
1358                  if( !empty( $class ) ) echo ' class="'.$class.'"';
1359                  echo '/>';
1360              }
1361              else
1362              { // Display as link
1363                  echo '<a href="'.$url.'" title="'.$title.'"';
1364                  if( $display_js_confirm )
1365                  {
1366                      echo ' onclick="return confirm(\''.$confirm_text.'\')"';
1367                  }
1368                  if( !empty( $class ) ) echo ' class="'.$class.'"';
1369                  echo '>'.$text.'</a>';
1370              }
1371          }
1372          echo $after;
1373  
1374          return true;
1375      }
1376  
1377  
1378      /**
1379       * Provide link to deprecate a comment if user has edit rights
1380       *
1381       * @param string to display before link
1382       * @param string to display after link
1383       * @param string link text
1384       * @param string link title
1385       * @param string class name
1386       * @param string glue between url params
1387       * @param boolean save context?
1388       * @param boolean true if create AJAX button
1389       */
1390  	function get_deprecate_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $redirect_to = NULL )
1391      {
1392          global $current_User, $admin_url;
1393  
1394          if( ! is_logged_in( false ) )
1395          {
1396              return false;
1397          }
1398  
1399          if( ( $this->status == 'deprecated' ) // Already deprecated!
1400              || !$current_User->check_perm( 'comment!deprecated', 'moderate', false, $this ) )
1401          { // User has no right to deprecated this comment:
1402              return false;
1403          }
1404  
1405          $status = 'deprecated';
1406          $status_order = get_visibility_statuses( 'ordered-array' );
1407          $status_index = get_visibility_statuses( 'ordered-index', array( 'redirected' ) );
1408          if( isset( $status_index[ $status ] ) &&
1409              isset( $status_order[ $status_index[ $status ] ] ) &&
1410              ! empty( $status_order[ $status_index[ $status ] ][3] ) )
1411          { // Get color of button icon
1412              $status_icon_color = $status_order[ $status_index[ $status ] ][3];
1413          }
1414          else
1415          { // Use grey arrow as default
1416              $status_icon_color = 'grey';
1417          }
1418  
1419          $params = array(
1420              'before' => $before,
1421              'after'  => $after,
1422              'text'   => ( ( $text == '#' ) ?  get_icon( 'move_down_'.$status_icon_color ).' '.T_('Deprecate!') : $text ),
1423              'title'  => $title,
1424              'class'  => $class,
1425              'glue'   => $glue,
1426              'save_context' => $save_context,
1427              'ajax_button'  => $ajax_button,
1428              'redirect_to'  => $redirect_to,
1429              'status' => 'deprecated',
1430              'action' => 'restrict'
1431          );
1432  
1433          return $this->get_moderation_link( $params );
1434      }
1435  
1436  
1437      /**
1438       * Provide link to vote a comment if user has edit rights
1439       *
1440       * @param string a vote type
1441       * @param string a vote value
1442       * @param string class name
1443       * @param string glue between url params
1444       * @param boolean save context?
1445       * @param boolean true if create AJAX button
1446       * @param array Params
1447       */
1448  	function get_vote_link( $vote_type, $vote_value, $class = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $params = array() )
1449      {
1450          $params = array_merge( array(
1451                  'title_spam'          => T_('Mark this comment as spam!'),
1452                  'title_spam_voted'    => T_('You think this comment is spam'),
1453                  'title_notsure'       => T_('Mark this comment as not sure!'),
1454                  'title_notsure_voted' => T_('You are not sure about this comment'),
1455                  'title_ok'            => T_('Mark this comment as OK!'),
1456                  'title_ok_voted'      => T_('You think this comment is OK'),
1457                  'title_yes'           => T_('Mark this comment as helpful!'),
1458                  'title_yes_voted'     => T_('You think this comment is helpful'),
1459                  'title_no'            => T_('Mark this comment as not helpful!'),
1460                  'title_no_voted'      => T_('You think this comment is not helpful'),
1461              ), $params );
1462  
1463          global $current_User, $admin_url;
1464  
1465          $this->get_Item();
1466  
1467          $is_voted = false;
1468          $icon_params = array();
1469          if( $class == 'voted' )
1470          { // Current user already voted for this
1471              $class = '';
1472              $is_voted = true;
1473              $icon_params = array( 'class' => 'voted' );
1474          }
1475  
1476          switch( $vote_value )
1477          {
1478              case "spam":
1479                  $title = $is_voted ? $params['title_spam_voted'] : $params['title_spam'];
1480                  $icon_params['title'] = $title;
1481                  $text = get_icon( 'vote_spam'.( $class != '' ? '_'.$class : '' ), 'imgtag', $icon_params );
1482                  $class .= ' roundbutton';
1483              break;
1484              case "notsure":
1485                  $title = $is_voted ? $params['title_notsure_voted'] : $params['title_notsure'];
1486                  $icon_params['title'] = $title;
1487                  $text = get_icon( 'vote_notsure'.( $class != '' ? '_'.$class : '' ), 'imgtag', $icon_params );
1488                  $class .= ' roundbutton';
1489              break;
1490              case "ok":
1491                  $title = $is_voted ? $params['title_ok_voted'] : $params['title_ok'];
1492                  $icon_params['title'] = $title;
1493                  $text = get_icon( 'vote_ok'.( $class != '' ? '_'.$class : '' ), 'imgtag', $icon_params );
1494                  $class .= ' roundbutton';
1495              break;
1496              case "yes":
1497                  $title = $is_voted ? $params['title_yes_voted'] : $params['title_yes'];
1498                  $icon_params['title'] = $title;
1499                  $text = get_icon( 'thumb_up'.( $class != '' ? '_'.$class : '' ), 'imgtag', $icon_params );
1500              break;
1501              case "no":
1502                  $title = $is_voted ? $params['title_no_voted'] : $params['title_no'];
1503                  $icon_params['title'] = $title;
1504                  $text = get_icon( 'thumb_down'.( $class != '' ? '_'.$class : '' ), 'imgtag', $icon_params );
1505              break;
1506          }
1507          if( strpos( $class, 'disabled' ) !== false )
1508          { // add rollover action for disabled buttons
1509               $class .= ' rollover_sprite';
1510          }
1511          $class .= ' action_icon';
1512  
1513          $r = '';
1514          if( !$is_voted )
1515          { // If user didn't vote for this we should create a link for voting
1516              $r .= '<a href="'.$admin_url.'?ctrl=comments'.$glue.'action='.$vote_type.$glue.'value='.$vote_value.$glue.'comment_ID='.$this->ID.'&amp;'.url_crumb('comment');
1517              if( $save_context )
1518              {
1519                  $r .= $glue.'redirect_to='.rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1520              }
1521              $r .= '"';
1522  
1523              if( $ajax_button )
1524              {
1525                  $r .= ' onclick="setCommentVote('.$this->ID.', \''.$vote_type.'\' , \''.$vote_value.'\' ); return false;"';
1526              }
1527  
1528              $r .= ' title="'.$title.'" class="'.$class.'">'.$text.'</a>';
1529          }
1530          else
1531          {
1532              $r .= '<span';
1533              if( !empty( $class ) )
1534              {
1535                  $r .= ' class="'.$class.'"';
1536              }
1537              $r .= '>'.$text.'</span>';
1538          }
1539  
1540          return $r;
1541      }
1542  
1543  
1544      /**
1545       * Display link to deprecate a comment if user has edit rights
1546       *
1547       * @param string to display before link
1548       * @param string to display after link
1549       * @param string link text
1550       * @param string link title
1551       * @param string class name
1552       * @param string glue between url params
1553       * @param boolean save context?
1554       * @param boolean true if create AJAX button
1555       */
1556  	function deprecate_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $redirect_to = NULL )
1557      {
1558          $deprecate_link = $this->get_deprecate_link( $before, $after, $text, $title, $class, $glue, $save_context, $ajax_button, $redirect_to );
1559          if( $deprecate_link === false )
1560          { // The deprecate link is unavailable for current user and for this comment
1561              return false;
1562          }
1563  
1564          // Display the deprecate link
1565          echo $deprecate_link;
1566  
1567          return true;
1568      }
1569  
1570  
1571      /**
1572       * Display link to vote a comment as SPAM if user has edit rights
1573       *
1574       * @param string to display before link
1575       * @param string to display after link
1576       * @param string glue between url params
1577       * @param boolean save context?
1578       * @param boolean true if create AJAX button
1579       * @param array Params
1580       */
1581  	function vote_spam( $before = '', $after = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $params = array())
1582      {
1583          $params = array_merge( array(
1584                  'display'             => false, // TRUE - to show this tool on loading(Used to make it visible only when JS is enalbed)
1585                  'title_spam'          => T_('Mark this comment as spam!'),
1586                  'title_spam_voted'    => T_('You think this comment is spam'),
1587                  'title_notsure'       => T_('Mark this comment as not sure!'),
1588                  'title_notsure_voted' => T_('You are not sure about this comment'),
1589                  'title_ok'            => T_('Mark this comment as OK!'),
1590                  'title_ok_voted'      => T_('You think this comment is OK'),
1591                  'title_empty'         => T_('No votes on spaminess yet.'),
1592              ), $params );
1593  
1594          global $current_User;
1595  
1596          $this->get_Item();
1597  
1598          if( !is_logged_in( false ) || !$current_User->check_perm( 'blog_vote_spam_comments', 'edit', false, $this->Item->get_blog_ID() ) )
1599          { // If User has no permission to vote spam
1600              return false;
1601          }
1602  
1603          echo $before;
1604  
1605          $style = $params['display'] ? '' : ' style="display:none"';
1606          echo '<div id="vote_spam_'.$this->ID.'" class="vote_spam"'.$style.'>';
1607  
1608          $vote_result = $this->get_vote_spam_disabled();
1609  
1610          if( $current_User->ID == $this->author_user_ID )
1611          { // Display only vote summary for users on their own comments
1612              $result_summary = $this->get_vote_summary( 'spam', array(
1613                      'result_title' => T_('Spam consensus:'),
1614                      'after_result' => '.',
1615                  ) );
1616              echo ( !empty( $result_summary ) ? $result_summary : $params['title_empty'] );
1617          }
1618          else
1619          { // Display form to vote
1620              echo T_('Spam Vote:').' ';
1621  
1622              echo '<span class="roundbutton_group">';
1623              foreach( $vote_result['icons_statuses'] as $vote_type => $vote_class )
1624              { // Print out 3 buttons for spam voting
1625                  echo $this->get_vote_link( 'spam', $vote_type, $vote_class, $glue, $save_context, $ajax_button, $params );
1626              }
1627              echo '</span>';
1628  
1629              if( $vote_result['is_voted'] )
1630              { // Display vote summary if user already voted on this comment
1631                  echo ' '.$this->get_vote_summary( 'spam', array(
1632                          'result_title' => T_('Consensus:'),
1633                          'after_result' => '.',
1634                      ) );
1635              }
1636          }
1637  
1638          echo '</div>';
1639  
1640          echo $after;
1641      }
1642  
1643  
1644      /**
1645       * Display links to vote a comment as HELPFUL if user is logged
1646       *
1647       * @param string to display before link
1648       * @param string to display after link
1649       * @param string glue between url params
1650       * @param boolean save context?
1651       * @param boolean true if create AJAX button
1652       * @param array Params
1653       */
1654  	function vote_helpful( $before = '', $after = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $params = array() )
1655      {
1656          $params = array_merge( array(
1657                  'helpful_text'    => T_('Is this comment helpful?'),
1658                  'title_yes'       => T_('Mark this comment as helpful!'),
1659                  'title_yes_voted' => T_('You think this comment is helpful'),
1660                  'title_no'        => T_('Mark this comment as not helpful!'),
1661                  'title_no_voted'  => T_('You think this comment is not helpful'),
1662                  'title_empty'     => T_('No votes on helpfulness yet.'),
1663                  'class'           => '',
1664              ), $params );
1665  
1666          global $current_User;
1667  
1668          $comment_Item = & $this->get_Item();
1669          $comment_Item->load_Blog();
1670  
1671          if( ! is_logged_in( false ) || ! $comment_Item->Blog->get_setting('allow_rating_comment_helpfulness') )
1672          { // If User is not logged OR Users cannot vote
1673              return false;
1674          }
1675  
1676          echo $before;
1677  
1678          $class = '';
1679          if( !empty( $params['class'] ) )
1680          {
1681              $class = ' class="'.$params['class'].'"';
1682          }
1683  
1684          echo '<span id="vote_helpful_'.$this->ID.'"'.$class.'> &nbsp; ';
1685  
1686          if( $current_User->ID == $this->author_user_ID )
1687          { // Display only vote summary for users on their own comments
1688              $params['result_title_undecided'] = T_('Helpfulness:');
1689              $params['after_result'] = '.';
1690              $result_summary = $this->get_vote_summary( 'helpful', $params );
1691              echo ( !empty( $result_summary ) ? $result_summary : $params['title_empty'] );
1692          }
1693          else
1694          { // Display form to vote
1695              $vote_result = $this->get_vote_helpful_disabled();
1696  
1697              if( !$vote_result['is_voted'] )
1698              { // Current user didn't vote on this comment
1699                  $title_text = $params['helpful_text'];
1700              }
1701              else
1702              { // Display vote summary if user already voted on this comment
1703                  $title_text = $this->get_vote_summary( 'helpful', $params );
1704              }
1705  
1706              display_voting_form( array(
1707                      'vote_type'             => 'comment',
1708                      'vote_ID'               => $this->ID,
1709                      'display_noopinion'     => false,
1710                      'display_inappropriate' => false,
1711                      'display_spam'          => false,
1712                      'title_text'            => $title_text.' ',
1713                      'title_like'            => $params['title_yes'],
1714                      'title_like_voted'      => $params['title_yes_voted'],
1715                      'title_dontlike'        => $params['title_no'],
1716                      'title_dontlike_voted'  => $params['title_no_voted'],
1717                  ) );
1718          }
1719  
1720          echo '</span>';
1721  
1722          echo $after;
1723      }
1724  
1725  
1726      /**
1727       * Get next status to publish/restrict to this comment
1728       *
1729       * @param boolean true to get next publish status, and false to get next restrict status
1730       * @param string Status that can be used instead of $this->status
1731       * @return mixed false if user has no permission | array( status, status_text, icon_color ) otherwise
1732       */
1733  	function get_next_status( $publish, $current_status = NULL )
1734      {
1735          if( !is_logged_in() )
1736          {
1737              return false;
1738          }
1739  
1740          global $current_User;
1741  
1742          if( is_null( $current_status ) )
1743          { // Use status of comment if param is NULL
1744              $current_status = $this->status;
1745          }
1746  
1747          $status_order = get_visibility_statuses( 'ordered-array' );
1748          $status_index = get_visibility_statuses( 'ordered-index', array( 'redirected' ) );
1749  
1750          $curr_index = $status_index[$current_status];
1751          if( ( !$publish ) && ( $curr_index == 0 ) && ( $current_status != 'trash' ) && ( $current_status != 'deprecated' ) )
1752          { // Increase curr_index value to allow deprecated status for the other statuses from the same public level
1753              $curr_index = $curr_index + 1;
1754          }
1755          $has_perm = false;
1756          while( !$has_perm && ( $publish ? ( $curr_index < 4 ) : ( $curr_index > 0 ) ) )
1757          { // Check until the user has permission or there is no more status to check
1758              $curr_index = $publish ? ( $curr_index + 1 ) : ( $curr_index - 1 );
1759              $has_perm = $current_User->check_perm( 'comment!'.$status_order[$curr_index][0], 'moderate', false, $this );
1760          }
1761          if( $has_perm )
1762          { // An available status has been found
1763              $label_index = $publish ? 1 : 2;
1764              return array( $status_order[$curr_index][0], $status_order[$curr_index][$label_index], $status_order[$curr_index][3] );
1765          }
1766          return false;
1767      }
1768  
1769  
1770      /**
1771       * Provide link to publish a comment if user has edit rights
1772       *
1773       * @param string to display before link
1774       * @param string to display after link
1775       * @param string link text
1776       * @param string link title
1777       * @param string class name
1778       * @param string glue between url params
1779       * @param boolean save context?
1780       * @param boolean true if create AJAX button
1781       */
1782  	function get_publish_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $redirect_to = NULL )
1783      {
1784          global $current_User, $admin_url;
1785  
1786          if( ! is_logged_in( false ) ) return false;
1787  
1788          $next_status_in_row = $this->get_next_status( true );
1789          if( !$next_status_in_row )
1790          {
1791              return false;
1792          }
1793  
1794          $publish_status = $next_status_in_row[0];
1795          $publish_text = $next_status_in_row[1];
1796  
1797          if( $text == '#' ) $text = get_icon( 'publish', 'imgtag' ).' '.$publish_text;
1798          if( $title == '#' ) $title = T_('Publish this comment!');
1799  
1800          $r = $before;
1801          $r .= '<a href="'.$admin_url.'?ctrl=comments'.$glue.'action=publish'.$glue.'publish_status='.$publish_status.$glue.'comment_ID='.$this->ID.'&amp;'.url_crumb('comment');
1802          if( $save_context )
1803          {
1804              if( $redirect_to != NULL )
1805              {
1806                  $r .= $glue.'redirect_to='.$redirect_to;
1807              }
1808              else
1809              {
1810                  $r .= $glue.'redirect_to='.rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1811              }
1812          }
1813          $r .= '"';
1814  
1815          if( $ajax_button )
1816          {
1817              if( $save_context && ( $redirect_to == NULL ) )
1818              {
1819                  $redirect_to = regenerate_url( '', 'filter=restore', '', '&' );
1820              }
1821              $r .= ' onclick="setCommentStatus('.$this->ID.', \''.$publish_status.'\', \''.$redirect_to.'\'); return false;"';
1822          }
1823  
1824          $r .= ' title="'.$title.'"';
1825          if( !empty( $class ) ) $r .= ' class="'.$class.'"';
1826          $r .= '>'.$text.'</a>';
1827          $r .= $after;
1828  
1829          return $r;
1830      }
1831  
1832  
1833      /**
1834       * Get any kind of moderation link where the user status will be changed.
1835       * This function should be private!
1836       * TODO: asimo>This function should be used instead the old get_publish_link and get_deprecate_link
1837       *
1838       * @param array params
1839       * @return string the moderate link
1840       */
1841  	function get_moderation_link( $params )
1842      {
1843          global $admin_url;
1844  
1845          $redirect_to = $params['redirect_to'];
1846          $new_status = $params['status'];
1847          $action = $params['action'];
1848          $glue = $params['glue'];
1849          $status_param = ( $action == 'publish' ) ? 'publish_status' : 'comment_status';
1850  
1851          $r = $params['before'];
1852          $r .= '<a href="'.$admin_url.'?ctrl=comments'.$glue.'action='.$action.$glue.$status_param.'='.$new_status.$glue.'comment_ID='.$this->ID.'&amp;'.url_crumb('comment');
1853          if( $params['save_context'] )
1854          {
1855              if( $redirect_to != NULL )
1856              {
1857                  $r .= $glue.'redirect_to='.$redirect_to;
1858              }
1859              else
1860              {
1861                  $r .= $glue.'redirect_to='.rawurlencode( regenerate_url( '', 'filter=restore', '', '&' ) );
1862              }
1863          }
1864          $r .= '"';
1865  
1866          if( $params['ajax_button'] )
1867          {
1868              if( $params['save_context'] && ( $redirect_to == NULL ) )
1869              {
1870                  $redirect_to = regenerate_url( '', 'filter=restore', '', '&' );
1871              }
1872              $r .= ' onclick="setCommentStatus('.$this->ID.', \''.$new_status.'\', \''.$redirect_to.'\'); return false;"';
1873          }
1874  
1875          $status_title = get_visibility_statuses( 'moderation-titles' );
1876          $r .= ' title="'.$status_title[$new_status].'"';
1877          if( !empty( $params['class'] ) ) $r .= ' class="'.$params['class'].'"';
1878          $r .= '>'.$params['text'].'</a>';
1879          $r .= $params['after'];
1880  
1881          return $r;
1882      }
1883  
1884  
1885      /**
1886       * Display link to publish a comment if user has edit rights
1887       * TODO: asimo> Use params array instead of so many param
1888       *
1889       * @param string to display before link
1890       * @param string to display after link
1891       * @param string link text
1892       * @param string link title
1893       * @param string class name
1894       * @param string glue between url params
1895       * @param boolean save context?
1896       * @param boolean true if create AJAX button
1897       * @return boolean TRUE - if the publish link is available
1898       */
1899  	function publish_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '', $glue = '&amp;', $save_context = true, $ajax_button = false, $redirect_to = NULL )
1900      {
1901          global $current_User;
1902  
1903          if( ! is_logged_in( false ) ) return false;
1904  
1905          if( !$current_User->check_perm( 'comment!CURSTATUS', 'edit', false, $this ) )
1906          { // User has no permission to edit this comment
1907              return false;
1908          }
1909  
1910          $this->get_Item();
1911          $target_blog_ID = $this->Item->get_blog_ID();
1912          // get the current User highest publish status in this comment item blog
1913          list( $highest_status, $publish_text ) = get_highest_publish_status( 'comment', $target_blog_ID );
1914          if( compare_visibility_status( $highest_status, $this->status ) <= 0 )
1915          { // Current User has no permission to change this comment status to a more public status
1916              return false;
1917          }
1918  
1919          $status_order = get_visibility_statuses( 'ordered-array' );
1920          $status_index = get_visibility_statuses( 'ordered-index', array( 'redirected' ) );
1921          if( isset( $status_index[ $highest_status ] ) &&
1922              isset( $status_order[ $status_index[ $highest_status ] ] ) &&
1923              ! empty( $status_order[ $status_index[ $highest_status ] ][3] ) )
1924          { // Get color of button icon
1925              $status_icon_color = $status_order[ $status_index[ $highest_status ] ][3];
1926          }
1927          else
1928          { // Use green arrow as default
1929              $status_icon_color = 'green';
1930          }
1931  
1932          $params = array(
1933              'before' => $before,
1934              'after'  => $after,
1935              'text'   => ( ( $text == '#' ) ? get_icon( 'move_up_'.$status_icon_color, 'imgtag' ).' '.$publish_text : $text ),
1936              'title'  => ( ( $title == '#' ) ? $publish_text : $title ),
1937              'class'  => $class,
1938              'glue'   => $glue,
1939              'save_context' => $save_context,
1940              'ajax_button'  => $ajax_button,
1941              'redirect_to'  => $redirect_to,
1942              'status' => $highest_status,
1943              'action' => 'publish'
1944          );
1945  
1946          // Display the publish link
1947          echo $this->get_moderation_link( $params );
1948  
1949          return true;
1950      }
1951  
1952  
1953      /**
1954       * Display next available level raise/lower status link
1955       *
1956       * @param array params
1957       * @param boolean set true to get raise link and false to get lower link
1958       * @param string set any status what is required instead of $this->status
1959       * @return boolean true if link is available, false otherwise
1960       */
1961  	function next_status_link( $params, $raise, $current_status = NULL )
1962      {
1963          global $current_User;
1964  
1965          if( ! is_logged_in( false ) ) return false;
1966  
1967          $next_status_in_row = $this->get_next_status( $raise, $current_status );
1968          if( !$next_status_in_row )
1969          { // Next status is not allowed for current user
1970              return false;
1971          }
1972  
1973          $class = empty( $params['class'] ) ? '' : $params['class'].' ';
1974          unset( $params['class'] );
1975  
1976          $next_status = $next_status_in_row[0];
1977          $status_text = $next_status_in_row[1];
1978          if( $raise )
1979          {
1980              $action = 'publish';
1981              $action_icon = get_icon( 'move_up_'.$next_status_in_row[2], 'imgtag', array( 'title' => '' ) );
1982              $class .= 'btn_raise_'.$next_status;
1983          }
1984          else
1985          {
1986              $action = 'restrict';
1987              $action_icon = get_icon( 'move_down_'.$next_status_in_row[2], 'imgtag', array( 'title' => '' ) );
1988              $class .= 'btn_lower_'.$next_status;
1989          }
1990  
1991          $params = array_merge( array(
1992                  'before'       => '',
1993                  'after'        => '',
1994                  'text'         => $action_icon.' '.$status_text,
1995                  'title'        => $status_text,
1996                  'action'       => $action,
1997                  'status'       => $next_status,
1998                  'class'        => $class,
1999                  'glue'         => '&amp;',
2000                  'save_context' => true,
2001                  'ajax_button'  => false,
2002                  'redirect_to'  => NULL,
2003              ), $params
2004          );
2005  
2006          echo $this->get_moderation_link( $params );
2007          return true;
2008      }
2009  
2010  
2011      /**
2012       * Display raise status link if it is available
2013       *
2014       * @param array params
2015       * @return boolean true if link was displayed, false otherwise
2016       */
2017  	function raise_link( $params )
2018      {
2019          return $this->next_status_link( $params, true );
2020      }
2021  
2022  
2023      /**
2024       * Display lower status link if it is available
2025       *
2026       * @param array params
2027       * @return boolean true if link was displayed, false otherwise
2028       */
2029  	function lower_link( $params )
2030      {
2031          return $this->next_status_link( $params, false );
2032      }
2033  
2034  
2035      /**
2036       * Display moderation status links if it is available
2037       *
2038       * @param array params
2039       * @return boolean true if link was displayed, false otherwise
2040       */
2041  	function moderation_links( $params )
2042      {
2043          $params = array_merge( array(
2044                  'detect_last' => true, // TRUE if we should find what button is last and visible, FALSE if we have some other buttons after moderation buttons (e.g. button to delete a comment)
2045              ), $params );
2046  
2047          $statuses = get_visibility_statuses( 'ordered-array' );
2048          $statuses = array_reverse( $statuses );
2049  
2050          // Get first and last statuses that will be visible buttons
2051          $first_status_in_row = $this->get_next_status( true, $this->status );
2052          $last_status_in_row = $this->get_next_status( false, $this->status );
2053          $first_status = $first_status_in_row ? $first_status_in_row[0] : '';
2054          $last_status = '';
2055          if( $params['detect_last'] )
2056          { // We should detect what button is last
2057              $last_status = $last_status_in_row ? $last_status_in_row[0] : '';
2058          }
2059  
2060          $r = '';
2061          $prev_status = '';
2062          foreach( $statuses as $status )
2063          { // Print the buttons to increase status
2064              $next_status_in_row = $this->get_next_status( true, $status[0] );
2065              if( $next_status_in_row && $prev_status != $next_status_in_row[0] )
2066              {
2067                  $tmp_params = $params;
2068                  if( $first_status == $next_status_in_row[0] )
2069                  { // Mark this button as first visible
2070                      $tmp_params['class'] = ( isset( $tmp_params['class'] ) ? $tmp_params['class'] : '' ).' first-child';
2071                      if( $params['detect_last'] && empty( $last_status ) )
2072                      { // This first button is also last button
2073                          $tmp_params['class'] .= ' last-child';
2074                      }
2075                  }
2076                  if( $next_status_in_row[0] == $first_status_in_row[0] )
2077                  {
2078                      $tmp_params['class'] .= ' btn_next_status';
2079                  }
2080                  $r .= $this->next_status_link( $tmp_params, true, $status[0] );
2081              }
2082              $prev_status = $next_status_in_row[0];
2083          }
2084  
2085          $prev_status = '';
2086          foreach( $statuses as $status )
2087          { // Print the buttons to decrease status
2088              $next_status_in_row = $this->get_next_status( false, $status[0] );
2089  
2090              if( $next_status_in_row && $prev_status != $next_status_in_row[0] )
2091              {
2092                  $tmp_params = $params;
2093                  $tmp_params['class'] = (isset( $tmp_params['class'] ) ? $tmp_params['class'] : '' );
2094                  if( $params['detect_last'] && $last_status == $next_status_in_row[0] )
2095                  { // Mark this button as last visible
2096                      $tmp_params['class'] .= ' last-child';
2097                  }
2098                  if( empty( $first_status ) )
2099                  { // This last button also is first button
2100                      $tmp_params['class'] .= ' first-child';
2101                  }
2102                  if( $next_status_in_row[0] == $last_status_in_row[0] )
2103                  {
2104                      $tmp_params['class'] .= ' btn_next_status';
2105                  }
2106                  if( $next_status_in_row[0] == 'deprecated' )
2107                  { // Don't make ajax button to Deprecate comment
2108                      $tmp_params = array_merge( $tmp_params, array( 'ajax_button' => false ) );
2109                  }
2110                  $r .= $this->next_status_link( $tmp_params, false, $status[0] );
2111              }
2112              $prev_status = $next_status_in_row[0];
2113          }
2114  
2115          return $r;
2116      }
2117  
2118  
2119      /**
2120       * Provide link to message form for this comment's author
2121       *
2122       * @param string url of the message form
2123       * @param string to display before link
2124       * @param string to display after link
2125       * @param string link text
2126       * @param string link title
2127       * @param string class name
2128       */
2129  	function msgform_link( $form_url, $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '' )
2130      {
2131          if( $this->get_author_User() )
2132          { // This comment is from a registered user:
2133              $msg_type = $this->author_User->get_msgform_possibility();
2134              if( empty( $msg_type ) )
2135              { // message form is not allowed
2136                  return false;
2137              }
2138              $form_url = url_add_param( $form_url, 'recipient_id='.$this->author_User->ID );
2139          }
2140          else
2141          { // This comment is from a visitor:
2142              if( empty($this->author_email) )
2143              { // We have no email for this comment :(
2144                  return false;
2145              }
2146              elseif( empty($this->allow_msgform) )
2147              { // Anonymous commentator does not allow message form (for this comment)
2148                  return false;
2149              }
2150              $msg_type = 'email';
2151          }
2152  
2153          $form_url = url_add_param( $form_url, 'recipient_id=0&amp;comment_id='.$this->ID.'&amp;post_id='.$this->item_ID
2154                  .'&amp;redirect_to='.rawurlencode(url_rel_to_same_host(regenerate_url('','','','&'), $form_url)) );
2155  
2156          if( $title == '#' )
2157          {
2158              if( $msg_type == 'email' )
2159              {
2160                  $title = T_('Send email to comment author');
2161              }
2162              else
2163              {
2164                  $title = T_('Send message to comment author');
2165              }
2166          }
2167          if( $text == '#' ) $text = get_icon( 'email', 'imgtag', array( 'class' => 'middle', 'title' => $title ) );
2168  
2169          echo $before;
2170          echo '<a href="'.$form_url.'" title="'.$title.'"';
2171          if( !empty( $class ) ) echo ' class="'.$class.'"';
2172          // TODO: have an SEO setting for nofollow here, default to nofollow
2173          echo ' rel="nofollow"';
2174          echo '>'.$text.'</a>';
2175          echo $after;
2176  
2177          return true;
2178      }
2179  
2180  
2181      /**
2182       * Generate permalink to this comment.
2183       *
2184       * Note: This actually only returns the URL, to get a real link, use Comment::get_permanent_link()
2185       *
2186       * @param string glue between url params
2187       */
2188  	function get_permanent_url( $glue = '&amp;' )
2189      {
2190          $this->get_Item();
2191  
2192          $post_permalink = $this->Item->get_single_url( 'auto', '', $glue );
2193  
2194          return $post_permalink.'#'.$this->get_anchor();
2195      }
2196  
2197  
2198      /**
2199       * Template function: display permalink to this comment
2200       *
2201       * Note: This actually only returns the URL, to get a real link, use Comment::permanent_link()
2202       *
2203       * @param string 'urltitle', 'pid', 'archive#id' or 'archive#title'
2204       * @param string url to use
2205       */
2206  	function permanent_url( $mode = '', $blogurl='' )
2207      {
2208          echo $this->get_permanent_url( $mode, $blogurl );
2209      }
2210  
2211  
2212      /**
2213       * Returns a permalink link to the Comment
2214       *
2215       * Note: If you only want the permalink URL, use Comment::get_permanent_url()
2216       *
2217       * @param string link text or special value: '#', '#icon#', '#text#'
2218       * @param string link title
2219       * @param string class name
2220       * @param boolean TRUE - to use attr rel="nofollow"
2221       * @param boolean Restrict by inskin statuses
2222       * @return string Link
2223       */
2224  	function get_permanent_link( $text = '#', $title = '#', $class = '', $nofollow = false, $restrict_status = true )
2225      {
2226          if( $restrict_status && ! in_array( $this->status, get_inskin_statuses() ) )
2227          {
2228              return '';
2229          }
2230  
2231          global $current_User, $baseurl;
2232  
2233          switch( $text )
2234          {
2235              case '#':
2236                  $text = get_icon( 'permalink' ).T_('Permalink');
2237                  break;
2238  
2239              case '#icon#':
2240                  $text = get_icon( 'permalink' );
2241                  break;
2242  
2243              case '#text#':
2244                  $text = T_('Permalink');
2245                  break;
2246  
2247              case '#item#':
2248                  $comment_Item = & $this->get_Item();
2249                  $text = $comment_Item->get_title( array( 'link_type' => 'none' ) );
2250                  break;
2251          }
2252  
2253          if( $title == '#' ) $title = T_('Permanent link to this comment');
2254  
2255          $url = $this->get_permanent_url();
2256  
2257          // Display as link
2258          $r = '<a href="'.$url.'" title="'.$title.'"';
2259          if( !empty( $class ) ) $r .= ' class="'.$class.'"';
2260          if( !empty( $nofollow ) ) $r .= ' rel="nofollow"';
2261          $r .= '>'.$text.'</a>';
2262  
2263          return $r;
2264      }
2265  
2266  
2267      /**
2268       * Displays a permalink link to the Comment
2269       *
2270       * Note: If you only want the permalink URL, use Comment::permanent_url()
2271       */
2272  	function permanent_link( $params = array() )
2273      {
2274          // Make sure we are not missing any param:
2275          $params = array_merge( array(
2276                  'before'      => ' ',
2277                  'after'       => ' ',
2278                  'text'        => '#',
2279                  'title'       => '#',
2280                  'class'       => '',
2281                  'nofollow'    => false,
2282              ), $params );
2283  
2284          echo $params['before'];
2285          echo $this->get_permanent_link( $params['text'], $params['title'], $params['class'], $params['nofollow'] );
2286          echo $params['after'];
2287      }
2288  
2289  
2290  	function get_prerendered_content( $format  = 'htmlbody' )
2291      {
2292          global $CommentList, $Plugins, $DB;
2293  
2294          $use_cache = $this->ID && in_array( $format, array('htmlbody', 'entityencoded', 'xml', 'text') );
2295          if( $use_cache )
2296          { // the format/comment can be cached:
2297              if( empty( $CommentList ) )
2298              { // set comments Blog from comment Item
2299                  $this->get_Item();
2300                  $comments_Blog = & $this->Item->get_Blog();
2301              }
2302              else
2303              { // set comments Blog from CommentList
2304                  $comments_Blog = & $CommentList->Blog;
2305              }
2306              $comment_renderers = $this->get_renderers_validated();
2307              if( empty( $comment_renderers ) )
2308              {
2309                  return format_to_output( $this->content, $format );
2310              }
2311              $comment_renderers = implode( '.', $comment_renderers );
2312              $cache_key = $format.'/'.$comment_renderers;
2313  
2314              $CommentPrerenderingCache = & get_CommentPrerenderingCache();
2315  
2316              if( isset($CommentPrerenderingCache[$format][$this->ID][$cache_key]) )
2317              { // already in PHP cache.
2318                  $r = $CommentPrerenderingCache[$format][$this->ID][$cache_key];
2319                  // Save memory, typically only accessed once.
2320                  unset($CommentPrerenderingCache[$format][$this->ID][$cache_key]);
2321              }
2322              else
2323              { // try loading into Cache
2324                  if( ! isset($CommentPrerenderingCache[$format]) )
2325                  { // only do the prefetch loading once.
2326                      $CommentPrerenderingCache[$format] = array();
2327  
2328                      $SQL = new SQL();
2329                      $SQL->SELECT( 'cmpr_cmt_ID, cmpr_format, cmpr_renderers, cmpr_content_prerendered' );
2330                      $SQL->FROM( 'T_comments__prerendering' );
2331                      if( empty( $CommentList ) )
2332                      {  // load prerendered cache for each comment which belongs to this comments Item
2333                          $SQL->FROM_add( 'INNER JOIN T_comments ON cmpr_cmt_ID = comment_ID' );
2334                          $SQL->WHERE( 'comment_post_ID = '.$this->Item->ID );
2335                      }
2336                      else
2337                      { // load prerendered cache for each comment from the CommentList
2338                          $SQL->WHERE( 'cmpr_cmt_ID IN ( '.implode( ',', $CommentList->get_page_ID_array() ).' )' );
2339                      }
2340                      $SQL->WHERE_and( 'cmpr_format = '.$DB->quote( $format ) );
2341                      $rows = $DB->get_results( $SQL->get(), OBJECT, 'Preload prerendered comments content ('.$format.')' );
2342                      foreach($rows as $row)
2343                      {
2344                          $row_cache_key = $row->cmpr_format.'/'.$row->cmpr_renderers;
2345  
2346                          if( ! isset($CommentPrerenderingCache[$format][$row->cmpr_cmt_ID]) )
2347                          { // init list
2348                              $CommentPrerenderingCache[$format][$row->cmpr_cmt_ID] = array();
2349                          }
2350  
2351                          $CommentPrerenderingCache[$format][$row->cmpr_cmt_ID][$row_cache_key] = $row->cmpr_content_prerendered;
2352                      }
2353  
2354                      // Get the value for current Comment.
2355                      if( isset($CommentPrerenderingCache[$format][$this->ID][$cache_key]) )
2356                      {
2357                          $r = $CommentPrerenderingCache[$format][$this->ID][$cache_key];
2358                          // Save memory, typically only accessed once.
2359                          unset($CommentPrerenderingCache[$format][$this->ID][$cache_key]);
2360                      }
2361                  }
2362              }
2363          }
2364  
2365          if( !isset( $r ) )
2366          {
2367              $data = $this->content;
2368              $Plugins->trigger_event( 'FilterCommentContent', array( 'data' => & $data, 'Comment' => $this ) );
2369              $r = format_to_output( $data, $format );
2370  
2371              if( $use_cache )
2372              { // save into DB (using REPLACE INTO because it may have been pre-rendered by another thread since the SELECT above)
2373                  $DB->query( "
2374                      REPLACE INTO T_comments__prerendering (cmpr_cmt_ID, cmpr_format, cmpr_renderers, cmpr_content_prerendered)
2375                       VALUES ( ".$this->ID.", '".$format."', ".$DB->quote( $comment_renderers ).', '.$DB->quote($r).' )', 'Cache prerendered comment content' );
2376              }
2377          }
2378  
2379          return $r;
2380      }
2381  
2382  
2383      /**
2384       * Unset any prerendered content for this item (in PHP cache).
2385       */
2386  	function delete_prerendered_content()
2387      {
2388          global $DB;
2389  
2390          // Delete DB rows.
2391          $DB->query( 'DELETE FROM T_comments__prerendering WHERE cmpr_cmt_ID = '.$this->ID );
2392  
2393          // Delete cache.
2394          $CommentPrerenderingCache = & get_CommentPrerenderingCache();
2395          foreach( array_keys($CommentPrerenderingCache) as $format )
2396          {
2397              unset($CommentPrerenderingCache[$format][$this->ID]);
2398          }
2399      }
2400  
2401  
2402      /**
2403       * Template function: get content of comment
2404       *
2405       * @param string Output format, see {@link format_to_output()}
2406       * @return string
2407       */
2408  	function get_content( $format = 'htmlbody' )
2409      {
2410          if( $format == 'raw_text' )
2411          {
2412              return format_to_output( $this->content, 'text' );
2413          }
2414          return $this->get_prerendered_content( $format );
2415      }
2416  
2417  
2418      /**
2419       * Template function: display content of comment
2420       *
2421       * @param string Output format, see {@link format_to_output()}
2422       * @param boolean Add ban url action icon after each url or not
2423       * @param boolean show comment attachments
2424       * @param array attachment display params
2425       */
2426  	function content( $format = 'htmlbody', $ban_urls = false, $show_attachments = true, $params = array() )
2427      {
2428          global $current_User;
2429          global $Plugins;
2430  
2431          // Make sure we are not missing any param:
2432          $params = array_merge( array(
2433                  'before_image'          => '<div class="image_block">',
2434                  'before_image_legend'   => '<div class="image_legend">',
2435                  'after_image_legend'    => '</div>',
2436                  'after_image'           => '</div>',
2437                  'image_size'            => 'fit-400x320',
2438                  'image_text'            => '', // Text below attached pictures
2439                  'attachments_mode'      => 'read', // read | view
2440                  'attachments_view_text' => '',
2441              ), $params );
2442  
2443          $attachments = array();
2444  
2445          if( $show_attachments )
2446          {
2447              if( empty( $this->ID ) && isset( $this->checked_attachments ) )
2448              { // PREVIEW
2449                  $attachment_ids = explode( ',', $this->checked_attachments );
2450                  $FileCache = & get_FileCache();
2451                  foreach( $attachment_ids as $ID )
2452                  {
2453                      $File = $FileCache->get_by_ID( $ID, false, false );
2454                      if( $File != NULL )
2455                      {
2456                          $attachments[] = $File;
2457                      }
2458                  }
2459              }
2460              else
2461              { // Get links
2462                  $LinkCache = & get_LinkCache();
2463                  $commentLinks = $LinkCache->get_by_comment_ID( $this->ID );
2464                  if( !empty( $commentLinks ) )
2465                  {
2466                      foreach( $commentLinks as $Link )
2467                      {
2468                          $File = $Link->get_File();
2469                          $attachments[] = $File;
2470                      }
2471                  }
2472              }
2473          }
2474  
2475          $images_is_attached = false;
2476          foreach ($attachments as $index => $attachment)
2477          {
2478              $File = $attachment;
2479  
2480              if( empty( $File ) )
2481              { // File doesn't exist in DB
2482                  unset( $attachments[ $index ] );
2483                  continue;
2484              }
2485  
2486              if( ! $File->exists() )
2487              { // File doesn't exist
2488                  global $Debuglog;
2489                  $Debuglog->add( sprintf( 'File linked to comment #%d does not exist (%s)!', $this->ID, $File->get_full_path() ), array( 'error', 'files' ) );
2490                  unset( $attachments[ $index ] );
2491                  continue;
2492              }
2493  
2494              $r = '';
2495              $params['File'] = $File;
2496              $params['data'] = & $r;
2497  
2498              if( count( $Plugins->trigger_event_first_true( 'RenderCommentAttachment', $params ) ) != 0 )
2499              { // File was processed by plugin
2500                  echo $r;
2501                  unset( $attachments[ $index ] );
2502                  continue;
2503              }
2504              if( $File->is_image() )
2505              { // File is image
2506                  if( $params['attachments_mode'] == 'view' )
2507                  {    // Only preview attachments
2508                      $image_link_rel = '';
2509                      $image_link_to = '';
2510                  }
2511                  else// if( $params['attachments_mode'] == 'read' )
2512                  {    // Read attachments
2513                      $image_link_rel = 'lightbox[c'.$this->ID.']';
2514                      $image_link_to = 'original';
2515                  }
2516                  echo $File->get_tag( $params['before_image'], $params['before_image_legend'], $params['after_image_legend'], $params['after_image'], $params['image_size'], $image_link_to, T_('Posted by ').$this->get_author_name(), $image_link_rel );
2517                  unset( $attachments[ $index ] );
2518                  $images_is_attached = true;
2519              }
2520          }
2521  
2522          if( $images_is_attached && $params['image_text'] != '' )
2523          { // Display info text below pictures
2524              echo $params['image_text'];
2525          }
2526  
2527          if( $ban_urls )
2528          { // add ban icons if user has edit permission for this comment
2529              $ban_urls = $current_User->check_perm( 'comment!CURSTATUS', 'edit', false, $this );
2530          }
2531  
2532          if( $ban_urls )
2533          { // ban urls and user has permission
2534              echo add_ban_icons( $this->get_content( $format ) );
2535          }
2536          else
2537          { // don't ban urls
2538              echo $this->get_content( $format );
2539          }
2540  
2541          if( isset( $attachments ) )
2542          { // show not image attachments
2543              $after_docs = '';
2544              if( count( $attachments ) > 0 )
2545              {
2546                  echo '<br /><b>'.T_( 'Attachments:' ).'</b>';
2547                  echo '<ul class="bFiles">';
2548                  $after_docs = '</ul>';
2549              }
2550              foreach( $attachments as $doc_File )
2551              {
2552                  if( $params['attachments_mode'] == 'view' )
2553                  {    // Only preview attachments
2554                      $attachment_download_link = '';
2555                      $attachment_name = $doc_File->get_type();
2556                  }
2557                  else// if( $params['attachments_mode'] == 'read' )
2558                  {    // Read attachments
2559                      $attachment_download_link = action_icon( T_('Download file'), 'download', $doc_File->get_url(), '', 5 ).' ';
2560                      $attachment_name = $doc_File->get_view_link( $doc_File->get_name() );
2561                  }
2562                  echo '<li>';
2563                  echo $attachment_download_link;
2564                  echo $attachment_name;
2565                  echo ' ('.bytesreadable( $doc_File->get_size() ).')';
2566                  if( !empty( $params['attachments_view_text'] ) )
2567                  {
2568                      echo $params['attachments_view_text'];
2569                  }
2570                  echo '</li>';
2571              }
2572              echo $after_docs;
2573          }
2574      }
2575  
2576  
2577      /**
2578       * Template function: display checkable list of renderers
2579       *
2580       * @param array|NULL If given, assume these renderers to be checked.
2581       * @params boolean display or not
2582       */
2583  	function renderer_checkboxes( $comment_renderers = NULL, $display = true )
2584      {
2585          global $Plugins;
2586  
2587          if( is_null($comment_renderers) )
2588          {
2589              $comment_renderers = $this->get_renderers();
2590          }
2591          $r = $Plugins->get_renderer_checkboxes( $comment_renderers, array( 'Comment' => & $this ) );
2592  
2593          if( $display )
2594          {
2595              echo $r;
2596          }
2597  
2598          return $r;
2599      }
2600  
2601  
2602      /**
2603       * Get title of comment, e.g. "Comment from: Foo Bar"
2604       *
2605       * @param array Params
2606       *   'author_format': Formatting of the author (%s gets replaced with
2607       *                    the author string)
2608       *   'link_text'    : 'avatar' - display author's login with avatar icon,
2609       *                    'only_avatar' - display only author's avatar
2610       *                    'login' - display only author's login
2611       *   'thumb_size'   : Author's avatar size
2612       * @return string
2613       */
2614  	function get_title( $params = array() )
2615      {
2616          // Make sure we are not missing any param:
2617          $params = array_merge( array(
2618                  'author_format' => '%s',
2619                  'link_text'     => 'login', // avatar | only_avatar | login | nickname | firstname | lastname | fullname | preferredname
2620                  'thumb_size'    => 'crop-top-32x32' // author's avatar size
2621              ), $params );
2622  
2623          $author = sprintf( $params['author_format'], $this->get_author( $params ) );
2624  
2625          switch( $this->get( 'type' ) )
2626          {
2627              case 'comment': // Display a comment:
2628                  $s = T_('Comment from %s');
2629                  break;
2630  
2631              case 'trackback': // Display a trackback:
2632                  $s = T_('Trackback from %s');
2633                  break;
2634  
2635              case 'pingback': // Display a pingback:
2636                  $s = T_('Pingback from %s');
2637                  break;
2638          }
2639          return sprintf($s, $author);
2640      }
2641  
2642  
2643      /**
2644       * Get the list of validated renderers for this Comment. This includes stealth plugins etc.
2645       * @return array List of validated renderer codes
2646       */
2647  	function get_renderers_validated()
2648      {
2649          if( ! isset($this->renderers_validated) )
2650          {
2651              global $Plugins;
2652              $this->renderers_validated = $Plugins->validate_renderer_list( $this->get_renderers(), array( 'Comment' => & $this ) );
2653          }
2654          return $this->renderers_validated;
2655      }
2656  
2657  
2658      /**
2659       * Get the list of renderers for this Comment.
2660       * @return array
2661       */
2662  	function get_renderers()
2663      {
2664          return explode( '.', $this->renderers );
2665      }
2666  
2667  
2668      /**
2669       * Set the renderers of the Comment.
2670       *
2671       * @param array List of renderer codes.
2672       * @return boolean true, if it has been set; false if it has not changed
2673       */
2674  	function set_renderers( $renderers )
2675      {
2676          return $this->set_param( 'renderers', 'string', implode( '.', $renderers ) );
2677      }
2678  
2679  
2680      /**
2681       * Template function: display date (datetime) of comment
2682       *
2683       * @param string date/time format: leave empty to use locale default date format
2684       * @param boolean true if you want GMT
2685       */
2686  	function date( $format='', $useGM = false )
2687      {
2688          if( empty($format) )
2689              echo mysql2date( locale_datefmt(), $this->date, $useGM);
2690          else
2691              echo mysql2date( $format, $this->date, $useGM);
2692      }
2693  
2694  
2695      /**
2696       * Template function: display time (datetime) of comment
2697       *
2698       * @param string date/time format: leave empty to use locale default time format
2699       * @param boolean true if you want GMT
2700       */
2701  	function time( $format='', $useGM = false )
2702      {
2703          if( empty($format) )
2704              echo mysql2date( locale_timefmt(), $this->date, $useGM );
2705          else
2706              echo mysql2date( $format, $this->date, $useGM );
2707      }
2708  
2709  
2710      /**
2711       * Template tag:  display rating
2712       */
2713  	function rating( $params = array() )
2714      {
2715          if( empty( $this->rating ) )
2716          {
2717              return false;
2718          }
2719  
2720          // Make sure we are not missing any param:
2721          $params = array_merge( array(
2722                  'before'      => '<div class="comment_rating">',
2723                  'after'       => '</div>',
2724              ), $params );
2725  
2726          echo $params['before'];
2727  
2728          star_rating( $this->rating );
2729  
2730          echo $params['after'];
2731      }
2732  
2733    /**
2734       * Rating input
2735       */
2736  	function rating_input( $params = array() )
2737      {
2738          global $rsc_uri;
2739  
2740          $params = array_merge( array(
2741                                      'before'     => '',
2742                                      'after'      => '',
2743                                      'label_low'  => T_('Bad'),
2744                                      'label_2'    => T_('Poor'),
2745                                      'label_3'    => T_('Average'),
2746                                      'label_4'    => T_('Good'),
2747                                      'label_high' => T_('Excellent'),
2748                                      'reset'      => false,
2749                                      'item_ID'    => 0, // Set only for new comments without defined item ID
2750                                  ), $params );
2751  
2752          echo $params['before'];
2753  
2754          if( empty( $this->item_ID ) && !empty( $params['item_ID'] ) )
2755          {    // Set item ID for form with new comment
2756              $this->item_ID = $params['item_ID'];
2757          }
2758          if( $comment_Item = & $this->get_Item() )
2759          {
2760              if( $item_Blog = & $comment_Item->get_Blog() )
2761              {
2762                  if( $item_Blog->get_setting( 'rating_question' ) != '' )
2763                  {    // Display star rating question
2764                      echo '<div id="comment_rating_question">';
2765                      echo nl2br( $item_Blog->get_setting( 'rating_question' ) );
2766                      echo '</div>';
2767                  }
2768              }
2769          }
2770  
2771          echo '<div id="comment_rating">';
2772  
2773          echo $params['label_low'];
2774  
2775          for( $i=1; $i<=5; $i++ )
2776          {
2777              echo '<input type="radio" class="radio" name="comment_rating" value="'.$i.'"';
2778              if( $this->rating == $i )
2779              {
2780                  echo ' checked="checked"';
2781              }
2782              echo ' />';
2783          }
2784  
2785          echo $params['label_high'];
2786  
2787          $jquery_raty_param = '';
2788          if( $params['reset'] )
2789          { // Init "reset" button
2790              $jquery_raty_param = 'cancel: true';
2791              $this->rating_none_input( array( 'before' => '<p>', 'after' => '</p>' ) );
2792          }
2793  
2794          echo '</div>';
2795  
2796          echo '<script type="text/javascript">
2797          /* <![CDATA[ */
2798          jQuery("#comment_rating").html("").raty({
2799              scoreName: "comment_rating",
2800              start: '.(int)$this->rating.',
2801              hintList: ["'.$params['label_low'].'", "'.$params['label_2'].'", "'.$params['label_3'].'", "'.$params['label_4'].'", "'.$params['label_high'].'"],
2802              width: 110,
2803              '.$jquery_raty_param.'
2804          });
2805          /* ]]> */
2806          </script>';
2807  
2808          echo $params['after'];
2809      }
2810  
2811  
2812    /**
2813       * Rating reset input
2814       */
2815  	function rating_none_input( $params = array() )
2816      {
2817          $params = array_merge( array(
2818                                      'before'    => '',
2819                                      'after'     => '',
2820                                      'label'     => T_('No rating'),
2821                                  ), $params );
2822  
2823          echo $params['before'];
2824  
2825          echo '<label><input type="radio" class="radio" name="comment_rating" value="0"';
2826          if( empty($this->rating) )
2827          {
2828              echo ' checked="checked"';
2829          }
2830          echo ' />';
2831  
2832          echo $params['label'].'</label>';
2833  
2834          echo $params['after'];
2835      }
2836  
2837  
2838      /**
2839       * Get status of comment
2840       *
2841       * Statuses:
2842       * - published
2843       * - deprecated
2844       * - protected
2845       * - private
2846       * - draft
2847       *
2848       * @param string Output format, see {@link format_to_output()}
2849       * @return string Status
2850       */
2851  	function get_status( $format = 'htmlbody' )
2852      {
2853          $r = '';
2854  
2855          switch( $format )
2856          {
2857              case 'raw':
2858                  $r .= $this->dget( 'status', 'raw' );
2859                  break;
2860  
2861              case 'styled':
2862                  $r .= get_styled_status( $this->status, $this->get( 't_status' ) );
2863                  break;
2864  
2865              default:
2866                  $r .= format_to_output( $this->get( 't_status' ), $format );
2867                  break;
2868          }
2869  
2870          return $r;
2871      }
2872  
2873  
2874      /**
2875       * Template function: display status of comment
2876       *
2877       * Statuses:
2878       * - published
2879       * - deprecated
2880       * - protected
2881       * - private
2882       * - draft
2883       *
2884       * @param string Output format, see {@link format_to_output()}
2885       */
2886  	function status( $format = 'htmlbody' )
2887      {
2888          echo $this->get_status( $format );
2889      }
2890  
2891  
2892      /**
2893       * Template function: display all statuses and only one is visible by css class name
2894       *
2895       * Statuses:
2896       * - published
2897       * - community
2898       * - protected
2899       * - review
2900       * - private
2901       * - draft
2902       */
2903  	function statuses()
2904      {
2905          $statuses = get_visibility_statuses( '', array( 'deprecated', 'redirected', 'trash' ) );
2906  
2907          foreach( $statuses as $status => $title )
2908          {
2909              echo get_styled_status( $status, $title );
2910          }
2911      }
2912  
2913  
2914      /**
2915       * Handle comment email notifications
2916       *
2917       * Should be called only when a new comment was posted or when a comment status was changed to published
2918       * 
2919       * @param boolean set true if the comment was posted just now, false otherwise
2920       * @param integer the user ID who executed the action which will be notified, or NULL if it was executed by an anonymous user
2921       */
2922  	function handle_notifications( $just_posted = false, $executed_by_userid = NULL )
2923      {
2924          global $Settings;
2925  
2926          if( $just_posted )
2927          { // send email notification to moderators
2928              $this->send_email_notifications( true, false, $executed_by_userid );
2929          }
2930  
2931          if( $this->status != 'published' )
2932          { // don't send notificaitons about non published comments
2933              return;
2934          }
2935  
2936          $notifications_mode = $Settings->get('outbound_notifications_mode');
2937  
2938          if( $notifications_mode == 'off' )
2939          { // don't send notification
2940              return false;
2941          }
2942  
2943          if( $this->get( 'notif_status' ) != 'noreq' )
2944          { // notification have been done before, or is in progress
2945              return false;
2946          }
2947  
2948          $edited_Item = & $this->get_Item();
2949  
2950          if( $notifications_mode == 'immediate' )
2951          { // Send email notifications now!
2952              $this->send_email_notifications( false, $just_posted, $executed_by_userid );
2953  
2954              // Record that processing has been done:
2955              $this->set( 'notif_status', 'finished' );
2956          }
2957          else
2958          { // Create scheduled job to send notifications
2959              // CREATE OBJECT:
2960              load_class( '/cron/model/_cronjob.class.php', 'Cronjob' );
2961              $edited_Cronjob = new Cronjob();
2962  
2963              // start datetime. We do not want to ping before the post is effectively published:
2964              $edited_Cronjob->set( 'start_datetime', $this->date );
2965  
2966              // name:
2967              $edited_Cronjob->set( 'name', sprintf( T_('Send notifications about new comment on &laquo;%s&raquo;'), strip_tags($edited_Item->get( 'title' ) ) ) );
2968  
2969              // controller:
2970              $edited_Cronjob->set( 'controller', 'cron/jobs/_comment_notifications.job.php' );
2971  
2972              // params: specify which post this job is supposed to send notifications for:
2973              $edited_Cronjob->set( 'params', array( 'comment_ID' => $this->ID, 'except_moderators' => $just_posted, 'executed_by_userid' => $executed_by_userid ) );
2974  
2975              // Save cronjob to DB:
2976              $edited_Cronjob->dbinsert();
2977  
2978              // Memorize the cron job ID which is going to handle this post:
2979              $this->set( 'notif_ctsk_ID', $edited_Cronjob->ID );
2980  
2981              // Record that processing has been scheduled:
2982              $this->set( 'notif_status', 'todo' );
2983          }
2984          // update comment notification params
2985          $this->dbupdate();
2986      }
2987  
2988  
2989      /**
2990       * Send email notifications to subscribed users:
2991       *
2992       * efy-asimo> moderatation and subscription notifications have been separated
2993       *
2994       * @param boolean true if send only moderation email, false otherwise
2995       * @param boolean true if send for everyone else but not for moterators, because a moderation email was sent for them
2996       * @param integer the user ID who executed the action which will be notified, or NULL if it was executed by an anonymous user
2997       */
2998  	function send_email_notifications( $only_moderators = false, $except_moderators = false, $executed_by_userid = NULL )
2999      {
3000          global $DB, $admin_url, $baseurl, $debug, $Debuglog, $htsrv_url;
3001          global $Settings, $UserSettings;
3002  
3003          if( $only_moderators && $except_moderators )
3004          { // at least one of them must be false
3005              return;
3006          }
3007  
3008          $edited_Item = & $this->get_Item();
3009          $edited_Blog = & $edited_Item->get_Blog();
3010          $owner_User = $edited_Blog->get_owner_User();
3011          $notify_users = array();
3012          $moderators = array();
3013  
3014          if( $only_moderators || $except_moderators )
3015          { // we need the list of moderators:
3016              $sql = 'SELECT DISTINCT user_email, user_ID, uset_value as notify_moderation
3017                          FROM T_users
3018                              LEFT JOIN T_coll_user_perms ON bloguser_user_ID = user_ID
3019                              LEFT JOIN T_coll_group_perms ON bloggroup_group_ID = user_grp_ID
3020                              LEFT JOIN T_users__usersettings ON uset_user_ID = user_ID AND uset_name = "notify_comment_moderation"
3021                              LEFT JOIN T_groups ON grp_ID = user_grp_ID
3022                          WHERE ( ( bloguser_blog_ID = '.$edited_Blog->ID.' AND bloguser_perm_edit_cmt IN ( "anon", "lt", "le", "all" ) )
3023                                  OR ( bloggroup_blog_ID = '.$edited_Blog->ID.' AND bloggroup_perm_edit_cmt IN ( "anon", "lt", "le", "all" ) )
3024                                  OR ( grp_perm_blogs = "editall" ) )
3025                              AND LENGTH(TRIM(user_email)) > 0';
3026              $moderators_to_notify = $DB->get_results( $sql );
3027  
3028              foreach( $moderators_to_notify as $moderator )
3029              {
3030                  $notify_moderator = ( is_null( $moderator->notify_moderation ) ) ? $Settings->get( 'def_notify_comment_moderation' ) : $moderator->notify_moderation;
3031                  if( $notify_moderator )
3032                  { // add user to notify
3033                      $moderators[] = $moderator->user_ID;
3034                  }
3035              }
3036              if( $UserSettings->get( 'notify_comment_moderation', $owner_User->ID ) && is_email( $owner_User->get( 'email' ) ) )
3037              { // add blog owner
3038                  $moderators[] = $owner_User->ID;
3039              }
3040  
3041              // Load all moderators, and check each edit permission on this comment
3042              $UserCache = & get_UserCache();
3043              $UserCache->load_list( $moderators );
3044              foreach( $moderators as $index => $moderator_ID )
3045              {
3046                  $moderator_User = $UserCache->get_by_ID( $moderator_ID, false );
3047                  if( ( ! $moderator_User ) || ( ! $moderator_User->check_perm( 'comment!CURSTATUS', 'edit', false, $this ) ) )
3048                  { // User doesn't exists any more, or has no permission to edit this comment!
3049                      unset( $moderators[$index] );
3050                  }
3051                  elseif( $only_moderators )
3052                  {
3053                      $notify_users[$moderator_ID] = 'moderator';
3054                  }
3055              }
3056          }
3057  
3058          if( ! $only_moderators )
3059          { // Not only moderators needs to be notified:
3060              $except_condition = '';
3061  
3062              if( $except_moderators && ( ! empty( $moderators ) ) )
3063              { // Set except moderators condition. Exclude moderators who already got a notification email.
3064                  $except_condition = ' AND user_ID NOT IN ( "'.implode( '", "', $moderators ).'" )';
3065              }
3066  
3067              // Check if we need to include the item creator user:
3068              $creator_User = & $edited_Item->get_creator_User();
3069              if( $UserSettings->get( 'notify_published_comments', $creator_User->ID ) && ( ! empty( $creator_User->email ) )
3070                  && ( ! ( in_array( $creator_User->ID, $moderators ) ) ) )
3071              { // Post creator wants to be notified, and post author is not a moderator...
3072                  $notify_users[$creator_User->ID] = 'creator';
3073              }
3074  
3075              // Get list of users who want to be notified about the this post comments:
3076              if( $edited_Blog->get_setting( 'allow_item_subscriptions' ) )
3077              { // item subscriptions is allowed
3078                  $sql = 'SELECT DISTINCT user_ID
3079                                      FROM T_items__subscriptions INNER JOIN T_users ON isub_user_ID = user_ID
3080                                   WHERE isub_item_ID = '.$edited_Item->ID.'
3081                                     AND isub_comments <> 0
3082                                     AND LENGTH(TRIM(user_email)) > 0'.$except_condition;
3083                  $notify_list = $DB->get_results( $sql );
3084  
3085                  // Preprocess list:
3086                  foreach( $notify_list as $notification )
3087                  {
3088                      $notify_users[$notification->user_ID] = 'item_subscription';
3089                  }
3090              }
3091  
3092              // Get list of users who want to be notfied about this blog comments:
3093              if( $edited_Blog->get_setting( 'allow_subscriptions' ) )
3094              { // blog subscription is allowed
3095                  $sql = 'SELECT DISTINCT user_ID
3096                                  FROM T_subscriptions INNER JOIN T_users ON sub_user_ID = user_ID
3097                               WHERE sub_coll_ID = '.$edited_Blog->ID.'
3098                                 AND sub_comments <> 0
3099                                 AND LENGTH(TRIM(user_email)) > 0'.$except_condition;
3100                  $notify_list = $DB->get_results( $sql );
3101  
3102                  // Preprocess list:
3103                  foreach( $notify_list as $notification )
3104                  {
3105                      $notify_users[$notification->user_ID] = 'blog_subscription';
3106                  }
3107              }
3108          }
3109  
3110          if( ( $executed_by_userid != NULL ) && isset( $notify_users[$executed_by_userid] ) )
3111          { // don't notify the user who just created/updated this comment
3112              unset( $notify_users[$executed_by_userid] );
3113          }
3114  
3115          if( ! count( $notify_users ) )
3116          { // No-one to notify:
3117              return false;
3118          }
3119  
3120  
3121          /*
3122           * We have a list of user IDs to notify:
3123           */
3124  
3125          // TODO: dh> this reveals the comments author's email address to all subscribers!!
3126          //           $notify_from should get used by default, unless the user has opted in to be the sender!
3127          // fp>If the subscriber has permission to moderate the comments, he SHOULD receive the email address.
3128          // Get author email address. It will be visible for moderators/blog/post owners only -- NOT for other subscribers
3129          if( $this->get_author_User() )
3130          { // Comment from a registered user:
3131              $reply_to = $this->author_User->get('email');
3132              $author_name = $this->author_User->get('login');
3133              $author_ID = $this->author_User->ID;
3134          }
3135          elseif( ! empty( $this->author_email ) )
3136          { // non-member, but with email address:
3137              $reply_to = $this->author_email;
3138              $author_name = $this->dget( 'author' );
3139              $author_ID = NULL;
3140          }
3141          else
3142          { // Fallback (we have no email address):  fp>TODO: or the subscriber is not allowed to view it.
3143              $reply_to = NULL;
3144              $author_name =  $this->dget( 'author' );
3145              $author_ID = NULL;
3146          }
3147  
3148          // Load all users who will be notified, becasuse another way the send_mail_to_User funtion would load them one by one
3149          $UserCache = & get_UserCache();
3150          $UserCache->load_list( array_keys( $notify_users ) );
3151  
3152          // Load a list with the blocked emails  in cache
3153          load_blocked_emails( array_keys( $notify_users ) );
3154  
3155          // Send emails:
3156          foreach( $notify_users as $notify_user_ID => $notify_type )
3157          {
3158              // get data content
3159              $notify_User = $UserCache->get_by_ID( $notify_user_ID );
3160              $notify_email = $notify_User->get( 'email' );
3161  
3162              // init notification setting
3163              locale_temp_switch( $notify_User->get( 'locale' ) );
3164              $notify_user_Group = $notify_User->get_Group();
3165              $notify_full = ( ( $notify_type == 'moderator' ) && ( $notify_user_Group->check_perm( 'comment_moderation_notif', 'full' ) )
3166                              || ( $notify_user_Group->check_perm( 'comment_subscription_notif', 'full' ) ) );
3167  
3168              switch( $this->type )
3169              {
3170                  case 'trackback':
3171                      /* TRANS: Subject of the mail to send on new trackbacks. First %s is the blog's shortname, the second %s is the item's title. */
3172                      $subject = T_('[%s] New trackback on "%s"');
3173                      break;
3174  
3175                  default:
3176                      /* TRANS: Subject of the mail to send on new comments. */
3177                      // In case of full notification the first %s is blog name, the second %s is the item's title.
3178                      // In case of short notification the first %s is author login, the second %s is the item's title.
3179                      $subject = $notify_full ? T_('[%s] New comment on "%s"') : T_( '%s posted a new comment on "%s"' );
3180                      if( $only_moderators )
3181                      {
3182                          if( $this->status == 'draft' )
3183                          {
3184                              $subject = $notify_full ? T_('[%s] New comment awaiting moderation on "%s"') : T_('New comment awaiting moderation: ').$subject;
3185                          }
3186                          else
3187                          {
3188                              $subject = $notify_full ? T_('[%s] New comment may need moderation on "%s"') : T_('New comment may need moderation: ').$subject;
3189                          }
3190                      }
3191              }
3192  
3193              if( $notify_type == 'moderator' )
3194              { // moderation email
3195                  $user_reply_to = $reply_to;
3196              }
3197              else if( $notify_type == 'blog_subscription' )
3198              { // blog subscription
3199                  $user_reply_to = NULL;
3200              }
3201              else if( $notify_type == 'item_subscription' )
3202              { // item subscription
3203                  $user_reply_to = NULL;
3204              }
3205              else if( $notify_type == 'creator' )
3206              { // user is the creator of the post
3207                  $user_reply_to = $reply_to;
3208              }
3209              else
3210              {
3211                  debug_die( 'Unknown user subscription type' );
3212              }
3213  
3214              $subject = sprintf( $subject, $notify_full ? $edited_Blog->get('shortname') : $author_name, $edited_Item->get('title') );
3215  
3216              $email_template_params = array(
3217                      'notify_full' => $notify_full,
3218                      'Comment'     => $this,
3219                      'Blog'        => $edited_Blog,
3220                      'Item'        => $edited_Item,
3221                      'author_name' => $author_name,
3222                      'author_ID'   => $author_ID,
3223                      'notify_type' => $notify_type,
3224                  );
3225  
3226              if( $debug )
3227              {
3228                  $notify_message = mail_template( 'comment_new', 'text', $email_template_params );
3229                  $mail_dump = "Sending notification to $notify_email:<pre>Subject: $subject\n$notify_message</pre>";
3230  
3231                  if( $debug >= 2 )
3232                  { // output mail content - NOTE: this will kill sending of headers.
3233                      echo "<p>$mail_dump</p>";
3234                  }
3235  
3236                  $Debuglog->add( $mail_dump, 'notification' );
3237              }
3238  
3239              // Send the email:
3240              // Note: Note activated users won't get notification email
3241              send_mail_to_User( $notify_user_ID, $subject, 'comment_new', $email_template_params, false, array( 'Reply-To' => $user_reply_to ) );
3242  
3243              blocked_emails_memorize( $notify_User->email );
3244  
3245              locale_restore_previous();
3246          }
3247  
3248          blocked_emails_display();
3249      }
3250  
3251  
3252      /**
3253       * Handle quick moderation secret param: checks if comment secret should expire after first comment moderation, and delete the secret if required
3254       * This should be called after every kind of commment moderation
3255       */
3256  	function handle_qm_secret( $save_comment = false )
3257      {
3258          $comment_Item = & $this->get_Item();
3259          $comment_Item->load_Blog();
3260          if( $comment_Item->Blog->get_setting( 'comment_quick_moderation' ) == 'expire' )
3261          { // comment secret expires after first comment moderation
3262              $this->set( 'secret', NULL );
3263          }
3264          if( $save_comment )
3265          {
3266              $this->dbupdate();
3267          }
3268      }
3269  
3270  
3271      /**
3272       * Check if this comment is published to some of the public statuses ( 'published', 'community', 'protected' )
3273       *
3274       * @return boolean true ir the item status is public or limited public, false otherwise
3275       */
3276  	function is_published()
3277      {
3278          $permvalue = get_status_permvalue( $this->status );
3279          $published_statuses_permvalue = get_status_permvalue( 'published_statuses' );
3280          return ( $permvalue & $published_statuses_permvalue ) ? true : false;
3281      }
3282  
3283  
3284      /**
3285       * Check if comment public or limited public status was changed. Limited public status is like community or protected.
3286       *
3287       * @return boolean false if status was not changed or neither the previous nor current status is public or limited public, true otherwise
3288       */
3289  	function check_publish_status_changed()
3290      {
3291          if( !isset( $this->previous_status ) || $this->previous_status == $this->status )
3292          { // Status was not changed
3293              return false;
3294          }
3295  
3296          $previous_status_permvalue = get_status_permvalue( $this->previous_status );
3297          $current_status_permvalue = get_status_permvalue( $this->status );
3298          $published_statuses_permvalue = get_status_permvalue( 'published_statuses' );
3299  
3300          if( $current_status_permvalue & $published_statuses_permvalue )
3301          { // status has been changed to another public or limited public status
3302              return true;
3303          }
3304  
3305          if( $previous_status_permvalue & $published_statuses_permvalue )
3306          { // srevious status was  public or limited public status, but current status is not
3307              return true;
3308          }
3309  
3310          // This comment was not publsihed before and it is not published now either
3311          return false;
3312      }
3313  
3314  
3315      /**
3316       * Trigger event AfterCommentUpdate after calling parent method.
3317       *
3318       * @return boolean true on success
3319       */
3320  	function dbupdate()
3321      {
3322          global $Plugins, $DB;
3323  
3324          $dbchanges = $this->dbchanges;
3325  
3326          $DB->begin();
3327  
3328          if( ( $r = parent::dbupdate() ) !== false )
3329          {
3330              if( isset( $dbchanges['comment_content'] ) || isset( $dbchanges['comment_renderers'] ) )
3331              {
3332                  $this->delete_prerendered_content();
3333              }
3334  
3335              if( $this->check_publish_status_changed() )
3336              { // Update last touched date of item if comment is updated into/out some public status
3337                  $comment_Item = & $this->get_Item();
3338                  $comment_Item->update_last_touched_date();
3339              }
3340  
3341              $DB->commit();
3342  
3343              $Plugins->trigger_event( 'AfterCommentUpdate', $params = array( 'Comment' => & $this, 'dbchanges' => $dbchanges ) );
3344          }
3345          else
3346          {
3347              $DB->rollback();
3348          }
3349  
3350          return $r;
3351      }
3352  
3353  
3354      /**
3355       * Get karma and set it before adding the Comment to DB.
3356       *
3357       * @return boolean true on success, false if it did not get inserted
3358       */
3359  	function dbinsert()
3360      {
3361          /**
3362           * @var Plugins
3363           */
3364          global $Plugins;
3365          global $Settings;
3366  
3367          // Get karma percentage (interval -100 - 100)
3368          $spam_karma = $Plugins->trigger_karma_collect( 'GetSpamKarmaForComment', array( 'Comment' => & $this ) );
3369  
3370          $this->set_spam_karma( $spam_karma );
3371  
3372          // Change status accordingly:
3373          if( ! is_null($spam_karma) )
3374          {
3375              if( $spam_karma < $Settings->get('antispam_threshold_publish') )
3376              { // Publish:
3377                  $this->set( 'status', 'published' );
3378              }
3379              elseif( $spam_karma > $Settings->get('antispam_threshold_delete') )
3380              { // Delete/No insert:
3381                  return false;
3382              }
3383          }
3384  
3385          // set comment secret for quick moderation
3386          // fp> users have requested this for all comments
3387          $comment_Item = & $this->get_Item();
3388          $comment_Blog = & $comment_Item->get_Blog();
3389          if( $comment_Blog->get_setting( 'comment_quick_moderation' ) != 'never' )
3390          { // quick moderation is permitted, set comment secret
3391              $this->set( 'secret', generate_random_key() );
3392          }
3393  
3394          $dbchanges = $this->dbchanges;
3395  
3396          if( $r = parent::dbinsert() )
3397          {
3398              if( $this->is_published() )
3399              { // Update last touched date of item if comment is created in published status
3400                  $comment_Item->update_last_touched_date();
3401              }
3402              $Plugins->trigger_event( 'AfterCommentInsert', $params = array( 'Comment' => & $this, 'dbchanges' => $dbchanges ) );
3403          }
3404  
3405          return $r;
3406      }
3407  
3408  
3409      /**
3410       * Trigger event AfterCommentDelete after calling parent method.
3411       *
3412       * @param boolean set true to force permanent delete, leave false otherwise
3413       * @return boolean true on success
3414       */
3415  	function dbdelete( $force_permanent_delete = false )
3416      {
3417          global $Plugins, $DB;
3418  
3419          $DB->begin();
3420  
3421          $was_published = $this->is_published();
3422          if( $this->status != 'trash' )
3423          { // The comment was not recycled yet
3424              if( $this->has_replies() )
3425              { // Move the replies to the one level up
3426                  $new_parent_ID = !empty( $this->in_reply_to_cmt_ID ) ? $DB->quote( $this->in_reply_to_cmt_ID ) : 'NULL';
3427                  $DB->query( 'UPDATE T_comments
3428                      SET comment_in_reply_to_cmt_ID = '.$new_parent_ID.'
3429                    WHERE comment_in_reply_to_cmt_ID = '.$this->ID );
3430              }
3431          }
3432  
3433          if( $force_permanent_delete || ( $this->status == 'trash' ) )
3434          {
3435              // remember ID, because parent method resets it to 0
3436              $old_ID = $this->ID;
3437  
3438              // Select comment attachment ids
3439              $result = $DB->get_col( '
3440                  SELECT link_file_ID
3441                      FROM T_links
3442                   WHERE link_cmt_ID = '.$this->ID );
3443  
3444              if( $r = parent::dbdelete() )
3445              {
3446                  if( !empty( $result ) )
3447                  { // remove deleted comment not linked attachments
3448                      remove_orphan_files( $result );
3449                  }
3450  
3451                  // re-set the ID for the Plugin event
3452                  $this->ID = $old_ID;
3453  
3454                  $this->delete_prerendered_content();
3455  
3456                  $Plugins->trigger_event( 'AfterCommentDelete', $params = array( 'Comment' => & $this ) );
3457  
3458                  $this->ID = 0;
3459              }
3460          }
3461          else
3462          { // don't delete, just move to the trash:
3463              $this->set( 'status', 'trash' );
3464              $r = $this->dbupdate();
3465          }
3466  
3467          if( $r )
3468          {
3469              if( $was_published )
3470              { // Update last touched date of item if a published comment was deleted
3471                  $comment_Item = & $this->get_Item();
3472                  $comment_Item->update_last_touched_date();
3473              }
3474              $DB->commit();
3475          }
3476          else
3477          {
3478              $DB->rollback();
3479          }
3480  
3481          return $r;
3482      }
3483  
3484  
3485      /**
3486       * Displays link for replying to the Comment if blog's setting allows this action
3487       *
3488       * @param string to display before link
3489       * @param string to display after link
3490       * @param string link text
3491       * @param string link title
3492       * @param string class name
3493       */
3494  	function reply_link( $before = ' ', $after = ' ', $text = '#', $title = '#', $class = '' )
3495      {
3496          if( ! is_logged_in( false ) )
3497          {
3498              return false;
3499          }
3500  
3501          if( empty( $this->ID ) )
3502          {    // Happens in Preview
3503              return false;
3504          }
3505  
3506          $this->get_Item();
3507          $this->Item->load_Blog();
3508  
3509          if( ! $this->Item->Blog->get_setting( 'threaded_comments' ) )
3510          {    // A blog's setting is OFF for replying to the comment
3511              return false;
3512          }
3513  
3514          if( !$this->Item->can_comment() )
3515          {    // The comments are disabled
3516              return false;
3517          }
3518  
3519          // ID of a replying comment
3520          $comment_reply_ID = param( 'reply_ID', 'integer', 0 );
3521  
3522          if( $text == '#' )
3523          {    // Use default text
3524              $text = $this->ID == $comment_reply_ID ? T_('You are currently replying to this comment') : T_('Reply to this comment');
3525          }
3526          if( $title == '#' )
3527          {    // Use default title
3528              $title = T_('Reply to this comment');
3529          }
3530  
3531          $class .= ' comment_reply';
3532          if( $this->ID == $comment_reply_ID )
3533          {    // This comment is using for replying now
3534              $class .= ' active';
3535          }
3536          $class = ' class="'.trim( $class ).'"';
3537  
3538          $url = url_add_param( $this->Item->get_permanent_url(), 'reply_ID='.$this->ID.'&amp;redir=no' ).'#form_p'.$this->Item->ID;
3539  
3540          echo $before;
3541  
3542          // Display a link
3543          echo '<a href="'.$url.'" title="'.$title.'"'.$class.' rel="'.$this->ID.'">'.$text.'</a>';
3544  
3545          echo $after;
3546  
3547          return true;
3548      }
3549  
3550  
3551      /**
3552       * Check if comment has the replies
3553       */
3554  	function has_replies()
3555      {
3556          global $cache_comments_has_replies;
3557  
3558          if( ! isset( $cache_comments_has_replies ) )
3559          { // Init an array to cache
3560              $cache_comments_has_replies = array();
3561          }
3562  
3563          if( ! isset( $cache_comments_has_replies[ $this->item_ID ] ) )
3564          { // Get all comments that have the replies from DB (first time)
3565              global $DB;
3566  
3567              // Cache a result
3568              $SQL = new SQL();
3569              $SQL->SELECT( 'DISTINCT ( comment_in_reply_to_cmt_ID ), comment_ID' );
3570              $SQL->FROM( 'T_comments' );
3571              $SQL->WHERE( 'comment_in_reply_to_cmt_ID IS NOT NULL' );
3572              $SQL->WHERE_and( 'comment_post_ID = '.$this->item_ID );
3573  
3574              // Init an array to cache a result from current item
3575              $cache_comments_has_replies[ $this->item_ID ] = $DB->get_assoc( $SQL->get() );
3576          }
3577  
3578          // Get a result from cache
3579          return isset( $cache_comments_has_replies[ $this->item_ID ][ $this->ID ] );
3580      }
3581  
3582  
3583      /**
3584       * Get a permalink link to the Item of this Comment
3585       *
3586       * @param array Params
3587       * @return string Link to Item with anchor to Comment
3588       */
3589  	function get_permanent_item_link( $params = array() )
3590      {
3591          $params = array_merge( array(
3592                  'text'            => '#item#',
3593                  'title'           => '#',
3594                  'class'           => '',
3595                  'nofollow'        => false,
3596                  'restrict_status' => false,
3597              ), $params );
3598  
3599          return $this->get_permanent_link( $params['text'], $params['title'], $params['class'], $params['nofollow'], $params['restrict_status'] );
3600      }
3601  }
3602  
3603  ?>

title

Description

title

Description

title

Description

title

title

Body