1<?php 2/** 3 * 4 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 5 * @author Andreas Gohr <andi@splitbrain.org> 6 */ 7// must be run within Dokuwiki 8if(!defined('DOKU_INC')) die(); 9require_once(DOKU_PLUGIN.'syntax.php'); 10 11class syntax_plugin_semanticdata_entry extends DokuWiki_Syntax_Plugin { 12 13 /** 14 * will hold the data helper plugin 15 */ 16 var $dthlp = null; 17 18 /** 19 * Constructor. Load helper plugin 20 */ 21 function syntax_plugin_semanticdata_entry(){ 22 $this->dthlp =& plugin_load('helper', 'semanticdata'); 23 if(!$this->dthlp) msg('Loading the data helper failed. Make sure the semanticdata plugin is installed.',-1); 24 } 25 26 /** 27 * What kind of syntax are we? 28 */ 29 function getType(){ 30 return 'substition'; 31 } 32 33 /** 34 * What about paragraphs? 35 */ 36 function getPType(){ 37 return 'block'; 38 } 39 40 /** 41 * Where to sort in? 42 */ 43 function getSort(){ 44 return 155; 45 } 46 47 /** 48 * Connect pattern to lexer 49 */ 50 function connectTo($mode) { 51 $this->Lexer->addSpecialPattern('----+ *dataentry(?: [ a-zA-Z0-9_]*)?-+\n.*?\n----+',$mode,'plugin_semanticdata_entry'); 52 } 53 54 /** 55 * Handle the match - parse the data 56 */ 57 function handle($match, $state, $pos, &$handler){ 58 // get lines 59 $lines = explode("\n",$match); 60 array_pop($lines); 61 $class = array_shift($lines); 62 $class = str_replace('dataentry','',$class); 63 $class = trim($class,'- '); 64 65 // parse info 66 $data = array(); 67 $meta = array(); 68 foreach ( $lines as $line ) { 69 // ignore comments 70 preg_match('/^(.*?(?<![&\\\\]))(?:#(.*))?$/',$line, $matches); 71 $line = $matches[1]; 72 $line = str_replace('\\#','#',$line); 73 $line = trim($line); 74 if(empty($line)) continue; 75 $line = preg_split('/\s*:\s*/',$line,2); 76 77 $column = $this->dthlp->_column($line[0]); 78 if (isset($matches[2])) $column['comment'] = $matches[2]; 79 if($column['multi']){ 80 if(!isset($data[$column['key']])) { 81 // init with empty array 82 // Note that multiple occurrences of the field are 83 // practically merged 84 $data[$column['key']] = array(); 85 } 86 $vals = explode(',',$line[1]); 87 foreach($vals as $val){ 88 $val = trim($this->dthlp->_cleanData($val,$column['type'])); 89 if($val == '') continue; 90 if(!in_array($val,$data[$column['key']])) $data[$column['key']][] = $val; 91 } 92 }else{ 93 $data[$column['key']] = $this->dthlp->_cleanData($line[1],$column['type']); 94 } 95 $columns[$column['key']] = $column; 96 } 97 return array('data'=>$data, 'cols'=>$columns, 'classes'=>$class, 98 'pos' => $pos, 'len' => strlen($match)); // not utf8_strlen 99 } 100 101 /** 102 * Create output or save the data 103 */ 104 function render($format, &$renderer, $data) { 105 global $ID; 106 switch ($format){ 107 case 'xhtml': 108 $this->_showData($data,$renderer); 109 return true; 110 case 'metadata': 111 $this->_saveData($data,$ID,$renderer->meta['title']); 112 return true; 113 case 'plugin_semanticdata_edit': 114 $this->_editData($data, $renderer); 115 return true; 116 default: 117 return false; 118 } 119 } 120 121 /** 122 * Output the data in a table 123 */ 124 function _showData($data,&$R){ 125 global $ID; 126 $ret = ''; 127 128 if (method_exists($R, 'startSectionEdit')) { 129 $data['classes'] .= ' ' . $R->startSectionEdit($data['pos'], 'plugin_semanticdata'); 130 } 131 $ret .= '<div class="inline dataplugin_entry '.$data['classes'].'"><dl>'; 132 foreach($data['data'] as $key => $val){ 133 if($val == '' || !count($val)) continue; 134 $type = $data['cols'][$key]['type']; 135 if (is_array($type)) $type = $type['type']; 136 switch ($type) { 137 case 'pageid': 138 $type = 'title'; 139 case 'wiki': 140 $val = $ID . '|' . $val; 141 break; 142 } 143 144 $ret .= '<dt class="' . hsc($key) . '">'.hsc($data['cols'][$key]['title']).'<span class="sep">: </span></dt>'; 145 if(is_array($val)){ 146 $cnt = count($val); 147 for ($i=0; $i<$cnt; $i++){ 148 $ret .= '<dd class="' . hsc($key) . '">'; 149 $ret .= $this->dthlp->_formatData($data['cols'][$key], $val[$i],$R); 150 if($i < $cnt - 1) $ret .= '<span class="sep">, </span>'; 151 $ret .= '</dd>'; 152 } 153 }else{ 154 $ret .= '<dd class="' . hsc($key) . '">'. 155 $this->dthlp->_formatData($data['cols'][$key], $val, $R).'</dd>'; 156 } 157 } 158 $ret .= '</dl></div>'; 159 $R->doc .= $ret; 160 if (method_exists($R, 'finishSectionEdit')) { 161 $R->finishSectionEdit($data['len'] + $data['pos']); 162 } 163 } 164 165 /** 166 * Save date to the triple store 167 */ 168 function _saveData($data,$id,$title){ 169 $store = $this->dthlp->_getTripleStore(); 170 $resultFormat = phpSesame::SPARQL_XML; 171 $lang = "sparql"; 172 $infer = true; 173 174 if(!$store) return false; 175 176 $error = ''; 177 if(!$title) $title = $id; 178 179 $class = $data['classes']; 180 181 // delete all data from this page 182 $sparql = 183 sprintf('DELETE DATA { <%s%s> ?s ?o }',$this->getConf('base_url'),urlencode($id)); 184 $result = $store->update($sparql, $resultFormat, $lang, $infer); 185 186 187 // add page information 188 $sparql = 189 "PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>" . 190 sprintf("PREFIX spd:<%s> ",$this->getConf('base_url')) . 191 "INSERT DATA " . 192 sprintf("{ <%s%s> rdfs:label \"%s\" ; spd:hastitle \"%s\" ; spd:class \"%s\" . }",$this->getConf('base_url'),urlencode($id),$id,$title,$class); 193 $result = $store->update($sparql, $resultFormat, $lang, $infer); 194 195 // note, it should be possible to delete and update in a single query <<TODO>> 196 197 // insert new data 198 foreach ($data['data'] as $key => $val){ 199 if(is_array($val)) foreach($val as $v){ 200 $sparql = 201 sprintf("PREFIX spd:<%s> ",$this->getConf('base_url')) . 202 'INSERT DATA ' . 203 sprintf('{ <%s%s> <%s%s> "%s" . }',$this->getConf('base_url'),urlencode($id),$this->getConf('base_url'),urlencode($key),$v); 204 $result = $store->update($sparql, $resultFormat, $lang, $infer); 205 }else { 206 $sparql = 207 sprintf("PREFIX spd:<%s> ",$this->getConf('base_url')) . 208 'INSERT DATA ' . 209 sprintf('{ <%s%s> <%s%s> "%s" . }',$this->getConf('base_url'),urlencode($id),$this->getConf('base_url'),urlencode($key),$val); 210 $result = $store->update($sparql, $resultFormat, $lang, $infer); 211 } 212 } 213 214 return true; 215 } 216 217 function _editData($data, &$renderer) { 218 $renderer->form->startFieldset($this->getLang('dataentry')); 219 $renderer->form->_content[count($renderer->form->_content) - 1]['class'] = 'plugin__data'; 220 221 if ($this->getConf('edit_content_only')) { 222 $renderer->form->addHidden('data_edit[classes]', $data['classes']); 223 $renderer->form->addElement('<table>'); 224 } else { 225 $renderer->form->addElement(form_makeField('text', 'data_edit[classes]', $data['classes'], $this->getLang('class'), 'data__classes')); 226 $renderer->form->addElement('<table>'); 227 228 $text = '<tr>'; 229 foreach(array('title', 'type', 'multi', 'value', 'comment') as $val) { 230 $text .= '<th>' . $this->getLang($val) . '</th>'; 231 } 232 $renderer->form->addElement($text . '</tr>'); 233 234 // New line 235 $data['data'][''] = ''; 236 $data['cols'][''] = array('type' => '', 'multi' => false); 237 } 238 239 $n = 0; 240 foreach($data['cols'] as $key => $vals) { 241 $fieldid = 'data_edit[data][' . $n++ . ']'; 242 $content = $vals['multi'] ? implode(', ', $data['data'][$key]) : $data['data'][$key]; 243 if (is_array($vals['type'])) { 244 $vals['basetype'] = $vals['type']['type']; 245 if (isset($vals['type']['enum'])) { 246 $vals['enum'] = $vals['type']['enum']; 247 } 248 $vals['type'] = $vals['origtype']; 249 } else { 250 $vals['basetype'] = $vals['type']; 251 } 252 $renderer->form->addElement('<tr>'); 253 if ($this->getConf('edit_content_only')) { 254 if (isset($vals['enum'])) { 255 $values = preg_split('/\s*,\s*/', $vals['enum']); 256 if (!$vals['multi']) array_unshift($values, ''); 257 $content = form_makeListboxField($fieldid . '[value][]', $values, 258 $data['data'][$key], $vals['title'], '', '', ($vals['multi'] ? array('multiple' => 'multiple'): array())); 259 } else { 260 $classes = 'data_type_' . $vals['type'] . ($vals['multi'] ? 's' : '') . ' ' . 261 'data_type_' . $vals['basetype'] . ($vals['multi'] ? 's' : ''); 262 $content = form_makeField('text', $fieldid . '[value]', $content, $vals['title'], '', $classes); 263 264 } 265 $cells = array($vals['title'] . ':', 266 $content, 267 $vals['comment']); 268 foreach(array('title', 'multi', 'comment', 'type') as $field) { 269 $renderer->form->addHidden($fieldid . "[$field]", $vals[$field]); 270 } 271 } else { 272 $check_data = $vals['multi'] ? array('checked' => 'checked') : array(); 273 $cells = array(form_makeField('text', $fieldid . '[title]', $vals['title'], $this->getLang('title')), 274 form_makeMenuField($fieldid . '[type]', 275 array_merge(array('', 'page', 'nspage', 'title', 276 'mail', 'url', 'tag', 'wiki', 'dt'), 277 array_keys($this->dthlp->_aliases())), 278 $vals['type'], 279 $this->getLang('type')), 280 form_makeCheckboxField($fieldid . '[multi]', array('1', ''), $this->getLang('multi'), '', '', $check_data), 281 form_makeField('text', $fieldid . '[value]', $content, $this->getLang('value')), 282 form_makeField('text', $fieldid . '[comment]', $vals['comment'], $this->getLang('comment'), '', 'data_comment', array('readonly' => 1))); 283 } 284 foreach($cells as $cell) { 285 $renderer->form->addElement('<td>'); 286 $renderer->form->addElement($cell); 287 $renderer->form->addElement('</td>'); 288 } 289 $renderer->form->addElement('</tr>'); 290 } 291 292 $renderer->form->addElement('</table>'); 293 $renderer->form->endFieldset(); 294 } 295 296 function _normalize($txt) { 297 return str_replace('#', '\#', trim($txt)); 298 } 299 300 public static function editToWiki($data) { 301 $nudata = array(); 302 $len = 0; 303 foreach ($data['data'] as $field) { 304 if ($field['title'] === '') continue; 305 $s = syntax_plugin_semanticdata_entry::_normalize($field['title']); 306 if (trim($field['type']) !== '' || 307 (substr($s, -1, 1) === 's' && $field['multi'] === '')) { 308 $s .= '_' . syntax_plugin_semanticdata_entry::_normalize($field['type']); 309 } 310 if ($field['multi'] === '1') { 311 $s .= 's'; 312 } 313 if (is_array($field['value'])) { 314 $field['value'] = join(', ', $field['value']); 315 } 316 317 $nudata[] = array($s, syntax_plugin_semanticdata_entry::_normalize($field['value']), 318 isset($field['comment']) ? trim($field['comment']) : ''); 319 $len = max($len, utf8_strlen($nudata[count($nudata) - 1][0])); 320 } 321 322 $ret = '---- dataentry ' . trim($data['classes']) . ' ----' . DOKU_LF; 323 foreach ($nudata as $field) { 324 $ret .= $field[0] . str_repeat(' ', $len + 1 - utf8_strlen($field[0])) . ': ' . 325 $field[1]; 326 if ($field[2] !== '') { 327 $ret .= ' #' . $field[2]; 328 } 329 $ret .= DOKU_LF; 330 } 331 $ret .= '----'; 332 return $ret; 333 } 334} 335