3

I am working on a front-end web app where a nested unordered list would be used for the jQuery plugin mcdropdown.

Here is the data structure from PHP: a nested array of arrays :

Array
(
    [0] => Array
        (
            [fullpath] => ../foil/alphanumeric/
            [depth] => 0
        )

    [1] => Array
        (
            [fullpath] => ../foil/alphanumeric/letters/
            [depth] => 1
        )

    [2] => Array
        (
            [fullpath] => ../foil/alphanumeric/numbers/
            [depth] => 1
        )

    [3] => Array
        (
            [fullpath] => ../foil/alphanumeric/numbers/symbols/
            [depth] => 2
        )
)

Basically, I took the excellent answer from this question on SO, modified it a bit :

global $fullpaths; // $fullpaths contains the above data structure in print_r
$result = '';
$currentDepth = -1;

while(!empty($fullpaths))
{
    $currentNode = array_shift($fullpaths);

    if($currentNode['depth'] > $currentDepth)
    {
        $result .='<ul>';
    }

    if($currentNode['depth'] < $currentDepth)
    {
        $result .=str_repeat('</ul>', $currentDepth - $currentNode['depth']);
    }

    $result .= '<li>'. $currentNode['fullpath'] .'</li>';

    $currentDepth = $currentNode['depth'];

    if(empty($fullpaths))
    {
        $result .= str_repeat('</ul>', 1 + $currentDepth);
    }
}

print $result;

and got the following output:

<ul>
    <li>../foil/alphanumeric/</li>
    <ul>
        <li>../foil/alphanumeric/letters/</li>
        <li>../foil/alphanumeric/numbers/</li>
        <ul>
            <li>../foil/alphanumeric/numbers/symbols/</li>
        </ul>
    </ul>
</ul>

Which cannot be accepted by the mcdropdown jQuery plugin, it expects something like this:

<li rel="1">
'Alphanumeric'
    <ul>
        <li rel="2">'Letters'</li>
        <li rel="3">'Numbers'
            <ul>
                <li rel="4">'Symbols'</li>
            </ul>
        </li>
    </ul>
</li>

To be frank, I don't quite understand how the answer from that question works, I have been trying to modify that solution to cope with my situation, but still failed.

Any help and suggestion is much appropriated in advance.

2 Answers 2

2

If you already have the correct depth values, then you don't need recursion. I have a similar function that I use for <ul>-<li>-generation:

function ulli($newlevel, &$level, $UL="ul", $once=1) {

  if ($level == $newlevel) {
     echo "</li>\n";
  }

  while ($level<$newlevel) {
     $level++;
     echo "\n  <$UL>\n";
  }

  while ($level>$newlevel) {
     if ($once-->0) { echo "</li>\n"; } 
     $level--;
     echo "  </$UL>"
     . ($level>0 ? "</li>" : "") . "\n";  // skip for final </ul> (level=0)
  }
}

It needs a current $level variable for reference (=$currentDepth). And you pass it your depth as $newlevel. It however needs the first depth to be 1.

Basic usage is like:

$currentDepth=0;
foreach ($array as $_) {
   ulli($_["depth"]+1, $currentDepth);
   echo "<li>$_[path]";
}
ulli(0, $currentDepth);

Well, quirky. But it worked for me.

Sign up to request clarification or add additional context in comments.

1 Comment

and it works for me as well:) I will do a bit modification and I believe the mcdropdown jQuery plugin can work well with the output then. Thanks a lot!
2

Does this code (indentation apart) produces the result you want?

$d = array(
  0 => array(
    'fullpath' => '../foil/alphanumeric/',
    'depth' => 0
    ),

  1 => array(
    'fullpath' => '../foil/alphanumeric/letters/',
    'depth' => 1
    ),

  2 => array(
    'fullpath' => '../foil/alphanumeric/numbers/',
    'depth' => 1
    ),

  3 => array(
    'fullpath' => '../foil/alphanumeric/numbers/symbols/',
    'depth' => 2
    )
  );

echo "<ul>\n";
$cdepth = 0; $rel = 1; $first = true; $veryfirst = true;
foreach($d as $e)
{
  $mpath = "'" . ucfirst(basename($e['fullpath'])) ."'";
  if ( $e['depth'] == $cdepth ) {
    if ( $first && !$veryfirst) { echo "</li>\n";}
    echo "<li rel=\"$rel\">", $mpath;
    $rel++; $first = false; $veryfirst = false;
  } else {
    $depthdiff = $e['depth'] - $cdepth;
    if ( $depthdiff < 0 ) {
      for($i = 0; $i < -$depthdiff; $i++) {
    echo "</ul>\n</li>\n";
      }
    } else {
      for($i = 0; $i < $depthdiff; $i++) {
    echo "\n<ul>\n";
    $first = true;
        // indeed buggy if $depthdiff > 1...
      }
    }
    echo "<li rel=\"$rel\">", $mpath, "\n";
    $rel++; $first = true;
  }
  $cdepth = $e['depth'];
}
for($i = 0; $i < $cdepth; $i++) {
  echo "</ul>\n</li>\n";
}
echo "</ul>\n";

EDITED code: Still not perfect but you can work on it... :D

5 Comments

I have made that so every change in depth produce another li; if instead the new ul coming from changing the level must be part of the prev li, you have to modify a bit the code. I have not tested it in every circumstances (just quick coding)
hm, I am a little bit sloppy, now I've seen what the intended result should be; working on a new code...
Thanks for the code and your update. I just got home from work and now I am also working on this :)
hope you can extract something useful; the code is really imperfect even though it reproduces more or less the working output you've given; i am noting just now that i've added $veryfirst but it should be redundant...
yeah I can see the logic now. But It is the business people that actually populates the array, so I will check it tomorrow and see how it goes with the actual data (secret : they might not even be ready for my code yet :( )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.