1<?php
2/**
3 * DokuWiki Plugin tagfilter (Syntax Component)
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author  lisps
7 */
8
9/*
10 * All DokuWiki plugins to extend the parser/rendering mechanism
11 * need to inherit from this class
12 */
13class syntax_plugin_tagfilter_filter extends DokuWiki_Syntax_Plugin {
14
15    private $_itemPos = array();
16    function incItemPos() {
17        global $ID;
18        if(array_key_exists($ID,$this->_itemPos)) {
19            return $this->_itemPos[$ID]++;
20        } else {
21            $this->_itemPos[$ID] = 1;
22            return 0;
23        }
24    }
25    function getItemPos(){
26        global $ID;
27        if(array_key_exists($ID,$this->_itemPos)) {
28            $this->_itemPos[$ID];
29        } else {
30            return 0;
31        }
32    }
33
34    /*
35     * What kind of syntax are we?
36     */
37    function getType() {return 'substition';}
38
39    /*
40     * Where to sort in?
41     */
42    function getSort() {return 155;}
43
44    /*
45     * Paragraph Type
46     */
47    function getPType(){return 'block';}
48
49    /*
50     * Connect pattern to lexer
51     */
52    function connectTo($mode) {
53		$this->Lexer->addSpecialPattern("\{\{tagfilter>.*?\}\}",$mode,'plugin_tagfilter_filter');
54	}
55
56    /*
57     * Handle the matches
58     */
59    function handle($match, $state, $pos, Doku_Handler $handler) {
60		global $ID;
61		$HtagfilterSyntax = $this->loadHelper('tagfilter_syntax');
62		$opts['id']=$this->incItemPos();
63
64		$match=trim(substr($match,12,-2));
65
66        list($match, $flags) = explode('&', $match, 2);
67        $flags = explode('&', $flags);
68        list($ns, $tag) = explode('?', $match);
69
70        if (!$tag) {
71            $tag = $ns;
72            $ns   = '';
73        }
74
75        if (($ns == '*') || ($ns == ':')) $ns = '';
76        elseif ($ns == '.') $ns = getNS($ID);
77        else $ns = cleanID($ns);
78
79		$opts['ns']=$ns;
80
81		//only flags for tagfilter
82		$opts['tfFlags'] = $HtagfilterSyntax->parseFlags($flags);
83
84		//all flags for pagelist plugin
85		$opts['flags']=array_map('trim',$flags);
86
87		//read and parse tag
88		$tagselect_r = array();
89		$select_expr_r = array_map('trim',explode('|',$tag));
90		foreach($select_expr_r as $key=>$usr_syntax){
91			$usr_syntax = explode("=",$usr_syntax);//aufsplitten in Label,RegExp,DefaultWert
92
93			$tagselect_r['label'][$key]  = trim($usr_syntax[0]);
94			$tagselect_r['tag_expr'][$key]  = trim($usr_syntax[1]);
95			$tagselect_r['selectedTags'][$key] = isset($usr_syntax[2])?explode(' ',$usr_syntax[2]):array();
96		}
97
98		$opts['tagselect_r'] = $tagselect_r;
99
100		return ($opts);
101    }
102
103    /*
104     * Create output
105     */
106    function render($mode, Doku_Renderer $renderer, $opt)
107	{
108		global $INFO;
109		global $ID;
110		global $INPUT;
111		global $USERINFO;
112		global $conf;
113		/* @var  $HtagfilterSyntax helper_plugin_tagfilter_syntax */
114		$HtagfilterSyntax = $this->loadHelper('tagfilter_syntax');
115		$flags = $opt['tfFlags'];
116
117		if($mode === 'metadata') return false;
118		if($mode === 'xhtml') {
119			$renderer->info['cache'] = false;
120
121			/* @var $Htagfilter helper_plugin_tagfilter */
122			$Htagfilter = $this->loadHelper('tagfilter');
123			$renderer->cdata("\n");
124
125
126			$depends = array('files'=>array(
127				$INFO['filepath'],
128				DOKU_CONF . '/acl.auth.php',
129				getConfigFiles('main'),
130			));
131
132			if($flags['cache']){
133				$depends['age']=$flags['cache'];
134			} else if($flags['cache'] === false){
135				//build cache dependencies
136				$dir  = utf8_encodeFN(str_replace(':','/',$opt['ns']));
137				$data = array();
138				search($data,$conf['datadir'],array($HtagfilterSyntax,'search_all_pages'),array('ns' => $opt['ns'],'excludeNs'=>$flags['excludeNs']),$dir); //all pages inside namespace
139				$depends['files'] = array_merge($depends['files'],$data);
140			} else {
141				$depends['purge'] = true;
142			}
143
144			$cache_key = 'plugin_tagfilter_'.$ID . '_' . $opt['id'];
145			$cache = new cache($cache_key, '.tcache');
146			if(!$cache->useCache($depends)) {
147				$cachedata = $HtagfilterSyntax->getTagPageRelations($opt);
148				$cachedata[] = $HtagfilterSyntax->prepareList($cachedata[1],$flags);
149				$cache->storeCache(serialize($cachedata));
150			} else {
151				$cachedata = unserialize($cache->retrieveCache());
152			}
153
154			list($tagselect_r, $pageids, $preparedPages) = $cachedata;
155
156			$cache_u_key = 'plugin_tagfilter_'.$ID . '_' . $opt['id'] . '_' . $_SERVER['REMOTE_USER'].$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
157			$cache_u = new cache($cache_u_key, '.tucache');
158
159			foreach($pageids as &$pageid) {
160				if(!page_exists($pageid)) {
161					unset($pageid);
162					$cache->removeCache();
163					$cache_u->removeCache();
164				}
165			} unset($pageid);
166
167			if(!$cache_u->useCache(array('files'=>array($cache->cache)))) {
168				$output = '';
169
170				//check for read access
171				foreach($pageids as $key=>$pageid) {
172					if(! $Htagfilter->canRead($pageid)) {
173						unset($pageids[$key]);
174					}
175				}
176
177				//check tags for visibility
178				foreach($tagselect_r['tagPages'] as &$select_r) {
179				    if(!is_array($select_r)) $select_r = array();
180					foreach($select_r as $tag=>$pageid_r) {
181						if(count(array_intersect(($pageid_r), $pageids)) == 0) {
182							unset($select_r[$tag]);
183						}
184					}
185				}
186
187				foreach($preparedPages as $key=>$page) {
188					if(!in_array($page['id'],$pageids)) {
189						unset($preparedPages[$key]);
190					}
191				}
192
193				$form = new Doku_Form(array(
194					'id'=>'tagdd_'.$opt['id'],
195					'data-idx'=>$opt['id'],
196					'data-plugin'=>'tagfilter',
197					'data-tags' => json_encode($tagselect_r['tagPages']),
198				));
199				$output .= "\n";
200				//Fieldset manuell hinzufügen da ein style Parameter übergeben werden soll
201				$form->addElement(array(
202						'_elem'=>'openfieldset',
203						'_legend'=>'Tagfilter',
204						'style'=>'text-align:left;width:99%',
205						'id'=>'__tagfilter_'.$opt['id'],
206						'class'=>($flags['labels']!==false)?'':'hidelabel',
207
208				));
209				$form->_infieldset=true; //Fieldset starten
210
211				if($flags['pagesearch']){
212					$label = $flags['pagesearchlabel'];
213
214					$pagetitle_r = array();
215					foreach($pageids as $pageid) {
216						$pagetitle_r[$pageid] = $Htagfilter->getPageTitle($pageid);
217					}
218					asort($pagetitle_r, SORT_NATURAL|SORT_FLAG_CASE);
219
220					$selectedTags = array();
221					$id = '__tagfilter_page_'.$opt['id'];
222
223					$options = array(//generelle Optionen für DropDownListe onchange->submit von id namespace und den flags für pagelist
224						'onChange'=>'tagfilter_submit('.$opt['id'].','.json_encode($opt['ns']).','.json_encode(array($opt['flags'],$flags)).')',
225						'class'=>'tagdd_select tagfilter tagdd_select_'.$opt['id']  . ($flags['chosen']?' chosen':''),
226						'data-placeholder'=>hsc($label.' '.$this->getLang('choose')),
227						'data-label'=>hsc(utf8_strtolower(trim($label))),
228						);
229					if($flags['multi']){ //unterscheidung ob Multiple oder Single
230						$options['multiple']='multiple';
231						$options['size']=$this->getConf("DropDownList_size");
232					} else {
233						$options['size']=1;
234						$pagetitle_r = array_reverse($pagetitle_r,true);
235						$pagetitle_r['']='';
236						$pagetitle_r = array_reverse($pagetitle_r,true);
237					}
238					$form->addElement(form_makeListboxField($label, $pagetitle_r, $selectedTags , $label, $id, 'tagfilter', $options));
239				}
240				$output .= '<script type="text/javascript">/*<![CDATA[*/ var tagfilter_container = {}; /*!]]>*/</script>'."\n";
241				//$output .= '<script type="text/javascript">/*<![CDATA[*/ '.'tagfilter_container.tagfilter_'.$opt['id'].' = '.json_encode($tagselect_r['tags2']).'; /*!]]>*/</script>'."\n";
242				foreach($tagselect_r['tagPages'] as $key=>$pages){
243					$id=false;
244					$label = $tagselect_r['label'][$key];
245					$selectedTags = $tagselect_r['selectedTags'][$key];
246
247					//get tag labels
248					$tags = array();
249
250					foreach(array_keys($tagselect_r['tagPages'][$key]) as $tagid) {
251						$tags[$tagid] = $Htagfilter->getTagLabel($tagid);
252					}
253
254					foreach($selectedTags as &$item) {
255						$item = utf8_strtolower(trim($item));
256					} unset($item);
257
258
259					$options = array(//generelle Optionen für DropDownListe onchange->submit von id namespace und den flags für pagelist
260						'onChange'=>'tagfilter_submit('.$opt['id'].','.json_encode($opt['ns']).','.json_encode(array($opt['flags'],$flags)).')',
261						'class'=>'tagdd_select tagfilter tagdd_select_'.$opt['id'] . ($flags['chosen']?' chosen':''),
262						'data-placeholder'=>hsc($label.' '.$this->getLang('choose')),
263						'data-label'=>hsc(str_replace(' ','_',utf8_strtolower(trim($label)))),
264
265						);
266					if($flags['multi']){ //unterscheidung ob Multiple oder Single
267						$options['multiple']='multiple';
268						$options['size']=$this->getConf("DropDownList_size");
269					} else {
270						$options['size']=1;
271						$tags = array_reverse($tags,true);
272						$tags['']='';
273						$tags = array_reverse($tags,true);
274					}
275
276					if($flags['chosen']){
277						$links = array();
278						foreach($tags as $k=>$t){
279							$links[$k]=array(
280								'link'=>$Htagfilter->getImageLinkByTag($k),
281							);
282						}
283						$jsVar = 'tagfilter_jsVar_'.rand();
284						$output .= '<script type="text/javascript">/*<![CDATA[*/ tagfilter_container.'.$jsVar.' ='
285											.json_encode($links).
286											'; /*!]]>*/</script>'."\n";
287
288						$id='__tagfilter_'.$opt["id"].'_'.rand();
289
290						if($flags['tagimage']){
291						    $options['data-tagimage'] = $jsVar;
292						}
293
294					}
295					$form->addElement(form_makeListboxField($label, $tags, $selectedTags , $label, $id, 'tagfilter' , $options));
296				}
297
298				$form->addElement(form_makeButton('button','', $this->getLang('Delete filter'), array('onclick'=>'tagfilter_cleanform('.$opt['id'].',true)')));
299				if($flags['count']) {
300				    $form->addElement('<div class="tagfilter_count">'.$this->getLang('found_count').': ' . '<span class="tagfilter_count_number"></span></div>');
301				}
302				$form->endFieldset();
303				$output .= $form->getForm();//Form Ausgeben
304
305				$output.= "<div id='tagfilter_ergebnis_".$opt['id']."' class='tagfilter'>";
306				//dbg($opt['flags']);
307				$output .= $HtagfilterSyntax->renderList($preparedPages,$flags, $opt['flags']);
308				$output.= "</div>";
309
310				$cache_u->storeCache($output);
311
312			} else {
313				$output =$cache_u->retrieveCache();
314			}
315
316			$renderer->doc .= $output;
317		}
318		return true;
319	}
320
321
322
323}
324
325//Setup VIM: ex: et ts=4 enc=utf-8 :
326