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.

Menu Item disabled?

Jonathan WJonathan W Scranton, PA
edited April 2015 in Vanilla 2.0 - 2.8

So in my add-on, HideComments, I add a menu item that hides a specific comment in a discussion. I have some javascript that handles things when the comment is hidden so that the page doesn't need to be refreshed. It might not be the best, but it's a work in progress:

window.updateHidden = function() {
   var el = $(this);
   if (!el.hasClass('HiddenComment'))
      el = el.closest('.HiddenComment');
   el.addClass('HiddenCommentHide');
   var opt = $('a.Hide' + $(this).attr('id'));
   opt.text("Unhide Comment");
}

There's an identical one for updateShown, and both are called via this line in the PHP code:

$Sender->JsonTarget("#Comment_{$CommentID}", 'updateHidden', 'Callback');

Again, there's an identical request for updateShown in the corresponding part of that code.

My problem is that the menu item is being disabled, probably when the framework hijacks it and handles the request, but I cannot seem to re-enable it. I tried adding opt.prop("disabled", false) to my callback functions, but it doesn't do what I expected. I even tried to do opt.disabled = false as opt should point to the DOM element in question.

I'm fairly certain I am mishandling something here. If you're curious, my full code is on github: https://github.com/xorith/HideComments.git

I would appreciate any help :)

EDIT: I should also mention that the add-on seems to function properly here: http://forums.wurmly.com
I had installed a fresh Vanilla on my Koding.com VM to play around a bit and all I did was clone my plugin: http://xorith.koding.io/forums

EDIT: Removed a //@todo that I had already done, and may have been confusing :)

«1

Answers

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    Just from looking at the code above, you seem to be using js to addClass of HiddenComment.

    To reverse the process, you would need to removeClass HiddenComment.

  • Jonathan WJonathan W Scranton, PA

    HiddenComment is added when I handle displaying the comment. The javascript simply removes the class if it's hidden and someone clicks Unhdie, or adds the class if someone clicks Hide. I do that so the page doesn't have to refresh once the AJAX request is handled.

    My problem is when the menu item is clicked, something sets the disabled property on that item. I'm assuming it's from when the link is hijacked.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP
    edited April 2015

    On your test forum the process does not work at all to hide, and you get a status message that says "Your comment will now be shown" after I click "Hide Comment"
    After that the hide comment button becomes disabled , I must assume because it was already selected and the comment is supposed to be hidden , but it is not.

    You can't load js without reloading the page.

  • Jonathan WJonathan W Scranton, PA

    Just to clarify what I'm talking about:

    <a href="/forums/discussion/hidecomment/1/3" class="HideComment Hijack HideComment_3">Hide Comment</a>
    

    Becomes

    <a class="HideComment Hijack HideComment_3" disabled="disabled" href="/forums/discussion/hidecomment/1/3">Unhide Comment</a>
    

    And adding this to my callback functions

    opt.prop('disabled', false);
    // OR
    opt.disabled = false;
    

    Doesn't fix it

  • Jonathan WJonathan W Scranton, PA
    edited April 2015

    @vrijvlinder said:
    On your test forum the process does not work at all to hide, and you get a status message that says "Your comment will now be shown" after I click "Hide Comment"
    After that the hide comment button becomes disabled , I must assume because it was already selected and the comment is supposed to be hidden , but it is not.

    Which test forum? On xorith.koding.io/forums the feature works - the comment is hidden, and the preference for it is saved. Or are you hiding as a guest? That shouldn't even be possible. I have email verification off to make it easier to register test users.

    Edit: Ha! Okay, so the option is there for guests. It's not working because of how the code is written. Anyway, I'll squash that bug, but it's a different issue than my question above. Thank you for the assist on guests though. :)

  • vrijvlindervrijvlinder Papillon-Sauvage MVP
    edited April 2015

    Or are you hiding as a guest? That shouldn't even be possible.

    Yes that forum, The option to hide appears to guests and has the same malfunction you describe. The button becomes grey/disabled and you get a message on the bottom left that now the comment will be shown" ...

    I do not register on forums. People usually make a test account and give the login info. I am only reporting what I saw you can test it too just log out and see for yourself what it does.

  • Jonathan WJonathan W Scranton, PA

    Test account: user2
    Password: user2user

  • Jonathan WJonathan W Scranton, PA

    Guests having the Hide option has been fixed. Any other ideas on why the menu item remains "disabled"?

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    The disabled attribute can be set to keep a user from clicking on the button until some other condition has been met (like selecting a checkbox, etc.).

    if (condition1) {
        block of code to be executed if condition1 is true
    } else if (condition2) {
        block of code to be executed if the condition1 is false and condition2 is true
    } else {
        block of code to be executed if the condition1 is false and condition2 is false
    }
    

    Then, a JavaScript could remove the disabled value, and make the button usable.

    You likely are missing that in between step so the button stays disabled because there is no other condition to meet.

  • Jonathan WJonathan W Scranton, PA

    @vrijvlinder said:
    The disabled attribute can be set to keep a user from clicking on the button until some other condition has been met (like selecting a checkbox, etc.).

    if (condition1) {
        block of code to be executed if condition1 is true
    } else if (condition2) {
        block of code to be executed if the condition1 is false and condition2 is true
    } else {
        block of code to be executed if the condition1 is false and condition2 is false
    }
    

    Then, a JavaScript could remove the disabled value, and make the button usable.

    You likely are missing that in between step so the button stays disabled because there is no other condition to meet.

    The step I'm missing is where it's even being disabled. :)

    I'm not doing it in my own code - it's being done somewhere else in the framework, I assume it happens when the framework hijacks the link (via the Hijack class). I've already tried to remove the disabled property via my callback functions in Javascript as I showed in my original post - that did not work.

    I think there's a step I'm missing in the way I'm using the Hijack class - perhaps some value that should be returned? Or is it because I'm using a callback function?

  • Jonathan WJonathan W Scranton, PA

    Well I'm very sure something is staring me in the face now.

    In global.js:

          $.ajax({
             type: "POST",
             url: href,
             data: { DeliveryType: 'VIEW', DeliveryMethod: 'JSON', TransientKey: gdn.definition('TransientKey') },
             dataType: 'json',
             complete: function() {
                gdn.enable(this);
                $elem.removeClass(progressClass);
                $elem.attr('href', href);
    
                // If we are in a flyout, close it.
                $flyout.removeClass('Open').find('.Flyout').hide();
             },
             error: function(xhr) {
                gdn.informError(xhr);
             },
             success: function(json) {
                if (json == null) json = {};
    
                var informed = gdn.inform(json);
                gdn.processTargets(json.Targets, $elem, $parent);
                // If there is a redirect url, go to it.
                if (json.RedirectUrl) {
                   setTimeout(function() {
                         window.location.replace(json.RedirectUrl);
                      },
                      informed ? 3000 : 0);
                }
             }
    

    complete is supposed to re-enable the element if I'm reading this right, and that's called right after either an error or success status.

    I must not be generating either status with my JSON response?

    {"Targets":[{"Target":"#Comment_2","Data":"HiddenComment","Type":"RemoveClass"},{"Target":"#Comment_2","Data":"updateShown","Type":"Callback"}],"FormSaved":true,"DeliveryType":"VIEW","Data":"","InformMessages":[{"CssClass":"Dismissable AutoDismiss","Message":"The comment will now be shown."}],"ErrorMessages":"","RedirectUrl":""}
    

    Here's what generates that:

    $Sender->JsonTarget("#Comment_{$CommentID}", 'HiddenComment', 'AddClass'); // Add the class
    $Sender->JsonTarget("#Comment_{$CommentID}", 'updateHidden', 'Callback'); // Trigger updateHidden() from hidecomments.js to update live page status.
    // Further down...
    $Sender->InformMessage(T('The '.(($CommentID == NULL) ? "discussion" : "comment").' will now be hidden.'));
    // Then finally, render
    $Sender->Render('Blank', 'Utility', 'Dashboard');
    
  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    I decided to test this idea using a quick jquery script into my master to see if this could be done without needing to hijack the options menu. Something I prefer doing . Maybe because I like buttons...

    <script>
    $(document).ready(function(){
        $("li.ItemComment").prepend('<button id="hide">Hide</button><button id="show">Show</button>');
        $("#hide").click(function(){
            $(".Comment").hide();
        });
        $("#show").click(function(){
            $(".Comment").show();
        });
    });
    </script>
    

    This simple script allows me to show and hide all the comments... obviously to be able to hide each one separately that is where the rest of your plugin comes in.

    Maybe try this approach.

  • Jonathan WJonathan W Scranton, PA

    @vrijvlinder - I thank you for your continued attempts at helping, but I think you're looking at the wrong issue. It's not so much hiding and unhiding comments in javascript as much as it is the way the framework handles Hijack links, and my own likely mishandling of that functionality.

    I apologize if I haven't been clear on this. :)

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    Yes I am not helping too much :(

    Not sure if this matters but it may in any case I think this is the correct way because the names of those php files are in small caps.

    $Sender->Render('blank','utility','dashboard');

  • Jonathan WJonathan W Scranton, PA

    I made that change, but it didn't do anything different. It feels as if I must somehow send a success status - but I don't know how to do this within the framework.

    $Sender->setJson('Status','success'); -- didn't do it

  • Jonathan WJonathan W Scranton, PA

    So, to continue with my debugging...

          gdn.disable(this, progressClass);
    

    That is line# 670 of global.js - at that time, this refers to the DOM element in the menu that was clicked.

    Later down, the AJAX is handled and you have

             complete: function() {
                gdn.enable(this);
                $elem.removeClass(progressClass);
                $elem.attr('href', href);
    
                // If we are in a flyout, close it.
                $flyout.removeClass('Open').find('.Flyout').hide();
             },
    

    If you notice, there's a gdn.enable(this); - But at this point during the script's execution, this does not reference the DOM object. I used breakpoints in Chrome to examine the scope variables to figure this out. I'm not saying it's an issue with global.js, because I'm only one person having this issue. Could it be due to my use of callbacks? Does that change things? Someone had mentioned that they hadn't seen them used before, but knew the support was available. Perhaps I'm not using them right?

  • Jonathan WJonathan W Scranton, PA

    Well, after making the above post, I noticed that the rest of the function uses $elem instead of this to handle the element. I changed my version of global.js to use $elem and it now functions as expected. I'm still not sure why this worked as expected on my live forums and not the test ones I set up via a git clone, but anyway...

    Now my question is - is this something wrong with the core? It seems to me that the complete function should make use of the same variable throughout. If so, I can make a pull request with the change. If not, then could someone please let me know how to make this work without changing global.js?

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    for a success status you would use

    $Sender->SetJson('Status',200);

  • Jonathan WJonathan W Scranton, PA

    Yeah, my issue isn't that - using debugging I found I'm entering the right portion of code. It's the use of this instead of $elem that was causing me issues. I'm more curious why.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    Maybe because it creates a dependency on an implementation of EventHandler that is not immediately obvious and that would be difficult to extend or replace.

Sign In or Register to comment.