Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.
Options

add link discussion after hit anchor in comment

This question is about a plugin i use from last year, original written by @hgtonight.
What it is about: in every comment appears an gray V which a user can click on. After clicking, the V becomes green. So a user can click on it when he/she decides that that comment was the best answer to his question. This all works fine.

What i want to achieve now is that when a V is marked green, there must be an anchor "echood" to the top of the Discussion with a permalink to that specific comment which has the green V

This is part of the code i already have:

    protected function AddMarkV($Sender) {
    $Discussion = $Sender->EventArguments['Discussion'];
    $Session = Gdn::Session();
    $Comment = $Sender->EventArguments['Comment'];
      if($Session->UserID == $Discussion->InsertUserID || $Session->CheckPermission('Garden.Moderation.Manage')) {
      if ($Comment->MarkV) {
         //echo Anchor("", 'discussion/markv/' . $Comment->CommentID, 'Hijack img-swap on');
    echo Anchor("", 'discussion/markv/' . $Comment->CommentID, array('title' => "Annuleren", 'class' => "Hijack img-swap on"));

      }
      else {
        //echo Anchor("", 'discussion/markv/' . $Comment->CommentID, 'Hijack img-swap');
       echo Anchor("", 'discussion/markv/' . $Comment->CommentID, array('title' => "Beste Antwoord", 'class' => "Hijack img-swap"));
      }
    }
    else {
      if ($Comment->MarkV) {
        echo Wrap("", 'div', array('class' => 'Hijack img-swap on'));
    $Sender->CommentModel->SetField($Comment->CommentID, 'MarkV', !$Comment->MarkV);

    }
      else {
        echo Wrap("", 'div', array('class' => 'Hijack img-swap'));
      }
    }
  }

When hitting the V, the background of the class changes and the V becomes green. So it is only a class change.

This is what i am experimenting with so that the Link to the green V comment appears before the first comment in the discussion (so just below the topic start-comment). But i get stuck on it and i need some help with it:

///////////////////////////////in development /////////////////////////////
  public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { //this place is between topic start and first comment

    //$Permalink = '/discussion/comment/'.$Comment->CommentID.'/#Comment_'.$Comment->CommentID;
    $Permalink = GetValue('Url', $Comment, '/discussion/comment/'.$Comment->CommentID.'/#Comment_'.$Comment->CommentID);
    if ('class' => "Hijack img-swap on") { // if the green V is hit
      echo Anchor(T('Linktext'), $Permalink, 'Permalink', array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow')); // echo this anchor to the top of the discussion
    }

  }

  ////////////////////////////////////////////////////////////

Comments

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    As far as I understand this, the info which comment is marked is only stored in the specific comment, correct? If that's so, you would have to loop through all comments in order to find out the correct link.

    I would recommend that you store the information about the "MarkV.CommentID" in the discussions attributes. There are some methods for that in the model: http://vanillaforums.org/discussion/comment/233096/#Comment_233096

    I think you should use public function saveToSerializedColumn($Column, $RowID, $Name, $Value = '') like that:

    // Use this somewhere in the method that you store the MarkV in the comment
    $DiscussionModel = new DiscussionModel();
    $DiscussionModel->SaveToSerializedColumn(
        'Attributes',
        $DiscussionID,
        'MarkV.CommentID',
        $CommentID
    );
    

    In DiscussionController_AfterDiscussion_Handler you should be able to access this info with $CommentID = $Discussion->Attributes['MarkV.CommentID'], build a link based on that and display it.

    I'm not 100% sure about that $Discussion->Attributes['MarkV.CommentID'], but if you do a decho($Discussion->Attributes); it should become obvious on how to access that info.


    P.S.: don't you want to replace "V" with
    ✅ => ✅
    ✓ => ✓
    ✔ => ✔
    or even
    👌 => 👌
    💡 => 💡
    💋 => 💋

    Unicode is so cool! =)

  • Options
    jackmaessenjackmaessen ✭✭✭
    edited October 2015

    I now have this create and the link appears after a refresh when clicked on the V:
    I created a new public function:

    public function BestAnswerLink($Sender) {
         $Discussion = $Sender->EventArguments['Discussion'];
        $Comment = $Sender->EventArguments['Comment'];
        if ($Comment->MarkV) {
          ?>
          <li class="bestanswer">
        <?php
         echo Anchor('testlink', 'discussion/comment/' . $Comment->CommentID . '/#Comment_' . $Comment->CommentID, array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow'));
    
        ?>
          </li>
          <?php
          }
    
       }
    

    And now i add this function to the DiscussionController (BeforeCommentHeading):

    public function DiscussionController_BeforeCommentHeading_Handler($Sender) { //this place is between topic start and first comment
        $this->BestAnswerLink($Sender);
    }
    

    The problem: the link does not appear before the first comment (which should be because BeforeCommentHeading is that place)
    When i change it to: public function DiscussionController_BeforeCommentDisplay_Handler($Sender) {

    the testlink does appear but at the wrong place ofcourse.
    Don't know why public function DiscussionController_BeforeCommentHeading_Handler($Sender) { does not show the link

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    You could always test if your function is called by inserting something like decho(__LINE__);
    In this case I would assume it is not called because that is never used as an event: https://github.com/vanilla/vanilla/search?utf8=✓&amp;q=BeforeCommentHeading

    Try the plugin eventi to find out the events your can use. But don't use that plugin in production.

  • Options
    jackmaessenjackmaessen ✭✭✭
    edited October 2015

    Well, i tried to find out the fireEvent and i did compare it with Voting plugin.
    This is where the sorting tabs are echood in Voting:

            public function DiscussionController_BeforeCommentDisplay_Handler($Sender) {
                 $AnswerCount = $Sender->Discussion->CountComments;
                    $Type = GetValue('Type', $Sender->EventArguments, 'Comment');
                    if ($Type == 'Comment' && !GetValue('VoteHeaderWritten', $Sender) && $Sender->Offset==0) {
                    ?>
                    <li class="SortVotingReactions">
                        <div class="VotingSort">
                        <?php
                        echo
                            Wrap($AnswerCount.' '.Plural($AnswerCount, 'Comment', 'Comments'), 'strong');
                            echo '<br /> Sort by: '
                           .Anchor('Most Votes', Url(DiscussionUrl($Sender->Discussion).'?Sort=popular', TRUE), '', array('rel' => 'nofollow', 'class' => self::CommentSort() == 'popular' ? 'Active' : ''))
                           .' / '
                           .Anchor('Date', Url(DiscussionUrl($Sender->Discussion).'?Sort=date', TRUE), '', array('rel' => 'nofollow', 'class' => self::CommentSort() == 'date' ? 'Active' : ''));
                        ?>
                        </div>
                    </li>
                    <?php
                  $Sender->VoteHeaderWritten = TRUE;
                    }
                }
    

    In markV plugin i have this code:

    ///////////////////////////////in development /////////////////////////////
          public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { //this place is between topic start and first comment
    
            $Comment = $Sender->EventArguments['Comment'];
            if ($Comment->MarkV) {
    
            echo Anchor('TESTLINK', Url('discussion/comment/' . $Comment->CommentID . '/#Comment_' . $Comment->CommentID), array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow'));
    
            }
    
          }
    
      ////////////////////////////////////////////////////////////
    

    This is the result:

    You can see in both plugins, the code is in DiscussionController_BeforeCommentDisplay_Handler; but they appear in the Voting plugin on the correct place and in the MarkV plugin on the wrong plaace (above user icon)

    What am i doing wrong?

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    In such a case you should do two things:
    1. look at the code that fires the event in order to know what markup is expected and
    2. check the rendered html if the output has the desired markup

    Look at https://github.com/vanilla/vanilla/blob/release/2.1/applications/vanilla/views/discussion/helper_functions.php#L77-L78 and you will see that the next line after the event starts with a li tag so obviously this event is fired in an unordered list. Your output must be enclosed in li tags to generate valid html.

  • Options
    jackmaessenjackmaessen ✭✭✭
    edited October 2015

    I now get stuck on the markV condition.
    I show 3 situations what happens.
    See below:

    Snap1:

    • public function DiscussionController_CommentHeading_Handler($Sender) {
    • //if ($Comment->MarkV) { ..... //disabled

    Snap2:

    • public function DiscussionController_CommentHeading_Handler($Sender) {
    • if ($Comment->MarkV) { .... enabled

    Snap3:

    • public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { (instead of CommentHeading)
    • if ($Comment->MarkV) { .... enabled

    This is the code:

    ///////////////////////////////in development /////////////////////////////
       //public function DiscussionController_CommentHeading_Handler($Sender) {
      public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { 
    
            $Discussion = $Sender->EventArguments['Discussion'];
            $Comment = $Sender->EventArguments['Comment'];
    
                    if ($Comment->MarkV) {
        ?>
                    <li class="BestAnswerLink">
                   <div class="BestAnswer">
    
            <?php
              echo Anchor('TESTLINK', Url('discussion/comment/' . $Comment->CommentID . '/#Comment_' . $Comment->CommentID), array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow'));
        ?>
    
                   </div>
                </li>
            <?php
            } // endif (Comment->MarkV)
      }
    
      ////////////////////////////////////////////////////////////
    

    So the situation what happens:
    If i echo only TESTLINK without the condition if ($Comment->MarkV) { on line 8 above, the TESTLINK appears in CommentHeading area.
    If i put the TESTLINK echo in the condition, TESTLINK is gone in CommentHeading area.
    If i change public function DiscussionController_CommentHeading_Handler($Sender) { to public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { with the condition and clicked on 2 green V, the 2 TESTLINKS are visible but at the wrong place ofcourse.
    But these TESTLINKS should appear in CommentHeading ! Seems not possible? What am i doing wrong?

  • Options
    peregrineperegrine MVP
    edited October 2015

    not closely following, but if you can't get something positioned as you wish with one type of event, you can always choose a different event and position things.

    Perhaps pick a suitable event that displays the items correctly as far as visibility in all cases you need it and then use css positioning to move it to correct place.

    http://www.w3schools.com/css/css_positioning.asp

    I may not provide the completed solution you might desire, but I do try to provide honest suggestions to help you solve your issue.

  • Options

    @peregrine Yes that is also possible, i know. But i was wondering if this is not possible what i am trying to achieve or am i doing something wrong?

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    It mightbe possible, but I'm also unsure what you try to achieve...

    Generally:
    When something in a condition is not shown, although you expect it, the condition is not met ;)
    So if you would swear that a=b but the code in if ($a == $b) {...} is not executed, try a decho($a); decho($b);.
    If I stumble upon code that behaves not like I expect it, I add numerous decho(__LINE__); right before if conditions and loops and inside o them just to see what is really executed and what is not.
    Another thing you should do when you expect that there must be an output but you cannot see it: look at the html source. Because you might run into styling issues and therefore your output might be hidden.

    In your case:
    BeforeCommentDisplay is fired between comments. So semantically, I wouldn't add any comment related info there. You are right in the unordered list of all comments, so semantically whatever you put there has the character of a comment. I could not think of a anything to echo there. Instead of this, I would only use it to change one of the EventArguments, but that is not your intention here.

    Back to the problem:
    We haven't really understood what you want to do. You have said "This is what i am experimenting with so that the Link to the green V comment appears before the first comment in the discussion (so just below the topic start-comment)"
    Looking at it right now seems to explain why we cannot help you and you get surprised by the results of what you are doing.

    So what you think you are doing right now is: you loop through all comments and if there is a marked comment, you write some html with the help of any event at the top of the comment list, correct?

    What I know you are doing is that those events are called for every comment. So you are already in the loop of comments when the event is fired. If you want to show something right before the start of all comments you must find that event. The events you are trying are all fired inside of the WriteComment function. This function writes the markup for each single comment. So if you try to take influence on what is written before the very first one, this is not the right place to look.

    So if you look for the right place to echo markup you have to understand the structure of Vanilla. You have to inspect the view that Vanilla uses for rendering a discussion. Et voilà! Look at applications/vanilla/views/discussion. Okay here is more than one file. But what file is always the default file on the good old internet? The index file! So take a look at index.php and you'll find the html structure of a discussion.

    You can call AfterDiscussion to add info that is discussion related because it is called right before the <div class="MessageList Discussion"> closes.
    You can also use CommentHeading but looking at the code I'd say that you would have styling problems because that seems to be enclosed from paginating markup.

    So try DiscussionController_AfterDiscussion! And that is the place where you have to loop through all comments to find the one which MarkV == true.
    Better than looping through all comments would be store the MarkVCommentID in the discussion attributes, so that you directly access it.

  • Options
    jackmaessenjackmaessen ✭✭✭
    edited October 2015

    When something in a condition is not shown, although you expect it, the condition is not met

    You seem to be right @R_J
    I put an else in the loop (line 24 below)

     ///////////////////////////////in development /////////////////////////////
       public function DiscussionController_AfterDiscussion_Handler($Sender) {
      //public function DiscussionController_BeforeCommentDisplay_Handler($Sender) { 
    
            $Discussion = $Sender->EventArguments['Discussion'];
            $Comment = $Sender->EventArguments['Comment'];
    
                    if ($Comment->MarkV) {
    
        ?>
                    <li class="BestAnswerLink">
                   <div class="BestAnswer">
    
            <?php
    
              echo Anchor('TESTLINK', Url('discussion/comment/' . $Comment->CommentID . '/#Comment_' . $Comment->CommentID), array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow'));
        ?>
    
                   </div>
                </li>
            <?php
            }
            else {
              echo 'NOT MET CONDITION';
            }// endif (Comment->MarkV)
      }
    
      ////////////////////////////////////////////////////////////
    

    This is what happens when i use DiscussionController_BeforeCommentDisplay_Handler

    And this is what happens when i use DiscussionController_AfterDiscussion_Handler

    This behaviour explains to me that in BeforeCommentDisplay event he looks if MarkV is clicked and then shows the TESTLINK for that Comment ID (because it met the condition)
    In AfterDiscussion event he checks not on the Comment ID anymore and if only 1 markV is not clicked, then it does not met the condition anymore and the NOT MET CONDITION appears

Sign In or Register to comment.