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
11 if ( !defined( 'DOKU_INC' ) ) die();
12 //dbglog(sprintf("LOADING '%s'\n",__FILE__));
13 
14 if ( !defined( 'DOKU_PLUGIN' ) ) define( 'DOKU_PLUGIN', DOKU_INC.'lib/plugins/' );
15 require_once DOKU_PLUGIN.'syntax.php';
16 
17 class 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