PageRenderTime 60ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/core/controllers/blocks/autonav.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 675 lines | 433 code | 84 blank | 158 comment | 190 complexity | aa0e3ae93176e23596c7249f2c970a7b MD5 | raw file
  1. <?php
  2. defined('C5_EXECUTE') or die("Access Denied.");
  3. /**
  4. * The controller for the Auto-Nav block.
  5. *
  6. * @package Blocks
  7. * @subpackage Auto-Nav
  8. * @author Andrew Embler <andrew@concrete5.org>
  9. * @author Jordan Lev
  10. * @copyright Copyright (c) 2003-2012 Concrete5. (http://www.concrete5.org)
  11. * @license http://www.concrete5.org/license/ MIT License
  12. *
  13. */
  14. class Concrete5_Controller_Block_Autonav extends BlockController {
  15. protected $btTable = 'btNavigation';
  16. protected $btInterfaceWidth = "500";
  17. protected $btInterfaceHeight = "350";
  18. protected $btCacheBlockRecord = true;
  19. protected $btCacheBlockOutput = true;
  20. protected $btCacheBlockOutputOnPost = true;
  21. protected $btCacheBlockOutputForRegisteredUsers = false;
  22. protected $btCacheBlockOutputLifetime = 300;
  23. protected $btWrapperClass = 'ccm-ui';
  24. protected $btExportPageColumns = array('displayPagesCID');
  25. public function getBlockTypeDescription() {
  26. return t("Creates navigation trees and sitemaps.");
  27. }
  28. public function getBlockTypeName() {
  29. return t("Auto-Nav");
  30. }
  31. public $navArray = array();
  32. public $cParentIDArray = array();
  33. public $sorted_array = array();
  34. public $navSort = array();
  35. public $navObjectNames = array();
  36. public $displayPages, $displayPagesCID, $displayPagesIncludeSelf, $displaySubPages, $displaySubPageLevels, $displaySubPageLevelsNum, $orderBy, $displayUnavailablePages;
  37. public $haveRetrievedSelf = false;
  38. public $haveRetrievedSelfPlus1 = false;
  39. public $displaySystemPages = false;
  40. // private variable $displayUnapproved, used by the dashboard
  41. public $displayUnapproved = false;
  42. // haveRetrievedSelf is a variable that stores whether or not a particular tree walking operation has retrieved the current page. We use this
  43. // with subpage modes like enough and enough_plus1
  44. // displayUnavailablePages allows us to decide whether this autonav block filters out unavailable pages (pages we can't see, are restricted, etc...)
  45. // or whether they display them, but then restrict them when the page is actually visited
  46. // TODO - Implement displayUnavailablePages in the btNavigation table, and in the frontend of the autonav block
  47. function __construct($obj = null) {
  48. if (is_object($obj)) {
  49. switch(strtolower(get_class($obj))) {
  50. case "blocktype":
  51. // instantiating autonav on a particular collection page, instead of adding
  52. // it through the block interface
  53. $this->bID = null;
  54. break;
  55. case "block": // block
  56. // standard block object
  57. $this->bID = $obj->bID;
  58. break;
  59. }
  60. }
  61. $c = Page::getCurrentPage();
  62. if (is_object($c)) {
  63. if ($c->getCollectionPointerOriginalID() > 0) {
  64. $this->cID = $c->getCollectionPointerOriginalID();
  65. } else {
  66. $this->cID = $c->getCollectionID();
  67. }
  68. $this->cParentID = $c->getCollectionParentID();
  69. }
  70. parent::__construct($obj);
  71. }
  72. function save($args) {
  73. $args['displayPagesIncludeSelf'] = $args['displayPagesIncludeSelf'] ? 1 : 0;
  74. $args['displayPagesCID'] = $args['displayPagesCID'] ? $args['displayPagesCID'] : 0;
  75. $args['displaySubPageLevelsNum'] = $args['displaySubPageLevelsNum'] > 0 ? $args['displaySubPageLevelsNum'] : 0;
  76. $args['displayUnavailablePages'] = $args['displayUnavailablePages'] ? 1 : 0;
  77. parent::save($args);
  78. }
  79. function getContent() {
  80. /* our templates expect a variable not an object */
  81. $con = array();
  82. foreach($this as $key => $value) {
  83. $con[$key] = $value;
  84. }
  85. return $con;
  86. }
  87. public function getChildPages($c) {
  88. // a quickie
  89. $db = Loader::db();
  90. $r = $db->query("select cID from Pages where cParentID = ? order by cDisplayOrder asc", array($c->getCollectionID()));
  91. $pages = array();
  92. while ($row = $r->fetchRow()) {
  93. $pages[] = Page::getByID($row['cID'], 'ACTIVE');
  94. }
  95. return $pages;
  96. }
  97. /**
  98. * This function is used by the getNavItems() method to generate the raw "pre-processed" nav items array.
  99. * It also must exist as a separate function to preserve backwards-compatibility with older autonav templates.
  100. * Warning: this function has side-effects -- if this gets called twice, items will be duplicated in the nav structure!
  101. */
  102. function generateNav() {
  103. if (isset($this->displayPagesCID) && !Loader::helper('validation/numbers')->integer($this->displayPagesCID)) {
  104. $this->displayPagesCID = 0;
  105. }
  106. $db = Loader::db();
  107. // now we proceed, with information obtained either from the database, or passed manually from
  108. $orderBy = "";
  109. /*switch($this->orderBy) {
  110. switch($this->orderBy) {
  111. case 'display_asc':
  112. $orderBy = "order by Collections.cDisplayOrder asc";
  113. break;
  114. case 'display_desc':
  115. $orderBy = "order by Collections.cDisplayOrder desc";
  116. break;
  117. case 'chrono_asc':
  118. $orderBy = "order by cvDatePublic asc";
  119. break;
  120. case 'chrono_desc':
  121. $orderBy = "order by cvDatePublic desc";
  122. break;
  123. case 'alpha_desc':
  124. $orderBy = "order by cvName desc";
  125. break;
  126. default:
  127. $orderBy = "order by cvName asc";
  128. break;
  129. }*/
  130. switch($this->orderBy) {
  131. case 'display_asc':
  132. $orderBy = "order by Pages.cDisplayOrder asc";
  133. break;
  134. case 'display_desc':
  135. $orderBy = "order by Pages.cDisplayOrder desc";
  136. break;
  137. default:
  138. $orderBy = '';
  139. break;
  140. }
  141. $level = 0;
  142. $cParentID = 0;
  143. switch($this->displayPages) {
  144. case 'current':
  145. $cParentID = $this->cParentID;
  146. if ($cParentID < 1) {
  147. $cParentID = 1;
  148. }
  149. break;
  150. case 'top':
  151. // top level actually has ID 1 as its parent, since the home page is effectively alone at the top
  152. $cParentID = 1;
  153. break;
  154. case 'above':
  155. $cParentID = $this->getParentParentID();
  156. break;
  157. case 'below':
  158. $cParentID = $this->cID;
  159. break;
  160. case 'second_level':
  161. $cParentID = $this->getParentAtLevel(2);
  162. break;
  163. case 'third_level':
  164. $cParentID = $this->getParentAtLevel(3);
  165. break;
  166. case 'custom':
  167. $cParentID = $this->displayPagesCID;
  168. break;
  169. default:
  170. $cParentID = 1;
  171. break;
  172. }
  173. if ($cParentID != null) {
  174. /*
  175. $displayHeadPage = false;
  176. if ($this->displayPagesIncludeSelf) {
  177. $q = "select Pages.cID from Pages where Pages.cID = '{$cParentID}' and cIsTemplate = 0";
  178. $r = $db->query($q);
  179. if ($r) {
  180. $row = $r->fetchRow();
  181. $displayHeadPage = true;
  182. if ($this->displayUnapproved) {
  183. $tc1 = Page::getByID($row['cID'], "RECENT");
  184. } else {
  185. $tc1 = Page::getByID($row['cID'], "ACTIVE");
  186. }
  187. $tc1v = $tc1->getVersionObject();
  188. if (!$tc1v->isApproved() && !$this->displayUnapproved) {
  189. $displayHeadPage = false;
  190. }
  191. }
  192. }
  193. if ($displayHeadPage) {
  194. $level++;
  195. }
  196. */
  197. if ($this->displaySubPages == 'relevant' || $this->displaySubPages == 'relevant_breadcrumb') {
  198. $this->populateParentIDArray($this->cID);
  199. }
  200. $this->getNavigationArray($cParentID, $orderBy, $level);
  201. // if we're at the top level we add home to the beginning
  202. if ($cParentID == 1) {
  203. if ($this->displayUnapproved) {
  204. $tc1 = Page::getByID(HOME_CID, "RECENT");
  205. } else {
  206. $tc1 = Page::getByID(HOME_CID, "ACTIVE");
  207. }
  208. $niRow = array();
  209. $niRow['cvName'] = $tc1->getCollectionName();
  210. $niRow['cID'] = HOME_CID;
  211. $niRow['cvDescription'] = $tc1->getCollectionDescription();
  212. $niRow['cPath'] = $tc1->getCollectionPath();
  213. $ni = new AutonavBlockItem($niRow, 0);
  214. $ni->setCollectionObject($tc1);
  215. array_unshift($this->navArray, $ni);
  216. }
  217. /*
  218. if ($displayHeadPage) {
  219. $niRow = array();
  220. $niRow['cvName'] = $tc1->getCollectionName();
  221. $niRow['cID'] = $row['cID'];
  222. $niRow['cvDescription'] = $tc1->getCollectionDescription();
  223. $niRow['cPath'] = $tc1->getCollectionPath();
  224. $ni = new AutonavBlockItem($niRow, 0);
  225. $level++;
  226. $ni->setCollectionObject($tc1);
  227. array_unshift($this->navArray, $ni);
  228. }
  229. */
  230. }
  231. return $this->navArray;
  232. }
  233. function getParentAtLevel($level) {
  234. // this function works in the following way
  235. // we go from the current collection up to the top level. Then we find the parent Id at the particular level specified, and begin our
  236. // autonav from that point
  237. $this->populateParentIDArray($this->cID);
  238. $idArray = array_reverse($this->cParentIDArray);
  239. $this->cParentIDArray = array();
  240. if ($level - count($idArray) == 0) {
  241. // This means that the parent ID array is one less than the item
  242. // we're trying to grab - so we return our CURRENT page as the item to get
  243. // things under
  244. return $this->cID;
  245. }
  246. if (isset($idArray[$level])) {
  247. return $idArray[$level];
  248. } else {
  249. return null;
  250. }
  251. }
  252. protected function displayPage($tc) {
  253. if ($tc->isSystemPage() && (!$this->displaySystemPages)) {
  254. if ($tc->getCollectionPath() == '/members' && Config::get('ENABLE_USER_PROFILES')) {
  255. if ($this->displayUnavailablePages) {
  256. return true;
  257. } else {
  258. $tcp = new Permissions($tc);
  259. return $tcp->canRead();
  260. }
  261. }
  262. return false;
  263. }
  264. $tcv = $tc->getVersionObject();
  265. if ((!is_object($tcv)) || (!$tcv->isApproved() && !$this->displayUnapproved)) {
  266. return false;
  267. }
  268. if ($this->displayUnavailablePages == false) {
  269. $tcp = new Permissions($tc);
  270. if (!$tcp->canRead() && ($tc->getCollectionPointerExternalLink() == null)) {
  271. return false;
  272. }
  273. }
  274. return true;
  275. }
  276. function getNavigationArray($cParentID, $orderBy, $currentLevel) {
  277. // increment all items in the nav array with a greater $currentLevel
  278. foreach($this->navArray as $ni) {
  279. if ($ni->getLevel() + 1 < $currentLevel) {
  280. $ni->hasChildren = true;
  281. }
  282. }
  283. $db = Loader::db();
  284. $navSort = $this->navSort;
  285. $sorted_array = $this->sorted_array;
  286. $navObjectNames = $this->navObjectNames;
  287. $q = "select Pages.cID from Pages where cIsTemplate = 0 and cIsActive = 1 and cParentID = '{$cParentID}' {$orderBy}";
  288. $r = $db->query($q);
  289. if ($r) {
  290. while ($row = $r->fetchRow()) {
  291. if ($this->displaySubPages != 'relevant_breadcrumb' || (in_array($row['cID'], $this->cParentIDArray) || $row['cID'] == $this->cID)) {
  292. /*
  293. if ($this->haveRetrievedSelf) {
  294. // since we've already retrieved self, and we're going through again, we set plus 1
  295. $this->haveRetrievedSelfPlus1 = true;
  296. } else
  297. */
  298. if ($this->haveRetrievedSelf && $cParentID == $this->cID) {
  299. $this->haveRetrievedSelfPlus1 = true;
  300. } else if ($row['cID'] == $this->cID) {
  301. $this->haveRetrievedSelf = true;
  302. }
  303. $displayPage = true;
  304. if ($this->displayUnapproved) {
  305. $tc = Page::getByID($row['cID'], "RECENT");
  306. } else {
  307. $tc = Page::getByID($row['cID'], "ACTIVE");
  308. }
  309. $displayPage = $this->displayPage($tc);
  310. if ($displayPage) {
  311. $niRow = array();
  312. $niRow['cvName'] = $tc->getCollectionName();
  313. $niRow['cID'] = $row['cID'];
  314. $niRow['cvDescription'] = $tc->getCollectionDescription();
  315. $niRow['cPath'] = $tc->getCollectionPath();
  316. $niRow['cPointerExternalLink'] = $tc->getCollectionPointerExternalLink();
  317. $niRow['cPointerExternalLinkNewWindow'] = $tc->openCollectionPointerExternalLinkInNewWindow();
  318. $dateKey = strtotime($tc->getCollectionDatePublic());
  319. $ni = new AutonavBlockItem($niRow, $currentLevel);
  320. $ni->setCollectionObject($tc);
  321. // $this->navArray[] = $ni;
  322. $navSort[$niRow['cID']] = $dateKey;
  323. $sorted_array[$niRow['cID']] = $ni;
  324. $_c = $ni->getCollectionObject();
  325. $object_name = $_c->getCollectionName();
  326. $navObjectNames[$niRow['cID']] = $object_name;
  327. }
  328. }
  329. }
  330. // end while -- sort navSort
  331. // Joshua's Huge Sorting Crap
  332. if($navSort) {
  333. $sortit=0;
  334. if($this->orderBy == "chrono_asc") { asort($navSort); $sortit=1; }
  335. if($this->orderBy == "chrono_desc") { arsort($navSort); $sortit=1; }
  336. if($sortit) {
  337. foreach($navSort as $sortCID => $sortdatewhocares) {
  338. // create sorted_array
  339. $this->navArray[] = $sorted_array[$sortCID];
  340. #############start_recursive_crap
  341. $retrieveMore = false;
  342. if ($this->displaySubPages == 'all') {
  343. if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  344. $retrieveMore = true;
  345. }
  346. } else if (($this->displaySubPages == "relevant" || $this->displaySubPages == "relevant_breadcrumb") && (in_array($sortCID, $this->cParentIDArray) || $sortCID == $this->cID)) {
  347. if ($this->displaySubPageLevels == "enough" && $this->haveRetrievedSelf == false) {
  348. $retrieveMore = true;
  349. } else if ($this->displaySubPageLevels == "enough_plus1" && $this->haveRetrievedSelfPlus1 == false) {
  350. $retrieveMore = true;
  351. } else if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  352. $retrieveMore = true;
  353. }
  354. }
  355. if ($retrieveMore) {
  356. $this->getNavigationArray($sortCID, $orderBy, $currentLevel + 1);
  357. }
  358. #############end_recursive_crap
  359. }
  360. }
  361. $sortit=0;
  362. if($this->orderBy == "alpha_desc") {
  363. $navObjectNames = array_map('strtolower',$navObjectNames);
  364. arsort($navObjectNames);
  365. $sortit=1;
  366. }
  367. if($this->orderBy == "alpha_asc") {
  368. $navObjectNames = array_map('strtolower',$navObjectNames);
  369. asort($navObjectNames);
  370. $sortit=1;
  371. }
  372. if($sortit) {
  373. foreach($navObjectNames as $sortCID => $sortnameaction) {
  374. // create sorted_array
  375. $this->navArray[] = $sorted_array[$sortCID];
  376. #############start_recursive_crap
  377. $retrieveMore = false;
  378. if ($this->displaySubPages == 'all') {
  379. if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  380. $retrieveMore = true;
  381. }
  382. } else if (($this->displaySubPages == "relevant" || $this->displaySubPages == "relevant_breadcrumb") && (in_array($sortCID, $this->cParentIDArray) || $sortCID == $this->cID)) {
  383. if ($this->displaySubPageLevels == "enough" && $this->haveRetrievedSelf == false) {
  384. $retrieveMore = true;
  385. } else if ($this->displaySubPageLevels == "enough_plus1" && $this->haveRetrievedSelfPlus1 == false) {
  386. $retrieveMore = true;
  387. } else if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  388. $retrieveMore = true;
  389. }
  390. }
  391. if ($retrieveMore) {
  392. $this->getNavigationArray($sortCID, $orderBy, $currentLevel + 1);
  393. }
  394. #############end_recursive_crap
  395. }
  396. }
  397. $sortit=0;
  398. if($this->orderBy == "display_desc") { $sortit=1; }
  399. if($this->orderBy == "display_asc") { $sortit=1; }
  400. if($sortit) {
  401. // for display order? this stuff is already sorted...
  402. foreach($navObjectNames as $sortCID => $sortnameaction) {
  403. // create sorted_array
  404. $this->navArray[] = $sorted_array[$sortCID];
  405. #############start_recursive_crap
  406. $retrieveMore = false;
  407. if ($this->displaySubPages == 'all') {
  408. if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  409. $retrieveMore = true;
  410. }
  411. } else if (($this->displaySubPages == "relevant" || $this->displaySubPages == "relevant_breadcrumb") && (in_array($sortCID, $this->cParentIDArray) || $sortCID == $this->cID)) {
  412. if ($this->displaySubPageLevels == "enough" && $this->haveRetrievedSelf == false) {
  413. $retrieveMore = true;
  414. } else if ($this->displaySubPageLevels == "enough_plus1" && $this->haveRetrievedSelfPlus1 == false) {
  415. $retrieveMore = true;
  416. } else if ($this->displaySubPageLevels == 'all' || ($this->displaySubPageLevels == 'custom' && $this->displaySubPageLevelsNum > $currentLevel)) {
  417. $retrieveMore = true;
  418. }
  419. }
  420. if ($retrieveMore) {
  421. $this->getNavigationArray($sortCID, $orderBy, $currentLevel + 1);
  422. }
  423. #############end_recursive_crap
  424. }
  425. }
  426. }
  427. // End Joshua's Huge Sorting Crap
  428. }
  429. }
  430. /** Pupulates the $cParentIDArray instance property.
  431. * @param int $cID The collection id.
  432. */
  433. function populateParentIDArray($cID) {
  434. // returns an array of collection IDs going from the top level to the current item
  435. $cParentID = Page::getCollectionParentIDFromChildID($cID);
  436. if(is_numeric($cParentID)) {
  437. if (!in_array($cParentID, $this->cParentIDArray)) {
  438. $this->cParentIDArray[] = $cParentID;
  439. }
  440. if($cParentID > 0) {
  441. $this->populateParentIDArray($cParentID);
  442. }
  443. }
  444. }
  445. /**
  446. * heh. probably should've gone the simpler route and named this getGrandparentID()
  447. */
  448. function getParentParentID() {
  449. // this has to be the stupidest name of a function I've ever created. sigh
  450. $cParentID = Page::getCollectionParentIDFromChildID($this->cParentID);
  451. return ($cParentID) ? $cParentID : 0;
  452. }
  453. /**
  454. * New and improved version of "generateNav()" function.
  455. * Use this unless you need to maintain backwards compatibility with older custom templates.
  456. *
  457. * Pass in TRUE for the $ignore_exclude_nav arg if you don't want to exclude any pages
  458. * (for both the "exclude_nav" and "exclude_subpages_from_nav" attribute).
  459. * This is useful for breadcrumb nav menus, for example.
  460. *
  461. * Historical note: this must stay a function that gets called by the view templates
  462. * (as opposed to just having the view() method set the variables)
  463. * because we need to maintain the generateNav() function for backwards compatibility with
  464. * older custom templates... and that function unfortunately has side-effects so it cannot
  465. * be called more than once per request (otherwise there will be duplicate items in the nav menu).
  466. */
  467. public function getNavItems($ignore_exclude_nav = false) {
  468. $c = Page::getCurrentPage();
  469. //Create an array of parent cIDs so we can determine the "nav path" of the current page
  470. $inspectC = $c;
  471. $selectedPathCIDs = array($inspectC->getCollectionID());
  472. $parentCIDnotZero=true;
  473. while ($parentCIDnotZero) {
  474. $cParentID = $inspectC->cParentID;
  475. if (!intval($cParentID)) {
  476. $parentCIDnotZero=false;
  477. } else {
  478. if ($cParentID != HOME_CID) {
  479. $selectedPathCIDs[] = $cParentID; //Don't want home page in nav-path-selected
  480. }
  481. $inspectC = Page::getById($cParentID, 'ACTIVE');
  482. }
  483. }
  484. //Retrieve the raw "pre-processed" list of all nav items (before any custom attributes are considered)
  485. $allNavItems = $this->generateNav();
  486. //Remove excluded pages from the list (do this first because some of the data prep code needs to "look ahead" in the list)
  487. $includedNavItems = array();
  488. $excluded_parent_level = 9999; //Arbitrarily high number denotes that we're NOT currently excluding a parent (because all actual page levels will be lower than this)
  489. $exclude_children_below_level = 9999; //Same deal as above. Note that in this case "below" means a HIGHER number (because a lower number indicates higher placement in the sitemp -- e.g. 0 is top-level)
  490. foreach ($allNavItems as $ni) {
  491. $_c = $ni->getCollectionObject();
  492. $current_level = $ni->getLevel();
  493. if ($_c->getAttribute('exclude_nav') && ($current_level <= $excluded_parent_level)) {
  494. $excluded_parent_level = $current_level;
  495. $exclude_page = true;
  496. } else if (($current_level > $excluded_parent_level) || ($current_level > $exclude_children_below_level)) {
  497. $exclude_page = true;
  498. } else {
  499. $excluded_parent_level = 9999; //Reset to arbitrarily high number to denote that we're no longer excluding a parent
  500. $exclude_children_below_level = $_c->getAttribute('exclude_subpages_from_nav') ? $current_level : 9999;
  501. $exclude_page = false;
  502. }
  503. if (!$exclude_page || $ignore_exclude_nav) {
  504. $includedNavItems[] = $ni;
  505. }
  506. }
  507. //Prep all data and put it into a clean structure so markup output is as simple as possible
  508. $navItems = array();
  509. $navItemCount = count($includedNavItems);
  510. for ($i = 0; $i < $navItemCount; $i++) {
  511. $ni = $includedNavItems[$i];
  512. $_c = $ni->getCollectionObject();
  513. $current_level = $ni->getLevel();
  514. //Link target (e.g. open in new window)
  515. $target = $ni->getTarget();
  516. $target = empty($target) ? '_self' : $target;
  517. //Link URL
  518. $pageLink = false;
  519. if ($_c->getAttribute('replace_link_with_first_in_nav')) {
  520. $subPage = $_c->getFirstChild(); //Note: could be a rare bug here if first child was excluded, but this is so unlikely (and can be solved by moving it in the sitemap) that it's not worth the trouble to check
  521. if ($subPage instanceof Page) {
  522. $pageLink = Loader::helper('navigation')->getLinkToCollection($subPage); //We could optimize by instantiating the navigation helper outside the loop, but this is such an infrequent attribute that I prefer code clarity over performance in this case
  523. }
  524. }
  525. if (!$pageLink) {
  526. $pageLink = $ni->getURL();
  527. }
  528. //Current/ancestor page
  529. $selected = false;
  530. $path_selected = false;
  531. if ($c->getCollectionID() == $_c->getCollectionID()) {
  532. $selected = true; //Current item is the page being viewed
  533. $path_selected = true;
  534. } elseif (in_array($_c->getCollectionID(), $selectedPathCIDs)) {
  535. $path_selected = true; //Current item is an ancestor of the page being viewed
  536. }
  537. //Calculate difference between this item's level and next item's level so we know how many closing tags to output in the markup
  538. $next_level = isset($includedNavItems[$i+1]) ? $includedNavItems[$i+1]->getLevel() : 0;
  539. $levels_between_this_and_next = $current_level - $next_level;
  540. //Determine if this item has children (can't rely on $ni->hasChildren() because it doesn't ignore excluded items!)
  541. $has_children = $next_level > $current_level;
  542. //Calculate if this is the first item in its level (useful for CSS classes)
  543. $prev_level = isset($includedNavItems[$i-1]) ? $includedNavItems[$i-1]->getLevel() : -1;
  544. $is_first_in_level = $current_level > $prev_level;
  545. //Calculate if this is the last item in its level (useful for CSS classes)
  546. $is_last_in_level = true;
  547. for ($j = $i+1; $j < $navItemCount; $j++) {
  548. if ($includedNavItems[$j]->getLevel() == $current_level) {
  549. //we found a subsequent item at this level (before this level "ended"), so this is NOT the last in its level
  550. $is_last_in_level = false;
  551. break;
  552. }
  553. if ($includedNavItems[$j]->getLevel() < $current_level) {
  554. //we found a previous level before any other items in this level, so this IS the last in its level
  555. $is_last_in_level = true;
  556. break;
  557. }
  558. } //If loop ends before one of the "if" conditions is hit, then this is the last in its level (and $is_last_in_level stays true)
  559. //Custom CSS class
  560. $attribute_class = $_c->getAttribute('nav_item_class');
  561. $attribute_class = empty($attribute_class) ? '' : $attribute_class;
  562. //Page ID stuff
  563. $item_cid = $_c->getCollectionID();
  564. $is_home_page = ($item_cid == HOME_CID);
  565. //Package up all the data
  566. $navItem = new stdClass();
  567. $navItem->url = $pageLink;
  568. $navItem->name = $ni->getName();
  569. $navItem->target = $target;
  570. $navItem->level = $current_level + 1; //make this 1-based instead of 0-based (more human-friendly)
  571. $navItem->subDepth = $levels_between_this_and_next;
  572. $navItem->hasSubmenu = $has_children;
  573. $navItem->isFirst = $is_first_in_level;
  574. $navItem->isLast = $is_last_in_level;
  575. $navItem->isCurrent = $selected;
  576. $navItem->inPath = $path_selected;
  577. $navItem->attrClass = $attribute_class;
  578. $navItem->isHome = $is_home_page;
  579. $navItem->cID = $item_cid;
  580. $navItem->cObj = $_c;
  581. $navItems[] = $navItem;
  582. }
  583. return $navItems;
  584. }
  585. }