1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2019 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16namespace Fisharebest\Webtrees\Controller;
17
18use Fisharebest\Webtrees\Database;
19
20/**
21 * Base controller for all other controllers
22 */
23class BaseController
24{
25    // The controller accumulates Javascript (inline and external), and renders it in the footer
26    const JS_PRIORITY_HIGH   = 0;
27    const JS_PRIORITY_NORMAL = 1;
28    const JS_PRIORITY_LOW    = 2;
29
30    /** @var string[][] Inline JavaScript to add to the page. */
31    private $inline_javascript = array(
32        self::JS_PRIORITY_HIGH   => array(),
33        self::JS_PRIORITY_NORMAL => array(),
34        self::JS_PRIORITY_LOW    => array(),
35    );
36
37    /** @var string[] Exteral JavaScript files to load. */
38    private $external_javascript = array();
39
40    /**
41     * Startup activity
42     */
43    public function __construct()
44    {
45    }
46
47    /**
48     * Make a list of external Javascript, so we can render them in the footer
49     *
50     * @param string $script_name
51     *
52     * @return $this
53     */
54    public function addExternalJavascript($script_name)
55    {
56        $this->external_javascript[$script_name] = true;
57
58        return $this;
59    }
60
61    /**
62     * Make a list of inline Javascript, so we can render them in the footer
63     * NOTE: there is no need to use "jQuery(document).ready(function(){...})", etc.
64     * as this Javascript won’t be inserted until the very end of the page.
65     *
66     * @param string $script
67     * @param int    $priority
68     *
69     * @return $this
70     */
71    public function addInlineJavascript($script, $priority = self::JS_PRIORITY_NORMAL)
72    {
73        $tmp   = &$this->inline_javascript[$priority];
74        $tmp[] = $script;
75
76        return $this;
77    }
78
79    /**
80     * We've collected up Javascript fragments while rendering the page.
81     * Now display them in order.
82     *
83     * @return string
84     */
85    public function getJavascript()
86    {
87        $javascript1 = '';
88        $javascript2 = '';
89        $javascript3 = '';
90
91        // Inline (high priority) javascript
92        foreach ($this->inline_javascript[self::JS_PRIORITY_HIGH] as $script) {
93            $javascript1 .= $script;
94        }
95
96        // External javascript
97        foreach (array_keys($this->external_javascript) as $script_name) {
98            $javascript2 .= '<script src="' . $script_name . '"></script>';
99        }
100
101        // Inline (lower priority) javascript
102        if ($this->inline_javascript) {
103            foreach ($this->inline_javascript as $priority => $scripts) {
104                if ($priority !== self::JS_PRIORITY_HIGH) {
105                    foreach ($scripts as $script) {
106                        $javascript3 .= $script;
107                    }
108                }
109            }
110        }
111
112        // We could, in theory, inject JS at any point in the page (not just the bottom) - prepare for next time
113        $this->inline_javascript = array(
114            self::JS_PRIORITY_HIGH   => array(),
115            self::JS_PRIORITY_NORMAL => array(),
116            self::JS_PRIORITY_LOW    => array(),
117        );
118        $this->external_javascript = array();
119
120        return '<script>' . $javascript1 . '</script>' . $javascript2 . '<script>' . $javascript3 . '</script>';
121    }
122
123    /**
124     * Print the page header, using the theme
125     *
126     * @return $this
127     */
128    public function pageHeader()
129    {
130        // We've displayed the header - display the footer automatically
131        register_shutdown_function(array($this, 'pageFooter'));
132
133        return $this;
134    }
135
136    /**
137     * Print the page footer, using the theme
138     */
139    public function pageFooter()
140    {
141        if (WT_DEBUG_SQL) {
142            echo Database::getQueryLog();
143        }
144        echo $this->getJavascript();
145    }
146}
147