Help extending custom drag-drop page ordering on admin page list screen

Not really an answer, but perhaps the answer lies within this somewhere. I unpacked the navmenu js script, and stripped out what appeared to be the code which makes the drag/drop sortable nested nav items possible. It’s not pretty.

I don’t think jQuery UI’s dragable/sortable modules support nesting elements, and that’s most likely the thing that will make or break whether you make it work that way. The navmenu script has a rather indepth and hard to decipher set of objects and functions that are used to calculate the inner and outer width, or depth’s. I would try to figure it out, but I have my own issue with my ajax post attachments uploading dynamic metabox plugin and making that work correctly still.

Maybe looking at this though will give you some insight to what you need to do in your code, if you are even able to using jqUI.

Here’s the entire nav-menu.js file unpacked, https://gist.github.com/820633
There are pieces you may need to see which tie this stuff together in order to make sense of it, which I didn’t include.

depthToPx: function (c) {
    return c * a.options.menuItemDepthPerLevel
},
pxToDepth: function (c) {
    return Math.floor(c / a.options.menuItemDepthPerLevel)
}

menuItemDepth: function () {
    var c = a.isRTL ? this.eq(0).css("margin-right") : this.eq(0).css("margin-left");
    return a.pxToDepth(c && -1 != c.indexOf("px") ? c.slice(0, -2) : 0)
},
updateDepthClass: function (d, c) {
    return this.each(function () {
        var e = b(this);
        c = c || e.menuItemDepth();
        b(this).removeClass("menu-item-depth-" + c).addClass("menu-item-depth-" + d)
    })
},
shiftDepthClass: function (c) {
    return this.each(function () {
        var d = b(this),
            e = d.menuItemDepth();
        b(this).removeClass("menu-item-depth-" + e).addClass("menu-item-depth-" + (e + c))
    })
},
childMenuItems: function () {
    var c = b();
    this.each(function () {
        var d = b(this),
            f = d.menuItemDepth(),
            e = d.next();
        while (e.length && e.menuItemDepth() > f) {
            c = c.add(e);
            e = e.next()
        }
    });
    return c
},
updateParentMenuItemDBId: function () {
    return this.each(function () {
        var e = b(this),
            c = e.find(".menu-item-data-parent-id"),
            f = e.menuItemDepth(),
            d = e.prev();
        if (f == 0) {
            c.val(0)
        } else {
            while (!d[0] || !d[0].className || -1 == d[0].className.indexOf("menu-item") || (d.menuItemDepth() != f - 1)) {
                d = d.prev()
            }
            c.val(d.find(".menu-item-data-db-id").val())
        }
    })
}

This is the sortables init method, which does some crazy algebraic E=Mc2 looking stuff lol

initSortables: function () {
    var p = 0,
        e, t, d, l, o, f, c, i, s, m = a.menuList.offset().left,
        h = b("body"),
        q, n = r();
    m += a.isRTL ? a.menuList.width() : 0;
    a.menuList.sortable({
        handle: ".menu-item-handle",
        placeholder: "sortable-placeholder",
        start: function (A, z) {
            var u, x, w, v, y;
            if (a.isRTL) {
                z.item[0].style.right = "auto"
            }
            s = z.item.children(".menu-item-transport");
            e = z.item.menuItemDepth();
            j(z, e);
            w = (z.item.next()[0] == z.placeholder[0]) ? z.item.next() : z.item;
            v = w.childMenuItems();
            s.append(v);
            u = s.outerHeight();
            u += (u > 0) ? (z.placeholder.css("margin-top").slice(0, -2) * 1) : 0;
            u += z.helper.outerHeight();
            i = u;
            u -= 2;
            z.placeholder.height(u);
            q = e;
            v.each(function () {
                var B = b(this).menuItemDepth();
                q = (B > q) ? B : q
            });
            x = z.helper.find(".menu-item-handle").outerWidth();
            x += a.depthToPx(q - e);
            x -= 2;
            z.placeholder.width(x);
            y = z.placeholder.next();
            y.css("margin-top", i + "px");
            z.placeholder.detach();
            b(this).sortable("refresh");
            z.item.after(z.placeholder);
            y.css("margin-top", 0);
            k(z)
        },
        stop: function (x, w) {
            var v, u = p - e;
            v = s.children().insertAfter(w.item);
            if (u != 0) {
                w.item.updateDepthClass(p);
                v.shiftDepthClass(u);
                g(u)
            }
            a.registerChange();
            w.item.updateParentMenuItemDBId();
            w.item[0].style.top = 0;
            if (a.isRTL) {
                w.item[0].style.left = "auto";
                w.item[0].style.right = 0
            }
            a.refreshMenuTabs(true)
        },
        change: function (v, u) {
            if (!u.placeholder.parent().hasClass("menu")) {
                (l.length) ? l.after(u.placeholder) : a.menuList.prepend(u.placeholder)
            }
            k(u)
        },
        sort: function (w, v) {
            var y = v.helper.offset(),
                u = a.isRTL ? y.left + v.helper.width() : y.left,
                x = a.negateIfRTL * a.pxToDepth(u - m);
            if (x > d || y.top < f) {
                x = d
            } else {
                if (x < t) {
                    x = t
                }
            }
            if (x != p) {
                j(v, x)
            }
            if (c && y.top + i > c) {
                o.after(v.placeholder);
                k(v);
                b(this).sortable("refreshPositions")
            }
        }
    });

    function k(u) {
        var v;
        l = u.placeholder.prev();
        o = u.placeholder.next();
        if (l[0] == u.item[0]) {
            l = l.prev()
        }
        if (o[0] == u.item[0]) {
            o = o.next()
        }
        f = (l.length) ? l.offset().top + l.height() : 0;
        c = (o.length) ? o.offset().top + o.height() / 3 : 0;
        t = (o.length) ? o.menuItemDepth() : 0;
        if (l.length) {
            d = ((v = l.menuItemDepth() + 1) > a.options.globalMaxDepth) ? a.options.globalMaxDepth : v
        } else {
            d = 0
        }
    }
    function j(u, v) {
        u.placeholder.updateDepthClass(v, p);
        p = v
    }
    function r() {
        if (!h[0].className) {
            return 0
        }
        var u = h[0].className.match(/menu-max-depth-(\d+)/);
        return u && u[1] ? parseInt(u[1]) : 0
    }
    function g(u) {
        var v, w = n;
        if (u === 0) {
            return
        } else {
            if (u > 0) {
                v = q + u;
                if (v > n) {
                    w = v
                }
            } else {
                if (u < 0 && q == n) {
                    while (!b(".menu-item-depth-" + w, a.menuList).length && w > 0) {
                        w--
                    }
                }
            }
        }
        h.removeClass("menu-max-depth-" + n).addClass("menu-max-depth-" + w);
        n = w
    }
}

Would be nice if they had a dev version of this file, like they do with other scripts in WP. The minified single letter vars are too much to handle for me right now.
It’s just Alphabet soup.

tech