1<?php
2/**
3 * DokuWiki Plugin Clipboard Utils
4 *
5 * @license	GPL 2 (http://www.gnu.org/licenses/gpl.html)*
6 * @author Jean-Marc Boulade <jean-marc@boulade.com>
7 * @version 2021-09-08
8 */
9
10// must be run within Dokuwiki
11if ( !defined( 'DOKU_INC' ) ) die();
12//dbglog(sprintf("LOADING '%s'\n",__FILE__));
13
14if ( !defined( 'DOKU_PLUGIN' ) ) define( 'DOKU_PLUGIN', DOKU_INC.'lib/plugins/' );
15require_once DOKU_PLUGIN.'syntax.php';
16
17class syntax_plugin_clipboardutils extends DokuWiki_Syntax_Plugin {
18	var $c;
19
20  function getType() { return 'substition';}
21  //function getPType() { return 'block';}
22  function getSort() { return 999; }
23
24	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
25  /**
26   * Ensure class initialisation.
27   */
28  public function assertInit() {
29		if (!is_array($this->c)) {
30			$this->c =array(
31				'url_icons' => 'lib/plugins/clipboardutils/images/'
32			);
33		}
34	}
35	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
36  /**
37   * Connect lookup pattern to lexer.
38   *
39   * @param string  $mode Parser mode
40   */
41  public function connectTo($mode) {
42		$this->assertInit();
43		//dbglog(sprintf("%s('%s')\n",__METHOD__,$mode));
44		$this->Lexer->addSpecialPattern('<(?:clipb?)\b.*?>.*?</clipb>', $mode, 'plugin_clipboardutils');
45  }
46	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
47  /**
48   * Handle matches of the clippy syntax
49   *
50   * @param string  $match   The match of the syntax
51   * @param int     $state   The state of the handler
52   * @param int     $pos     The position in the document
53   * @param Doku_Handler $handler The handler
54   * @return array Data for the renderer
55   */
56  public function handle($match, $state, $pos, Doku_Handler $handler) {
57		//dbglog(sprintf("%s('%s') %s\n",__METHOD__,$state,print_r($match,TRUE)));
58		$data =array('state' => $state, 'match' => $match, 'matchv' => htmlentities($match), 'pos' => $pos, 'att' => array());
59		if (preg_match('/<(?:clipb?)\b(.*?)>(.*?)<\/clipb>/s',$match,$m)) {
60			$data['m'] =$m;
61			$data['value'] =$m[2];
62			if (($str =trim($m[1])) != '') {
63				$data['att_string'] =$str;
64				foreach(preg_split('/[;\s]/',$str) as $el) {
65					if (preg_match('/(\w+)\s*[=:]\s*(.*)$/',trim($el),$m2)) {
66						$key =strtolower($m2[1]);
67						switch($key) {
68							case 't' : $key ='type'; break;
69							case 'f' : $key ='format'; break;
70							case 'i' : $key ='icon'; break;
71						}
72						$data['att'][$key] =$m2[2];
73					}
74				}
75			}
76		} else $data['error'] =TRUE;
77		if (!isset($data['att']['type'])) {
78			if (!empty($data['att']['format'])) $data['att']['type'] ='format';
79			else $data['att']['type'] =$this->getConf('defaultype');
80		}
81		return $data;
82  }
83	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
84	/**
85	 * For debug purpose
86	 */
87  public function debugArrayString($data, $level =0) {
88		$pad =str_pad('',$level*2,' ');
89		foreach($data as $key => $value) {
90			$str .=$pad . $key;
91			if (is_array($value)) {
92				$sep =str_pad('',80,'-');
93				$str .='   : IS an ARRAY :' . PHP_EOL . $sep . PHP_EOL;
94				$str .=$this->debugArrayString($value,$level+1) . $sep . PHP_EOL;;
95			} else {
96				$str .='   : "' . htmlentities($value) . '"' . PHP_EOL;
97			}
98		}
99		return $str;
100	}
101	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
102	/**
103	 * For debug purpose
104	 */
105  public function debugDataString($data) {
106		$str ='';
107		if (!is_array($data) || count($data) < 1) {
108			$str .='--- EMPTY VALUE ---' . PHP_EOL;
109		} else {
110			$str .=$this->debugArrayString($data);
111		}
112		return $str;
113	}
114	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
115	/**
116	 * Get icon url from $data
117	 *
118	 * @param array $data The original data from the handler() function
119	 * @return string with url of icon.
120	 */
121  public function GetIconFromData($data) {
122		$this->assertInit();
123		if (!empty($data['att']['icon'])) $icon =$data['att']['icon'];
124		else $icon =$this->getConf('icon');
125		if ($icon == '') $icon ='copy1.png';
126		if (strpos($icon,'.') === FALSE) $icon .='.png';
127		return $this->c['url_icons'] . $icon;
128	}
129	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
130	/**
131	 * Render a 'type' of output from $data
132	 *
133	 * @param array $data The original data from the handler() function
134	 * @param array $type Override the $data['type'].
135	 * @return string to add $renderer->doc.
136	 */
137  public function GetStringFromData(Doku_Renderer $renderer, $data, $type ='-') {
138		$str ='';
139		if ($type == '-') $type =(empty($data['att']['type'])) ? '' : $data['att']['type'];
140		$type =strtolower(trim($type));
141		switch($type) {
142			// Les types de base :
143			case 'c' :
144			case 'clic' : // Le texte que l'on clique pour le copier dans le presse papier.
145				$str .='<span class="clipu-c vclipu" data-clipboard-text="' . $data['value'] . '">' . $renderer->_xmlEntities($data['value']) .'</span>';
146				break;
147			case 'i' :
148			case 'icon' : // Une icone cliquable
149				$str .='<span class="bclipu"><img class="clipu-c bclipu" data-clipboard-text="' . $data['value'] . '" src="' . $this->GetIconFromData($data) . '"></span>';
150				break;
151			case 't' :
152			case 'text' : // le texte brut sans autre fonctionalités
153				$str .=$renderer->_xmlEntities($data['value']);
154				break;
155			case 'f' :
156			// LE type multiple :
157			case 'format' : // Un ensemble de formats
158				$f_str =(empty($data['att']['format'])) ? 'i' : $data['att']['format'];
159				if (strpos($f_str,',') !== FALSE) $formats =explode(',',$f_str);
160				else $formats =str_split($f_str);
161				$cpt_format =0;
162				foreach($formats as $format) {
163					$format =strtolower($format);
164					switch($format) {
165						case '' : // on évite un certain nombre de type non compatible.
166						case '-' :
167						case 'f' :
168						case 'f' :
169						case 'format' :
170							break;
171						default :
172							$value =$this->GetStringFromData($renderer,$data,$format);
173							if (!empty($value)) {
174								if ($cpt_format > 0) $str .=' ';
175								$str .=$value;
176								$cpt_format++;
177							}
178							break;
179					}
180				}
181				break;
182			// Les types composés :
183			case 'ti' :
184			case 'texticon' : // Le text avec l'icone cliquable.
185				$str .=$this->GetStringFromData($renderer,$data,'t') . ' ' . $this->GetStringFromData($renderer,$data,'i');
186				break;
187			case 'it' :
188			case 'icontext' : // L'icone cliquable d'abord et le text derrière.
189				$str .=$this->GetStringFromData($renderer,$data,'i') . ' ' . $this->GetStringFromData($renderer,$data,'t');
190				break;
191			case 'ci' :
192			case 'clicicon' : // Le textcliquable ET l'icone cliquable.
193				$str .=$this->GetStringFromData($renderer,$data,'c') . ' ' . $this->GetStringFromData($renderer,$data,'i');
194				break;
195			case 'ic' :
196			case 'iconclic' : // L'icone cliquable d'abord et le text derrière.
197				$str .=$this->GetStringFromData($renderer,$data,'i') . ' ' . $this->GetStringFromData($renderer,$data,'c');
198				break;
199			// Les types pour le debogage :
200			case 'debug' :
201				$str .='<pre>' . print_r($conf,TRUE) . '</pre>';
202				break;
203			case 'data' :
204				$str .= '<pre>'. $this->debugDataString($data) .'</pre>';
205				break;
206		}
207		return $str;
208	}
209	// -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
210	/**
211	 * Render xhtml output or metadata
212	 *
213	 * @param string $mode Renderer mode
214	 * @param Doku_Renderer $renderer The renderer
215	 * @param array $data The data from the handler() function
216	 * @return bool If rendering was successful.
217	 */
218  public function render($mode, Doku_Renderer $renderer, $data) {
219		global $conf;
220
221    if ( $mode != 'xhtml' ) return false;
222		if (!is_array($data) || !isset($data['state'])) return false;
223		$renderer->doc .=$this->GetStringFromData($renderer,$data,'-');
224    return true;
225  }
226}
227
228