1<?php
2
3/**
4 * Plugin RefNotes: Configuration interface
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Mykola Ostrovskyy <dwpforge@gmail.com>
8 */
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11class admin_plugin_refnotes extends DokuWiki_Admin_Plugin {
12    use refnotes_localization_plugin;
13
14    private $html;
15    private $locale;
16
17    /**
18     * Constructor
19     */
20    public function __construct() {
21        refnotes_localization::initialize($this);
22
23        $this->html = new refnotes_html_sink();
24        $this->locale = refnotes_localization::getInstance();
25    }
26
27    /**
28     * Handle user request
29     */
30    public function handle() {
31        /* All handling is done using AJAX */
32    }
33
34    /**
35     * Output appropriate html
36     */
37    public function html() {
38        print($this->locale_xhtml('intro'));
39
40        $this->html->ptln('<!-- refnotes -->');
41
42        $this->printLanguageStrings();
43
44        $this->html->ptln('<div id="refnotes-config"><div id="config__manager">');
45        $this->html->ptln('<noscript><div class="error">' . $this->locale->getLang('noscript') . '</div></noscript>');
46        $this->html->ptln('<div id="server-status" class="info" style="display: none;">&nbsp;</div>');
47        $this->html->ptln('<form action="" method="post">');
48        $this->html->indent();
49
50        $this->printGeneral();
51        $this->printNamespaces();
52        $this->printNotes();
53
54        $this->html->ptln($this->getButton('save'));
55
56        $this->html->unindent();
57        $this->html->ptln('</form></div></div>');
58        $this->html->ptln('<!-- /refnotes -->');
59    }
60
61    /**
62     * Built-in JS localization stores all language strings in the common script (produced by js.php).
63     * The strings used by administration plugin seem to be unnecessary in that script. Instead we print
64     * them as part of the page and then load them into the LANG array on the client side.
65     */
66    private function printLanguageStrings() {
67        $lang = $this->locale->getByPrefix('js');
68
69        $this->html->ptln('<div id="refnotes-lang" style="display: none;">');
70
71        foreach ($lang as $key => $value) {
72            ptln($key . ' : ' . $value . ':eos:');
73        }
74
75        $this->html->ptln('</div>');
76    }
77
78    /**
79     *
80     */
81    private function printGeneral() {
82        $section = new refnotes_config_general();
83        $section->printHtml($this->html);
84    }
85
86    /**
87     *
88     */
89    private function printNamespaces() {
90        $section = new refnotes_config_namespaces();
91        $section->printHtml($this->html);
92    }
93
94    /**
95     *
96     */
97    private function printNotes() {
98        $section = new refnotes_config_notes();
99        $section->printHtml($this->html);
100    }
101
102    /**
103     *
104     */
105    private function getButton($action) {
106        $html = '<input type="button" class="button"';
107        $id = $action . '-config';
108        $html .= ' id="' . $id . '"';
109        $html .= ' name="' . $id . '"';
110        $html .= ' value="' . $this->locale->getLang('btn_' . $action) . '"';
111        $html .= ' />';
112
113        return $html;
114    }
115}
116
117////////////////////////////////////////////////////////////////////////////////////////////////////
118class refnotes_config_section {
119
120    protected $html;
121    protected $id;
122    protected $title;
123
124    /**
125     * Constructor
126     */
127    public function __construct($id) {
128        $this->html = NULL;
129        $this->id = $id;
130        $this->title = 'sec_' . $id;
131    }
132
133    /**
134     *
135     */
136    public function printHtml($html) {
137        $this->html = $html;
138        $this->open();
139        $this->printFields();
140        $this->close();
141    }
142
143    /**
144     *
145     */
146    protected function open() {
147        $title = refnotes_localization::getInstance()->getLang($this->title);
148
149        $this->html->ptln('<fieldset id="' . $this->id . '">');
150        $this->html->ptln('<legend>' . $title . '</legend>');
151        $this->html->ptln('<table class="inline" cols="3">');
152        $this->html->indent();
153    }
154
155    /**
156     *
157     */
158    protected function close() {
159        $this->html->unindent();
160        $this->html->ptln('</table>');
161        $this->html->ptln('</fieldset>');
162    }
163
164    /**
165     *
166     */
167    protected function printFields() {
168        $field = $this->getFields();
169        foreach ($field as $f) {
170            $this->printFieldRow($f);
171        }
172    }
173
174    /**
175     *
176     */
177    protected function getFields() {
178        $fieldData = $this->getFieldDefinitions();
179        $field = array();
180
181        foreach ($fieldData as $id => $fd) {
182            $class = 'refnotes_config_' . $fd['class'];
183            $field[] = new $class($id, $fd);
184        }
185
186        return $field;
187    }
188
189    /**
190     *
191     */
192    protected function printFieldRow($field, $startRow = true) {
193        if ($startRow) {
194            $this->html->ptln('<tr>');
195            $this->html->indent();
196        }
197
198        if (get_class($field) != 'refnotes_config_textarea') {
199            $settingName = $field->getSettingName();
200            if ($settingName != '') {
201                $this->html->ptln('<td class="label">');
202                $this->html->ptln($settingName);
203            }
204            else {
205                $this->html->ptln('<td class="lean-label">');
206            }
207
208            $this->html->ptln($field->getLabel());
209            $this->html->ptln('</td><td class="value">');
210        }
211        else {
212            $this->html->ptln('<td class="value" colspan="2">');
213        }
214
215        $this->html->ptln($field->getControl());
216        $this->html->ptln('</td>');
217
218        $this->html->unindent();
219        $this->html->ptln('</tr>');
220    }
221}
222
223////////////////////////////////////////////////////////////////////////////////////////////////////
224class refnotes_config_list_section extends refnotes_config_section {
225
226    private $listRows;
227
228    /**
229     * Constructor
230     */
231    public function __construct($id, $listRows) {
232        parent::__construct($id);
233
234        $this->listRows = $listRows;
235    }
236
237    /**
238     *
239     */
240    protected function close() {
241        $this->html->unindent();
242        $this->html->ptln('</table>');
243        $this->printListControls();
244        $this->html->ptln('</fieldset>');
245    }
246
247    /**
248     *
249     */
250    private function printListControls() {
251        $this->html->ptln('<div class="list-controls">');
252        $this->html->indent();
253
254        $this->html->ptln($this->getEdit());
255        $this->html->ptln($this->getButton('add'));
256        $this->html->ptln($this->getButton('rename'));
257        $this->html->ptln($this->getButton('delete'));
258
259        $this->html->unindent();
260        $this->html->ptln('</div>');
261    }
262
263    /**
264     *
265     */
266    private function getEdit() {
267        $html = '<input type="text" class="edit"';
268        $id = 'name-' . $this->id;
269        $html .= ' id="' . $id . '"';
270        $html .= ' name="' . $id . '"';
271        $html .= ' value=""';
272        $html .= ' />';
273
274        return $html;
275    }
276
277    /**
278     *
279     */
280    private function getButton($action) {
281        $label = refnotes_localization::getInstance()->getLang('btn_' . $action);
282
283        $id = $action . '-' . $this->id;
284        $html = '<input type="button" class="button"';
285        $html .= ' id="' . $id . '"';
286        $html .= ' name="' . $id . '"';
287        $html .= ' value="' . $label . '"';
288        $html .= ' />';
289
290        return $html;
291    }
292
293    /**
294     *
295     */
296    protected function printFields() {
297        $field = $this->getFields();
298        $fields = count($field);
299
300        $this->html->ptln('<tr>');
301        $this->html->indent();
302        $this->html->ptln('<td class="list" rowspan="' . $fields . '">');
303        $this->html->ptln('<select class="list" id="select-' . $this->id . '" size="' . $this->listRows . '"></select>');
304        $this->html->ptln('</td>');
305
306        $this->printFieldRow($field[0], false);
307
308        for ($f = 1; $f < $fields; $f++) {
309            $this->printFieldRow($field[$f]);
310        }
311    }
312}
313
314////////////////////////////////////////////////////////////////////////////////////////////////////
315class refnotes_config_general extends refnotes_config_section {
316
317    /**
318     * Constructor
319     */
320    public function __construct() {
321        parent::__construct('general');
322    }
323
324    /**
325     *
326     */
327    protected function getFieldDefinitions() {
328        static $field = array(
329            'replace-footnotes' => array(
330                'class' => 'checkbox',
331                'lean' => true
332            ),
333            'reference-db-enable' => array(
334                'class' => 'checkbox',
335                'lean' => true
336            ),
337            'reference-db-namespace' => array(
338                'class' => 'edit',
339                'lean' => true
340            )
341        );
342
343        return $field;
344    }
345}
346
347////////////////////////////////////////////////////////////////////////////////////////////////////
348class refnotes_config_namespaces extends refnotes_config_list_section {
349
350    /**
351     * Constructor
352     */
353    public function __construct() {
354        parent::__construct('namespaces', 48);
355    }
356
357    /**
358     *
359     */
360    protected function getFieldDefinitions() {
361        static $field = array(
362            'refnote-id' => array(
363                'class' => 'select',
364                'option' => array('numeric', 'latin-lower', 'latin-upper', 'roman-lower', 'roman-upper', 'stars', 'note-name', 'inherit')
365            ),
366            'reference-base' => array(
367                'class' => 'select',
368                'option' => array('super', 'normal-text', 'inherit')
369            ),
370            'reference-font-weight' => array(
371                'class' => 'select',
372                'option' => array('normal', 'bold', 'inherit')
373            ),
374            'reference-font-style' => array(
375                'class' => 'select',
376                'option' => array('normal', 'italic', 'inherit')
377            ),
378            'reference-format' => array(
379                'class' => 'select',
380                'option' => array('right-parent', 'parents', 'right-bracket', 'brackets', 'none', 'inherit')
381            ),
382            'reference-group' => array(
383                'class' => 'select',
384                'option' => array('group-none', 'group-comma', 'group-semicolon', 'inherit')
385            ),
386            'reference-render' => array(
387                'class' => 'select',
388                'option' => array('basic', 'harvard', 'inherit')
389            ),
390            'multi-ref-id' => array(
391                'class' => 'select',
392                'option' => array('ref-counter', 'note-counter', 'inherit')
393            ),
394            'note-preview' => array(
395                'class' => 'select',
396                'option' => array('popup', 'tooltip', 'none', 'inherit')
397            ),
398            'notes-separator' => array(
399                'class' => 'edit_inherit'
400            ),
401            'note-text-align' => array(
402                'class' => 'select',
403                'option' => array('justify', 'left', 'inherit')
404            ),
405            'note-font-size' => array(
406                'class' => 'select',
407                'option' => array('normal', 'small', 'inherit')
408            ),
409            'note-render' => array(
410                'class' => 'select',
411                'option' => array('basic', 'harvard', 'inherit')
412            ),
413            'note-id-base' => array(
414                'class' => 'select',
415                'option' => array('super', 'normal-text', 'inherit')
416            ),
417            'note-id-font-weight' => array(
418                'class' => 'select',
419                'option' => array('normal', 'bold', 'inherit')
420            ),
421            'note-id-font-style' => array(
422                'class' => 'select',
423                'option' => array('normal', 'italic', 'inherit')
424            ),
425            'note-id-format' => array(
426                'class' => 'select',
427                'option' => array('right-parent', 'parents', 'right-bracket', 'brackets', 'dot', 'none', 'inherit')
428            ),
429            'back-ref-caret' => array(
430                'class' => 'select',
431                'option' => array('prefix', 'merge', 'none', 'inherit')
432            ),
433            'back-ref-base' => array(
434                'class' => 'select',
435                'option' => array('super', 'normal-text', 'inherit')
436            ),
437            'back-ref-font-weight' => array(
438                'class' => 'select',
439                'option' => array('normal', 'bold', 'inherit')
440            ),
441            'back-ref-font-style' => array(
442                'class' => 'select',
443                'option' => array('normal', 'italic', 'inherit')
444            ),
445            'back-ref-format' => array(
446                'class' => 'select',
447                'option' => array('note-id', 'latin', 'numeric', 'caret', 'arrow', 'none', 'inherit')
448            ),
449            'back-ref-separator' => array(
450                'class' => 'select',
451                'option' => array('comma', 'none', 'inherit')
452            ),
453            'scoping' => array(
454                'class' => 'select',
455                'option' => array('reset', 'single')
456            )
457        );
458
459        return $field;
460    }
461}
462
463////////////////////////////////////////////////////////////////////////////////////////////////////
464class refnotes_config_notes extends refnotes_config_list_section {
465
466    /**
467     * Constructor
468     */
469    public function __construct() {
470        parent::__construct('notes', 14);
471    }
472
473    /**
474     *
475     */
476    protected function getFieldDefinitions() {
477        static $field = array(
478            'note-text' => array(
479                'class' => 'textarea',
480                'rows' => '4',
481                'lean' => true
482            ),
483            'inline' => array(
484                'class' => 'checkbox',
485                'lean' => true
486            ),
487            'use-reference-base' => array(
488                'class' => 'checkbox',
489                'lean' => true
490            ),
491            'use-reference-font-weight' => array(
492                'class' => 'checkbox',
493                'lean' => true
494            ),
495            'use-reference-font-style' => array(
496                'class' => 'checkbox',
497                'lean' => true
498            ),
499            'use-reference-format' => array(
500                'class' => 'checkbox',
501                'lean' => true
502            )
503        );
504
505        return $field;
506    }
507}
508
509////////////////////////////////////////////////////////////////////////////////////////////////////
510class refnotes_config_field {
511
512    protected $id;
513    protected $settingName;
514    protected $label;
515
516    /**
517     * Constructor
518     */
519    public function __construct($id, $data) {
520        $this->id = 'field-' . $id;
521        $this->label = 'lbl_' . $id;
522
523        if (array_key_exists('lean', $data) && $data['lean']) {
524            $this->settingName = '';
525        }
526        else {
527            $this->settingName = $id;
528        }
529    }
530
531    /**
532     *
533     */
534    public function getSettingName() {
535        $html = '';
536
537        if ($this->settingName != '') {
538            $html = '<span class="outkey">' . $this->settingName . '</span>';
539        }
540
541        return $html;
542    }
543
544    /**
545     *
546     */
547    public function getLabel() {
548        $label = refnotes_localization::getInstance()->getLang($this->label);
549
550        return '<label for="' . $this->id . '">' . $label . '</label>';
551    }
552}
553
554////////////////////////////////////////////////////////////////////////////////////////////////////
555class refnotes_config_checkbox extends refnotes_config_field {
556
557    /**
558     * Constructor
559     */
560    public function __construct($id, $data) {
561        parent::__construct($id, $data);
562    }
563
564    /**
565     *
566     */
567    public function getControl() {
568        $html = '<div class="input">';
569        $html .= '<input type="checkbox" class="checkbox"';
570        $html .= ' id="' . $this->id . '"';
571        $html .= ' name="' . $this->id . '" value="1"';
572        $html .= '/></div>';
573
574        return $html;
575    }
576}
577
578////////////////////////////////////////////////////////////////////////////////////////////////////
579class refnotes_config_select extends refnotes_config_field {
580
581    private $option;
582
583    /**
584     * Constructor
585     */
586    public function __construct($id, $data) {
587        parent::__construct($id, $data);
588
589        $this->option = $data['option'];
590    }
591
592    /**
593     *
594     */
595    public function getControl() {
596        $locale = refnotes_localization::getInstance();
597
598        $html = '<div class="input">';
599
600        $html .= '<select class="edit"';
601        $html .= ' id="' . $this->id . '"';
602        $html .= ' name="' . $this->id . '">' . DOKU_LF;
603
604        foreach ($this->option as $option) {
605            $html .= '<option value="' . $option . '">' . $locale->getLang('opt_' . $option) . '</option>' . DOKU_LF;
606        }
607
608        $html .= '</select>';
609        $html .= '</div>';
610
611        return $html;
612    }
613}
614
615////////////////////////////////////////////////////////////////////////////////////////////////////
616class refnotes_config_edit extends refnotes_config_field {
617
618    /**
619     * Constructor
620     */
621    public function __construct($id, $data) {
622        parent::__construct($id, $data);
623    }
624
625    /**
626     *
627     */
628    public function getControl() {
629        $html = '<div class="input">';
630
631        $html .= '<input type="text" class="edit"';
632        $html .= ' id="' . $this->id . '"';
633        $html .= ' name="' . $this->id . '" />' . DOKU_LF;
634
635        $html .= '</div>';
636
637        return $html;
638    }
639}
640
641////////////////////////////////////////////////////////////////////////////////////////////////////
642class refnotes_config_edit_inherit extends refnotes_config_field {
643
644    /**
645     * Constructor
646     */
647    public function __construct($id, $data) {
648        parent::__construct($id, $data);
649    }
650
651    /**
652     *
653     */
654    public function getControl() {
655        $buttonLabel = refnotes_localization::getInstance()->getLang('opt_inherit');
656
657        $html = '<div class="input">';
658
659        $html .= '<input type="text" class="edit"';
660        $html .= ' id="' . $this->id . '"';
661        $html .= ' name="' . $this->id . '" />' . DOKU_LF;
662
663        $html .= '<input type="button" class="button"';
664        $html .= ' id="' . $this->id . '-inherit"';
665        $html .= ' name="' . $this->id . '-inherit"';
666        $html .= ' value="' . $buttonLabel . '"';
667        $html .= ' />';
668
669        $html .= '</div>';
670
671        return $html;
672    }
673}
674
675////////////////////////////////////////////////////////////////////////////////////////////////////
676class refnotes_config_textarea extends refnotes_config_field {
677
678    private $rows;
679
680    /**
681     * Constructor
682     */
683    public function __construct($id, $data) {
684        parent::__construct($id, $data);
685
686        $this->rows = $data['rows'];
687    }
688
689    /**
690     *
691     */
692    public function getControl() {
693        $html = '<div class="input">';
694        $html .= '<textarea class="edit"';
695        $html .= ' id="' . $this->id . '"';
696        $html .= ' name="' . $this->id . '"';
697        $html .= ' cols="40" rows="' . $this->rows . '">';
698        $html .= '</textarea></div>';
699
700        return $html;
701    }
702}
703
704////////////////////////////////////////////////////////////////////////////////////////////////////
705class refnotes_html_sink {
706
707    private $indentIncrement;
708    private $indent;
709
710    /**
711     * Constructor
712     */
713    public function __construct() {
714        $this->indentIncrement = 2;
715        $this->indent = 0;
716    }
717
718    /**
719     *
720     */
721    public function indent() {
722        $this->indent += $this->indentIncrement;
723    }
724
725    /**
726     *
727     */
728    public function unindent() {
729        if ($this->indent >= $this->indentIncrement) {
730            $this->indent -= $this->indentIncrement;
731        }
732    }
733
734    /**
735     *
736     */
737    public function ptln($string, $indentDelta = 0) {
738        if ($indentDelta < 0) {
739            $this->indent += $this->indentIncrement * $indentDelta;
740        }
741
742        $text = explode(DOKU_LF, $string);
743        foreach ($text as $string) {
744            ptln($string, $this->indent);
745        }
746
747        if ($indentDelta > 0) {
748            $this->indent += $this->indentIncrement * $indentDelta;
749        }
750    }
751}
752