14731b875SAndreas Gohr<?php 24731b875SAndreas Gohr/** 34731b875SAndreas Gohr * DokuWiki Plugin struct (Action Component) 44731b875SAndreas Gohr * 54731b875SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 64731b875SAndreas Gohr * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 74731b875SAndreas Gohr */ 84731b875SAndreas Gohr 94731b875SAndreas Gohr// must be run within Dokuwiki 104731b875SAndreas Gohruse dokuwiki\plugin\struct\meta\Column; 114731b875SAndreas Gohruse dokuwiki\plugin\struct\meta\SchemaData; 124731b875SAndreas Gohruse dokuwiki\plugin\struct\meta\StructException; 134731b875SAndreas Gohruse dokuwiki\plugin\struct\meta\Validator; 144731b875SAndreas Gohr 154731b875SAndreas Gohrif(!defined('DOKU_INC')) die(); 164731b875SAndreas Gohr 174731b875SAndreas Gohr/** 184731b875SAndreas Gohr * Class action_plugin_struct_inline 194731b875SAndreas Gohr * 204731b875SAndreas Gohr * Handle inline editing 214731b875SAndreas Gohr */ 224731b875SAndreas Gohrclass action_plugin_struct_inline extends DokuWiki_Action_Plugin { 234731b875SAndreas Gohr 244731b875SAndreas Gohr /** @var SchemaData */ 254731b875SAndreas Gohr protected $schemadata = null; 264731b875SAndreas Gohr 274731b875SAndreas Gohr /** @var Column */ 284731b875SAndreas Gohr protected $column = null; 294731b875SAndreas Gohr 304731b875SAndreas Gohr /** @var String */ 314731b875SAndreas Gohr protected $pid = ''; 324731b875SAndreas Gohr 334731b875SAndreas Gohr /** 344731b875SAndreas Gohr * Registers a callback function for a given event 354731b875SAndreas Gohr * 364731b875SAndreas Gohr * @param Doku_Event_Handler $controller DokuWiki's event controller object 374731b875SAndreas Gohr * @return void 384731b875SAndreas Gohr */ 394731b875SAndreas Gohr public function register(Doku_Event_Handler $controller) { 404731b875SAndreas Gohr $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax'); 414731b875SAndreas Gohr } 424731b875SAndreas Gohr 434731b875SAndreas Gohr /** 444731b875SAndreas Gohr * @param Doku_Event $event 454731b875SAndreas Gohr * @param $param 464731b875SAndreas Gohr */ 474731b875SAndreas Gohr public function handle_ajax(Doku_Event $event, $param) { 484731b875SAndreas Gohr $len = strlen('plugin_struct_inline_'); 494731b875SAndreas Gohr if(substr($event->data, 0, $len) != 'plugin_struct_inline_') return; 504731b875SAndreas Gohr $event->preventDefault(); 514731b875SAndreas Gohr $event->stopPropagation(); 524731b875SAndreas Gohr 534731b875SAndreas Gohr if(substr($event->data, $len) == 'editor') { 544731b875SAndreas Gohr $this->inline_editor(); 554731b875SAndreas Gohr } 564731b875SAndreas Gohr 574731b875SAndreas Gohr if(substr($event->data, $len) == 'save') { 584731b875SAndreas Gohr try { 594731b875SAndreas Gohr $this->inline_save(); 604731b875SAndreas Gohr } catch(StructException $e) { 614731b875SAndreas Gohr http_status(500); 624731b875SAndreas Gohr header('Content-Type: text/plain; charset=utf-8'); 634731b875SAndreas Gohr echo $e->getMessage(); 644731b875SAndreas Gohr } 654731b875SAndreas Gohr } 66cdd09a96SAndreas Gohr 67cdd09a96SAndreas Gohr if(substr($event->data, $len) == 'cancel') { 68cdd09a96SAndreas Gohr $this->inline_cancel(); 69cdd09a96SAndreas Gohr } 704731b875SAndreas Gohr } 714731b875SAndreas Gohr 72cdd09a96SAndreas Gohr /** 73cdd09a96SAndreas Gohr * Creates the inline editor 74cdd09a96SAndreas Gohr */ 754731b875SAndreas Gohr protected function inline_editor() { 76cdd09a96SAndreas Gohr // silently fail when editing not possible 774731b875SAndreas Gohr if(!$this->initFromInput()) return; 78cdd09a96SAndreas Gohr if(auth_quickaclcheck($this->pid) < AUTH_EDIT) return; 79cdd09a96SAndreas Gohr if(checklock($this->pid)) return; 804731b875SAndreas Gohr 81cdd09a96SAndreas Gohr // lock page 82cdd09a96SAndreas Gohr lock($this->pid); 834731b875SAndreas Gohr 84cdd09a96SAndreas Gohr // output the editor 854731b875SAndreas Gohr $value = $this->schemadata->getDataColumn($this->column); 86*63e019d0SAndreas Gohr echo '<label data-column="'.hsc($this->column->getFullQualifiedLabel()).'">'; 874731b875SAndreas Gohr echo $value->getValueEditor('entry'); 88*63e019d0SAndreas Gohr echo '</label>'; 894731b875SAndreas Gohr $hint = $this->column->getType()->getTranslatedHint(); 904731b875SAndreas Gohr if($hint) { 914731b875SAndreas Gohr echo '<div class="hint">'; 924731b875SAndreas Gohr echo hsc($hint); 934731b875SAndreas Gohr echo '</div>'; 944731b875SAndreas Gohr } 95cdd09a96SAndreas Gohr 96cdd09a96SAndreas Gohr // csrf protection 97cdd09a96SAndreas Gohr formSecurityToken(); 984731b875SAndreas Gohr } 994731b875SAndreas Gohr 100cdd09a96SAndreas Gohr /** 101cdd09a96SAndreas Gohr * Save the data posted by the inline editor 102cdd09a96SAndreas Gohr */ 1034731b875SAndreas Gohr protected function inline_save() { 1044731b875SAndreas Gohr global $INPUT; 1054731b875SAndreas Gohr 1064d2da382SAndreas Gohr if(!$this->initFromInput()) { 1074d2da382SAndreas Gohr throw new StructException('inline save error: init'); 1084d2da382SAndreas Gohr } 1094d2da382SAndreas Gohr // our own implementation of checkSecurityToken because we don't want the msg() call 110cdd09a96SAndreas Gohr if( 1114d2da382SAndreas Gohr $INPUT->server->str('REMOTE_USER') && 1124d2da382SAndreas Gohr getSecurityToken() != $INPUT->str('sectok') 113cdd09a96SAndreas Gohr ) { 1144d2da382SAndreas Gohr throw new StructException('inline save error: csrf'); 1154d2da382SAndreas Gohr } 1164d2da382SAndreas Gohr if(auth_quickaclcheck($this->pid) < AUTH_EDIT) { 1174d2da382SAndreas Gohr throw new StructException('inline save error: acl'); 1184d2da382SAndreas Gohr } 1194d2da382SAndreas Gohr if(checklock($this->pid)) { 1204d2da382SAndreas Gohr throw new StructException('inline save error: lock'); 1214731b875SAndreas Gohr } 1224731b875SAndreas Gohr 1234731b875SAndreas Gohr // validate 1244731b875SAndreas Gohr $value = $INPUT->param('entry'); 1254731b875SAndreas Gohr $validator = new Validator(); 1264731b875SAndreas Gohr if(!$validator->validateValue($this->column, $value)) { 1274731b875SAndreas Gohr throw new StructException(join("\n", $validator->getErrors())); 1284731b875SAndreas Gohr } 1294731b875SAndreas Gohr 1304731b875SAndreas Gohr // current data 1314731b875SAndreas Gohr $tosave = $this->schemadata->getDataArray(); 1324731b875SAndreas Gohr $tosave[$this->column->getLabel()] = $value; 1334731b875SAndreas Gohr $tosave = array($this->schemadata->getTable() => $tosave); 1344731b875SAndreas Gohr 1354731b875SAndreas Gohr // save 1364731b875SAndreas Gohr /** @var helper_plugin_struct $helper */ 1374731b875SAndreas Gohr $helper = plugin_load('helper', 'struct'); 1384731b875SAndreas Gohr $helper->saveData($this->pid, $tosave, 'inline edit'); 1394731b875SAndreas Gohr 140cdd09a96SAndreas Gohr // unlock 141cdd09a96SAndreas Gohr unlock($this->pid); 1424731b875SAndreas Gohr 1434731b875SAndreas Gohr // reinit then render 1444731b875SAndreas Gohr $this->initFromInput(); 1454731b875SAndreas Gohr $value = $this->schemadata->getDataColumn($this->column); 1464731b875SAndreas Gohr $R = new Doku_Renderer_xhtml(); 1474731b875SAndreas Gohr $value->render($R, 'xhtml'); // FIXME use configured default renderer 1484731b875SAndreas Gohr echo $R->doc; 1494731b875SAndreas Gohr } 1504731b875SAndreas Gohr 1514731b875SAndreas Gohr /** 152cdd09a96SAndreas Gohr * Unlock a page (on cancel action) 153cdd09a96SAndreas Gohr */ 154cdd09a96SAndreas Gohr protected function inline_cancel() { 155cdd09a96SAndreas Gohr global $INPUT; 156cdd09a96SAndreas Gohr $pid = $INPUT->str('pid'); 157cdd09a96SAndreas Gohr unlock($pid); 158cdd09a96SAndreas Gohr } 159cdd09a96SAndreas Gohr 160cdd09a96SAndreas Gohr /** 1614731b875SAndreas Gohr * Initialize internal state based on input variables 1624731b875SAndreas Gohr * 1634731b875SAndreas Gohr * @return bool if initialization was successfull 1644731b875SAndreas Gohr */ 1654731b875SAndreas Gohr protected function initFromInput() { 1664731b875SAndreas Gohr global $INPUT; 1674731b875SAndreas Gohr 1684731b875SAndreas Gohr $this->schemadata = null; 1694731b875SAndreas Gohr $this->column = null; 1704731b875SAndreas Gohr 1714731b875SAndreas Gohr $pid = $INPUT->str('pid'); 1724731b875SAndreas Gohr list($table, $field) = explode('.', $INPUT->str('field')); 1734731b875SAndreas Gohr if(blank($pid)) return false; 1744731b875SAndreas Gohr if(blank($table)) return false; 1754731b875SAndreas Gohr if(blank($field)) return false; 1764731b875SAndreas Gohr 1774731b875SAndreas Gohr $this->pid = $pid; 1784731b875SAndreas Gohr 1794731b875SAndreas Gohr $this->schemadata = new SchemaData($table, $pid, 0); 1804731b875SAndreas Gohr if(!$this->schemadata->getId()) { 1814731b875SAndreas Gohr $this->schemadata = null; 1824731b875SAndreas Gohr return false; 1834731b875SAndreas Gohr } 1844731b875SAndreas Gohr 1854731b875SAndreas Gohr $this->column = $this->schemadata->findColumn($field); 1864731b875SAndreas Gohr if(!$this->column || !$this->column->isVisibleInEditor()) { 1874731b875SAndreas Gohr $this->schemadata = null; 1884731b875SAndreas Gohr $this->column = null; 1894731b875SAndreas Gohr return false; 1904731b875SAndreas Gohr } 1914731b875SAndreas Gohr 1924731b875SAndreas Gohr return true; 1934731b875SAndreas Gohr } 1944731b875SAndreas Gohr 1954731b875SAndreas Gohr} 196