/bp-forums/bbpress/bb-includes/class.bb-walker.php

  1. <?php 
  2.  
  3. class BB_Walker { 
  4. var $tree_type; 
  5. var $db_fields; 
  6.  
  7. //abstract callbacks 
  8. function start_lvl($output) { return $output; } 
  9. function end_lvl($output) { return $output; } 
  10. function start_el($output) { return $output; } 
  11. function end_el($output) { return $output; } 
  12.  
  13. function _init() { 
  14. $this->parents = array(); 
  15. $this->depth = 1; 
  16. $this->previous_element = ''; 
  17. }  
  18.  
  19. function walk($elements, $to_depth) { 
  20. $args = array_slice(func_get_args(), 2); 
  21. $output = ''; 
  22.  
  23. // padding at the end 
  24. $last_element->{$this->db_fields['parent']} = 0; 
  25. $last_element->{$this->db_fields['id']} = 0; 
  26. $elements[] = $last_element; 
  27.  
  28. $flat = (-1 == $to_depth) ? true : false; 
  29. foreach ( $elements as $element ) 
  30. $output .= call_user_func_array( array(&$this, 'step'), array_merge( array($element, $to_depth), $args ) ); 
  31.  
  32. return $output; 
  33.  
  34. function step( $element, $to_depth ) { 
  35. if ( !isset($this->depth) ) 
  36. $this->_init(); 
  37.  
  38. $args = array_slice(func_get_args(), 2); 
  39. $id_field = $this->db_fields['id']; 
  40. $parent_field = $this->db_fields['parent']; 
  41.  
  42. $flat = (-1 == $to_depth) ? true : false; 
  43.  
  44. $output = ''; 
  45.  
  46. // If flat, start and end the element and skip the level checks. 
  47. if ( $flat ) { 
  48. // Start the element. 
  49. if ( isset($element->$id_field) && $element->$id_field != 0 ) { 
  50. $cb_args = array_merge( array(&$output, $element, $this->depth - 1), $args); 
  51. call_user_func_array(array(&$this, 'start_el'), $cb_args); 
  52.  
  53. // End the element. 
  54. if ( isset($element->$id_field) && $element->$id_field != 0 ) { 
  55. $cb_args = array_merge( array(&$output, $element, $this->depth - 1), $args); 
  56. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  57.  
  58. return; 
  59.  
  60. // Walk the tree. 
  61. if ( !empty($element) && !empty($this->previous_element) && $element->$parent_field == $this->previous_element->$id_field ) { 
  62. // Previous element is my parent. Descend a level. 
  63. array_unshift($this->parents, $this->previous_element); 
  64. if ( !$to_depth || ($this->depth < $to_depth) ) { //only descend if we're below $to_depth 
  65. $cb_args = array_merge( array(&$output, $this->depth), $args); 
  66. call_user_func_array(array(&$this, 'start_lvl'), $cb_args); 
  67. } else if ( $to_depth && $this->depth == $to_depth ) { // If we've reached depth, end the previous element. 
  68. $cb_args = array_merge( array(&$output, $this->previous_element, $this->depth), $args); 
  69. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  70. $this->depth++; //always do this so when we start the element further down, we know where we are 
  71. } else if ( !empty($element) && !empty($this->previous_element) && $element->$parent_field == $this->previous_element->$parent_field) { 
  72. // On the same level as previous element. 
  73. if ( !$to_depth || ($this->depth <= $to_depth) ) { 
  74. $cb_args = array_merge( array(&$output, $this->previous_element, $this->depth - 1), $args); 
  75. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  76. } else if ( $this->depth > 1 ) { 
  77. // Ascend one or more levels. 
  78. if ( !$to_depth || ($this->depth <= $to_depth) ) { 
  79. $cb_args = array_merge( array(&$output, $this->previous_element, $this->depth - 1), $args); 
  80. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  81.  
  82. while ( $parent = array_shift($this->parents) ) { 
  83. $this->depth--; 
  84. if ( !$to_depth || ($this->depth < $to_depth) ) { 
  85. $cb_args = array_merge( array(&$output, $this->depth), $args); 
  86. call_user_func_array(array(&$this, 'end_lvl'), $cb_args); 
  87. $cb_args = array_merge( array(&$output, $parent, $this->depth - 1), $args); 
  88. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  89. if ( !empty($element) && isset($this->parents[0]) && $element->$parent_field == $this->parents[0]->$id_field ) { 
  90. break; 
  91. } else if ( !empty($this->previous_element) ) { 
  92. // Close off previous element. 
  93. if ( !$to_depth || ($this->depth <= $to_depth) ) { 
  94. $cb_args = array_merge( array(&$output, $this->previous_element, $this->depth - 1), $args); 
  95. call_user_func_array(array(&$this, 'end_el'), $cb_args); 
  96.  
  97. // Start the element. 
  98. if ( !$to_depth || ($this->depth <= $to_depth) ) { 
  99. if ( !empty($element) && $element->$id_field != 0 ) { 
  100. $cb_args = array_merge( array(&$output, $element, $this->depth - 1), $args); 
  101. call_user_func_array(array(&$this, 'start_el'), $cb_args); 
  102.  
  103. $this->previous_element = $element; 
  104. return $output; 
  105.  
  106. class BB_Walker_Blank extends BB_Walker { // Used for template functions 
  107. var $tree_type; 
  108. var $db_fields = array( 'id' => '', 'parent' => '' ); 
  109.  
  110. var $start_lvl = ''; 
  111. var $end_lvl = ''; 
  112.  
  113. //abstract callbacks 
  114. function start_lvl( $output, $depth ) {  
  115. if ( !$this->start_lvl ) 
  116. return ''; 
  117. $indent = str_repeat("\t", $depth); 
  118. $output .= $indent . "$this->start_lvl\n"; 
  119. return $output; 
  120.  
  121. function end_lvl( $output, $depth ) { 
  122. if ( !$this->end_lvl ) 
  123. return ''; 
  124. $indent = str_repeat("\t", $depth); 
  125. $output .= $indent . "$this->end_lvl\n"; 
  126. return $output; 
  127.  
  128. function start_el() { return ''; } 
  129. function end_el() { return ''; } 
  130.  
  131. class BB_Loop { 
  132. var $elements; 
  133. var $walker; 
  134. var $_preserve = array(); 
  135. var $_looping = false; 
  136.  
  137. function &start( $elements, $walker = 'BB_Walker_Blank' ) { 
  138. $null = null; 
  139. $a = new BB_Loop( $elements ); 
  140. if ( !$a->elements ) 
  141. return $null; 
  142. $a->walker = new $walker; 
  143. return $a; 
  144.  
  145. function __construct( &$elements ) { 
  146. $this->elements = $elements; 
  147. if ( !is_array($this->elements) || empty($this->elements) ) 
  148. return $this->elements = false; 
  149.  
  150. function BB_Loop( &$elements ) { 
  151. $this->__construct( $elements ); 
  152.  
  153. function step() { 
  154. if ( !is_array($this->elements) || !current($this->elements) || !is_object($this->walker) ) 
  155. return false; 
  156.  
  157. if ( !$this->_looping ) { 
  158. $r = reset($this->elements); 
  159. $this->_looping = true; 
  160. } else { 
  161. $r = next($this->elements); 
  162.  
  163. if ( !$args = func_get_args() ) 
  164. $args = array( 0 ); 
  165. echo call_user_func_array( array(&$this->walker, 'step'), array_merge(array(current($this->elements)), $args) ); 
  166. return $r; 
  167.  
  168. function pad( $pad, $offset = 0 ) { 
  169. if ( !is_array($this->elements) || !is_object($this->walker) ) 
  170. return false; 
  171.  
  172. if ( is_numeric($pad) ) 
  173. return $pad * ($this->walker->depth - 1) + (int) $offset; 
  174.  
  175. return str_repeat( $pad, $this->walker->depth - 1 ); 
  176.  
  177. function preserve( $array ) { 
  178. if ( !is_array( $array ) ) 
  179. return false; 
  180.  
  181. foreach ( $array as $key ) 
  182. $this->_preserve[$key] = isset( $GLOBALS[$key] ) ? $GLOBALS[$key] : null; 
  183.  
  184. function reinstate() { 
  185. foreach ( $this->_preserve as $key => $value ) 
  186. $GLOBALS[$key] = $value; 
  187.  
  188. function classes( $output = 'string' ) { 
  189. if ( !is_array($this->elements) || !is_object($this->walker) ) 
  190. return false; 
  191. $classes = array(); 
  192.  
  193. $current = current($this->elements); 
  194.  
  195. if ( $prev = prev($this->elements) ) 
  196. next($this->elements); 
  197. else  
  198. reset($this->elements); 
  199.  
  200. if ( $next = next($this->elements) ) 
  201. prev($this->elements); 
  202. else 
  203. end($this->elements); 
  204.  
  205. if ( !empty($next) && $next->{$this->walker->db_fields['parent']} == $current->{$this->walker->db_fields['id']} ) 
  206. $classes[] = 'bb-parent'; 
  207. elseif ( !empty($next) && $next->{$this->walker->db_fields['parent']} == $current->{$this->walker->db_fields['parent']} ) 
  208. $classes[] = 'bb-precedes-sibling'; 
  209. else 
  210. $classes[] = 'bb-last-child'; 
  211.  
  212. if ( !empty($prev) && $current->{$this->walker->db_fields['parent']} == $prev->{$this->walker->db_fields['id']} ) 
  213. $classes[] = 'bb-first-child'; 
  214. elseif ( !empty($prev) && $current->{$this->walker->db_fields['parent']} == $prev->{$this->walker->db_fields['parent']} ) 
  215. $classes[] = 'bb-follows-sibling'; 
  216. elseif ( $prev ) 
  217. $classes[] = 'bb-follows-niece'; 
  218.  
  219. if ( $this->walker->depth > 1 ) 
  220. $classes[] = 'bb-child'; 
  221. else 
  222. $classes[] = 'bb-root'; 
  223.  
  224. if ( $output === 'string' ) 
  225. $classes = join(' ', $classes); 
  226.  
  227. return $classes; 
  228.  
.