views:

120

answers:

2

Hi all:

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  A: 

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.

mario
@mario : 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!
Michael Mao
+1  A: 

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

ShinTakezou
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)
ShinTakezou
hm, I am a little bit sloppy, now I've seen what the intended result should be; working on a new code...
ShinTakezou
@ShinTakezou : Thanks for the code and your update. I just got home from work and now I am also working on this :)
Michael Mao
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...
ShinTakezou
@ShinTakezou : 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 :( )
Michael Mao