xref: /plugin/struct/action/inline.php (revision 63e019d0e7d287267656881798da4ca77bc2da4b)
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