Search code examples
javascriptjquerysortinggreasemonkeyuserscripts

How can I use Greasemonkey to reorganize a <ul> list?


I tried to adapt someone's script from a Stack Overflow post, but I did something wrong. I've got essentially no experience with javascript or jQuery, so... Please help?


The target-page HTML looks like this:

<div class="container7">
    <div class="userdata">
        <h4></h4>
        <ul id="userinfo" class="set textsize">
            <li class="name"></li>
            <li class="joindate"></li>
            <li class="title"></li>
            <li class="custom"></li>
            <li class="description"></li>
        </ul>
    </div>
</div>

I want to modify it to look like this:

<div class="container7">
    <div class="userdata">
        <h4></h4>
        <ul id="userinfo" class="set textsize">
            <li class="joindate"></li>
            <li class="name"></li>
            <li class="custom"></li>
            <li class="description"></li>
            <li class="title"></li>
        </ul>
    </div>
</div>


I tried this:

// ==UserScript==
// @name        Reorganize li
// @namespace   blah
// @description Reorganize li
// @include     https://www.thewebsite.com/*
// @version     1
// @grant       none
// ==/UserScript==

var container    = document.querySelector (".userdata");
var firstTargDiv = container.querySelector (".userdata > li.name:first-child");
var lastTargDiv  = container.querySelector (".userdata > li.joindate:last-child");

//-- Swap last to first.
container.insertBefore (lastTargDiv, firstTargDiv);

//-- Move old first to last.
container.appendChild (firstTargDiv);

As a start -- just flipping the first two. It didn't work. I wasn't sure what I had done wrong. I've tried testing different querySelector values, but nothing seems to work.


Solution

  • That code would work (sort of) except that the CSS selectors, passed to querySelector, were off. For the HTML you gave, they should be:

    var container    = document .querySelector ("div.userdata > ul");
    var firstTargDiv = container.querySelector ("li.name");
    var lastTargDiv  = container.querySelector ("li.joindate");
    

    Also, the <li>s would not have ended up quite where you wanted.


    To sort a uniform collection of nodes just append them to the container in the order you want them. Appending existing nodes just moves the nodes.

    If your list of nodes (the <li>s in this case) each have a unique identifier or contained text, use an array to define an arbitrary sort order.
    In this case, each <li> has a unique CSS class so we'll define the sort order like so:

    var classOrder = ["joindate", "name", "custom", "description", "title"];
    

    We can then use this array to snag each <li> by class and append it in the desired order.

    Using jQuery, your complete userscript would become:

    // ==UserScript==
    // @name     Reorganize li
    // @include  https://www.thewebsite.com/*
    // @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
    // @grant    GM_addStyle
    // ==/UserScript==
    /*- The @grant GM_addStyle directive is needed to work around a design 
        change introduced in GM 1.0.   It restores the sandbox.
    */
    var classOrder  = ["joindate", "name", "custom", "description", "title"];
    var containerNd = $("div.userdata > ul");
    
    for (var J = 0, L = classOrder.length;  J < L;  J++) {
        var targetNode  = containerNd.find ('li.' + classOrder[J]);
        containerNd.append (targetNode);
    }
    


    You can see the code in action at jsFiddle.