1<?php
2/**
3 * Helper Component for the TwistieNav Plugin for Bootstrap 3 template
4 *
5 * @author   Simon DELAGE <sdelage@gmail.com>
6 * @license: CC Attribution-Share Alike 3.0 Unported <http://creativecommons.org/licenses/by-sa/3.0/>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_twistienav4bootstrap3 extends DokuWiki_Plugin {
13
14    protected $title_metadata   = array();
15    protected $exclusions       = array();
16    protected $nsignore         = array();
17
18    function build_titlemetafields() {
19        // Known plugins that set title and corresponding metadata keys
20        $this->title_metadata = array(
21            'croissant' => 'plugin_croissant_bctitle',
22            'pagetitle' => 'shorttitle',
23        );
24        foreach (array_keys($this->title_metadata) as $plugin) {
25            if(plugin_isdisabled($plugin)) unset($this->title_metadata[$plugin]);
26        }
27        $this->title_metadata['dokuwiki'] = 'title';
28        return $this->title_metadata;
29    }
30
31    function build_exclusions() {
32        global $conf;
33
34        // Convert "exclusions" config setting to array
35        foreach (explode(',', $this->getConf('exclusions')) as $exclusion) {
36            if (substr($exclusion, 0, 1) === '@') {
37                $this->nsignore[] = ltrim($exclusion, "@");
38            } else {
39                switch ($exclusion) {   // care pre-defined keys in multicheckbox
40                    case 'start':
41                        $this->exclusions[] = $conf['start'];
42                        break;
43                    case 'sidebar':
44                        $this->exclusions[] = $conf['sidebar'];
45                        break;
46                    default:
47                        $this->exclusions[] = $exclusion;
48                }
49            }
50        }
51        return array($this->exclusions, $this->nsignore);
52    }
53
54    /**
55     * Build a namespace index (list sub-namespaces and pages).
56     *
57     * @param (str)     $idx namespace ID, must not be a page ID.
58     *                  Could be provided with : cleanID(getNS($ID))
59     * @param (bool)    $useexclusions use `exclusions` setting or not
60     * @param (bool)    $split return a simple level or more complex array
61     * @return (arr)    list of sub namespaces and pages found within $idx namespace
62     *
63     * See https://www.dokuwiki.org/plugin:twistienav?do=draft#helper_component for details
64     *
65     */
66    function get_idx_data($idx = null, $useexclusions = true, $split = false) {
67        global $conf, $ID;
68        // From an ajax call (ie. a click on a TwistieNav), $ID value isn't available so we need to get it from another way
69        $ajaxId = ltrim(explode("id=", $_SERVER["HTTP_REFERER"])[1], ":");
70
71        $dir  = utf8_encodeFN(str_replace(':','/',$idx));
72        $data = array();
73        search($data,$conf['datadir'],'search_index',array('ns' => $idx),$dir);
74
75        if (count($data) != 0) {
76            foreach ($data as $datakey => $item) {
77                // Unset item if is in 'exclusions'
78                if (($useexclusions) && (in_array(noNS($item['id']), $this->exclusions))) {
79                    unset($data[$datakey]);
80                    continue;
81                // Unset item if it is in 'nsignore'
82                } elseif (($useexclusions) && (in_array(explode(":", $item['id'])[0], $this->nsignore))) {
83                    unset($data[$datakey]);
84                    continue;
85                // Unset item if it starts with "playground" or is equal to current $ID
86                } elseif ((explode(":", $item['id'])[0] == "playground") or ($item['id'] == $ID) or ($item['id'] == $ajaxId)) {
87                    unset($data[$datakey]);
88                    continue;
89                }
90                // If item is a directory, we need an ID that points to that namespace's start page (even if it doesn't exist)
91                if ($item['type'] == 'd') {
92                    $target = $item['id'].':'.$conf['start'];
93                    $classes = "is_ns ";
94                // Or just keep current item ID
95                } else {
96                    $target = $item['id'];
97                    $classes = "is_page ";
98                }
99                // Add (non-)existence class
100                if (page_exists($target)) {
101                    $classes .= "wikilink1";
102                } else {
103                    $classes .= "wikilink2";
104                }
105                // Get page title from metadata
106                foreach ($this->title_metadata as $plugin => $pluginkey) {
107                    $title = p_get_metadata($target, $pluginkey, METADATA_DONT_RENDER);
108                    if ($title != null) break;
109                }
110                $data[$datakey]['id'] = $target;
111                $title = @$title ?: hsc(noNS($item['id']));
112                // Store a link to the page in the data that will be sent back
113                $data[$datakey]['link'] = '<a href="'.wl($target).'" class="'.$classes.'">'.$title.'</a>';
114            }
115        }
116        if ($split) {
117            $result = array();
118            $result['namespaces'] = array_values(array_filter($data, function ($row) {
119                return $row["type"] == "d";
120            }));
121            $result['pages'] = array_values(array_filter($data, function ($row) {
122                return $row["type"] == "f";
123            }));
124            return $result;
125        } else {
126            return array_values($data);
127        }
128    }
129
130}
131