0

JSFiddle Demo

On my mail side nav I have a custom right-click hijack of which I have just made it so you can add a new sub-folder as partly seen below;

if ($(this).hasClass('NewSubFolder')) {
    if($('ul.inbox-nav li.Clicked').find('ul').length) {
        $('ul.inbox-nav li.Clicked > ul').prepend("<li class='NewSubFolder'><input type='text'></li>");
    } else {
        $('ul.inbox-nav li.Clicked').append('<ul><li class="NewSubFolder"><input type="text"></li></ul>');
    }
    $("ul.inbox-nav li.Clicked").removeClass('Clicked');
}

This will add another tier where there is not one to prepend where there is, an input field. Currently you have to hit the enter key after typing something for the new folder name and then it will have worked its magic...

...However this newly appended list item does not work when you right-click it.

  • use a delegated event handler on the parent `
      ` element that checks for ticks on an `li` (or `a`) element.
    – Jhecht May 18 '16 at 02:01
  • @Jhecht I'm new to delegated events, just tried `$('#MailMenuSecondTier li').on("click", "contextmenu", function() { {` of which broke my script. Could you please provide any more info? Thank you –  May 18 '16 at 02:19
  • @Jhecht I've just been looking into this and found this [answer](http://stackoverflow.com/a/8111171/2199267) useful however this is on click of an element outside of where the content is appended therefore I'm not sure if this is the right solution? –  May 18 '16 at 02:31
  • got your brackets/parenthesis mixed around Tim. – Jhecht May 18 '16 at 02:32
  • @Jhecht On my above link? I just edited that and never meant to add two `{` up there. I'm still working away trying to resolve however I only seem to be making things worse... –  May 18 '16 at 02:37
  • The problem comes from a chunk of your code. Odds are by the time I finish my answer someone will post basically the same code, but give me a second. I'm going to streamline the code and only have what is applicable to the situation. (there's some stuff with tables I can't figure out why it's there... probably used in your actual application?) – Jhecht May 18 '16 at 02:57
  • Yes, there is a line or two regarding a table, sorry about that! And thank you very much for your help :) –  May 18 '16 at 03:06
  • 1
    got something, adding comments to code – Jhecht May 18 '16 at 03:45

2 Answers2

0

Hopefully this gets what you need done.

Let me know if the comments are not clear enough.

EDIT

Made an edit to combine the two on(contextmenu) calls into one function. No need for redundancy.

$(document).ready(function() {

  // Trigger action when the contexmenu is about to be shown
  $('#inbox-nav').on("contextmenu", 'a', function(event) {

    event.preventDefault();
    $('.clicked').removeClass('clicked'); //Gets rid of all other clicked elements
    $(this).closest('li').addClass('clicked');
    //Clicks the closest li element
    var menu = ($(this).is('#inbox-nav>li>a')) ? 'MailMenuFirstTier' : 'MailMenuSecondTier';
    /*This is an inline if statement, read in words it goes like this:
      if this element is a direct level link, then we're going to need to use the first menu tier.
      else we're going to need use the second menu tier.
    */

    $("#" + menu).finish().show(100)
      //dynamically calls the menu we're using.
      .css({
        left: event.pageX,
        top: event.pageY
      }); //Moves the first mail menu to the event position

  });
  /*
    check the element to see which menut to show instead of using two different things.
  */
  $(document).on('mousedown', function(e) {
    //Mouse down events!
    if ($('.custom-menu').is(':visible') && !$(e.target).parent().hasClass('custom-menu')) {
      /*
      In English:
        if a custom menu is visible, AND the target of the click DOES NOT have the custom-menu class, hide the custom menu.
      */
      $('.custom-menu').finish().hide();
    }

    if ($(e.target).parent().hasClass('custom-menu')) {
      //Figure out what to do since your element is a child of the custom menu
      $('.custom-menu').finish().hide();

      var action = $(e.target).data('action');
      //Gets our action element
      var clicked = $('.clicked');
      //gets the clicked element we will be working on.
      switch (action) {
        case 'new-folder':
          //If the clicked element does not have a child ul element, add one.
          $('input.rename').focusout();
          //Any current input.renames will have their focus out method called
          if (clicked.children('ul').length == 0) {

            clicked.append($('<ul></ul>'))
          }
          var ul = clicked.children('ul');
          //Either this child element existed before or we just made it the step before. 
          var input = $('<input />', {
            type: 'text',
            value: 'New Sub Folder',
            class: 'rename',
            'data-start': 'New Sub Folder',
            focusout: function() {
              var value = ($(this).val() == '') ? $(this).data('start') : $(this).val();
              $(this).siblings('a').html(value).show();
              $(this).remove();
            },
            autofocus: true
          });
          //Creates an input tag of type text, with class rename, a placeholder value, and a focusout function.
          var anchor = $('<a>', {
            href: '#',
            css: {
              display: 'none'
            }
          });
          //Creates an anchor tag that is originally hidden
          ul.append($('<li>').append([input, anchor]));
          ul.find('input').click();
          //Adds the (should be selected) element and the anchor
          //The input element takes care of things from there

          break; // end new-folder case
        case 'rename-folder':
          $('input.rename').focusout();
          //any current input.rename items will have their focusout method called
          var anchor = clicked.find('a');
          //get our closest anchor of our clicked element
          anchor.before($('<input />', {
            type: 'text',
            value: anchor.html(),
            class: 'rename',
            'data-start': anchor.html(),
            focusout: function() {
              var value = ($(this).val() == '') ? $(this).data('start') : $(this).val();
              $(this).siblings('a').html(value).show();
              $(this).remove();
            },
            autofocus: true
          })).hide();

          //Creates an input element, adds it before the anchor element, 
          //hides anchor element. the newly created input element takes care of things from there
          break;
          /*
          ADD NEW ACTIONS HERE
          */
        default:
          return;
          break;
      }
    }
  }).on('keyup', 'input.rename', function(e) {
    //Used for laziness. If a user hits enter in the input.rename tag, we fire the focusout target
    e.preventDefault();
    if (e.keyCode == 13) {
      $(e.target).focusout();
    }
  });
});
.custom-menu {
  display: none;
  z-index: 1000;
  position: absolute;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
  border: 1px solid #CCC;
  white-space: nowrap;
  font-family: sans-serif;
  background: #FFF;
  color: #333;
  border-radius: 5px;
  font-size: 12px;
}
.custom-menu li {
  padding: 8px 12px;
  cursor: pointer;
}
.custom-menu li:hover {
  background-color: #DEF;
}
menu {
  position: absolute;
}
.custom-menu .divider {
  content: " ";
  height: 1px;
  margin: 4px 10px;
  background: #929292;
}
#MailBodyList.custom-menu li.Title {
  color: #929292;
}
#MailBodyList.custom-menu li.Title:hover {
  background: #FFF;
  cursor: default;
}
#MailBodyList.custom-menu li.ForThisSenderMore {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="inbox-nav" id="inbox-nav">
  <li class="active">
    <a href="javascript:;" data-type="inbox" data-title="Inbox">
      <div class="Arrow"></div>Inbox
    </a>
    <ul>
      <li><a href="javascript:;" data-type="inbox" data-title="Sub_1">Sub-Folder 1</a>
      </li>
      <li><a href="javascript:;" data-type="inbox" data-title="Sub_2">Sub-Folder 2</a>
      </li>
      <li>
        <a href="javascript:;" data-type="inbox" data-title="Sub_3">Sub-Folder 3</a>
        <ul>
          <li><a href="javascript:;" data-type="inbox" data-title="Sub_1">Sub-Folder 1</a>
          </li>
          <li><a href="javascript:;" data-type="inbox" data-title="Sub_2">Sub-Folder 2</a>
          </li>
        </ul>
      </li>
      <li><a href="javascript:;" data-type="inbox" data-title="Sub_4">Sub-Folder 4</a>
      </li>
      <li><a href="javascript:;" data-type="inbox" data-title="Sub_5">Sub-Folder 5</a>
      </li>
    </ul>
  </li>
  <li>
    <a href="javascript:;" data-type="important" data-title="Inbox"> Important </a>
  </li>
  <li>
    <a href="javascript:;" data-type="sent" data-title="Sent"> Sent </a>
  </li>
  <li>
    <a href="javascript:;" data-type="draft" data-title="Draft"> Draft
            <span class="badge badge-danger">8</span>
        </a>
  </li>
  <li>
    <a href="javascript:;" class="sbold uppercase" data-title="Trash"> Trash
            <span class="badge badge-info">23</span>
        </a>
  </li>
  <li>
    <a href="javascript:;" data-type="inbox" data-title="Promotions"> Promotions
            <span class="badge badge-warning">2</span>
        </a>
  </li>
  <li>
    <a href="javascript:;" data-type="inbox" data-title="News"> News </a>
  </li>
</ul>

<ul id="MailMenuFirstTier" class="custom-menu">
  <li>Mark All As Read</li>
  <li>Empty Folder</li>
</ul>

<ul class="custom-menu" id="MailMenuSecondTier">
  <li class="NewSubFolder" data-action="new-folder">New Sub-Folder</li>
  <li class="Rename" data-action="rename-folder">Rename</li>
  <li class="Delete" data-action="delete-folder">Delete</li>
  <li>Mark All As Read</li>
  <li>Empty Folder</li>
</ul>
Jhecht
  • 4,407
  • 1
  • 26
  • 44
  • I've noticed a couple of errors compared to my working [fiddle](https://jsfiddle.net/j9natngh/) other than the question. They lie around renaming and on input focusout. You can rename multiple at once and if li > ul the renaming input appears. Not sure if you can delete as I haven't included this additional code... Please give me some time to look through! –  May 18 '16 at 04:05
  • `Tried simply replacing my current script and nothing seems to work... Shmae my server is down! –  May 18 '16 at 04:09
  • Wow, this is a bit advanced for me... I cannot even find how you tell `
  • New Sub-Folder
  • ` to make a new tier... –  May 18 '16 at 05:08
  • it's in the `data-action` attribute, I gave it some readable but descriptive value ("new-folder"). Then in the mousedown function there is a line `var action = $(e.target).data('action');` and a switch statement after that. – Jhecht May 18 '16 at 05:12
  • I'm not sure how I managed to, pretty proud of myself, fixed all problems apart from one. All works on focus out as long as when the input appears it is already focused. See this [JSFiddle](https://jsfiddle.net/xnbfcfu4/) –  May 18 '16 at 08:34
  • 1
    Thank you for your help, you have inspired myself a lot and somewhat improved on my skills! The about is still a problem but not enough to leave this an unvalid answer! +1 too :) –  May 18 '16 at 09:21
  • Two problems really, one making sure the input field is not null or just contains white space and secondly autofocus on the input. When I do `var input = $('', {`, this doesn't work `value: 'testing'. Still cannot believe all this new stuff I've learned... Thank you :)` –  May 18 '16 at 22:51
  • I had issues with the autofocus as well but I noticed the same bug with your code. Just figured it was standard. – Jhecht May 18 '16 at 22:53
  • I've tried adding an if on focus out it if null then do nothing but for the other, can't there be added something on click outside of the input area the same actions happen as the on enter key press? –  May 18 '16 at 23:33
  • Can I possibly interest you in my other question prior needing to update with the new script and all the updating of my old script. [JQuery contextmenu show/hide problems](http://stackoverflow.com/q/37264095/2199267) –  May 19 '16 at 02:06
  • 1
    Cannot thank you enough for progressing my skills so rapidly, I've grasped this so well :) –  May 19 '16 at 02:30
  • Everybody starts somewhere. – Jhecht May 19 '16 at 02:34
  • Regarding a variable you yet, I've posted for more of an understanding here - [Understanding Setting JQuery Variables](http://stackoverflow.com/q/37336026/2199267) –  May 20 '16 at 00:13