PageRenderTime 64ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/cnk_section_tree.php

https://github.com/netcarver/cnk_section_tree
PHP | 1527 lines | 766 code | 266 blank | 495 comment | 229 complexity | f154d863ddb9e58579544a26394e034e MD5 | raw file
  1. <?php
  2. $plugin['name'] = 'cnk_section_tree';
  3. $plugin['version'] = '0.3.9';
  4. $plugin['author'] = 'Christian Nowak';
  5. $plugin['author_uri'] = 'http://www.cnowak.de';
  6. $plugin['description'] = 'Section Tree';
  7. $plugin['type'] = '1';
  8. @include_once('zem_tpl.php');
  9. # --- BEGIN PLUGIN CODE ---
  10. if(@txpinterface == 'admin')
  11. {
  12. /*
  13. 1 => gTxt('publisher'),
  14. 2 => gTxt('managing_editor'),
  15. 3 => gTxt('copy_editor'),
  16. 4 => gTxt('staff_writer'),
  17. 5 => gTxt('freelancer'),
  18. 6 => gTxt('designer'),
  19. 0 => gTxt('none')
  20. */
  21. add_privs('cnk_section_tree','1,2');
  22. register_tab('extensions', 'cnk_section_tree', "section tree");
  23. register_callback('cnk_section_tree', 'cnk_section_tree');
  24. register_callback('cnk_section_list', 'section', '', 1);
  25. register_callback('cnk_article_view', 'article', '', 1);
  26. register_callback('cnk_section_create', 'section', 'section_create');
  27. register_callback('cnk_section_delete', 'section', 'section_delete', 1);
  28. register_callback('cnk_section_save', 'section', 'section_save');
  29. $cnk_tree = NULL;
  30. $cnk_tree_id = 0;
  31. }
  32. else if (@txpinterface == 'public')
  33. {
  34. register_callback('cnk_pretext', 'pretext');
  35. register_callback('cnk_textpattern', 'textpattern');
  36. define('CNK_FRIENDLY_URLS', false);
  37. }
  38. // -------------------------------------------------------------
  39. //
  40. // TAG: breadcrumb <txp:cnk_breadcrumb />
  41. //
  42. // PARAMETERS:
  43. //
  44. // |*append_article_title*
  45. // | appends the article title |('y' ; 'n' ; default: 'n')|
  46. // |*url_pattern*
  47. // | defines the href attribute of section links. %s is the section name, %u is site_root_url |(string ; default depends on txp's permlink_mode)|
  48. //
  49. // -------------------------------------------------------------
  50. function cnk_breadcrumb($atts)
  51. {
  52. global $cnk_tree, $prefs, $pretext, $s, $id, $title;
  53. extract(lAtts(array(
  54. 'append_article_title' => 'y',
  55. 'url_pattern' => ''
  56. ), $atts));
  57. // build url pattern for section links
  58. if (!$url_pattern)
  59. {
  60. switch($prefs['permlink_mode'])
  61. {
  62. case 'messy':
  63. $url_pattern = '%u?s=%s';
  64. break;
  65. default:
  66. $url_pattern = '%u%s';
  67. }
  68. }
  69. $path_array = cnk_get_path($s);
  70. if ($append_article_title == 'y' && $id)
  71. {
  72. $a = safe_row("id, posted, title, url_title", "textpattern", "id=".doSlash($id));
  73. }
  74. $res = '<div class="cnk_crumbs">';
  75. $path = '/';
  76. for ($i=0; $i < count($path_array); $i++)
  77. {
  78. $path .= $path_array[$i]['name'].'/';
  79. $res .= '<span class="cnk_crumb">';
  80. if ($i > 0) $res .= '<span> » </span>';
  81. if ($i == (count($path_array)-1) && !$id)
  82. {
  83. $res .= $path_array[$i]['title'];
  84. }
  85. else
  86. {
  87. $search = array('%s', '%u', '%p');
  88. $replacement = array($path_array[$i]['name'], hu, $path);
  89. $res .= '<a href="'.str_replace($search, $replacement, $url_pattern).'">'.$path_array[$i]['title'].'</a>';
  90. }
  91. $res .= '</span>';
  92. }
  93. if ($append_article_title == 'y' && $id)
  94. {
  95. //$search = array('%s', '%a', '%t', '%u', '%y', '%m', '%d');
  96. //$replacement = array($section_name, $a['id'], $a['url_title'], hu, substr($a['posted'], 0, 4), substr($a['posted'], 5, 2), substr($a['posted'], 8, 2));
  97. $res .= '<span class="cnk_crumb"><span> » </span>'.$a['title'].'</span>';
  98. }
  99. $res .= '</div>';
  100. return $res;
  101. }
  102. // -------------------------------------------------------------
  103. //
  104. // TAG: section tree <txp:cnk_sec_list />
  105. //
  106. // PARAMETERS:
  107. //
  108. // |*active_section_articles*
  109. // | whether to show article list of active section or not |('y' ; 'n' ; default: 'n')|
  110. // |*active_section_article_order_by*
  111. // | order article list by |('posted' ; 'lastmod' ; 'title' ; default: 'posted')|
  112. // |*active_section_article_order*
  113. // | order article list direction |('asc' ; 'desc' ; default: 'asc')|
  114. // |*active_section_article_max_count*
  115. // | limit articles. if set to 0, all articles will be rendered|(integer ; default: 5)|
  116. // |*exclude_sections*
  117. // | comma separated list of section names that should not show up in the tree.
  118. // subsections of excluded sections won't show up either |('name1','name2' ; default: '')|
  119. // |*start_section*
  120. // | name of section that should be rendered exclusively. subsections will also be rendered |(string ; default: '')|
  121. // |*css_id*
  122. // | id property of the top-level ul tag |(string ; default: 'cnk_sec_tree')|
  123. // |*css_active_section_class*
  124. // | class property of active section element |(string ; default: cnk_active_section)|
  125. // |*css_active_article_class*
  126. // | class property of active article element |(string ; default: cnk_active_article)|
  127. // |*css_article_class*
  128. // | class property of all article elements|(string ; default: cnk_article)|
  129. // |*css_section_class*
  130. // | class property of all section elements|(string ; default: cnk_section)|
  131. // |*css_section_class_open*
  132. // | class property of all opened section elements|(string ; default: cnk_section_open)|
  133. // |*css_section_class_closed*
  134. // | class property of all closed section elements|(string ; default: cnk_section_closed)|
  135. // |*show_article_count*
  136. // | show number of articles with status 4 for every section if at least one article exists. |('y' ; 'n' ; default 'n')|
  137. // |*show_article_count_bottom*
  138. // | show number of articles with status 4 only for bottom sections if at least one article exists |('y' ; 'n' ; default 'n')|
  139. // |*exclude_empties*
  140. // | don't show sections, which have no articles with status 4 assigned to it |('y' ; 'n' ; default 'n')|
  141. // |*url_pattern_section*
  142. // | defines the href attribute of section links. %s is the section name, %u is site_root_url |(string ; default depends on txp's permlink_mode)|
  143. // |*url_pattern_article*
  144. // | defines the href attribute of article links.
  145. // %s is a placeholder for the section name, %a is article id, %t is article url_title, %u is site_root_url, %y(ear), %m(month), %d(ay) |(string ; default depends on txp's permlink_mode)|
  146. // |*section_append_hmtl*
  147. // | appends string right before the closing li tag of a section. same placeholders as url_pattern_section |(string ; default '')|
  148. // |*article_count_pattern*
  149. // | restyle the article count part of section links. %c is placeholder for article count |(string ; default '(%c)')|
  150. // |*expand_all*
  151. // | Expands all section elements. If set to 'n' only the active seciton and its parents will be expanded | ('y' ; 'n' ; default 'y')
  152. //
  153. // -------------------------------------------------------------
  154. function cnk_sec_list($atts)
  155. {
  156. global $cnk_tree, $cnk_tree_id, $prefs, $s, $id;
  157. extract(lAtts(array(
  158. 'active_section_articles' => 'y',
  159. 'active_section_article_order_by' => 'posted',
  160. 'active_section_article_order' => 'asc',
  161. 'active_section_article_max_count' => 5,
  162. 'exclude_sections' => '',
  163. 'start_section' => '',
  164. 'css_id' => 'cnk_sec_tree',
  165. 'css_active_section_class' => 'cnk_active_section',
  166. 'css_active_article_class' => 'cnk_active_article',
  167. 'css_article_class' => 'cnk_article',
  168. 'css_section_class' => 'cnk_section',
  169. 'css_section_class_open' => 'cnk_section_open',
  170. 'css_section_class_closed' => 'cnk_section_closed',
  171. 'show_article_count' => 'n',
  172. 'show_article_count_bottom' => 'n',
  173. 'exclude_empties' => 'n',
  174. 'url_pattern_section' => '',
  175. 'url_pattern_article' => '',
  176. 'section_append_html' => '',
  177. 'article_count_pattern' => '(%c)',
  178. 'expand_all' => 'y'
  179. ), $atts));
  180. // build url pattern for section links
  181. if (!$url_pattern_section)
  182. {
  183. switch($prefs['permlink_mode'])
  184. {
  185. case 'messy':
  186. $url_pattern_section = '%u?s=%s';
  187. break;
  188. default:
  189. $url_pattern_section = '%u%s';
  190. }
  191. }
  192. // build url pattern for article links
  193. if (!$url_pattern_article)
  194. {
  195. switch($prefs['permlink_mode'])
  196. {
  197. case 'messy':
  198. $url_pattern_article = '%u?id=%a';
  199. break;
  200. case 'section_title':
  201. $url_pattern_article = '%u%s/%t';
  202. break;
  203. case 'section_id_title':
  204. $url_pattern_article = '%u%s/%a/%t';
  205. break;
  206. case 'id_title':
  207. $url_pattern_article = '%u%a/%t';
  208. break;
  209. case 'title_only':
  210. $url_pattern_article = '%u%t';
  211. break;
  212. case 'year_month_day_title':
  213. $url_pattern_article = '%u%y/%m/%d/%t';
  214. break;
  215. default:
  216. $url_pattern_article = '%u?id=%a';
  217. }
  218. }
  219. // get lft and rgt value from section node, to decide if sections are in the path
  220. if ($expand_all == 'n')
  221. {
  222. $section_node = safe_row('*', 'txp_section', "lower(name) = lower('".doSlash($s)."')");
  223. }
  224. $is_article_list = safe_count('textpattern', "status = 4 and lower(section) = lower('".doSlash($s)."')")?true:false;
  225. $section_excludes = explode(',', strtolower(str_replace(' ', '', $exclude_sections)));
  226. // create article order clause
  227. switch(strtolower($active_section_article_order_by))
  228. {
  229. case 'posted':
  230. $active_section_article_order_by = 'Posted';
  231. break;
  232. case 'lastmod':
  233. $active_section_article_order_by = 'LastMod';
  234. break;
  235. case 'title':
  236. $active_section_article_order_by = 'Title';
  237. break;
  238. default:
  239. $active_section_article_order_by = 'Posted';
  240. }
  241. $active_section_article_order_clause = (strtolower($active_section_article_order) == 'asc')?'asc':'desc';
  242. $active_section_article_max_count = intval($active_section_article_max_count)?intval($active_section_article_max_count):5;
  243. $active_section_article_order_clause = " order by ".$active_section_article_order_by." ".$active_section_article_order;
  244. if ($active_section_article_order_clause > 0) $active_section_article_order_clause .= " limit 0, ".$active_section_article_max_count;
  245. if ($show_article_count == 'y' || $show_article_count_bottom == 'y' || $exclude_empties == 'y')
  246. {
  247. $count_articles = 'y';
  248. }
  249. else
  250. {
  251. $count_articles = 'n';
  252. }
  253. cnk_st_get_tree($start_section, $count_articles);
  254. //echo "<CNO_DEBUG><pre>".print_r($cnk_tree)."</pre></CNO_DEBUG>";
  255. $open_list = array();
  256. $res = '<div id="cnk_section_tree'.($cnk_tree_id?'_'.$cnk_tree_id:'').'"><ul id="'.$css_id.'">';
  257. $strip_level = -1;
  258. for ($i=0; $i < count($cnk_tree); $i++)
  259. {
  260. if ($cnk_tree[$i]['name'] != 'default')
  261. {
  262. extract($cnk_tree[$i]);
  263. // close open lists
  264. while (($c = count($open_list)) && $open_list[$c-1]['level'] >= $level)
  265. {
  266. $res .= '</ul>';
  267. if ($active_section_articles == 'y' && strtolower($open_list[$c-1]['section']) == strtolower($s) && $is_article_list === true)
  268. {
  269. $res .= cnk_active_article_list($open_list[$c-1]['section'], $active_section_article_order_clause, $url_pattern_article, $css_active_article_class, $css_article_class);
  270. }
  271. array_pop($open_list);
  272. $res .= '</li>';
  273. }
  274. if ($strip_level > -1 && $level <= $strip_level)
  275. {
  276. // when we leave the excluded children array, we can render sections again
  277. $strip_level = -1;
  278. }
  279. if ($strip_level > -1 || ($exclude_empties == 'y' && $children == 0 && $article_count == 0) || (is_array($section_excludes) && in_array(strtolower($name), $section_excludes)))
  280. {
  281. // if section is excluded, subsections should not show up either
  282. if ($strip_level < 0) $strip_level = $level;
  283. }
  284. else
  285. {
  286. $search = array('%s', '%u');
  287. $replacement = array($name, hu);
  288. if ($id || (strtolower($s) != strtolower($name)))
  289. {
  290. $res .= '<li class="'.$css_section_class;
  291. if ($expand_all == 'y' || ($expand_all == 'n' && ($section_node['lft'] >= $lft && $section_node['lft'] < $rgt)))
  292. {
  293. // section is in path or expand_all is on, so it has to be open
  294. $res .= ' '.$css_section_class_open;
  295. }
  296. else
  297. {
  298. $res .= ' '.$css_section_class_closed;
  299. }
  300. $res .= '"><a href="'.str_replace($search, $replacement, $url_pattern_section).'">'.gTxt($title);
  301. if ($article_count > 0 && ($show_article_count == 'y' || ($show_article_count_bottom == 'y' && $children == 0))) $res .= ' '.str_replace('%c', $article_count, $article_count_pattern);
  302. $res .= '</a>'.str_replace($search, $replacement, $section_append_html);
  303. }
  304. else
  305. {
  306. $res .= '<li class="'.$css_section_class.' '.$css_active_section_class;
  307. if ($expand_all == 'y' || ($expand_all == 'n' && ($section_node['lft'] >= $lft && $section_node['lft'] < $rgt)))
  308. {
  309. // section is in path or expand_all is on, so it has to be open
  310. $res .= ' '.$css_section_class_open;
  311. }
  312. else
  313. {
  314. $res .= ' '.$css_section_class_closed;
  315. }
  316. $res .= '">'.gTxt($title);
  317. if ($article_count > 0 && ($show_article_count == 'y' || ($show_article_count_bottom == 'y' && $children == 0))) $res .= ' '.str_replace('%c', $article_count, $article_count_pattern);
  318. $res .= str_replace($search, $replacement, $section_append_html);
  319. }
  320. if ($children > 0)
  321. {
  322. $res .= '<ul>';
  323. array_push($open_list, array('level' => $level, 'section' => $name));
  324. }
  325. else
  326. {
  327. if ($active_section_articles == 'y' && strtolower($s) == strtolower($name) && $is_article_list === true)
  328. {
  329. $res .= cnk_active_article_list($name, $active_section_article_order_clause, $url_pattern_article, $css_active_article_class, $css_article_class);
  330. }
  331. $res .= '</li>';
  332. }
  333. }
  334. }
  335. }
  336. // close remaining open lists
  337. while (($c = count($open_list)) && $open_list[$c-1]['level'] >= $level)
  338. {
  339. $res .= '</ul>';
  340. if ($active_section_articles == 'y' && strtolower($open_list[$c-1]['section']) == strtolower($s) && $is_article_list === true)
  341. {
  342. $res .= cnk_active_article_list($open_list[$c-1]['section'], $active_section_article_order_clause, $url_pattern_article, $css_active_article_class, $css_article_class);
  343. }
  344. array_pop($open_list);
  345. $res .= '</li>';
  346. }
  347. $cnk_tree_id++;
  348. return $res.'</ul></div>';
  349. }
  350. // -------------------------------------------------------------
  351. //
  352. // Function: generates section path for specified section
  353. //
  354. // -------------------------------------------------------------
  355. function cnk_get_path($section_name)
  356. {
  357. // TODO: implement caching
  358. $path = array();
  359. $rs = safe_query("SELECT s1.name, s1.title FROM ".safe_pfx('txp_section')." s1, ".safe_pfx('txp_section')." s2 WHERE lower(s2.name) = lower('".doSlash($section_name)."') AND s2.lft BETWEEN s1.lft AND s1.rgt AND s1.name <> 'default' ORDER BY s1.lft");
  360. while ($a = nextRow($rs))
  361. {
  362. array_push($path, $a);
  363. }
  364. return $path;
  365. }
  366. // -------------------------------------------------------------
  367. //
  368. // Function: generates article list for active section
  369. //
  370. // -------------------------------------------------------------
  371. function cnk_active_article_list($section_name, $order, $url_pattern_article, $css_active_article_class, $css_article_class)
  372. {
  373. global $prefs, $id;
  374. //echo "<CNO_DEBUG>".$id."</CNO_DEBUG>";
  375. $res = '<ul>';
  376. $rs = safe_rows_start("id, posted, title, url_title","textpattern", "lower(section)='".strtolower($section_name)."' and status = 4 ".$order);
  377. while ($a = nextRow($rs))
  378. {
  379. if (strtolower($id) != strtolower($a['id']))
  380. {
  381. $search = array('%s', '%a', '%t', '%u', '%y', '%m', '%d');
  382. $replacement = array($section_name, $a['id'], $a['url_title'], hu, substr($a['posted'], 0, 4), substr($a['posted'], 5, 2), substr($a['posted'], 8, 2));
  383. $res .= '<li class="'.$css_article_class.'"><a href="'.str_replace($search, $replacement, $url_pattern_article).'">'.gTxt($a['title']).'</a></li>';
  384. }
  385. else
  386. {
  387. $res .= '<li class="'.$css_article_class.' '.$css_active_article_class.'">'.gTxt($a['title']);
  388. }
  389. }
  390. return $res.'</ul>';
  391. }
  392. // -------------------------------------------------------------
  393. //
  394. // Function: send hooks to correct functions
  395. //
  396. // -------------------------------------------------------------
  397. function cnk_section_tree($event, $step)
  398. {
  399. if(!$step or !in_array($step, array( 'cnk_st_install', 'cnk_st_deinstall', 'cnk_section_delete'))) {
  400. cnk_st_configure();
  401. }
  402. else
  403. {
  404. $step();
  405. }
  406. }
  407. // -------------------------------------------------------------
  408. //
  409. // Function: saves sections
  410. //
  411. // -------------------------------------------------------------
  412. function cnk_section_save()
  413. {
  414. global $cnk_tree;
  415. // get section
  416. $old_name = ps('old_name');
  417. $name = sanitizeForUrl(ps('name'));
  418. $parent = ps('parent');
  419. $old_parent = ps('old_parent');
  420. $children = ps('children');
  421. // if name was changed to an existing one, don't update, otherwise fix parent
  422. if ($old_name && (strtolower($name) != strtolower($old_name)))
  423. {
  424. $chk = fetch('name','txp_section','name',$old_name);
  425. if ($chk)
  426. {
  427. $cnk_tree = NULL;
  428. return;
  429. }
  430. else
  431. {
  432. safe_update("txp_section", "parent='".$name."'", "parent='".$old_name."'");
  433. }
  434. }
  435. // if parent changed, update
  436. if ($parent != $old_parent)
  437. {
  438. // if node has children move complete subtree
  439. if ($children > 0)
  440. {
  441. cnk_st_move_subtree($name, $parent);
  442. }
  443. else
  444. {
  445. cnk_st_move_node($name, $parent);
  446. }
  447. }
  448. $cnk_tree = NULL;
  449. }
  450. // -------------------------------------------------------------
  451. //
  452. // Function: deletes section (and also all subsections)
  453. //
  454. // -------------------------------------------------------------
  455. function cnk_section_delete()
  456. {
  457. // global $cnk_tree;
  458. $name = ps('name');
  459. // only delete, if no articles are found in that section (TXP native behaviour)
  460. if (!safe_count('textpattern', "lower(section) = lower('".$name."')"))
  461. {
  462. $n = safe_row("*", "txp_section", "name='".$name."'");
  463. // delete all subnodes or add them to the parent of the deleted node?
  464. if (($n['rgt'] - $n['lft']) > 1)
  465. {
  466. // ask where to append subtree or if it should be completely deleted
  467. //pagetop(gTxt('sections'));
  468. /* This codes deletes the complete subtree
  469. $width = $n['rgt'] - $n['lft'] + 1;
  470. safe_delete('txp_section', "lft between ".$n['lft']." AND ".$n['rgt']);
  471. safe_update("txp_section","rgt=rgt-".$width, "rgt > ".$n['rgt']);
  472. safe_update("txp_section","lft=lft-".$width, "lft > ".$n['rgt']);
  473. */
  474. // delete section and move all children one level up
  475. // safe_delete('txp_section', "lft=".$n['lft']);
  476. safe_update('txp_section', "lft=lft-1, rgt=rgt-1, level=level-1", "lft between ".$n['lft']." AND ".$n['rgt']);
  477. safe_update("txp_section", "parent='".$n['parent']."'", "parent='".$n['name']."'");
  478. safe_update("txp_section", "rgt=rgt-2", "rgt > ".$n['rgt']);
  479. safe_update("txp_section", "lft=lft-2", "lft > ".$n['rgt']);
  480. }
  481. else
  482. {
  483. // safe_delete('txp_section', "name = '".$name."'");
  484. safe_update("txp_section","rgt=rgt-2", "rgt > ".$n['rgt']);
  485. safe_update("txp_section","lft=lft-2", "lft > ".$n['rgt']);
  486. }
  487. }
  488. // $cnk_tree = NULL;
  489. // $message = gTxt('section_deleted', array('{name}' => $name));
  490. // header("Location: ?event=section&message=".urlencode($message)); exit;
  491. }
  492. // -------------------------------------------------------------
  493. //
  494. // Function: creates new section
  495. //
  496. // -------------------------------------------------------------
  497. function cnk_section_create()
  498. {
  499. // get name
  500. $name = sanitizeForUrl(ps('name'));
  501. // if new section was created, add to node to default
  502. $chk = safe_field('name','txp_section',"name='".$name."' and lft is null");
  503. if ($chk) cnk_st_add_node($name, 'default');
  504. }
  505. // -------------------------------------------------------------
  506. //
  507. // Function: adds additional form elements to section view
  508. //
  509. // -------------------------------------------------------------
  510. function cnk_section_list()
  511. {
  512. ob_start('cnk_section_inject');
  513. }
  514. function cnk_section_inject($buffer)
  515. {
  516. global $DB, $prefs;
  517. if(!isset($DB)) $DB = new db;
  518. if(!isset($prefs)) $prefs = get_prefs();
  519. // add tree javascript and css
  520. $script = '<script type="text/javascript">
  521. function cnk_move_up(section)
  522. {
  523. // nothing
  524. }
  525. function cnk_move_down(section)
  526. {
  527. // nothing
  528. }
  529. </script>
  530. <style>
  531. #cnk_section_tree li
  532. {
  533. margin: 4px 0px 4px 10px !important;
  534. }
  535. </style>';
  536. $buffer = str_replace('<script type="text/javascript" src="jquery.js"></script>', '<script type="text/javascript" src="jquery.js"></script>'.$script, $buffer);
  537. // add section tree navigation above form
  538. $move_links = ''; //' <a href="javascript:cnk_move_up(\'%s\');">u</a> <a href="javascript:cnk_move_down(\'%s\');">d</a>';
  539. $navigation = cnk_sec_list(array('active_section_articles' => 'n', 'url_pattern_section' => '#section-%s', 'section_append_html' => $move_links));
  540. $buffer = str_replace('</h1>', '</h1>'.$navigation, $buffer);
  541. // replace delete event
  542. //$buffer = str_replace('<input type="hidden" name="event" value="section" /><input type="hidden" name="step" value="section_delete" />', '<input type="hidden" name="event" value="cnk_section_tree" /><input type="hidden" name="step" value="cnk_section_delete" />', $buffer);
  543. // insert section tree code
  544. $pattern = '#(<tr><td colspan="2" class="noline"><input type="submit" name="" value=".*" class="smallerbox" /><input type="hidden" name="event" value="section" /><input type="hidden" name="step" value="section_save" /><input type="hidden" name="old_name" value="(.*)" />)#m';
  545. $insert = 'cnk_st_dropdown';
  546. $buffer = preg_replace_callback($pattern, $insert, $buffer);
  547. return $buffer;
  548. }
  549. // -------------------------------------------------------------
  550. //
  551. // Function: replaces section dropdown with section tree
  552. // in write tab
  553. //
  554. // -------------------------------------------------------------
  555. function cnk_article_view()
  556. {
  557. ob_start('cnk_write_inject');
  558. }
  559. function cnk_write_inject($buffer)
  560. {
  561. global $DB;
  562. if(!isset($DB)) $DB = new db;
  563. if(!isset($prefs)) $prefs = get_prefs();
  564. // replace section dropdown TODO: tidy up regexp!
  565. $pattern = '#name="Section".*</select></p>#sU';
  566. if (gps('step') == 'edit') $pattern = '#(name="Section".*<option value="(.*)" selected="selected">.*</select></p>)#s';
  567. $insert = 'cnk_st_dropdown_article';
  568. $buffer = preg_replace_callback($pattern, $insert, $buffer);
  569. return $buffer;
  570. }
  571. // -------------------------------------------------------------
  572. //
  573. // Function: cnk_article_view() helper function
  574. //
  575. // -------------------------------------------------------------
  576. function cnk_st_dropdown_article($matches)
  577. {
  578. global $cnk_tree;
  579. $found_name = isset($matches[2])?$matches[2]:'';
  580. cnk_st_get_tree();
  581. $res = 'name="Section" class="list">';
  582. for ($i=1; $i < count($cnk_tree); $i++) //hides default
  583. {
  584. extract($cnk_tree[$i]);
  585. $res .= '<option value="'.$name.'" '.((strtolower($name)==strtolower($found_name))?'selected="selected"':'').'>'.cnk_st_spaces($level-1).gTxt($title).'</option>';
  586. }
  587. $res .= '</select>';
  588. return $res;
  589. }
  590. // -------------------------------------------------------------
  591. //
  592. // Function: cnk_section_list() helper function
  593. //
  594. // -------------------------------------------------------------
  595. function cnk_st_dropdown($matches)
  596. {
  597. global $cnk_tree;
  598. cnk_st_get_tree();
  599. $node = cnk_st_get_node($matches[2]);
  600. $sec_parent = $node['parent'];
  601. $stop_rgt = 0;
  602. $res = '<tr><td class="noline" style="text-align: right; vertical-align: middle;">Parent: </td> <td class="noline"><select name="parent" class="list">';
  603. for ($i=0; $i < count($cnk_tree); $i++)
  604. {
  605. extract($cnk_tree[$i]);
  606. // don't show the node itself or it's children
  607. if ($stop_rgt < $rgt)
  608. {
  609. if ($name != $matches[2])
  610. {
  611. $res .= '<option value="'.$name.'" '.(($name==$sec_parent)?'selected="selected"':'').'>'.cnk_st_spaces($level).gTxt($title).'</option>';
  612. }
  613. else
  614. {
  615. $stop_rgt = $rgt;
  616. }
  617. }
  618. }
  619. $res .= '</select><input type="hidden" name="children" value="'.$node['children'].'" /><input type="hidden" name="old_parent" value="'.$sec_parent.'" /></td></tr>';
  620. $res .= '<tr><td class="noline">&nbsp;</td><td class="noline"><a href="#cnk_section_tree">^ go up to tree</a></td></tr>'.$matches[1];
  621. return $res;
  622. }
  623. // -------------------------------------------------------------
  624. //
  625. // Function: internal nested set function to get a node
  626. //
  627. // -------------------------------------------------------------
  628. function cnk_st_get_node($child_name)
  629. {
  630. global $cnk_tree;
  631. cnk_st_get_tree();
  632. $i = 0;
  633. for($i=0; $i < count($cnk_tree); $i++)
  634. {
  635. if ($cnk_tree[$i]['name'] == $child_name) return $cnk_tree[$i];
  636. }
  637. }
  638. // -------------------------------------------------------------
  639. //
  640. // Function: internal helper function to indent strings
  641. //
  642. // -------------------------------------------------------------
  643. function cnk_st_spaces($count)
  644. {
  645. $str = '';
  646. for ($i=0; $i < $count; $i++) $str .= '-';
  647. return $str.' ';
  648. }
  649. // -------------------------------------------------------------
  650. //
  651. // Function: internal nested set function to get the tree
  652. // or a subtree specified by parent_node
  653. //
  654. // -------------------------------------------------------------
  655. function cnk_st_get_tree($parent_node = '', $count_articles = 'n')
  656. {
  657. global $cnk_tree;
  658. if ($cnk_tree === NULL || $parent_node != $cnk_tree[0]['name'] || (!isset($cnk_tree[0]['article_count']) && $count_articles == 'y'))
  659. {
  660. $cnk_tree = array();
  661. $sql_fields = "s.name, s.title, s.parent, s.level, s.lft, s.rgt";
  662. if ($parent_node != '')
  663. {
  664. $sql_tables = safe_pfx('txp_section')." s LEFT JOIN ".safe_pfx('txp_section')." p ON s.lft >= p.lft AND s.rgt <= p.rgt";
  665. $sql_where = "lower(p.name) = '".doSlash(strtolower($parent_node))."' GROUP BY s.lft asc";
  666. }
  667. else
  668. {
  669. $sql_tables = safe_pfx('txp_section')." s";
  670. $sql_where = "1=1 GROUP BY s.lft asc";
  671. }
  672. if ($count_articles == 'y')
  673. {
  674. $sql_fields .= ", count(a.section) AS article_count";
  675. $sql_tables .= " LEFT JOIN ".safe_pfx('textpattern')." a ON a.section = s.name AND a.status = 4";
  676. $sql_where = $sql_where.", s.name";
  677. }
  678. $rs = safe_query("SELECT ".$sql_fields." FROM ".$sql_tables." WHERE ".$sql_where);
  679. while ($a = nextRow($rs))
  680. {
  681. $a['children'] = ($a['rgt'] - $a['lft'] - 1) / 2;
  682. if (!isset($a['article_count'])) $a['article_count'] = 0;
  683. array_push($cnk_tree, $a);
  684. }
  685. }
  686. }
  687. // -------------------------------------------------------------
  688. //
  689. // Function: Prints out configuration menu
  690. //
  691. // TODO: Make pretty!
  692. //
  693. // -------------------------------------------------------------
  694. function cnk_st_configure($message='')
  695. {
  696. pagetop('Section Tree Configuration', $message);
  697. echo "<a href=\"?event=cnk_section_tree&#38;step=cnk_st_install\">Install</a>";
  698. echo "<br /><br />";
  699. echo "<a href=\"?event=cnk_section_tree&#38;step=cnk_st_deinstall\">Deinstall</a>";
  700. }
  701. // -------------------------------------------------------------
  702. //
  703. // Function: install
  704. //
  705. // -------------------------------------------------------------
  706. function cnk_st_install($message='')
  707. {
  708. pagetop('Section Tree Configuration', $message);
  709. $res = true;
  710. // add columns
  711. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." ADD parent VARCHAR(128);")) $res = false;
  712. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." ADD level TINYINT;")) $res = false;
  713. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." ADD lft INT(12);")) $res = false;
  714. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." ADD rgt INT(12);")) $res = false;
  715. // update root
  716. if (!safe_update("txp_section","level=0, lft=1, rgt=2", "name='default'")) $res = false;
  717. // get other sections and add to root
  718. $rs = safe_rows_start("name","txp_section", "lft is null");
  719. while ($a = nextRow($rs))
  720. {
  721. extract($a);
  722. if (!cnk_st_add_node($name, 'default')) $res = false;
  723. }
  724. // add indexes TODO: fix nested set functions to be unique index safe, until then we use just index
  725. if (!safe_query('ALTER TABLE `'.safe_pfx('txp_section').'` ADD INDEX (`rgt`)')) $res = false;
  726. if (!safe_query('ALTER TABLE `'.safe_pfx('txp_section').'` ADD INDEX (`lft`)')) $res = false;
  727. if ($res)
  728. {
  729. echo "Installation was successful!";
  730. }
  731. else
  732. {
  733. echo "Installation was not successful!";
  734. }
  735. }
  736. // -------------------------------------------------------------
  737. //
  738. // Function: deinstall
  739. //
  740. // -------------------------------------------------------------
  741. function cnk_st_deinstall($message='')
  742. {
  743. pagetop('Section Tree Configuration', $message);
  744. $res = true;
  745. // remove columns
  746. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." DROP COLUMN parent;")) $res = false;
  747. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." DROP COLUMN level;")) $res = false;
  748. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." DROP COLUMN lft;")) $res = false;
  749. if (!safe_query("ALTER TABLE ".safe_pfx("txp_section")." DROP COLUMN rgt;")) $res = false;
  750. // drop indexes
  751. //if (!safe_query('ALTER TABLE `'.safe_pfx(txp_section).'` DROP UNIQUE (`rgt`)')) $res = false;
  752. //if (!safe_query('ALTER TABLE `'.safe_pfx(txp_section).'` DROP UNIQUE (`lft`)')) $res = false;
  753. if ($res)
  754. {
  755. echo "Deinstallation was successful!";
  756. }
  757. else
  758. {
  759. echo "Deinstallation was not successful!";
  760. }
  761. }
  762. // -------------------------------------------------------------
  763. //
  764. // Function: internal nested set function to add a node
  765. // currently redirects to cnk_st_add_node_end()
  766. //
  767. // -------------------------------------------------------------
  768. function cnk_st_add_node($node_name, $parent_name)
  769. {
  770. return cnk_st_add_node_end($node_name, $parent_name);
  771. }
  772. // -------------------------------------------------------------
  773. //
  774. // Function: internal nested set function to add a node at
  775. // last position within the parent node
  776. //
  777. // -------------------------------------------------------------
  778. function cnk_st_add_node_end($node_name, $parent_name)
  779. {
  780. // get parent rgt
  781. $p = safe_row("level, rgt", "txp_section", "name='".$parent_name."'");
  782. // update parents
  783. if (!safe_update("txp_section","rgt=rgt+2", "rgt >= ".$p['rgt'])) return false;
  784. if (!safe_update("txp_section","lft=lft+2", "lft > ".$p['rgt'])) return false;
  785. // update node
  786. if (!safe_update("txp_section","parent='".$parent_name."', level=".$p['level']."+1, lft=".$p['rgt'].", rgt=".$p['rgt']."+1", "name = '".$node_name."'")) return false;
  787. return true;
  788. }
  789. // -------------------------------------------------------------
  790. //
  791. // Function: internal nested set function to move a node
  792. //
  793. // -------------------------------------------------------------
  794. function cnk_st_move_node($node_name, $parent_name)
  795. {
  796. $n = safe_row("rgt", "txp_section", "name='".$node_name."'");
  797. if (cnk_st_add_node_end($node_name, $parent_name) === true)
  798. {
  799. if (!safe_update("txp_section","rgt=rgt-2", "rgt > ".$n['rgt'])) return false;
  800. if (!safe_update("txp_section","lft=lft-2", "lft > ".$n['rgt'])) return false;
  801. return true;
  802. }
  803. else
  804. {
  805. return false;
  806. }
  807. }
  808. // -------------------------------------------------------------
  809. //
  810. // Function: internal nested set function to move a subtree
  811. //
  812. // -------------------------------------------------------------
  813. function cnk_st_move_subtree($node_name, $parent_name)
  814. {
  815. $n = safe_row("rgt, lft, level", "txp_section", "name='".$node_name."'");
  816. $p = safe_row("rgt, lft, level", "txp_section", "name='".$parent_name."'");
  817. $width = $n['rgt'] - $n['lft'] + 1;
  818. $level_diff = $p['level'] - $n['level'] + 1;
  819. $diff = $p['rgt'] - $n['lft'];
  820. // let's first update parent information of the anchor node
  821. if (!safe_update("txp_section","parent='".$parent_name."'", "name = '".$node_name."'")) return false;
  822. // create place for subtree
  823. if (!safe_update("txp_section","rgt=rgt+".$width, "rgt >= ".$p['rgt'])) return false;
  824. if (!safe_update("txp_section","lft=lft+".$width, "lft > ".$p['rgt'])) return false;
  825. if ($p['lft'] < $n['lft'])
  826. {
  827. $n['lft'] = $n['lft'] + $width;
  828. $n['rgt'] = $n['rgt'] + $width;
  829. $diff = $diff - $width;
  830. }
  831. // move subtree
  832. if (!safe_update("txp_section","lft = lft + (".$diff."), rgt = rgt + (".$diff."), level=level+(".$level_diff.")", "lft between ".$n['lft']." AND ".$n['rgt'])) return false;
  833. // close hole
  834. if (!safe_update("txp_section","rgt=rgt-".$width, "rgt > ".$n['rgt'])) return false;
  835. if (!safe_update("txp_section","lft=lft-".$width, "lft > ".$n['rgt'])) return false;
  836. }
  837. // -------------------------------------------------------------
  838. //
  839. // Function: Hooks into txp's pretext function to takeover url
  840. // analyzing.
  841. //
  842. // -------------------------------------------------------------
  843. function cnk_pretext()
  844. {
  845. global $prefs;
  846. // only takeover url algorithm when in section_title mode
  847. if (CNK_FRIENDLY_URLS && $prefs['permlink_mode'] == 'section_title')
  848. {
  849. extract($prefs);
  850. $out = array();
  851. // some useful vars for taghandlers, plugins
  852. $out['request_uri'] = preg_replace("|^https?://[^/]+|i","",serverSet('REQUEST_URI'));
  853. $out['qs'] = serverSet('QUERY_STRING');
  854. // IIS fix
  855. if (!$out['request_uri'] and serverSet('SCRIPT_NAME'))
  856. $out['request_uri'] = serverSet('SCRIPT_NAME').( (serverSet('QUERY_STRING')) ? '?'.serverSet('QUERY_STRING') : '');
  857. // another IIS fix
  858. if (!$out['request_uri'] and serverSet('argv'))
  859. {
  860. $argv = serverSet('argv');
  861. $out['request_uri'] = @substr($argv[0], strpos($argv[0], ';') + 1);
  862. }
  863. $subpath = preg_quote(preg_replace("/https?:\/\/.*(\/.*)/Ui","$1",hu),"/");
  864. $req = preg_replace("/^$subpath/i","/",$out['request_uri']);
  865. $url_chunks = explode('/', trim($req, '/'));
  866. $req = '/'.implode('/', array_slice($url_chunks, -2));
  867. //echo $req;
  868. extract(chopUrl($req));
  869. //first we sniff out some of the preset url schemes
  870. if (strlen($u1))
  871. {
  872. switch($u1)
  873. {
  874. case 'atom':
  875. include txpath.'/publish/atom.php'; exit(atom());
  876. case 'rss':
  877. include txpath.'/publish/rss.php'; exit(rss());
  878. // urldecode(strtolower(urlencode())) looks ugly but is the only way to
  879. // make it multibyte-safe without breaking backwards-compatibility
  880. case urldecode(strtolower(urlencode(gTxt('section')))):
  881. $out['s'] = (ckEx('section',$u2)) ? $u2 : ''; break;
  882. case urldecode(strtolower(urlencode(gTxt('category')))):
  883. $out['c'] = (ckEx('category',$u2)) ? $u2 : ''; break;
  884. case urldecode(strtolower(urlencode(gTxt('author')))):
  885. $out['author'] = (!empty($u2)) ? $u2 : ''; break;
  886. // AuthorID gets resolved from Name further down
  887. case urldecode(strtolower(urlencode(gTxt('file_download')))):
  888. $out['s'] = 'file_download';
  889. $out['id'] = (!empty($u2)) ? $u2 : ''; break;
  890. default:
  891. // then see if the prefs-defined permlink scheme is usable
  892. switch ($permlink_mode) {
  893. /*
  894. case 'section_id_title':
  895. if (empty($u2))
  896. {
  897. $out['s'] = (ckEx('section',$u1)) ? $u1 : '';
  898. }
  899. else
  900. {
  901. $rs = lookupByIDSection($u2, $u1);
  902. $out['s'] = @$rs['Section'];
  903. $out['id'] = @$rs['ID'];
  904. }
  905. break;
  906. case 'year_month_day_title':
  907. if (empty($u2))
  908. {
  909. $out['s'] = (ckEx('section',$u1)) ? $u1 : '';
  910. }
  911. elseif (empty($u4))
  912. {
  913. $month = "$u1-$u2";
  914. if (!empty($u3)) $month.= "-$u3";
  915. if (preg_match('/\d+-\d+(?:-\d+)?/', $month)) {
  916. $out['month'] = $month;
  917. $out['s'] = 'default';
  918. }
  919. }
  920. else
  921. {
  922. $when = "$u1-$u2-$u3";
  923. $rs = lookupByDateTitle($when,$u4);
  924. $out['id'] = (!empty($rs['ID'])) ? $rs['ID'] : '';
  925. $out['s'] = (!empty($rs['Section'])) ? $rs['Section'] : '';
  926. }
  927. break;
  928. */
  929. case 'section_title':
  930. if (empty($u2))
  931. {
  932. $out['s'] = (ckEx('section',$u1)) ? $u1 : '';
  933. }
  934. else
  935. {
  936. // match section/title
  937. $rs = lookupByTitleSection($u2,$u1);
  938. if (count($rs))
  939. {
  940. // check path TODO: move to function
  941. /*
  942. $rs_path = safe_rows("name", "txp_section", "lft <= ".$rs['lft']." and ((rgt-lft) > 1 OR lft = ".$rs['lft'].") and name != 'default' order by lft");
  943. $path = '/';
  944. for($i=0; $i < count($rs_path); $i++)
  945. {
  946. $path .= $rs_path[$i]['name'].'/';
  947. }
  948. if ($path == '/'.implode('/', $url_chunks).'/') */
  949. {
  950. $out['id'] = @$rs['ID'];
  951. $out['s'] = @$rs['Section'];
  952. }
  953. }
  954. else
  955. {
  956. // match parentsection/section
  957. $rs = safe_row("name, lft",'txp_section',"lower(name) like '".doSlash($u2)."' AND lower(parent)='".doSlash($u1)."' limit 1");
  958. if (count($rs))
  959. {
  960. // check path TODO: move to function
  961. $rs_path = safe_rows("name", "txp_section", "lft <= ".$rs['lft']." and ((rgt-lft) > 1 OR lft = ".$rs['lft'].") and name != 'default' order by lft");
  962. $path = '/';
  963. for($i=0; $i < count($rs_path); $i++)
  964. {
  965. $path .= $rs_path[$i]['name'].'/';
  966. }
  967. if ($path == '/'.implode('/', $url_chunks).'/')
  968. {
  969. $out['s'] = @$rs['name'];
  970. }
  971. }
  972. }
  973. }
  974. break;
  975. /*
  976. case 'title_only':
  977. $rs = lookupByTitle($u1);
  978. $out['id'] = @$rs['ID'];
  979. $out['s'] = (empty($rs['Section']) ? ckEx('section', $u1) : $rs['Section']);
  980. break;
  981. case 'id_title':
  982. if (is_numeric($u1) && ckExID($u1))
  983. {
  984. $rs = lookupByID($u1);
  985. $out['id'] = (!empty($rs['ID'])) ? $rs['ID'] : '';
  986. $out['s'] = (!empty($rs['Section'])) ? $rs['Section'] : '';
  987. }
  988. else
  989. {
  990. # We don't want to miss the /section/ pages
  991. $out['s']= ckEx('section',$u1)? $u1 : '';
  992. }
  993. break; */
  994. }
  995. }
  996. }
  997. else
  998. {
  999. $out['s'] = 'default';
  1000. }
  1001. //print_r($out);
  1002. if (isset($out['id'])) $_GET['id'] = $out['id'];
  1003. if (isset($out['s'])) $_GET['s'] = $out['s'];
  1004. }
  1005. }
  1006. // -------------------------------------------------------------
  1007. //
  1008. // Function: Hooks into txp's textpattern function to takeover
  1009. // url rewriting.
  1010. //
  1011. // -------------------------------------------------------------
  1012. function cnk_textpattern()
  1013. {
  1014. global $prefs, $pretext, $permlink_mode;
  1015. // only takeover url algorithm when in section_title mode
  1016. if (CNK_FRIENDLY_URLS && $prefs['permlink_mode'] == 'section_title')
  1017. {
  1018. // tell textpattern to use messy urls
  1019. $permlink_mode = 'messy';
  1020. @ob_start('cnk_override_buffer');
  1021. }
  1022. }
  1023. // -------------------------------------------------------------
  1024. //
  1025. // Function: Hooks into txp's textpattern end function to takeover
  1026. // url rewriting.
  1027. //
  1028. // -------------------------------------------------------------
  1029. function cnk_textpattern_end()
  1030. {
  1031. global $prefs;
  1032. // only takeover url algorithm when in section_title mode
  1033. if (CNK_FRIENDLY_URLS && $prefs['permlink_mode'] == 'section_title')
  1034. {
  1035. @ob_end_flush(); exit;
  1036. }
  1037. }
  1038. // -------------------------------------------------------------
  1039. //
  1040. // Function: internal page buffer url rewriting function
  1041. //
  1042. // -------------------------------------------------------------
  1043. function cnk_override_buffer($buffer)
  1044. {
  1045. global $pretext, $production_status;
  1046. $buffer = preg_replace_callback('%href="('.hu.'|\?)([^"]*)"%', 'cnk_replace_pageurls', $buffer);
  1047. return $buffer;
  1048. }
  1049. // -------------------------------------------------------------
  1050. //
  1051. // Function: internal page buffer url rewriting callback function
  1052. //
  1053. // -------------------------------------------------------------
  1054. function cnk_replace_pageurls($parts)
  1055. {
  1056. extract(lAtts(array(
  1057. 'path' => 'index.php',
  1058. 'query' => '',
  1059. 'fragment' => '',
  1060. ), parse_url(html_entity_decode(str_replace('&#38;', '&', $parts[2])))));
  1061. // Tidy up links back to the site homepage
  1062. if ($path == 'index.php' && empty($query))
  1063. {
  1064. return 'href="' .hu. '"';
  1065. }
  1066. // Fix matches like href="?s=foo"
  1067. else if ($path && empty($query) && $parts[1] == '?')
  1068. {
  1069. $query = $path;
  1070. $path = 'index.php';
  1071. }
  1072. // Check to see if there is query to work with.
  1073. else if (empty($query) || $path != 'index.php' || strpos($query, '/') === true)
  1074. {
  1075. return $parts[0];
  1076. }
  1077. // '&amp;' will break parse_str() if they are found in a query string
  1078. $query = str_replace('&amp;', '&', $query);
  1079. if ($fragment) $fragment = '#'.$fragment;
  1080. global $pretext;
  1081. parse_str($query, $query_part);
  1082. if (!array_key_exists('pg', $query_part)) $query_part['pg'] = 0;
  1083. if (!array_key_exists('id', $query_part)) $query_part['id'] = 0;
  1084. if (!array_key_exists('rss', $query_part)) $query_part['rss'] = 0;
  1085. if (!array_key_exists('atom', $query_part)) $query_part['atom'] = 0;
  1086. /* if ($this->pref('join_pretext_to_pagelinks'))
  1087. {
  1088. extract(array_merge($pretext, $query_part));
  1089. /* }
  1090. else
  1091. */ {
  1092. extract($query_part);
  1093. }
  1094. // We have a id, pass to permlinkurl()
  1095. if ($id)
  1096. {
  1097. if (@$s == 'file_download')
  1098. {
  1099. //$url = $this->toggle_permlink_mode('filedownloadurl', $id); TODO!!
  1100. }
  1101. else
  1102. {
  1103. $rs = safe_row('section, url_title', 'textpattern', "id = ".doSlash($id));
  1104. if (!count($rs))
  1105. {
  1106. $url = 'chriloi:'.$id;
  1107. }
  1108. else
  1109. {
  1110. $url = hu.'/'.@$rs['section'].'/'.@$rs['url_title'].$fragment; // make section_title link
  1111. }
  1112. }
  1113. return 'href="'.$url.'"';
  1114. }
  1115. if (@$s == 'default') unset($s);
  1116. // Some TxP tags, e.g. <txp:feed_link /> use 'section' or 'category' inconsistent
  1117. // with most other tags. Process these now so we only have to check $s and $c.
  1118. if (@$section && !$s) $s = $section;
  1119. if (@$category && !$c) $c = $category;
  1120. /*
  1121. if (@$pretext['permlink_override']) {
  1122. $override_ids = explode(',', $pretext['permlink_override']);
  1123. foreach ($override_ids as $override_id) {
  1124. $pl = $this->get_permlink($override_id);
  1125. if (count($pl) > 0) $permlinks[] = $pl;
  1126. }
  1127. }
  1128. if (empty($permlinks)) {
  1129. $permlinks = $this->get_all_permlinks(1);
  1130. $permlinks['gbp_permanent_links_default'] = array(
  1131. 'components' => array(
  1132. array('type' => 'text', 'text' => strtolower(urlencode(gTxt('category')))),
  1133. array('type' => 'category'),
  1134. ),
  1135. 'settings' => array(
  1136. 'pl_name' => 'gbp_permanent_links_default', 'pl_precedence' => '', 'pl_preview' => '',
  1137. 'con_section' => '', 'con_category' => '', 'des_section' => '', 'des_category' => '',
  1138. 'des_permlink' => '', 'des_feed' => '', 'des_location' => '',
  1139. ));
  1140. }
  1141. $highest_match_count = null;
  1142. foreach ($permlinks as $key => $pl) {
  1143. $this->buffer_debug[] = 'Testing permlink: '. $pl['settings']['pl_name'] .' - '. $key;
  1144. $this->buffer_debug[] = 'Preview: '. $pl['settings']['pl_preview'];
  1145. $out = array(); $match_count = 0;
  1146. foreach ($pl['components'] as $pl_c) {
  1147. switch ($pl_c['type']) {
  1148. case 'text':
  1149. $out[] = $pl_c['text'];
  1150. $match_count--;
  1151. break;
  1152. case 'regex':
  1153. $out[] = $pretext['permlink_regex_'.$pl_c['name']];
  1154. $match_count--;
  1155. break;
  1156. case 'section':
  1157. if (@$s) $out[] = $s;
  1158. else break 2;
  1159. break;
  1160. case 'category':
  1161. if (@$c) $out[] = $c;
  1162. else break 2;
  1163. break;
  1164. case 'feed':
  1165. if (@$rss) $out[] = 'rss';
  1166. else if (@$atom) $out[] = 'atom';
  1167. else break 2;
  1168. break;
  1169. case 'search':
  1170. if (@$q) $out[] = $q;
  1171. else break 2;
  1172. break;
  1173. default: break 2;
  1174. }
  1175. if (!in_array($pl_c['type'], array('title', 'id')))
  1176. $match_count++;
  1177. else break;
  1178. }
  1179. $this->buffer_debug[] = 'Match count: '. $match_count;
  1180. // Todo: Store according to the precedence value
  1181. if (count($out) > 0 && ($match_count > $highest_match_count || !isset($highest_match_count)) &&
  1182. !($key == 'gbp_permanent_links_default' && !$match_count)) {
  1183. extract($pl['settings']);
  1184. if ((empty($s) && empty($c)) ||
  1185. (empty($con_section) || @$s == $con_section) ||
  1186. (empty($con_category) || @$c == $con_category)) {
  1187. $this->buffer_debug[] = 'New highest match! '. implode('/', $out);
  1188. $highest_match_count = $match_count;
  1189. $match = $out;
  1190. }
  1191. }
  1192. }
  1193. if (empty($match) && (!(@$pg && $this->pref('clean_page_archive_links')) || (@$pg && @$q))) {
  1194. global $prefs, $pretext, $permlink_mode;
  1195. $this->buffer_debug[] = 'No match';
  1196. $this->buffer_debug[] = '----';
  1197. $pretext['permlink_mode'] = $permlink_mode = $prefs['permlink_mode'];
  1198. $url = pagelinkurl($query_part);
  1199. $pretext['permlink_mode'] = $permlink_mode = 'messy';
  1200. return 'href="'. $url .'"';
  1201. }
  1202. $this->buffer_debug[] = serialize($match);
  1203. $url = '/'.join('/', $match);
  1204. $url = rtrim(hu, '/').rtrim($url, '/').'/';
  1205. if ($rss)
  1206. $url .= 'rss';
  1207. else if ($atom)
  1208. $url .= 'atom';
  1209. else if ($this->pref('clean_page_archive_links') && $pg)
  1210. $url .= $pg;
  1211. else if ($pg) {
  1212. $url .= '?pg='. $pg;
  1213. $omit_trailing_slash = true;
  1214. }
  1215. $url = rtrim($url, '/') . '/';
  1216. if (@$omit_trailing_slash || $this->pref('omit_trailing_slash'))
  1217. $url = rtrim($url, '/');
  1218. $this->buffer_debug[] = $url;
  1219. $this->buffer_debug[] = '----';
  1220. if ($path == 'index.php' && $url != hu)
  1221. return 'href="'. $url . $fragment .'"';
  1222. /*
  1223. 1 = index, textpattern/css, NULL (=index)
  1224. 2 = id, s, section, c, category, rss, atom, pg, q, (n, p, month, author)
  1225. */
  1226. return $parts[0];
  1227. }
  1228. # --- END PLUGIN CODE ---
  1229. if (0) {
  1230. ?>
  1231. <!--
  1232. # --- BEGIN PLUGIN HELP ---
  1233. # --- END PLUGIN HELP ---
  1234. -->
  1235. <?php
  1236. }
  1237. ?>