Welcome Guest, Not a member yet? Register   Sign In
Parsing nested lists
#1

[eluser]slowgary[/eluser]
Hi all,

I'm new to OOPHP, MVC, and CI but I must say I'm loving the experience. CodeIgniter has made everything so easy that it just makes sense, even to someone like me that resisted the move to OO for such a long time.

I'm creating a lightweight CMS for the experience and I could really use the help of some of you seasoned veterans around this forum. My problem exists in my menu manager. It allows users to drag and drop elements of the navigation around to suit their needs (uses JavaScript), which works fine. The issue is in saving it back to the database.

The site navigation would be a CSS dropdown menu, database driven, organized into nested lists like so:
Code:
<ul>
     <li>link 1</li>
     <li>link 2</li>
     <li>link 3
          <ul>
               <li>link 4</li>
               <li>link 5</li>
               <li>link 6
                    <ul>
                         <li>link 7</li>
                    </ul>
               </li>
          </ul>
     </li>
</ul>

And the database table structure:
Code:
--------------------------------------
|  id   |   position   |   caption   |
--------------------------------------
|  1    |      1       |    link 1   |
|  2    |      2       |    link 2   |
|  3    |      3       |    link 3   |
|  4    |      3.1     |    link 4   |
|  5    |      3.2     |    link 5   |
|  6    |      3.3     |    link 6   |
|  7    |      3.3.1   |    link 7   |
--------------------------------------

I've already created the necessary functionality to generate the navigation from the above table, what I'm having problems with is creating a management tool. The JavaScript works great, but so far the best method I can come up with to save the changes to the database is to send an AJAX request with the markup from the reordered list, then use PHP to parse it and update the necessary rows. I don't know where to start in implementing this. I'll be able to AJAX the markup to a PHP script, so I'd have something like this:

Code:
$markup =
"<ul>
     <li>link 1</li>
     <li>link 2</li>
     <li>link 3
          <ul>
               <li>link 4</li>
               <li>link 5</li>
               <li>link 6
                    <ul>
                         <li>link 7</li>
                    </ul>
               </li>
          </ul>
     </li>
</ul>";

Parsing this HTML with PHP is where I get lost. If I can turn the nested lists into an associative array I can figure the rest out. Can you (yeah YOU) throw me a hint on how to do this? Or maybe I'm going about this whole thing the wrong way? I would so much appreciate your expertise.

You can check an example navigation here-> aaroncicali.com/pages/home

And the sweet drag & drop manager here-> aaroncicali.com/menu

Thank you for taking the time to read this, I appreciate any efforts you send my way.
#2

[eluser]TheFuzzy0ne[/eluser]
Perhaps MPTT is the solution for you.

http://en.wikipedia.org/wiki/Tree_traversal
http://ellislab.com/forums/viewthread/74114/

EDIT: Sorry, I just realised that this doesn't really help you achieve you're main objective.

What you'll need to do, is start with the parent UL, and create a function which returns an array (obviously). The function should iterate through each parent element, if it's a UL, the function should call itself, and append the returned array to the current array, using the current UL as the parent. I might see if I can get a working solution for you later, but it's 4:23AM, and my brain is not fully operational.
#3

[eluser]TheFuzzy0ne[/eluser]
It's been a while since I wrote any serious JavaScript, but this is my proposed JavaScript function.
Code:
function menu2array(parentNode) {
    var ret = Array();
    var cn;
    for (var i = 0; i < parentNode.childNodes.length; i++) {
        cn = parentNode.childNodes[i];
        if (cn.nodeName.toLowerCase() == 'li') {
            ret[ret.length] = cn.id;
            if (cn.childNodes[1] && cn.childNodes[1].nodeName.toLowerCase() == 'ul') {
               ret[ret.length] = menu2array(cn.childNodes[1]);
            }
        }
    }
    return ret;
}

It will probably need modifying, and can more than likely be cleaned up a bit, but it should work. Just pass it a reference to the parent UL, and grab the returned array. The code will build the array using the id of the LI nodes, so you should really print out your menu with the appropriate ids set. You can use numbers as ids, so I'd suggest something like, item_1, item_2, item_3 and so on. You can have your PHP code extract the actual id numbers at the server end.
#4

[eluser]slowgary[/eluser]
Much love TheFuzzyOne. Works like a charm, I just had to change the array indexes from 1 to 2, so:
Code:
if (cn.childNodes[2] && cn.childNodes[2].nodeName.toLowerCase() == 'ul') {
               ret[ret.length] = menu2array(cn.childNodes[2]);

Not quite sure why, apparently they don't start at zero? Anyways, it's perfect. Thank you very much! Love the LOLLERSKATES btw.
#5

[eluser]TheFuzzy0ne[/eluser]
JavaScript arrays do start at 0, however, spaces in your source code also show in the DOM, so chances are, with the way your source code was, cn.childNodes[1].nodeName was probably "#text" and not "UL". In order to remove spaces from the dom, you'd have to write your source code so it looks something like this:
Code:
<ul><li>link 1</li><li>link 2</li><li>link 3<ul><li>link 4</li><li>link 5</li><li>link 6<ul><li>link 7</li></ul></li></ul></li></ul>

It looks messy, but it's much easier to manipulate the DOM.

Glad you got it working. Not bad for 5:30 AM Tongue

It's 6:10 now, so I'm off to bed. G'nite!




Theme © iAndrew 2016 - Forum software by © MyBB