1<?php
2/**
3 * DokuWiki Plugin strata (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Brend Wanders <b.wanders@utwente.nl>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die('Meh.');
11
12/**
13 * This utility helper offers methods for configuration handling
14 * type and aggregator loading, and rendering.
15 */
16class helper_plugin_strata_util extends DokuWiki_Plugin {
17    /**
18     * Constructor.
19     */
20    function __construct() {
21        // we can't depend on the syntax helper due to recursive dependencies.
22        // Since we really only need the pattern helper anyway, we grab it
23        // directly. (This isn't the nicest solution -- but depending on
24        // a helper that depends on us isn't either)
25        $this->patterns = helper_plugin_strata_syntax::$patterns;
26    }
27
28    function getMethods() {
29        $result = array();
30        return $result;
31    }
32
33    /**
34     * The loaded types and aggregates cache.
35     */
36    var $loaded = array();
37
38    /**
39     * Loads something.
40     */
41    private function _load($kind, $name, $default) {
42        // handle null value
43        if($name == null) {
44            $name = $default;
45        }
46
47        // use cache if possible
48        if(empty($this->loaded[$kind][$name])) {
49            $class = "plugin_strata_${kind}_${name}";
50            $this->loaded[$kind][$name] = new $class();
51        }
52
53        return $this->loaded[$kind][$name];
54
55    }
56
57    /**
58     * Loads a type.
59     */
60    function loadType($type) {
61        list($default,) = $this->getDefaultType();
62        return $this->_load('type', $type, $default);
63    }
64
65    /**
66     * Loads an aggregate.
67     */
68    function loadAggregate($aggregate) {
69        return $this->_load('aggregate', $aggregate, 'all');
70    }
71
72    /**
73     * Parses a 'name(hint)' pattern.
74     *
75     * @param string string the text to parse
76     * @return an array with a name and hint, or false
77     */
78    function parseType($string) {
79        $p = $this->patterns;
80        if(preg_match("/^({$p->type})?$/", $string, $match)) {
81            list($type, $hint) = $p->type($match[1]);
82            return array($type, $hint);
83        } else {
84            return false;
85        }
86    }
87
88    /**
89     * The parsed configuration types.
90     */
91    var $configTypes = array();
92
93    /**
94     * Parses a type from configuration.
95     */
96    function _parseConfigType($key) {
97        // lazy parse
98        if(empty($this->configTypes[$key])) {
99            // parse
100            $this->configTypes[$key] = $this->parseType($this->getConf($key));
101
102            // handle failed parse
103            if($this->configTypes[$key] === false) {
104                msg(sprintf($this->getLang('error_types_config'), $key), -1);
105                $this->configTypes[$key] = array(
106                    'text',
107                    null
108                );
109            }
110        }
111
112        return $this->configTypes[$key];
113    }
114
115    /**
116     * Returns the default type.
117     */
118    function getDefaultType() {
119        return $this->_parseConfigType('default_type');
120    }
121
122    /**
123     * Returns the type used for predicates.
124     */
125    function getPredicateType() {
126        return $this->_parseConfigType('predicate_type');
127    }
128
129    /**
130     * Returns the normalized value for the 'is a' predicate.
131     */
132    function getIsaKey($normalized=true) {
133        $result = $this->getConf('isa_key');
134        if($normalized) $result = $this->normalizePredicate($result);
135        return $result;
136    }
137
138    /**
139     * Returns the normalized valued for the 'title' predicate.
140     */
141    function getTitleKey($normalized=true) {
142        $result = $this->getConf('title_key');
143        if($normalized) $result = $this->normalizePredicate($result);
144        return $result;
145    }
146
147    /**
148     * Normalizes a predicate.
149     *
150     * @param p the string to normalize
151     */
152    function normalizePredicate($p) {
153        list($type, $hint) = $this->getPredicateType();
154        return $this->loadType($type)->normalize($p, $hint);
155    }
156
157    /**
158     * Renders a predicate as a full field.
159     *
160     * @param mode the rendering mode
161     * @param R the renderer
162     * @param T the triples helper
163     * @param p the predicate
164     */
165    function renderPredicate($mode, &$R, &$T, $p) {
166        list($typename, $hint) = $this->getPredicateType();
167        $this->renderField($mode, $R, $T, $p, $typename, $hint);
168    }
169
170    /**
171     * Renders a single value. If the mode is xhtml, this also surrounds the value with
172     * the necessary <span> tag to allow styling of types and to ease extraction of values
173     * with javascript.
174     *
175     * @param mode the rendering mode
176     * @param R the renderer
177     * @param T the triples helper
178     * @param value the value to render
179     * @param typename name of the type
180     * @param hint optional type hint
181     * @param type optional type object, if omitted the typename will be used to get the type
182     */
183    function renderValue($mode, &$R, &$T, $value, $typename, $hint=null, &$type=null) {
184        // load type if needed
185        if($type == null)  $type = $this->loadType($typename);
186
187        // render value
188        $this->openValue($mode, $R, $typename);
189        $type->render($mode, $R, $T, $value, $hint);
190        $this->closeValue($mode, $R);
191    }
192
193    /**
194     * Renders multiple values. If the mode is xhtml, this also surrounds the field with
195     * the necessary <span> tag to allow styling of fields and to ease extraction of values
196     * with javascript.
197     *
198     * @param mode the rendering mode
199     * @param R the renderer
200     * @param T the triples helper
201     * @param values a list of values to render, or optionally a single value
202     * @param typename the name of the type
203     * @param hint optional type hint
204     * @param type optional type object, if omitted typename will be used
205     * @param field the field name of this field
206     * @param separator the seperation string to use in-between values
207     */
208    function renderField($mode, &$R, &$T, $values, $typename, $hint=null, &$type=null, $field=null, $separator=', ') {
209        // arrayfication of values (if a single value is given)
210        if(!is_array($values)) $values = array($values);
211
212        // load type if needed
213        if($type == null) $type = $this->loadType($typename);
214
215        // render values
216        $firstValue = true;
217        $this->openField($mode, $R, $field);
218        foreach($values as $value) {
219            if(!$firstValue) $R->cdata($separator);
220            $this->renderValue($mode, $R, $T, $value, $typename, $hint, $type);
221            $firstValue = false;
222        }
223        $this->closeField($mode, $R);
224    }
225
226    function openField($mode, &$R, $field=null) {
227        if($mode == 'xhtml') $R->doc .= '<span class="strata-field" '.(!empty($field)?'data-field="'.hsc($field).'"':'').'>';
228    }
229
230    function closeField($mode, &$R) {
231        if($mode == 'xhtml') $R->doc .= '</span>';
232    }
233
234    function openValue($mode, &$R, $typename) {
235        if($mode == 'xhtml') $R->doc .= '<span class="strata-value strata-type-'.$typename.'">';
236    }
237
238    function closeValue($mode, &$R) {
239        if($mode == 'xhtml') $R->doc .= '</span>';
240    }
241
242    function renderCaptions($mode, &$R, $fields) {
243        if($mode == 'xhtml') {
244            foreach($fields as $f) {
245                $R->doc .= '<div class="strata-caption hidden" data-field="'.hsc($f['variable']).'">';
246                $R->cdata($f['caption']);
247                $R->doc .= '</div>'.DOKU_LF;
248            }
249        }
250    }
251}
252