Function: go to previous sibling (skip children)

Matt
Joined: 14 Nov 2009

Function: go to previous sibling (skip children)

Posted:25 Aug 2010 (05:34 UTC)
Hi, all. I'm trying to build Wiki Structure navigation that only moves to the previous or the next SIBLING (i.e. children are skipped).

Next was easy. Deleted a part of the original function.

Previous: FAIL - I don't understand how it works. I will try to understand, but would any of you devs maybe help me rewrite this below, so that the getPrevSiblingNode() will return the previous sibling, NOT the last child of the previous sibling?

This below is an exception from LibertyStructure.php (this is a copy of the original getPrevStructureNode(), just renamed)


function getPrevSiblingNode($structure_id, $deep = false) {
//Drill down to last child for this tree node
if ($deep) {
$query = "select `structure_id` ";
$query .= "from `".BIT_DB_PREFIX."liberty_structures` ls ";
$query .= "where `parent_id`=? ";
$query .= "order by ".$this->mDb->convertSortmode("pos_desc");
$result = $this->mDb->query($query,array($structure_id));

if ($result->numRows()) {
//There are more children
$res = $result->fetchRow();
$structure_id = $this->getPrevSiblingNode($res"structure_id", true);
}
return $structure_id;
}
// Try to get the previous page with the same parent as this
$page_info = $this->getNode($structure_id);
$parent_id = $page_info"parent_id";
$pos = $page_info"pos";

//At the top of the tree
if (!isset($parent_id))
return null;

$query = "select `structure_id` ";
$query .= "from `".BIT_DB_PREFIX."liberty_structures` ls ";
$query .= "where `parent_id`=? and `pos`<? ";
$query .= "order by ".$this->mDb->convertSortmode("pos_desc");
$result = $this->mDb->query($query,array((int)$parent_id, (int)$pos));

if ($result->numRows()) {
//There is a previous sibling
$res = $result->fetchRow();
$structure_id = $this->getPrevSiblingNode($res"structure_id", true);
}
else {
//No previous siblings, just the parent
$structure_id = $parent_id;
}
return $structure_id;
}


HELP.
spiderr
Profile Picture
Joined: 08 Feb 2004

Re: Function: go to previous sibling (skip children)

Posted:26 Aug 2010 (01:46 UTC)
HI Matt,

Ugh. Structures is ugly and what you are asking for is pretty sophisticated in terms of tree traversal.

You might want to create a function that *only* goes to a certain depth. Then it's more simple to get your previous sibling.

The latest 2.8 code passes the depth while building the trees.
Matt
Joined: 14 Nov 2009

Re: Function: go to previous sibling (skip children)

Posted:26 Aug 2010 (16:44 UTC)
I appreciate the response, spiderr. I understand your time constraints as a dev.

The same-level navigation is an extremely important feature on the site I'm working on. It has an educational edge and a user must be able to stay on the same difficulty level unless he/she will decide to go in-depth.

I'm *seriously* interested in a solution.

Would you recommend me to upgrade to 2.7 or wait 'till 2.8? I've been templating/styling this site for 5-6 months in my spare time, but I'm still on 2.1 on my localhost.

Or should I pay someone to do that code for me? I don't know PHP at all.

Thanks!
Matt
Joined: 14 Nov 2009

Re: Function: go to previous sibling (skip children)

Posted:26 Aug 2010 (16:50 UTC)
on a side note: if I talk to someone about that, is it correct to suggest that the function should get an array of structure_id's that have the same parent and return the one with first smaller pos?

I haven't the time to look at the database structure since I posted this so maybe the question is silly.
Matt
Joined: 14 Nov 2009

Re: Function: go to previous sibling (skip children)

Posted:28 Aug 2010 (02:48 UTC)
OK problem solved. Rare influx of reason @11pm: just sort it backwards.

Summary: The only difference between the getNextSiblingNode and getPrevSiblingNode functions is sorting arrays in different order and picking different position after or before ('>?' or '<?').
These functions do NOT return a parent if nothing else is found, because their only purpose is to navigate at the same level. In order to navigate to a parent level, you must add another "up" link in your Smarty code, and use sub-structure "in-depth" links to the children (these links don't require extra PHP code, they work similar to TOC sub-structure links in WikiBooks)
So newcomers please NOTE that this is not meant to replace the default navigation.

All changes made in the LibertyStructure.php file.

loadNavigation function - Add new code
function loadNavigation() {
if( $this->isValid() ) {
$this->mInfo"prev" = null;
// Get structure info for this page
if( !$this->isRootNode() && ($prev_structure_id = $this->getPrevStructureNode( $this->mStructureId )) ) {
$this->mInfo"prev" = $this->getNode($prev_structure_id);
}
$next_structure_id = $this->getNextStructureNode( $this->mStructureId );
$this->mInfo"next" = null;
if (isset($next_structure_id)) {
$this->mInfo"next" = $this->getNode( $next_structure_id) ;
}
// MY SIBLING CODE STARTS HERE
$this->mInfo"prevsibling" = null;
if( !$this->isRootNode() && ($prev_sibling_id = $this->getPrevSiblingNode( $this->mStructureId )) ) {
$this->mInfo"prevsibling" = $this->getNode($prev_sibling_id);
}
$next_sibling_id = $this->getNextSiblingNode( $this->mStructureId );
$this->mInfo"nextsibling" = null;
if (isset($next_sibling_id)) {
$this->mInfo"nextsibling" = $this->getNode( $next_sibling_id) ;
}
// MY SIBLING CODE ENDS HERE

$this->mInfo"parent" = $this->getStructureParentInfo( $this->mStructureId );
$this->mInfo"home" = $this->getNode( $this->mStructureId );
}
return TRUE;
}

function loadPath() {
if( $this->isValid() ) {
$this->mInfostructure_path>'structure_path' = $this->getPath( $this->mStructureId );
}
return( !empty( $this->mInfostructure_path>'structure_path' ) );
}


Add these two functions somewhere at the bottom of your file
function getNextSiblingNode($structure_id) {
$page_info = $this->getNode($structure_id);
$parent_id = $page_info"parent_id";
$page_pos = $page_info"pos";

if (!$parent_id)
return null;

$query = "SELECT `structure_id`
FROM `".BIT_DB_PREFIX."liberty_structures` ls
WHERE `parent_id`=? and `pos`>?
ORDER BY ".$this->mDb->convertSortmode("pos_asc");
$result2 = $this->mDb->query($query,array((int)$parent_id, (int)$page_pos));

if ($result2->numRows()) {
$res = $result2->fetchRow();
return $res"structure_id";
}
}

function getPrevSiblingNode($structure_id) {
$page_info = $this->getNode($structure_id);
$parent_id = $page_info"parent_id";
$page_pos = $page_info"pos";

if (!$parent_id)
return null;

$query = "SELECT `structure_id`
FROM `".BIT_DB_PREFIX."liberty_structures` ls
WHERE `parent_id`=? and `pos`<?
ORDER BY ".$this->mDb->convertSortmode("pos_desc");
$result2 = $this->mDb->query($query,array((int)$parent_id, (int)$page_pos));

if ($result2->numRows()) {
$res = $result2->fetchRow();
return $res"structure_id";
}
}

Now, in your Smarty template, you use the output like this:
{$structureInfo.prevsibling.structure_id} and {$structureInfo.prevsibling.title|escape}

and this:
{$structureInfo.nextsibling.structure_id} and {$structureInfo.nextsibling.title|escape}

See the conditional code of the default functions and use these in a similar context.

I tested this with a four-level structure and it worked.
HTH