Passed
Push — 1.7 ( 23cbb7...8df8a8 )
by Greg
08:15
created
app/Theme/FabTheme.php 3 patches
Indentation   +138 added lines, -138 removed lines patch added patch discarded remove patch
@@ -22,153 +22,153 @@
 block discarded – undo
22 22
  * The F.A.B. theme.
23 23
  */
24 24
 class FabTheme extends AbstractTheme implements ThemeInterface {
25
-	/**
26
-	 * Where are our CSS, JS and other assets?
27
-	 *
28
-	 * @return string A relative path, such as "themes/foo/"
29
-	 */
30
-	public function assetUrl() {
31
-		return 'themes/fab/css-1.7.8/';
32
-	}
25
+    /**
26
+     * Where are our CSS, JS and other assets?
27
+     *
28
+     * @return string A relative path, such as "themes/foo/"
29
+     */
30
+    public function assetUrl() {
31
+        return 'themes/fab/css-1.7.8/';
32
+    }
33 33
 
34
-	/**
35
-	 * Add markup to a flash message.
36
-	 *
37
-	 * @param \stdClass $message
38
-	 *
39
-	 * @return string
40
-	 */
41
-	protected function flashMessageContainer(\stdClass $message) {
42
-		// This theme uses jQueryUI markup.
43
-		switch ($message->status) {
44
-		case 'danger':
45
-			return '<p class="ui-state-error">' . $message->text . '</p>';
46
-		default:
47
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
48
-		}
49
-	}
34
+    /**
35
+     * Add markup to a flash message.
36
+     *
37
+     * @param \stdClass $message
38
+     *
39
+     * @return string
40
+     */
41
+    protected function flashMessageContainer(\stdClass $message) {
42
+        // This theme uses jQueryUI markup.
43
+        switch ($message->status) {
44
+        case 'danger':
45
+            return '<p class="ui-state-error">' . $message->text . '</p>';
46
+        default:
47
+            return '<p class="ui-state-highlight">' . $message->text . '</p>';
48
+        }
49
+    }
50 50
 
51
-	/**
52
-	 * Add markup to the secondary menu.
53
-	 *
54
-	 * @return string
55
-	 */
56
-	protected function formatSecondaryMenu() {
57
-		return
58
-			'<ul class="secondary-menu">' .
59
-			implode('', $this->secondaryMenu()) .
60
-			'<li>' .
61
-			$this->formQuickSearch() .
62
-			'</li>' .
63
-			'</ul>';
64
-	}
51
+    /**
52
+     * Add markup to the secondary menu.
53
+     *
54
+     * @return string
55
+     */
56
+    protected function formatSecondaryMenu() {
57
+        return
58
+            '<ul class="secondary-menu">' .
59
+            implode('', $this->secondaryMenu()) .
60
+            '<li>' .
61
+            $this->formQuickSearch() .
62
+            '</li>' .
63
+            '</ul>';
64
+    }
65 65
 
66
-	/**
67
-	 * Create the contents of the <header> tag.
68
-	 *
69
-	 * @return string
70
-	 */
71
-	protected function headerContent() {
72
-		return
73
-			//$this->accessibilityLinks() .
74
-			$this->formatTreeTitle() .
75
-			$this->formatSecondaryMenu();
76
-	}
66
+    /**
67
+     * Create the contents of the <header> tag.
68
+     *
69
+     * @return string
70
+     */
71
+    protected function headerContent() {
72
+        return
73
+            //$this->accessibilityLinks() .
74
+            $this->formatTreeTitle() .
75
+            $this->formatSecondaryMenu();
76
+    }
77 77
 
78
-	/**
79
-	 * Add markup to an item in the secondary menu.
80
-	 *
81
-	 * @param Menu $menu
82
-	 *
83
-	 * @return string
84
-	 */
85
-	protected function formatSecondaryMenuItem(Menu $menu) {
86
-		return $menu->getMenuAsList();
87
-	}
78
+    /**
79
+     * Add markup to an item in the secondary menu.
80
+     *
81
+     * @param Menu $menu
82
+     *
83
+     * @return string
84
+     */
85
+    protected function formatSecondaryMenuItem(Menu $menu) {
86
+        return $menu->getMenuAsList();
87
+    }
88 88
 
89
-	/**
90
-	 * Create a search field and submit button for the quick search form in the header.
91
-	 *
92
-	 * @return string
93
-	 */
94
-	protected function formQuickSearchFields() {
95
-		return
96
-			'<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
97
-	}
89
+    /**
90
+     * Create a search field and submit button for the quick search form in the header.
91
+     *
92
+     * @return string
93
+     */
94
+    protected function formQuickSearchFields() {
95
+        return
96
+            '<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
97
+    }
98 98
 
99
-	/**
100
-	 * Allow themes to add extra scripts to the page footer.
101
-	 *
102
-	 * @return string
103
-	 */
104
-	public function hookFooterExtraJavascript() {
105
-		return
106
-			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
107
-			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
108
-			'<script>' .
109
-			'activate_colorbox();' .
110
-			'jQuery.extend(jQuery.colorbox.settings, {' .
111
-			' width: "85%",' .
112
-			' height: "85%",' .
113
-			' transition: "none",' .
114
-			' slideshowStart: "' . I18N::translate('Play') . '",' .
115
-			' slideshowStop: "' . I18N::translate('Stop') . '",' .
116
-			' title: function() { return jQuery(this).data("title"); }' .
117
-			'});' .
118
-			'</script>';
119
-	}
99
+    /**
100
+     * Allow themes to add extra scripts to the page footer.
101
+     *
102
+     * @return string
103
+     */
104
+    public function hookFooterExtraJavascript() {
105
+        return
106
+            '<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
107
+            '<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
108
+            '<script>' .
109
+            'activate_colorbox();' .
110
+            'jQuery.extend(jQuery.colorbox.settings, {' .
111
+            ' width: "85%",' .
112
+            ' height: "85%",' .
113
+            ' transition: "none",' .
114
+            ' slideshowStart: "' . I18N::translate('Play') . '",' .
115
+            ' slideshowStop: "' . I18N::translate('Stop') . '",' .
116
+            ' title: function() { return jQuery(this).data("title"); }' .
117
+            '});' .
118
+            '</script>';
119
+    }
120 120
 
121
-	/**
122
-	 * Misecellaneous dimensions, fonts, styles, etc.
123
-	 *
124
-	 * @param string $parameter_name
125
-	 *
126
-	 * @return string|int|float
127
-	 */
128
-	public function parameter($parameter_name) {
129
-		$parameters = array(
130
-			'chart-background-f'             => 'e9daf1',
131
-			'chart-background-m'             => 'b1cff0',
132
-			'chart-box-x'                    => 260,
133
-			'chart-box-y'                    => 85,
134
-			'distribution-chart-high-values' => '9ca3d4',
135
-			'distribution-chart-low-values'  => 'e5e6ef',
136
-		);
121
+    /**
122
+     * Misecellaneous dimensions, fonts, styles, etc.
123
+     *
124
+     * @param string $parameter_name
125
+     *
126
+     * @return string|int|float
127
+     */
128
+    public function parameter($parameter_name) {
129
+        $parameters = array(
130
+            'chart-background-f'             => 'e9daf1',
131
+            'chart-background-m'             => 'b1cff0',
132
+            'chart-box-x'                    => 260,
133
+            'chart-box-y'                    => 85,
134
+            'distribution-chart-high-values' => '9ca3d4',
135
+            'distribution-chart-low-values'  => 'e5e6ef',
136
+        );
137 137
 
138
-		if (array_key_exists($parameter_name, $parameters)) {
139
-			return $parameters[$parameter_name];
140
-		} else {
141
-			return parent::parameter($parameter_name);
142
-		}
143
-	}
138
+        if (array_key_exists($parameter_name, $parameters)) {
139
+            return $parameters[$parameter_name];
140
+        } else {
141
+            return parent::parameter($parameter_name);
142
+        }
143
+    }
144 144
 
145
-	/**
146
-	 * A list of CSS files to include for this page.
147
-	 *
148
-	 * @return string[]
149
-	 */
150
-	protected function stylesheets() {
151
-		return array(
152
-			'themes/fab/jquery-ui-1.11.2/jquery-ui.css',
153
-			$this->assetUrl() . 'style.css',
154
-		);
155
-	}
145
+    /**
146
+     * A list of CSS files to include for this page.
147
+     *
148
+     * @return string[]
149
+     */
150
+    protected function stylesheets() {
151
+        return array(
152
+            'themes/fab/jquery-ui-1.11.2/jquery-ui.css',
153
+            $this->assetUrl() . 'style.css',
154
+        );
155
+    }
156 156
 
157
-	/**
158
-	 * A fixed string to identify this theme, in settings, etc.
159
-	 *
160
-	 * @return string
161
-	 */
162
-	public function themeId() {
163
-		return 'fab';
164
-	}
157
+    /**
158
+     * A fixed string to identify this theme, in settings, etc.
159
+     *
160
+     * @return string
161
+     */
162
+    public function themeId() {
163
+        return 'fab';
164
+    }
165 165
 
166
-	/**
167
-	 * What is this theme called?
168
-	 *
169
-	 * @return string
170
-	 */
171
-	public function themeName() {
172
-		return /* I18N: Name of a theme. */ I18N::translate('F.A.B.');
173
-	}
166
+    /**
167
+     * What is this theme called?
168
+     *
169
+     * @return string
170
+     */
171
+    public function themeName() {
172
+        return /* I18N: Name of a theme. */ I18N::translate('F.A.B.');
173
+    }
174 174
 }
Please login to merge, or discard this patch.
Braces   +24 added lines, -12 removed lines patch added patch discarded remove patch
@@ -21,13 +21,15 @@  discard block
 block discarded – undo
21 21
 /**
22 22
  * The F.A.B. theme.
23 23
  */
24
-class FabTheme extends AbstractTheme implements ThemeInterface {
24
+class FabTheme extends AbstractTheme implements ThemeInterface
25
+{
25 26
 	/**
26 27
 	 * Where are our CSS, JS and other assets?
27 28
 	 *
28 29
 	 * @return string A relative path, such as "themes/foo/"
29 30
 	 */
30
-	public function assetUrl() {
31
+	public function assetUrl()
32
+	{
31 33
 		return 'themes/fab/css-1.7.8/';
32 34
 	}
33 35
 
@@ -38,7 +40,8 @@  discard block
 block discarded – undo
38 40
 	 *
39 41
 	 * @return string
40 42
 	 */
41
-	protected function flashMessageContainer(\stdClass $message) {
43
+	protected function flashMessageContainer(\stdClass $message)
44
+	{
42 45
 		// This theme uses jQueryUI markup.
43 46
 		switch ($message->status) {
44 47
 		case 'danger':
@@ -53,7 +56,8 @@  discard block
 block discarded – undo
53 56
 	 *
54 57
 	 * @return string
55 58
 	 */
56
-	protected function formatSecondaryMenu() {
59
+	protected function formatSecondaryMenu()
60
+	{
57 61
 		return
58 62
 			'<ul class="secondary-menu">' .
59 63
 			implode('', $this->secondaryMenu()) .
@@ -68,7 +72,8 @@  discard block
 block discarded – undo
68 72
 	 *
69 73
 	 * @return string
70 74
 	 */
71
-	protected function headerContent() {
75
+	protected function headerContent()
76
+	{
72 77
 		return
73 78
 			//$this->accessibilityLinks() .
74 79
 			$this->formatTreeTitle() .
@@ -82,7 +87,8 @@  discard block
 block discarded – undo
82 87
 	 *
83 88
 	 * @return string
84 89
 	 */
85
-	protected function formatSecondaryMenuItem(Menu $menu) {
90
+	protected function formatSecondaryMenuItem(Menu $menu)
91
+	{
86 92
 		return $menu->getMenuAsList();
87 93
 	}
88 94
 
@@ -91,7 +97,8 @@  discard block
 block discarded – undo
91 97
 	 *
92 98
 	 * @return string
93 99
 	 */
94
-	protected function formQuickSearchFields() {
100
+	protected function formQuickSearchFields()
101
+	{
95 102
 		return
96 103
 			'<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
97 104
 	}
@@ -101,7 +108,8 @@  discard block
 block discarded – undo
101 108
 	 *
102 109
 	 * @return string
103 110
 	 */
104
-	public function hookFooterExtraJavascript() {
111
+	public function hookFooterExtraJavascript()
112
+	{
105 113
 		return
106 114
 			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
107 115
 			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
@@ -125,7 +133,8 @@  discard block
 block discarded – undo
125 133
 	 *
126 134
 	 * @return string|int|float
127 135
 	 */
128
-	public function parameter($parameter_name) {
136
+	public function parameter($parameter_name)
137
+	{
129 138
 		$parameters = array(
130 139
 			'chart-background-f'             => 'e9daf1',
131 140
 			'chart-background-m'             => 'b1cff0',
@@ -147,7 +156,8 @@  discard block
 block discarded – undo
147 156
 	 *
148 157
 	 * @return string[]
149 158
 	 */
150
-	protected function stylesheets() {
159
+	protected function stylesheets()
160
+	{
151 161
 		return array(
152 162
 			'themes/fab/jquery-ui-1.11.2/jquery-ui.css',
153 163
 			$this->assetUrl() . 'style.css',
@@ -159,7 +169,8 @@  discard block
 block discarded – undo
159 169
 	 *
160 170
 	 * @return string
161 171
 	 */
162
-	public function themeId() {
172
+	public function themeId()
173
+	{
163 174
 		return 'fab';
164 175
 	}
165 176
 
@@ -168,7 +179,8 @@  discard block
 block discarded – undo
168 179
 	 *
169 180
 	 * @return string
170 181
 	 */
171
-	public function themeName() {
182
+	public function themeName()
183
+	{
172 184
 		return /* I18N: Name of a theme. */ I18N::translate('F.A.B.');
173 185
 	}
174 186
 }
Please login to merge, or discard this patch.
Switch Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -42,10 +42,10 @@
 block discarded – undo
42 42
 	protected function flashMessageContainer(\stdClass $message) {
43 43
 		// This theme uses jQueryUI markup.
44 44
 		switch ($message->status) {
45
-		case 'danger':
46
-			return '<p class="ui-state-error">' . $message->text . '</p>';
47
-		default:
48
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
45
+		    case 'danger':
46
+			    return '<p class="ui-state-error">' . $message->text . '</p>';
47
+		    default:
48
+			    return '<p class="ui-state-highlight">' . $message->text . '</p>';
49 49
 		}
50 50
 	}
51 51
 
Please login to merge, or discard this patch.
app/Theme/AbstractTheme.php 3 patches
Indentation   +2034 added lines, -2034 removed lines patch added patch discarded remove patch
@@ -53,2038 +53,2038 @@
 block discarded – undo
53 53
  * Common functions for all themes.
54 54
  */
55 55
 abstract class AbstractTheme {
56
-	/** @var Tree The current tree */
57
-	protected $tree;
58
-
59
-	/** @var string An escaped version of the "ged=XXX" URL parameter */
60
-	protected $tree_url;
61
-
62
-	/** @var int The number of times this page has been shown */
63
-	protected $page_views;
64
-
65
-	/**
66
-	 * Custom themes should place their initialization code in the function hookAfterInit(), not in
67
-	 * the constructor, as all themes get constructed - whether they are used or not.
68
-	 */
69
-	final public function __construct() {
70
-	}
71
-
72
-	/**
73
-	 * Create accessibility links for the header.
74
-	 *
75
-	 * "Skip to content" allows keyboard only users to navigate over the headers without
76
-	 * pressing TAB many times.
77
-	 *
78
-	 * @return string
79
-	 */
80
-	protected function accessibilityLinks() {
81
-		return
82
-			'<div class="accessibility-links">' .
83
-			'<a class="sr-only sr-only-focusable btn btn-info btn-sm" href="#content">' .
84
-			/* I18N: Skip over the headers and menus, to the main content of the page */ I18N::translate('Skip to content') .
85
-			'</a>' .
86
-			'</div>';
87
-	}
88
-
89
-	/**
90
-	 * Create scripts for analytics and tracking.
91
-	 *
92
-	 * @return string
93
-	 */
94
-	protected function analytics() {
95
-		if ($this->themeId() === '_administration' || !empty($_SERVER['HTTP_DNT'])) {
96
-			return '';
97
-		} else {
98
-			return
99
-				$this->analyticsBingWebmaster(
100
-					Site::getPreference('BING_WEBMASTER_ID')
101
-				) .
102
-				$this->analyticsGoogleWebmaster(
103
-					Site::getPreference('GOOGLE_WEBMASTER_ID')
104
-				) .
105
-				$this->analyticsGoogleTracker(
106
-					Site::getPreference('GOOGLE_ANALYTICS_ID')
107
-				) .
108
-				$this->analyticsPiwikTracker(
109
-					Site::getPreference('PIWIK_URL'),
110
-					Site::getPreference('PIWIK_SITE_ID')
111
-				) .
112
-				$this->analyticsStatcounterTracker(
113
-					Site::getPreference('STATCOUNTER_PROJECT_ID'),
114
-					Site::getPreference('STATCOUNTER_SECURITY_ID')
115
-				);
116
-		}
117
-	}
118
-
119
-	/**
120
-	 * Create the verification code for Google Webmaster Tools.
121
-	 *
122
-	 * @param string $verification_id
123
-	 *
124
-	 * @return string
125
-	 */
126
-	protected function analyticsBingWebmaster($verification_id) {
127
-		// Only need to add this to the home page.
128
-		if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
129
-			return '<meta name="msvalidate.01" content="' . $verification_id . '">';
130
-		} else {
131
-			return '';
132
-		}
133
-	}
134
-
135
-	/**
136
-	 * Create the verification code for Google Webmaster Tools.
137
-	 *
138
-	 * @param string $verification_id
139
-	 *
140
-	 * @return string
141
-	 */
142
-	protected function analyticsGoogleWebmaster($verification_id) {
143
-		// Only need to add this to the home page.
144
-		if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
145
-			return '<meta name="google-site-verification" content="' . $verification_id . '">';
146
-		} else {
147
-			return '';
148
-		}
149
-	}
150
-
151
-	/**
152
-	 * Create the tracking code for Google Analytics.
153
-	 *
154
-	 * See https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced
155
-	 *
156
-	 * @param string $analytics_id
157
-	 *
158
-	 * @return string
159
-	 */
160
-	protected function analyticsGoogleTracker($analytics_id) {
161
-		if ($analytics_id) {
162
-			// Add extra dimensions (i.e. filtering categories)
163
-			$dimensions = (object) array(
164
-				'dimension1' => $this->tree ? $this->tree->getName() : '-',
165
-				'dimension2' => $this->tree ? Auth::accessLevel($this->tree) : '-',
166
-			);
167
-
168
-			return
169
-				'<script async src="https://www.google-analytics.com/analytics.js"></script>' .
170
-				'<script>' .
171
-				'window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;' .
172
-				'ga("create","' . $analytics_id . '","auto");' .
173
-				'ga("send", "pageview", ' . json_encode($dimensions) . ');' .
174
-				'</script>';
175
-		} else {
176
-			return '';
177
-		}
178
-	}
179
-
180
-	/**
181
-	 * Create the tracking code for Piwik Analytics.
182
-	 *
183
-	 * @param string $url     - The domain/path to Piwik
184
-	 * @param string $site_id - The Piwik site identifier
185
-	 *
186
-	 * @return string
187
-	 */
188
-	protected function analyticsPiwikTracker($url, $site_id) {
189
-		$url = preg_replace(array('/^https?:\/\//', '/\/$/'), '', $url);
190
-
191
-		if ($url && $site_id) {
192
-			return
193
-				'<script>' .
194
-				'var _paq=_paq||[];' .
195
-				'(function(){var u=(("https:"==document.location.protocol)?"https://' . $url . '/":"http://' . $url . '/");' .
196
-				'_paq.push(["setSiteId",' . $site_id . ']);' .
197
-				'_paq.push(["setTrackerUrl",u+"piwik.php"]);' .
198
-				'_paq.push(["trackPageView"]);' .
199
-				'_paq.push(["enableLinkTracking"]);' .
200
-				'var d=document,g=d.createElement("script"),s=d.getElementsByTagName("script")[0];g.defer=true;g.async=true;g.src=u+"piwik.js";' .
201
-				's.parentNode.insertBefore(g,s);})();' .
202
-				'</script>';
203
-		} else {
204
-			return '';
205
-		}
206
-	}
207
-
208
-	/**
209
-	 * Create the tracking code for Statcounter.
210
-	 *
211
-	 * @param string $project_id  - The statcounter project ID
212
-	 * @param string $security_id - The statcounter security ID
213
-	 *
214
-	 * @return string
215
-	 */
216
-	protected function analyticsStatcounterTracker($project_id, $security_id) {
217
-		if ($project_id && $security_id) {
218
-			return
219
-				'<script>' .
220
-				'var sc_project=' . (int) $project_id . ',sc_invisible=1,sc_security="' . $security_id .
221
-				'",scJsHost = (("https:"===document.location.protocol)?"https://secure.":"http://www.");' .
222
-				'document.write("<sc"+"ript src=\'"+scJsHost+"statcounter.com/counter/counter.js\'></"+"script>");' .
223
-				'</script>';
224
-		} else {
225
-			return '';
226
-		}
227
-	}
228
-
229
-	/**
230
-	 * Create the top of the <body>.
231
-	 *
232
-	 * @return string
233
-	 */
234
-	public function bodyHeader() {
235
-		return
236
-			'<body class="container">' .
237
-			'<header>' .
238
-			$this->headerContent() .
239
-			$this->primaryMenuContainer($this->primaryMenu()) .
240
-			'</header>' .
241
-			'<main id="content">' .
242
-			$this->flashMessagesContainer(FlashMessages::getMessages());
243
-	}
244
-
245
-	/**
246
-	 * Create the top of the <body> (for popup windows).
247
-	 *
248
-	 * @return string
249
-	 */
250
-	public function bodyHeaderPopupWindow() {
251
-		return
252
-			'<body class="container container-popup">' .
253
-			'<main id="content">' .
254
-			$this->flashMessagesContainer(FlashMessages::getMessages());
255
-	}
256
-
257
-	/**
258
-	 * Create a contact link for a user.
259
-	 *
260
-	 * @param User $user
261
-	 *
262
-	 * @return string
263
-	 */
264
-	public function contactLink(User $user) {
265
-		$method = $user->getPreference('contactmethod');
266
-
267
-		switch ($method) {
268
-		case 'none':
269
-			return '';
270
-		case 'mailto':
271
-			return '<a href="mailto:' . Filter::escapeHtml($user->getEmail()) . '">' . $user->getRealNameHtml() . '</a>';
272
-		default:
273
-			return "<a href='#' onclick='message(\"" . Filter::escapeHtml($user->getUserName()) . "\", \"" . $method . "\", \"" . WT_BASE_URL . Filter::escapeHtml(Functions::getQueryUrl()) . "\", \"\");return false;'>" . $user->getRealNameHtml() . '</a>';
274
-		}
275
-	}
276
-
277
-	/**
278
-	 * Create contact link for both technical and genealogy support.
279
-	 *
280
-	 * @param User $user
281
-	 *
282
-	 * @return string
283
-	 */
284
-	protected function contactLinkEverything(User $user) {
285
-		return I18N::translate('For technical support or genealogy questions contact %s.', $this->contactLink($user));
286
-	}
287
-
288
-	/**
289
-	 * Create contact link for genealogy support.
290
-	 *
291
-	 * @param User $user
292
-	 *
293
-	 * @return string
294
-	 */
295
-	protected function contactLinkGenealogy(User $user) {
296
-		return I18N::translate('For help with genealogy questions contact %s.', $this->contactLink($user));
297
-	}
298
-
299
-	/**
300
-	 * Create contact link for technical support.
301
-	 *
302
-	 * @param User $user
303
-	 *
304
-	 * @return string
305
-	 */
306
-	protected function contactLinkTechnical(User $user) {
307
-		return I18N::translate('For technical support and information contact %s.', $this->contactLink($user));
308
-	}
309
-
310
-	/**
311
-	 * Create contact links for the page footer.
312
-	 *
313
-	 * @return string
314
-	 */
315
-	protected function contactLinks() {
316
-		$contact_user   = User::find($this->tree->getPreference('CONTACT_USER_ID'));
317
-		$webmaster_user = User::find($this->tree->getPreference('WEBMASTER_USER_ID'));
318
-
319
-		if ($contact_user && $contact_user === $webmaster_user) {
320
-			return $this->contactLinkEverything($contact_user);
321
-		} elseif ($contact_user && $webmaster_user) {
322
-			return $this->contactLinkGenealogy($contact_user) . '<br>' . $this->contactLinkTechnical($webmaster_user);
323
-		} elseif ($contact_user) {
324
-			return $this->contactLinkGenealogy($contact_user);
325
-		} elseif ($webmaster_user) {
326
-			return $this->contactLinkTechnical($webmaster_user);
327
-		} else {
328
-			return '';
329
-		}
330
-	}
331
-
332
-	/**
333
-	 * Create a cookie warning.
334
-	 *
335
-	 * @return string
336
-	 */
337
-	public function cookieWarning() {
338
-		if (
339
-			empty($_SERVER['HTTP_DNT']) &&
340
-			empty($_COOKIE['cookie']) &&
341
-			(Site::getPreference('GOOGLE_ANALYTICS_ID') || Site::getPreference('PIWIK_SITE_ID') || Site::getPreference('STATCOUNTER_PROJECT_ID'))
342
-		) {
343
-			return
344
-				'<div class="cookie-warning">' .
345
-				I18N::translate('Cookies') . ' - ' .
346
-				I18N::translate('This website uses cookies to learn about visitor behaviour.') . ' ' .
347
-				'<button onclick="document.cookie=\'cookie=1\'; this.parentNode.classList.add(\'hidden\');">' . I18N::translate('continue') . '</button>' .
348
-				'</div>';
349
-		} else {
350
-			return '';
351
-		}
352
-	}
353
-
354
-	/**
355
-	 * Create the <DOCTYPE> tag.
356
-	 *
357
-	 * @return string
358
-	 */
359
-	public function doctype() {
360
-		return '<!DOCTYPE html>';
361
-	}
362
-
363
-	/**
364
-	 * HTML link to a "favorites icon".
365
-	 *
366
-	 * @return string
367
-	 */
368
-	protected function favicon() {
369
-		return
370
-			'<link rel="icon" href="' . $this->assetUrl() . 'favicon.png" type="image/png">' .
371
-			'<link rel="icon" type="image/png" href="' . $this->assetUrl() . 'favicon192.png" sizes="192x192">' .
372
-			'<link rel="apple-touch-icon" sizes="180x180" href="' . $this->assetUrl() . 'favicon180.png">';
373
-	}
374
-
375
-	/**
376
-	 * Add markup to a flash message.
377
-	 *
378
-	 * @param \stdClass $message
379
-	 *
380
-	 * @return string
381
-	 */
382
-	protected function flashMessageContainer(\stdClass $message) {
383
-		return $this->htmlAlert($message->text, $message->status, true);
384
-	}
385
-
386
-	/**
387
-	 * Create a container for messages that are "flashed" to the session
388
-	 * on one request, and displayed on another. If there are many messages,
389
-	 * the container may need a max-height and scroll-bar.
390
-	 *
391
-	 * @param \stdClass[] $messages
392
-	 *
393
-	 * @return string
394
-	 */
395
-	protected function flashMessagesContainer(array $messages) {
396
-		$html = '';
397
-		foreach ($messages as $message) {
398
-			$html .= $this->flashMessageContainer($message);
399
-		}
400
-
401
-		if ($html) {
402
-			return '<div class="flash-messages">' . $html . '</div>';
403
-		} else {
404
-			return '';
405
-		}
406
-	}
407
-
408
-	/**
409
-	 * Close the main content and create the <footer> tag.
410
-	 *
411
-	 * @return string
412
-	 */
413
-	public function footerContainer() {
414
-		return '</main><footer>' . $this->footerContent() . '</footer>';
415
-	}
416
-
417
-	/**
418
-	 * Close the main content.
419
-	 * Note that popup windows are deprecated
420
-	 *
421
-	 * @return string
422
-	 */
423
-	public function footerContainerPopupWindow() {
424
-		return '</main>';
425
-	}
426
-
427
-	/**
428
-	 * Create the contents of the <footer> tag.
429
-	 *
430
-	 * @return string
431
-	 */
432
-	protected function footerContent() {
433
-		return
434
-			$this->formatContactLinks() .
435
-			$this->logoPoweredBy() .
436
-			$this->formatPageViews($this->page_views) .
437
-			$this->cookieWarning();
438
-	}
439
-
440
-	/**
441
-	 * Format the contents of a variable-height home-page block.
442
-	 *
443
-	 * @param string $id
444
-	 * @param string $title
445
-	 * @param string $class
446
-	 * @param string $content
447
-	 *
448
-	 * @return string
449
-	 */
450
-	public function formatBlock($id, $title, $class, $content) {
451
-		return
452
-			'<div id="' . $id . '" class="block" >' .
453
-			'<div class="blockheader">' . $title . '</div>' .
454
-			'<div class="blockcontent ' . $class . '">' . $content . '</div>' .
455
-			'</div>';
456
-	}
457
-
458
-	/**
459
-	 * Add markup to the contact links.
460
-	 *
461
-	 * @return string
462
-	 */
463
-	protected function formatContactLinks() {
464
-		if ($this->tree) {
465
-			return '<div class="contact-links">' . $this->contactLinks() . '</div>';
466
-		} else {
467
-			return '';
468
-		}
469
-	}
470
-
471
-	/**
472
-	 * Add markup to the hit counter.
473
-	 *
474
-	 * @param int $count
475
-	 *
476
-	 * @return string
477
-	 */
478
-	protected function formatPageViews($count) {
479
-		if ($count > 0) {
480
-			return
481
-				'<div class="page-views">' .
482
-				I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $count,
483
-					'<span class="odometer">' . I18N::digits($count) . '</span>') .
484
-				'</div>';
485
-		} else {
486
-			return '';
487
-		}
488
-	}
489
-
490
-	/**
491
-	 * Create a pending changes link for the page footer.
492
-	 *
493
-	 * @return string
494
-	 */
495
-	protected function formatPendingChangesLink() {
496
-		if ($this->pendingChangesExist()) {
497
-			return '<div class="pending-changes-link">' . $this->pendingChangesLink() . '</div>';
498
-		} else {
499
-			return '';
500
-		}
501
-	}
502
-
503
-	/**
504
-	 * Create a quick search form for the header.
505
-	 *
506
-	 * @return string
507
-	 */
508
-	protected function formQuickSearch() {
509
-		if ($this->tree) {
510
-			return
511
-				'<form action="search.php" class="header-search" role="search">' .
512
-				'<input type="hidden" name="action" value="header">' .
513
-				'<input type="hidden" name="ged" value="' . $this->tree->getNameHtml() . '">' .
514
-				$this->formQuickSearchFields() .
515
-				'</form>';
516
-		} else {
517
-			return '';
518
-		}
519
-	}
520
-
521
-	/**
522
-	 * Create a search field and submit button for the quick search form in the header.
523
-	 *
524
-	 * @return string
525
-	 */
526
-	protected function formQuickSearchFields() {
527
-		return
528
-			'<input type="search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
529
-			'<input type="image" src="' . $this->assetUrl() . 'images/go.png" alt="' . I18N::translate('Search') . '">';
530
-	}
531
-
532
-	/**
533
-	 * Add markup to the tree title.
534
-	 *
535
-	 * @return string
536
-	 */
537
-	protected function formatTreeTitle() {
538
-		if ($this->tree) {
539
-			return '<h1 class="header-title">' . $this->tree->getTitleHtml() . '</h1>';
540
-		} else {
541
-			return '';
542
-		}
543
-	}
544
-
545
-	/**
546
-	 * Add markup to the secondary menu.
547
-	 *
548
-	 * @return string
549
-	 */
550
-	protected function formatSecondaryMenu() {
551
-		return
552
-			'<ul class="secondary-menu">' .
553
-			implode('', $this->secondaryMenu()) .
554
-			'</ul>';
555
-	}
556
-
557
-	/**
558
-	 * Add markup to an item in the secondary menu.
559
-	 *
560
-	 * @param Menu $menu
561
-	 *
562
-	 * @return string
563
-	 */
564
-	protected function formatSecondaryMenuItem(Menu $menu) {
565
-		return $menu->getMenuAsList();
566
-	}
567
-
568
-	/**
569
-	 * Create the <head> tag.
570
-	 *
571
-	 * @param PageController $controller The current controller
572
-	 *
573
-	 * @return string
574
-	 */
575
-	public function head(PageController $controller) {
576
-		// Record this now. By the time we render the footer, $controller no longer exists.
577
-		$this->page_views = $this->pageViews($controller);
578
-
579
-		return
580
-			'<head>' .
581
-			$this->headContents($controller) .
582
-			$this->hookHeaderExtraContent() .
583
-			$this->analytics() .
584
-			'</head>';
585
-	}
586
-
587
-	/**
588
-	 * Create the contents of the <head> tag.
589
-	 *
590
-	 * @param PageController $controller The current controller
591
-	 *
592
-	 * @return string
593
-	 */
594
-	protected function headContents(PageController $controller) {
595
-		// The title often includes the names of records, which may include HTML markup.
596
-		$title = Filter::unescapeHtml($controller->getPageTitle());
597
-
598
-		// If an extra (site) title is specified, append it.
599
-		if ($this->tree && $this->tree->getPreference('META_TITLE')) {
600
-			$title .= ' – ' . $this->tree->getPreference('META_TITLE');
601
-		}
602
-
603
-		$html =
604
-			// modernizr.js and respond.js need to be loaded before the <body> to avoid FOUC
605
-			'<!--[if IE 8]><script src="' . WT_MODERNIZR_JS_URL . '"></script><![endif]-->' .
606
-			'<!--[if IE 8]><script src="' . WT_RESPOND_JS_URL . '"></script><![endif]-->' .
607
-			$this->metaCharset() .
608
-			$this->title($title) .
609
-			$this->favicon() .
610
-			$this->metaViewport() .
611
-			$this->metaRobots($controller->getMetaRobots()) .
612
-			$this->metaUaCompatible() .
613
-			$this->metaGenerator(WT_WEBTREES . ' ' . WT_VERSION . ' - ' . WT_WEBTREES_URL);
614
-
615
-		if ($this->tree) {
616
-			$html .= $this->metaDescription($this->tree->getPreference('META_DESCRIPTION'));
617
-		}
618
-
619
-		// CSS files
620
-		foreach ($this->stylesheets() as $css) {
621
-			$html .= '<link rel="stylesheet" type="text/css" href="' . $css . '">';
622
-		}
623
-
624
-		return $html;
625
-	}
626
-
627
-	/**
628
-	 * Create the contents of the <header> tag.
629
-	 *
630
-	 * @return string
631
-	 */
632
-	protected function headerContent() {
633
-		return
634
-			//$this->accessibilityLinks() .
635
-			$this->logoHeader() .
636
-			$this->secondaryMenuContainer($this->secondaryMenu()) .
637
-			$this->formatTreeTitle() .
638
-			$this->formQuickSearch();
639
-	}
640
-
641
-	/**
642
-	 * Create the <header> tag for a popup window.
643
-	 *
644
-	 * @return string
645
-	 */
646
-	protected function headerSimple() {
647
-		return
648
-			$this->flashMessagesContainer(FlashMessages::getMessages()) .
649
-			'<div id="content">';
650
-	}
651
-
652
-	/**
653
-	 * Allow themes to do things after initialization (since they cannot use
654
-	 * the constructor).
655
-	 */
656
-	public function hookAfterInit() {
657
-	}
658
-
659
-	/**
660
-	 * Allow themes to add extra scripts to the page footer.
661
-	 *
662
-	 * @return string
663
-	 */
664
-	public function hookFooterExtraJavascript() {
665
-		return '';
666
-	}
667
-
668
-	/**
669
-	 * Allow themes to add extra content to the page header.
670
-	 * Typically this will be additional CSS.
671
-	 *
672
-	 * @return string
673
-	 */
674
-	public function hookHeaderExtraContent() {
675
-		return '';
676
-	}
677
-
678
-	/**
679
-	 * Create the <html> tag.
680
-	 *
681
-	 * @return string
682
-	 */
683
-	public function html() {
684
-		return '<html ' . I18N::htmlAttributes() . '>';
685
-	}
686
-
687
-	/**
688
-	 * Add HTML markup to create an alert
689
-	 *
690
-	 * @param string $html        The content of the alert
691
-	 * @param string $level       One of 'success', 'info', 'warning', 'danger'
692
-	 * @param bool   $dismissible If true, add a close button.
693
-	 *
694
-	 * @return string
695
-	 */
696
-	public function htmlAlert($html, $level, $dismissible) {
697
-		if ($dismissible) {
698
-			return
699
-				'<div class="alert alert-' . $level . ' alert-dismissible" role="alert">' .
700
-				'<button type="button" class="close" data-dismiss="alert" aria-label="' . I18N::translate('close') . '">' .
701
-				'<span aria-hidden="true">&times;</span>' .
702
-				'</button>' .
703
-				$html .
704
-				'</div>';
705
-		} else {
706
-			return
707
-				'<div class="alert alert-' . $level . '" role="alert">' .
708
-				$html .
709
-				'</div>';
710
-		}
711
-	}
712
-
713
-	/**
714
-	 * Display an icon for this fact.
715
-	 *
716
-	 * @param Fact $fact
717
-	 *
718
-	 * @return string
719
-	 */
720
-	public function icon(Fact $fact) {
721
-		$icon = 'images/facts/' . $fact->getTag() . '.png';
722
-		$dir  = substr($this->assetUrl(), strlen(WT_STATIC_URL));
723
-		if (file_exists($dir . $icon)) {
724
-			return '<img src="' . $this->assetUrl() . $icon . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">';
725
-		} elseif (file_exists($dir . 'images/facts/NULL.png')) {
726
-			// Spacer image - for alignment - until we move to a sprite.
727
-			return '<img src="' . Theme::theme()->assetUrl() . 'images/facts/NULL.png">';
728
-		} else {
729
-			return '';
730
-		}
731
-	}
732
-
733
-	/**
734
-	 * Display an individual in a box - for charts, etc.
735
-	 *
736
-	 * @param Individual $individual
737
-	 *
738
-	 * @return string
739
-	 */
740
-	public function individualBox(Individual $individual) {
741
-		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
742
-		if ($individual->canShow() && $individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
743
-			$thumbnail = $individual->displayImage();
744
-		} else {
745
-			$thumbnail = '';
746
-		}
747
-
748
-		$content = '<span class="namedef name1">' . $individual->getFullName() . '</span>';
749
-		$icons   = '';
750
-		if ($individual->canShow()) {
751
-			$content =
752
-				'<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
753
-				'<div class="namedef name1">' . $individual->getAddName() . '</div>';
754
-			$icons   =
755
-				'<div class="noprint icons">' .
756
-				'<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
757
-				'<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
758
-				'<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
759
-				'</div>' .
760
-				'</div>' .
761
-				'</div>';
762
-		}
763
-
764
-		return
765
-			'<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px">' .
766
-			$icons .
767
-			'<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' .
768
-			$thumbnail .
769
-			$content .
770
-			'<div class="inout2 details1">' . $this->individualBoxFacts($individual) . '</div>' .
771
-			'</div>' .
772
-			'<div class="inout"></div>' .
773
-			'</div>';
774
-	}
775
-
776
-	/**
777
-	 * Display an empty box - for a missing individual in a chart.
778
-	 *
779
-	 * @return string
780
-	 */
781
-	public function individualBoxEmpty() {
782
-		return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px"></div>';
783
-	}
784
-
785
-	/**
786
-	 * Display an individual in a box - for charts, etc.
787
-	 *
788
-	 * @param Individual $individual
789
-	 *
790
-	 * @return string
791
-	 */
792
-	public function individualBoxLarge(Individual $individual) {
793
-		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
794
-		if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
795
-			$thumbnail = $individual->displayImage();
796
-		} else {
797
-			$thumbnail = '';
798
-		}
799
-
800
-		$content = '<span class="namedef name1">' . $individual->getFullName() . '</span>';
801
-		$icons   = '';
802
-		if ($individual->canShow()) {
803
-			$content =
804
-				'<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
805
-				'<div class="namedef name2">' . $individual->getAddName() . '</div>';
806
-			$icons   =
807
-				'<div class="noprint icons">' .
808
-				'<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
809
-				'<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
810
-				'<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
811
-				'</div>' .
812
-				'</div>' .
813
-				'</div>';
814
-		}
815
-
816
-		return
817
-			'<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' box-style2">' .
818
-			$icons .
819
-			'<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' .
820
-			$thumbnail .
821
-			$content .
822
-			'<div class="inout2 details2">' . $this->individualBoxFacts($individual) . '</div>' .
823
-			'</div>' .
824
-			'<div class="inout"></div>' .
825
-			'</div>';
826
-	}
827
-
828
-	/**
829
-	 * Display an individual in a box - for charts, etc.
830
-	 *
831
-	 * @param Individual $individual
832
-	 *
833
-	 * @return string
834
-	 */
835
-	public function individualBoxSmall(Individual $individual) {
836
-		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
837
-		if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
838
-			$thumbnail = $individual->displayImage();
839
-		} else {
840
-			$thumbnail = '';
841
-		}
842
-
843
-		return
844
-			'<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' iconz box-style0" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px">' .
845
-			'<div class="compact_view">' .
846
-			$thumbnail .
847
-			'<a href="' . $individual->getHtmlUrl() . '">' .
848
-			'<span class="namedef name0">' . $individual->getFullName() . '</span>' .
849
-			'</a>' .
850
-			'<div class="inout2 details0">' . $individual->getLifeSpan() . '</div>' .
851
-			'</div>' .
852
-			'<div class="inout"></div>' .
853
-			'</div>';
854
-	}
855
-
856
-	/**
857
-	 * Display an individual in a box - for charts, etc.
858
-	 *
859
-	 * @return string
860
-	 */
861
-	public function individualBoxSmallEmpty() {
862
-		return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px"></div>';
863
-	}
864
-
865
-	/**
866
-	 * Generate the facts, for display in charts.
867
-	 *
868
-	 * @param Individual $individual
869
-	 *
870
-	 * @return string
871
-	 */
872
-	protected function individualBoxFacts(Individual $individual) {
873
-		$html = '';
874
-
875
-		$opt_tags = preg_split('/\W/', $individual->getTree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY);
876
-		// Show BIRT or equivalent event
877
-		foreach (explode('|', WT_EVENTS_BIRT) as $birttag) {
878
-			if (!in_array($birttag, $opt_tags)) {
879
-				$event = $individual->getFirstFact($birttag);
880
-				if ($event) {
881
-					$html .= $event->summary();
882
-					break;
883
-				}
884
-			}
885
-		}
886
-		// Show optional events (before death)
887
-		foreach ($opt_tags as $key => $tag) {
888
-			if (!preg_match('/^(' . WT_EVENTS_DEAT . ')$/', $tag)) {
889
-				$event = $individual->getFirstFact($tag);
890
-				if (!is_null($event)) {
891
-					$html .= $event->summary();
892
-					unset($opt_tags[$key]);
893
-				}
894
-			}
895
-		}
896
-		// Show DEAT or equivalent event
897
-		foreach (explode('|', WT_EVENTS_DEAT) as $deattag) {
898
-			$event = $individual->getFirstFact($deattag);
899
-			if ($event) {
900
-				$html .= $event->summary();
901
-				if (in_array($deattag, $opt_tags)) {
902
-					unset($opt_tags[array_search($deattag, $opt_tags)]);
903
-				}
904
-				break;
905
-			}
906
-		}
907
-		// Show remaining optional events (after death)
908
-		foreach ($opt_tags as $tag) {
909
-			$event = $individual->getFirstFact($tag);
910
-			if ($event) {
911
-				$html .= $event->summary();
912
-			}
913
-		}
914
-
915
-		return $html;
916
-	}
917
-
918
-	/**
919
-	 * Generate the LDS summary, for display in charts.
920
-	 *
921
-	 * @param Individual $individual
922
-	 *
923
-	 * @return string
924
-	 */
925
-	protected function individualBoxLdsSummary(Individual $individual) {
926
-		if ($individual->getTree()->getPreference('SHOW_LDS_AT_GLANCE')) {
927
-			$BAPL = $individual->getFacts('BAPL') ? 'B' : '_';
928
-			$ENDL = $individual->getFacts('ENDL') ? 'E' : '_';
929
-			$SLGC = $individual->getFacts('SLGC') ? 'C' : '_';
930
-			$SLGS = '_';
931
-
932
-			foreach ($individual->getSpouseFamilies() as $family) {
933
-				if ($family->getFacts('SLGS')) {
934
-					$SLGS = '';
935
-				}
936
-			}
937
-
938
-			return $BAPL . $ENDL . $SLGS . $SLGC;
939
-		} else {
940
-			return '';
941
-		}
942
-	}
943
-
944
-	/**
945
-	 * Links, to show in chart boxes;
946
-	 *
947
-	 * @param Individual $individual
948
-	 *
949
-	 * @return Menu[]
950
-	 */
951
-	public function individualBoxMenu(Individual $individual) {
952
-		$menus = array_merge(
953
-			$this->individualBoxMenuCharts($individual),
954
-			$this->individualBoxMenuFamilyLinks($individual)
955
-		);
956
-
957
-		return $menus;
958
-	}
959
-
960
-	/**
961
-	 * Chart links, to show in chart boxes;
962
-	 *
963
-	 * @param Individual $individual
964
-	 *
965
-	 * @return Menu[]
966
-	 */
967
-	protected function individualBoxMenuCharts(Individual $individual) {
968
-		$menus = array();
969
-		foreach (Module::getActiveCharts($this->tree) as $chart) {
970
-			$menu = $chart->getBoxChartMenu($individual);
971
-			if ($menu) {
972
-				$menus[] = $menu;
973
-			}
974
-		}
975
-
976
-		usort($menus, function (Menu $x, Menu $y) {
977
-			return I18N::strcasecmp($x->getLabel(), $y->getLabel());
978
-		});
979
-
980
-		return $menus;
981
-	}
982
-
983
-	/**
984
-	 * Family links, to show in chart boxes.
985
-	 *
986
-	 * @param Individual $individual
987
-	 *
988
-	 * @return Menu[]
989
-	 */
990
-	protected function individualBoxMenuFamilyLinks(Individual $individual) {
991
-		$menus = array();
992
-
993
-		foreach ($individual->getSpouseFamilies() as $family) {
994
-			$menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->getHtmlUrl());
995
-			$spouse  = $family->getSpouse($individual);
996
-			if ($spouse && $spouse->canShowName()) {
997
-				$menus[] = new Menu($spouse->getFullName(), $spouse->getHtmlUrl());
998
-			}
999
-			foreach ($family->getChildren() as $child) {
1000
-				if ($child->canShowName()) {
1001
-					$menus[] = new Menu($child->getFullName(), $child->getHtmlUrl());
1002
-				}
1003
-			}
1004
-		}
1005
-
1006
-		return $menus;
1007
-	}
1008
-
1009
-	/**
1010
-	 * Create part of an individual box
1011
-	 *
1012
-	 * @param Individual $individual
1013
-	 *
1014
-	 * @return string
1015
-	 */
1016
-	protected function individualBoxSexSymbol(Individual $individual) {
1017
-		if ($individual->getTree()->getPreference('PEDIGREE_SHOW_GENDER')) {
1018
-			return $individual->sexImage('large');
1019
-		} else {
1020
-			return '';
1021
-		}
1022
-	}
1023
-
1024
-	/**
1025
-	 * Initialise the theme. We cannot pass these in a constructor, as the construction
1026
-	 * happens in a theme file, and we need to be able to change it.
1027
-	 *
1028
-	 * @param Tree|null $tree The current tree (if there is one).
1029
-	 */
1030
-	final public function init(Tree $tree = null) {
1031
-		$this->tree     = $tree;
1032
-		$this->tree_url = $tree ? 'ged=' . $tree->getNameUrl() : '';
1033
-
1034
-		$this->hookAfterInit();
1035
-	}
1036
-
1037
-	/**
1038
-	 * A large webtrees logo, for the header.
1039
-	 *
1040
-	 * @return string
1041
-	 */
1042
-	protected function logoHeader() {
1043
-		return '<div class="header-logo"></div>';
1044
-	}
1045
-
1046
-	/**
1047
-	 * A small "powered by webtrees" logo for the footer.
1048
-	 *
1049
-	 * @return string
1050
-	 */
1051
-	protected function logoPoweredBy() {
1052
-		return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '"></a>';
1053
-	}
1054
-
1055
-	/**
1056
-	 * A menu for the day/month/year calendar views.
1057
-	 *
1058
-	 * @return Menu
1059
-	 */
1060
-	protected function menuCalendar() {
1061
-		return new Menu(I18N::translate('Calendar'), '#', 'menu-calendar', array('rel' => 'nofollow'), array(
1062
-			// Day view
1063
-			new Menu(I18N::translate('Day'), 'calendar.php?' . $this->tree_url . '&amp;view=day', 'menu-calendar-day', array('rel' => 'nofollow')),
1064
-			// Month view
1065
-			new Menu(I18N::translate('Month'), 'calendar.php?' . $this->tree_url . '&amp;view=month', 'menu-calendar-month', array('rel' => 'nofollow')),
1066
-			//Year view
1067
-			new Menu(I18N::translate('Year'), 'calendar.php?' . $this->tree_url . '&amp;view=year', 'menu-calendar-year', array('rel' => 'nofollow')),
1068
-		));
1069
-	}
1070
-
1071
-	/**
1072
-	 * Generate a menu item to change the blocks on the current (index.php) page.
1073
-	 *
1074
-	 * @return Menu|null
1075
-	 */
1076
-	protected function menuChangeBlocks() {
1077
-		if (WT_SCRIPT_NAME === 'index.php' && Auth::check() && Filter::get('ctype', 'gedcom|user', 'user') === 'user') {
1078
-			return new Menu(I18N::translate('Customize this page'), 'index_edit.php?user_id=' . Auth::id(), 'menu-change-blocks');
1079
-		} elseif (WT_SCRIPT_NAME === 'index.php' && Auth::isManager($this->tree)) {
1080
-			return new Menu(I18N::translate('Customize this page'), 'index_edit.php?gedcom_id=' . $this->tree->getTreeId(), 'menu-change-blocks');
1081
-		} else {
1082
-			return null;
1083
-		}
1084
-	}
1085
-
1086
-	/**
1087
-	 * Generate a menu for each of the different charts.
1088
-	 *
1089
-	 * @param Individual $individual
1090
-	 *
1091
-	 * @return Menu|null
1092
-	 */
1093
-	protected function menuChart(Individual $individual) {
1094
-		$submenus = array();
1095
-		foreach (Module::getActiveCharts($this->tree) as $chart) {
1096
-			$menu = $chart->getChartMenu($individual);
1097
-			if ($menu) {
1098
-				$submenus[] = $menu;
1099
-			}
1100
-		}
1101
-
1102
-		if ($submenus) {
1103
-			usort($submenus, function (Menu $x, Menu $y) {
1104
-				return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1105
-			});
1106
-
1107
-			return new Menu(I18N::translate('Charts'), '#', 'menu-chart', array('rel' => 'nofollow'), $submenus);
1108
-		} else {
1109
-			return null;
1110
-		}
1111
-	}
1112
-
1113
-	/**
1114
-	 * Generate a menu item for the ancestors chart.
1115
-	 *
1116
-	 * @param Individual $individual
1117
-	 *
1118
-	 * @return Menu|null
1119
-	 *
1120
-	 * @deprecated
1121
-	 */
1122
-	protected function menuChartAncestors(Individual $individual) {
1123
-		$chart = new AncestorsChartModule(WT_ROOT . WT_MODULES_DIR . 'ancestors_chart');
1124
-
1125
-		return $chart->getChartMenu($individual);
1126
-	}
1127
-
1128
-	/**
1129
-	 * Generate a menu item for the compact tree.
1130
-	 *
1131
-	 * @param Individual $individual
1132
-	 *
1133
-	 * @return Menu|null
1134
-	 *
1135
-	 * @deprecated
1136
-	 */
1137
-	protected function menuChartCompact(Individual $individual) {
1138
-		$chart = new CompactTreeChartModule(WT_ROOT . WT_MODULES_DIR . 'compact_tree_chart');
1139
-
1140
-		return $chart->getChartMenu($individual);
1141
-	}
1142
-
1143
-	/**
1144
-	 * Generate a menu item for the descendants chart.
1145
-	 *
1146
-	 * @param Individual $individual
1147
-	 *
1148
-	 * @return Menu|null
1149
-	 *
1150
-	 * @deprecated
1151
-	 */
1152
-	protected function menuChartDescendants(Individual $individual) {
1153
-		$chart = new DescendancyChartModule(WT_ROOT . WT_MODULES_DIR . 'descendancy_chart');
1154
-
1155
-		return $chart->getChartMenu($individual);
1156
-	}
1157
-
1158
-	/**
1159
-	 * Generate a menu item for the family-book chart.
1160
-	 *
1161
-	 * @param Individual $individual
1162
-	 *
1163
-	 * @return Menu|null
1164
-	 *
1165
-	 * @deprecated
1166
-	 */
1167
-	protected function menuChartFamilyBook(Individual $individual) {
1168
-		$chart = new FamilyBookChartModule(WT_ROOT . WT_MODULES_DIR . 'family_book_chart');
1169
-
1170
-		return $chart->getChartMenu($individual);
1171
-	}
1172
-
1173
-	/**
1174
-	 * Generate a menu item for the fan chart.
1175
-	 *
1176
-	 * We can only do this if the GD2 library is installed with TrueType support.
1177
-	 *
1178
-	 * @param Individual $individual
1179
-	 *
1180
-	 * @return Menu|null
1181
-	 *
1182
-	 * @deprecated
1183
-	 */
1184
-	protected function menuChartFanChart(Individual $individual) {
1185
-		$chart = new FanChartModule(WT_ROOT . WT_MODULES_DIR . 'fan_chart');
1186
-
1187
-		return $chart->getChartMenu($individual);
1188
-	}
1189
-
1190
-	/**
1191
-	 * Generate a menu item for the interactive tree.
1192
-	 *
1193
-	 * @param Individual $individual
1194
-	 *
1195
-	 * @return Menu|null
1196
-	 *
1197
-	 * @deprecated
1198
-	 */
1199
-	protected function menuChartInteractiveTree(Individual $individual) {
1200
-		$chart = new InteractiveTreeModule(WT_ROOT . WT_MODULES_DIR . 'tree');
1201
-
1202
-		return $chart->getChartMenu($individual);
1203
-	}
1204
-
1205
-	/**
1206
-	 * Generate a menu item for the hourglass chart.
1207
-	 *
1208
-	 * @param Individual $individual
1209
-	 *
1210
-	 * @return Menu|null
1211
-	 *
1212
-	 * @deprecated
1213
-	 */
1214
-	protected function menuChartHourglass(Individual $individual) {
1215
-		$chart = new HourglassChartModule(WT_ROOT . WT_MODULES_DIR . 'hourglass_chart');
1216
-
1217
-		return $chart->getChartMenu($individual);
1218
-	}
1219
-
1220
-	/**
1221
-	 * Generate a menu item for the lifepsan chart.
1222
-	 *
1223
-	 * @param Individual $individual
1224
-	 *
1225
-	 * @return Menu|null
1226
-	 *
1227
-	 * @deprecated
1228
-	 */
1229
-	protected function menuChartLifespan(Individual $individual) {
1230
-		$chart = new LifespansChartModule(WT_ROOT . WT_MODULES_DIR . 'lifespans_chart');
1231
-
1232
-		return $chart->getChartMenu($individual);
1233
-	}
1234
-
1235
-	/**
1236
-	 * Generate a menu item for the pedigree chart.
1237
-	 *
1238
-	 * @param Individual $individual
1239
-	 *
1240
-	 * @return Menu|null
1241
-	 *
1242
-	 * @deprecated
1243
-	 */
1244
-	protected function menuChartPedigree(Individual $individual) {
1245
-		$chart = new PedigreeChartModule(WT_ROOT . WT_MODULES_DIR . 'pedigree_chart');
1246
-
1247
-		return $chart->getChartMenu($individual);
1248
-	}
1249
-
1250
-	/**
1251
-	 * Generate a menu item for the pedigree map.
1252
-	 *
1253
-	 * @param Individual $individual
1254
-	 *
1255
-	 * @return Menu|null
1256
-	 *
1257
-	 * @deprecated
1258
-	 */
1259
-	protected function menuChartPedigreeMap(Individual $individual) {
1260
-		$chart = new GoogleMapsModule(WT_ROOT . WT_MODULES_DIR . 'googlemap');
1261
-
1262
-		return $chart->getChartMenu($individual);
1263
-	}
1264
-
1265
-	/**
1266
-	 * Generate a menu item for the relationship chart.
1267
-	 *
1268
-	 * @param Individual $individual
1269
-	 *
1270
-	 * @return Menu|null
1271
-	 *
1272
-	 * @deprecated
1273
-	 */
1274
-	protected function menuChartRelationship(Individual $individual) {
1275
-		$chart = new RelationshipsChartModule(WT_ROOT . WT_MODULES_DIR . 'relationships_chart');
1276
-
1277
-		return $chart->getChartMenu($individual);
1278
-	}
1279
-
1280
-	/**
1281
-	 * Generate a menu item for the statistics charts.
1282
-	 *
1283
-	 * @return Menu|null
1284
-	 *
1285
-	 * @deprecated
1286
-	 */
1287
-	protected function menuChartStatistics() {
1288
-		$chart = new StatisticsChartModule(WT_ROOT . WT_MODULES_DIR . 'statistics_chart');
1289
-
1290
-		return $chart->getChartMenu(null);
1291
-	}
1292
-
1293
-	/**
1294
-	 * Generate a menu item for the timeline chart.
1295
-	 *
1296
-	 * @param Individual $individual
1297
-	 *
1298
-	 * @return Menu|null
1299
-	 *
1300
-	 * @deprecated
1301
-	 */
1302
-	protected function menuChartTimeline(Individual $individual) {
1303
-		$chart = new TimelineChartModule(WT_ROOT . WT_MODULES_DIR . 'timeline_chart');
1304
-
1305
-		return $chart->getChartMenu($individual);
1306
-	}
1307
-
1308
-	/**
1309
-	 * Generate a menu item for the control panel.
1310
-	 *
1311
-	 * @return Menu|null
1312
-	 */
1313
-	protected function menuControlPanel() {
1314
-		if (Auth::isManager($this->tree)) {
1315
-			return new Menu(I18N::translate('Control panel'), 'admin.php', 'menu-admin');
1316
-		} else {
1317
-			return null;
1318
-		}
1319
-	}
1320
-
1321
-	/**
1322
-	 * Favorites menu.
1323
-	 *
1324
-	 * @return Menu|null
1325
-	 */
1326
-	protected function menuFavorites() {
1327
-		global $controller;
1328
-
1329
-		$show_user_favorites = $this->tree && Module::getModuleByName('user_favorites') && Auth::check();
1330
-		$show_tree_favorites = $this->tree && Module::getModuleByName('gedcom_favorites');
1331
-
1332
-		if ($show_user_favorites && $show_tree_favorites) {
1333
-			$favorites = array_merge(
1334
-				FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()),
1335
-				UserFavoritesModule::getFavorites(Auth::id())
1336
-			);
1337
-		} elseif ($show_user_favorites) {
1338
-			$favorites = UserFavoritesModule::getFavorites(Auth::id());
1339
-		} elseif ($show_tree_favorites) {
1340
-			$favorites = FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId());
1341
-		} else {
1342
-			$favorites = array();
1343
-		}
1344
-
1345
-		$submenus = array();
1346
-		$records  = array();
1347
-		foreach ($favorites as $favorite) {
1348
-			switch ($favorite['type']) {
1349
-			case 'URL':
1350
-				$submenus[] = new Menu($favorite['title'], $favorite['url']);
1351
-				break;
1352
-			case 'INDI':
1353
-			case 'FAM':
1354
-			case 'SOUR':
1355
-			case 'OBJE':
1356
-			case 'NOTE':
1357
-				$record = GedcomRecord::getInstance($favorite['gid'], $this->tree);
1358
-				if ($record && $record->canShowName()) {
1359
-					$submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl());
1360
-					$records[]  = $record;
1361
-				}
1362
-				break;
1363
-			}
1364
-		}
1365
-
1366
-		if ($show_user_favorites && isset($controller->record) && $controller->record instanceof GedcomRecord && !in_array($controller->record, $records)) {
1367
-			$submenus[] = new Menu(I18N::translate('Add to favorites'), '#', '', array(
1368
-				'onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite", {xref:"' . $controller->record->getXref() . '"},function(){location.reload();})',
1369
-			));
1370
-		}
1371
-
1372
-		if (empty($submenus)) {
1373
-			return null;
1374
-		} else {
1375
-			return new Menu(I18N::translate('Favorites'), '#', 'menu-favorites', array(), $submenus);
1376
-		}
1377
-	}
1378
-
1379
-	/**
1380
-	 * A menu for the home (family tree) pages.
1381
-	 *
1382
-	 * @return Menu
1383
-	 */
1384
-	protected function menuHomePage() {
1385
-		if (count(Tree::getAll()) === 1 || Site::getPreference('ALLOW_CHANGE_GEDCOM') === '0') {
1386
-			return new Menu(I18N::translate('Family tree'), 'index.php?ctype=gedcom&amp;' . $this->tree_url, 'menu-tree');
1387
-		} else {
1388
-			$submenus = array();
1389
-			foreach (Tree::getAll() as $tree) {
1390
-				if ($tree == $this->tree) {
1391
-					$active = 'active ';
1392
-				} else {
1393
-					$active = '';
1394
-				}
1395
-				$submenus[] = new Menu($tree->getTitleHtml(), 'index.php?ctype=gedcom&amp;ged=' . $tree->getNameUrl(), $active . 'menu-tree-' . $tree->getTreeId());
1396
-			}
1397
-
1398
-			return new Menu(I18N::translate('Family trees'), '#', 'menu-tree', array(), $submenus);
1399
-		}
1400
-	}
1401
-
1402
-	/**
1403
-	 * A menu to show a list of available languages.
1404
-	 *
1405
-	 * @return Menu|null
1406
-	 */
1407
-	protected function menuLanguages() {
1408
-		$menu = new Menu(I18N::translate('Language'), '#', 'menu-language');
1409
-
1410
-		foreach (I18N::activeLocales() as $locale) {
1411
-			$language_tag = $locale->languageTag();
1412
-			$class        = 'menu-language-' . $language_tag . (WT_LOCALE === $language_tag ? ' active' : '');
1413
-			$menu->addSubmenu(new Menu($locale->endonym(), '#', $class, array(
1414
-				'onclick'       => 'return false;',
1415
-				'data-language' => $language_tag,
1416
-			)));
1417
-		}
1418
-
1419
-		if (count($menu->getSubmenus()) > 1) {
1420
-			return $menu;
1421
-		} else {
1422
-			return null;
1423
-		}
1424
-	}
1425
-
1426
-	/**
1427
-	 * Create a menu to show lists of individuals, families, sources, etc.
1428
-	 *
1429
-	 * @param string $surname The significant surname on the page
1430
-	 *
1431
-	 * @return Menu
1432
-	 */
1433
-	protected function menuLists($surname) {
1434
-		// Do not show empty lists
1435
-		$row = Database::prepare(
1436
-			"SELECT" .
1437
-			" EXISTS(SELECT 1 FROM `##sources` WHERE s_file = ?) AS sour," .
1438
-			" EXISTS(SELECT 1 FROM `##other` WHERE o_file = ? AND o_type='REPO') AS repo," .
1439
-			" EXISTS(SELECT 1 FROM `##other` WHERE o_file = ? AND o_type='NOTE') AS note," .
1440
-			" EXISTS(SELECT 1 FROM `##media` WHERE m_file = ?) AS obje"
1441
-		)->execute(array(
1442
-			$this->tree->getTreeId(),
1443
-			$this->tree->getTreeId(),
1444
-			$this->tree->getTreeId(),
1445
-			$this->tree->getTreeId(),
1446
-		))->fetchOneRow();
1447
-
1448
-		$submenus = array(
1449
-			$this->menuListsIndividuals($surname),
1450
-			$this->menuListsFamilies($surname),
1451
-			$this->menuListsBranches($surname),
1452
-			$this->menuListsPlaces(),
1453
-		);
1454
-		if ($row->obje) {
1455
-			$submenus[] = $this->menuListsMedia();
1456
-		}
1457
-		if ($row->repo) {
1458
-			$submenus[] = $this->menuListsRepositories();
1459
-		}
1460
-		if ($row->sour) {
1461
-			$submenus[] = $this->menuListsSources();
1462
-		}
1463
-		if ($row->note) {
1464
-			$submenus[] = $this->menuListsNotes();
1465
-		}
1466
-
1467
-		uasort($submenus, function (Menu $x, Menu $y) {
1468
-			return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1469
-		});
1470
-
1471
-		return new Menu(I18N::translate('Lists'), '#', 'menu-list', array(), $submenus);
1472
-	}
1473
-
1474
-	/**
1475
-	 * A menu for the list of branches
1476
-	 *
1477
-	 * @param string $surname The significant surname on the page
1478
-	 *
1479
-	 * @return Menu
1480
-	 */
1481
-	protected function menuListsBranches($surname) {
1482
-		return new Menu(I18N::translate('Branches'), 'branches.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-branches', array('rel' => 'nofollow'));
1483
-	}
1484
-
1485
-	/**
1486
-	 * A menu for the list of families
1487
-	 *
1488
-	 * @param string $surname The significant surname on the page
1489
-	 *
1490
-	 * @return Menu
1491
-	 */
1492
-	protected function menuListsFamilies($surname) {
1493
-		return new Menu(I18N::translate('Families'), 'famlist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-fam', array('rel' => 'nofollow'));
1494
-	}
1495
-
1496
-	/**
1497
-	 * A menu for the list of individuals
1498
-	 *
1499
-	 * @param string $surname The significant surname on the page
1500
-	 *
1501
-	 * @return Menu
1502
-	 */
1503
-	protected function menuListsIndividuals($surname) {
1504
-		return new Menu(I18N::translate('Individuals'), 'indilist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-indi');
1505
-	}
1506
-
1507
-	/**
1508
-	 * A menu for the list of media objects
1509
-	 *
1510
-	 * @return Menu
1511
-	 */
1512
-	protected function menuListsMedia() {
1513
-		return new Menu(I18N::translate('Media objects'), 'medialist.php?' . $this->tree_url, 'menu-list-obje', array('rel' => 'nofollow'));
1514
-	}
1515
-
1516
-	/**
1517
-	 * A menu for the list of notes
1518
-	 *
1519
-	 * @return Menu
1520
-	 */
1521
-	protected function menuListsNotes() {
1522
-		return new Menu(I18N::translate('Shared notes'), 'notelist.php?' . $this->tree_url, 'menu-list-note', array('rel' => 'nofollow'));
1523
-	}
1524
-
1525
-	/**
1526
-	 * A menu for the list of individuals
1527
-	 *
1528
-	 * @return Menu
1529
-	 */
1530
-	protected function menuListsPlaces() {
1531
-		return new Menu(I18N::translate('Place hierarchy'), 'placelist.php?ged=' . $this->tree->getNameUrl(), 'menu-list-plac', array('rel' => 'nofollow'));
1532
-	}
1533
-
1534
-	/**
1535
-	 * A menu for the list of repositories
1536
-	 *
1537
-	 * @return Menu
1538
-	 */
1539
-	protected function menuListsRepositories() {
1540
-		return new Menu(I18N::translate('Repositories'), 'repolist.php?' . $this->tree_url, 'menu-list-repo', array('rel' => 'nofollow'));
1541
-	}
1542
-
1543
-	/**
1544
-	 * A menu for the list of sources
1545
-	 *
1546
-	 * @return Menu
1547
-	 */
1548
-	protected function menuListsSources() {
1549
-		return new Menu(I18N::translate('Sources'), 'sourcelist.php?' . $this->tree_url, 'menu-list-sour', array('rel' => 'nofollow'));
1550
-	}
1551
-
1552
-	/**
1553
-	 * A login menu option (or null if we are already logged in).
1554
-	 *
1555
-	 * @return Menu|null
1556
-	 */
1557
-	protected function menuLogin() {
1558
-		if (Auth::check() || WT_SCRIPT_NAME === 'login.php') {
1559
-			return null;
1560
-		} else {
1561
-			return new Menu(I18N::translate('Sign in'), WT_LOGIN_URL . '?url=' . rawurlencode(Functions::getQueryUrl()), 'menu-login', array('rel' => 'nofollow'));
1562
-		}
1563
-	}
1564
-
1565
-	/**
1566
-	 * A logout menu option (or null if we are already logged out).
1567
-	 *
1568
-	 * @return Menu|null
1569
-	 */
1570
-	protected function menuLogout() {
1571
-		if (Auth::check()) {
1572
-			return new Menu(I18N::translate('Sign out'), 'logout.php', 'menu-logout');
1573
-		} else {
1574
-			return null;
1575
-		}
1576
-	}
1577
-
1578
-	/**
1579
-	 * Get the additional menus created by each of the modules
1580
-	 *
1581
-	 * @return Menu[]
1582
-	 */
1583
-	protected function menuModules() {
1584
-		$menus = array();
1585
-		foreach (Module::getActiveMenus($this->tree) as $module) {
1586
-			$menus[] = $module->getMenu();
1587
-		}
1588
-
1589
-		return array_filter($menus);
1590
-	}
1591
-
1592
-	/**
1593
-	 * A link to allow users to edit their account settings (edituser.php).
1594
-	 *
1595
-	 * @return Menu|null
1596
-	 */
1597
-	protected function menuMyAccount() {
1598
-		if (Auth::check()) {
1599
-			return new Menu(I18N::translate('My account'), 'edituser.php');
1600
-		} else {
1601
-			return null;
1602
-		}
1603
-	}
1604
-
1605
-	/**
1606
-	 * A link to the user's individual record (individual.php).
1607
-	 *
1608
-	 * @return Menu|null
1609
-	 */
1610
-	protected function menuMyIndividualRecord() {
1611
-		$gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1612
-
1613
-		if ($gedcomid) {
1614
-			return new Menu(I18N::translate('My individual record'), 'individual.php?pid=' . $gedcomid . '&amp;' . $this->tree_url, 'menu-myrecord');
1615
-		} else {
1616
-			return null;
1617
-		}
1618
-	}
1619
-
1620
-	/**
1621
-	 * A link to the user's personal home page.
1622
-	 *
1623
-	 * @return Menu
1624
-	 */
1625
-	protected function menuMyPage() {
1626
-		return new Menu(I18N::translate('My page'), 'index.php?ctype=user&amp;' . $this->tree_url, 'menu-mypage');
1627
-	}
1628
-
1629
-	/**
1630
-	 * A menu for the user's personal pages.
1631
-	 *
1632
-	 * @return Menu|null
1633
-	 */
1634
-	protected function menuMyPages() {
1635
-		if (Auth::id()) {
1636
-			return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', array(), array_filter(array(
1637
-				$this->menuMyPage(),
1638
-				$this->menuMyIndividualRecord(),
1639
-				$this->menuMyPedigree(),
1640
-				$this->menuMyAccount(),
1641
-				$this->menuControlPanel(),
1642
-				$this->menuChangeBlocks(),
1643
-			)));
1644
-		} else {
1645
-			return null;
1646
-		}
1647
-	}
1648
-
1649
-	/**
1650
-	 * A link to the user's individual record.
1651
-	 *
1652
-	 * @return Menu|null
1653
-	 */
1654
-	protected function menuMyPedigree() {
1655
-		$gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1656
-
1657
-		if ($gedcomid && Module::isActiveChart($this->tree, 'pedigree_chart')) {
1658
-			$showFull   = $this->tree->getPreference('PEDIGREE_FULL_DETAILS') ? 1 : 0;
1659
-			$showLayout = $this->tree->getPreference('PEDIGREE_LAYOUT') ? 1 : 0;
1660
-
1661
-			return new Menu(
1662
-				I18N::translate('My pedigree'),
1663
-				'pedigree.php?' . $this->tree_url . '&amp;rootid=' . $gedcomid . '&amp;show_full=' . $showFull . '&amp;talloffset=' . $showLayout,
1664
-				'menu-mypedigree'
1665
-			);
1666
-		} else {
1667
-			return null;
1668
-		}
1669
-	}
1670
-
1671
-	/**
1672
-	 * Create a pending changes menu.
1673
-	 *
1674
-	 * @return Menu|null
1675
-	 */
1676
-	protected function menuPendingChanges() {
1677
-		if ($this->pendingChangesExist()) {
1678
-			$menu = new Menu(I18N::translate('Pending changes'), '#', 'menu-pending', array('onclick' => 'window.open("edit_changes.php", "_blank", chan_window_specs); return false;'));
1679
-
1680
-			return $menu;
1681
-		} else {
1682
-			return null;
1683
-		}
1684
-	}
1685
-
1686
-	/**
1687
-	 * A menu with a list of reports.
1688
-	 *
1689
-	 * @return Menu|null
1690
-	 */
1691
-	protected function menuReports() {
1692
-		$submenus = array();
1693
-		foreach (Module::getActiveReports($this->tree) as $report) {
1694
-			$submenus[] = $report->getReportMenu();
1695
-		}
1696
-
1697
-		if ($submenus) {
1698
-			return new Menu(I18N::translate('Reports'), '#', 'menu-report', array('rel' => 'nofollow'), $submenus);
1699
-		} else {
1700
-			return null;
1701
-		}
1702
-	}
1703
-
1704
-	/**
1705
-	 * Create the search menu.
1706
-	 *
1707
-	 * @return Menu
1708
-	 */
1709
-	protected function menuSearch() {
1710
-		return new Menu(I18N::translate('Search'), '#', 'menu-search', array('rel' => 'nofollow'), array_filter(array(
1711
-			$this->menuSearchGeneral(),
1712
-			$this->menuSearchPhonetic(),
1713
-			$this->menuSearchAdvanced(),
1714
-			$this->menuSearchAndReplace(),
1715
-		)));
1716
-	}
1717
-
1718
-	/**
1719
-	 * Create the general search sub-menu.
1720
-	 *
1721
-	 * @return Menu
1722
-	 */
1723
-	protected function menuSearchGeneral() {
1724
-		return new Menu(I18N::translate('General search'), 'search.php?' . $this->tree_url, 'menu-search-general', array('rel' => 'nofollow'));
1725
-	}
1726
-
1727
-	/**
1728
-	 * Create the phonetic search sub-menu.
1729
-	 *
1730
-	 * @return Menu
1731
-	 */
1732
-	protected function menuSearchPhonetic() {
1733
-		return new Menu(/* I18N: search using “sounds like”, rather than exact spelling */ I18N::translate('Phonetic search'), 'search.php?' . $this->tree_url . '&amp;action=soundex', 'menu-search-soundex', array('rel' => 'nofollow'));
1734
-	}
1735
-
1736
-	/**
1737
-	 * Create the advanced search sub-menu.
1738
-	 *
1739
-	 * @return Menu
1740
-	 */
1741
-	protected function menuSearchAdvanced() {
1742
-		return new Menu(I18N::translate('Advanced search'), 'search_advanced.php?' . $this->tree_url, 'menu-search-advanced', array('rel' => 'nofollow'));
1743
-	}
1744
-
1745
-	/**
1746
-	 * Create the advanced search sub-menu.
1747
-	 *
1748
-	 * @return Menu
1749
-	 */
1750
-	protected function menuSearchAndReplace() {
1751
-		if (Auth::isEditor($this->tree)) {
1752
-			return new Menu(I18N::translate('Search and replace'), 'search.php?' . $this->tree_url . '&amp;action=replace', 'menu-search-replace');
1753
-		} else {
1754
-			return null;
1755
-		}
1756
-	}
1757
-
1758
-	/**
1759
-	 * Themes menu.
1760
-	 *
1761
-	 * @return Menu|null
1762
-	 */
1763
-	public function menuThemes() {
1764
-		if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
1765
-			$submenus = array();
1766
-			foreach (Theme::installedThemes() as $theme) {
1767
-				$class      = 'menu-theme-' . $theme->themeId() . ($theme === $this ? ' active' : '');
1768
-				$submenus[] = new Menu($theme->themeName(), '#', $class, array(
1769
-					'onclick'    => 'return false;',
1770
-					'data-theme' => $theme->themeId(),
1771
-				));
1772
-			}
1773
-
1774
-			usort($submenus, function (Menu $x, Menu $y) {
1775
-				return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1776
-			});
1777
-
1778
-			$menu = new Menu(I18N::translate('Theme'), '#', 'menu-theme', array(), $submenus);
1779
-
1780
-			return $menu;
1781
-		} else {
1782
-			return null;
1783
-		}
1784
-	}
1785
-
1786
-	/**
1787
-	 * Create the <meta charset=""> tag.
1788
-	 *
1789
-	 * @return string
1790
-	 */
1791
-	protected function metaCharset() {
1792
-		return '<meta charset="UTF-8">';
1793
-	}
1794
-
1795
-	/**
1796
-	 * Create the <meta name="description"> tag.
1797
-	 *
1798
-	 * @param string $description
1799
-	 *
1800
-	 * @return string
1801
-	 */
1802
-	protected function metaDescription($description) {
1803
-		if ($description) {
1804
-			return '<meta name="description" content="' . $description . '">';
1805
-		} else {
1806
-			return '';
1807
-		}
1808
-	}
1809
-
1810
-	/**
1811
-	 * Create the <meta name="generator"> tag.
1812
-	 *
1813
-	 * @param string $generator
1814
-	 *
1815
-	 * @return string
1816
-	 */
1817
-	protected function metaGenerator($generator) {
1818
-		if ($generator) {
1819
-			return '<meta name="generator" content="' . $generator . '">';
1820
-		} else {
1821
-			return '';
1822
-		}
1823
-	}
1824
-
1825
-	/**
1826
-	 * Create the <meta name="robots"> tag.
1827
-	 *
1828
-	 * @param string $robots
1829
-	 *
1830
-	 * @return string
1831
-	 */
1832
-	protected function metaRobots($robots) {
1833
-		if ($robots) {
1834
-			return '<meta name="robots" content="' . $robots . '">';
1835
-		} else {
1836
-			return '';
1837
-		}
1838
-	}
1839
-
1840
-	/**
1841
-	 * Create the <meta http-equiv="X-UA-Compatible"> tag.
1842
-	 *
1843
-	 * @return string
1844
-	 */
1845
-	protected function metaUaCompatible() {
1846
-		return '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
1847
-	}
1848
-
1849
-	/**
1850
-	 * Create the <meta name="viewport" content="width=device-width, initial-scale=1"> tag.
1851
-	 *
1852
-	 * @return string
1853
-	 */
1854
-	protected function metaViewport() {
1855
-		return '<meta name="viewport" content="width=device-width, initial-scale=1">';
1856
-	}
1857
-
1858
-	/**
1859
-	 * How many times has the current page been shown?
1860
-	 *
1861
-	 * @param  PageController $controller
1862
-	 *
1863
-	 * @return int Number of views, or zero for pages that aren't logged.
1864
-	 */
1865
-	protected function pageViews(PageController $controller) {
1866
-		if ($this->tree && $this->tree->getPreference('SHOW_COUNTER')) {
1867
-			if (isset($controller->record) && $controller->record instanceof GedcomRecord) {
1868
-				return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->record->getXref());
1869
-			} elseif (isset($controller->root) && $controller->root instanceof GedcomRecord) {
1870
-				return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->root->getXref());
1871
-			} elseif (WT_SCRIPT_NAME === 'index.php') {
1872
-				if (Auth::check() && Filter::get('ctype') !== 'gedcom') {
1873
-					return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'user:' . Auth::id());
1874
-				} else {
1875
-					return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'gedcom:' . $this->tree->getTreeId());
1876
-				}
1877
-			}
1878
-		}
1879
-
1880
-		return 0;
1881
-	}
1882
-
1883
-	/**
1884
-	 * Misecellaneous dimensions, fonts, styles, etc.
1885
-	 *
1886
-	 * @param string $parameter_name
1887
-	 *
1888
-	 * @return string|int|float
1889
-	 */
1890
-	public function parameter($parameter_name) {
1891
-		$parameters = array(
1892
-			'chart-background-f'             => 'dddddd',
1893
-			'chart-background-m'             => 'cccccc',
1894
-			'chart-background-u'             => 'eeeeee',
1895
-			'chart-box-x'                    => 250,
1896
-			'chart-box-y'                    => 80,
1897
-			'chart-descendancy-indent'       => 15,
1898
-			'chart-font-color'               => '000000',
1899
-			'chart-font-name'                => WT_ROOT . 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf',
1900
-			'chart-font-size'                => 7,
1901
-			'chart-spacing-x'                => 5,
1902
-			'chart-spacing-y'                => 10,
1903
-			'compact-chart-box-x'            => 240,
1904
-			'compact-chart-box-y'            => 50,
1905
-			'distribution-chart-high-values' => '555555',
1906
-			'distribution-chart-low-values'  => 'cccccc',
1907
-			'distribution-chart-no-values'   => 'ffffff',
1908
-			'distribution-chart-x'           => 440,
1909
-			'distribution-chart-y'           => 220,
1910
-			'line-width'                     => 1.5,
1911
-			'shadow-blur'                    => 0,
1912
-			'shadow-color'                   => '',
1913
-			'shadow-offset-x'                => 0,
1914
-			'shadow-offset-y'                => 0,
1915
-			'stats-small-chart-x'            => 440,
1916
-			'stats-small-chart-y'            => 125,
1917
-			'stats-large-chart-x'            => 900,
1918
-			'image-dline'                    => $this->assetUrl() . 'images/dline.png',
1919
-			'image-dline2'                   => $this->assetUrl() . 'images/dline2.png',
1920
-			'image-hline'                    => $this->assetUrl() . 'images/hline.png',
1921
-			'image-spacer'                   => $this->assetUrl() . 'images/spacer.png',
1922
-			'image-vline'                    => $this->assetUrl() . 'images/vline.png',
1923
-			'image-minus'                    => $this->assetUrl() . 'images/minus.png',
1924
-			'image-plus'                     => $this->assetUrl() . 'images/plus.png',
1925
-		);
1926
-
1927
-		if (array_key_exists($parameter_name, $parameters)) {
1928
-			return $parameters[$parameter_name];
1929
-		} else {
1930
-			throw new \InvalidArgumentException($parameter_name);
1931
-		}
1932
-	}
1933
-
1934
-	/**
1935
-	 * Are there any pending changes for us to approve?
1936
-	 *
1937
-	 * @return bool
1938
-	 */
1939
-	protected function pendingChangesExist() {
1940
-		return $this->tree && $this->tree->hasPendingEdit() && Auth::isModerator($this->tree);
1941
-	}
1942
-
1943
-	/**
1944
-	 * Create a pending changes link. Some themes prefer an alert/banner to a menu.
1945
-	 *
1946
-	 * @return string
1947
-	 */
1948
-	protected function pendingChangesLink() {
1949
-		return
1950
-			'<a href="#" onclick="window.open(\'edit_changes.php\', \'_blank\', chan_window_specs); return false;">' .
1951
-			$this->pendingChangesLinkText() .
1952
-			'</a>';
1953
-	}
1954
-
1955
-	/**
1956
-	 * Text to use in the pending changes link.
1957
-	 *
1958
-	 * @return string
1959
-	 */
1960
-	protected function pendingChangesLinkText() {
1961
-		return I18N::translate('There are pending changes for you to moderate.');
1962
-	}
1963
-
1964
-	/**
1965
-	 * Generate a list of items for the main menu.
1966
-	 *
1967
-	 * @return Menu[]
1968
-	 */
1969
-	protected function primaryMenu() {
1970
-		global $controller;
1971
-
1972
-		if ($this->tree) {
1973
-			$individual = $controller->getSignificantIndividual();
1974
-
1975
-			return array_filter(array_merge(array(
1976
-				$this->menuHomePage(),
1977
-				$this->menuChart($individual),
1978
-				$this->menuLists($controller->getSignificantSurname()),
1979
-				$this->menuCalendar(),
1980
-				$this->menuReports(),
1981
-				$this->menuSearch(),
1982
-			), $this->menuModules()));
1983
-		} else {
1984
-			// No public trees? No genealogy menu!
1985
-			return array();
1986
-		}
1987
-	}
1988
-
1989
-	/**
1990
-	 * Add markup to the primary menu.
1991
-	 *
1992
-	 * @param Menu[] $menus
1993
-	 *
1994
-	 * @return string
1995
-	 */
1996
-	protected function primaryMenuContainer(array $menus) {
1997
-		return '<nav><ul class="primary-menu">' . $this->primaryMenuContent($menus) . '</ul></nav>';
1998
-	}
1999
-
2000
-	/**
2001
-	 * Create the primary menu.
2002
-	 *
2003
-	 * @param Menu[] $menus
2004
-	 *
2005
-	 * @return string
2006
-	 */
2007
-	protected function primaryMenuContent(array $menus) {
2008
-		return implode('', array_map(function (Menu $menu) {
2009
-			return $menu->getMenuAsList();
2010
-		}, $menus));
2011
-	}
2012
-
2013
-	/**
2014
-	 * Generate a list of items for the user menu.
2015
-	 *
2016
-	 * @return Menu[]
2017
-	 */
2018
-	protected function secondaryMenu() {
2019
-		return array_filter(array(
2020
-			$this->menuPendingChanges(),
2021
-			$this->menuMyPages(),
2022
-			$this->menuFavorites(),
2023
-			$this->menuThemes(),
2024
-			$this->menuLanguages(),
2025
-			$this->menuLogin(),
2026
-			$this->menuLogout(),
2027
-		));
2028
-	}
2029
-
2030
-	/**
2031
-	 * Add markup to the secondary menu.
2032
-	 *
2033
-	 * @param Menu[] $menus
2034
-	 *
2035
-	 * @return string
2036
-	 */
2037
-	protected function secondaryMenuContainer(array $menus) {
2038
-		return '<ul class="nav nav-pills secondary-menu">' . $this->secondaryMenuContent($menus) . '</ul>';
2039
-	}
2040
-
2041
-	/**
2042
-	 * Format the secondary menu.
2043
-	 *
2044
-	 * @param Menu[] $menus
2045
-	 *
2046
-	 * @return string
2047
-	 */
2048
-	protected function secondaryMenuContent(array $menus) {
2049
-		return implode('', array_map(function (Menu $menu) {
2050
-			return $menu->getMenuAsList();
2051
-		}, $menus));
2052
-	}
2053
-
2054
-	/**
2055
-	 * Send any HTTP headers.
2056
-	 */
2057
-	public function sendHeaders() {
2058
-		header('Content-Type: text/html; charset=UTF-8');
2059
-	}
2060
-
2061
-	/**
2062
-	 * A list of CSS files to include for this page.
2063
-	 *
2064
-	 * @return string[]
2065
-	 */
2066
-	protected function stylesheets() {
2067
-		$stylesheets = array(
2068
-			WT_BOOTSTRAP_CSS_URL,
2069
-			WT_FONT_AWESOME_CSS_URL,
2070
-			WT_FONT_AWESOME_RTL_CSS_URL,
2071
-		);
2072
-
2073
-		if (I18N::direction() === 'rtl') {
2074
-			$stylesheets[] = WT_BOOTSTRAP_RTL_CSS_URL;
2075
-		}
2076
-
2077
-		return $stylesheets;
2078
-	}
2079
-
2080
-	/**
2081
-	 * Create the <title> tag.
2082
-	 *
2083
-	 * @param string $title
2084
-	 *
2085
-	 * @return string
2086
-	 */
2087
-	protected function title($title) {
2088
-		return '<title>' . Filter::escapeHtml($title) . '</title>';
2089
-	}
56
+    /** @var Tree The current tree */
57
+    protected $tree;
58
+
59
+    /** @var string An escaped version of the "ged=XXX" URL parameter */
60
+    protected $tree_url;
61
+
62
+    /** @var int The number of times this page has been shown */
63
+    protected $page_views;
64
+
65
+    /**
66
+     * Custom themes should place their initialization code in the function hookAfterInit(), not in
67
+     * the constructor, as all themes get constructed - whether they are used or not.
68
+     */
69
+    final public function __construct() {
70
+    }
71
+
72
+    /**
73
+     * Create accessibility links for the header.
74
+     *
75
+     * "Skip to content" allows keyboard only users to navigate over the headers without
76
+     * pressing TAB many times.
77
+     *
78
+     * @return string
79
+     */
80
+    protected function accessibilityLinks() {
81
+        return
82
+            '<div class="accessibility-links">' .
83
+            '<a class="sr-only sr-only-focusable btn btn-info btn-sm" href="#content">' .
84
+            /* I18N: Skip over the headers and menus, to the main content of the page */ I18N::translate('Skip to content') .
85
+            '</a>' .
86
+            '</div>';
87
+    }
88
+
89
+    /**
90
+     * Create scripts for analytics and tracking.
91
+     *
92
+     * @return string
93
+     */
94
+    protected function analytics() {
95
+        if ($this->themeId() === '_administration' || !empty($_SERVER['HTTP_DNT'])) {
96
+            return '';
97
+        } else {
98
+            return
99
+                $this->analyticsBingWebmaster(
100
+                    Site::getPreference('BING_WEBMASTER_ID')
101
+                ) .
102
+                $this->analyticsGoogleWebmaster(
103
+                    Site::getPreference('GOOGLE_WEBMASTER_ID')
104
+                ) .
105
+                $this->analyticsGoogleTracker(
106
+                    Site::getPreference('GOOGLE_ANALYTICS_ID')
107
+                ) .
108
+                $this->analyticsPiwikTracker(
109
+                    Site::getPreference('PIWIK_URL'),
110
+                    Site::getPreference('PIWIK_SITE_ID')
111
+                ) .
112
+                $this->analyticsStatcounterTracker(
113
+                    Site::getPreference('STATCOUNTER_PROJECT_ID'),
114
+                    Site::getPreference('STATCOUNTER_SECURITY_ID')
115
+                );
116
+        }
117
+    }
118
+
119
+    /**
120
+     * Create the verification code for Google Webmaster Tools.
121
+     *
122
+     * @param string $verification_id
123
+     *
124
+     * @return string
125
+     */
126
+    protected function analyticsBingWebmaster($verification_id) {
127
+        // Only need to add this to the home page.
128
+        if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
129
+            return '<meta name="msvalidate.01" content="' . $verification_id . '">';
130
+        } else {
131
+            return '';
132
+        }
133
+    }
134
+
135
+    /**
136
+     * Create the verification code for Google Webmaster Tools.
137
+     *
138
+     * @param string $verification_id
139
+     *
140
+     * @return string
141
+     */
142
+    protected function analyticsGoogleWebmaster($verification_id) {
143
+        // Only need to add this to the home page.
144
+        if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
145
+            return '<meta name="google-site-verification" content="' . $verification_id . '">';
146
+        } else {
147
+            return '';
148
+        }
149
+    }
150
+
151
+    /**
152
+     * Create the tracking code for Google Analytics.
153
+     *
154
+     * See https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced
155
+     *
156
+     * @param string $analytics_id
157
+     *
158
+     * @return string
159
+     */
160
+    protected function analyticsGoogleTracker($analytics_id) {
161
+        if ($analytics_id) {
162
+            // Add extra dimensions (i.e. filtering categories)
163
+            $dimensions = (object) array(
164
+                'dimension1' => $this->tree ? $this->tree->getName() : '-',
165
+                'dimension2' => $this->tree ? Auth::accessLevel($this->tree) : '-',
166
+            );
167
+
168
+            return
169
+                '<script async src="https://www.google-analytics.com/analytics.js"></script>' .
170
+                '<script>' .
171
+                'window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;' .
172
+                'ga("create","' . $analytics_id . '","auto");' .
173
+                'ga("send", "pageview", ' . json_encode($dimensions) . ');' .
174
+                '</script>';
175
+        } else {
176
+            return '';
177
+        }
178
+    }
179
+
180
+    /**
181
+     * Create the tracking code for Piwik Analytics.
182
+     *
183
+     * @param string $url     - The domain/path to Piwik
184
+     * @param string $site_id - The Piwik site identifier
185
+     *
186
+     * @return string
187
+     */
188
+    protected function analyticsPiwikTracker($url, $site_id) {
189
+        $url = preg_replace(array('/^https?:\/\//', '/\/$/'), '', $url);
190
+
191
+        if ($url && $site_id) {
192
+            return
193
+                '<script>' .
194
+                'var _paq=_paq||[];' .
195
+                '(function(){var u=(("https:"==document.location.protocol)?"https://' . $url . '/":"http://' . $url . '/");' .
196
+                '_paq.push(["setSiteId",' . $site_id . ']);' .
197
+                '_paq.push(["setTrackerUrl",u+"piwik.php"]);' .
198
+                '_paq.push(["trackPageView"]);' .
199
+                '_paq.push(["enableLinkTracking"]);' .
200
+                'var d=document,g=d.createElement("script"),s=d.getElementsByTagName("script")[0];g.defer=true;g.async=true;g.src=u+"piwik.js";' .
201
+                's.parentNode.insertBefore(g,s);})();' .
202
+                '</script>';
203
+        } else {
204
+            return '';
205
+        }
206
+    }
207
+
208
+    /**
209
+     * Create the tracking code for Statcounter.
210
+     *
211
+     * @param string $project_id  - The statcounter project ID
212
+     * @param string $security_id - The statcounter security ID
213
+     *
214
+     * @return string
215
+     */
216
+    protected function analyticsStatcounterTracker($project_id, $security_id) {
217
+        if ($project_id && $security_id) {
218
+            return
219
+                '<script>' .
220
+                'var sc_project=' . (int) $project_id . ',sc_invisible=1,sc_security="' . $security_id .
221
+                '",scJsHost = (("https:"===document.location.protocol)?"https://secure.":"http://www.");' .
222
+                'document.write("<sc"+"ript src=\'"+scJsHost+"statcounter.com/counter/counter.js\'></"+"script>");' .
223
+                '</script>';
224
+        } else {
225
+            return '';
226
+        }
227
+    }
228
+
229
+    /**
230
+     * Create the top of the <body>.
231
+     *
232
+     * @return string
233
+     */
234
+    public function bodyHeader() {
235
+        return
236
+            '<body class="container">' .
237
+            '<header>' .
238
+            $this->headerContent() .
239
+            $this->primaryMenuContainer($this->primaryMenu()) .
240
+            '</header>' .
241
+            '<main id="content">' .
242
+            $this->flashMessagesContainer(FlashMessages::getMessages());
243
+    }
244
+
245
+    /**
246
+     * Create the top of the <body> (for popup windows).
247
+     *
248
+     * @return string
249
+     */
250
+    public function bodyHeaderPopupWindow() {
251
+        return
252
+            '<body class="container container-popup">' .
253
+            '<main id="content">' .
254
+            $this->flashMessagesContainer(FlashMessages::getMessages());
255
+    }
256
+
257
+    /**
258
+     * Create a contact link for a user.
259
+     *
260
+     * @param User $user
261
+     *
262
+     * @return string
263
+     */
264
+    public function contactLink(User $user) {
265
+        $method = $user->getPreference('contactmethod');
266
+
267
+        switch ($method) {
268
+        case 'none':
269
+            return '';
270
+        case 'mailto':
271
+            return '<a href="mailto:' . Filter::escapeHtml($user->getEmail()) . '">' . $user->getRealNameHtml() . '</a>';
272
+        default:
273
+            return "<a href='#' onclick='message(\"" . Filter::escapeHtml($user->getUserName()) . "\", \"" . $method . "\", \"" . WT_BASE_URL . Filter::escapeHtml(Functions::getQueryUrl()) . "\", \"\");return false;'>" . $user->getRealNameHtml() . '</a>';
274
+        }
275
+    }
276
+
277
+    /**
278
+     * Create contact link for both technical and genealogy support.
279
+     *
280
+     * @param User $user
281
+     *
282
+     * @return string
283
+     */
284
+    protected function contactLinkEverything(User $user) {
285
+        return I18N::translate('For technical support or genealogy questions contact %s.', $this->contactLink($user));
286
+    }
287
+
288
+    /**
289
+     * Create contact link for genealogy support.
290
+     *
291
+     * @param User $user
292
+     *
293
+     * @return string
294
+     */
295
+    protected function contactLinkGenealogy(User $user) {
296
+        return I18N::translate('For help with genealogy questions contact %s.', $this->contactLink($user));
297
+    }
298
+
299
+    /**
300
+     * Create contact link for technical support.
301
+     *
302
+     * @param User $user
303
+     *
304
+     * @return string
305
+     */
306
+    protected function contactLinkTechnical(User $user) {
307
+        return I18N::translate('For technical support and information contact %s.', $this->contactLink($user));
308
+    }
309
+
310
+    /**
311
+     * Create contact links for the page footer.
312
+     *
313
+     * @return string
314
+     */
315
+    protected function contactLinks() {
316
+        $contact_user   = User::find($this->tree->getPreference('CONTACT_USER_ID'));
317
+        $webmaster_user = User::find($this->tree->getPreference('WEBMASTER_USER_ID'));
318
+
319
+        if ($contact_user && $contact_user === $webmaster_user) {
320
+            return $this->contactLinkEverything($contact_user);
321
+        } elseif ($contact_user && $webmaster_user) {
322
+            return $this->contactLinkGenealogy($contact_user) . '<br>' . $this->contactLinkTechnical($webmaster_user);
323
+        } elseif ($contact_user) {
324
+            return $this->contactLinkGenealogy($contact_user);
325
+        } elseif ($webmaster_user) {
326
+            return $this->contactLinkTechnical($webmaster_user);
327
+        } else {
328
+            return '';
329
+        }
330
+    }
331
+
332
+    /**
333
+     * Create a cookie warning.
334
+     *
335
+     * @return string
336
+     */
337
+    public function cookieWarning() {
338
+        if (
339
+            empty($_SERVER['HTTP_DNT']) &&
340
+            empty($_COOKIE['cookie']) &&
341
+            (Site::getPreference('GOOGLE_ANALYTICS_ID') || Site::getPreference('PIWIK_SITE_ID') || Site::getPreference('STATCOUNTER_PROJECT_ID'))
342
+        ) {
343
+            return
344
+                '<div class="cookie-warning">' .
345
+                I18N::translate('Cookies') . ' - ' .
346
+                I18N::translate('This website uses cookies to learn about visitor behaviour.') . ' ' .
347
+                '<button onclick="document.cookie=\'cookie=1\'; this.parentNode.classList.add(\'hidden\');">' . I18N::translate('continue') . '</button>' .
348
+                '</div>';
349
+        } else {
350
+            return '';
351
+        }
352
+    }
353
+
354
+    /**
355
+     * Create the <DOCTYPE> tag.
356
+     *
357
+     * @return string
358
+     */
359
+    public function doctype() {
360
+        return '<!DOCTYPE html>';
361
+    }
362
+
363
+    /**
364
+     * HTML link to a "favorites icon".
365
+     *
366
+     * @return string
367
+     */
368
+    protected function favicon() {
369
+        return
370
+            '<link rel="icon" href="' . $this->assetUrl() . 'favicon.png" type="image/png">' .
371
+            '<link rel="icon" type="image/png" href="' . $this->assetUrl() . 'favicon192.png" sizes="192x192">' .
372
+            '<link rel="apple-touch-icon" sizes="180x180" href="' . $this->assetUrl() . 'favicon180.png">';
373
+    }
374
+
375
+    /**
376
+     * Add markup to a flash message.
377
+     *
378
+     * @param \stdClass $message
379
+     *
380
+     * @return string
381
+     */
382
+    protected function flashMessageContainer(\stdClass $message) {
383
+        return $this->htmlAlert($message->text, $message->status, true);
384
+    }
385
+
386
+    /**
387
+     * Create a container for messages that are "flashed" to the session
388
+     * on one request, and displayed on another. If there are many messages,
389
+     * the container may need a max-height and scroll-bar.
390
+     *
391
+     * @param \stdClass[] $messages
392
+     *
393
+     * @return string
394
+     */
395
+    protected function flashMessagesContainer(array $messages) {
396
+        $html = '';
397
+        foreach ($messages as $message) {
398
+            $html .= $this->flashMessageContainer($message);
399
+        }
400
+
401
+        if ($html) {
402
+            return '<div class="flash-messages">' . $html . '</div>';
403
+        } else {
404
+            return '';
405
+        }
406
+    }
407
+
408
+    /**
409
+     * Close the main content and create the <footer> tag.
410
+     *
411
+     * @return string
412
+     */
413
+    public function footerContainer() {
414
+        return '</main><footer>' . $this->footerContent() . '</footer>';
415
+    }
416
+
417
+    /**
418
+     * Close the main content.
419
+     * Note that popup windows are deprecated
420
+     *
421
+     * @return string
422
+     */
423
+    public function footerContainerPopupWindow() {
424
+        return '</main>';
425
+    }
426
+
427
+    /**
428
+     * Create the contents of the <footer> tag.
429
+     *
430
+     * @return string
431
+     */
432
+    protected function footerContent() {
433
+        return
434
+            $this->formatContactLinks() .
435
+            $this->logoPoweredBy() .
436
+            $this->formatPageViews($this->page_views) .
437
+            $this->cookieWarning();
438
+    }
439
+
440
+    /**
441
+     * Format the contents of a variable-height home-page block.
442
+     *
443
+     * @param string $id
444
+     * @param string $title
445
+     * @param string $class
446
+     * @param string $content
447
+     *
448
+     * @return string
449
+     */
450
+    public function formatBlock($id, $title, $class, $content) {
451
+        return
452
+            '<div id="' . $id . '" class="block" >' .
453
+            '<div class="blockheader">' . $title . '</div>' .
454
+            '<div class="blockcontent ' . $class . '">' . $content . '</div>' .
455
+            '</div>';
456
+    }
457
+
458
+    /**
459
+     * Add markup to the contact links.
460
+     *
461
+     * @return string
462
+     */
463
+    protected function formatContactLinks() {
464
+        if ($this->tree) {
465
+            return '<div class="contact-links">' . $this->contactLinks() . '</div>';
466
+        } else {
467
+            return '';
468
+        }
469
+    }
470
+
471
+    /**
472
+     * Add markup to the hit counter.
473
+     *
474
+     * @param int $count
475
+     *
476
+     * @return string
477
+     */
478
+    protected function formatPageViews($count) {
479
+        if ($count > 0) {
480
+            return
481
+                '<div class="page-views">' .
482
+                I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $count,
483
+                    '<span class="odometer">' . I18N::digits($count) . '</span>') .
484
+                '</div>';
485
+        } else {
486
+            return '';
487
+        }
488
+    }
489
+
490
+    /**
491
+     * Create a pending changes link for the page footer.
492
+     *
493
+     * @return string
494
+     */
495
+    protected function formatPendingChangesLink() {
496
+        if ($this->pendingChangesExist()) {
497
+            return '<div class="pending-changes-link">' . $this->pendingChangesLink() . '</div>';
498
+        } else {
499
+            return '';
500
+        }
501
+    }
502
+
503
+    /**
504
+     * Create a quick search form for the header.
505
+     *
506
+     * @return string
507
+     */
508
+    protected function formQuickSearch() {
509
+        if ($this->tree) {
510
+            return
511
+                '<form action="search.php" class="header-search" role="search">' .
512
+                '<input type="hidden" name="action" value="header">' .
513
+                '<input type="hidden" name="ged" value="' . $this->tree->getNameHtml() . '">' .
514
+                $this->formQuickSearchFields() .
515
+                '</form>';
516
+        } else {
517
+            return '';
518
+        }
519
+    }
520
+
521
+    /**
522
+     * Create a search field and submit button for the quick search form in the header.
523
+     *
524
+     * @return string
525
+     */
526
+    protected function formQuickSearchFields() {
527
+        return
528
+            '<input type="search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
529
+            '<input type="image" src="' . $this->assetUrl() . 'images/go.png" alt="' . I18N::translate('Search') . '">';
530
+    }
531
+
532
+    /**
533
+     * Add markup to the tree title.
534
+     *
535
+     * @return string
536
+     */
537
+    protected function formatTreeTitle() {
538
+        if ($this->tree) {
539
+            return '<h1 class="header-title">' . $this->tree->getTitleHtml() . '</h1>';
540
+        } else {
541
+            return '';
542
+        }
543
+    }
544
+
545
+    /**
546
+     * Add markup to the secondary menu.
547
+     *
548
+     * @return string
549
+     */
550
+    protected function formatSecondaryMenu() {
551
+        return
552
+            '<ul class="secondary-menu">' .
553
+            implode('', $this->secondaryMenu()) .
554
+            '</ul>';
555
+    }
556
+
557
+    /**
558
+     * Add markup to an item in the secondary menu.
559
+     *
560
+     * @param Menu $menu
561
+     *
562
+     * @return string
563
+     */
564
+    protected function formatSecondaryMenuItem(Menu $menu) {
565
+        return $menu->getMenuAsList();
566
+    }
567
+
568
+    /**
569
+     * Create the <head> tag.
570
+     *
571
+     * @param PageController $controller The current controller
572
+     *
573
+     * @return string
574
+     */
575
+    public function head(PageController $controller) {
576
+        // Record this now. By the time we render the footer, $controller no longer exists.
577
+        $this->page_views = $this->pageViews($controller);
578
+
579
+        return
580
+            '<head>' .
581
+            $this->headContents($controller) .
582
+            $this->hookHeaderExtraContent() .
583
+            $this->analytics() .
584
+            '</head>';
585
+    }
586
+
587
+    /**
588
+     * Create the contents of the <head> tag.
589
+     *
590
+     * @param PageController $controller The current controller
591
+     *
592
+     * @return string
593
+     */
594
+    protected function headContents(PageController $controller) {
595
+        // The title often includes the names of records, which may include HTML markup.
596
+        $title = Filter::unescapeHtml($controller->getPageTitle());
597
+
598
+        // If an extra (site) title is specified, append it.
599
+        if ($this->tree && $this->tree->getPreference('META_TITLE')) {
600
+            $title .= ' – ' . $this->tree->getPreference('META_TITLE');
601
+        }
602
+
603
+        $html =
604
+            // modernizr.js and respond.js need to be loaded before the <body> to avoid FOUC
605
+            '<!--[if IE 8]><script src="' . WT_MODERNIZR_JS_URL . '"></script><![endif]-->' .
606
+            '<!--[if IE 8]><script src="' . WT_RESPOND_JS_URL . '"></script><![endif]-->' .
607
+            $this->metaCharset() .
608
+            $this->title($title) .
609
+            $this->favicon() .
610
+            $this->metaViewport() .
611
+            $this->metaRobots($controller->getMetaRobots()) .
612
+            $this->metaUaCompatible() .
613
+            $this->metaGenerator(WT_WEBTREES . ' ' . WT_VERSION . ' - ' . WT_WEBTREES_URL);
614
+
615
+        if ($this->tree) {
616
+            $html .= $this->metaDescription($this->tree->getPreference('META_DESCRIPTION'));
617
+        }
618
+
619
+        // CSS files
620
+        foreach ($this->stylesheets() as $css) {
621
+            $html .= '<link rel="stylesheet" type="text/css" href="' . $css . '">';
622
+        }
623
+
624
+        return $html;
625
+    }
626
+
627
+    /**
628
+     * Create the contents of the <header> tag.
629
+     *
630
+     * @return string
631
+     */
632
+    protected function headerContent() {
633
+        return
634
+            //$this->accessibilityLinks() .
635
+            $this->logoHeader() .
636
+            $this->secondaryMenuContainer($this->secondaryMenu()) .
637
+            $this->formatTreeTitle() .
638
+            $this->formQuickSearch();
639
+    }
640
+
641
+    /**
642
+     * Create the <header> tag for a popup window.
643
+     *
644
+     * @return string
645
+     */
646
+    protected function headerSimple() {
647
+        return
648
+            $this->flashMessagesContainer(FlashMessages::getMessages()) .
649
+            '<div id="content">';
650
+    }
651
+
652
+    /**
653
+     * Allow themes to do things after initialization (since they cannot use
654
+     * the constructor).
655
+     */
656
+    public function hookAfterInit() {
657
+    }
658
+
659
+    /**
660
+     * Allow themes to add extra scripts to the page footer.
661
+     *
662
+     * @return string
663
+     */
664
+    public function hookFooterExtraJavascript() {
665
+        return '';
666
+    }
667
+
668
+    /**
669
+     * Allow themes to add extra content to the page header.
670
+     * Typically this will be additional CSS.
671
+     *
672
+     * @return string
673
+     */
674
+    public function hookHeaderExtraContent() {
675
+        return '';
676
+    }
677
+
678
+    /**
679
+     * Create the <html> tag.
680
+     *
681
+     * @return string
682
+     */
683
+    public function html() {
684
+        return '<html ' . I18N::htmlAttributes() . '>';
685
+    }
686
+
687
+    /**
688
+     * Add HTML markup to create an alert
689
+     *
690
+     * @param string $html        The content of the alert
691
+     * @param string $level       One of 'success', 'info', 'warning', 'danger'
692
+     * @param bool   $dismissible If true, add a close button.
693
+     *
694
+     * @return string
695
+     */
696
+    public function htmlAlert($html, $level, $dismissible) {
697
+        if ($dismissible) {
698
+            return
699
+                '<div class="alert alert-' . $level . ' alert-dismissible" role="alert">' .
700
+                '<button type="button" class="close" data-dismiss="alert" aria-label="' . I18N::translate('close') . '">' .
701
+                '<span aria-hidden="true">&times;</span>' .
702
+                '</button>' .
703
+                $html .
704
+                '</div>';
705
+        } else {
706
+            return
707
+                '<div class="alert alert-' . $level . '" role="alert">' .
708
+                $html .
709
+                '</div>';
710
+        }
711
+    }
712
+
713
+    /**
714
+     * Display an icon for this fact.
715
+     *
716
+     * @param Fact $fact
717
+     *
718
+     * @return string
719
+     */
720
+    public function icon(Fact $fact) {
721
+        $icon = 'images/facts/' . $fact->getTag() . '.png';
722
+        $dir  = substr($this->assetUrl(), strlen(WT_STATIC_URL));
723
+        if (file_exists($dir . $icon)) {
724
+            return '<img src="' . $this->assetUrl() . $icon . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">';
725
+        } elseif (file_exists($dir . 'images/facts/NULL.png')) {
726
+            // Spacer image - for alignment - until we move to a sprite.
727
+            return '<img src="' . Theme::theme()->assetUrl() . 'images/facts/NULL.png">';
728
+        } else {
729
+            return '';
730
+        }
731
+    }
732
+
733
+    /**
734
+     * Display an individual in a box - for charts, etc.
735
+     *
736
+     * @param Individual $individual
737
+     *
738
+     * @return string
739
+     */
740
+    public function individualBox(Individual $individual) {
741
+        $personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
742
+        if ($individual->canShow() && $individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
743
+            $thumbnail = $individual->displayImage();
744
+        } else {
745
+            $thumbnail = '';
746
+        }
747
+
748
+        $content = '<span class="namedef name1">' . $individual->getFullName() . '</span>';
749
+        $icons   = '';
750
+        if ($individual->canShow()) {
751
+            $content =
752
+                '<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
753
+                '<div class="namedef name1">' . $individual->getAddName() . '</div>';
754
+            $icons   =
755
+                '<div class="noprint icons">' .
756
+                '<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
757
+                '<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
758
+                '<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
759
+                '</div>' .
760
+                '</div>' .
761
+                '</div>';
762
+        }
763
+
764
+        return
765
+            '<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px">' .
766
+            $icons .
767
+            '<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' .
768
+            $thumbnail .
769
+            $content .
770
+            '<div class="inout2 details1">' . $this->individualBoxFacts($individual) . '</div>' .
771
+            '</div>' .
772
+            '<div class="inout"></div>' .
773
+            '</div>';
774
+    }
775
+
776
+    /**
777
+     * Display an empty box - for a missing individual in a chart.
778
+     *
779
+     * @return string
780
+     */
781
+    public function individualBoxEmpty() {
782
+        return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px"></div>';
783
+    }
784
+
785
+    /**
786
+     * Display an individual in a box - for charts, etc.
787
+     *
788
+     * @param Individual $individual
789
+     *
790
+     * @return string
791
+     */
792
+    public function individualBoxLarge(Individual $individual) {
793
+        $personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
794
+        if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
795
+            $thumbnail = $individual->displayImage();
796
+        } else {
797
+            $thumbnail = '';
798
+        }
799
+
800
+        $content = '<span class="namedef name1">' . $individual->getFullName() . '</span>';
801
+        $icons   = '';
802
+        if ($individual->canShow()) {
803
+            $content =
804
+                '<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
805
+                '<div class="namedef name2">' . $individual->getAddName() . '</div>';
806
+            $icons   =
807
+                '<div class="noprint icons">' .
808
+                '<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
809
+                '<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
810
+                '<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
811
+                '</div>' .
812
+                '</div>' .
813
+                '</div>';
814
+        }
815
+
816
+        return
817
+            '<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' box-style2">' .
818
+            $icons .
819
+            '<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' .
820
+            $thumbnail .
821
+            $content .
822
+            '<div class="inout2 details2">' . $this->individualBoxFacts($individual) . '</div>' .
823
+            '</div>' .
824
+            '<div class="inout"></div>' .
825
+            '</div>';
826
+    }
827
+
828
+    /**
829
+     * Display an individual in a box - for charts, etc.
830
+     *
831
+     * @param Individual $individual
832
+     *
833
+     * @return string
834
+     */
835
+    public function individualBoxSmall(Individual $individual) {
836
+        $personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
837
+        if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
838
+            $thumbnail = $individual->displayImage();
839
+        } else {
840
+            $thumbnail = '';
841
+        }
842
+
843
+        return
844
+            '<div data-pid="' . $individual->getXref() . '" class="person_box_template ' . $personBoxClass . ' iconz box-style0" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px">' .
845
+            '<div class="compact_view">' .
846
+            $thumbnail .
847
+            '<a href="' . $individual->getHtmlUrl() . '">' .
848
+            '<span class="namedef name0">' . $individual->getFullName() . '</span>' .
849
+            '</a>' .
850
+            '<div class="inout2 details0">' . $individual->getLifeSpan() . '</div>' .
851
+            '</div>' .
852
+            '<div class="inout"></div>' .
853
+            '</div>';
854
+    }
855
+
856
+    /**
857
+     * Display an individual in a box - for charts, etc.
858
+     *
859
+     * @return string
860
+     */
861
+    public function individualBoxSmallEmpty() {
862
+        return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px"></div>';
863
+    }
864
+
865
+    /**
866
+     * Generate the facts, for display in charts.
867
+     *
868
+     * @param Individual $individual
869
+     *
870
+     * @return string
871
+     */
872
+    protected function individualBoxFacts(Individual $individual) {
873
+        $html = '';
874
+
875
+        $opt_tags = preg_split('/\W/', $individual->getTree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY);
876
+        // Show BIRT or equivalent event
877
+        foreach (explode('|', WT_EVENTS_BIRT) as $birttag) {
878
+            if (!in_array($birttag, $opt_tags)) {
879
+                $event = $individual->getFirstFact($birttag);
880
+                if ($event) {
881
+                    $html .= $event->summary();
882
+                    break;
883
+                }
884
+            }
885
+        }
886
+        // Show optional events (before death)
887
+        foreach ($opt_tags as $key => $tag) {
888
+            if (!preg_match('/^(' . WT_EVENTS_DEAT . ')$/', $tag)) {
889
+                $event = $individual->getFirstFact($tag);
890
+                if (!is_null($event)) {
891
+                    $html .= $event->summary();
892
+                    unset($opt_tags[$key]);
893
+                }
894
+            }
895
+        }
896
+        // Show DEAT or equivalent event
897
+        foreach (explode('|', WT_EVENTS_DEAT) as $deattag) {
898
+            $event = $individual->getFirstFact($deattag);
899
+            if ($event) {
900
+                $html .= $event->summary();
901
+                if (in_array($deattag, $opt_tags)) {
902
+                    unset($opt_tags[array_search($deattag, $opt_tags)]);
903
+                }
904
+                break;
905
+            }
906
+        }
907
+        // Show remaining optional events (after death)
908
+        foreach ($opt_tags as $tag) {
909
+            $event = $individual->getFirstFact($tag);
910
+            if ($event) {
911
+                $html .= $event->summary();
912
+            }
913
+        }
914
+
915
+        return $html;
916
+    }
917
+
918
+    /**
919
+     * Generate the LDS summary, for display in charts.
920
+     *
921
+     * @param Individual $individual
922
+     *
923
+     * @return string
924
+     */
925
+    protected function individualBoxLdsSummary(Individual $individual) {
926
+        if ($individual->getTree()->getPreference('SHOW_LDS_AT_GLANCE')) {
927
+            $BAPL = $individual->getFacts('BAPL') ? 'B' : '_';
928
+            $ENDL = $individual->getFacts('ENDL') ? 'E' : '_';
929
+            $SLGC = $individual->getFacts('SLGC') ? 'C' : '_';
930
+            $SLGS = '_';
931
+
932
+            foreach ($individual->getSpouseFamilies() as $family) {
933
+                if ($family->getFacts('SLGS')) {
934
+                    $SLGS = '';
935
+                }
936
+            }
937
+
938
+            return $BAPL . $ENDL . $SLGS . $SLGC;
939
+        } else {
940
+            return '';
941
+        }
942
+    }
943
+
944
+    /**
945
+     * Links, to show in chart boxes;
946
+     *
947
+     * @param Individual $individual
948
+     *
949
+     * @return Menu[]
950
+     */
951
+    public function individualBoxMenu(Individual $individual) {
952
+        $menus = array_merge(
953
+            $this->individualBoxMenuCharts($individual),
954
+            $this->individualBoxMenuFamilyLinks($individual)
955
+        );
956
+
957
+        return $menus;
958
+    }
959
+
960
+    /**
961
+     * Chart links, to show in chart boxes;
962
+     *
963
+     * @param Individual $individual
964
+     *
965
+     * @return Menu[]
966
+     */
967
+    protected function individualBoxMenuCharts(Individual $individual) {
968
+        $menus = array();
969
+        foreach (Module::getActiveCharts($this->tree) as $chart) {
970
+            $menu = $chart->getBoxChartMenu($individual);
971
+            if ($menu) {
972
+                $menus[] = $menu;
973
+            }
974
+        }
975
+
976
+        usort($menus, function (Menu $x, Menu $y) {
977
+            return I18N::strcasecmp($x->getLabel(), $y->getLabel());
978
+        });
979
+
980
+        return $menus;
981
+    }
982
+
983
+    /**
984
+     * Family links, to show in chart boxes.
985
+     *
986
+     * @param Individual $individual
987
+     *
988
+     * @return Menu[]
989
+     */
990
+    protected function individualBoxMenuFamilyLinks(Individual $individual) {
991
+        $menus = array();
992
+
993
+        foreach ($individual->getSpouseFamilies() as $family) {
994
+            $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->getHtmlUrl());
995
+            $spouse  = $family->getSpouse($individual);
996
+            if ($spouse && $spouse->canShowName()) {
997
+                $menus[] = new Menu($spouse->getFullName(), $spouse->getHtmlUrl());
998
+            }
999
+            foreach ($family->getChildren() as $child) {
1000
+                if ($child->canShowName()) {
1001
+                    $menus[] = new Menu($child->getFullName(), $child->getHtmlUrl());
1002
+                }
1003
+            }
1004
+        }
1005
+
1006
+        return $menus;
1007
+    }
1008
+
1009
+    /**
1010
+     * Create part of an individual box
1011
+     *
1012
+     * @param Individual $individual
1013
+     *
1014
+     * @return string
1015
+     */
1016
+    protected function individualBoxSexSymbol(Individual $individual) {
1017
+        if ($individual->getTree()->getPreference('PEDIGREE_SHOW_GENDER')) {
1018
+            return $individual->sexImage('large');
1019
+        } else {
1020
+            return '';
1021
+        }
1022
+    }
1023
+
1024
+    /**
1025
+     * Initialise the theme. We cannot pass these in a constructor, as the construction
1026
+     * happens in a theme file, and we need to be able to change it.
1027
+     *
1028
+     * @param Tree|null $tree The current tree (if there is one).
1029
+     */
1030
+    final public function init(Tree $tree = null) {
1031
+        $this->tree     = $tree;
1032
+        $this->tree_url = $tree ? 'ged=' . $tree->getNameUrl() : '';
1033
+
1034
+        $this->hookAfterInit();
1035
+    }
1036
+
1037
+    /**
1038
+     * A large webtrees logo, for the header.
1039
+     *
1040
+     * @return string
1041
+     */
1042
+    protected function logoHeader() {
1043
+        return '<div class="header-logo"></div>';
1044
+    }
1045
+
1046
+    /**
1047
+     * A small "powered by webtrees" logo for the footer.
1048
+     *
1049
+     * @return string
1050
+     */
1051
+    protected function logoPoweredBy() {
1052
+        return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '"></a>';
1053
+    }
1054
+
1055
+    /**
1056
+     * A menu for the day/month/year calendar views.
1057
+     *
1058
+     * @return Menu
1059
+     */
1060
+    protected function menuCalendar() {
1061
+        return new Menu(I18N::translate('Calendar'), '#', 'menu-calendar', array('rel' => 'nofollow'), array(
1062
+            // Day view
1063
+            new Menu(I18N::translate('Day'), 'calendar.php?' . $this->tree_url . '&amp;view=day', 'menu-calendar-day', array('rel' => 'nofollow')),
1064
+            // Month view
1065
+            new Menu(I18N::translate('Month'), 'calendar.php?' . $this->tree_url . '&amp;view=month', 'menu-calendar-month', array('rel' => 'nofollow')),
1066
+            //Year view
1067
+            new Menu(I18N::translate('Year'), 'calendar.php?' . $this->tree_url . '&amp;view=year', 'menu-calendar-year', array('rel' => 'nofollow')),
1068
+        ));
1069
+    }
1070
+
1071
+    /**
1072
+     * Generate a menu item to change the blocks on the current (index.php) page.
1073
+     *
1074
+     * @return Menu|null
1075
+     */
1076
+    protected function menuChangeBlocks() {
1077
+        if (WT_SCRIPT_NAME === 'index.php' && Auth::check() && Filter::get('ctype', 'gedcom|user', 'user') === 'user') {
1078
+            return new Menu(I18N::translate('Customize this page'), 'index_edit.php?user_id=' . Auth::id(), 'menu-change-blocks');
1079
+        } elseif (WT_SCRIPT_NAME === 'index.php' && Auth::isManager($this->tree)) {
1080
+            return new Menu(I18N::translate('Customize this page'), 'index_edit.php?gedcom_id=' . $this->tree->getTreeId(), 'menu-change-blocks');
1081
+        } else {
1082
+            return null;
1083
+        }
1084
+    }
1085
+
1086
+    /**
1087
+     * Generate a menu for each of the different charts.
1088
+     *
1089
+     * @param Individual $individual
1090
+     *
1091
+     * @return Menu|null
1092
+     */
1093
+    protected function menuChart(Individual $individual) {
1094
+        $submenus = array();
1095
+        foreach (Module::getActiveCharts($this->tree) as $chart) {
1096
+            $menu = $chart->getChartMenu($individual);
1097
+            if ($menu) {
1098
+                $submenus[] = $menu;
1099
+            }
1100
+        }
1101
+
1102
+        if ($submenus) {
1103
+            usort($submenus, function (Menu $x, Menu $y) {
1104
+                return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1105
+            });
1106
+
1107
+            return new Menu(I18N::translate('Charts'), '#', 'menu-chart', array('rel' => 'nofollow'), $submenus);
1108
+        } else {
1109
+            return null;
1110
+        }
1111
+    }
1112
+
1113
+    /**
1114
+     * Generate a menu item for the ancestors chart.
1115
+     *
1116
+     * @param Individual $individual
1117
+     *
1118
+     * @return Menu|null
1119
+     *
1120
+     * @deprecated
1121
+     */
1122
+    protected function menuChartAncestors(Individual $individual) {
1123
+        $chart = new AncestorsChartModule(WT_ROOT . WT_MODULES_DIR . 'ancestors_chart');
1124
+
1125
+        return $chart->getChartMenu($individual);
1126
+    }
1127
+
1128
+    /**
1129
+     * Generate a menu item for the compact tree.
1130
+     *
1131
+     * @param Individual $individual
1132
+     *
1133
+     * @return Menu|null
1134
+     *
1135
+     * @deprecated
1136
+     */
1137
+    protected function menuChartCompact(Individual $individual) {
1138
+        $chart = new CompactTreeChartModule(WT_ROOT . WT_MODULES_DIR . 'compact_tree_chart');
1139
+
1140
+        return $chart->getChartMenu($individual);
1141
+    }
1142
+
1143
+    /**
1144
+     * Generate a menu item for the descendants chart.
1145
+     *
1146
+     * @param Individual $individual
1147
+     *
1148
+     * @return Menu|null
1149
+     *
1150
+     * @deprecated
1151
+     */
1152
+    protected function menuChartDescendants(Individual $individual) {
1153
+        $chart = new DescendancyChartModule(WT_ROOT . WT_MODULES_DIR . 'descendancy_chart');
1154
+
1155
+        return $chart->getChartMenu($individual);
1156
+    }
1157
+
1158
+    /**
1159
+     * Generate a menu item for the family-book chart.
1160
+     *
1161
+     * @param Individual $individual
1162
+     *
1163
+     * @return Menu|null
1164
+     *
1165
+     * @deprecated
1166
+     */
1167
+    protected function menuChartFamilyBook(Individual $individual) {
1168
+        $chart = new FamilyBookChartModule(WT_ROOT . WT_MODULES_DIR . 'family_book_chart');
1169
+
1170
+        return $chart->getChartMenu($individual);
1171
+    }
1172
+
1173
+    /**
1174
+     * Generate a menu item for the fan chart.
1175
+     *
1176
+     * We can only do this if the GD2 library is installed with TrueType support.
1177
+     *
1178
+     * @param Individual $individual
1179
+     *
1180
+     * @return Menu|null
1181
+     *
1182
+     * @deprecated
1183
+     */
1184
+    protected function menuChartFanChart(Individual $individual) {
1185
+        $chart = new FanChartModule(WT_ROOT . WT_MODULES_DIR . 'fan_chart');
1186
+
1187
+        return $chart->getChartMenu($individual);
1188
+    }
1189
+
1190
+    /**
1191
+     * Generate a menu item for the interactive tree.
1192
+     *
1193
+     * @param Individual $individual
1194
+     *
1195
+     * @return Menu|null
1196
+     *
1197
+     * @deprecated
1198
+     */
1199
+    protected function menuChartInteractiveTree(Individual $individual) {
1200
+        $chart = new InteractiveTreeModule(WT_ROOT . WT_MODULES_DIR . 'tree');
1201
+
1202
+        return $chart->getChartMenu($individual);
1203
+    }
1204
+
1205
+    /**
1206
+     * Generate a menu item for the hourglass chart.
1207
+     *
1208
+     * @param Individual $individual
1209
+     *
1210
+     * @return Menu|null
1211
+     *
1212
+     * @deprecated
1213
+     */
1214
+    protected function menuChartHourglass(Individual $individual) {
1215
+        $chart = new HourglassChartModule(WT_ROOT . WT_MODULES_DIR . 'hourglass_chart');
1216
+
1217
+        return $chart->getChartMenu($individual);
1218
+    }
1219
+
1220
+    /**
1221
+     * Generate a menu item for the lifepsan chart.
1222
+     *
1223
+     * @param Individual $individual
1224
+     *
1225
+     * @return Menu|null
1226
+     *
1227
+     * @deprecated
1228
+     */
1229
+    protected function menuChartLifespan(Individual $individual) {
1230
+        $chart = new LifespansChartModule(WT_ROOT . WT_MODULES_DIR . 'lifespans_chart');
1231
+
1232
+        return $chart->getChartMenu($individual);
1233
+    }
1234
+
1235
+    /**
1236
+     * Generate a menu item for the pedigree chart.
1237
+     *
1238
+     * @param Individual $individual
1239
+     *
1240
+     * @return Menu|null
1241
+     *
1242
+     * @deprecated
1243
+     */
1244
+    protected function menuChartPedigree(Individual $individual) {
1245
+        $chart = new PedigreeChartModule(WT_ROOT . WT_MODULES_DIR . 'pedigree_chart');
1246
+
1247
+        return $chart->getChartMenu($individual);
1248
+    }
1249
+
1250
+    /**
1251
+     * Generate a menu item for the pedigree map.
1252
+     *
1253
+     * @param Individual $individual
1254
+     *
1255
+     * @return Menu|null
1256
+     *
1257
+     * @deprecated
1258
+     */
1259
+    protected function menuChartPedigreeMap(Individual $individual) {
1260
+        $chart = new GoogleMapsModule(WT_ROOT . WT_MODULES_DIR . 'googlemap');
1261
+
1262
+        return $chart->getChartMenu($individual);
1263
+    }
1264
+
1265
+    /**
1266
+     * Generate a menu item for the relationship chart.
1267
+     *
1268
+     * @param Individual $individual
1269
+     *
1270
+     * @return Menu|null
1271
+     *
1272
+     * @deprecated
1273
+     */
1274
+    protected function menuChartRelationship(Individual $individual) {
1275
+        $chart = new RelationshipsChartModule(WT_ROOT . WT_MODULES_DIR . 'relationships_chart');
1276
+
1277
+        return $chart->getChartMenu($individual);
1278
+    }
1279
+
1280
+    /**
1281
+     * Generate a menu item for the statistics charts.
1282
+     *
1283
+     * @return Menu|null
1284
+     *
1285
+     * @deprecated
1286
+     */
1287
+    protected function menuChartStatistics() {
1288
+        $chart = new StatisticsChartModule(WT_ROOT . WT_MODULES_DIR . 'statistics_chart');
1289
+
1290
+        return $chart->getChartMenu(null);
1291
+    }
1292
+
1293
+    /**
1294
+     * Generate a menu item for the timeline chart.
1295
+     *
1296
+     * @param Individual $individual
1297
+     *
1298
+     * @return Menu|null
1299
+     *
1300
+     * @deprecated
1301
+     */
1302
+    protected function menuChartTimeline(Individual $individual) {
1303
+        $chart = new TimelineChartModule(WT_ROOT . WT_MODULES_DIR . 'timeline_chart');
1304
+
1305
+        return $chart->getChartMenu($individual);
1306
+    }
1307
+
1308
+    /**
1309
+     * Generate a menu item for the control panel.
1310
+     *
1311
+     * @return Menu|null
1312
+     */
1313
+    protected function menuControlPanel() {
1314
+        if (Auth::isManager($this->tree)) {
1315
+            return new Menu(I18N::translate('Control panel'), 'admin.php', 'menu-admin');
1316
+        } else {
1317
+            return null;
1318
+        }
1319
+    }
1320
+
1321
+    /**
1322
+     * Favorites menu.
1323
+     *
1324
+     * @return Menu|null
1325
+     */
1326
+    protected function menuFavorites() {
1327
+        global $controller;
1328
+
1329
+        $show_user_favorites = $this->tree && Module::getModuleByName('user_favorites') && Auth::check();
1330
+        $show_tree_favorites = $this->tree && Module::getModuleByName('gedcom_favorites');
1331
+
1332
+        if ($show_user_favorites && $show_tree_favorites) {
1333
+            $favorites = array_merge(
1334
+                FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()),
1335
+                UserFavoritesModule::getFavorites(Auth::id())
1336
+            );
1337
+        } elseif ($show_user_favorites) {
1338
+            $favorites = UserFavoritesModule::getFavorites(Auth::id());
1339
+        } elseif ($show_tree_favorites) {
1340
+            $favorites = FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId());
1341
+        } else {
1342
+            $favorites = array();
1343
+        }
1344
+
1345
+        $submenus = array();
1346
+        $records  = array();
1347
+        foreach ($favorites as $favorite) {
1348
+            switch ($favorite['type']) {
1349
+            case 'URL':
1350
+                $submenus[] = new Menu($favorite['title'], $favorite['url']);
1351
+                break;
1352
+            case 'INDI':
1353
+            case 'FAM':
1354
+            case 'SOUR':
1355
+            case 'OBJE':
1356
+            case 'NOTE':
1357
+                $record = GedcomRecord::getInstance($favorite['gid'], $this->tree);
1358
+                if ($record && $record->canShowName()) {
1359
+                    $submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl());
1360
+                    $records[]  = $record;
1361
+                }
1362
+                break;
1363
+            }
1364
+        }
1365
+
1366
+        if ($show_user_favorites && isset($controller->record) && $controller->record instanceof GedcomRecord && !in_array($controller->record, $records)) {
1367
+            $submenus[] = new Menu(I18N::translate('Add to favorites'), '#', '', array(
1368
+                'onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite", {xref:"' . $controller->record->getXref() . '"},function(){location.reload();})',
1369
+            ));
1370
+        }
1371
+
1372
+        if (empty($submenus)) {
1373
+            return null;
1374
+        } else {
1375
+            return new Menu(I18N::translate('Favorites'), '#', 'menu-favorites', array(), $submenus);
1376
+        }
1377
+    }
1378
+
1379
+    /**
1380
+     * A menu for the home (family tree) pages.
1381
+     *
1382
+     * @return Menu
1383
+     */
1384
+    protected function menuHomePage() {
1385
+        if (count(Tree::getAll()) === 1 || Site::getPreference('ALLOW_CHANGE_GEDCOM') === '0') {
1386
+            return new Menu(I18N::translate('Family tree'), 'index.php?ctype=gedcom&amp;' . $this->tree_url, 'menu-tree');
1387
+        } else {
1388
+            $submenus = array();
1389
+            foreach (Tree::getAll() as $tree) {
1390
+                if ($tree == $this->tree) {
1391
+                    $active = 'active ';
1392
+                } else {
1393
+                    $active = '';
1394
+                }
1395
+                $submenus[] = new Menu($tree->getTitleHtml(), 'index.php?ctype=gedcom&amp;ged=' . $tree->getNameUrl(), $active . 'menu-tree-' . $tree->getTreeId());
1396
+            }
1397
+
1398
+            return new Menu(I18N::translate('Family trees'), '#', 'menu-tree', array(), $submenus);
1399
+        }
1400
+    }
1401
+
1402
+    /**
1403
+     * A menu to show a list of available languages.
1404
+     *
1405
+     * @return Menu|null
1406
+     */
1407
+    protected function menuLanguages() {
1408
+        $menu = new Menu(I18N::translate('Language'), '#', 'menu-language');
1409
+
1410
+        foreach (I18N::activeLocales() as $locale) {
1411
+            $language_tag = $locale->languageTag();
1412
+            $class        = 'menu-language-' . $language_tag . (WT_LOCALE === $language_tag ? ' active' : '');
1413
+            $menu->addSubmenu(new Menu($locale->endonym(), '#', $class, array(
1414
+                'onclick'       => 'return false;',
1415
+                'data-language' => $language_tag,
1416
+            )));
1417
+        }
1418
+
1419
+        if (count($menu->getSubmenus()) > 1) {
1420
+            return $menu;
1421
+        } else {
1422
+            return null;
1423
+        }
1424
+    }
1425
+
1426
+    /**
1427
+     * Create a menu to show lists of individuals, families, sources, etc.
1428
+     *
1429
+     * @param string $surname The significant surname on the page
1430
+     *
1431
+     * @return Menu
1432
+     */
1433
+    protected function menuLists($surname) {
1434
+        // Do not show empty lists
1435
+        $row = Database::prepare(
1436
+            "SELECT" .
1437
+            " EXISTS(SELECT 1 FROM `##sources` WHERE s_file = ?) AS sour," .
1438
+            " EXISTS(SELECT 1 FROM `##other` WHERE o_file = ? AND o_type='REPO') AS repo," .
1439
+            " EXISTS(SELECT 1 FROM `##other` WHERE o_file = ? AND o_type='NOTE') AS note," .
1440
+            " EXISTS(SELECT 1 FROM `##media` WHERE m_file = ?) AS obje"
1441
+        )->execute(array(
1442
+            $this->tree->getTreeId(),
1443
+            $this->tree->getTreeId(),
1444
+            $this->tree->getTreeId(),
1445
+            $this->tree->getTreeId(),
1446
+        ))->fetchOneRow();
1447
+
1448
+        $submenus = array(
1449
+            $this->menuListsIndividuals($surname),
1450
+            $this->menuListsFamilies($surname),
1451
+            $this->menuListsBranches($surname),
1452
+            $this->menuListsPlaces(),
1453
+        );
1454
+        if ($row->obje) {
1455
+            $submenus[] = $this->menuListsMedia();
1456
+        }
1457
+        if ($row->repo) {
1458
+            $submenus[] = $this->menuListsRepositories();
1459
+        }
1460
+        if ($row->sour) {
1461
+            $submenus[] = $this->menuListsSources();
1462
+        }
1463
+        if ($row->note) {
1464
+            $submenus[] = $this->menuListsNotes();
1465
+        }
1466
+
1467
+        uasort($submenus, function (Menu $x, Menu $y) {
1468
+            return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1469
+        });
1470
+
1471
+        return new Menu(I18N::translate('Lists'), '#', 'menu-list', array(), $submenus);
1472
+    }
1473
+
1474
+    /**
1475
+     * A menu for the list of branches
1476
+     *
1477
+     * @param string $surname The significant surname on the page
1478
+     *
1479
+     * @return Menu
1480
+     */
1481
+    protected function menuListsBranches($surname) {
1482
+        return new Menu(I18N::translate('Branches'), 'branches.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-branches', array('rel' => 'nofollow'));
1483
+    }
1484
+
1485
+    /**
1486
+     * A menu for the list of families
1487
+     *
1488
+     * @param string $surname The significant surname on the page
1489
+     *
1490
+     * @return Menu
1491
+     */
1492
+    protected function menuListsFamilies($surname) {
1493
+        return new Menu(I18N::translate('Families'), 'famlist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-fam', array('rel' => 'nofollow'));
1494
+    }
1495
+
1496
+    /**
1497
+     * A menu for the list of individuals
1498
+     *
1499
+     * @param string $surname The significant surname on the page
1500
+     *
1501
+     * @return Menu
1502
+     */
1503
+    protected function menuListsIndividuals($surname) {
1504
+        return new Menu(I18N::translate('Individuals'), 'indilist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-indi');
1505
+    }
1506
+
1507
+    /**
1508
+     * A menu for the list of media objects
1509
+     *
1510
+     * @return Menu
1511
+     */
1512
+    protected function menuListsMedia() {
1513
+        return new Menu(I18N::translate('Media objects'), 'medialist.php?' . $this->tree_url, 'menu-list-obje', array('rel' => 'nofollow'));
1514
+    }
1515
+
1516
+    /**
1517
+     * A menu for the list of notes
1518
+     *
1519
+     * @return Menu
1520
+     */
1521
+    protected function menuListsNotes() {
1522
+        return new Menu(I18N::translate('Shared notes'), 'notelist.php?' . $this->tree_url, 'menu-list-note', array('rel' => 'nofollow'));
1523
+    }
1524
+
1525
+    /**
1526
+     * A menu for the list of individuals
1527
+     *
1528
+     * @return Menu
1529
+     */
1530
+    protected function menuListsPlaces() {
1531
+        return new Menu(I18N::translate('Place hierarchy'), 'placelist.php?ged=' . $this->tree->getNameUrl(), 'menu-list-plac', array('rel' => 'nofollow'));
1532
+    }
1533
+
1534
+    /**
1535
+     * A menu for the list of repositories
1536
+     *
1537
+     * @return Menu
1538
+     */
1539
+    protected function menuListsRepositories() {
1540
+        return new Menu(I18N::translate('Repositories'), 'repolist.php?' . $this->tree_url, 'menu-list-repo', array('rel' => 'nofollow'));
1541
+    }
1542
+
1543
+    /**
1544
+     * A menu for the list of sources
1545
+     *
1546
+     * @return Menu
1547
+     */
1548
+    protected function menuListsSources() {
1549
+        return new Menu(I18N::translate('Sources'), 'sourcelist.php?' . $this->tree_url, 'menu-list-sour', array('rel' => 'nofollow'));
1550
+    }
1551
+
1552
+    /**
1553
+     * A login menu option (or null if we are already logged in).
1554
+     *
1555
+     * @return Menu|null
1556
+     */
1557
+    protected function menuLogin() {
1558
+        if (Auth::check() || WT_SCRIPT_NAME === 'login.php') {
1559
+            return null;
1560
+        } else {
1561
+            return new Menu(I18N::translate('Sign in'), WT_LOGIN_URL . '?url=' . rawurlencode(Functions::getQueryUrl()), 'menu-login', array('rel' => 'nofollow'));
1562
+        }
1563
+    }
1564
+
1565
+    /**
1566
+     * A logout menu option (or null if we are already logged out).
1567
+     *
1568
+     * @return Menu|null
1569
+     */
1570
+    protected function menuLogout() {
1571
+        if (Auth::check()) {
1572
+            return new Menu(I18N::translate('Sign out'), 'logout.php', 'menu-logout');
1573
+        } else {
1574
+            return null;
1575
+        }
1576
+    }
1577
+
1578
+    /**
1579
+     * Get the additional menus created by each of the modules
1580
+     *
1581
+     * @return Menu[]
1582
+     */
1583
+    protected function menuModules() {
1584
+        $menus = array();
1585
+        foreach (Module::getActiveMenus($this->tree) as $module) {
1586
+            $menus[] = $module->getMenu();
1587
+        }
1588
+
1589
+        return array_filter($menus);
1590
+    }
1591
+
1592
+    /**
1593
+     * A link to allow users to edit their account settings (edituser.php).
1594
+     *
1595
+     * @return Menu|null
1596
+     */
1597
+    protected function menuMyAccount() {
1598
+        if (Auth::check()) {
1599
+            return new Menu(I18N::translate('My account'), 'edituser.php');
1600
+        } else {
1601
+            return null;
1602
+        }
1603
+    }
1604
+
1605
+    /**
1606
+     * A link to the user's individual record (individual.php).
1607
+     *
1608
+     * @return Menu|null
1609
+     */
1610
+    protected function menuMyIndividualRecord() {
1611
+        $gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1612
+
1613
+        if ($gedcomid) {
1614
+            return new Menu(I18N::translate('My individual record'), 'individual.php?pid=' . $gedcomid . '&amp;' . $this->tree_url, 'menu-myrecord');
1615
+        } else {
1616
+            return null;
1617
+        }
1618
+    }
1619
+
1620
+    /**
1621
+     * A link to the user's personal home page.
1622
+     *
1623
+     * @return Menu
1624
+     */
1625
+    protected function menuMyPage() {
1626
+        return new Menu(I18N::translate('My page'), 'index.php?ctype=user&amp;' . $this->tree_url, 'menu-mypage');
1627
+    }
1628
+
1629
+    /**
1630
+     * A menu for the user's personal pages.
1631
+     *
1632
+     * @return Menu|null
1633
+     */
1634
+    protected function menuMyPages() {
1635
+        if (Auth::id()) {
1636
+            return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', array(), array_filter(array(
1637
+                $this->menuMyPage(),
1638
+                $this->menuMyIndividualRecord(),
1639
+                $this->menuMyPedigree(),
1640
+                $this->menuMyAccount(),
1641
+                $this->menuControlPanel(),
1642
+                $this->menuChangeBlocks(),
1643
+            )));
1644
+        } else {
1645
+            return null;
1646
+        }
1647
+    }
1648
+
1649
+    /**
1650
+     * A link to the user's individual record.
1651
+     *
1652
+     * @return Menu|null
1653
+     */
1654
+    protected function menuMyPedigree() {
1655
+        $gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1656
+
1657
+        if ($gedcomid && Module::isActiveChart($this->tree, 'pedigree_chart')) {
1658
+            $showFull   = $this->tree->getPreference('PEDIGREE_FULL_DETAILS') ? 1 : 0;
1659
+            $showLayout = $this->tree->getPreference('PEDIGREE_LAYOUT') ? 1 : 0;
1660
+
1661
+            return new Menu(
1662
+                I18N::translate('My pedigree'),
1663
+                'pedigree.php?' . $this->tree_url . '&amp;rootid=' . $gedcomid . '&amp;show_full=' . $showFull . '&amp;talloffset=' . $showLayout,
1664
+                'menu-mypedigree'
1665
+            );
1666
+        } else {
1667
+            return null;
1668
+        }
1669
+    }
1670
+
1671
+    /**
1672
+     * Create a pending changes menu.
1673
+     *
1674
+     * @return Menu|null
1675
+     */
1676
+    protected function menuPendingChanges() {
1677
+        if ($this->pendingChangesExist()) {
1678
+            $menu = new Menu(I18N::translate('Pending changes'), '#', 'menu-pending', array('onclick' => 'window.open("edit_changes.php", "_blank", chan_window_specs); return false;'));
1679
+
1680
+            return $menu;
1681
+        } else {
1682
+            return null;
1683
+        }
1684
+    }
1685
+
1686
+    /**
1687
+     * A menu with a list of reports.
1688
+     *
1689
+     * @return Menu|null
1690
+     */
1691
+    protected function menuReports() {
1692
+        $submenus = array();
1693
+        foreach (Module::getActiveReports($this->tree) as $report) {
1694
+            $submenus[] = $report->getReportMenu();
1695
+        }
1696
+
1697
+        if ($submenus) {
1698
+            return new Menu(I18N::translate('Reports'), '#', 'menu-report', array('rel' => 'nofollow'), $submenus);
1699
+        } else {
1700
+            return null;
1701
+        }
1702
+    }
1703
+
1704
+    /**
1705
+     * Create the search menu.
1706
+     *
1707
+     * @return Menu
1708
+     */
1709
+    protected function menuSearch() {
1710
+        return new Menu(I18N::translate('Search'), '#', 'menu-search', array('rel' => 'nofollow'), array_filter(array(
1711
+            $this->menuSearchGeneral(),
1712
+            $this->menuSearchPhonetic(),
1713
+            $this->menuSearchAdvanced(),
1714
+            $this->menuSearchAndReplace(),
1715
+        )));
1716
+    }
1717
+
1718
+    /**
1719
+     * Create the general search sub-menu.
1720
+     *
1721
+     * @return Menu
1722
+     */
1723
+    protected function menuSearchGeneral() {
1724
+        return new Menu(I18N::translate('General search'), 'search.php?' . $this->tree_url, 'menu-search-general', array('rel' => 'nofollow'));
1725
+    }
1726
+
1727
+    /**
1728
+     * Create the phonetic search sub-menu.
1729
+     *
1730
+     * @return Menu
1731
+     */
1732
+    protected function menuSearchPhonetic() {
1733
+        return new Menu(/* I18N: search using “sounds like”, rather than exact spelling */ I18N::translate('Phonetic search'), 'search.php?' . $this->tree_url . '&amp;action=soundex', 'menu-search-soundex', array('rel' => 'nofollow'));
1734
+    }
1735
+
1736
+    /**
1737
+     * Create the advanced search sub-menu.
1738
+     *
1739
+     * @return Menu
1740
+     */
1741
+    protected function menuSearchAdvanced() {
1742
+        return new Menu(I18N::translate('Advanced search'), 'search_advanced.php?' . $this->tree_url, 'menu-search-advanced', array('rel' => 'nofollow'));
1743
+    }
1744
+
1745
+    /**
1746
+     * Create the advanced search sub-menu.
1747
+     *
1748
+     * @return Menu
1749
+     */
1750
+    protected function menuSearchAndReplace() {
1751
+        if (Auth::isEditor($this->tree)) {
1752
+            return new Menu(I18N::translate('Search and replace'), 'search.php?' . $this->tree_url . '&amp;action=replace', 'menu-search-replace');
1753
+        } else {
1754
+            return null;
1755
+        }
1756
+    }
1757
+
1758
+    /**
1759
+     * Themes menu.
1760
+     *
1761
+     * @return Menu|null
1762
+     */
1763
+    public function menuThemes() {
1764
+        if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
1765
+            $submenus = array();
1766
+            foreach (Theme::installedThemes() as $theme) {
1767
+                $class      = 'menu-theme-' . $theme->themeId() . ($theme === $this ? ' active' : '');
1768
+                $submenus[] = new Menu($theme->themeName(), '#', $class, array(
1769
+                    'onclick'    => 'return false;',
1770
+                    'data-theme' => $theme->themeId(),
1771
+                ));
1772
+            }
1773
+
1774
+            usort($submenus, function (Menu $x, Menu $y) {
1775
+                return I18N::strcasecmp($x->getLabel(), $y->getLabel());
1776
+            });
1777
+
1778
+            $menu = new Menu(I18N::translate('Theme'), '#', 'menu-theme', array(), $submenus);
1779
+
1780
+            return $menu;
1781
+        } else {
1782
+            return null;
1783
+        }
1784
+    }
1785
+
1786
+    /**
1787
+     * Create the <meta charset=""> tag.
1788
+     *
1789
+     * @return string
1790
+     */
1791
+    protected function metaCharset() {
1792
+        return '<meta charset="UTF-8">';
1793
+    }
1794
+
1795
+    /**
1796
+     * Create the <meta name="description"> tag.
1797
+     *
1798
+     * @param string $description
1799
+     *
1800
+     * @return string
1801
+     */
1802
+    protected function metaDescription($description) {
1803
+        if ($description) {
1804
+            return '<meta name="description" content="' . $description . '">';
1805
+        } else {
1806
+            return '';
1807
+        }
1808
+    }
1809
+
1810
+    /**
1811
+     * Create the <meta name="generator"> tag.
1812
+     *
1813
+     * @param string $generator
1814
+     *
1815
+     * @return string
1816
+     */
1817
+    protected function metaGenerator($generator) {
1818
+        if ($generator) {
1819
+            return '<meta name="generator" content="' . $generator . '">';
1820
+        } else {
1821
+            return '';
1822
+        }
1823
+    }
1824
+
1825
+    /**
1826
+     * Create the <meta name="robots"> tag.
1827
+     *
1828
+     * @param string $robots
1829
+     *
1830
+     * @return string
1831
+     */
1832
+    protected function metaRobots($robots) {
1833
+        if ($robots) {
1834
+            return '<meta name="robots" content="' . $robots . '">';
1835
+        } else {
1836
+            return '';
1837
+        }
1838
+    }
1839
+
1840
+    /**
1841
+     * Create the <meta http-equiv="X-UA-Compatible"> tag.
1842
+     *
1843
+     * @return string
1844
+     */
1845
+    protected function metaUaCompatible() {
1846
+        return '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
1847
+    }
1848
+
1849
+    /**
1850
+     * Create the <meta name="viewport" content="width=device-width, initial-scale=1"> tag.
1851
+     *
1852
+     * @return string
1853
+     */
1854
+    protected function metaViewport() {
1855
+        return '<meta name="viewport" content="width=device-width, initial-scale=1">';
1856
+    }
1857
+
1858
+    /**
1859
+     * How many times has the current page been shown?
1860
+     *
1861
+     * @param  PageController $controller
1862
+     *
1863
+     * @return int Number of views, or zero for pages that aren't logged.
1864
+     */
1865
+    protected function pageViews(PageController $controller) {
1866
+        if ($this->tree && $this->tree->getPreference('SHOW_COUNTER')) {
1867
+            if (isset($controller->record) && $controller->record instanceof GedcomRecord) {
1868
+                return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->record->getXref());
1869
+            } elseif (isset($controller->root) && $controller->root instanceof GedcomRecord) {
1870
+                return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->root->getXref());
1871
+            } elseif (WT_SCRIPT_NAME === 'index.php') {
1872
+                if (Auth::check() && Filter::get('ctype') !== 'gedcom') {
1873
+                    return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'user:' . Auth::id());
1874
+                } else {
1875
+                    return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'gedcom:' . $this->tree->getTreeId());
1876
+                }
1877
+            }
1878
+        }
1879
+
1880
+        return 0;
1881
+    }
1882
+
1883
+    /**
1884
+     * Misecellaneous dimensions, fonts, styles, etc.
1885
+     *
1886
+     * @param string $parameter_name
1887
+     *
1888
+     * @return string|int|float
1889
+     */
1890
+    public function parameter($parameter_name) {
1891
+        $parameters = array(
1892
+            'chart-background-f'             => 'dddddd',
1893
+            'chart-background-m'             => 'cccccc',
1894
+            'chart-background-u'             => 'eeeeee',
1895
+            'chart-box-x'                    => 250,
1896
+            'chart-box-y'                    => 80,
1897
+            'chart-descendancy-indent'       => 15,
1898
+            'chart-font-color'               => '000000',
1899
+            'chart-font-name'                => WT_ROOT . 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf',
1900
+            'chart-font-size'                => 7,
1901
+            'chart-spacing-x'                => 5,
1902
+            'chart-spacing-y'                => 10,
1903
+            'compact-chart-box-x'            => 240,
1904
+            'compact-chart-box-y'            => 50,
1905
+            'distribution-chart-high-values' => '555555',
1906
+            'distribution-chart-low-values'  => 'cccccc',
1907
+            'distribution-chart-no-values'   => 'ffffff',
1908
+            'distribution-chart-x'           => 440,
1909
+            'distribution-chart-y'           => 220,
1910
+            'line-width'                     => 1.5,
1911
+            'shadow-blur'                    => 0,
1912
+            'shadow-color'                   => '',
1913
+            'shadow-offset-x'                => 0,
1914
+            'shadow-offset-y'                => 0,
1915
+            'stats-small-chart-x'            => 440,
1916
+            'stats-small-chart-y'            => 125,
1917
+            'stats-large-chart-x'            => 900,
1918
+            'image-dline'                    => $this->assetUrl() . 'images/dline.png',
1919
+            'image-dline2'                   => $this->assetUrl() . 'images/dline2.png',
1920
+            'image-hline'                    => $this->assetUrl() . 'images/hline.png',
1921
+            'image-spacer'                   => $this->assetUrl() . 'images/spacer.png',
1922
+            'image-vline'                    => $this->assetUrl() . 'images/vline.png',
1923
+            'image-minus'                    => $this->assetUrl() . 'images/minus.png',
1924
+            'image-plus'                     => $this->assetUrl() . 'images/plus.png',
1925
+        );
1926
+
1927
+        if (array_key_exists($parameter_name, $parameters)) {
1928
+            return $parameters[$parameter_name];
1929
+        } else {
1930
+            throw new \InvalidArgumentException($parameter_name);
1931
+        }
1932
+    }
1933
+
1934
+    /**
1935
+     * Are there any pending changes for us to approve?
1936
+     *
1937
+     * @return bool
1938
+     */
1939
+    protected function pendingChangesExist() {
1940
+        return $this->tree && $this->tree->hasPendingEdit() && Auth::isModerator($this->tree);
1941
+    }
1942
+
1943
+    /**
1944
+     * Create a pending changes link. Some themes prefer an alert/banner to a menu.
1945
+     *
1946
+     * @return string
1947
+     */
1948
+    protected function pendingChangesLink() {
1949
+        return
1950
+            '<a href="#" onclick="window.open(\'edit_changes.php\', \'_blank\', chan_window_specs); return false;">' .
1951
+            $this->pendingChangesLinkText() .
1952
+            '</a>';
1953
+    }
1954
+
1955
+    /**
1956
+     * Text to use in the pending changes link.
1957
+     *
1958
+     * @return string
1959
+     */
1960
+    protected function pendingChangesLinkText() {
1961
+        return I18N::translate('There are pending changes for you to moderate.');
1962
+    }
1963
+
1964
+    /**
1965
+     * Generate a list of items for the main menu.
1966
+     *
1967
+     * @return Menu[]
1968
+     */
1969
+    protected function primaryMenu() {
1970
+        global $controller;
1971
+
1972
+        if ($this->tree) {
1973
+            $individual = $controller->getSignificantIndividual();
1974
+
1975
+            return array_filter(array_merge(array(
1976
+                $this->menuHomePage(),
1977
+                $this->menuChart($individual),
1978
+                $this->menuLists($controller->getSignificantSurname()),
1979
+                $this->menuCalendar(),
1980
+                $this->menuReports(),
1981
+                $this->menuSearch(),
1982
+            ), $this->menuModules()));
1983
+        } else {
1984
+            // No public trees? No genealogy menu!
1985
+            return array();
1986
+        }
1987
+    }
1988
+
1989
+    /**
1990
+     * Add markup to the primary menu.
1991
+     *
1992
+     * @param Menu[] $menus
1993
+     *
1994
+     * @return string
1995
+     */
1996
+    protected function primaryMenuContainer(array $menus) {
1997
+        return '<nav><ul class="primary-menu">' . $this->primaryMenuContent($menus) . '</ul></nav>';
1998
+    }
1999
+
2000
+    /**
2001
+     * Create the primary menu.
2002
+     *
2003
+     * @param Menu[] $menus
2004
+     *
2005
+     * @return string
2006
+     */
2007
+    protected function primaryMenuContent(array $menus) {
2008
+        return implode('', array_map(function (Menu $menu) {
2009
+            return $menu->getMenuAsList();
2010
+        }, $menus));
2011
+    }
2012
+
2013
+    /**
2014
+     * Generate a list of items for the user menu.
2015
+     *
2016
+     * @return Menu[]
2017
+     */
2018
+    protected function secondaryMenu() {
2019
+        return array_filter(array(
2020
+            $this->menuPendingChanges(),
2021
+            $this->menuMyPages(),
2022
+            $this->menuFavorites(),
2023
+            $this->menuThemes(),
2024
+            $this->menuLanguages(),
2025
+            $this->menuLogin(),
2026
+            $this->menuLogout(),
2027
+        ));
2028
+    }
2029
+
2030
+    /**
2031
+     * Add markup to the secondary menu.
2032
+     *
2033
+     * @param Menu[] $menus
2034
+     *
2035
+     * @return string
2036
+     */
2037
+    protected function secondaryMenuContainer(array $menus) {
2038
+        return '<ul class="nav nav-pills secondary-menu">' . $this->secondaryMenuContent($menus) . '</ul>';
2039
+    }
2040
+
2041
+    /**
2042
+     * Format the secondary menu.
2043
+     *
2044
+     * @param Menu[] $menus
2045
+     *
2046
+     * @return string
2047
+     */
2048
+    protected function secondaryMenuContent(array $menus) {
2049
+        return implode('', array_map(function (Menu $menu) {
2050
+            return $menu->getMenuAsList();
2051
+        }, $menus));
2052
+    }
2053
+
2054
+    /**
2055
+     * Send any HTTP headers.
2056
+     */
2057
+    public function sendHeaders() {
2058
+        header('Content-Type: text/html; charset=UTF-8');
2059
+    }
2060
+
2061
+    /**
2062
+     * A list of CSS files to include for this page.
2063
+     *
2064
+     * @return string[]
2065
+     */
2066
+    protected function stylesheets() {
2067
+        $stylesheets = array(
2068
+            WT_BOOTSTRAP_CSS_URL,
2069
+            WT_FONT_AWESOME_CSS_URL,
2070
+            WT_FONT_AWESOME_RTL_CSS_URL,
2071
+        );
2072
+
2073
+        if (I18N::direction() === 'rtl') {
2074
+            $stylesheets[] = WT_BOOTSTRAP_RTL_CSS_URL;
2075
+        }
2076
+
2077
+        return $stylesheets;
2078
+    }
2079
+
2080
+    /**
2081
+     * Create the <title> tag.
2082
+     *
2083
+     * @param string $title
2084
+     *
2085
+     * @return string
2086
+     */
2087
+    protected function title($title) {
2088
+        return '<title>' . Filter::escapeHtml($title) . '</title>';
2089
+    }
2090 2090
 }
Please login to merge, or discard this patch.
Switch Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -265,12 +265,12 @@  discard block
 block discarded – undo
265 265
 		$method = $user->getPreference('contactmethod');
266 266
 
267 267
 		switch ($method) {
268
-		case 'none':
269
-			return '';
270
-		case 'mailto':
271
-			return '<a href="mailto:' . Filter::escapeHtml($user->getEmail()) . '">' . $user->getRealNameHtml() . '</a>';
272
-		default:
273
-			return "<a href='#' onclick='message(\"" . Filter::escapeHtml($user->getUserName()) . "\", \"" . $method . "\", \"" . WT_BASE_URL . Filter::escapeHtml(Functions::getQueryUrl()) . "\", \"\");return false;'>" . $user->getRealNameHtml() . '</a>';
268
+		    case 'none':
269
+			    return '';
270
+		    case 'mailto':
271
+			    return '<a href="mailto:' . Filter::escapeHtml($user->getEmail()) . '">' . $user->getRealNameHtml() . '</a>';
272
+		    default:
273
+			    return "<a href='#' onclick='message(\"" . Filter::escapeHtml($user->getUserName()) . "\", \"" . $method . "\", \"" . WT_BASE_URL . Filter::escapeHtml(Functions::getQueryUrl()) . "\", \"\");return false;'>" . $user->getRealNameHtml() . '</a>';
274 274
 		}
275 275
 	}
276 276
 
@@ -1346,20 +1346,20 @@  discard block
 block discarded – undo
1346 1346
 		$records  = array();
1347 1347
 		foreach ($favorites as $favorite) {
1348 1348
 			switch ($favorite['type']) {
1349
-			case 'URL':
1350
-				$submenus[] = new Menu($favorite['title'], $favorite['url']);
1351
-				break;
1352
-			case 'INDI':
1353
-			case 'FAM':
1354
-			case 'SOUR':
1355
-			case 'OBJE':
1356
-			case 'NOTE':
1357
-				$record = GedcomRecord::getInstance($favorite['gid'], $this->tree);
1358
-				if ($record && $record->canShowName()) {
1359
-					$submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl());
1360
-					$records[]  = $record;
1361
-				}
1362
-				break;
1349
+			    case 'URL':
1350
+				    $submenus[] = new Menu($favorite['title'], $favorite['url']);
1351
+				    break;
1352
+			    case 'INDI':
1353
+			    case 'FAM':
1354
+			    case 'SOUR':
1355
+			    case 'OBJE':
1356
+			    case 'NOTE':
1357
+				    $record = GedcomRecord::getInstance($favorite['gid'], $this->tree);
1358
+				    if ($record && $record->canShowName()) {
1359
+					    $submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl());
1360
+					    $records[]  = $record;
1361
+				    }
1362
+				    break;
1363 1363
 			}
1364 1364
 		}
1365 1365
 
Please login to merge, or discard this patch.
Braces   +244 added lines, -122 removed lines patch added patch discarded remove patch
@@ -52,7 +52,8 @@  discard block
 block discarded – undo
52 52
 /**
53 53
  * Common functions for all themes.
54 54
  */
55
-abstract class AbstractTheme {
55
+abstract class AbstractTheme
56
+{
56 57
 	/** @var Tree The current tree */
57 58
 	protected $tree;
58 59
 
@@ -66,7 +67,8 @@  discard block
 block discarded – undo
66 67
 	 * Custom themes should place their initialization code in the function hookAfterInit(), not in
67 68
 	 * the constructor, as all themes get constructed - whether they are used or not.
68 69
 	 */
69
-	final public function __construct() {
70
+	final public function __construct()
71
+	{
70 72
 	}
71 73
 
72 74
 	/**
@@ -77,7 +79,8 @@  discard block
 block discarded – undo
77 79
 	 *
78 80
 	 * @return string
79 81
 	 */
80
-	protected function accessibilityLinks() {
82
+	protected function accessibilityLinks()
83
+	{
81 84
 		return
82 85
 			'<div class="accessibility-links">' .
83 86
 			'<a class="sr-only sr-only-focusable btn btn-info btn-sm" href="#content">' .
@@ -91,7 +94,8 @@  discard block
 block discarded – undo
91 94
 	 *
92 95
 	 * @return string
93 96
 	 */
94
-	protected function analytics() {
97
+	protected function analytics()
98
+	{
95 99
 		if ($this->themeId() === '_administration' || !empty($_SERVER['HTTP_DNT'])) {
96 100
 			return '';
97 101
 		} else {
@@ -123,7 +127,8 @@  discard block
 block discarded – undo
123 127
 	 *
124 128
 	 * @return string
125 129
 	 */
126
-	protected function analyticsBingWebmaster($verification_id) {
130
+	protected function analyticsBingWebmaster($verification_id)
131
+	{
127 132
 		// Only need to add this to the home page.
128 133
 		if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
129 134
 			return '<meta name="msvalidate.01" content="' . $verification_id . '">';
@@ -139,7 +144,8 @@  discard block
 block discarded – undo
139 144
 	 *
140 145
 	 * @return string
141 146
 	 */
142
-	protected function analyticsGoogleWebmaster($verification_id) {
147
+	protected function analyticsGoogleWebmaster($verification_id)
148
+	{
143 149
 		// Only need to add this to the home page.
144 150
 		if (WT_SCRIPT_NAME === 'index.php' && $verification_id) {
145 151
 			return '<meta name="google-site-verification" content="' . $verification_id . '">';
@@ -157,7 +163,8 @@  discard block
 block discarded – undo
157 163
 	 *
158 164
 	 * @return string
159 165
 	 */
160
-	protected function analyticsGoogleTracker($analytics_id) {
166
+	protected function analyticsGoogleTracker($analytics_id)
167
+	{
161 168
 		if ($analytics_id) {
162 169
 			// Add extra dimensions (i.e. filtering categories)
163 170
 			$dimensions = (object) array(
@@ -185,7 +192,8 @@  discard block
 block discarded – undo
185 192
 	 *
186 193
 	 * @return string
187 194
 	 */
188
-	protected function analyticsPiwikTracker($url, $site_id) {
195
+	protected function analyticsPiwikTracker($url, $site_id)
196
+	{
189 197
 		$url = preg_replace(array('/^https?:\/\//', '/\/$/'), '', $url);
190 198
 
191 199
 		if ($url && $site_id) {
@@ -213,7 +221,8 @@  discard block
 block discarded – undo
213 221
 	 *
214 222
 	 * @return string
215 223
 	 */
216
-	protected function analyticsStatcounterTracker($project_id, $security_id) {
224
+	protected function analyticsStatcounterTracker($project_id, $security_id)
225
+	{
217 226
 		if ($project_id && $security_id) {
218 227
 			return
219 228
 				'<script>' .
@@ -231,7 +240,8 @@  discard block
 block discarded – undo
231 240
 	 *
232 241
 	 * @return string
233 242
 	 */
234
-	public function bodyHeader() {
243
+	public function bodyHeader()
244
+	{
235 245
 		return
236 246
 			'<body class="container">' .
237 247
 			'<header>' .
@@ -247,7 +257,8 @@  discard block
 block discarded – undo
247 257
 	 *
248 258
 	 * @return string
249 259
 	 */
250
-	public function bodyHeaderPopupWindow() {
260
+	public function bodyHeaderPopupWindow()
261
+	{
251 262
 		return
252 263
 			'<body class="container container-popup">' .
253 264
 			'<main id="content">' .
@@ -261,7 +272,8 @@  discard block
 block discarded – undo
261 272
 	 *
262 273
 	 * @return string
263 274
 	 */
264
-	public function contactLink(User $user) {
275
+	public function contactLink(User $user)
276
+	{
265 277
 		$method = $user->getPreference('contactmethod');
266 278
 
267 279
 		switch ($method) {
@@ -281,7 +293,8 @@  discard block
 block discarded – undo
281 293
 	 *
282 294
 	 * @return string
283 295
 	 */
284
-	protected function contactLinkEverything(User $user) {
296
+	protected function contactLinkEverything(User $user)
297
+	{
285 298
 		return I18N::translate('For technical support or genealogy questions contact %s.', $this->contactLink($user));
286 299
 	}
287 300
 
@@ -292,7 +305,8 @@  discard block
 block discarded – undo
292 305
 	 *
293 306
 	 * @return string
294 307
 	 */
295
-	protected function contactLinkGenealogy(User $user) {
308
+	protected function contactLinkGenealogy(User $user)
309
+	{
296 310
 		return I18N::translate('For help with genealogy questions contact %s.', $this->contactLink($user));
297 311
 	}
298 312
 
@@ -303,7 +317,8 @@  discard block
 block discarded – undo
303 317
 	 *
304 318
 	 * @return string
305 319
 	 */
306
-	protected function contactLinkTechnical(User $user) {
320
+	protected function contactLinkTechnical(User $user)
321
+	{
307 322
 		return I18N::translate('For technical support and information contact %s.', $this->contactLink($user));
308 323
 	}
309 324
 
@@ -312,7 +327,8 @@  discard block
 block discarded – undo
312 327
 	 *
313 328
 	 * @return string
314 329
 	 */
315
-	protected function contactLinks() {
330
+	protected function contactLinks()
331
+	{
316 332
 		$contact_user   = User::find($this->tree->getPreference('CONTACT_USER_ID'));
317 333
 		$webmaster_user = User::find($this->tree->getPreference('WEBMASTER_USER_ID'));
318 334
 
@@ -334,7 +350,8 @@  discard block
 block discarded – undo
334 350
 	 *
335 351
 	 * @return string
336 352
 	 */
337
-	public function cookieWarning() {
353
+	public function cookieWarning()
354
+	{
338 355
 		if (
339 356
 			empty($_SERVER['HTTP_DNT']) &&
340 357
 			empty($_COOKIE['cookie']) &&
@@ -356,7 +373,8 @@  discard block
 block discarded – undo
356 373
 	 *
357 374
 	 * @return string
358 375
 	 */
359
-	public function doctype() {
376
+	public function doctype()
377
+	{
360 378
 		return '<!DOCTYPE html>';
361 379
 	}
362 380
 
@@ -365,7 +383,8 @@  discard block
 block discarded – undo
365 383
 	 *
366 384
 	 * @return string
367 385
 	 */
368
-	protected function favicon() {
386
+	protected function favicon()
387
+	{
369 388
 		return
370 389
 			'<link rel="icon" href="' . $this->assetUrl() . 'favicon.png" type="image/png">' .
371 390
 			'<link rel="icon" type="image/png" href="' . $this->assetUrl() . 'favicon192.png" sizes="192x192">' .
@@ -379,7 +398,8 @@  discard block
 block discarded – undo
379 398
 	 *
380 399
 	 * @return string
381 400
 	 */
382
-	protected function flashMessageContainer(\stdClass $message) {
401
+	protected function flashMessageContainer(\stdClass $message)
402
+	{
383 403
 		return $this->htmlAlert($message->text, $message->status, true);
384 404
 	}
385 405
 
@@ -392,7 +412,8 @@  discard block
 block discarded – undo
392 412
 	 *
393 413
 	 * @return string
394 414
 	 */
395
-	protected function flashMessagesContainer(array $messages) {
415
+	protected function flashMessagesContainer(array $messages)
416
+	{
396 417
 		$html = '';
397 418
 		foreach ($messages as $message) {
398 419
 			$html .= $this->flashMessageContainer($message);
@@ -410,7 +431,8 @@  discard block
 block discarded – undo
410 431
 	 *
411 432
 	 * @return string
412 433
 	 */
413
-	public function footerContainer() {
434
+	public function footerContainer()
435
+	{
414 436
 		return '</main><footer>' . $this->footerContent() . '</footer>';
415 437
 	}
416 438
 
@@ -420,7 +442,8 @@  discard block
 block discarded – undo
420 442
 	 *
421 443
 	 * @return string
422 444
 	 */
423
-	public function footerContainerPopupWindow() {
445
+	public function footerContainerPopupWindow()
446
+	{
424 447
 		return '</main>';
425 448
 	}
426 449
 
@@ -429,7 +452,8 @@  discard block
 block discarded – undo
429 452
 	 *
430 453
 	 * @return string
431 454
 	 */
432
-	protected function footerContent() {
455
+	protected function footerContent()
456
+	{
433 457
 		return
434 458
 			$this->formatContactLinks() .
435 459
 			$this->logoPoweredBy() .
@@ -447,7 +471,8 @@  discard block
 block discarded – undo
447 471
 	 *
448 472
 	 * @return string
449 473
 	 */
450
-	public function formatBlock($id, $title, $class, $content) {
474
+	public function formatBlock($id, $title, $class, $content)
475
+	{
451 476
 		return
452 477
 			'<div id="' . $id . '" class="block" >' .
453 478
 			'<div class="blockheader">' . $title . '</div>' .
@@ -460,7 +485,8 @@  discard block
 block discarded – undo
460 485
 	 *
461 486
 	 * @return string
462 487
 	 */
463
-	protected function formatContactLinks() {
488
+	protected function formatContactLinks()
489
+	{
464 490
 		if ($this->tree) {
465 491
 			return '<div class="contact-links">' . $this->contactLinks() . '</div>';
466 492
 		} else {
@@ -475,7 +501,8 @@  discard block
 block discarded – undo
475 501
 	 *
476 502
 	 * @return string
477 503
 	 */
478
-	protected function formatPageViews($count) {
504
+	protected function formatPageViews($count)
505
+	{
479 506
 		if ($count > 0) {
480 507
 			return
481 508
 				'<div class="page-views">' .
@@ -492,7 +519,8 @@  discard block
 block discarded – undo
492 519
 	 *
493 520
 	 * @return string
494 521
 	 */
495
-	protected function formatPendingChangesLink() {
522
+	protected function formatPendingChangesLink()
523
+	{
496 524
 		if ($this->pendingChangesExist()) {
497 525
 			return '<div class="pending-changes-link">' . $this->pendingChangesLink() . '</div>';
498 526
 		} else {
@@ -505,7 +533,8 @@  discard block
 block discarded – undo
505 533
 	 *
506 534
 	 * @return string
507 535
 	 */
508
-	protected function formQuickSearch() {
536
+	protected function formQuickSearch()
537
+	{
509 538
 		if ($this->tree) {
510 539
 			return
511 540
 				'<form action="search.php" class="header-search" role="search">' .
@@ -523,7 +552,8 @@  discard block
 block discarded – undo
523 552
 	 *
524 553
 	 * @return string
525 554
 	 */
526
-	protected function formQuickSearchFields() {
555
+	protected function formQuickSearchFields()
556
+	{
527 557
 		return
528 558
 			'<input type="search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
529 559
 			'<input type="image" src="' . $this->assetUrl() . 'images/go.png" alt="' . I18N::translate('Search') . '">';
@@ -534,7 +564,8 @@  discard block
 block discarded – undo
534 564
 	 *
535 565
 	 * @return string
536 566
 	 */
537
-	protected function formatTreeTitle() {
567
+	protected function formatTreeTitle()
568
+	{
538 569
 		if ($this->tree) {
539 570
 			return '<h1 class="header-title">' . $this->tree->getTitleHtml() . '</h1>';
540 571
 		} else {
@@ -547,7 +578,8 @@  discard block
 block discarded – undo
547 578
 	 *
548 579
 	 * @return string
549 580
 	 */
550
-	protected function formatSecondaryMenu() {
581
+	protected function formatSecondaryMenu()
582
+	{
551 583
 		return
552 584
 			'<ul class="secondary-menu">' .
553 585
 			implode('', $this->secondaryMenu()) .
@@ -561,7 +593,8 @@  discard block
 block discarded – undo
561 593
 	 *
562 594
 	 * @return string
563 595
 	 */
564
-	protected function formatSecondaryMenuItem(Menu $menu) {
596
+	protected function formatSecondaryMenuItem(Menu $menu)
597
+	{
565 598
 		return $menu->getMenuAsList();
566 599
 	}
567 600
 
@@ -572,7 +605,8 @@  discard block
 block discarded – undo
572 605
 	 *
573 606
 	 * @return string
574 607
 	 */
575
-	public function head(PageController $controller) {
608
+	public function head(PageController $controller)
609
+	{
576 610
 		// Record this now. By the time we render the footer, $controller no longer exists.
577 611
 		$this->page_views = $this->pageViews($controller);
578 612
 
@@ -591,7 +625,8 @@  discard block
 block discarded – undo
591 625
 	 *
592 626
 	 * @return string
593 627
 	 */
594
-	protected function headContents(PageController $controller) {
628
+	protected function headContents(PageController $controller)
629
+	{
595 630
 		// The title often includes the names of records, which may include HTML markup.
596 631
 		$title = Filter::unescapeHtml($controller->getPageTitle());
597 632
 
@@ -629,7 +664,8 @@  discard block
 block discarded – undo
629 664
 	 *
630 665
 	 * @return string
631 666
 	 */
632
-	protected function headerContent() {
667
+	protected function headerContent()
668
+	{
633 669
 		return
634 670
 			//$this->accessibilityLinks() .
635 671
 			$this->logoHeader() .
@@ -643,7 +679,8 @@  discard block
 block discarded – undo
643 679
 	 *
644 680
 	 * @return string
645 681
 	 */
646
-	protected function headerSimple() {
682
+	protected function headerSimple()
683
+	{
647 684
 		return
648 685
 			$this->flashMessagesContainer(FlashMessages::getMessages()) .
649 686
 			'<div id="content">';
@@ -653,7 +690,8 @@  discard block
 block discarded – undo
653 690
 	 * Allow themes to do things after initialization (since they cannot use
654 691
 	 * the constructor).
655 692
 	 */
656
-	public function hookAfterInit() {
693
+	public function hookAfterInit()
694
+	{
657 695
 	}
658 696
 
659 697
 	/**
@@ -661,7 +699,8 @@  discard block
 block discarded – undo
661 699
 	 *
662 700
 	 * @return string
663 701
 	 */
664
-	public function hookFooterExtraJavascript() {
702
+	public function hookFooterExtraJavascript()
703
+	{
665 704
 		return '';
666 705
 	}
667 706
 
@@ -671,7 +710,8 @@  discard block
 block discarded – undo
671 710
 	 *
672 711
 	 * @return string
673 712
 	 */
674
-	public function hookHeaderExtraContent() {
713
+	public function hookHeaderExtraContent()
714
+	{
675 715
 		return '';
676 716
 	}
677 717
 
@@ -680,7 +720,8 @@  discard block
 block discarded – undo
680 720
 	 *
681 721
 	 * @return string
682 722
 	 */
683
-	public function html() {
723
+	public function html()
724
+	{
684 725
 		return '<html ' . I18N::htmlAttributes() . '>';
685 726
 	}
686 727
 
@@ -693,7 +734,8 @@  discard block
 block discarded – undo
693 734
 	 *
694 735
 	 * @return string
695 736
 	 */
696
-	public function htmlAlert($html, $level, $dismissible) {
737
+	public function htmlAlert($html, $level, $dismissible)
738
+	{
697 739
 		if ($dismissible) {
698 740
 			return
699 741
 				'<div class="alert alert-' . $level . ' alert-dismissible" role="alert">' .
@@ -717,7 +759,8 @@  discard block
 block discarded – undo
717 759
 	 *
718 760
 	 * @return string
719 761
 	 */
720
-	public function icon(Fact $fact) {
762
+	public function icon(Fact $fact)
763
+	{
721 764
 		$icon = 'images/facts/' . $fact->getTag() . '.png';
722 765
 		$dir  = substr($this->assetUrl(), strlen(WT_STATIC_URL));
723 766
 		if (file_exists($dir . $icon)) {
@@ -737,7 +780,8 @@  discard block
 block discarded – undo
737 780
 	 *
738 781
 	 * @return string
739 782
 	 */
740
-	public function individualBox(Individual $individual) {
783
+	public function individualBox(Individual $individual)
784
+	{
741 785
 		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
742 786
 		if ($individual->canShow() && $individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
743 787
 			$thumbnail = $individual->displayImage();
@@ -778,7 +822,8 @@  discard block
 block discarded – undo
778 822
 	 *
779 823
 	 * @return string
780 824
 	 */
781
-	public function individualBoxEmpty() {
825
+	public function individualBoxEmpty()
826
+	{
782 827
 		return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px"></div>';
783 828
 	}
784 829
 
@@ -789,7 +834,8 @@  discard block
 block discarded – undo
789 834
 	 *
790 835
 	 * @return string
791 836
 	 */
792
-	public function individualBoxLarge(Individual $individual) {
837
+	public function individualBoxLarge(Individual $individual)
838
+	{
793 839
 		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
794 840
 		if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
795 841
 			$thumbnail = $individual->displayImage();
@@ -832,7 +878,8 @@  discard block
 block discarded – undo
832 878
 	 *
833 879
 	 * @return string
834 880
 	 */
835
-	public function individualBoxSmall(Individual $individual) {
881
+	public function individualBoxSmall(Individual $individual)
882
+	{
836 883
 		$personBoxClass = array_search($individual->getSex(), array('person_box' => 'M', 'person_boxF' => 'F', 'person_boxNN' => 'U'));
837 884
 		if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
838 885
 			$thumbnail = $individual->displayImage();
@@ -858,7 +905,8 @@  discard block
 block discarded – undo
858 905
 	 *
859 906
 	 * @return string
860 907
 	 */
861
-	public function individualBoxSmallEmpty() {
908
+	public function individualBoxSmallEmpty()
909
+	{
862 910
 		return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px"></div>';
863 911
 	}
864 912
 
@@ -869,7 +917,8 @@  discard block
 block discarded – undo
869 917
 	 *
870 918
 	 * @return string
871 919
 	 */
872
-	protected function individualBoxFacts(Individual $individual) {
920
+	protected function individualBoxFacts(Individual $individual)
921
+	{
873 922
 		$html = '';
874 923
 
875 924
 		$opt_tags = preg_split('/\W/', $individual->getTree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY);
@@ -922,7 +971,8 @@  discard block
 block discarded – undo
922 971
 	 *
923 972
 	 * @return string
924 973
 	 */
925
-	protected function individualBoxLdsSummary(Individual $individual) {
974
+	protected function individualBoxLdsSummary(Individual $individual)
975
+	{
926 976
 		if ($individual->getTree()->getPreference('SHOW_LDS_AT_GLANCE')) {
927 977
 			$BAPL = $individual->getFacts('BAPL') ? 'B' : '_';
928 978
 			$ENDL = $individual->getFacts('ENDL') ? 'E' : '_';
@@ -948,7 +998,8 @@  discard block
 block discarded – undo
948 998
 	 *
949 999
 	 * @return Menu[]
950 1000
 	 */
951
-	public function individualBoxMenu(Individual $individual) {
1001
+	public function individualBoxMenu(Individual $individual)
1002
+	{
952 1003
 		$menus = array_merge(
953 1004
 			$this->individualBoxMenuCharts($individual),
954 1005
 			$this->individualBoxMenuFamilyLinks($individual)
@@ -964,7 +1015,8 @@  discard block
 block discarded – undo
964 1015
 	 *
965 1016
 	 * @return Menu[]
966 1017
 	 */
967
-	protected function individualBoxMenuCharts(Individual $individual) {
1018
+	protected function individualBoxMenuCharts(Individual $individual)
1019
+	{
968 1020
 		$menus = array();
969 1021
 		foreach (Module::getActiveCharts($this->tree) as $chart) {
970 1022
 			$menu = $chart->getBoxChartMenu($individual);
@@ -987,7 +1039,8 @@  discard block
 block discarded – undo
987 1039
 	 *
988 1040
 	 * @return Menu[]
989 1041
 	 */
990
-	protected function individualBoxMenuFamilyLinks(Individual $individual) {
1042
+	protected function individualBoxMenuFamilyLinks(Individual $individual)
1043
+	{
991 1044
 		$menus = array();
992 1045
 
993 1046
 		foreach ($individual->getSpouseFamilies() as $family) {
@@ -1013,7 +1066,8 @@  discard block
 block discarded – undo
1013 1066
 	 *
1014 1067
 	 * @return string
1015 1068
 	 */
1016
-	protected function individualBoxSexSymbol(Individual $individual) {
1069
+	protected function individualBoxSexSymbol(Individual $individual)
1070
+	{
1017 1071
 		if ($individual->getTree()->getPreference('PEDIGREE_SHOW_GENDER')) {
1018 1072
 			return $individual->sexImage('large');
1019 1073
 		} else {
@@ -1027,7 +1081,8 @@  discard block
 block discarded – undo
1027 1081
 	 *
1028 1082
 	 * @param Tree|null $tree The current tree (if there is one).
1029 1083
 	 */
1030
-	final public function init(Tree $tree = null) {
1084
+	final public function init(Tree $tree = null)
1085
+	{
1031 1086
 		$this->tree     = $tree;
1032 1087
 		$this->tree_url = $tree ? 'ged=' . $tree->getNameUrl() : '';
1033 1088
 
@@ -1039,7 +1094,8 @@  discard block
 block discarded – undo
1039 1094
 	 *
1040 1095
 	 * @return string
1041 1096
 	 */
1042
-	protected function logoHeader() {
1097
+	protected function logoHeader()
1098
+	{
1043 1099
 		return '<div class="header-logo"></div>';
1044 1100
 	}
1045 1101
 
@@ -1048,7 +1104,8 @@  discard block
 block discarded – undo
1048 1104
 	 *
1049 1105
 	 * @return string
1050 1106
 	 */
1051
-	protected function logoPoweredBy() {
1107
+	protected function logoPoweredBy()
1108
+	{
1052 1109
 		return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '"></a>';
1053 1110
 	}
1054 1111
 
@@ -1057,7 +1114,8 @@  discard block
 block discarded – undo
1057 1114
 	 *
1058 1115
 	 * @return Menu
1059 1116
 	 */
1060
-	protected function menuCalendar() {
1117
+	protected function menuCalendar()
1118
+	{
1061 1119
 		return new Menu(I18N::translate('Calendar'), '#', 'menu-calendar', array('rel' => 'nofollow'), array(
1062 1120
 			// Day view
1063 1121
 			new Menu(I18N::translate('Day'), 'calendar.php?' . $this->tree_url . '&amp;view=day', 'menu-calendar-day', array('rel' => 'nofollow')),
@@ -1073,7 +1131,8 @@  discard block
 block discarded – undo
1073 1131
 	 *
1074 1132
 	 * @return Menu|null
1075 1133
 	 */
1076
-	protected function menuChangeBlocks() {
1134
+	protected function menuChangeBlocks()
1135
+	{
1077 1136
 		if (WT_SCRIPT_NAME === 'index.php' && Auth::check() && Filter::get('ctype', 'gedcom|user', 'user') === 'user') {
1078 1137
 			return new Menu(I18N::translate('Customize this page'), 'index_edit.php?user_id=' . Auth::id(), 'menu-change-blocks');
1079 1138
 		} elseif (WT_SCRIPT_NAME === 'index.php' && Auth::isManager($this->tree)) {
@@ -1090,7 +1149,8 @@  discard block
 block discarded – undo
1090 1149
 	 *
1091 1150
 	 * @return Menu|null
1092 1151
 	 */
1093
-	protected function menuChart(Individual $individual) {
1152
+	protected function menuChart(Individual $individual)
1153
+	{
1094 1154
 		$submenus = array();
1095 1155
 		foreach (Module::getActiveCharts($this->tree) as $chart) {
1096 1156
 			$menu = $chart->getChartMenu($individual);
@@ -1119,7 +1179,8 @@  discard block
 block discarded – undo
1119 1179
 	 *
1120 1180
 	 * @deprecated
1121 1181
 	 */
1122
-	protected function menuChartAncestors(Individual $individual) {
1182
+	protected function menuChartAncestors(Individual $individual)
1183
+	{
1123 1184
 		$chart = new AncestorsChartModule(WT_ROOT . WT_MODULES_DIR . 'ancestors_chart');
1124 1185
 
1125 1186
 		return $chart->getChartMenu($individual);
@@ -1134,7 +1195,8 @@  discard block
 block discarded – undo
1134 1195
 	 *
1135 1196
 	 * @deprecated
1136 1197
 	 */
1137
-	protected function menuChartCompact(Individual $individual) {
1198
+	protected function menuChartCompact(Individual $individual)
1199
+	{
1138 1200
 		$chart = new CompactTreeChartModule(WT_ROOT . WT_MODULES_DIR . 'compact_tree_chart');
1139 1201
 
1140 1202
 		return $chart->getChartMenu($individual);
@@ -1149,7 +1211,8 @@  discard block
 block discarded – undo
1149 1211
 	 *
1150 1212
 	 * @deprecated
1151 1213
 	 */
1152
-	protected function menuChartDescendants(Individual $individual) {
1214
+	protected function menuChartDescendants(Individual $individual)
1215
+	{
1153 1216
 		$chart = new DescendancyChartModule(WT_ROOT . WT_MODULES_DIR . 'descendancy_chart');
1154 1217
 
1155 1218
 		return $chart->getChartMenu($individual);
@@ -1164,7 +1227,8 @@  discard block
 block discarded – undo
1164 1227
 	 *
1165 1228
 	 * @deprecated
1166 1229
 	 */
1167
-	protected function menuChartFamilyBook(Individual $individual) {
1230
+	protected function menuChartFamilyBook(Individual $individual)
1231
+	{
1168 1232
 		$chart = new FamilyBookChartModule(WT_ROOT . WT_MODULES_DIR . 'family_book_chart');
1169 1233
 
1170 1234
 		return $chart->getChartMenu($individual);
@@ -1181,7 +1245,8 @@  discard block
 block discarded – undo
1181 1245
 	 *
1182 1246
 	 * @deprecated
1183 1247
 	 */
1184
-	protected function menuChartFanChart(Individual $individual) {
1248
+	protected function menuChartFanChart(Individual $individual)
1249
+	{
1185 1250
 		$chart = new FanChartModule(WT_ROOT . WT_MODULES_DIR . 'fan_chart');
1186 1251
 
1187 1252
 		return $chart->getChartMenu($individual);
@@ -1196,7 +1261,8 @@  discard block
 block discarded – undo
1196 1261
 	 *
1197 1262
 	 * @deprecated
1198 1263
 	 */
1199
-	protected function menuChartInteractiveTree(Individual $individual) {
1264
+	protected function menuChartInteractiveTree(Individual $individual)
1265
+	{
1200 1266
 		$chart = new InteractiveTreeModule(WT_ROOT . WT_MODULES_DIR . 'tree');
1201 1267
 
1202 1268
 		return $chart->getChartMenu($individual);
@@ -1211,7 +1277,8 @@  discard block
 block discarded – undo
1211 1277
 	 *
1212 1278
 	 * @deprecated
1213 1279
 	 */
1214
-	protected function menuChartHourglass(Individual $individual) {
1280
+	protected function menuChartHourglass(Individual $individual)
1281
+	{
1215 1282
 		$chart = new HourglassChartModule(WT_ROOT . WT_MODULES_DIR . 'hourglass_chart');
1216 1283
 
1217 1284
 		return $chart->getChartMenu($individual);
@@ -1226,7 +1293,8 @@  discard block
 block discarded – undo
1226 1293
 	 *
1227 1294
 	 * @deprecated
1228 1295
 	 */
1229
-	protected function menuChartLifespan(Individual $individual) {
1296
+	protected function menuChartLifespan(Individual $individual)
1297
+	{
1230 1298
 		$chart = new LifespansChartModule(WT_ROOT . WT_MODULES_DIR . 'lifespans_chart');
1231 1299
 
1232 1300
 		return $chart->getChartMenu($individual);
@@ -1241,7 +1309,8 @@  discard block
 block discarded – undo
1241 1309
 	 *
1242 1310
 	 * @deprecated
1243 1311
 	 */
1244
-	protected function menuChartPedigree(Individual $individual) {
1312
+	protected function menuChartPedigree(Individual $individual)
1313
+	{
1245 1314
 		$chart = new PedigreeChartModule(WT_ROOT . WT_MODULES_DIR . 'pedigree_chart');
1246 1315
 
1247 1316
 		return $chart->getChartMenu($individual);
@@ -1256,7 +1325,8 @@  discard block
 block discarded – undo
1256 1325
 	 *
1257 1326
 	 * @deprecated
1258 1327
 	 */
1259
-	protected function menuChartPedigreeMap(Individual $individual) {
1328
+	protected function menuChartPedigreeMap(Individual $individual)
1329
+	{
1260 1330
 		$chart = new GoogleMapsModule(WT_ROOT . WT_MODULES_DIR . 'googlemap');
1261 1331
 
1262 1332
 		return $chart->getChartMenu($individual);
@@ -1271,7 +1341,8 @@  discard block
 block discarded – undo
1271 1341
 	 *
1272 1342
 	 * @deprecated
1273 1343
 	 */
1274
-	protected function menuChartRelationship(Individual $individual) {
1344
+	protected function menuChartRelationship(Individual $individual)
1345
+	{
1275 1346
 		$chart = new RelationshipsChartModule(WT_ROOT . WT_MODULES_DIR . 'relationships_chart');
1276 1347
 
1277 1348
 		return $chart->getChartMenu($individual);
@@ -1284,7 +1355,8 @@  discard block
 block discarded – undo
1284 1355
 	 *
1285 1356
 	 * @deprecated
1286 1357
 	 */
1287
-	protected function menuChartStatistics() {
1358
+	protected function menuChartStatistics()
1359
+	{
1288 1360
 		$chart = new StatisticsChartModule(WT_ROOT . WT_MODULES_DIR . 'statistics_chart');
1289 1361
 
1290 1362
 		return $chart->getChartMenu(null);
@@ -1299,7 +1371,8 @@  discard block
 block discarded – undo
1299 1371
 	 *
1300 1372
 	 * @deprecated
1301 1373
 	 */
1302
-	protected function menuChartTimeline(Individual $individual) {
1374
+	protected function menuChartTimeline(Individual $individual)
1375
+	{
1303 1376
 		$chart = new TimelineChartModule(WT_ROOT . WT_MODULES_DIR . 'timeline_chart');
1304 1377
 
1305 1378
 		return $chart->getChartMenu($individual);
@@ -1310,7 +1383,8 @@  discard block
 block discarded – undo
1310 1383
 	 *
1311 1384
 	 * @return Menu|null
1312 1385
 	 */
1313
-	protected function menuControlPanel() {
1386
+	protected function menuControlPanel()
1387
+	{
1314 1388
 		if (Auth::isManager($this->tree)) {
1315 1389
 			return new Menu(I18N::translate('Control panel'), 'admin.php', 'menu-admin');
1316 1390
 		} else {
@@ -1323,7 +1397,8 @@  discard block
 block discarded – undo
1323 1397
 	 *
1324 1398
 	 * @return Menu|null
1325 1399
 	 */
1326
-	protected function menuFavorites() {
1400
+	protected function menuFavorites()
1401
+	{
1327 1402
 		global $controller;
1328 1403
 
1329 1404
 		$show_user_favorites = $this->tree && Module::getModuleByName('user_favorites') && Auth::check();
@@ -1381,7 +1456,8 @@  discard block
 block discarded – undo
1381 1456
 	 *
1382 1457
 	 * @return Menu
1383 1458
 	 */
1384
-	protected function menuHomePage() {
1459
+	protected function menuHomePage()
1460
+	{
1385 1461
 		if (count(Tree::getAll()) === 1 || Site::getPreference('ALLOW_CHANGE_GEDCOM') === '0') {
1386 1462
 			return new Menu(I18N::translate('Family tree'), 'index.php?ctype=gedcom&amp;' . $this->tree_url, 'menu-tree');
1387 1463
 		} else {
@@ -1404,7 +1480,8 @@  discard block
 block discarded – undo
1404 1480
 	 *
1405 1481
 	 * @return Menu|null
1406 1482
 	 */
1407
-	protected function menuLanguages() {
1483
+	protected function menuLanguages()
1484
+	{
1408 1485
 		$menu = new Menu(I18N::translate('Language'), '#', 'menu-language');
1409 1486
 
1410 1487
 		foreach (I18N::activeLocales() as $locale) {
@@ -1430,7 +1507,8 @@  discard block
 block discarded – undo
1430 1507
 	 *
1431 1508
 	 * @return Menu
1432 1509
 	 */
1433
-	protected function menuLists($surname) {
1510
+	protected function menuLists($surname)
1511
+	{
1434 1512
 		// Do not show empty lists
1435 1513
 		$row = Database::prepare(
1436 1514
 			"SELECT" .
@@ -1478,7 +1556,8 @@  discard block
 block discarded – undo
1478 1556
 	 *
1479 1557
 	 * @return Menu
1480 1558
 	 */
1481
-	protected function menuListsBranches($surname) {
1559
+	protected function menuListsBranches($surname)
1560
+	{
1482 1561
 		return new Menu(I18N::translate('Branches'), 'branches.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-branches', array('rel' => 'nofollow'));
1483 1562
 	}
1484 1563
 
@@ -1489,7 +1568,8 @@  discard block
 block discarded – undo
1489 1568
 	 *
1490 1569
 	 * @return Menu
1491 1570
 	 */
1492
-	protected function menuListsFamilies($surname) {
1571
+	protected function menuListsFamilies($surname)
1572
+	{
1493 1573
 		return new Menu(I18N::translate('Families'), 'famlist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-fam', array('rel' => 'nofollow'));
1494 1574
 	}
1495 1575
 
@@ -1500,7 +1580,8 @@  discard block
 block discarded – undo
1500 1580
 	 *
1501 1581
 	 * @return Menu
1502 1582
 	 */
1503
-	protected function menuListsIndividuals($surname) {
1583
+	protected function menuListsIndividuals($surname)
1584
+	{
1504 1585
 		return new Menu(I18N::translate('Individuals'), 'indilist.php?ged=' . $this->tree->getNameUrl() . '&amp;surname=' . rawurlencode($surname), 'menu-list-indi');
1505 1586
 	}
1506 1587
 
@@ -1509,7 +1590,8 @@  discard block
 block discarded – undo
1509 1590
 	 *
1510 1591
 	 * @return Menu
1511 1592
 	 */
1512
-	protected function menuListsMedia() {
1593
+	protected function menuListsMedia()
1594
+	{
1513 1595
 		return new Menu(I18N::translate('Media objects'), 'medialist.php?' . $this->tree_url, 'menu-list-obje', array('rel' => 'nofollow'));
1514 1596
 	}
1515 1597
 
@@ -1518,7 +1600,8 @@  discard block
 block discarded – undo
1518 1600
 	 *
1519 1601
 	 * @return Menu
1520 1602
 	 */
1521
-	protected function menuListsNotes() {
1603
+	protected function menuListsNotes()
1604
+	{
1522 1605
 		return new Menu(I18N::translate('Shared notes'), 'notelist.php?' . $this->tree_url, 'menu-list-note', array('rel' => 'nofollow'));
1523 1606
 	}
1524 1607
 
@@ -1527,7 +1610,8 @@  discard block
 block discarded – undo
1527 1610
 	 *
1528 1611
 	 * @return Menu
1529 1612
 	 */
1530
-	protected function menuListsPlaces() {
1613
+	protected function menuListsPlaces()
1614
+	{
1531 1615
 		return new Menu(I18N::translate('Place hierarchy'), 'placelist.php?ged=' . $this->tree->getNameUrl(), 'menu-list-plac', array('rel' => 'nofollow'));
1532 1616
 	}
1533 1617
 
@@ -1536,7 +1620,8 @@  discard block
 block discarded – undo
1536 1620
 	 *
1537 1621
 	 * @return Menu
1538 1622
 	 */
1539
-	protected function menuListsRepositories() {
1623
+	protected function menuListsRepositories()
1624
+	{
1540 1625
 		return new Menu(I18N::translate('Repositories'), 'repolist.php?' . $this->tree_url, 'menu-list-repo', array('rel' => 'nofollow'));
1541 1626
 	}
1542 1627
 
@@ -1545,7 +1630,8 @@  discard block
 block discarded – undo
1545 1630
 	 *
1546 1631
 	 * @return Menu
1547 1632
 	 */
1548
-	protected function menuListsSources() {
1633
+	protected function menuListsSources()
1634
+	{
1549 1635
 		return new Menu(I18N::translate('Sources'), 'sourcelist.php?' . $this->tree_url, 'menu-list-sour', array('rel' => 'nofollow'));
1550 1636
 	}
1551 1637
 
@@ -1554,7 +1640,8 @@  discard block
 block discarded – undo
1554 1640
 	 *
1555 1641
 	 * @return Menu|null
1556 1642
 	 */
1557
-	protected function menuLogin() {
1643
+	protected function menuLogin()
1644
+	{
1558 1645
 		if (Auth::check() || WT_SCRIPT_NAME === 'login.php') {
1559 1646
 			return null;
1560 1647
 		} else {
@@ -1567,7 +1654,8 @@  discard block
 block discarded – undo
1567 1654
 	 *
1568 1655
 	 * @return Menu|null
1569 1656
 	 */
1570
-	protected function menuLogout() {
1657
+	protected function menuLogout()
1658
+	{
1571 1659
 		if (Auth::check()) {
1572 1660
 			return new Menu(I18N::translate('Sign out'), 'logout.php', 'menu-logout');
1573 1661
 		} else {
@@ -1580,7 +1668,8 @@  discard block
 block discarded – undo
1580 1668
 	 *
1581 1669
 	 * @return Menu[]
1582 1670
 	 */
1583
-	protected function menuModules() {
1671
+	protected function menuModules()
1672
+	{
1584 1673
 		$menus = array();
1585 1674
 		foreach (Module::getActiveMenus($this->tree) as $module) {
1586 1675
 			$menus[] = $module->getMenu();
@@ -1594,7 +1683,8 @@  discard block
 block discarded – undo
1594 1683
 	 *
1595 1684
 	 * @return Menu|null
1596 1685
 	 */
1597
-	protected function menuMyAccount() {
1686
+	protected function menuMyAccount()
1687
+	{
1598 1688
 		if (Auth::check()) {
1599 1689
 			return new Menu(I18N::translate('My account'), 'edituser.php');
1600 1690
 		} else {
@@ -1607,7 +1697,8 @@  discard block
 block discarded – undo
1607 1697
 	 *
1608 1698
 	 * @return Menu|null
1609 1699
 	 */
1610
-	protected function menuMyIndividualRecord() {
1700
+	protected function menuMyIndividualRecord()
1701
+	{
1611 1702
 		$gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1612 1703
 
1613 1704
 		if ($gedcomid) {
@@ -1622,7 +1713,8 @@  discard block
 block discarded – undo
1622 1713
 	 *
1623 1714
 	 * @return Menu
1624 1715
 	 */
1625
-	protected function menuMyPage() {
1716
+	protected function menuMyPage()
1717
+	{
1626 1718
 		return new Menu(I18N::translate('My page'), 'index.php?ctype=user&amp;' . $this->tree_url, 'menu-mypage');
1627 1719
 	}
1628 1720
 
@@ -1631,7 +1723,8 @@  discard block
 block discarded – undo
1631 1723
 	 *
1632 1724
 	 * @return Menu|null
1633 1725
 	 */
1634
-	protected function menuMyPages() {
1726
+	protected function menuMyPages()
1727
+	{
1635 1728
 		if (Auth::id()) {
1636 1729
 			return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', array(), array_filter(array(
1637 1730
 				$this->menuMyPage(),
@@ -1651,7 +1744,8 @@  discard block
 block discarded – undo
1651 1744
 	 *
1652 1745
 	 * @return Menu|null
1653 1746
 	 */
1654
-	protected function menuMyPedigree() {
1747
+	protected function menuMyPedigree()
1748
+	{
1655 1749
 		$gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
1656 1750
 
1657 1751
 		if ($gedcomid && Module::isActiveChart($this->tree, 'pedigree_chart')) {
@@ -1673,7 +1767,8 @@  discard block
 block discarded – undo
1673 1767
 	 *
1674 1768
 	 * @return Menu|null
1675 1769
 	 */
1676
-	protected function menuPendingChanges() {
1770
+	protected function menuPendingChanges()
1771
+	{
1677 1772
 		if ($this->pendingChangesExist()) {
1678 1773
 			$menu = new Menu(I18N::translate('Pending changes'), '#', 'menu-pending', array('onclick' => 'window.open("edit_changes.php", "_blank", chan_window_specs); return false;'));
1679 1774
 
@@ -1688,7 +1783,8 @@  discard block
 block discarded – undo
1688 1783
 	 *
1689 1784
 	 * @return Menu|null
1690 1785
 	 */
1691
-	protected function menuReports() {
1786
+	protected function menuReports()
1787
+	{
1692 1788
 		$submenus = array();
1693 1789
 		foreach (Module::getActiveReports($this->tree) as $report) {
1694 1790
 			$submenus[] = $report->getReportMenu();
@@ -1706,7 +1802,8 @@  discard block
 block discarded – undo
1706 1802
 	 *
1707 1803
 	 * @return Menu
1708 1804
 	 */
1709
-	protected function menuSearch() {
1805
+	protected function menuSearch()
1806
+	{
1710 1807
 		return new Menu(I18N::translate('Search'), '#', 'menu-search', array('rel' => 'nofollow'), array_filter(array(
1711 1808
 			$this->menuSearchGeneral(),
1712 1809
 			$this->menuSearchPhonetic(),
@@ -1720,7 +1817,8 @@  discard block
 block discarded – undo
1720 1817
 	 *
1721 1818
 	 * @return Menu
1722 1819
 	 */
1723
-	protected function menuSearchGeneral() {
1820
+	protected function menuSearchGeneral()
1821
+	{
1724 1822
 		return new Menu(I18N::translate('General search'), 'search.php?' . $this->tree_url, 'menu-search-general', array('rel' => 'nofollow'));
1725 1823
 	}
1726 1824
 
@@ -1729,7 +1827,8 @@  discard block
 block discarded – undo
1729 1827
 	 *
1730 1828
 	 * @return Menu
1731 1829
 	 */
1732
-	protected function menuSearchPhonetic() {
1830
+	protected function menuSearchPhonetic()
1831
+	{
1733 1832
 		return new Menu(/* I18N: search using “sounds like”, rather than exact spelling */ I18N::translate('Phonetic search'), 'search.php?' . $this->tree_url . '&amp;action=soundex', 'menu-search-soundex', array('rel' => 'nofollow'));
1734 1833
 	}
1735 1834
 
@@ -1738,7 +1837,8 @@  discard block
 block discarded – undo
1738 1837
 	 *
1739 1838
 	 * @return Menu
1740 1839
 	 */
1741
-	protected function menuSearchAdvanced() {
1840
+	protected function menuSearchAdvanced()
1841
+	{
1742 1842
 		return new Menu(I18N::translate('Advanced search'), 'search_advanced.php?' . $this->tree_url, 'menu-search-advanced', array('rel' => 'nofollow'));
1743 1843
 	}
1744 1844
 
@@ -1747,7 +1847,8 @@  discard block
 block discarded – undo
1747 1847
 	 *
1748 1848
 	 * @return Menu
1749 1849
 	 */
1750
-	protected function menuSearchAndReplace() {
1850
+	protected function menuSearchAndReplace()
1851
+	{
1751 1852
 		if (Auth::isEditor($this->tree)) {
1752 1853
 			return new Menu(I18N::translate('Search and replace'), 'search.php?' . $this->tree_url . '&amp;action=replace', 'menu-search-replace');
1753 1854
 		} else {
@@ -1760,7 +1861,8 @@  discard block
 block discarded – undo
1760 1861
 	 *
1761 1862
 	 * @return Menu|null
1762 1863
 	 */
1763
-	public function menuThemes() {
1864
+	public function menuThemes()
1865
+	{
1764 1866
 		if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
1765 1867
 			$submenus = array();
1766 1868
 			foreach (Theme::installedThemes() as $theme) {
@@ -1788,7 +1890,8 @@  discard block
 block discarded – undo
1788 1890
 	 *
1789 1891
 	 * @return string
1790 1892
 	 */
1791
-	protected function metaCharset() {
1893
+	protected function metaCharset()
1894
+	{
1792 1895
 		return '<meta charset="UTF-8">';
1793 1896
 	}
1794 1897
 
@@ -1799,7 +1902,8 @@  discard block
 block discarded – undo
1799 1902
 	 *
1800 1903
 	 * @return string
1801 1904
 	 */
1802
-	protected function metaDescription($description) {
1905
+	protected function metaDescription($description)
1906
+	{
1803 1907
 		if ($description) {
1804 1908
 			return '<meta name="description" content="' . $description . '">';
1805 1909
 		} else {
@@ -1814,7 +1918,8 @@  discard block
 block discarded – undo
1814 1918
 	 *
1815 1919
 	 * @return string
1816 1920
 	 */
1817
-	protected function metaGenerator($generator) {
1921
+	protected function metaGenerator($generator)
1922
+	{
1818 1923
 		if ($generator) {
1819 1924
 			return '<meta name="generator" content="' . $generator . '">';
1820 1925
 		} else {
@@ -1829,7 +1934,8 @@  discard block
 block discarded – undo
1829 1934
 	 *
1830 1935
 	 * @return string
1831 1936
 	 */
1832
-	protected function metaRobots($robots) {
1937
+	protected function metaRobots($robots)
1938
+	{
1833 1939
 		if ($robots) {
1834 1940
 			return '<meta name="robots" content="' . $robots . '">';
1835 1941
 		} else {
@@ -1842,7 +1948,8 @@  discard block
 block discarded – undo
1842 1948
 	 *
1843 1949
 	 * @return string
1844 1950
 	 */
1845
-	protected function metaUaCompatible() {
1951
+	protected function metaUaCompatible()
1952
+	{
1846 1953
 		return '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
1847 1954
 	}
1848 1955
 
@@ -1851,7 +1958,8 @@  discard block
 block discarded – undo
1851 1958
 	 *
1852 1959
 	 * @return string
1853 1960
 	 */
1854
-	protected function metaViewport() {
1961
+	protected function metaViewport()
1962
+	{
1855 1963
 		return '<meta name="viewport" content="width=device-width, initial-scale=1">';
1856 1964
 	}
1857 1965
 
@@ -1862,7 +1970,8 @@  discard block
 block discarded – undo
1862 1970
 	 *
1863 1971
 	 * @return int Number of views, or zero for pages that aren't logged.
1864 1972
 	 */
1865
-	protected function pageViews(PageController $controller) {
1973
+	protected function pageViews(PageController $controller)
1974
+	{
1866 1975
 		if ($this->tree && $this->tree->getPreference('SHOW_COUNTER')) {
1867 1976
 			if (isset($controller->record) && $controller->record instanceof GedcomRecord) {
1868 1977
 				return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->record->getXref());
@@ -1887,7 +1996,8 @@  discard block
 block discarded – undo
1887 1996
 	 *
1888 1997
 	 * @return string|int|float
1889 1998
 	 */
1890
-	public function parameter($parameter_name) {
1999
+	public function parameter($parameter_name)
2000
+	{
1891 2001
 		$parameters = array(
1892 2002
 			'chart-background-f'             => 'dddddd',
1893 2003
 			'chart-background-m'             => 'cccccc',
@@ -1936,7 +2046,8 @@  discard block
 block discarded – undo
1936 2046
 	 *
1937 2047
 	 * @return bool
1938 2048
 	 */
1939
-	protected function pendingChangesExist() {
2049
+	protected function pendingChangesExist()
2050
+	{
1940 2051
 		return $this->tree && $this->tree->hasPendingEdit() && Auth::isModerator($this->tree);
1941 2052
 	}
1942 2053
 
@@ -1945,7 +2056,8 @@  discard block
 block discarded – undo
1945 2056
 	 *
1946 2057
 	 * @return string
1947 2058
 	 */
1948
-	protected function pendingChangesLink() {
2059
+	protected function pendingChangesLink()
2060
+	{
1949 2061
 		return
1950 2062
 			'<a href="#" onclick="window.open(\'edit_changes.php\', \'_blank\', chan_window_specs); return false;">' .
1951 2063
 			$this->pendingChangesLinkText() .
@@ -1957,7 +2069,8 @@  discard block
 block discarded – undo
1957 2069
 	 *
1958 2070
 	 * @return string
1959 2071
 	 */
1960
-	protected function pendingChangesLinkText() {
2072
+	protected function pendingChangesLinkText()
2073
+	{
1961 2074
 		return I18N::translate('There are pending changes for you to moderate.');
1962 2075
 	}
1963 2076
 
@@ -1966,7 +2079,8 @@  discard block
 block discarded – undo
1966 2079
 	 *
1967 2080
 	 * @return Menu[]
1968 2081
 	 */
1969
-	protected function primaryMenu() {
2082
+	protected function primaryMenu()
2083
+	{
1970 2084
 		global $controller;
1971 2085
 
1972 2086
 		if ($this->tree) {
@@ -1993,7 +2107,8 @@  discard block
 block discarded – undo
1993 2107
 	 *
1994 2108
 	 * @return string
1995 2109
 	 */
1996
-	protected function primaryMenuContainer(array $menus) {
2110
+	protected function primaryMenuContainer(array $menus)
2111
+	{
1997 2112
 		return '<nav><ul class="primary-menu">' . $this->primaryMenuContent($menus) . '</ul></nav>';
1998 2113
 	}
1999 2114
 
@@ -2004,7 +2119,8 @@  discard block
 block discarded – undo
2004 2119
 	 *
2005 2120
 	 * @return string
2006 2121
 	 */
2007
-	protected function primaryMenuContent(array $menus) {
2122
+	protected function primaryMenuContent(array $menus)
2123
+	{
2008 2124
 		return implode('', array_map(function (Menu $menu) {
2009 2125
 			return $menu->getMenuAsList();
2010 2126
 		}, $menus));
@@ -2015,7 +2131,8 @@  discard block
 block discarded – undo
2015 2131
 	 *
2016 2132
 	 * @return Menu[]
2017 2133
 	 */
2018
-	protected function secondaryMenu() {
2134
+	protected function secondaryMenu()
2135
+	{
2019 2136
 		return array_filter(array(
2020 2137
 			$this->menuPendingChanges(),
2021 2138
 			$this->menuMyPages(),
@@ -2034,7 +2151,8 @@  discard block
 block discarded – undo
2034 2151
 	 *
2035 2152
 	 * @return string
2036 2153
 	 */
2037
-	protected function secondaryMenuContainer(array $menus) {
2154
+	protected function secondaryMenuContainer(array $menus)
2155
+	{
2038 2156
 		return '<ul class="nav nav-pills secondary-menu">' . $this->secondaryMenuContent($menus) . '</ul>';
2039 2157
 	}
2040 2158
 
@@ -2045,7 +2163,8 @@  discard block
 block discarded – undo
2045 2163
 	 *
2046 2164
 	 * @return string
2047 2165
 	 */
2048
-	protected function secondaryMenuContent(array $menus) {
2166
+	protected function secondaryMenuContent(array $menus)
2167
+	{
2049 2168
 		return implode('', array_map(function (Menu $menu) {
2050 2169
 			return $menu->getMenuAsList();
2051 2170
 		}, $menus));
@@ -2054,7 +2173,8 @@  discard block
 block discarded – undo
2054 2173
 	/**
2055 2174
 	 * Send any HTTP headers.
2056 2175
 	 */
2057
-	public function sendHeaders() {
2176
+	public function sendHeaders()
2177
+	{
2058 2178
 		header('Content-Type: text/html; charset=UTF-8');
2059 2179
 	}
2060 2180
 
@@ -2063,7 +2183,8 @@  discard block
 block discarded – undo
2063 2183
 	 *
2064 2184
 	 * @return string[]
2065 2185
 	 */
2066
-	protected function stylesheets() {
2186
+	protected function stylesheets()
2187
+	{
2067 2188
 		$stylesheets = array(
2068 2189
 			WT_BOOTSTRAP_CSS_URL,
2069 2190
 			WT_FONT_AWESOME_CSS_URL,
@@ -2084,7 +2205,8 @@  discard block
 block discarded – undo
2084 2205
 	 *
2085 2206
 	 * @return string
2086 2207
 	 */
2087
-	protected function title($title) {
2208
+	protected function title($title)
2209
+	{
2088 2210
 		return '<title>' . Filter::escapeHtml($title) . '</title>';
2089 2211
 	}
2090 2212
 }
Please login to merge, or discard this patch.
app/Theme/WebtreesTheme.php 3 patches
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -22,114 +22,114 @@
 block discarded – undo
22 22
  * The webtrees (default) theme.
23 23
  */
24 24
 class WebtreesTheme extends AbstractTheme implements ThemeInterface {
25
-	/**
26
-	 * Where are our CSS, JS and other assets?
27
-	 *
28
-	 * @return string A relative path, such as "themes/foo/"
29
-	 */
30
-	public function assetUrl() {
31
-		return 'themes/webtrees/css-1.7.8/';
32
-	}
25
+    /**
26
+     * Where are our CSS, JS and other assets?
27
+     *
28
+     * @return string A relative path, such as "themes/foo/"
29
+     */
30
+    public function assetUrl() {
31
+        return 'themes/webtrees/css-1.7.8/';
32
+    }
33 33
 
34
-	/**
35
-	 * Add markup to a flash message.
36
-	 *
37
-	 * @param \stdClass $message
38
-	 *
39
-	 * @return string
40
-	 */
41
-	protected function flashMessageContainer(\stdClass $message) {
42
-		// This theme uses jQueryUI markup.
43
-		switch ($message->status) {
44
-		case 'danger':
45
-			return '<p class="ui-state-error">' . $message->text . '</p>';
46
-		default:
47
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
48
-		}
49
-	}
34
+    /**
35
+     * Add markup to a flash message.
36
+     *
37
+     * @param \stdClass $message
38
+     *
39
+     * @return string
40
+     */
41
+    protected function flashMessageContainer(\stdClass $message) {
42
+        // This theme uses jQueryUI markup.
43
+        switch ($message->status) {
44
+        case 'danger':
45
+            return '<p class="ui-state-error">' . $message->text . '</p>';
46
+        default:
47
+            return '<p class="ui-state-highlight">' . $message->text . '</p>';
48
+        }
49
+    }
50 50
 
51
-	/**
52
-	 * Create a search field and submit button for the quick search form in the header.
53
-	 *
54
-	 * @return string
55
-	 */
56
-	protected function formQuickSearchFields() {
57
-		return
58
-			'<input type="search" name="query" size="25" placeholder="' . I18N::translate('Search') . '">' .
59
-			'<input type="image" class="image" src="' . $this->assetUrl() . 'images/search.png" alt="' . I18N::translate('Search') . '" title="' . I18N::translate('Search') . '">';
60
-	}
51
+    /**
52
+     * Create a search field and submit button for the quick search form in the header.
53
+     *
54
+     * @return string
55
+     */
56
+    protected function formQuickSearchFields() {
57
+        return
58
+            '<input type="search" name="query" size="25" placeholder="' . I18N::translate('Search') . '">' .
59
+            '<input type="image" class="image" src="' . $this->assetUrl() . 'images/search.png" alt="' . I18N::translate('Search') . '" title="' . I18N::translate('Search') . '">';
60
+    }
61 61
 
62
-	/**
63
-	 * Allow themes to add extra scripts to the page footer.
64
-	 *
65
-	 * @return string
66
-	 */
67
-	public function hookFooterExtraJavascript() {
68
-		return
69
-			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
70
-			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
71
-			'<script>' .
72
-			'activate_colorbox();' .
73
-			'jQuery.extend(jQuery.colorbox.settings, {' .
74
-			' width:"85%",' .
75
-			' height:"85%",' .
76
-			' transition:"none",' .
77
-			' slideshowStart:"' . I18N::translate('Play') . '",' .
78
-			' slideshowStop:"' . I18N::translate('Stop') . '",' .
79
-			' title: function() { return jQuery(this).data("title"); }' .
80
-			'});' .
81
-			'</script>';
82
-	}
62
+    /**
63
+     * Allow themes to add extra scripts to the page footer.
64
+     *
65
+     * @return string
66
+     */
67
+    public function hookFooterExtraJavascript() {
68
+        return
69
+            '<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
70
+            '<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
71
+            '<script>' .
72
+            'activate_colorbox();' .
73
+            'jQuery.extend(jQuery.colorbox.settings, {' .
74
+            ' width:"85%",' .
75
+            ' height:"85%",' .
76
+            ' transition:"none",' .
77
+            ' slideshowStart:"' . I18N::translate('Play') . '",' .
78
+            ' slideshowStop:"' . I18N::translate('Stop') . '",' .
79
+            ' title: function() { return jQuery(this).data("title"); }' .
80
+            '});' .
81
+            '</script>';
82
+    }
83 83
 
84
-	/**
85
-	 * Misecellaneous dimensions, fonts, styles, etc.
86
-	 *
87
-	 * @param string $parameter_name
88
-	 *
89
-	 * @return string|int|float
90
-	 */
91
-	public function parameter($parameter_name) {
92
-		$parameters = array(
93
-			'chart-background-f'             => 'e9daf1',
94
-			'chart-background-m'             => 'b1cff0',
95
-			'distribution-chart-high-values' => '84beff',
96
-			'distribution-chart-low-values'  => 'c3dfff',
97
-		);
84
+    /**
85
+     * Misecellaneous dimensions, fonts, styles, etc.
86
+     *
87
+     * @param string $parameter_name
88
+     *
89
+     * @return string|int|float
90
+     */
91
+    public function parameter($parameter_name) {
92
+        $parameters = array(
93
+            'chart-background-f'             => 'e9daf1',
94
+            'chart-background-m'             => 'b1cff0',
95
+            'distribution-chart-high-values' => '84beff',
96
+            'distribution-chart-low-values'  => 'c3dfff',
97
+        );
98 98
 
99
-		if (array_key_exists($parameter_name, $parameters)) {
100
-			return $parameters[$parameter_name];
101
-		} else {
102
-			return parent::parameter($parameter_name);
103
-		}
104
-	}
99
+        if (array_key_exists($parameter_name, $parameters)) {
100
+            return $parameters[$parameter_name];
101
+        } else {
102
+            return parent::parameter($parameter_name);
103
+        }
104
+    }
105 105
 
106
-	/**
107
-	 * A list of CSS files to include for this page.
108
-	 *
109
-	 * @return string[]
110
-	 */
111
-	protected function stylesheets() {
112
-		return array(
113
-			'themes/webtrees/jquery-ui-1.11.2/jquery-ui.css',
114
-			$this->assetUrl() . 'style.css',
115
-		);
116
-	}
106
+    /**
107
+     * A list of CSS files to include for this page.
108
+     *
109
+     * @return string[]
110
+     */
111
+    protected function stylesheets() {
112
+        return array(
113
+            'themes/webtrees/jquery-ui-1.11.2/jquery-ui.css',
114
+            $this->assetUrl() . 'style.css',
115
+        );
116
+    }
117 117
 
118
-	/**
119
-	 * A fixed string to identify this theme, in settings, etc.
120
-	 *
121
-	 * @return string
122
-	 */
123
-	public function themeId() {
124
-		return 'webtrees';
125
-	}
118
+    /**
119
+     * A fixed string to identify this theme, in settings, etc.
120
+     *
121
+     * @return string
122
+     */
123
+    public function themeId() {
124
+        return 'webtrees';
125
+    }
126 126
 
127
-	/**
128
-	 * What is this theme called?
129
-	 *
130
-	 * @return string
131
-	 */
132
-	public function themeName() {
133
-		return I18N::translate('webtrees');
134
-	}
127
+    /**
128
+     * What is this theme called?
129
+     *
130
+     * @return string
131
+     */
132
+    public function themeName() {
133
+        return I18N::translate('webtrees');
134
+    }
135 135
 }
Please login to merge, or discard this patch.
Braces   +18 added lines, -9 removed lines patch added patch discarded remove patch
@@ -21,13 +21,15 @@  discard block
 block discarded – undo
21 21
 /**
22 22
  * The webtrees (default) theme.
23 23
  */
24
-class WebtreesTheme extends AbstractTheme implements ThemeInterface {
24
+class WebtreesTheme extends AbstractTheme implements ThemeInterface
25
+{
25 26
 	/**
26 27
 	 * Where are our CSS, JS and other assets?
27 28
 	 *
28 29
 	 * @return string A relative path, such as "themes/foo/"
29 30
 	 */
30
-	public function assetUrl() {
31
+	public function assetUrl()
32
+	{
31 33
 		return 'themes/webtrees/css-1.7.8/';
32 34
 	}
33 35
 
@@ -38,7 +40,8 @@  discard block
 block discarded – undo
38 40
 	 *
39 41
 	 * @return string
40 42
 	 */
41
-	protected function flashMessageContainer(\stdClass $message) {
43
+	protected function flashMessageContainer(\stdClass $message)
44
+	{
42 45
 		// This theme uses jQueryUI markup.
43 46
 		switch ($message->status) {
44 47
 		case 'danger':
@@ -53,7 +56,8 @@  discard block
 block discarded – undo
53 56
 	 *
54 57
 	 * @return string
55 58
 	 */
56
-	protected function formQuickSearchFields() {
59
+	protected function formQuickSearchFields()
60
+	{
57 61
 		return
58 62
 			'<input type="search" name="query" size="25" placeholder="' . I18N::translate('Search') . '">' .
59 63
 			'<input type="image" class="image" src="' . $this->assetUrl() . 'images/search.png" alt="' . I18N::translate('Search') . '" title="' . I18N::translate('Search') . '">';
@@ -64,7 +68,8 @@  discard block
 block discarded – undo
64 68
 	 *
65 69
 	 * @return string
66 70
 	 */
67
-	public function hookFooterExtraJavascript() {
71
+	public function hookFooterExtraJavascript()
72
+	{
68 73
 		return
69 74
 			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
70 75
 			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
@@ -88,7 +93,8 @@  discard block
 block discarded – undo
88 93
 	 *
89 94
 	 * @return string|int|float
90 95
 	 */
91
-	public function parameter($parameter_name) {
96
+	public function parameter($parameter_name)
97
+	{
92 98
 		$parameters = array(
93 99
 			'chart-background-f'             => 'e9daf1',
94 100
 			'chart-background-m'             => 'b1cff0',
@@ -108,7 +114,8 @@  discard block
 block discarded – undo
108 114
 	 *
109 115
 	 * @return string[]
110 116
 	 */
111
-	protected function stylesheets() {
117
+	protected function stylesheets()
118
+	{
112 119
 		return array(
113 120
 			'themes/webtrees/jquery-ui-1.11.2/jquery-ui.css',
114 121
 			$this->assetUrl() . 'style.css',
@@ -120,7 +127,8 @@  discard block
 block discarded – undo
120 127
 	 *
121 128
 	 * @return string
122 129
 	 */
123
-	public function themeId() {
130
+	public function themeId()
131
+	{
124 132
 		return 'webtrees';
125 133
 	}
126 134
 
@@ -129,7 +137,8 @@  discard block
 block discarded – undo
129 137
 	 *
130 138
 	 * @return string
131 139
 	 */
132
-	public function themeName() {
140
+	public function themeName()
141
+	{
133 142
 		return I18N::translate('webtrees');
134 143
 	}
135 144
 }
Please login to merge, or discard this patch.
Switch Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -42,10 +42,10 @@
 block discarded – undo
42 42
 	protected function flashMessageContainer(\stdClass $message) {
43 43
 		// This theme uses jQueryUI markup.
44 44
 		switch ($message->status) {
45
-		case 'danger':
46
-			return '<p class="ui-state-error">' . $message->text . '</p>';
47
-		default:
48
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
45
+		    case 'danger':
46
+			    return '<p class="ui-state-error">' . $message->text . '</p>';
47
+		    default:
48
+			    return '<p class="ui-state-highlight">' . $message->text . '</p>';
49 49
 		}
50 50
 	}
51 51
 
Please login to merge, or discard this patch.
app/Theme/AdministrationTheme.php 2 patches
Indentation   +258 added lines, -258 removed lines patch added patch discarded remove patch
@@ -24,283 +24,283 @@
 block discarded – undo
24 24
  * The theme for the control panel.
25 25
  */
26 26
 class AdministrationTheme extends AbstractTheme implements ThemeInterface {
27
-	/**
28
-	 * A list of CSS files to include for this page.
29
-	 *
30
-	 * @return string[]
31
-	 */
32
-	protected function stylesheets() {
33
-		$stylesheets   = parent::stylesheets();
34
-		$stylesheets[] = WT_DATATABLES_BOOTSTRAP_CSS_URL;
35
-		$stylesheets[] = WT_BOOTSTRAP_DATETIMEPICKER_CSS_URL;
36
-		$stylesheets[] = $this->assetUrl() . 'style.css';
27
+    /**
28
+     * A list of CSS files to include for this page.
29
+     *
30
+     * @return string[]
31
+     */
32
+    protected function stylesheets() {
33
+        $stylesheets   = parent::stylesheets();
34
+        $stylesheets[] = WT_DATATABLES_BOOTSTRAP_CSS_URL;
35
+        $stylesheets[] = WT_BOOTSTRAP_DATETIMEPICKER_CSS_URL;
36
+        $stylesheets[] = $this->assetUrl() . 'style.css';
37 37
 
38
-		return $stylesheets;
39
-	}
38
+        return $stylesheets;
39
+    }
40 40
 
41
-	/**
42
-	 * Where are our CSS, JS and other assets?
43
-	 *
44
-	 * @return string A relative path, such as "themes/foo/"
45
-	 */
46
-	public function assetUrl() {
47
-		return 'themes/_administration/css-1.7.5/';
48
-	}
41
+    /**
42
+     * Where are our CSS, JS and other assets?
43
+     *
44
+     * @return string A relative path, such as "themes/foo/"
45
+     */
46
+    public function assetUrl() {
47
+        return 'themes/_administration/css-1.7.5/';
48
+    }
49 49
 
50
-	/**
51
-	 * HTML link to a "favorites icon".
52
-	 *
53
-	 * @return string
54
-	 */
55
-	protected function favicon() {
56
-		return '<link rel="icon" href="favicon.ico" type="image/x-icon">';
57
-	}
58
-	/**
59
-	 * Create the contents of the <footer> tag.
60
-	 *
61
-	 * @return string
62
-	 */
63
-	protected function footerContent() {
64
-		return '';
65
-	}
50
+    /**
51
+     * HTML link to a "favorites icon".
52
+     *
53
+     * @return string
54
+     */
55
+    protected function favicon() {
56
+        return '<link rel="icon" href="favicon.ico" type="image/x-icon">';
57
+    }
58
+    /**
59
+     * Create the contents of the <footer> tag.
60
+     *
61
+     * @return string
62
+     */
63
+    protected function footerContent() {
64
+        return '';
65
+    }
66 66
 
67
-	/**
68
-	 * Create the contents of the <header> tag.
69
-	 *
70
-	 * @return string
71
-	 */
72
-	protected function headerContent() {
73
-		return
74
-			$this->accessibilityLinks() .
75
-			$this->secondaryMenuContainer($this->secondaryMenu());
76
-	}
67
+    /**
68
+     * Create the contents of the <header> tag.
69
+     *
70
+     * @return string
71
+     */
72
+    protected function headerContent() {
73
+        return
74
+            $this->accessibilityLinks() .
75
+            $this->secondaryMenuContainer($this->secondaryMenu());
76
+    }
77 77
 
78
-	/**
79
-	 * Allow themes to add extra scripts to the page footer.
80
-	 *
81
-	 * @return string
82
-	 */
83
-	public function hookFooterExtraJavascript() {
84
-		return
85
-			'<script src="' . WT_BOOTSTRAP_JS_URL . '"></script>';
86
-	}
78
+    /**
79
+     * Allow themes to add extra scripts to the page footer.
80
+     *
81
+     * @return string
82
+     */
83
+    public function hookFooterExtraJavascript() {
84
+        return
85
+            '<script src="' . WT_BOOTSTRAP_JS_URL . '"></script>';
86
+    }
87 87
 
88
-	/**
89
-	 * Site administration functions.
90
-	 *
91
-	 * @return Menu
92
-	 */
93
-	protected function menuAdminSite() {
94
-		return new Menu(/* I18N: Menu entry*/ I18N::translate('Website'), '#', '', array(), array(
95
-			new Menu(/* I18N: Menu entry */ I18N::translate('Website preferences'), 'admin_site_config.php?action=site'),
96
-			new Menu(/* I18N: Menu entry */ I18N::translate('Sending email'), 'admin_site_config.php?action=email'),
97
-			new Menu(/* I18N: Menu entry */ I18N::translate('Sign-in and registration'), 'admin_site_config.php?action=login'),
98
-			new Menu(/* I18N: Menu entry */ I18N::translate('Languages'), 'admin_site_config.php?action=languages'),
99
-			new Menu(/* I18N: Menu entry */ I18N::translate('Tracking and analytics'), 'admin_site_config.php?action=tracking'),
100
-			new Menu(/* I18N: Menu entry */ I18N::translate('Website logs'), 'admin_site_logs.php'),
101
-			new Menu(/* I18N: Menu entry */ I18N::translate('Website access rules'), 'admin_site_access.php'),
102
-			new Menu(/* I18N: Menu entry */ I18N::translate('Clean up data folder'), 'admin_site_clean.php'),
103
-			new Menu(/* I18N: Menu entry */ I18N::translate('Server information'), 'admin_site_info.php'),
104
-			new Menu(/* I18N: Menu entry */ I18N::translate('README documentation'), 'admin_site_readme.php'),
105
-		));
106
-	}
88
+    /**
89
+     * Site administration functions.
90
+     *
91
+     * @return Menu
92
+     */
93
+    protected function menuAdminSite() {
94
+        return new Menu(/* I18N: Menu entry*/ I18N::translate('Website'), '#', '', array(), array(
95
+            new Menu(/* I18N: Menu entry */ I18N::translate('Website preferences'), 'admin_site_config.php?action=site'),
96
+            new Menu(/* I18N: Menu entry */ I18N::translate('Sending email'), 'admin_site_config.php?action=email'),
97
+            new Menu(/* I18N: Menu entry */ I18N::translate('Sign-in and registration'), 'admin_site_config.php?action=login'),
98
+            new Menu(/* I18N: Menu entry */ I18N::translate('Languages'), 'admin_site_config.php?action=languages'),
99
+            new Menu(/* I18N: Menu entry */ I18N::translate('Tracking and analytics'), 'admin_site_config.php?action=tracking'),
100
+            new Menu(/* I18N: Menu entry */ I18N::translate('Website logs'), 'admin_site_logs.php'),
101
+            new Menu(/* I18N: Menu entry */ I18N::translate('Website access rules'), 'admin_site_access.php'),
102
+            new Menu(/* I18N: Menu entry */ I18N::translate('Clean up data folder'), 'admin_site_clean.php'),
103
+            new Menu(/* I18N: Menu entry */ I18N::translate('Server information'), 'admin_site_info.php'),
104
+            new Menu(/* I18N: Menu entry */ I18N::translate('README documentation'), 'admin_site_readme.php'),
105
+        ));
106
+    }
107 107
 
108
-	/**
109
-	 * Tree administration menu.
110
-	 *
111
-	 * @return Menu
112
-	 */
113
-	protected function menuAdminTrees() {
114
-		return new Menu(/* I18N: Menu entry */ I18N::translate('Family trees'), '#', '', array(), array_filter(array(
115
-			$this->menuAdminTreesManage(),
116
-			$this->menuAdminTreesSetDefault(),
117
-			$this->menuAdminTreesMerge(),
118
-		)));
119
-	}
108
+    /**
109
+     * Tree administration menu.
110
+     *
111
+     * @return Menu
112
+     */
113
+    protected function menuAdminTrees() {
114
+        return new Menu(/* I18N: Menu entry */ I18N::translate('Family trees'), '#', '', array(), array_filter(array(
115
+            $this->menuAdminTreesManage(),
116
+            $this->menuAdminTreesSetDefault(),
117
+            $this->menuAdminTreesMerge(),
118
+        )));
119
+    }
120 120
 
121
-	/**
122
-	 * Manage trees menu.
123
-	 *
124
-	 * @return Menu
125
-	 */
126
-	protected function menuAdminTreesManage() {
127
-		return new Menu(/* I18N: Menu entry */ I18N::translate('Manage family trees'), 'admin_trees_manage.php');
128
-	}
121
+    /**
122
+     * Manage trees menu.
123
+     *
124
+     * @return Menu
125
+     */
126
+    protected function menuAdminTreesManage() {
127
+        return new Menu(/* I18N: Menu entry */ I18N::translate('Manage family trees'), 'admin_trees_manage.php');
128
+    }
129 129
 
130
-	/**
131
-	 * Merge trees menu.
132
-	 *
133
-	 * @return Menu|null
134
-	 */
135
-	protected function menuAdminTreesMerge() {
136
-		if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
137
-			return new Menu(/* I18N: Menu entry */ I18N::translate('Merge family trees'), 'admin_trees_merge.php');
138
-		} else {
139
-			return null;
140
-		}
141
-	}
130
+    /**
131
+     * Merge trees menu.
132
+     *
133
+     * @return Menu|null
134
+     */
135
+    protected function menuAdminTreesMerge() {
136
+        if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
137
+            return new Menu(/* I18N: Menu entry */ I18N::translate('Merge family trees'), 'admin_trees_merge.php');
138
+        } else {
139
+            return null;
140
+        }
141
+    }
142 142
 
143
-	/**
144
-	 * Set default blocks menu.
145
-	 *
146
-	 * @return Menu|null
147
-	 */
148
-	protected function menuAdminTreesSetDefault() {
149
-		if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
150
-			return new Menu(/* I18N: Menu entry */ I18N::translate('Set the default blocks for new family trees'), 'index_edit.php?gedcom_id=-1');
151
-		} else {
152
-			return null;
153
-		}
154
-	}
143
+    /**
144
+     * Set default blocks menu.
145
+     *
146
+     * @return Menu|null
147
+     */
148
+    protected function menuAdminTreesSetDefault() {
149
+        if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
150
+            return new Menu(/* I18N: Menu entry */ I18N::translate('Set the default blocks for new family trees'), 'index_edit.php?gedcom_id=-1');
151
+        } else {
152
+            return null;
153
+        }
154
+    }
155 155
 
156
-	/**
157
-	 * User administration menu.
158
-	 *
159
-	 * @return Menu
160
-	 */
161
-	protected function menuAdminUsers() {
162
-		return new Menu(/* I18N: Menu entry */ I18N::translate('Users'), '#', '', array(), array(
163
-			new Menu(/* I18N: Menu entry */ I18N::translate('User administration'), 'admin_users.php'),
164
-			new Menu(/* I18N: Menu entry */ I18N::translate('Add a user'), 'admin_users.php?action=edit'),
165
-			new Menu(/* I18N: Menu entry */ I18N::translate('Send broadcast messages'), 'admin_users_bulk.php'),
166
-			new Menu(/* I18N: Menu entry */ I18N::translate('Delete inactive users'), 'admin_users.php?action=cleanup'),
167
-			new Menu(/* I18N: Menu entry */ I18N::translate('Set the default blocks for new users'), 'index_edit.php?user_id=-1'),
168
-		));
169
-	}
156
+    /**
157
+     * User administration menu.
158
+     *
159
+     * @return Menu
160
+     */
161
+    protected function menuAdminUsers() {
162
+        return new Menu(/* I18N: Menu entry */ I18N::translate('Users'), '#', '', array(), array(
163
+            new Menu(/* I18N: Menu entry */ I18N::translate('User administration'), 'admin_users.php'),
164
+            new Menu(/* I18N: Menu entry */ I18N::translate('Add a user'), 'admin_users.php?action=edit'),
165
+            new Menu(/* I18N: Menu entry */ I18N::translate('Send broadcast messages'), 'admin_users_bulk.php'),
166
+            new Menu(/* I18N: Menu entry */ I18N::translate('Delete inactive users'), 'admin_users.php?action=cleanup'),
167
+            new Menu(/* I18N: Menu entry */ I18N::translate('Set the default blocks for new users'), 'index_edit.php?user_id=-1'),
168
+        ));
169
+    }
170 170
 
171
-	/**
172
-	 * Media administration menu.
173
-	 *
174
-	 * @return Menu
175
-	 */
176
-	protected function menuAdminMedia() {
177
-		return new Menu(/* I18N: Menu entry */ I18N::translate('Media'), '#', '', array(), array(
178
-			new Menu(/* I18N: Menu entry */ I18N::translate('Manage media'), 'admin_media.php'),
179
-			new Menu(/* I18N: Menu entry */ I18N::translate('Upload media files'), 'admin_media_upload.php'),
180
-		));
181
-	}
171
+    /**
172
+     * Media administration menu.
173
+     *
174
+     * @return Menu
175
+     */
176
+    protected function menuAdminMedia() {
177
+        return new Menu(/* I18N: Menu entry */ I18N::translate('Media'), '#', '', array(), array(
178
+            new Menu(/* I18N: Menu entry */ I18N::translate('Manage media'), 'admin_media.php'),
179
+            new Menu(/* I18N: Menu entry */ I18N::translate('Upload media files'), 'admin_media_upload.php'),
180
+        ));
181
+    }
182 182
 
183
-	/**
184
-	 * Module administration menu.
185
-	 *
186
-	 * @return Menu
187
-	 */
188
-	protected function menuAdminModules() {
189
-		return new Menu(/* I18N: Menu entry */ I18N::translate('Modules'), '#', '', array(), array(
190
-			new Menu(/* I18N: Menu entry */ I18N::translate('Module administration'), 'admin_modules.php'),
191
-			new Menu(/* I18N: Menu entry */ I18N::translate('Menus'), 'admin_module_menus.php'),
192
-			new Menu(/* I18N: Menu entry */ I18N::translate('Tabs'), 'admin_module_tabs.php'),
193
-			new Menu(/* I18N: Menu entry */ I18N::translate('Blocks'), 'admin_module_blocks.php'),
194
-			new Menu(/* I18N: Menu entry */ I18N::translate('Sidebars'), 'admin_module_sidebar.php'),
195
-			new Menu(/* I18N: Menu entry */ I18N::translate('Charts'), 'admin_module_charts.php'),
196
-			new Menu(/* I18N: Menu entry */ I18N::translate('Reports'), 'admin_module_reports.php'),
197
-		));
198
-	}
183
+    /**
184
+     * Module administration menu.
185
+     *
186
+     * @return Menu
187
+     */
188
+    protected function menuAdminModules() {
189
+        return new Menu(/* I18N: Menu entry */ I18N::translate('Modules'), '#', '', array(), array(
190
+            new Menu(/* I18N: Menu entry */ I18N::translate('Module administration'), 'admin_modules.php'),
191
+            new Menu(/* I18N: Menu entry */ I18N::translate('Menus'), 'admin_module_menus.php'),
192
+            new Menu(/* I18N: Menu entry */ I18N::translate('Tabs'), 'admin_module_tabs.php'),
193
+            new Menu(/* I18N: Menu entry */ I18N::translate('Blocks'), 'admin_module_blocks.php'),
194
+            new Menu(/* I18N: Menu entry */ I18N::translate('Sidebars'), 'admin_module_sidebar.php'),
195
+            new Menu(/* I18N: Menu entry */ I18N::translate('Charts'), 'admin_module_charts.php'),
196
+            new Menu(/* I18N: Menu entry */ I18N::translate('Reports'), 'admin_module_reports.php'),
197
+        ));
198
+    }
199 199
 
200
-	/**
201
-	 * Generate a list of items for the main menu.
202
-	 *
203
-	 * @return Menu[]
204
-	 */
205
-	protected function primaryMenu() {
206
-		if (Auth::isAdmin()) {
207
-			return array(
208
-				$this->menuAdminSite(),
209
-				$this->menuAdminTrees(),
210
-				$this->menuAdminUsers(),
211
-				$this->menuAdminMedia(),
212
-				$this->menuAdminModules(),
213
-			);
214
-		} else {
215
-			return array(
216
-				$this->menuAdminTrees(),
217
-			);
218
-		}
219
-	}
200
+    /**
201
+     * Generate a list of items for the main menu.
202
+     *
203
+     * @return Menu[]
204
+     */
205
+    protected function primaryMenu() {
206
+        if (Auth::isAdmin()) {
207
+            return array(
208
+                $this->menuAdminSite(),
209
+                $this->menuAdminTrees(),
210
+                $this->menuAdminUsers(),
211
+                $this->menuAdminMedia(),
212
+                $this->menuAdminModules(),
213
+            );
214
+        } else {
215
+            return array(
216
+                $this->menuAdminTrees(),
217
+            );
218
+        }
219
+    }
220 220
 
221
-	/**
222
-	 * Add markup to the primary menu.
223
-	 *
224
-	 * @param Menu[] $menus
225
-	 *
226
-	 * @return string
227
-	 */
228
-	protected function primaryMenuContainer(array $menus) {
229
-		$html = '';
230
-		foreach ($menus as $menu) {
231
-			$html .= $menu->bootstrap();
232
-		}
221
+    /**
222
+     * Add markup to the primary menu.
223
+     *
224
+     * @param Menu[] $menus
225
+     *
226
+     * @return string
227
+     */
228
+    protected function primaryMenuContainer(array $menus) {
229
+        $html = '';
230
+        foreach ($menus as $menu) {
231
+            $html .= $menu->bootstrap();
232
+        }
233 233
 
234
-		return
235
-			'<nav class="navbar navbar-default">' .
236
-			'<div class="navbar-header">' .
237
-			'<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#primary-navbar-collapse">' .
238
-			'<span class="sr-only">Toggle navigation</span>' .
239
-			'<span class="icon-bar"></span>' .
240
-			'<span class="icon-bar"></span>' .
241
-			'<span class="icon-bar"></span>' .
242
-			'</button>' .
243
-			'<a class="navbar-brand" href="admin.php">' . I18N::translate('Control panel') . '</a>' .
244
-			'</div>' .
245
-			'<div class="collapse navbar-collapse" id="primary-navbar-collapse">' .
246
-			'<ul class="nav navbar-nav">' .
247
-			$html .
248
-			'</ul>' .
249
-			'</div>' .
250
-			'</nav>';
251
-	}
234
+        return
235
+            '<nav class="navbar navbar-default">' .
236
+            '<div class="navbar-header">' .
237
+            '<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#primary-navbar-collapse">' .
238
+            '<span class="sr-only">Toggle navigation</span>' .
239
+            '<span class="icon-bar"></span>' .
240
+            '<span class="icon-bar"></span>' .
241
+            '<span class="icon-bar"></span>' .
242
+            '</button>' .
243
+            '<a class="navbar-brand" href="admin.php">' . I18N::translate('Control panel') . '</a>' .
244
+            '</div>' .
245
+            '<div class="collapse navbar-collapse" id="primary-navbar-collapse">' .
246
+            '<ul class="nav navbar-nav">' .
247
+            $html .
248
+            '</ul>' .
249
+            '</div>' .
250
+            '</nav>';
251
+    }
252 252
 
253
-	/**
254
-	 * Generate a list of items for the user menu.
255
-	 *
256
-	 * @return Menu[]
257
-	 */
258
-	protected function secondaryMenu() {
259
-		return array_filter(array(
260
-			$this->menuPendingChanges(),
261
-			$this->menuMyPage(),
262
-			$this->menuLanguages(),
263
-			$this->menuLogout(),
264
-		));
265
-	}
253
+    /**
254
+     * Generate a list of items for the user menu.
255
+     *
256
+     * @return Menu[]
257
+     */
258
+    protected function secondaryMenu() {
259
+        return array_filter(array(
260
+            $this->menuPendingChanges(),
261
+            $this->menuMyPage(),
262
+            $this->menuLanguages(),
263
+            $this->menuLogout(),
264
+        ));
265
+    }
266 266
 
267
-	/**
268
-	 * Add markup to the secondary menu.
269
-	 *
270
-	 * @param Menu[] $menus
271
-	 *
272
-	 * @return string
273
-	 */
274
-	protected function secondaryMenuContainer(array $menus) {
275
-		return '<div class="clearfix"><ul class="nav nav-pills small pull-right flip" role="menu">' . $this->secondaryMenuContent($menus) . '</ul></div>';
276
-	}
267
+    /**
268
+     * Add markup to the secondary menu.
269
+     *
270
+     * @param Menu[] $menus
271
+     *
272
+     * @return string
273
+     */
274
+    protected function secondaryMenuContainer(array $menus) {
275
+        return '<div class="clearfix"><ul class="nav nav-pills small pull-right flip" role="menu">' . $this->secondaryMenuContent($menus) . '</ul></div>';
276
+    }
277 277
 
278
-	/**
279
-	 * Format the secondary menu.
280
-	 *
281
-	 * @param Menu[] $menus
282
-	 *
283
-	 * @return string
284
-	 */
285
-	protected function secondaryMenuContent(array $menus) {
286
-		return implode('', array_map(function (Menu $menu) { return $menu->bootstrap(); }, $menus));
287
-	}
278
+    /**
279
+     * Format the secondary menu.
280
+     *
281
+     * @param Menu[] $menus
282
+     *
283
+     * @return string
284
+     */
285
+    protected function secondaryMenuContent(array $menus) {
286
+        return implode('', array_map(function (Menu $menu) { return $menu->bootstrap(); }, $menus));
287
+    }
288 288
 
289
-	/**
290
-	 * A fixed string to identify this theme, in settings, etc.
291
-	 *
292
-	 * @return string
293
-	 */
294
-	public function themeId() {
295
-		return '_administration';
296
-	}
289
+    /**
290
+     * A fixed string to identify this theme, in settings, etc.
291
+     *
292
+     * @return string
293
+     */
294
+    public function themeId() {
295
+        return '_administration';
296
+    }
297 297
 
298
-	/**
299
-	 * What is this theme called?
300
-	 *
301
-	 * @return string
302
-	 */
303
-	public function themeName() {
304
-		return 'administration';
305
-	}
298
+    /**
299
+     * What is this theme called?
300
+     *
301
+     * @return string
302
+     */
303
+    public function themeName() {
304
+        return 'administration';
305
+    }
306 306
 }
Please login to merge, or discard this patch.
Braces   +44 added lines, -22 removed lines patch added patch discarded remove patch
@@ -23,13 +23,15 @@  discard block
 block discarded – undo
23 23
 /**
24 24
  * The theme for the control panel.
25 25
  */
26
-class AdministrationTheme extends AbstractTheme implements ThemeInterface {
26
+class AdministrationTheme extends AbstractTheme implements ThemeInterface
27
+{
27 28
 	/**
28 29
 	 * A list of CSS files to include for this page.
29 30
 	 *
30 31
 	 * @return string[]
31 32
 	 */
32
-	protected function stylesheets() {
33
+	protected function stylesheets()
34
+	{
33 35
 		$stylesheets   = parent::stylesheets();
34 36
 		$stylesheets[] = WT_DATATABLES_BOOTSTRAP_CSS_URL;
35 37
 		$stylesheets[] = WT_BOOTSTRAP_DATETIMEPICKER_CSS_URL;
@@ -43,7 +45,8 @@  discard block
 block discarded – undo
43 45
 	 *
44 46
 	 * @return string A relative path, such as "themes/foo/"
45 47
 	 */
46
-	public function assetUrl() {
48
+	public function assetUrl()
49
+	{
47 50
 		return 'themes/_administration/css-1.7.5/';
48 51
 	}
49 52
 
@@ -52,7 +55,8 @@  discard block
 block discarded – undo
52 55
 	 *
53 56
 	 * @return string
54 57
 	 */
55
-	protected function favicon() {
58
+	protected function favicon()
59
+	{
56 60
 		return '<link rel="icon" href="favicon.ico" type="image/x-icon">';
57 61
 	}
58 62
 	/**
@@ -60,7 +64,8 @@  discard block
 block discarded – undo
60 64
 	 *
61 65
 	 * @return string
62 66
 	 */
63
-	protected function footerContent() {
67
+	protected function footerContent()
68
+	{
64 69
 		return '';
65 70
 	}
66 71
 
@@ -69,7 +74,8 @@  discard block
 block discarded – undo
69 74
 	 *
70 75
 	 * @return string
71 76
 	 */
72
-	protected function headerContent() {
77
+	protected function headerContent()
78
+	{
73 79
 		return
74 80
 			$this->accessibilityLinks() .
75 81
 			$this->secondaryMenuContainer($this->secondaryMenu());
@@ -80,7 +86,8 @@  discard block
 block discarded – undo
80 86
 	 *
81 87
 	 * @return string
82 88
 	 */
83
-	public function hookFooterExtraJavascript() {
89
+	public function hookFooterExtraJavascript()
90
+	{
84 91
 		return
85 92
 			'<script src="' . WT_BOOTSTRAP_JS_URL . '"></script>';
86 93
 	}
@@ -90,7 +97,8 @@  discard block
 block discarded – undo
90 97
 	 *
91 98
 	 * @return Menu
92 99
 	 */
93
-	protected function menuAdminSite() {
100
+	protected function menuAdminSite()
101
+	{
94 102
 		return new Menu(/* I18N: Menu entry*/ I18N::translate('Website'), '#', '', array(), array(
95 103
 			new Menu(/* I18N: Menu entry */ I18N::translate('Website preferences'), 'admin_site_config.php?action=site'),
96 104
 			new Menu(/* I18N: Menu entry */ I18N::translate('Sending email'), 'admin_site_config.php?action=email'),
@@ -110,7 +118,8 @@  discard block
 block discarded – undo
110 118
 	 *
111 119
 	 * @return Menu
112 120
 	 */
113
-	protected function menuAdminTrees() {
121
+	protected function menuAdminTrees()
122
+	{
114 123
 		return new Menu(/* I18N: Menu entry */ I18N::translate('Family trees'), '#', '', array(), array_filter(array(
115 124
 			$this->menuAdminTreesManage(),
116 125
 			$this->menuAdminTreesSetDefault(),
@@ -123,7 +132,8 @@  discard block
 block discarded – undo
123 132
 	 *
124 133
 	 * @return Menu
125 134
 	 */
126
-	protected function menuAdminTreesManage() {
135
+	protected function menuAdminTreesManage()
136
+	{
127 137
 		return new Menu(/* I18N: Menu entry */ I18N::translate('Manage family trees'), 'admin_trees_manage.php');
128 138
 	}
129 139
 
@@ -132,7 +142,8 @@  discard block
 block discarded – undo
132 142
 	 *
133 143
 	 * @return Menu|null
134 144
 	 */
135
-	protected function menuAdminTreesMerge() {
145
+	protected function menuAdminTreesMerge()
146
+	{
136 147
 		if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
137 148
 			return new Menu(/* I18N: Menu entry */ I18N::translate('Merge family trees'), 'admin_trees_merge.php');
138 149
 		} else {
@@ -145,7 +156,8 @@  discard block
 block discarded – undo
145 156
 	 *
146 157
 	 * @return Menu|null
147 158
 	 */
148
-	protected function menuAdminTreesSetDefault() {
159
+	protected function menuAdminTreesSetDefault()
160
+	{
149 161
 		if (Auth::isAdmin() && count(Tree::getAll()) > 1) {
150 162
 			return new Menu(/* I18N: Menu entry */ I18N::translate('Set the default blocks for new family trees'), 'index_edit.php?gedcom_id=-1');
151 163
 		} else {
@@ -158,7 +170,8 @@  discard block
 block discarded – undo
158 170
 	 *
159 171
 	 * @return Menu
160 172
 	 */
161
-	protected function menuAdminUsers() {
173
+	protected function menuAdminUsers()
174
+	{
162 175
 		return new Menu(/* I18N: Menu entry */ I18N::translate('Users'), '#', '', array(), array(
163 176
 			new Menu(/* I18N: Menu entry */ I18N::translate('User administration'), 'admin_users.php'),
164 177
 			new Menu(/* I18N: Menu entry */ I18N::translate('Add a user'), 'admin_users.php?action=edit'),
@@ -173,7 +186,8 @@  discard block
 block discarded – undo
173 186
 	 *
174 187
 	 * @return Menu
175 188
 	 */
176
-	protected function menuAdminMedia() {
189
+	protected function menuAdminMedia()
190
+	{
177 191
 		return new Menu(/* I18N: Menu entry */ I18N::translate('Media'), '#', '', array(), array(
178 192
 			new Menu(/* I18N: Menu entry */ I18N::translate('Manage media'), 'admin_media.php'),
179 193
 			new Menu(/* I18N: Menu entry */ I18N::translate('Upload media files'), 'admin_media_upload.php'),
@@ -185,7 +199,8 @@  discard block
 block discarded – undo
185 199
 	 *
186 200
 	 * @return Menu
187 201
 	 */
188
-	protected function menuAdminModules() {
202
+	protected function menuAdminModules()
203
+	{
189 204
 		return new Menu(/* I18N: Menu entry */ I18N::translate('Modules'), '#', '', array(), array(
190 205
 			new Menu(/* I18N: Menu entry */ I18N::translate('Module administration'), 'admin_modules.php'),
191 206
 			new Menu(/* I18N: Menu entry */ I18N::translate('Menus'), 'admin_module_menus.php'),
@@ -202,7 +217,8 @@  discard block
 block discarded – undo
202 217
 	 *
203 218
 	 * @return Menu[]
204 219
 	 */
205
-	protected function primaryMenu() {
220
+	protected function primaryMenu()
221
+	{
206 222
 		if (Auth::isAdmin()) {
207 223
 			return array(
208 224
 				$this->menuAdminSite(),
@@ -225,7 +241,8 @@  discard block
 block discarded – undo
225 241
 	 *
226 242
 	 * @return string
227 243
 	 */
228
-	protected function primaryMenuContainer(array $menus) {
244
+	protected function primaryMenuContainer(array $menus)
245
+	{
229 246
 		$html = '';
230 247
 		foreach ($menus as $menu) {
231 248
 			$html .= $menu->bootstrap();
@@ -255,7 +272,8 @@  discard block
 block discarded – undo
255 272
 	 *
256 273
 	 * @return Menu[]
257 274
 	 */
258
-	protected function secondaryMenu() {
275
+	protected function secondaryMenu()
276
+	{
259 277
 		return array_filter(array(
260 278
 			$this->menuPendingChanges(),
261 279
 			$this->menuMyPage(),
@@ -271,7 +289,8 @@  discard block
 block discarded – undo
271 289
 	 *
272 290
 	 * @return string
273 291
 	 */
274
-	protected function secondaryMenuContainer(array $menus) {
292
+	protected function secondaryMenuContainer(array $menus)
293
+	{
275 294
 		return '<div class="clearfix"><ul class="nav nav-pills small pull-right flip" role="menu">' . $this->secondaryMenuContent($menus) . '</ul></div>';
276 295
 	}
277 296
 
@@ -282,7 +301,8 @@  discard block
 block discarded – undo
282 301
 	 *
283 302
 	 * @return string
284 303
 	 */
285
-	protected function secondaryMenuContent(array $menus) {
304
+	protected function secondaryMenuContent(array $menus)
305
+	{
286 306
 		return implode('', array_map(function (Menu $menu) { return $menu->bootstrap(); }, $menus));
287 307
 	}
288 308
 
@@ -291,7 +311,8 @@  discard block
 block discarded – undo
291 311
 	 *
292 312
 	 * @return string
293 313
 	 */
294
-	public function themeId() {
314
+	public function themeId()
315
+	{
295 316
 		return '_administration';
296 317
 	}
297 318
 
@@ -300,7 +321,8 @@  discard block
 block discarded – undo
300 321
 	 *
301 322
 	 * @return string
302 323
 	 */
303
-	public function themeName() {
324
+	public function themeName()
325
+	{
304 326
 		return 'administration';
305 327
 	}
306 328
 }
Please login to merge, or discard this patch.
app/Theme/ThemeInterface.php 2 patches
Indentation   +213 added lines, -213 removed lines patch added patch discarded remove patch
@@ -26,217 +26,217 @@
 block discarded – undo
26 26
  * Specification for a theme.
27 27
  */
28 28
 interface ThemeInterface {
29
-	/**
30
-	 * Where are our CSS, JS and other assets?
31
-	 *
32
-	 * @return string A relative path, such as "themes/foo/"
33
-	 */
34
-	public function assetUrl();
35
-
36
-	/**
37
-	 * Create the top of the <body>.
38
-	 *
39
-	 * @return string
40
-	 */
41
-	public function bodyHeader();
42
-
43
-	/**
44
-	 * Create the top of the <body> (for popup windows).
45
-	 *
46
-	 * @return string
47
-	 */
48
-	public function bodyHeaderPopupWindow();
49
-
50
-	/**
51
-	 * Create a contact link for a user.
52
-	 *
53
-	 * @param User $user
54
-	 *
55
-	 * @return string
56
-	 */
57
-	public function contactLink(User $user);
58
-
59
-	/**
60
-	 * Create the <DOCTYPE> tag.
61
-	 *
62
-	 * @return string
63
-	 */
64
-	public function doctype();
65
-
66
-	/**
67
-	 * Close the main content and create the <footer> tag.
68
-	 *
69
-	 * @return string
70
-	 */
71
-	public function footerContainer();
72
-
73
-	/**
74
-	 * Close the main content.
75
-	 * Note that popup windows are deprecated
76
-	 *
77
-	 * @return string
78
-	 */
79
-	public function footerContainerPopupWindow();
80
-
81
-	/**
82
-	 * Format the contents of a variable-height home-page block.
83
-	 *
84
-	 * @param string $id
85
-	 * @param string $title
86
-	 * @param string $class
87
-	 * @param string $content
88
-	 *
89
-	 * @return string
90
-	 */
91
-	public function formatBlock($id, $title, $class, $content);
92
-
93
-	/**
94
-	 * Create the <head> tag.
95
-	 *
96
-	 * @param PageController $controller The current controller
97
-	 *
98
-	 * @return string
99
-	 */
100
-	public function head(PageController $controller);
101
-
102
-	/**
103
-	 * Allow themes to do things after initialization (since they cannot use
104
-	 * the constructor).
105
-	 */
106
-	public function hookAfterInit();
107
-
108
-	/**
109
-	 * Allow themes to add extra scripts to the page footer.
110
-	 *
111
-	 * @return string
112
-	 */
113
-	public function hookFooterExtraJavascript();
114
-
115
-	/**
116
-	 * Allow themes to add extra content to the page header.
117
-	 * Typically this will be additional CSS.
118
-	 *
119
-	 * @return string
120
-	 */
121
-	public function hookHeaderExtraContent();
122
-
123
-	/**
124
-	 * Create the <html> tag.
125
-	 *
126
-	 * @return string
127
-	 */
128
-	public function html();
129
-
130
-	/**
131
-	 * Add HTML markup to create an alert
132
-	 *
133
-	 * @param string $html        The content of the alert
134
-	 * @param string $level       One of 'success', 'info', 'warning', 'danger'
135
-	 * @param bool   $dismissible If true, add a close button.
136
-	 *
137
-	 * @return string
138
-	 */
139
-	public function htmlAlert($html, $level, $dismissible);
140
-
141
-	/**
142
-	 * Display an icon for this fact.
143
-	 *
144
-	 * @param Fact $fact
145
-	 *
146
-	 * @return string
147
-	 */
148
-	public function icon(Fact $fact);
149
-
150
-	/**
151
-	 * Display an individual in a box - for charts, etc.
152
-	 *
153
-	 * @param Individual $individual
154
-	 *
155
-	 * @return string
156
-	 */
157
-	public function individualBox(Individual $individual);
158
-
159
-	/**
160
-	 * Display an empty box - for a missing individual in a chart.
161
-	 *
162
-	 * @return string
163
-	 */
164
-	public function individualBoxEmpty();
165
-
166
-	/**
167
-	 * Display an individual in a box - for charts, etc.
168
-	 *
169
-	 * @param Individual $individual
170
-	 *
171
-	 * @return string
172
-	 */
173
-	public function individualBoxLarge(Individual $individual);
174
-
175
-	/**
176
-	 * Display an individual in a box - for charts, etc.
177
-	 *
178
-	 * @param Individual $individual
179
-	 *
180
-	 * @return string
181
-	 */
182
-	public function individualBoxSmall(Individual $individual);
183
-
184
-	/**
185
-	 * Display an individual in a box - for charts, etc.
186
-	 *
187
-	 * @return string
188
-	 */
189
-	public function individualBoxSmallEmpty();
190
-
191
-	/**
192
-	 * Initialise the theme. We cannot pass these in a constructor, as the construction
193
-	 * happens in a theme file, and we need to be able to change it.
194
-	 *
195
-	 * @param Tree|null $tree The current tree (if there is one).
196
-	 */
197
-	public function init(Tree $tree = null);
198
-
199
-	/**
200
-	 * Links, to show in chart boxes;
201
-	 *
202
-	 * @param Individual $individual
203
-	 *
204
-	 * @return Menu[]
205
-	 */
206
-	public function individualBoxMenu(Individual $individual);
207
-
208
-	/**
209
-	 * Themes menu.
210
-	 *
211
-	 * @return Menu|null
212
-	 */
213
-	public function menuThemes();
214
-
215
-	/**
216
-	 * Misecellaneous dimensions, fonts, styles, etc.
217
-	 *
218
-	 * @param string $parameter_name
219
-	 *
220
-	 * @return string|int|float
221
-	 */
222
-	public function parameter($parameter_name);
223
-
224
-	/**
225
-	 * Send any HTTP headers.
226
-	 */
227
-	public function sendHeaders();
228
-
229
-	/**
230
-	 * A fixed string to identify this theme, in settings, etc.
231
-	 *
232
-	 * @return string
233
-	 */
234
-	public function themeId();
235
-
236
-	/**
237
-	 * What is this theme called?
238
-	 *
239
-	 * @return string
240
-	 */
241
-	public function themeName();
29
+    /**
30
+     * Where are our CSS, JS and other assets?
31
+     *
32
+     * @return string A relative path, such as "themes/foo/"
33
+     */
34
+    public function assetUrl();
35
+
36
+    /**
37
+     * Create the top of the <body>.
38
+     *
39
+     * @return string
40
+     */
41
+    public function bodyHeader();
42
+
43
+    /**
44
+     * Create the top of the <body> (for popup windows).
45
+     *
46
+     * @return string
47
+     */
48
+    public function bodyHeaderPopupWindow();
49
+
50
+    /**
51
+     * Create a contact link for a user.
52
+     *
53
+     * @param User $user
54
+     *
55
+     * @return string
56
+     */
57
+    public function contactLink(User $user);
58
+
59
+    /**
60
+     * Create the <DOCTYPE> tag.
61
+     *
62
+     * @return string
63
+     */
64
+    public function doctype();
65
+
66
+    /**
67
+     * Close the main content and create the <footer> tag.
68
+     *
69
+     * @return string
70
+     */
71
+    public function footerContainer();
72
+
73
+    /**
74
+     * Close the main content.
75
+     * Note that popup windows are deprecated
76
+     *
77
+     * @return string
78
+     */
79
+    public function footerContainerPopupWindow();
80
+
81
+    /**
82
+     * Format the contents of a variable-height home-page block.
83
+     *
84
+     * @param string $id
85
+     * @param string $title
86
+     * @param string $class
87
+     * @param string $content
88
+     *
89
+     * @return string
90
+     */
91
+    public function formatBlock($id, $title, $class, $content);
92
+
93
+    /**
94
+     * Create the <head> tag.
95
+     *
96
+     * @param PageController $controller The current controller
97
+     *
98
+     * @return string
99
+     */
100
+    public function head(PageController $controller);
101
+
102
+    /**
103
+     * Allow themes to do things after initialization (since they cannot use
104
+     * the constructor).
105
+     */
106
+    public function hookAfterInit();
107
+
108
+    /**
109
+     * Allow themes to add extra scripts to the page footer.
110
+     *
111
+     * @return string
112
+     */
113
+    public function hookFooterExtraJavascript();
114
+
115
+    /**
116
+     * Allow themes to add extra content to the page header.
117
+     * Typically this will be additional CSS.
118
+     *
119
+     * @return string
120
+     */
121
+    public function hookHeaderExtraContent();
122
+
123
+    /**
124
+     * Create the <html> tag.
125
+     *
126
+     * @return string
127
+     */
128
+    public function html();
129
+
130
+    /**
131
+     * Add HTML markup to create an alert
132
+     *
133
+     * @param string $html        The content of the alert
134
+     * @param string $level       One of 'success', 'info', 'warning', 'danger'
135
+     * @param bool   $dismissible If true, add a close button.
136
+     *
137
+     * @return string
138
+     */
139
+    public function htmlAlert($html, $level, $dismissible);
140
+
141
+    /**
142
+     * Display an icon for this fact.
143
+     *
144
+     * @param Fact $fact
145
+     *
146
+     * @return string
147
+     */
148
+    public function icon(Fact $fact);
149
+
150
+    /**
151
+     * Display an individual in a box - for charts, etc.
152
+     *
153
+     * @param Individual $individual
154
+     *
155
+     * @return string
156
+     */
157
+    public function individualBox(Individual $individual);
158
+
159
+    /**
160
+     * Display an empty box - for a missing individual in a chart.
161
+     *
162
+     * @return string
163
+     */
164
+    public function individualBoxEmpty();
165
+
166
+    /**
167
+     * Display an individual in a box - for charts, etc.
168
+     *
169
+     * @param Individual $individual
170
+     *
171
+     * @return string
172
+     */
173
+    public function individualBoxLarge(Individual $individual);
174
+
175
+    /**
176
+     * Display an individual in a box - for charts, etc.
177
+     *
178
+     * @param Individual $individual
179
+     *
180
+     * @return string
181
+     */
182
+    public function individualBoxSmall(Individual $individual);
183
+
184
+    /**
185
+     * Display an individual in a box - for charts, etc.
186
+     *
187
+     * @return string
188
+     */
189
+    public function individualBoxSmallEmpty();
190
+
191
+    /**
192
+     * Initialise the theme. We cannot pass these in a constructor, as the construction
193
+     * happens in a theme file, and we need to be able to change it.
194
+     *
195
+     * @param Tree|null $tree The current tree (if there is one).
196
+     */
197
+    public function init(Tree $tree = null);
198
+
199
+    /**
200
+     * Links, to show in chart boxes;
201
+     *
202
+     * @param Individual $individual
203
+     *
204
+     * @return Menu[]
205
+     */
206
+    public function individualBoxMenu(Individual $individual);
207
+
208
+    /**
209
+     * Themes menu.
210
+     *
211
+     * @return Menu|null
212
+     */
213
+    public function menuThemes();
214
+
215
+    /**
216
+     * Misecellaneous dimensions, fonts, styles, etc.
217
+     *
218
+     * @param string $parameter_name
219
+     *
220
+     * @return string|int|float
221
+     */
222
+    public function parameter($parameter_name);
223
+
224
+    /**
225
+     * Send any HTTP headers.
226
+     */
227
+    public function sendHeaders();
228
+
229
+    /**
230
+     * A fixed string to identify this theme, in settings, etc.
231
+     *
232
+     * @return string
233
+     */
234
+    public function themeId();
235
+
236
+    /**
237
+     * What is this theme called?
238
+     *
239
+     * @return string
240
+     */
241
+    public function themeName();
242 242
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -25,7 +25,8 @@
 block discarded – undo
25 25
 /**
26 26
  * Specification for a theme.
27 27
  */
28
-interface ThemeInterface {
28
+interface ThemeInterface
29
+{
29 30
 	/**
30 31
 	 * Where are our CSS, JS and other assets?
31 32
 	 *
Please login to merge, or discard this patch.
app/Theme/MinimalTheme.php 3 patches
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -21,149 +21,149 @@
 block discarded – undo
21 21
  * The Minimal theme.
22 22
  */
23 23
 class MinimalTheme extends AbstractTheme implements ThemeInterface {
24
-	/**
25
-	 * Where are our CSS, JS and other assets?
26
-	 *
27
-	 * @return string A relative path, such as "themes/foo/"
28
-	 */
29
-	public function assetUrl() {
30
-		return 'themes/minimal/css-1.7.8/';
31
-	}
24
+    /**
25
+     * Where are our CSS, JS and other assets?
26
+     *
27
+     * @return string A relative path, such as "themes/foo/"
28
+     */
29
+    public function assetUrl() {
30
+        return 'themes/minimal/css-1.7.8/';
31
+    }
32 32
 
33
-	/**
34
-	 * Add markup to a flash message.
35
-	 *
36
-	 * @param \stdClass $message
37
-	 *
38
-	 * @return string
39
-	 */
40
-	protected function flashMessageContainer(\stdClass $message) {
41
-		// This theme uses jQueryUI markup.
42
-		switch ($message->status) {
43
-		case 'danger':
44
-			return '<p class="ui-state-error">' . $message->text . '</p>';
45
-		default:
46
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
47
-		}
48
-	}
33
+    /**
34
+     * Add markup to a flash message.
35
+     *
36
+     * @param \stdClass $message
37
+     *
38
+     * @return string
39
+     */
40
+    protected function flashMessageContainer(\stdClass $message) {
41
+        // This theme uses jQueryUI markup.
42
+        switch ($message->status) {
43
+        case 'danger':
44
+            return '<p class="ui-state-error">' . $message->text . '</p>';
45
+        default:
46
+            return '<p class="ui-state-highlight">' . $message->text . '</p>';
47
+        }
48
+    }
49 49
 
50
-	/**
51
-	 * Create a search field and submit button for the quick search form in the header.
52
-	 *
53
-	 * @return string
54
-	 */
55
-	protected function formQuickSearchFields() {
56
-		return
57
-			'<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
58
-	}
50
+    /**
51
+     * Create a search field and submit button for the quick search form in the header.
52
+     *
53
+     * @return string
54
+     */
55
+    protected function formQuickSearchFields() {
56
+        return
57
+            '<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
58
+    }
59 59
 
60
-	/**
61
-	 * Add markup to the secondary menu.
62
-	 *
63
-	 * @return string
64
-	 */
65
-	protected function formatSecondaryMenu() {
66
-		return
67
-			'<ul class="secondary-menu">' .
68
-			implode('', $this->secondaryMenu()) .
69
-			'<li>' .
70
-			$this->formQuickSearch() .
71
-			'</li>' .
72
-			'</ul>';
73
-	}
60
+    /**
61
+     * Add markup to the secondary menu.
62
+     *
63
+     * @return string
64
+     */
65
+    protected function formatSecondaryMenu() {
66
+        return
67
+            '<ul class="secondary-menu">' .
68
+            implode('', $this->secondaryMenu()) .
69
+            '<li>' .
70
+            $this->formQuickSearch() .
71
+            '</li>' .
72
+            '</ul>';
73
+    }
74 74
 
75
-	/**
76
-	 * Create the contents of the <header> tag.
77
-	 *
78
-	 * @return string
79
-	 */
80
-	protected function headerContent() {
81
-		return
82
-			//$this->accessibilityLinks() .
83
-			$this->formatTreeTitle() .
84
-			$this->formatSecondaryMenu();
85
-	}
75
+    /**
76
+     * Create the contents of the <header> tag.
77
+     *
78
+     * @return string
79
+     */
80
+    protected function headerContent() {
81
+        return
82
+            //$this->accessibilityLinks() .
83
+            $this->formatTreeTitle() .
84
+            $this->formatSecondaryMenu();
85
+    }
86 86
 
87
-	/**
88
-	 * A small "powered by webtrees" logo for the footer.
89
-	 *
90
-	 * @return string
91
-	 */
92
-	protected function logoPoweredBy() {
93
-		return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '">' . WT_WEBTREES . '</a>';
94
-	}
87
+    /**
88
+     * A small "powered by webtrees" logo for the footer.
89
+     *
90
+     * @return string
91
+     */
92
+    protected function logoPoweredBy() {
93
+        return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '">' . WT_WEBTREES . '</a>';
94
+    }
95 95
 
96
-	/**
97
-	 * Allow themes to add extra scripts to the page footer.
98
-	 *
99
-	 * @return string
100
-	 */
101
-	public function hookFooterExtraJavascript() {
102
-		return
103
-			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
104
-			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
105
-			'<script>' .
106
-			'activate_colorbox();' .
107
-			'jQuery.extend(jQuery.colorbox.settings, {' .
108
-			' width: "85%",' .
109
-			' height: "85%",' .
110
-			' transition: "none",' .
111
-			' slideshowStart: "' . I18N::translate('Play') . '",' .
112
-			' slideshowStop: "' . I18N::translate('Stop') . '",' .
113
-			' title: function() { return jQuery(this).data("title"); }' .
114
-			'});' .
115
-			'</script>';
116
-	}
96
+    /**
97
+     * Allow themes to add extra scripts to the page footer.
98
+     *
99
+     * @return string
100
+     */
101
+    public function hookFooterExtraJavascript() {
102
+        return
103
+            '<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
104
+            '<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
105
+            '<script>' .
106
+            'activate_colorbox();' .
107
+            'jQuery.extend(jQuery.colorbox.settings, {' .
108
+            ' width: "85%",' .
109
+            ' height: "85%",' .
110
+            ' transition: "none",' .
111
+            ' slideshowStart: "' . I18N::translate('Play') . '",' .
112
+            ' slideshowStop: "' . I18N::translate('Stop') . '",' .
113
+            ' title: function() { return jQuery(this).data("title"); }' .
114
+            '});' .
115
+            '</script>';
116
+    }
117 117
 
118
-	/**
119
-	 * Misecellaneous dimensions, fonts, styles, etc.
120
-	 *
121
-	 * @param string $parameter_name
122
-	 *
123
-	 * @return string|int|float
124
-	 */
125
-	public function parameter($parameter_name) {
126
-		$parameters = array(
127
-			'chart-background-f'             => 'dddddd',
128
-			'chart-background-m'             => 'cccccc',
129
-			'distribution-chart-low-values'  => 'cccccc',
130
-			'distribution-chart-no-values'   => 'ffffff',
131
-		);
118
+    /**
119
+     * Misecellaneous dimensions, fonts, styles, etc.
120
+     *
121
+     * @param string $parameter_name
122
+     *
123
+     * @return string|int|float
124
+     */
125
+    public function parameter($parameter_name) {
126
+        $parameters = array(
127
+            'chart-background-f'             => 'dddddd',
128
+            'chart-background-m'             => 'cccccc',
129
+            'distribution-chart-low-values'  => 'cccccc',
130
+            'distribution-chart-no-values'   => 'ffffff',
131
+        );
132 132
 
133
-		if (array_key_exists($parameter_name, $parameters)) {
134
-			return $parameters[$parameter_name];
135
-		} else {
136
-			return parent::parameter($parameter_name);
137
-		}
138
-	}
133
+        if (array_key_exists($parameter_name, $parameters)) {
134
+            return $parameters[$parameter_name];
135
+        } else {
136
+            return parent::parameter($parameter_name);
137
+        }
138
+    }
139 139
 
140
-	/**
141
-	 * A list of CSS files to include for this page.
142
-	 *
143
-	 * @return string[]
144
-	 */
145
-	protected function stylesheets() {
146
-		return array(
147
-			'themes/minimal/jquery-ui-1.11.2/jquery-ui.css',
148
-			$this->assetUrl() . 'style.css',
149
-		);
150
-	}
140
+    /**
141
+     * A list of CSS files to include for this page.
142
+     *
143
+     * @return string[]
144
+     */
145
+    protected function stylesheets() {
146
+        return array(
147
+            'themes/minimal/jquery-ui-1.11.2/jquery-ui.css',
148
+            $this->assetUrl() . 'style.css',
149
+        );
150
+    }
151 151
 
152
-	/**
153
-	 * A fixed string to identify this theme, in settings, etc.
154
-	 *
155
-	 * @return string
156
-	 */
157
-	public function themeId() {
158
-		return 'minimal';
159
-	}
152
+    /**
153
+     * A fixed string to identify this theme, in settings, etc.
154
+     *
155
+     * @return string
156
+     */
157
+    public function themeId() {
158
+        return 'minimal';
159
+    }
160 160
 
161
-	/**
162
-	 * What is this theme called?
163
-	 *
164
-	 * @return string
165
-	 */
166
-	public function themeName() {
167
-		return /* I18N: Name of a theme. */ I18N::translate('minimal');
168
-	}
161
+    /**
162
+     * What is this theme called?
163
+     *
164
+     * @return string
165
+     */
166
+    public function themeName() {
167
+        return /* I18N: Name of a theme. */ I18N::translate('minimal');
168
+    }
169 169
 }
Please login to merge, or discard this patch.
Braces   +24 added lines, -12 removed lines patch added patch discarded remove patch
@@ -20,13 +20,15 @@  discard block
 block discarded – undo
20 20
 /**
21 21
  * The Minimal theme.
22 22
  */
23
-class MinimalTheme extends AbstractTheme implements ThemeInterface {
23
+class MinimalTheme extends AbstractTheme implements ThemeInterface
24
+{
24 25
 	/**
25 26
 	 * Where are our CSS, JS and other assets?
26 27
 	 *
27 28
 	 * @return string A relative path, such as "themes/foo/"
28 29
 	 */
29
-	public function assetUrl() {
30
+	public function assetUrl()
31
+	{
30 32
 		return 'themes/minimal/css-1.7.8/';
31 33
 	}
32 34
 
@@ -37,7 +39,8 @@  discard block
 block discarded – undo
37 39
 	 *
38 40
 	 * @return string
39 41
 	 */
40
-	protected function flashMessageContainer(\stdClass $message) {
42
+	protected function flashMessageContainer(\stdClass $message)
43
+	{
41 44
 		// This theme uses jQueryUI markup.
42 45
 		switch ($message->status) {
43 46
 		case 'danger':
@@ -52,7 +55,8 @@  discard block
 block discarded – undo
52 55
 	 *
53 56
 	 * @return string
54 57
 	 */
55
-	protected function formQuickSearchFields() {
58
+	protected function formQuickSearchFields()
59
+	{
56 60
 		return
57 61
 			'<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
58 62
 	}
@@ -62,7 +66,8 @@  discard block
 block discarded – undo
62 66
 	 *
63 67
 	 * @return string
64 68
 	 */
65
-	protected function formatSecondaryMenu() {
69
+	protected function formatSecondaryMenu()
70
+	{
66 71
 		return
67 72
 			'<ul class="secondary-menu">' .
68 73
 			implode('', $this->secondaryMenu()) .
@@ -77,7 +82,8 @@  discard block
 block discarded – undo
77 82
 	 *
78 83
 	 * @return string
79 84
 	 */
80
-	protected function headerContent() {
85
+	protected function headerContent()
86
+	{
81 87
 		return
82 88
 			//$this->accessibilityLinks() .
83 89
 			$this->formatTreeTitle() .
@@ -89,7 +95,8 @@  discard block
 block discarded – undo
89 95
 	 *
90 96
 	 * @return string
91 97
 	 */
92
-	protected function logoPoweredBy() {
98
+	protected function logoPoweredBy()
99
+	{
93 100
 		return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '">' . WT_WEBTREES . '</a>';
94 101
 	}
95 102
 
@@ -98,7 +105,8 @@  discard block
 block discarded – undo
98 105
 	 *
99 106
 	 * @return string
100 107
 	 */
101
-	public function hookFooterExtraJavascript() {
108
+	public function hookFooterExtraJavascript()
109
+	{
102 110
 		return
103 111
 			'<script src="' . WT_JQUERY_COLORBOX_URL . '"></script>' .
104 112
 			'<script src="' . WT_JQUERY_WHEELZOOM_URL . '"></script>' .
@@ -122,7 +130,8 @@  discard block
 block discarded – undo
122 130
 	 *
123 131
 	 * @return string|int|float
124 132
 	 */
125
-	public function parameter($parameter_name) {
133
+	public function parameter($parameter_name)
134
+	{
126 135
 		$parameters = array(
127 136
 			'chart-background-f'             => 'dddddd',
128 137
 			'chart-background-m'             => 'cccccc',
@@ -142,7 +151,8 @@  discard block
 block discarded – undo
142 151
 	 *
143 152
 	 * @return string[]
144 153
 	 */
145
-	protected function stylesheets() {
154
+	protected function stylesheets()
155
+	{
146 156
 		return array(
147 157
 			'themes/minimal/jquery-ui-1.11.2/jquery-ui.css',
148 158
 			$this->assetUrl() . 'style.css',
@@ -154,7 +164,8 @@  discard block
 block discarded – undo
154 164
 	 *
155 165
 	 * @return string
156 166
 	 */
157
-	public function themeId() {
167
+	public function themeId()
168
+	{
158 169
 		return 'minimal';
159 170
 	}
160 171
 
@@ -163,7 +174,8 @@  discard block
 block discarded – undo
163 174
 	 *
164 175
 	 * @return string
165 176
 	 */
166
-	public function themeName() {
177
+	public function themeName()
178
+	{
167 179
 		return /* I18N: Name of a theme. */ I18N::translate('minimal');
168 180
 	}
169 181
 }
Please login to merge, or discard this patch.
Switch Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -42,10 +42,10 @@
 block discarded – undo
42 42
 	protected function flashMessageContainer(\stdClass $message) {
43 43
 		// This theme uses jQueryUI markup.
44 44
 		switch ($message->status) {
45
-		case 'danger':
46
-			return '<p class="ui-state-error">' . $message->text . '</p>';
47
-		default:
48
-			return '<p class="ui-state-highlight">' . $message->text . '</p>';
45
+		    case 'danger':
46
+			    return '<p class="ui-state-error">' . $message->text . '</p>';
47
+		    default:
48
+			    return '<p class="ui-state-highlight">' . $message->text . '</p>';
49 49
 		}
50 50
 	}
51 51
 
Please login to merge, or discard this patch.
app/Media.php 3 patches
Indentation   +595 added lines, -595 removed lines patch added patch discarded remove patch
@@ -23,599 +23,599 @@
 block discarded – undo
23 23
  * A GEDCOM media (OBJE) object.
24 24
  */
25 25
 class Media extends GedcomRecord {
26
-	const RECORD_TYPE = 'OBJE';
27
-	const URL_PREFIX  = 'mediaviewer.php?mid=';
28
-
29
-	/** @var string The "TITL" value from the GEDCOM */
30
-	private $title = '';
31
-
32
-	/** @var string The "FILE" value from the GEDCOM */
33
-	private $file = '';
34
-
35
-	/**
36
-	 * Create a GedcomRecord object from raw GEDCOM data.
37
-	 *
38
-	 * @param string      $xref
39
-	 * @param string      $gedcom  an empty string for new/pending records
40
-	 * @param string|null $pending null for a record with no pending edits,
41
-	 *                             empty string for records with pending deletions
42
-	 * @param Tree        $tree
43
-	 */
44
-	public function __construct($xref, $gedcom, $pending, $tree) {
45
-		parent::__construct($xref, $gedcom, $pending, $tree);
46
-
47
-		if (preg_match('/\n1 FILE (.+)/', $gedcom . $pending, $match)) {
48
-			$this->file = $match[1];
49
-		}
50
-		if (preg_match('/\n\d TITL (.+)/', $gedcom . $pending, $match)) {
51
-			$this->title = $match[1];
52
-		}
53
-	}
54
-
55
-	/**
56
-	 * Each object type may have its own special rules, and re-implement this function.
57
-	 *
58
-	 * @param int $access_level
59
-	 *
60
-	 * @return bool
61
-	 */
62
-	protected function canShowByType($access_level) {
63
-		// Hide media objects if they are attached to private records
64
-		$linked_ids = Database::prepare(
65
-			"SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?"
66
-		)->execute(array(
67
-			$this->xref, $this->tree->getTreeId(),
68
-		))->fetchOneColumn();
69
-		foreach ($linked_ids as $linked_id) {
70
-			$linked_record = GedcomRecord::getInstance($linked_id, $this->tree);
71
-			if ($linked_record && !$linked_record->canShow($access_level)) {
72
-				return false;
73
-			}
74
-		}
75
-
76
-		// ... otherwise apply default behaviour
77
-		return parent::canShowByType($access_level);
78
-	}
79
-
80
-	/**
81
-	 * Fetch data from the database
82
-	 *
83
-	 * @param string $xref
84
-	 * @param int    $tree_id
85
-	 *
86
-	 * @return null|string
87
-	 */
88
-	protected static function fetchGedcomRecord($xref, $tree_id) {
89
-		return Database::prepare(
90
-			"SELECT m_gedcom FROM `##media` WHERE m_id = :xref AND m_file = :tree_id"
91
-		)->execute(array(
92
-			'xref'    => $xref,
93
-			'tree_id' => $tree_id,
94
-		))->fetchOne();
95
-	}
96
-
97
-	/**
98
-	 * Get the first note attached to this media object
99
-	 *
100
-	 * @return null|string
101
-	 */
102
-	public function getNote() {
103
-		$note = $this->getFirstFact('NOTE');
104
-		if ($note) {
105
-			$text = $note->getValue();
106
-			if (preg_match('/^@' . WT_REGEX_XREF . '@$/', $text)) {
107
-				$text = $note->getTarget()->getNote();
108
-			}
109
-
110
-			return $text;
111
-		} else {
112
-			return '';
113
-		}
114
-	}
115
-
116
-	/**
117
-	 * Get the main media filename
118
-	 *
119
-	 * @return string
120
-	 */
121
-	public function getFilename() {
122
-		return $this->file;
123
-	}
124
-
125
-	/**
126
-	 * Get the media's title (name)
127
-	 *
128
-	 * @return string
129
-	 */
130
-	public function getTitle() {
131
-		return $this->title;
132
-	}
133
-
134
-	/**
135
-	 * Get the filename on the server - for those (very few!) functions which actually
136
-	 * need the filename, such as mediafirewall.php and the PDF reports.
137
-	 *
138
-	 * @param string $which
139
-	 *
140
-	 * @return string
141
-	 */
142
-	public function getServerFilename($which = 'main') {
143
-		$MEDIA_DIRECTORY = $this->tree->getPreference('MEDIA_DIRECTORY');
144
-		$THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
145
-
146
-		if ($this->isExternal() || !$this->file) {
147
-			// External image, or (in the case of corrupt GEDCOM data) no image at all
148
-			return $this->file;
149
-		} elseif ($which == 'main') {
150
-			// Main image
151
-			return WT_DATA_DIR . $MEDIA_DIRECTORY . $this->file;
152
-		} else {
153
-			// Thumbnail
154
-			$file = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $this->file;
155
-			// Does the thumbnail exist?
156
-			if (file_exists($file)) {
157
-				return $file;
158
-			}
159
-			// Does a user-generated thumbnail exist?
160
-			$user_thumb = preg_replace('/\.[a-z0-9]{3,5}$/i', '.png', $file);
161
-			if (file_exists($user_thumb)) {
162
-				return $user_thumb;
163
-			}
164
-			// Does the folder exist for this thumbnail?
165
-			if (!is_dir(dirname($file)) && !File::mkdir(dirname($file))) {
166
-				Log::addMediaLog('The folder ' . dirname($file) . ' could not be created for ' . $this->getXref());
167
-
168
-				return $file;
169
-			}
170
-			// Is there a corresponding main image?
171
-			$main_file = WT_DATA_DIR . $MEDIA_DIRECTORY . $this->file;
172
-			if (!file_exists($main_file)) {
173
-				Log::addMediaLog('The file ' . $main_file . ' does not exist for ' . $this->getXref());
174
-
175
-				return $file;
176
-			}
177
-			// Try to create a thumbnail automatically
178
-
179
-			try {
180
-				$imgsize = getimagesize($main_file);
181
-				// Image small enough to be its own thumbnail?
182
-				if ($imgsize[0] > 0 && $imgsize[0] <= $THUMBNAIL_WIDTH) {
183
-					try {
184
-						copy($main_file, $file);
185
-						Log::addMediaLog('Thumbnail created for ' . $main_file . ' (copy of main image)');
186
-					} catch (\ErrorException $ex) {
187
-						Log::addMediaLog('Thumbnail could not be created for ' . $main_file . ' (copy of main image)');
188
-					}
189
-				} else {
190
-					if (FunctionsMedia::hasMemoryForImage($main_file)) {
191
-						try {
192
-							switch ($imgsize['mime']) {
193
-							case 'image/png':
194
-								$main_image = imagecreatefrompng($main_file);
195
-								break;
196
-							case 'image/gif':
197
-								$main_image = imagecreatefromgif($main_file);
198
-								break;
199
-							case 'image/jpeg':
200
-								$main_image = imagecreatefromjpeg($main_file);
201
-								break;
202
-							default:
203
-								return $file; // Nothing else we can do :-(
204
-							}
205
-							if ($main_image) {
206
-								// How big should the thumbnail be?
207
-								$width       = $THUMBNAIL_WIDTH;
208
-								$height      = round($imgsize[1] * ($width / $imgsize[0]));
209
-								$thumb_image = imagecreatetruecolor($width, $height);
210
-								// Create a transparent background, instead of the default black one
211
-								imagesavealpha($thumb_image, true);
212
-								imagefill($thumb_image, 0, 0, imagecolorallocatealpha($thumb_image, 0, 0, 0, 127));
213
-								// Shrink the image
214
-								imagecopyresampled($thumb_image, $main_image, 0, 0, 0, 0, $width, $height, $imgsize[0], $imgsize[1]);
215
-								switch ($imgsize['mime']) {
216
-								case 'image/png':
217
-									imagepng($thumb_image, $file);
218
-									break;
219
-								case 'image/gif':
220
-									imagegif($thumb_image, $file);
221
-									break;
222
-								case 'image/jpeg':
223
-									imagejpeg($thumb_image, $file);
224
-									break;
225
-								}
226
-								imagedestroy($main_image);
227
-								imagedestroy($thumb_image);
228
-								Log::addMediaLog('Thumbnail created for ' . $main_file);
229
-							}
230
-						} catch (\ErrorException $ex) {
231
-							Log::addMediaLog('Failed to create thumbnail for ' . $main_file . ' (' . $ex . ')');
232
-						}
233
-					} else {
234
-						Log::addMediaLog('Not enough memory to create thumbnail for ' . $main_file);
235
-					}
236
-				}
237
-			} catch (\ErrorException $ex) {
238
-				// Not an image, or not a valid image?
239
-			}
240
-
241
-			return $file;
242
-		}
243
-	}
244
-
245
-	/**
246
-	 * check if the file exists on this server
247
-	 *
248
-	 * @param string $which specify either 'main' or 'thumb'
249
-	 *
250
-	 * @return bool
251
-	 */
252
-	public function fileExists($which = 'main') {
253
-		return file_exists($this->getServerFilename($which));
254
-	}
255
-
256
-	/**
257
-	 * Determine if the file is an external url
258
-	 *
259
-	 * @return bool
260
-	 */
261
-	public function isExternal() {
262
-		return strpos($this->file, '://') !== false;
263
-	}
264
-
265
-	/**
266
-	 * get the media file size in KB
267
-	 *
268
-	 * @param string $which specify either 'main' or 'thumb'
269
-	 *
270
-	 * @return string
271
-	 */
272
-	public function getFilesize($which = 'main') {
273
-		$size = $this->getFilesizeraw($which);
274
-		// Round up to the nearest KB.
275
-		$size = (int) (($size + 1023) / 1024);
276
-
277
-		return /* I18N: size of file in KB */ I18N::translate('%s KB', I18N::number($size));
278
-	}
279
-
280
-	/**
281
-	 * get the media file size, unformatted
282
-	 *
283
-	 * @param string $which specify either 'main' or 'thumb'
284
-	 *
285
-	 * @return int
286
-	 */
287
-	public function getFilesizeraw($which = 'main') {
288
-		try {
289
-			return filesize($this->getServerFilename($which));
290
-		} catch (\ErrorException $ex) {
291
-			return 0;
292
-		}
293
-	}
294
-
295
-	/**
296
-	 * get filemtime for the media file
297
-	 *
298
-	 * @param string $which specify either 'main' or 'thumb'
299
-	 *
300
-	 * @return int
301
-	 */
302
-	public function getFiletime($which = 'main') {
303
-		try {
304
-			return filemtime($this->getServerFilename($which));
305
-		} catch (\ErrorException $ex) {
306
-			return 0;
307
-		}
308
-	}
309
-
310
-	/**
311
-	 * Generate an etag specific to this media item and the current user
312
-	 *
313
-	 * @param string $which - specify either 'main' or 'thumb'
314
-	 *
315
-	 * @return string
316
-	 */
317
-	public function getEtag($which = 'main') {
318
-		if ($this->isExternal()) {
319
-			// etag not really defined for external media
320
-
321
-			return '';
322
-		}
323
-		$etag_string = basename($this->getServerFilename($which)) . $this->getFiletime($which) . $this->tree->getName() . Auth::accessLevel($this->tree) . $this->tree->getPreference('SHOW_NO_WATERMARK');
324
-		$etag_string = dechex(crc32($etag_string));
325
-
326
-		return $etag_string;
327
-	}
328
-
329
-	/**
330
-	 * Deprecated? This does not need to be a function here.
331
-	 *
332
-	 * @return string
333
-	 */
334
-	public function getMediaType() {
335
-		if (preg_match('/\n\d TYPE (.+)/', $this->gedcom, $match)) {
336
-			return strtolower($match[1]);
337
-		} else {
338
-			return '';
339
-		}
340
-	}
341
-
342
-	/**
343
-	 * Is this object marked as a highlighted image?
344
-	 *
345
-	 * @return string
346
-	 */
347
-	public function isPrimary() {
348
-		if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcom(), $match)) {
349
-			return $match[1];
350
-		} else {
351
-			return '';
352
-		}
353
-	}
354
-
355
-	/**
356
-	 * get image properties
357
-	 *
358
-	 * @param string $which     specify either 'main' or 'thumb'
359
-	 * @param int    $addWidth  amount to add to width
360
-	 * @param int    $addHeight amount to add to height
361
-	 *
362
-	 * @return array
363
-	 */
364
-	public function getImageAttributes($which = 'main', $addWidth = 0, $addHeight = 0) {
365
-		$THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
366
-
367
-		$var = $which . 'imagesize';
368
-		if (!empty($this->$var)) {
369
-			return $this->$var;
370
-		}
371
-		$imgsize = array();
372
-		if ($this->fileExists($which)) {
373
-
374
-			try {
375
-				$imgsize = getimagesize($this->getServerFilename($which));
376
-				if (is_array($imgsize) && !empty($imgsize['0'])) {
377
-					// this is an image
378
-					$imgsize[0]      = $imgsize[0] + 0;
379
-					$imgsize[1]      = $imgsize[1] + 0;
380
-					$imgsize['adjW'] = $imgsize[0] + $addWidth; // adjusted width
381
-					$imgsize['adjH'] = $imgsize[1] + $addHeight; // adjusted height
382
-					$imageTypes      = array('', 'GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF', 'TIFF', 'JPC', 'JP2', 'JPX', 'JB2', 'SWC', 'IFF', 'WBMP', 'XBM');
383
-					$imgsize['ext']  = $imageTypes[0 + $imgsize[2]];
384
-					// this is for display purposes, always show non-adjusted info
385
-					$imgsize['WxH']   =
386
-						/* I18N: image dimensions, width × height */
387
-						I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1']));
388
-					$imgsize['imgWH'] = ' width="' . $imgsize['adjW'] . '" height="' . $imgsize['adjH'] . '" ';
389
-					if (($which == 'thumb') && ($imgsize['0'] > $THUMBNAIL_WIDTH)) {
390
-						// don’t let large images break the dislay
391
-						$imgsize['imgWH'] = ' width="' . $THUMBNAIL_WIDTH . '" ';
392
-					}
393
-				}
394
-			} catch (\ErrorException $ex) {
395
-				// Not an image, or not a valid image?
396
-				$imgsize = false;
397
-			}
398
-		}
399
-
400
-		if (!is_array($imgsize) || empty($imgsize['0'])) {
401
-			// this is not an image, OR the file doesn’t exist OR it is a url
402
-			$imgsize[0]       = 0;
403
-			$imgsize[1]       = 0;
404
-			$imgsize['adjW']  = 0;
405
-			$imgsize['adjH']  = 0;
406
-			$imgsize['ext']   = '';
407
-			$imgsize['mime']  = '';
408
-			$imgsize['WxH']   = '';
409
-			$imgsize['imgWH'] = '';
410
-			if ($this->isExternal()) {
411
-				// don’t let large external images break the dislay
412
-				$imgsize['imgWH'] = ' width="' . $THUMBNAIL_WIDTH . '" ';
413
-			}
414
-		}
415
-
416
-		if (empty($imgsize['mime'])) {
417
-			// this is not an image, OR the file doesn’t exist OR it is a url
418
-			// set file type equal to the file extension - can’t use parse_url because this may not be a full url
419
-			$exp            = explode('?', $this->file);
420
-			$imgsize['ext'] = strtoupper(pathinfo($exp[0], PATHINFO_EXTENSION));
421
-			// all mimetypes we wish to serve with the media firewall must be added to this array.
422
-			$mime = array(
423
-				'DOC' => 'application/msword',
424
-				'MOV' => 'video/quicktime',
425
-				'MP3' => 'audio/mpeg',
426
-				'PDF' => 'application/pdf',
427
-				'PPT' => 'application/vnd.ms-powerpoint',
428
-				'RTF' => 'text/rtf',
429
-				'SID' => 'image/x-mrsid',
430
-				'TXT' => 'text/plain',
431
-				'XLS' => 'application/vnd.ms-excel',
432
-				'WMV' => 'video/x-ms-wmv',
433
-			);
434
-			if (empty($mime[$imgsize['ext']])) {
435
-				// if we don’t know what the mimetype is, use something ambiguous
436
-				$imgsize['mime'] = 'application/octet-stream';
437
-				if ($this->fileExists($which)) {
438
-					// alert the admin if we cannot determine the mime type of an existing file
439
-					// as the media firewall will be unable to serve this file properly
440
-					Log::addMediaLog('Media Firewall error: >Unknown Mimetype< for file >' . $this->file . '<');
441
-				}
442
-			} else {
443
-				$imgsize['mime'] = $mime[$imgsize['ext']];
444
-			}
445
-		}
446
-		$this->$var = $imgsize;
447
-
448
-		return $this->$var;
449
-	}
450
-
451
-	/**
452
-	 * Generate a URL directly to the media file
453
-	 *
454
-	 * @param string $which
455
-	 * @param bool   $download
456
-	 *
457
-	 * @return string
458
-	 */
459
-	public function getHtmlUrlDirect($which = 'main', $download = false) {
460
-		// “cb” is “cache buster”, so clients will make new request if anything significant about the user or the file changes
461
-		// The extension is there so that image viewers (e.g. colorbox) can do something sensible
462
-		$thumbstr    = ($which == 'thumb') ? '&amp;thumb=1' : '';
463
-		$downloadstr = ($download) ? '&dl=1' : '';
464
-
465
-		return
466
-			'mediafirewall.php?mid=' . $this->getXref() . $thumbstr . $downloadstr .
467
-			'&amp;ged=' . $this->tree->getNameUrl() .
468
-			'&amp;cb=' . $this->getEtag($which);
469
-	}
470
-
471
-	/**
472
-	 * What file extension is used by this file?
473
-	 *
474
-	 * @return string
475
-	 */
476
-	public function extension() {
477
-		if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->file, $match)) {
478
-			return strtolower($match[1]);
479
-		} else {
480
-			return '';
481
-		}
482
-	}
483
-
484
-	/**
485
-	 * What is the mime-type of this object?
486
-	 * For simplicity and efficiency, use the extension, rather than the contents.
487
-	 *
488
-	 * @return string
489
-	 */
490
-	public function mimeType() {
491
-		// Themes contain icon definitions for some/all of these mime-types
492
-		switch ($this->extension()) {
493
-		case 'bmp':
494
-			return 'image/bmp';
495
-		case 'doc':
496
-			return 'application/msword';
497
-		case 'docx':
498
-			return 'application/msword';
499
-		case 'ged':
500
-			return 'text/x-gedcom';
501
-		case 'gif':
502
-			return 'image/gif';
503
-		case 'htm':
504
-			return 'text/html';
505
-		case 'html':
506
-			return 'text/html';
507
-		case 'jpeg':
508
-			return 'image/jpeg';
509
-		case 'jpg':
510
-			return 'image/jpeg';
511
-		case 'mov':
512
-			return 'video/quicktime';
513
-		case 'mp3':
514
-			return 'audio/mpeg';
515
-		case 'ogv':
516
-			return 'video/ogg';
517
-		case 'pdf':
518
-			return 'application/pdf';
519
-		case 'png':
520
-			return 'image/png';
521
-		case 'rar':
522
-			return 'application/x-rar-compressed';
523
-		case 'swf':
524
-			return 'application/x-shockwave-flash';
525
-		case 'svg':
526
-			return 'image/svg';
527
-		case 'tif':
528
-			return 'image/tiff';
529
-		case 'tiff':
530
-			return 'image/tiff';
531
-		case 'xls':
532
-			return 'application/vnd-ms-excel';
533
-		case 'xlsx':
534
-			return 'application/vnd-ms-excel';
535
-		case 'wmv':
536
-			return 'video/x-ms-wmv';
537
-		case 'zip':
538
-			return 'application/zip';
539
-		default:
540
-			return 'application/octet-stream';
541
-		}
542
-	}
543
-
544
-	/**
545
-	 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
546
-	 *
547
-	 * @return string
548
-	 */
549
-	public function displayImage() {
550
-		// Default image for external, missing or corrupt images.
551
-		$image =
552
-			'<i' .
553
-			' dir="' . 'auto' . '"' . // For the tool-tip
554
-			' class="' . 'icon-mime-' . str_replace('/', '-', $this->mimeType()) . '"' .
555
-			' title="' . strip_tags($this->getFullName()) . '"' .
556
-			'></i>';
557
-
558
-		// Use a thumbnail image.
559
-		if (!$this->isExternal()) {
560
-			try {
561
-				$imgsize = getimagesize($this->getServerFilename('thumb'));
562
-				$image   =
563
-					'<img' .
564
-					' dir="' . 'auto' . '"' . // For the tool-tip
565
-					' src="' . $this->getHtmlUrlDirect('thumb') . '"' .
566
-					' alt="' . strip_tags($this->getFullName()) . '"' .
567
-					' title="' . strip_tags($this->getFullName()) . '"' .
568
-					' ' . $imgsize[3] . // height="yyy" width="xxx"
569
-					'>';
570
-			} catch (Exception $ex) {
571
-				// Image file unreadable or Corrupt.
572
-			}
573
-		}
574
-
575
-		return
576
-			'<a' .
577
-			' class="' . 'gallery' . '"' .
578
-			' href="' . $this->getHtmlUrlDirect('main') . '"' .
579
-			' type="' . $this->mimeType() . '"' .
580
-			' data-obje-url="' . $this->getHtmlUrl() . '"' .
581
-			' data-obje-note="' . Filter::escapeHtml($this->getNote()) . '"' .
582
-			' data-title="' . Filter::escapeHtml($this->getFullName()) . '"' .
583
-			'>' . $image . '</a>';
584
-	}
585
-
586
-	/**
587
-	 * If this object has no name, what do we call it?
588
-	 *
589
-	 * @return string
590
-	 */
591
-	public function getFallBackName() {
592
-		if ($this->canShow()) {
593
-			return basename($this->file);
594
-		} else {
595
-			return $this->getXref();
596
-		}
597
-	}
598
-
599
-	/**
600
-	 * Extract names from the GEDCOM record.
601
-	 */
602
-	public function extractNames() {
603
-		// Earlier gedcom versions had level 1 titles
604
-		// Later gedcom versions had level 2 titles
605
-		$this->extractNamesFromFacts(2, 'TITL', $this->getFacts('FILE'));
606
-		$this->extractNamesFromFacts(1, 'TITL', $this->getFacts('TITL'));
607
-	}
608
-
609
-	/**
610
-	 * This function should be redefined in derived classes to show any major
611
-	 * identifying characteristics of this record.
612
-	 *
613
-	 * @return string
614
-	 */
615
-	public function formatListDetails() {
616
-		ob_start();
617
-		FunctionsPrintFacts::printMediaLinks('1 OBJE @' . $this->getXref() . '@', 1);
618
-
619
-		return ob_get_clean();
620
-	}
26
+    const RECORD_TYPE = 'OBJE';
27
+    const URL_PREFIX  = 'mediaviewer.php?mid=';
28
+
29
+    /** @var string The "TITL" value from the GEDCOM */
30
+    private $title = '';
31
+
32
+    /** @var string The "FILE" value from the GEDCOM */
33
+    private $file = '';
34
+
35
+    /**
36
+     * Create a GedcomRecord object from raw GEDCOM data.
37
+     *
38
+     * @param string      $xref
39
+     * @param string      $gedcom  an empty string for new/pending records
40
+     * @param string|null $pending null for a record with no pending edits,
41
+     *                             empty string for records with pending deletions
42
+     * @param Tree        $tree
43
+     */
44
+    public function __construct($xref, $gedcom, $pending, $tree) {
45
+        parent::__construct($xref, $gedcom, $pending, $tree);
46
+
47
+        if (preg_match('/\n1 FILE (.+)/', $gedcom . $pending, $match)) {
48
+            $this->file = $match[1];
49
+        }
50
+        if (preg_match('/\n\d TITL (.+)/', $gedcom . $pending, $match)) {
51
+            $this->title = $match[1];
52
+        }
53
+    }
54
+
55
+    /**
56
+     * Each object type may have its own special rules, and re-implement this function.
57
+     *
58
+     * @param int $access_level
59
+     *
60
+     * @return bool
61
+     */
62
+    protected function canShowByType($access_level) {
63
+        // Hide media objects if they are attached to private records
64
+        $linked_ids = Database::prepare(
65
+            "SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?"
66
+        )->execute(array(
67
+            $this->xref, $this->tree->getTreeId(),
68
+        ))->fetchOneColumn();
69
+        foreach ($linked_ids as $linked_id) {
70
+            $linked_record = GedcomRecord::getInstance($linked_id, $this->tree);
71
+            if ($linked_record && !$linked_record->canShow($access_level)) {
72
+                return false;
73
+            }
74
+        }
75
+
76
+        // ... otherwise apply default behaviour
77
+        return parent::canShowByType($access_level);
78
+    }
79
+
80
+    /**
81
+     * Fetch data from the database
82
+     *
83
+     * @param string $xref
84
+     * @param int    $tree_id
85
+     *
86
+     * @return null|string
87
+     */
88
+    protected static function fetchGedcomRecord($xref, $tree_id) {
89
+        return Database::prepare(
90
+            "SELECT m_gedcom FROM `##media` WHERE m_id = :xref AND m_file = :tree_id"
91
+        )->execute(array(
92
+            'xref'    => $xref,
93
+            'tree_id' => $tree_id,
94
+        ))->fetchOne();
95
+    }
96
+
97
+    /**
98
+     * Get the first note attached to this media object
99
+     *
100
+     * @return null|string
101
+     */
102
+    public function getNote() {
103
+        $note = $this->getFirstFact('NOTE');
104
+        if ($note) {
105
+            $text = $note->getValue();
106
+            if (preg_match('/^@' . WT_REGEX_XREF . '@$/', $text)) {
107
+                $text = $note->getTarget()->getNote();
108
+            }
109
+
110
+            return $text;
111
+        } else {
112
+            return '';
113
+        }
114
+    }
115
+
116
+    /**
117
+     * Get the main media filename
118
+     *
119
+     * @return string
120
+     */
121
+    public function getFilename() {
122
+        return $this->file;
123
+    }
124
+
125
+    /**
126
+     * Get the media's title (name)
127
+     *
128
+     * @return string
129
+     */
130
+    public function getTitle() {
131
+        return $this->title;
132
+    }
133
+
134
+    /**
135
+     * Get the filename on the server - for those (very few!) functions which actually
136
+     * need the filename, such as mediafirewall.php and the PDF reports.
137
+     *
138
+     * @param string $which
139
+     *
140
+     * @return string
141
+     */
142
+    public function getServerFilename($which = 'main') {
143
+        $MEDIA_DIRECTORY = $this->tree->getPreference('MEDIA_DIRECTORY');
144
+        $THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
145
+
146
+        if ($this->isExternal() || !$this->file) {
147
+            // External image, or (in the case of corrupt GEDCOM data) no image at all
148
+            return $this->file;
149
+        } elseif ($which == 'main') {
150
+            // Main image
151
+            return WT_DATA_DIR . $MEDIA_DIRECTORY . $this->file;
152
+        } else {
153
+            // Thumbnail
154
+            $file = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $this->file;
155
+            // Does the thumbnail exist?
156
+            if (file_exists($file)) {
157
+                return $file;
158
+            }
159
+            // Does a user-generated thumbnail exist?
160
+            $user_thumb = preg_replace('/\.[a-z0-9]{3,5}$/i', '.png', $file);
161
+            if (file_exists($user_thumb)) {
162
+                return $user_thumb;
163
+            }
164
+            // Does the folder exist for this thumbnail?
165
+            if (!is_dir(dirname($file)) && !File::mkdir(dirname($file))) {
166
+                Log::addMediaLog('The folder ' . dirname($file) . ' could not be created for ' . $this->getXref());
167
+
168
+                return $file;
169
+            }
170
+            // Is there a corresponding main image?
171
+            $main_file = WT_DATA_DIR . $MEDIA_DIRECTORY . $this->file;
172
+            if (!file_exists($main_file)) {
173
+                Log::addMediaLog('The file ' . $main_file . ' does not exist for ' . $this->getXref());
174
+
175
+                return $file;
176
+            }
177
+            // Try to create a thumbnail automatically
178
+
179
+            try {
180
+                $imgsize = getimagesize($main_file);
181
+                // Image small enough to be its own thumbnail?
182
+                if ($imgsize[0] > 0 && $imgsize[0] <= $THUMBNAIL_WIDTH) {
183
+                    try {
184
+                        copy($main_file, $file);
185
+                        Log::addMediaLog('Thumbnail created for ' . $main_file . ' (copy of main image)');
186
+                    } catch (\ErrorException $ex) {
187
+                        Log::addMediaLog('Thumbnail could not be created for ' . $main_file . ' (copy of main image)');
188
+                    }
189
+                } else {
190
+                    if (FunctionsMedia::hasMemoryForImage($main_file)) {
191
+                        try {
192
+                            switch ($imgsize['mime']) {
193
+                            case 'image/png':
194
+                                $main_image = imagecreatefrompng($main_file);
195
+                                break;
196
+                            case 'image/gif':
197
+                                $main_image = imagecreatefromgif($main_file);
198
+                                break;
199
+                            case 'image/jpeg':
200
+                                $main_image = imagecreatefromjpeg($main_file);
201
+                                break;
202
+                            default:
203
+                                return $file; // Nothing else we can do :-(
204
+                            }
205
+                            if ($main_image) {
206
+                                // How big should the thumbnail be?
207
+                                $width       = $THUMBNAIL_WIDTH;
208
+                                $height      = round($imgsize[1] * ($width / $imgsize[0]));
209
+                                $thumb_image = imagecreatetruecolor($width, $height);
210
+                                // Create a transparent background, instead of the default black one
211
+                                imagesavealpha($thumb_image, true);
212
+                                imagefill($thumb_image, 0, 0, imagecolorallocatealpha($thumb_image, 0, 0, 0, 127));
213
+                                // Shrink the image
214
+                                imagecopyresampled($thumb_image, $main_image, 0, 0, 0, 0, $width, $height, $imgsize[0], $imgsize[1]);
215
+                                switch ($imgsize['mime']) {
216
+                                case 'image/png':
217
+                                    imagepng($thumb_image, $file);
218
+                                    break;
219
+                                case 'image/gif':
220
+                                    imagegif($thumb_image, $file);
221
+                                    break;
222
+                                case 'image/jpeg':
223
+                                    imagejpeg($thumb_image, $file);
224
+                                    break;
225
+                                }
226
+                                imagedestroy($main_image);
227
+                                imagedestroy($thumb_image);
228
+                                Log::addMediaLog('Thumbnail created for ' . $main_file);
229
+                            }
230
+                        } catch (\ErrorException $ex) {
231
+                            Log::addMediaLog('Failed to create thumbnail for ' . $main_file . ' (' . $ex . ')');
232
+                        }
233
+                    } else {
234
+                        Log::addMediaLog('Not enough memory to create thumbnail for ' . $main_file);
235
+                    }
236
+                }
237
+            } catch (\ErrorException $ex) {
238
+                // Not an image, or not a valid image?
239
+            }
240
+
241
+            return $file;
242
+        }
243
+    }
244
+
245
+    /**
246
+     * check if the file exists on this server
247
+     *
248
+     * @param string $which specify either 'main' or 'thumb'
249
+     *
250
+     * @return bool
251
+     */
252
+    public function fileExists($which = 'main') {
253
+        return file_exists($this->getServerFilename($which));
254
+    }
255
+
256
+    /**
257
+     * Determine if the file is an external url
258
+     *
259
+     * @return bool
260
+     */
261
+    public function isExternal() {
262
+        return strpos($this->file, '://') !== false;
263
+    }
264
+
265
+    /**
266
+     * get the media file size in KB
267
+     *
268
+     * @param string $which specify either 'main' or 'thumb'
269
+     *
270
+     * @return string
271
+     */
272
+    public function getFilesize($which = 'main') {
273
+        $size = $this->getFilesizeraw($which);
274
+        // Round up to the nearest KB.
275
+        $size = (int) (($size + 1023) / 1024);
276
+
277
+        return /* I18N: size of file in KB */ I18N::translate('%s KB', I18N::number($size));
278
+    }
279
+
280
+    /**
281
+     * get the media file size, unformatted
282
+     *
283
+     * @param string $which specify either 'main' or 'thumb'
284
+     *
285
+     * @return int
286
+     */
287
+    public function getFilesizeraw($which = 'main') {
288
+        try {
289
+            return filesize($this->getServerFilename($which));
290
+        } catch (\ErrorException $ex) {
291
+            return 0;
292
+        }
293
+    }
294
+
295
+    /**
296
+     * get filemtime for the media file
297
+     *
298
+     * @param string $which specify either 'main' or 'thumb'
299
+     *
300
+     * @return int
301
+     */
302
+    public function getFiletime($which = 'main') {
303
+        try {
304
+            return filemtime($this->getServerFilename($which));
305
+        } catch (\ErrorException $ex) {
306
+            return 0;
307
+        }
308
+    }
309
+
310
+    /**
311
+     * Generate an etag specific to this media item and the current user
312
+     *
313
+     * @param string $which - specify either 'main' or 'thumb'
314
+     *
315
+     * @return string
316
+     */
317
+    public function getEtag($which = 'main') {
318
+        if ($this->isExternal()) {
319
+            // etag not really defined for external media
320
+
321
+            return '';
322
+        }
323
+        $etag_string = basename($this->getServerFilename($which)) . $this->getFiletime($which) . $this->tree->getName() . Auth::accessLevel($this->tree) . $this->tree->getPreference('SHOW_NO_WATERMARK');
324
+        $etag_string = dechex(crc32($etag_string));
325
+
326
+        return $etag_string;
327
+    }
328
+
329
+    /**
330
+     * Deprecated? This does not need to be a function here.
331
+     *
332
+     * @return string
333
+     */
334
+    public function getMediaType() {
335
+        if (preg_match('/\n\d TYPE (.+)/', $this->gedcom, $match)) {
336
+            return strtolower($match[1]);
337
+        } else {
338
+            return '';
339
+        }
340
+    }
341
+
342
+    /**
343
+     * Is this object marked as a highlighted image?
344
+     *
345
+     * @return string
346
+     */
347
+    public function isPrimary() {
348
+        if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcom(), $match)) {
349
+            return $match[1];
350
+        } else {
351
+            return '';
352
+        }
353
+    }
354
+
355
+    /**
356
+     * get image properties
357
+     *
358
+     * @param string $which     specify either 'main' or 'thumb'
359
+     * @param int    $addWidth  amount to add to width
360
+     * @param int    $addHeight amount to add to height
361
+     *
362
+     * @return array
363
+     */
364
+    public function getImageAttributes($which = 'main', $addWidth = 0, $addHeight = 0) {
365
+        $THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
366
+
367
+        $var = $which . 'imagesize';
368
+        if (!empty($this->$var)) {
369
+            return $this->$var;
370
+        }
371
+        $imgsize = array();
372
+        if ($this->fileExists($which)) {
373
+
374
+            try {
375
+                $imgsize = getimagesize($this->getServerFilename($which));
376
+                if (is_array($imgsize) && !empty($imgsize['0'])) {
377
+                    // this is an image
378
+                    $imgsize[0]      = $imgsize[0] + 0;
379
+                    $imgsize[1]      = $imgsize[1] + 0;
380
+                    $imgsize['adjW'] = $imgsize[0] + $addWidth; // adjusted width
381
+                    $imgsize['adjH'] = $imgsize[1] + $addHeight; // adjusted height
382
+                    $imageTypes      = array('', 'GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF', 'TIFF', 'JPC', 'JP2', 'JPX', 'JB2', 'SWC', 'IFF', 'WBMP', 'XBM');
383
+                    $imgsize['ext']  = $imageTypes[0 + $imgsize[2]];
384
+                    // this is for display purposes, always show non-adjusted info
385
+                    $imgsize['WxH']   =
386
+                        /* I18N: image dimensions, width × height */
387
+                        I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1']));
388
+                    $imgsize['imgWH'] = ' width="' . $imgsize['adjW'] . '" height="' . $imgsize['adjH'] . '" ';
389
+                    if (($which == 'thumb') && ($imgsize['0'] > $THUMBNAIL_WIDTH)) {
390
+                        // don’t let large images break the dislay
391
+                        $imgsize['imgWH'] = ' width="' . $THUMBNAIL_WIDTH . '" ';
392
+                    }
393
+                }
394
+            } catch (\ErrorException $ex) {
395
+                // Not an image, or not a valid image?
396
+                $imgsize = false;
397
+            }
398
+        }
399
+
400
+        if (!is_array($imgsize) || empty($imgsize['0'])) {
401
+            // this is not an image, OR the file doesn’t exist OR it is a url
402
+            $imgsize[0]       = 0;
403
+            $imgsize[1]       = 0;
404
+            $imgsize['adjW']  = 0;
405
+            $imgsize['adjH']  = 0;
406
+            $imgsize['ext']   = '';
407
+            $imgsize['mime']  = '';
408
+            $imgsize['WxH']   = '';
409
+            $imgsize['imgWH'] = '';
410
+            if ($this->isExternal()) {
411
+                // don’t let large external images break the dislay
412
+                $imgsize['imgWH'] = ' width="' . $THUMBNAIL_WIDTH . '" ';
413
+            }
414
+        }
415
+
416
+        if (empty($imgsize['mime'])) {
417
+            // this is not an image, OR the file doesn’t exist OR it is a url
418
+            // set file type equal to the file extension - can’t use parse_url because this may not be a full url
419
+            $exp            = explode('?', $this->file);
420
+            $imgsize['ext'] = strtoupper(pathinfo($exp[0], PATHINFO_EXTENSION));
421
+            // all mimetypes we wish to serve with the media firewall must be added to this array.
422
+            $mime = array(
423
+                'DOC' => 'application/msword',
424
+                'MOV' => 'video/quicktime',
425
+                'MP3' => 'audio/mpeg',
426
+                'PDF' => 'application/pdf',
427
+                'PPT' => 'application/vnd.ms-powerpoint',
428
+                'RTF' => 'text/rtf',
429
+                'SID' => 'image/x-mrsid',
430
+                'TXT' => 'text/plain',
431
+                'XLS' => 'application/vnd.ms-excel',
432
+                'WMV' => 'video/x-ms-wmv',
433
+            );
434
+            if (empty($mime[$imgsize['ext']])) {
435
+                // if we don’t know what the mimetype is, use something ambiguous
436
+                $imgsize['mime'] = 'application/octet-stream';
437
+                if ($this->fileExists($which)) {
438
+                    // alert the admin if we cannot determine the mime type of an existing file
439
+                    // as the media firewall will be unable to serve this file properly
440
+                    Log::addMediaLog('Media Firewall error: >Unknown Mimetype< for file >' . $this->file . '<');
441
+                }
442
+            } else {
443
+                $imgsize['mime'] = $mime[$imgsize['ext']];
444
+            }
445
+        }
446
+        $this->$var = $imgsize;
447
+
448
+        return $this->$var;
449
+    }
450
+
451
+    /**
452
+     * Generate a URL directly to the media file
453
+     *
454
+     * @param string $which
455
+     * @param bool   $download
456
+     *
457
+     * @return string
458
+     */
459
+    public function getHtmlUrlDirect($which = 'main', $download = false) {
460
+        // “cb” is “cache buster”, so clients will make new request if anything significant about the user or the file changes
461
+        // The extension is there so that image viewers (e.g. colorbox) can do something sensible
462
+        $thumbstr    = ($which == 'thumb') ? '&amp;thumb=1' : '';
463
+        $downloadstr = ($download) ? '&dl=1' : '';
464
+
465
+        return
466
+            'mediafirewall.php?mid=' . $this->getXref() . $thumbstr . $downloadstr .
467
+            '&amp;ged=' . $this->tree->getNameUrl() .
468
+            '&amp;cb=' . $this->getEtag($which);
469
+    }
470
+
471
+    /**
472
+     * What file extension is used by this file?
473
+     *
474
+     * @return string
475
+     */
476
+    public function extension() {
477
+        if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->file, $match)) {
478
+            return strtolower($match[1]);
479
+        } else {
480
+            return '';
481
+        }
482
+    }
483
+
484
+    /**
485
+     * What is the mime-type of this object?
486
+     * For simplicity and efficiency, use the extension, rather than the contents.
487
+     *
488
+     * @return string
489
+     */
490
+    public function mimeType() {
491
+        // Themes contain icon definitions for some/all of these mime-types
492
+        switch ($this->extension()) {
493
+        case 'bmp':
494
+            return 'image/bmp';
495
+        case 'doc':
496
+            return 'application/msword';
497
+        case 'docx':
498
+            return 'application/msword';
499
+        case 'ged':
500
+            return 'text/x-gedcom';
501
+        case 'gif':
502
+            return 'image/gif';
503
+        case 'htm':
504
+            return 'text/html';
505
+        case 'html':
506
+            return 'text/html';
507
+        case 'jpeg':
508
+            return 'image/jpeg';
509
+        case 'jpg':
510
+            return 'image/jpeg';
511
+        case 'mov':
512
+            return 'video/quicktime';
513
+        case 'mp3':
514
+            return 'audio/mpeg';
515
+        case 'ogv':
516
+            return 'video/ogg';
517
+        case 'pdf':
518
+            return 'application/pdf';
519
+        case 'png':
520
+            return 'image/png';
521
+        case 'rar':
522
+            return 'application/x-rar-compressed';
523
+        case 'swf':
524
+            return 'application/x-shockwave-flash';
525
+        case 'svg':
526
+            return 'image/svg';
527
+        case 'tif':
528
+            return 'image/tiff';
529
+        case 'tiff':
530
+            return 'image/tiff';
531
+        case 'xls':
532
+            return 'application/vnd-ms-excel';
533
+        case 'xlsx':
534
+            return 'application/vnd-ms-excel';
535
+        case 'wmv':
536
+            return 'video/x-ms-wmv';
537
+        case 'zip':
538
+            return 'application/zip';
539
+        default:
540
+            return 'application/octet-stream';
541
+        }
542
+    }
543
+
544
+    /**
545
+     * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
546
+     *
547
+     * @return string
548
+     */
549
+    public function displayImage() {
550
+        // Default image for external, missing or corrupt images.
551
+        $image =
552
+            '<i' .
553
+            ' dir="' . 'auto' . '"' . // For the tool-tip
554
+            ' class="' . 'icon-mime-' . str_replace('/', '-', $this->mimeType()) . '"' .
555
+            ' title="' . strip_tags($this->getFullName()) . '"' .
556
+            '></i>';
557
+
558
+        // Use a thumbnail image.
559
+        if (!$this->isExternal()) {
560
+            try {
561
+                $imgsize = getimagesize($this->getServerFilename('thumb'));
562
+                $image   =
563
+                    '<img' .
564
+                    ' dir="' . 'auto' . '"' . // For the tool-tip
565
+                    ' src="' . $this->getHtmlUrlDirect('thumb') . '"' .
566
+                    ' alt="' . strip_tags($this->getFullName()) . '"' .
567
+                    ' title="' . strip_tags($this->getFullName()) . '"' .
568
+                    ' ' . $imgsize[3] . // height="yyy" width="xxx"
569
+                    '>';
570
+            } catch (Exception $ex) {
571
+                // Image file unreadable or Corrupt.
572
+            }
573
+        }
574
+
575
+        return
576
+            '<a' .
577
+            ' class="' . 'gallery' . '"' .
578
+            ' href="' . $this->getHtmlUrlDirect('main') . '"' .
579
+            ' type="' . $this->mimeType() . '"' .
580
+            ' data-obje-url="' . $this->getHtmlUrl() . '"' .
581
+            ' data-obje-note="' . Filter::escapeHtml($this->getNote()) . '"' .
582
+            ' data-title="' . Filter::escapeHtml($this->getFullName()) . '"' .
583
+            '>' . $image . '</a>';
584
+    }
585
+
586
+    /**
587
+     * If this object has no name, what do we call it?
588
+     *
589
+     * @return string
590
+     */
591
+    public function getFallBackName() {
592
+        if ($this->canShow()) {
593
+            return basename($this->file);
594
+        } else {
595
+            return $this->getXref();
596
+        }
597
+    }
598
+
599
+    /**
600
+     * Extract names from the GEDCOM record.
601
+     */
602
+    public function extractNames() {
603
+        // Earlier gedcom versions had level 1 titles
604
+        // Later gedcom versions had level 2 titles
605
+        $this->extractNamesFromFacts(2, 'TITL', $this->getFacts('FILE'));
606
+        $this->extractNamesFromFacts(1, 'TITL', $this->getFacts('TITL'));
607
+    }
608
+
609
+    /**
610
+     * This function should be redefined in derived classes to show any major
611
+     * identifying characteristics of this record.
612
+     *
613
+     * @return string
614
+     */
615
+    public function formatListDetails() {
616
+        ob_start();
617
+        FunctionsPrintFacts::printMediaLinks('1 OBJE @' . $this->getXref() . '@', 1);
618
+
619
+        return ob_get_clean();
620
+    }
621 621
 }
Please login to merge, or discard this patch.
Switch Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -190,17 +190,17 @@  discard block
 block discarded – undo
190 190
 					if (FunctionsMedia::hasMemoryForImage($main_file)) {
191 191
 						try {
192 192
 							switch ($imgsize['mime']) {
193
-							case 'image/png':
194
-								$main_image = imagecreatefrompng($main_file);
195
-								break;
196
-							case 'image/gif':
197
-								$main_image = imagecreatefromgif($main_file);
198
-								break;
199
-							case 'image/jpeg':
200
-								$main_image = imagecreatefromjpeg($main_file);
201
-								break;
202
-							default:
203
-								return $file; // Nothing else we can do :-(
193
+							    case 'image/png':
194
+								    $main_image = imagecreatefrompng($main_file);
195
+								    break;
196
+							    case 'image/gif':
197
+								    $main_image = imagecreatefromgif($main_file);
198
+								    break;
199
+							    case 'image/jpeg':
200
+								    $main_image = imagecreatefromjpeg($main_file);
201
+								    break;
202
+							    default:
203
+								    return $file; // Nothing else we can do :-(
204 204
 							}
205 205
 							if ($main_image) {
206 206
 								// How big should the thumbnail be?
@@ -213,15 +213,15 @@  discard block
 block discarded – undo
213 213
 								// Shrink the image
214 214
 								imagecopyresampled($thumb_image, $main_image, 0, 0, 0, 0, $width, $height, $imgsize[0], $imgsize[1]);
215 215
 								switch ($imgsize['mime']) {
216
-								case 'image/png':
217
-									imagepng($thumb_image, $file);
218
-									break;
219
-								case 'image/gif':
220
-									imagegif($thumb_image, $file);
221
-									break;
222
-								case 'image/jpeg':
223
-									imagejpeg($thumb_image, $file);
224
-									break;
216
+								    case 'image/png':
217
+									    imagepng($thumb_image, $file);
218
+									    break;
219
+								    case 'image/gif':
220
+									    imagegif($thumb_image, $file);
221
+									    break;
222
+								    case 'image/jpeg':
223
+									    imagejpeg($thumb_image, $file);
224
+									    break;
225 225
 								}
226 226
 								imagedestroy($main_image);
227 227
 								imagedestroy($thumb_image);
@@ -490,54 +490,54 @@  discard block
 block discarded – undo
490 490
 	public function mimeType() {
491 491
 		// Themes contain icon definitions for some/all of these mime-types
492 492
 		switch ($this->extension()) {
493
-		case 'bmp':
494
-			return 'image/bmp';
495
-		case 'doc':
496
-			return 'application/msword';
497
-		case 'docx':
498
-			return 'application/msword';
499
-		case 'ged':
500
-			return 'text/x-gedcom';
501
-		case 'gif':
502
-			return 'image/gif';
503
-		case 'htm':
504
-			return 'text/html';
505
-		case 'html':
506
-			return 'text/html';
507
-		case 'jpeg':
508
-			return 'image/jpeg';
509
-		case 'jpg':
510
-			return 'image/jpeg';
511
-		case 'mov':
512
-			return 'video/quicktime';
513
-		case 'mp3':
514
-			return 'audio/mpeg';
515
-		case 'ogv':
516
-			return 'video/ogg';
517
-		case 'pdf':
518
-			return 'application/pdf';
519
-		case 'png':
520
-			return 'image/png';
521
-		case 'rar':
522
-			return 'application/x-rar-compressed';
523
-		case 'swf':
524
-			return 'application/x-shockwave-flash';
525
-		case 'svg':
526
-			return 'image/svg';
527
-		case 'tif':
528
-			return 'image/tiff';
529
-		case 'tiff':
530
-			return 'image/tiff';
531
-		case 'xls':
532
-			return 'application/vnd-ms-excel';
533
-		case 'xlsx':
534
-			return 'application/vnd-ms-excel';
535
-		case 'wmv':
536
-			return 'video/x-ms-wmv';
537
-		case 'zip':
538
-			return 'application/zip';
539
-		default:
540
-			return 'application/octet-stream';
493
+		    case 'bmp':
494
+			    return 'image/bmp';
495
+		    case 'doc':
496
+			    return 'application/msword';
497
+		    case 'docx':
498
+			    return 'application/msword';
499
+		    case 'ged':
500
+			    return 'text/x-gedcom';
501
+		    case 'gif':
502
+			    return 'image/gif';
503
+		    case 'htm':
504
+			    return 'text/html';
505
+		    case 'html':
506
+			    return 'text/html';
507
+		    case 'jpeg':
508
+			    return 'image/jpeg';
509
+		    case 'jpg':
510
+			    return 'image/jpeg';
511
+		    case 'mov':
512
+			    return 'video/quicktime';
513
+		    case 'mp3':
514
+			    return 'audio/mpeg';
515
+		    case 'ogv':
516
+			    return 'video/ogg';
517
+		    case 'pdf':
518
+			    return 'application/pdf';
519
+		    case 'png':
520
+			    return 'image/png';
521
+		    case 'rar':
522
+			    return 'application/x-rar-compressed';
523
+		    case 'swf':
524
+			    return 'application/x-shockwave-flash';
525
+		    case 'svg':
526
+			    return 'image/svg';
527
+		    case 'tif':
528
+			    return 'image/tiff';
529
+		    case 'tiff':
530
+			    return 'image/tiff';
531
+		    case 'xls':
532
+			    return 'application/vnd-ms-excel';
533
+		    case 'xlsx':
534
+			    return 'application/vnd-ms-excel';
535
+		    case 'wmv':
536
+			    return 'video/x-ms-wmv';
537
+		    case 'zip':
538
+			    return 'application/zip';
539
+		    default:
540
+			    return 'application/octet-stream';
541 541
 		}
542 542
 	}
543 543
 
Please login to merge, or discard this patch.
Braces   +48 added lines, -24 removed lines patch added patch discarded remove patch
@@ -22,7 +22,8 @@  discard block
 block discarded – undo
22 22
 /**
23 23
  * A GEDCOM media (OBJE) object.
24 24
  */
25
-class Media extends GedcomRecord {
25
+class Media extends GedcomRecord
26
+{
26 27
 	const RECORD_TYPE = 'OBJE';
27 28
 	const URL_PREFIX  = 'mediaviewer.php?mid=';
28 29
 
@@ -41,7 +42,8 @@  discard block
 block discarded – undo
41 42
 	 *                             empty string for records with pending deletions
42 43
 	 * @param Tree        $tree
43 44
 	 */
44
-	public function __construct($xref, $gedcom, $pending, $tree) {
45
+	public function __construct($xref, $gedcom, $pending, $tree)
46
+	{
45 47
 		parent::__construct($xref, $gedcom, $pending, $tree);
46 48
 
47 49
 		if (preg_match('/\n1 FILE (.+)/', $gedcom . $pending, $match)) {
@@ -59,7 +61,8 @@  discard block
 block discarded – undo
59 61
 	 *
60 62
 	 * @return bool
61 63
 	 */
62
-	protected function canShowByType($access_level) {
64
+	protected function canShowByType($access_level)
65
+	{
63 66
 		// Hide media objects if they are attached to private records
64 67
 		$linked_ids = Database::prepare(
65 68
 			"SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?"
@@ -85,7 +88,8 @@  discard block
 block discarded – undo
85 88
 	 *
86 89
 	 * @return null|string
87 90
 	 */
88
-	protected static function fetchGedcomRecord($xref, $tree_id) {
91
+	protected static function fetchGedcomRecord($xref, $tree_id)
92
+	{
89 93
 		return Database::prepare(
90 94
 			"SELECT m_gedcom FROM `##media` WHERE m_id = :xref AND m_file = :tree_id"
91 95
 		)->execute(array(
@@ -99,7 +103,8 @@  discard block
 block discarded – undo
99 103
 	 *
100 104
 	 * @return null|string
101 105
 	 */
102
-	public function getNote() {
106
+	public function getNote()
107
+	{
103 108
 		$note = $this->getFirstFact('NOTE');
104 109
 		if ($note) {
105 110
 			$text = $note->getValue();
@@ -118,7 +123,8 @@  discard block
 block discarded – undo
118 123
 	 *
119 124
 	 * @return string
120 125
 	 */
121
-	public function getFilename() {
126
+	public function getFilename()
127
+	{
122 128
 		return $this->file;
123 129
 	}
124 130
 
@@ -127,7 +133,8 @@  discard block
 block discarded – undo
127 133
 	 *
128 134
 	 * @return string
129 135
 	 */
130
-	public function getTitle() {
136
+	public function getTitle()
137
+	{
131 138
 		return $this->title;
132 139
 	}
133 140
 
@@ -139,7 +146,8 @@  discard block
 block discarded – undo
139 146
 	 *
140 147
 	 * @return string
141 148
 	 */
142
-	public function getServerFilename($which = 'main') {
149
+	public function getServerFilename($which = 'main')
150
+	{
143 151
 		$MEDIA_DIRECTORY = $this->tree->getPreference('MEDIA_DIRECTORY');
144 152
 		$THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
145 153
 
@@ -249,7 +257,8 @@  discard block
 block discarded – undo
249 257
 	 *
250 258
 	 * @return bool
251 259
 	 */
252
-	public function fileExists($which = 'main') {
260
+	public function fileExists($which = 'main')
261
+	{
253 262
 		return file_exists($this->getServerFilename($which));
254 263
 	}
255 264
 
@@ -258,7 +267,8 @@  discard block
 block discarded – undo
258 267
 	 *
259 268
 	 * @return bool
260 269
 	 */
261
-	public function isExternal() {
270
+	public function isExternal()
271
+	{
262 272
 		return strpos($this->file, '://') !== false;
263 273
 	}
264 274
 
@@ -269,7 +279,8 @@  discard block
 block discarded – undo
269 279
 	 *
270 280
 	 * @return string
271 281
 	 */
272
-	public function getFilesize($which = 'main') {
282
+	public function getFilesize($which = 'main')
283
+	{
273 284
 		$size = $this->getFilesizeraw($which);
274 285
 		// Round up to the nearest KB.
275 286
 		$size = (int) (($size + 1023) / 1024);
@@ -284,7 +295,8 @@  discard block
 block discarded – undo
284 295
 	 *
285 296
 	 * @return int
286 297
 	 */
287
-	public function getFilesizeraw($which = 'main') {
298
+	public function getFilesizeraw($which = 'main')
299
+	{
288 300
 		try {
289 301
 			return filesize($this->getServerFilename($which));
290 302
 		} catch (\ErrorException $ex) {
@@ -299,7 +311,8 @@  discard block
 block discarded – undo
299 311
 	 *
300 312
 	 * @return int
301 313
 	 */
302
-	public function getFiletime($which = 'main') {
314
+	public function getFiletime($which = 'main')
315
+	{
303 316
 		try {
304 317
 			return filemtime($this->getServerFilename($which));
305 318
 		} catch (\ErrorException $ex) {
@@ -314,7 +327,8 @@  discard block
 block discarded – undo
314 327
 	 *
315 328
 	 * @return string
316 329
 	 */
317
-	public function getEtag($which = 'main') {
330
+	public function getEtag($which = 'main')
331
+	{
318 332
 		if ($this->isExternal()) {
319 333
 			// etag not really defined for external media
320 334
 
@@ -331,7 +345,8 @@  discard block
 block discarded – undo
331 345
 	 *
332 346
 	 * @return string
333 347
 	 */
334
-	public function getMediaType() {
348
+	public function getMediaType()
349
+	{
335 350
 		if (preg_match('/\n\d TYPE (.+)/', $this->gedcom, $match)) {
336 351
 			return strtolower($match[1]);
337 352
 		} else {
@@ -344,7 +359,8 @@  discard block
 block discarded – undo
344 359
 	 *
345 360
 	 * @return string
346 361
 	 */
347
-	public function isPrimary() {
362
+	public function isPrimary()
363
+	{
348 364
 		if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcom(), $match)) {
349 365
 			return $match[1];
350 366
 		} else {
@@ -361,7 +377,8 @@  discard block
 block discarded – undo
361 377
 	 *
362 378
 	 * @return array
363 379
 	 */
364
-	public function getImageAttributes($which = 'main', $addWidth = 0, $addHeight = 0) {
380
+	public function getImageAttributes($which = 'main', $addWidth = 0, $addHeight = 0)
381
+	{
365 382
 		$THUMBNAIL_WIDTH = $this->tree->getPreference('THUMBNAIL_WIDTH');
366 383
 
367 384
 		$var = $which . 'imagesize';
@@ -456,7 +473,8 @@  discard block
 block discarded – undo
456 473
 	 *
457 474
 	 * @return string
458 475
 	 */
459
-	public function getHtmlUrlDirect($which = 'main', $download = false) {
476
+	public function getHtmlUrlDirect($which = 'main', $download = false)
477
+	{
460 478
 		// “cb” is “cache buster”, so clients will make new request if anything significant about the user or the file changes
461 479
 		// The extension is there so that image viewers (e.g. colorbox) can do something sensible
462 480
 		$thumbstr    = ($which == 'thumb') ? '&amp;thumb=1' : '';
@@ -473,7 +491,8 @@  discard block
 block discarded – undo
473 491
 	 *
474 492
 	 * @return string
475 493
 	 */
476
-	public function extension() {
494
+	public function extension()
495
+	{
477 496
 		if (preg_match('/\.([a-zA-Z0-9]+)$/', $this->file, $match)) {
478 497
 			return strtolower($match[1]);
479 498
 		} else {
@@ -487,7 +506,8 @@  discard block
 block discarded – undo
487 506
 	 *
488 507
 	 * @return string
489 508
 	 */
490
-	public function mimeType() {
509
+	public function mimeType()
510
+	{
491 511
 		// Themes contain icon definitions for some/all of these mime-types
492 512
 		switch ($this->extension()) {
493 513
 		case 'bmp':
@@ -546,7 +566,8 @@  discard block
 block discarded – undo
546 566
 	 *
547 567
 	 * @return string
548 568
 	 */
549
-	public function displayImage() {
569
+	public function displayImage()
570
+	{
550 571
 		// Default image for external, missing or corrupt images.
551 572
 		$image =
552 573
 			'<i' .
@@ -588,7 +609,8 @@  discard block
 block discarded – undo
588 609
 	 *
589 610
 	 * @return string
590 611
 	 */
591
-	public function getFallBackName() {
612
+	public function getFallBackName()
613
+	{
592 614
 		if ($this->canShow()) {
593 615
 			return basename($this->file);
594 616
 		} else {
@@ -599,7 +621,8 @@  discard block
 block discarded – undo
599 621
 	/**
600 622
 	 * Extract names from the GEDCOM record.
601 623
 	 */
602
-	public function extractNames() {
624
+	public function extractNames()
625
+	{
603 626
 		// Earlier gedcom versions had level 1 titles
604 627
 		// Later gedcom versions had level 2 titles
605 628
 		$this->extractNamesFromFacts(2, 'TITL', $this->getFacts('FILE'));
@@ -612,7 +635,8 @@  discard block
 block discarded – undo
612 635
 	 *
613 636
 	 * @return string
614 637
 	 */
615
-	public function formatListDetails() {
638
+	public function formatListDetails()
639
+	{
616 640
 		ob_start();
617 641
 		FunctionsPrintFacts::printMediaLinks('1 OBJE @' . $this->getXref() . '@', 1);
618 642
 
Please login to merge, or discard this patch.
app/Config.php 2 patches
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -20,204 +20,204 @@
 block discarded – undo
20 20
  * although most of it can be altered to customise local installations.
21 21
  */
22 22
 class Config {
23
-	/** Font used to watermark images */
24
-	const FONT_DEJAVU_SANS_TTF = 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf';
23
+    /** Font used to watermark images */
24
+    const FONT_DEJAVU_SANS_TTF = 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf';
25 25
 
26
-	/**
27
-	 * NPFX tags - name prefixes
28
-	 *
29
-	 * @return string[]
30
-	 */
31
-	public static function namePrefixes() {
32
-		return array(
33
-			'Adm', 'Amb', 'Brig', 'Can', 'Capt', 'Chan', 'Chapln', 'Cmdr', 'Col', 'Cpl',
34
-			'Cpt', 'Dr', 'Gen', 'Gov', 'Hon', 'Lady', 'Lt', 'Mr', 'Mrs', 'Ms', 'Msgr',
35
-			'Pfc', 'Pres', 'Prof', 'Pvt', 'Rabbi', 'Rep', 'Rev', 'Sen', 'Sgt', 'Sir',
36
-			'Sr', 'Sra', 'Srta', 'Ven',
37
-		);
38
-	}
26
+    /**
27
+     * NPFX tags - name prefixes
28
+     *
29
+     * @return string[]
30
+     */
31
+    public static function namePrefixes() {
32
+        return array(
33
+            'Adm', 'Amb', 'Brig', 'Can', 'Capt', 'Chan', 'Chapln', 'Cmdr', 'Col', 'Cpl',
34
+            'Cpt', 'Dr', 'Gen', 'Gov', 'Hon', 'Lady', 'Lt', 'Mr', 'Mrs', 'Ms', 'Msgr',
35
+            'Pfc', 'Pres', 'Prof', 'Pvt', 'Rabbi', 'Rep', 'Rev', 'Sen', 'Sgt', 'Sir',
36
+            'Sr', 'Sra', 'Srta', 'Ven',
37
+        );
38
+    }
39 39
 
40
-	/**
41
-	 * FILE:FORM tags - file formats
42
-	 *
43
-	 * @return string[]
44
-	 */
45
-	public static function fileFormats() {
46
-		return array(
47
-			'avi', 'bmp', 'gif', 'jpeg', 'mp3', 'ole', 'pcx', 'png', 'tiff', 'wav',
48
-		);
49
-	}
40
+    /**
41
+     * FILE:FORM tags - file formats
42
+     *
43
+     * @return string[]
44
+     */
45
+    public static function fileFormats() {
46
+        return array(
47
+            'avi', 'bmp', 'gif', 'jpeg', 'mp3', 'ole', 'pcx', 'png', 'tiff', 'wav',
48
+        );
49
+    }
50 50
 
51
-	/**
52
-	 * Fact tags (as opposed to event tags), that don't normally have a value
53
-	 *
54
-	 * return string[]
55
-	 */
56
-	public static function emptyFacts() {
57
-		return array(
58
-			'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
59
-			'CENS', 'CHAN', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DATA', 'DEAT',
60
-			'DIV', 'DIVF', 'EMIG', 'ENDL', 'ENGA', 'FCOM', 'GRAD', 'HUSB', 'IMMI',
61
-			'MAP', 'MARB', 'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'ORDN', 'PROB',
62
-			'RESI', 'RETI', 'SLGC', 'SLGS', 'WIFE', 'WILL', '_HOL', '_NMR', '_NMAR',
63
-			'_SEPR',
64
-		);
65
-	}
51
+    /**
52
+     * Fact tags (as opposed to event tags), that don't normally have a value
53
+     *
54
+     * return string[]
55
+     */
56
+    public static function emptyFacts() {
57
+        return array(
58
+            'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
59
+            'CENS', 'CHAN', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DATA', 'DEAT',
60
+            'DIV', 'DIVF', 'EMIG', 'ENDL', 'ENGA', 'FCOM', 'GRAD', 'HUSB', 'IMMI',
61
+            'MAP', 'MARB', 'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'ORDN', 'PROB',
62
+            'RESI', 'RETI', 'SLGC', 'SLGS', 'WIFE', 'WILL', '_HOL', '_NMR', '_NMAR',
63
+            '_SEPR',
64
+        );
65
+    }
66 66
 
67
-	/**
68
-	 * Tags that don't require a PLAC subtag
69
-	 *
70
-	 * @return string[]
71
-	 */
72
-	public static function nonPlaceFacts() {
73
-		return array(
74
-			'ENDL', 'NCHI', 'REFN', 'SLGC', 'SLGS',
75
-		);
76
-	}
67
+    /**
68
+     * Tags that don't require a PLAC subtag
69
+     *
70
+     * @return string[]
71
+     */
72
+    public static function nonPlaceFacts() {
73
+        return array(
74
+            'ENDL', 'NCHI', 'REFN', 'SLGC', 'SLGS',
75
+        );
76
+    }
77 77
 
78
-	/**
79
-	 * Tags that don't require a DATE subtag
80
-	 *
81
-	 * @return string[]
82
-	 */
83
-	public static function nonDateFacts() {
84
-		return array(
85
-			'ABBR', 'ADDR', 'AFN', 'ALIA', 'AUTH', 'CHIL', 'EMAIL', 'FAX', 'FILE',
86
-			'HUSB', 'NAME', 'NCHI', 'NOTE', 'OBJE', 'PHON', 'PUBL', 'REFN', 'REPO',
87
-			'RESN', 'SEX', 'SOUR', 'SSN', 'TEXT', 'WIFE', 'WWW', '_EMAIL',
88
-		);
89
-	}
78
+    /**
79
+     * Tags that don't require a DATE subtag
80
+     *
81
+     * @return string[]
82
+     */
83
+    public static function nonDateFacts() {
84
+        return array(
85
+            'ABBR', 'ADDR', 'AFN', 'ALIA', 'AUTH', 'CHIL', 'EMAIL', 'FAX', 'FILE',
86
+            'HUSB', 'NAME', 'NCHI', 'NOTE', 'OBJE', 'PHON', 'PUBL', 'REFN', 'REPO',
87
+            'RESN', 'SEX', 'SOUR', 'SSN', 'TEXT', 'WIFE', 'WWW', '_EMAIL',
88
+        );
89
+    }
90 90
 
91
-	/**
92
-	 * Tags that require a DATE:TIME as well as a DATE
93
-	 *
94
-	 * @return string[]
95
-	 */
96
-	public static function dateAndTime() {
97
-		return array(
98
-			'BIRT', 'DEAT',
99
-		);
100
-	}
91
+    /**
92
+     * Tags that require a DATE:TIME as well as a DATE
93
+     *
94
+     * @return string[]
95
+     */
96
+    public static function dateAndTime() {
97
+        return array(
98
+            'BIRT', 'DEAT',
99
+        );
100
+    }
101 101
 
102
-	/**
103
-	 * Level 2 tags that apply to specific Level 1 tags
104
-	 * Tags are applied in the order they appear here.
105
-	 *
106
-	 * @return string[][]
107
-	 */
108
-	public static function levelTwoTags() {
109
-		return array(
110
-			'_HEB'     => array(
111
-				'NAME', 'TITL',
112
-			),
113
-			'ROMN'     => array(
114
-				'NAME', 'TITL',
115
-			),
116
-			'TYPE'     => array(
117
-				'EVEN', 'FACT', 'GRAD', 'IDNO', 'MARR', 'ORDN', 'SSN',
118
-			),
119
-			'AGNC'     => array(
120
-				'EDUC', 'GRAD', 'OCCU', 'ORDN', 'RETI',
121
-			),
122
-			'CALN'     => array(
123
-				'REPO',
124
-			),
125
-			'CEME'     => array(// CEME is NOT a valid 5.5.1 tag
126
-				//'BURI',
127
-			),
128
-			'RELA'     => array(
129
-				'ASSO', '_ASSO',
130
-			),
131
-			'DATE'     => array(
132
-				'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
133
-				'CENS', 'CENS', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DEAT', 'DIV', 'DIVF',
134
-				'DSCR', 'EDUC', 'EMIG', 'ENDL', 'ENGA', 'EVEN', 'FCOM', 'GRAD', 'IMMI',
135
-				'MARB', 'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'OCCU', 'ORDN', 'PROB',
136
-				'PROP', 'RELI', 'RESI', 'RETI', 'SLGC', 'SLGS', 'WILL', '_TODO',
137
-			),
138
-			'AGE'      => array(
139
-				'CENS', 'DEAT',
140
-			),
141
-			'TEMP'     => array(
142
-				'BAPL', 'CONL', 'ENDL', 'SLGC', 'SLGS',
143
-			),
144
-			'PLAC'     => array(
145
-				'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
146
-				'CENS', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DEAT', 'DIV', 'DIVF',
147
-				'EDUC', 'EMIG', 'ENDL', 'ENGA', 'EVEN', 'FCOM', 'GRAD', 'IMMI', 'MARB',
148
-				'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'OCCU', 'ORDN', 'PROB', 'PROP',
149
-				'RELI', 'RESI', 'RETI', 'SLGC', 'SLGS', 'SSN', 'WILL',
150
-			),
151
-			'STAT'     => array(
152
-				'BAPL', 'CONL', 'ENDL', 'SLGC', 'SLGS',
153
-			),
154
-			'ADDR'     => array(
155
-				'BAPM', 'BIRT', 'BURI', 'CENS', 'CHR', 'CHRA', 'CONF', 'CREM', 'DEAT',
156
-				'EDUC', 'EVEN', 'GRAD', 'MARR', 'OCCU', 'ORDN', 'PROP', 'RESI',
157
-			),
158
-			'CAUS'     => array(
159
-				'DEAT',
160
-			),
161
-			'PHON'     => array(
162
-				'OCCU', 'RESI',
163
-			),
164
-			'FAX'      => array(
165
-				'OCCU', 'RESI',
166
-			),
167
-			'WWW'      => array(
168
-				'OCCU', 'RESI',
169
-			),
170
-			'EMAIL'    => array(
171
-				'OCCU', 'RESI',
172
-			),
173
-			'HUSB'     => array(
174
-				'MARR',
175
-			),
176
-			'WIFE'     => array(
177
-				'MARR',
178
-			),
179
-			'FAMC'     => array(
180
-				'ADOP', 'SLGC',
181
-			),
182
-			'FILE'     => array(
183
-				'OBJE',
184
-			),
185
-			'_PRIM'    => array(
186
-				'OBJE',
187
-			),
188
-			'EVEN'     => array(
189
-				'DATA',
190
-			),
191
-			'_WT_USER' => array(
192
-				'_TODO',
193
-			),
194
-			// See https://bugs.launchpad.net/webtrees/+bug/1082666
195
-			'RELI'     => array(
196
-				'CHR', 'CHRA', 'BAPM', 'MARR', 'BURI',
197
-			),
198
-		);
199
-	}
102
+    /**
103
+     * Level 2 tags that apply to specific Level 1 tags
104
+     * Tags are applied in the order they appear here.
105
+     *
106
+     * @return string[][]
107
+     */
108
+    public static function levelTwoTags() {
109
+        return array(
110
+            '_HEB'     => array(
111
+                'NAME', 'TITL',
112
+            ),
113
+            'ROMN'     => array(
114
+                'NAME', 'TITL',
115
+            ),
116
+            'TYPE'     => array(
117
+                'EVEN', 'FACT', 'GRAD', 'IDNO', 'MARR', 'ORDN', 'SSN',
118
+            ),
119
+            'AGNC'     => array(
120
+                'EDUC', 'GRAD', 'OCCU', 'ORDN', 'RETI',
121
+            ),
122
+            'CALN'     => array(
123
+                'REPO',
124
+            ),
125
+            'CEME'     => array(// CEME is NOT a valid 5.5.1 tag
126
+                //'BURI',
127
+            ),
128
+            'RELA'     => array(
129
+                'ASSO', '_ASSO',
130
+            ),
131
+            'DATE'     => array(
132
+                'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
133
+                'CENS', 'CENS', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DEAT', 'DIV', 'DIVF',
134
+                'DSCR', 'EDUC', 'EMIG', 'ENDL', 'ENGA', 'EVEN', 'FCOM', 'GRAD', 'IMMI',
135
+                'MARB', 'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'OCCU', 'ORDN', 'PROB',
136
+                'PROP', 'RELI', 'RESI', 'RETI', 'SLGC', 'SLGS', 'WILL', '_TODO',
137
+            ),
138
+            'AGE'      => array(
139
+                'CENS', 'DEAT',
140
+            ),
141
+            'TEMP'     => array(
142
+                'BAPL', 'CONL', 'ENDL', 'SLGC', 'SLGS',
143
+            ),
144
+            'PLAC'     => array(
145
+                'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
146
+                'CENS', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DEAT', 'DIV', 'DIVF',
147
+                'EDUC', 'EMIG', 'ENDL', 'ENGA', 'EVEN', 'FCOM', 'GRAD', 'IMMI', 'MARB',
148
+                'MARC', 'MARL', 'MARR', 'MARS', 'NATU', 'OCCU', 'ORDN', 'PROB', 'PROP',
149
+                'RELI', 'RESI', 'RETI', 'SLGC', 'SLGS', 'SSN', 'WILL',
150
+            ),
151
+            'STAT'     => array(
152
+                'BAPL', 'CONL', 'ENDL', 'SLGC', 'SLGS',
153
+            ),
154
+            'ADDR'     => array(
155
+                'BAPM', 'BIRT', 'BURI', 'CENS', 'CHR', 'CHRA', 'CONF', 'CREM', 'DEAT',
156
+                'EDUC', 'EVEN', 'GRAD', 'MARR', 'OCCU', 'ORDN', 'PROP', 'RESI',
157
+            ),
158
+            'CAUS'     => array(
159
+                'DEAT',
160
+            ),
161
+            'PHON'     => array(
162
+                'OCCU', 'RESI',
163
+            ),
164
+            'FAX'      => array(
165
+                'OCCU', 'RESI',
166
+            ),
167
+            'WWW'      => array(
168
+                'OCCU', 'RESI',
169
+            ),
170
+            'EMAIL'    => array(
171
+                'OCCU', 'RESI',
172
+            ),
173
+            'HUSB'     => array(
174
+                'MARR',
175
+            ),
176
+            'WIFE'     => array(
177
+                'MARR',
178
+            ),
179
+            'FAMC'     => array(
180
+                'ADOP', 'SLGC',
181
+            ),
182
+            'FILE'     => array(
183
+                'OBJE',
184
+            ),
185
+            '_PRIM'    => array(
186
+                'OBJE',
187
+            ),
188
+            'EVEN'     => array(
189
+                'DATA',
190
+            ),
191
+            '_WT_USER' => array(
192
+                '_TODO',
193
+            ),
194
+            // See https://bugs.launchpad.net/webtrees/+bug/1082666
195
+            'RELI'     => array(
196
+                'CHR', 'CHRA', 'BAPM', 'MARR', 'BURI',
197
+            ),
198
+        );
199
+    }
200 200
 
201
-	/**
202
-	 * Name fields
203
-	 *
204
-	 * @return string[]
205
-	 */
206
-	public static function standardNameFacts() {
207
-		return array(
208
-			'NAME', 'NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX',
209
-		);
210
-	}
201
+    /**
202
+     * Name fields
203
+     *
204
+     * @return string[]
205
+     */
206
+    public static function standardNameFacts() {
207
+        return array(
208
+            'NAME', 'NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX',
209
+        );
210
+    }
211 211
 
212
-	/**
213
-	 * A list of facts/events that generally have two associates
214
-	 * (two witnesses, two godparents, etc.)
215
-	 *
216
-	 * @return string[]
217
-	 */
218
-	public static function twoAssociates() {
219
-		return array(
220
-			'CHR', 'BAPM', 'MARR',
221
-		);
222
-	}
212
+    /**
213
+     * A list of facts/events that generally have two associates
214
+     * (two witnesses, two godparents, etc.)
215
+     *
216
+     * @return string[]
217
+     */
218
+    public static function twoAssociates() {
219
+        return array(
220
+            'CHR', 'BAPM', 'MARR',
221
+        );
222
+    }
223 223
 }
Please login to merge, or discard this patch.
Braces   +20 added lines, -10 removed lines patch added patch discarded remove patch
@@ -19,7 +19,8 @@  discard block
 block discarded – undo
19 19
  * Application configuration data. Data here has no GUI to edit it,
20 20
  * although most of it can be altered to customise local installations.
21 21
  */
22
-class Config {
22
+class Config
23
+{
23 24
 	/** Font used to watermark images */
24 25
 	const FONT_DEJAVU_SANS_TTF = 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf';
25 26
 
@@ -28,7 +29,8 @@  discard block
 block discarded – undo
28 29
 	 *
29 30
 	 * @return string[]
30 31
 	 */
31
-	public static function namePrefixes() {
32
+	public static function namePrefixes()
33
+	{
32 34
 		return array(
33 35
 			'Adm', 'Amb', 'Brig', 'Can', 'Capt', 'Chan', 'Chapln', 'Cmdr', 'Col', 'Cpl',
34 36
 			'Cpt', 'Dr', 'Gen', 'Gov', 'Hon', 'Lady', 'Lt', 'Mr', 'Mrs', 'Ms', 'Msgr',
@@ -42,7 +44,8 @@  discard block
 block discarded – undo
42 44
 	 *
43 45
 	 * @return string[]
44 46
 	 */
45
-	public static function fileFormats() {
47
+	public static function fileFormats()
48
+	{
46 49
 		return array(
47 50
 			'avi', 'bmp', 'gif', 'jpeg', 'mp3', 'ole', 'pcx', 'png', 'tiff', 'wav',
48 51
 		);
@@ -53,7 +56,8 @@  discard block
 block discarded – undo
53 56
 	 *
54 57
 	 * return string[]
55 58
 	 */
56
-	public static function emptyFacts() {
59
+	public static function emptyFacts()
60
+	{
57 61
 		return array(
58 62
 			'ADOP', 'ANUL', 'BAPL', 'BAPM', 'BARM', 'BASM', 'BIRT', 'BLES', 'BURI',
59 63
 			'CENS', 'CHAN', 'CHR', 'CHRA', 'CONF', 'CONL', 'CREM', 'DATA', 'DEAT',
@@ -69,7 +73,8 @@  discard block
 block discarded – undo
69 73
 	 *
70 74
 	 * @return string[]
71 75
 	 */
72
-	public static function nonPlaceFacts() {
76
+	public static function nonPlaceFacts()
77
+	{
73 78
 		return array(
74 79
 			'ENDL', 'NCHI', 'REFN', 'SLGC', 'SLGS',
75 80
 		);
@@ -80,7 +85,8 @@  discard block
 block discarded – undo
80 85
 	 *
81 86
 	 * @return string[]
82 87
 	 */
83
-	public static function nonDateFacts() {
88
+	public static function nonDateFacts()
89
+	{
84 90
 		return array(
85 91
 			'ABBR', 'ADDR', 'AFN', 'ALIA', 'AUTH', 'CHIL', 'EMAIL', 'FAX', 'FILE',
86 92
 			'HUSB', 'NAME', 'NCHI', 'NOTE', 'OBJE', 'PHON', 'PUBL', 'REFN', 'REPO',
@@ -93,7 +99,8 @@  discard block
 block discarded – undo
93 99
 	 *
94 100
 	 * @return string[]
95 101
 	 */
96
-	public static function dateAndTime() {
102
+	public static function dateAndTime()
103
+	{
97 104
 		return array(
98 105
 			'BIRT', 'DEAT',
99 106
 		);
@@ -105,7 +112,8 @@  discard block
 block discarded – undo
105 112
 	 *
106 113
 	 * @return string[][]
107 114
 	 */
108
-	public static function levelTwoTags() {
115
+	public static function levelTwoTags()
116
+	{
109 117
 		return array(
110 118
 			'_HEB'     => array(
111 119
 				'NAME', 'TITL',
@@ -203,7 +211,8 @@  discard block
 block discarded – undo
203 211
 	 *
204 212
 	 * @return string[]
205 213
 	 */
206
-	public static function standardNameFacts() {
214
+	public static function standardNameFacts()
215
+	{
207 216
 		return array(
208 217
 			'NAME', 'NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX',
209 218
 		);
@@ -215,7 +224,8 @@  discard block
 block discarded – undo
215 224
 	 *
216 225
 	 * @return string[]
217 226
 	 */
218
-	public static function twoAssociates() {
227
+	public static function twoAssociates()
228
+	{
219 229
 		return array(
220 230
 			'CHR', 'BAPM', 'MARR',
221 231
 		);
Please login to merge, or discard this patch.
app/Source.php 2 patches
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -19,62 +19,62 @@
 block discarded – undo
19 19
  * A GEDCOM source (SOUR) object.
20 20
  */
21 21
 class Source extends GedcomRecord {
22
-	const RECORD_TYPE = 'SOUR';
23
-	const URL_PREFIX  = 'source.php?sid=';
22
+    const RECORD_TYPE = 'SOUR';
23
+    const URL_PREFIX  = 'source.php?sid=';
24 24
 
25
-	/**
26
-	 * Each object type may have its own special rules, and re-implement this function.
27
-	 *
28
-	 * @param int $access_level
29
-	 *
30
-	 * @return bool
31
-	 */
32
-	protected function canShowByType($access_level) {
33
-		// Hide sources if they are attached to private repositories ...
34
-		preg_match_all('/\n1 REPO @(.+)@/', $this->gedcom, $matches);
35
-		foreach ($matches[1] as $match) {
36
-			$repo = Repository::getInstance($match, $this->tree);
37
-			if ($repo && !$repo->canShow($access_level)) {
38
-				return false;
39
-			}
40
-		}
25
+    /**
26
+     * Each object type may have its own special rules, and re-implement this function.
27
+     *
28
+     * @param int $access_level
29
+     *
30
+     * @return bool
31
+     */
32
+    protected function canShowByType($access_level) {
33
+        // Hide sources if they are attached to private repositories ...
34
+        preg_match_all('/\n1 REPO @(.+)@/', $this->gedcom, $matches);
35
+        foreach ($matches[1] as $match) {
36
+            $repo = Repository::getInstance($match, $this->tree);
37
+            if ($repo && !$repo->canShow($access_level)) {
38
+                return false;
39
+            }
40
+        }
41 41
 
42
-		// ... otherwise apply default behaviour
43
-		return parent::canShowByType($access_level);
44
-	}
42
+        // ... otherwise apply default behaviour
43
+        return parent::canShowByType($access_level);
44
+    }
45 45
 
46
-	/**
47
-	 * Generate a private version of this record
48
-	 *
49
-	 * @param int $access_level
50
-	 *
51
-	 * @return string
52
-	 */
53
-	protected function createPrivateGedcomRecord($access_level) {
54
-		return '0 @' . $this->xref . "@ SOUR\n1 TITL " . I18N::translate('Private');
55
-	}
46
+    /**
47
+     * Generate a private version of this record
48
+     *
49
+     * @param int $access_level
50
+     *
51
+     * @return string
52
+     */
53
+    protected function createPrivateGedcomRecord($access_level) {
54
+        return '0 @' . $this->xref . "@ SOUR\n1 TITL " . I18N::translate('Private');
55
+    }
56 56
 
57
-	/**
58
-	 * Fetch data from the database
59
-	 *
60
-	 * @param string $xref
61
-	 * @param int    $tree_id
62
-	 *
63
-	 * @return null|string
64
-	 */
65
-	protected static function fetchGedcomRecord($xref, $tree_id) {
66
-		return Database::prepare(
67
-			"SELECT s_gedcom FROM `##sources` WHERE s_id = :xref AND s_file = :tree_id"
68
-		)->execute(array(
69
-			'xref'    => $xref,
70
-			'tree_id' => $tree_id,
71
-		))->fetchOne();
72
-	}
57
+    /**
58
+     * Fetch data from the database
59
+     *
60
+     * @param string $xref
61
+     * @param int    $tree_id
62
+     *
63
+     * @return null|string
64
+     */
65
+    protected static function fetchGedcomRecord($xref, $tree_id) {
66
+        return Database::prepare(
67
+            "SELECT s_gedcom FROM `##sources` WHERE s_id = :xref AND s_file = :tree_id"
68
+        )->execute(array(
69
+            'xref'    => $xref,
70
+            'tree_id' => $tree_id,
71
+        ))->fetchOne();
72
+    }
73 73
 
74
-	/**
75
-	 * Extract names from the GEDCOM record.
76
-	 */
77
-	public function extractNames() {
78
-		parent::extractNamesFromFacts(1, 'TITL', $this->getFacts('TITL'));
79
-	}
74
+    /**
75
+     * Extract names from the GEDCOM record.
76
+     */
77
+    public function extractNames() {
78
+        parent::extractNamesFromFacts(1, 'TITL', $this->getFacts('TITL'));
79
+    }
80 80
 }
Please login to merge, or discard this patch.
Braces   +10 added lines, -5 removed lines patch added patch discarded remove patch
@@ -18,7 +18,8 @@  discard block
 block discarded – undo
18 18
 /**
19 19
  * A GEDCOM source (SOUR) object.
20 20
  */
21
-class Source extends GedcomRecord {
21
+class Source extends GedcomRecord
22
+{
22 23
 	const RECORD_TYPE = 'SOUR';
23 24
 	const URL_PREFIX  = 'source.php?sid=';
24 25
 
@@ -29,7 +30,8 @@  discard block
 block discarded – undo
29 30
 	 *
30 31
 	 * @return bool
31 32
 	 */
32
-	protected function canShowByType($access_level) {
33
+	protected function canShowByType($access_level)
34
+	{
33 35
 		// Hide sources if they are attached to private repositories ...
34 36
 		preg_match_all('/\n1 REPO @(.+)@/', $this->gedcom, $matches);
35 37
 		foreach ($matches[1] as $match) {
@@ -50,7 +52,8 @@  discard block
 block discarded – undo
50 52
 	 *
51 53
 	 * @return string
52 54
 	 */
53
-	protected function createPrivateGedcomRecord($access_level) {
55
+	protected function createPrivateGedcomRecord($access_level)
56
+	{
54 57
 		return '0 @' . $this->xref . "@ SOUR\n1 TITL " . I18N::translate('Private');
55 58
 	}
56 59
 
@@ -62,7 +65,8 @@  discard block
 block discarded – undo
62 65
 	 *
63 66
 	 * @return null|string
64 67
 	 */
65
-	protected static function fetchGedcomRecord($xref, $tree_id) {
68
+	protected static function fetchGedcomRecord($xref, $tree_id)
69
+	{
66 70
 		return Database::prepare(
67 71
 			"SELECT s_gedcom FROM `##sources` WHERE s_id = :xref AND s_file = :tree_id"
68 72
 		)->execute(array(
@@ -74,7 +78,8 @@  discard block
 block discarded – undo
74 78
 	/**
75 79
 	 * Extract names from the GEDCOM record.
76 80
 	 */
77
-	public function extractNames() {
81
+	public function extractNames()
82
+	{
78 83
 		parent::extractNamesFromFacts(1, 'TITL', $this->getFacts('TITL'));
79 84
 	}
80 85
 }
Please login to merge, or discard this patch.