Completed
Push — 1.7 ( 284d8b...6ce0c4 )
by
unknown
07:17
created
admin_site_config.php 1 patch
Indentation   +99 added lines, -99 removed lines patch added patch discarded remove patch
@@ -26,136 +26,136 @@  discard block
 block discarded – undo
26 26
 
27 27
 switch (Filter::post('action')) {
28 28
 case 'site':
29
-	if (Filter::checkCsrf()) {
30
-		$INDEX_DIRECTORY = Filter::post('INDEX_DIRECTORY');
31
-		if (substr($INDEX_DIRECTORY, -1) !== '/') {
32
-			$INDEX_DIRECTORY .= '/';
33
-		}
34
-		if (File::mkdir($INDEX_DIRECTORY)) {
35
-			Site::setPreference('INDEX_DIRECTORY', $INDEX_DIRECTORY);
36
-		} else {
37
-			FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Filter::escapeHtml($INDEX_DIRECTORY)), 'danger');
38
-		}
39
-		Site::setPreference('MEMORY_LIMIT', Filter::post('MEMORY_LIMIT'));
40
-		Site::setPreference('MAX_EXECUTION_TIME', Filter::post('MAX_EXECUTION_TIME'));
41
-		Site::setPreference('ALLOW_USER_THEMES', Filter::postBool('ALLOW_USER_THEMES'));
42
-		Site::setPreference('THEME_DIR', Filter::post('THEME_DIR'));
43
-		Site::setPreference('ALLOW_CHANGE_GEDCOM', Filter::postBool('ALLOW_CHANGE_GEDCOM'));
44
-		Site::setPreference('SESSION_TIME', Filter::post('SESSION_TIME'));
45
-		Site::setPreference('SERVER_URL', Filter::post('SERVER_URL'));
46
-		Site::setPreference('TIMEZONE', Filter::post('TIMEZONE'));
47
-		FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
48
-	}
49
-	header('Location: ' . WT_BASE_URL . 'admin.php');
50
-
51
-	return;
29
+    if (Filter::checkCsrf()) {
30
+        $INDEX_DIRECTORY = Filter::post('INDEX_DIRECTORY');
31
+        if (substr($INDEX_DIRECTORY, -1) !== '/') {
32
+            $INDEX_DIRECTORY .= '/';
33
+        }
34
+        if (File::mkdir($INDEX_DIRECTORY)) {
35
+            Site::setPreference('INDEX_DIRECTORY', $INDEX_DIRECTORY);
36
+        } else {
37
+            FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Filter::escapeHtml($INDEX_DIRECTORY)), 'danger');
38
+        }
39
+        Site::setPreference('MEMORY_LIMIT', Filter::post('MEMORY_LIMIT'));
40
+        Site::setPreference('MAX_EXECUTION_TIME', Filter::post('MAX_EXECUTION_TIME'));
41
+        Site::setPreference('ALLOW_USER_THEMES', Filter::postBool('ALLOW_USER_THEMES'));
42
+        Site::setPreference('THEME_DIR', Filter::post('THEME_DIR'));
43
+        Site::setPreference('ALLOW_CHANGE_GEDCOM', Filter::postBool('ALLOW_CHANGE_GEDCOM'));
44
+        Site::setPreference('SESSION_TIME', Filter::post('SESSION_TIME'));
45
+        Site::setPreference('SERVER_URL', Filter::post('SERVER_URL'));
46
+        Site::setPreference('TIMEZONE', Filter::post('TIMEZONE'));
47
+        FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
48
+    }
49
+    header('Location: ' . WT_BASE_URL . 'admin.php');
50
+
51
+    return;
52 52
 
53 53
 case 'email':
54
-	if (Filter::checkCsrf()) {
55
-		Site::setPreference('SMTP_ACTIVE', Filter::post('SMTP_ACTIVE'));
56
-		Site::setPreference('SMTP_FROM_NAME', Filter::post('SMTP_FROM_NAME'));
57
-		Site::setPreference('SMTP_HOST', Filter::post('SMTP_HOST'));
58
-		Site::setPreference('SMTP_PORT', Filter::post('SMTP_PORT'));
59
-		Site::setPreference('SMTP_AUTH', Filter::post('SMTP_AUTH'));
60
-		Site::setPreference('SMTP_AUTH_USER', Filter::post('SMTP_AUTH_USER'));
61
-		Site::setPreference('SMTP_SSL', Filter::post('SMTP_SSL'));
62
-		Site::setPreference('SMTP_HELO', Filter::post('SMTP_HELO'));
63
-		if (Filter::post('SMTP_AUTH_PASS')) {
64
-			Site::setPreference('SMTP_AUTH_PASS', Filter::post('SMTP_AUTH_PASS'));
65
-		}
66
-		FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
67
-	}
68
-	header('Location: ' . WT_BASE_URL . 'admin.php');
69
-
70
-	return;
54
+    if (Filter::checkCsrf()) {
55
+        Site::setPreference('SMTP_ACTIVE', Filter::post('SMTP_ACTIVE'));
56
+        Site::setPreference('SMTP_FROM_NAME', Filter::post('SMTP_FROM_NAME'));
57
+        Site::setPreference('SMTP_HOST', Filter::post('SMTP_HOST'));
58
+        Site::setPreference('SMTP_PORT', Filter::post('SMTP_PORT'));
59
+        Site::setPreference('SMTP_AUTH', Filter::post('SMTP_AUTH'));
60
+        Site::setPreference('SMTP_AUTH_USER', Filter::post('SMTP_AUTH_USER'));
61
+        Site::setPreference('SMTP_SSL', Filter::post('SMTP_SSL'));
62
+        Site::setPreference('SMTP_HELO', Filter::post('SMTP_HELO'));
63
+        if (Filter::post('SMTP_AUTH_PASS')) {
64
+            Site::setPreference('SMTP_AUTH_PASS', Filter::post('SMTP_AUTH_PASS'));
65
+        }
66
+        FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
67
+    }
68
+    header('Location: ' . WT_BASE_URL . 'admin.php');
69
+
70
+    return;
71 71
 case 'login':
72
-	if (Filter::checkCsrf()) {
73
-		Site::setPreference('LOGIN_URL', Filter::post('LOGIN_URL'));
74
-		Site::setPreference('WELCOME_TEXT_AUTH_MODE', Filter::post('WELCOME_TEXT_AUTH_MODE'));
75
-		Site::setPreference('WELCOME_TEXT_AUTH_MODE_' . WT_LOCALE, Filter::post('WELCOME_TEXT_AUTH_MODE_4'));
76
-		Site::setPreference('USE_REGISTRATION_MODULE', Filter::post('USE_REGISTRATION_MODULE'));
77
-		Site::setPreference('SHOW_REGISTER_CAUTION', Filter::post('SHOW_REGISTER_CAUTION'));
78
-		FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
79
-	}
80
-	header('Location: ' . WT_BASE_URL . 'admin.php');
81
-
82
-	return;
72
+    if (Filter::checkCsrf()) {
73
+        Site::setPreference('LOGIN_URL', Filter::post('LOGIN_URL'));
74
+        Site::setPreference('WELCOME_TEXT_AUTH_MODE', Filter::post('WELCOME_TEXT_AUTH_MODE'));
75
+        Site::setPreference('WELCOME_TEXT_AUTH_MODE_' . WT_LOCALE, Filter::post('WELCOME_TEXT_AUTH_MODE_4'));
76
+        Site::setPreference('USE_REGISTRATION_MODULE', Filter::post('USE_REGISTRATION_MODULE'));
77
+        Site::setPreference('SHOW_REGISTER_CAUTION', Filter::post('SHOW_REGISTER_CAUTION'));
78
+        FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
79
+    }
80
+    header('Location: ' . WT_BASE_URL . 'admin.php');
81
+
82
+    return;
83 83
 
84 84
 case 'tracking':
85
-	if (Filter::checkCsrf()) {
86
-		Site::setPreference('BING_WEBMASTER_ID', Filter::post('BING_WEBMASTER_ID'));
87
-		Site::setPreference('GOOGLE_WEBMASTER_ID', Filter::post('GOOGLE_WEBMASTER_ID'));
88
-		Site::setPreference('GOOGLE_ANALYTICS_ID', Filter::post('GOOGLE_ANALYTICS_ID'));
89
-		Site::setPreference('PIWIK_URL', Filter::post('PIWIK_URL'));
90
-		Site::setPreference('PIWIK_SITE_ID', Filter::post('PIWIK_SITE_ID'));
91
-		Site::setPreference('STATCOUNTER_PROJECT_ID', Filter::post('STATCOUNTER_PROJECT_ID'));
92
-		Site::setPreference('STATCOUNTER_SECURITY_ID', Filter::post('STATCOUNTER_SECURITY_ID'));
93
-		FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
94
-	}
95
-	header('Location: ' . WT_BASE_URL . 'admin.php');
96
-
97
-	return;
85
+    if (Filter::checkCsrf()) {
86
+        Site::setPreference('BING_WEBMASTER_ID', Filter::post('BING_WEBMASTER_ID'));
87
+        Site::setPreference('GOOGLE_WEBMASTER_ID', Filter::post('GOOGLE_WEBMASTER_ID'));
88
+        Site::setPreference('GOOGLE_ANALYTICS_ID', Filter::post('GOOGLE_ANALYTICS_ID'));
89
+        Site::setPreference('PIWIK_URL', Filter::post('PIWIK_URL'));
90
+        Site::setPreference('PIWIK_SITE_ID', Filter::post('PIWIK_SITE_ID'));
91
+        Site::setPreference('STATCOUNTER_PROJECT_ID', Filter::post('STATCOUNTER_PROJECT_ID'));
92
+        Site::setPreference('STATCOUNTER_SECURITY_ID', Filter::post('STATCOUNTER_SECURITY_ID'));
93
+        FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
94
+    }
95
+    header('Location: ' . WT_BASE_URL . 'admin.php');
96
+
97
+    return;
98 98
 
99 99
 case 'languages':
100
-	if (Filter::checkCsrf()) {
101
-		Site::setPreference('LANGUAGES', implode(',', Filter::postArray('LANGUAGES')));
102
-		FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
103
-	}
104
-	header('Location: ' . WT_BASE_URL . 'admin.php');
100
+    if (Filter::checkCsrf()) {
101
+        Site::setPreference('LANGUAGES', implode(',', Filter::postArray('LANGUAGES')));
102
+        FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success');
103
+    }
104
+    header('Location: ' . WT_BASE_URL . 'admin.php');
105 105
 
106
-	return;
106
+    return;
107 107
 }
108 108
 
109 109
 // Lists of options for <select> controls.
110 110
 $SMTP_SSL_OPTIONS = array(
111
-	'none'                                                                        => I18N::translate('none'),
112
-	/* I18N: Secure Sockets Layer - a secure communications protocol*/ 'ssl'      => I18N::translate('ssl'),
113
-	/* I18N: Transport Layer Security - a secure communications protocol */ 'tls' => I18N::translate('tls'),
111
+    'none'                                                                        => I18N::translate('none'),
112
+    /* I18N: Secure Sockets Layer - a secure communications protocol*/ 'ssl'      => I18N::translate('ssl'),
113
+    /* I18N: Transport Layer Security - a secure communications protocol */ 'tls' => I18N::translate('tls'),
114 114
 );
115 115
 
116 116
 $SMTP_ACTIVE_OPTIONS = array(
117
-	'internal' => I18N::translate('Use PHP mail to send messages'),
118
-	'sendmail' => /* I18N: "sendmail" is the name of some mail software */ I18N::translate('Use sendmail to send messages'),
119
-	'external' => I18N::translate('Use SMTP to send messages'),
117
+    'internal' => I18N::translate('Use PHP mail to send messages'),
118
+    'sendmail' => /* I18N: "sendmail" is the name of some mail software */ I18N::translate('Use sendmail to send messages'),
119
+    'external' => I18N::translate('Use SMTP to send messages'),
120 120
 );
121 121
 
122 122
 if (!function_exists('proc_open')) {
123
-	unset($SMTP_ACTIVE_OPTIONS['sendmail']);
123
+    unset($SMTP_ACTIVE_OPTIONS['sendmail']);
124 124
 }
125 125
 
126 126
 $WELCOME_TEXT_AUTH_MODE_OPTIONS = array(
127
-	0 => I18N::translate('No predefined text'),
128
-	1 => I18N::translate('Predefined text that states all users can request a user account'),
129
-	2 => I18N::translate('Predefined text that states admin will decide on each request for a user account'),
130
-	3 => I18N::translate('Predefined text that states only family members can request a user account'),
131
-	4 => I18N::translate('Choose user defined welcome text typed below'),
127
+    0 => I18N::translate('No predefined text'),
128
+    1 => I18N::translate('Predefined text that states all users can request a user account'),
129
+    2 => I18N::translate('Predefined text that states admin will decide on each request for a user account'),
130
+    3 => I18N::translate('Predefined text that states only family members can request a user account'),
131
+    4 => I18N::translate('Choose user defined welcome text typed below'),
132 132
 );
133 133
 
134 134
 $language_tags = array();
135 135
 foreach (I18N::activeLocales() as $active_locale) {
136
-	$language_tags[] = $active_locale->languageTag();
136
+    $language_tags[] = $active_locale->languageTag();
137 137
 }
138 138
 
139 139
 switch (Filter::get('action')) {
140 140
 case 'site':
141
-	$controller->setPageTitle(I18N::translate('Website preferences'));
142
-	break;
141
+    $controller->setPageTitle(I18N::translate('Website preferences'));
142
+    break;
143 143
 case 'email':
144
-	$controller->setPageTitle(I18N::translate('Sending email'));
145
-	break;
144
+    $controller->setPageTitle(I18N::translate('Sending email'));
145
+    break;
146 146
 case 'login':
147
-	$controller->setPageTitle(I18N::translate('Sign-in and registration'));
148
-	break;
147
+    $controller->setPageTitle(I18N::translate('Sign-in and registration'));
148
+    break;
149 149
 case 'tracking':
150
-	$controller->setPageTitle(/* I18N: e.g. http://www.google.com/analytics */ I18N::translate('Tracking and analytics'));
151
-	break;
150
+    $controller->setPageTitle(/* I18N: e.g. http://www.google.com/analytics */ I18N::translate('Tracking and analytics'));
151
+    break;
152 152
 case 'languages':
153
-	$controller->setPageTitle(I18N::translate('Languages'));
154
-	break;
153
+    $controller->setPageTitle(I18N::translate('Languages'));
154
+    break;
155 155
 default:
156
-	header('Location: ' . WT_BASE_URL . 'admin.php');
156
+    header('Location: ' . WT_BASE_URL . 'admin.php');
157 157
 
158
-	return;
158
+    return;
159 159
 }
160 160
 
161 161
 $controller->pageHeader();
@@ -221,10 +221,10 @@  discard block
 block discarded – undo
221 221
 			<input type="text" class="form-control" id="MAX_EXECUTION_TIME" name="MAX_EXECUTION_TIME" value="<?php echo Filter::escapeHtml(Site::getPreference('MAX_EXECUTION_TIME')) ?>" pattern="[0-9]*" placeholder="<?php echo get_cfg_var('max_execution_time') ?>" maxlength="255">
222 222
 			<p class="small text-muted">
223 223
 				<?php echo I18N::plural(
224
-					'By default, your server allows scripts to run for %s second.',
225
-					'By default, your server allows scripts to run for %s seconds.',
226
-					get_cfg_var('max_execution_time'), I18N::number(get_cfg_var('max_execution_time')));
227
-				?>
224
+                    'By default, your server allows scripts to run for %s second.',
225
+                    'By default, your server allows scripts to run for %s seconds.',
226
+                    get_cfg_var('max_execution_time'), I18N::number(get_cfg_var('max_execution_time')));
227
+                ?>
228 228
 				<?php echo I18N::translate('You can request a higher or lower limit, although the server may ignore this request.') ?>
229 229
 				<?php echo I18N::translate('Leave this blank to use the default value.') ?>
230 230
 			</p>
Please login to merge, or discard this patch.
reportengine.php 1 patch
Indentation   +170 added lines, -170 removed lines patch added patch discarded remove patch
@@ -43,80 +43,80 @@  discard block
 block discarded – undo
43 43
 $varnames = Filter::get('varnames');
44 44
 $type     = Filter::get('type');
45 45
 if (!is_array($vars)) {
46
-	$vars = array();
46
+    $vars = array();
47 47
 }
48 48
 if (!is_array($varnames)) {
49
-	$varnames = array();
49
+    $varnames = array();
50 50
 }
51 51
 if (!is_array($type)) {
52
-	$type = array();
52
+    $type = array();
53 53
 }
54 54
 
55 55
 //-- setup the arrays
56 56
 $newvars = array();
57 57
 foreach ($vars as $name => $var) {
58
-	$newvars[$name]['id'] = $var;
59
-	if (!empty($type[$name])) {
60
-		switch ($type[$name]) {
61
-		case 'INDI':
62
-			$record = Individual::getInstance($var, $WT_TREE);
63
-			if ($record && $record->canShowName()) {
64
-				$newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
65
-			} else {
66
-				$action = 'setup';
67
-			}
68
-			break;
69
-		case 'FAM':
70
-			$record = Family::getInstance($var, $WT_TREE);
71
-			if ($record && $record->canShowName()) {
72
-				$newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
73
-			} else {
74
-				$action = 'setup';
75
-			}
76
-			break;
77
-		case 'SOUR':
78
-			$record = Source::getInstance($var, $WT_TREE);
79
-			if ($record && $record->canShowName()) {
80
-				$newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
81
-			} else {
82
-				$action = 'setup';
83
-			}
84
-			break;
85
-		default:
86
-			break;
87
-		}
88
-	}
58
+    $newvars[$name]['id'] = $var;
59
+    if (!empty($type[$name])) {
60
+        switch ($type[$name]) {
61
+        case 'INDI':
62
+            $record = Individual::getInstance($var, $WT_TREE);
63
+            if ($record && $record->canShowName()) {
64
+                $newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
65
+            } else {
66
+                $action = 'setup';
67
+            }
68
+            break;
69
+        case 'FAM':
70
+            $record = Family::getInstance($var, $WT_TREE);
71
+            if ($record && $record->canShowName()) {
72
+                $newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
73
+            } else {
74
+                $action = 'setup';
75
+            }
76
+            break;
77
+        case 'SOUR':
78
+            $record = Source::getInstance($var, $WT_TREE);
79
+            if ($record && $record->canShowName()) {
80
+                $newvars[$name]['gedcom'] = $record->privatizeGedcom(Auth::accessLevel($WT_TREE));
81
+            } else {
82
+                $action = 'setup';
83
+            }
84
+            break;
85
+        default:
86
+            break;
87
+        }
88
+    }
89 89
 }
90 90
 $vars = $newvars;
91 91
 
92 92
 foreach ($varnames as $name) {
93
-	if (!isset($vars[$name])) {
94
-		$vars[$name]['id'] = '';
95
-	}
93
+    if (!isset($vars[$name])) {
94
+        $vars[$name]['id'] = '';
95
+    }
96 96
 }
97 97
 
98 98
 $reports = array();
99 99
 foreach (Module::getActiveReports($WT_TREE) as $rep) {
100
-	$menu = $rep->getReportMenu();
101
-	if (preg_match('/report=(' . preg_quote(WT_MODULES_DIR, '/') . '[a-z0-9_]+\/[a-z0-9_]+\.xml)/', $menu->getLink(), $match)) {
102
-		$reports[$match[1]] = $menu->getLabel();
103
-	}
100
+    $menu = $rep->getReportMenu();
101
+    if (preg_match('/report=(' . preg_quote(WT_MODULES_DIR, '/') . '[a-z0-9_]+\/[a-z0-9_]+\.xml)/', $menu->getLink(), $match)) {
102
+        $reports[$match[1]] = $menu->getLabel();
103
+    }
104 104
 }
105 105
 
106 106
 if (!empty($report)) {
107
-	if (!array_key_exists($report, $reports)) {
108
-		$action = 'choose';
109
-	}
107
+    if (!array_key_exists($report, $reports)) {
108
+        $action = 'choose';
109
+    }
110 110
 }
111 111
 
112 112
 //-- choose a report to run
113 113
 switch ($action) {
114 114
 case 'choose':
115
-	$controller
116
-		->setPageTitle(I18N::translate('Choose a report to run'))
117
-		->pageHeader();
115
+    $controller
116
+        ->setPageTitle(I18N::translate('Choose a report to run'))
117
+        ->pageHeader();
118 118
 
119
-	echo '<div id="reportengine-page">
119
+    echo '<div id="reportengine-page">
120 120
 		<h2 class="center">', I18N::translate('Choose a report to run'), '</h2>
121 121
 		<form name="choosereport" method="get" action="reportengine.php">
122 122
 		<input type="hidden" name="action" value="setup">
@@ -124,27 +124,27 @@  discard block
 block discarded – undo
124 124
 		<table class="facts_table width40">
125 125
 		<tr><td class="descriptionbox wrap width33 vmiddle">', I18N::translate('Report'), '</td>
126 126
 		<td class="optionbox"><select name="report">';
127
-	foreach ($reports as $file => $report) {
128
-		echo '<option value="', Filter::escapeHtml($file), '">', Filter::escapeHtml($report), '</option>';
129
-	}
130
-	echo '</select></td></tr>
127
+    foreach ($reports as $file => $report) {
128
+        echo '<option value="', Filter::escapeHtml($file), '">', Filter::escapeHtml($report), '</option>';
129
+    }
130
+    echo '</select></td></tr>
131 131
 		<tr><td class="topbottombar" colspan="2"><input type="submit" value="', I18N::translate('continue'), '"></td></tr>
132 132
 		</table></form></div>';
133
-	break;
133
+    break;
134 134
 
135 135
 case 'setup':
136
-	$report_setup = new ReportParserSetup($report);
137
-	$report_array = $report_setup->reportProperties();
136
+    $report_setup = new ReportParserSetup($report);
137
+    $report_array = $report_setup->reportProperties();
138 138
 
139
-	$controller
140
-		->setPageTitle($report_array['title'])
141
-		->pageHeader()
142
-		->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
143
-		->addInlineJavascript('autocomplete();');
139
+    $controller
140
+        ->setPageTitle($report_array['title'])
141
+        ->pageHeader()
142
+        ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
143
+        ->addInlineJavascript('autocomplete();');
144 144
 
145
-	FunctionsPrint::initializeCalendarPopup();
145
+    FunctionsPrint::initializeCalendarPopup();
146 146
 
147
-	echo '<div id="reportengine-page">
147
+    echo '<div id="reportengine-page">
148 148
 		<h2 class="center">', $report_array['title'], '</h2>
149 149
 		<form name="setupreport" method="get" action="reportengine.php">
150 150
 		<input type="hidden" name="action" value="run">
@@ -152,102 +152,102 @@  discard block
 block discarded – undo
152 152
 		<table class="facts_table width50">
153 153
 		<tr><td class="descriptionbox width30 wrap">', I18N::translate('Report'), '</td><td class="optionbox">', $report_array['description'], '</td></tr>';
154 154
 
155
-	if (!isset($report_array['inputs'])) {
156
-		$report_array['inputs'] = array();
157
-	}
158
-	foreach ($report_array['inputs'] as $input) {
159
-		echo '<tr><td class="descriptionbox wrap">';
160
-		echo '<input type="hidden" name="varnames[]" value="', Filter::escapeHtml($input["name"]), '">';
161
-		echo I18N::translate($input['value']), '</td><td class="optionbox">';
162
-		if (!isset($input['type'])) {
163
-			$input['type'] = 'text';
164
-		}
165
-		if (!isset($input['default'])) {
166
-			$input['default'] = '';
167
-		}
168
-		if (!isset($input['lookup'])) {
169
-			$input['lookup'] = '';
170
-		}
155
+    if (!isset($report_array['inputs'])) {
156
+        $report_array['inputs'] = array();
157
+    }
158
+    foreach ($report_array['inputs'] as $input) {
159
+        echo '<tr><td class="descriptionbox wrap">';
160
+        echo '<input type="hidden" name="varnames[]" value="', Filter::escapeHtml($input["name"]), '">';
161
+        echo I18N::translate($input['value']), '</td><td class="optionbox">';
162
+        if (!isset($input['type'])) {
163
+            $input['type'] = 'text';
164
+        }
165
+        if (!isset($input['default'])) {
166
+            $input['default'] = '';
167
+        }
168
+        if (!isset($input['lookup'])) {
169
+            $input['lookup'] = '';
170
+        }
171 171
 
172
-		if ($input['type'] == 'text') {
173
-			echo '<input';
172
+        if ($input['type'] == 'text') {
173
+            echo '<input';
174 174
 
175
-			switch ($input['lookup']) {
176
-			case 'INDI':
177
-				echo ' data-autocomplete-type="INDI"';
178
-				if (!empty($pid)) {
179
-					$input['default'] = $pid;
180
-				} else {
181
-					$input['default'] = $controller->getSignificantIndividual()->getXref();
182
-				}
183
-				break;
184
-			case 'FAM':
185
-				echo ' data-autocomplete-type="FAM"';
186
-				if (!empty($famid)) {
187
-					$input['default'] = $famid;
188
-				} else {
189
-					$input['default'] = $controller->getSignificantFamily()->getXref();
190
-				}
191
-				break;
192
-			case 'SOUR':
193
-				echo ' data-autocomplete-type="SOUR"';
194
-				if (!empty($sid)) {
195
-					$input['default'] = $sid;
196
-				}
197
-				break;
198
-			case 'DATE':
199
-				if (isset($input['default'])) {
200
-					$input['default'] = strtoupper($input['default']);
201
-				}
202
-				break;
203
-			}
175
+            switch ($input['lookup']) {
176
+            case 'INDI':
177
+                echo ' data-autocomplete-type="INDI"';
178
+                if (!empty($pid)) {
179
+                    $input['default'] = $pid;
180
+                } else {
181
+                    $input['default'] = $controller->getSignificantIndividual()->getXref();
182
+                }
183
+                break;
184
+            case 'FAM':
185
+                echo ' data-autocomplete-type="FAM"';
186
+                if (!empty($famid)) {
187
+                    $input['default'] = $famid;
188
+                } else {
189
+                    $input['default'] = $controller->getSignificantFamily()->getXref();
190
+                }
191
+                break;
192
+            case 'SOUR':
193
+                echo ' data-autocomplete-type="SOUR"';
194
+                if (!empty($sid)) {
195
+                    $input['default'] = $sid;
196
+                }
197
+                break;
198
+            case 'DATE':
199
+                if (isset($input['default'])) {
200
+                    $input['default'] = strtoupper($input['default']);
201
+                }
202
+                break;
203
+            }
204 204
 
205
-			echo ' type="text" name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '" value="', Filter::escapeHtml($input['default']), '" style="direction: ltr;">';
206
-		}
207
-		if ($input['type'] == 'checkbox') {
208
-			echo '<input type="checkbox" name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '" value="1" ';
209
-			echo $input['default'] == '1' ? 'checked' : '';
210
-			echo '>';
211
-		}
212
-		if ($input['type'] == 'select') {
213
-			echo '<select name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '_var">';
214
-			$options = preg_split('/[|]+/', $input['options']);
215
-			foreach ($options as $option) {
216
-				$opt                   = explode('=>', $option);
217
-				list($value, $display) = $opt;
218
-				if (preg_match('/^I18N::number\((.+?)(,([\d+]))?\)$/', $display, $match)) {
219
-					$display = I18N::number($match[1], isset($match[3]) ? $match[3] : 0);
220
-				} elseif (preg_match('/^I18N::translate\(\'(.+)\'\)$/', $display, $match)) {
221
-					$display = I18N::translate($match[1]);
222
-				} elseif (preg_match('/^I18N::translateContext\(\'(.+)\', *\'(.+)\'\)$/', $display, $match)) {
223
-					$display = I18N::translateContext($match[1], $match[2]);
224
-				}
225
-				echo '<option value="', Filter::escapeHtml($value), '" ';
226
-				if ($opt[0] == $input['default']) {
227
-					echo 'selected';
228
-				}
229
-				echo '>', Filter::escapeHtml($display), '</option>';
230
-			}
231
-			echo '</select>';
232
-		}
233
-		if (isset($input['lookup'])) {
234
-			echo '<input type="hidden" name="type[', Filter::escapeHtml($input['name']), ']" value="', Filter::escapeHtml($input['lookup']), '">';
235
-			if ($input['lookup'] == 'INDI') {
236
-				echo FunctionsPrint::printFindIndividualLink('pid');
237
-			} elseif ($input['lookup'] == 'PLAC') {
238
-				echo FunctionsPrint::printFindPlaceLink($input['name']);
239
-			} elseif ($input['lookup'] == 'FAM') {
240
-				echo FunctionsPrint::printFindFamilyLink('famid');
241
-			} elseif ($input['lookup'] == 'SOUR') {
242
-				echo FunctionsPrint::printFindSourceLink($input['name']);
243
-			} elseif ($input['lookup'] == 'DATE') {
244
-				echo ' <a href="#" onclick="cal_toggleDate(\'div_', Filter::escapeJs($input['name']), '\', \'', Filter::escapeJs($input['name']), '\'); return false;" class="icon-button_calendar" title="', I18N::translate('Select a date'), '"></a>';
245
-				echo '<div id="div_', Filter::escapeHtml($input['name']), '" style="position:absolute;visibility:hidden;background-color:white;"></div>';
246
-			}
247
-		}
248
-		echo '</td></tr>';
249
-	}
250
-	echo '<tr>
205
+            echo ' type="text" name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '" value="', Filter::escapeHtml($input['default']), '" style="direction: ltr;">';
206
+        }
207
+        if ($input['type'] == 'checkbox') {
208
+            echo '<input type="checkbox" name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '" value="1" ';
209
+            echo $input['default'] == '1' ? 'checked' : '';
210
+            echo '>';
211
+        }
212
+        if ($input['type'] == 'select') {
213
+            echo '<select name="vars[', Filter::escapeHtml($input['name']), ']" id="', Filter::escapeHtml($input['name']), '_var">';
214
+            $options = preg_split('/[|]+/', $input['options']);
215
+            foreach ($options as $option) {
216
+                $opt                   = explode('=>', $option);
217
+                list($value, $display) = $opt;
218
+                if (preg_match('/^I18N::number\((.+?)(,([\d+]))?\)$/', $display, $match)) {
219
+                    $display = I18N::number($match[1], isset($match[3]) ? $match[3] : 0);
220
+                } elseif (preg_match('/^I18N::translate\(\'(.+)\'\)$/', $display, $match)) {
221
+                    $display = I18N::translate($match[1]);
222
+                } elseif (preg_match('/^I18N::translateContext\(\'(.+)\', *\'(.+)\'\)$/', $display, $match)) {
223
+                    $display = I18N::translateContext($match[1], $match[2]);
224
+                }
225
+                echo '<option value="', Filter::escapeHtml($value), '" ';
226
+                if ($opt[0] == $input['default']) {
227
+                    echo 'selected';
228
+                }
229
+                echo '>', Filter::escapeHtml($display), '</option>';
230
+            }
231
+            echo '</select>';
232
+        }
233
+        if (isset($input['lookup'])) {
234
+            echo '<input type="hidden" name="type[', Filter::escapeHtml($input['name']), ']" value="', Filter::escapeHtml($input['lookup']), '">';
235
+            if ($input['lookup'] == 'INDI') {
236
+                echo FunctionsPrint::printFindIndividualLink('pid');
237
+            } elseif ($input['lookup'] == 'PLAC') {
238
+                echo FunctionsPrint::printFindPlaceLink($input['name']);
239
+            } elseif ($input['lookup'] == 'FAM') {
240
+                echo FunctionsPrint::printFindFamilyLink('famid');
241
+            } elseif ($input['lookup'] == 'SOUR') {
242
+                echo FunctionsPrint::printFindSourceLink($input['name']);
243
+            } elseif ($input['lookup'] == 'DATE') {
244
+                echo ' <a href="#" onclick="cal_toggleDate(\'div_', Filter::escapeJs($input['name']), '\', \'', Filter::escapeJs($input['name']), '\'); return false;" class="icon-button_calendar" title="', I18N::translate('Select a date'), '"></a>';
245
+                echo '<div id="div_', Filter::escapeHtml($input['name']), '" style="position:absolute;visibility:hidden;background-color:white;"></div>';
246
+            }
247
+        }
248
+        echo '</td></tr>';
249
+    }
250
+    echo '<tr>
251 251
 		<td colspan="2" class="optionbox">
252 252
 		<div class="report-type">
253 253
 		<div>
@@ -264,22 +264,22 @@  discard block
 block discarded – undo
264 264
 		<tr><td class="topbottombar" colspan="2">
265 265
 		<input type="submit" value="', I18N::translate('continue'), '">
266 266
 		</td></tr></table></form></div>';
267
-	break;
267
+    break;
268 268
 
269 269
 case 'run':
270
-	if (strstr($report, 'report_singlepage.xml') !== false) {
271
-		// This is a custom module?
272
-		new \ReportPedigree;
273
-		break;
274
-	}
270
+    if (strstr($report, 'report_singlepage.xml') !== false) {
271
+        // This is a custom module?
272
+        new \ReportPedigree;
273
+        break;
274
+    }
275 275
 
276
-	switch ($output) {
277
-	case 'HTML':
278
-		header('Content-type: text/html; charset=UTF-8');
279
-		new ReportParserGenerate($report, new ReportHtml, $vars);
280
-		break;
281
-	case 'PDF':
282
-		new ReportParserGenerate($report, new ReportPdf, $vars);
283
-		break;
284
-	}
276
+    switch ($output) {
277
+    case 'HTML':
278
+        header('Content-type: text/html; charset=UTF-8');
279
+        new ReportParserGenerate($report, new ReportHtml, $vars);
280
+        break;
281
+    case 'PDF':
282
+        new ReportParserGenerate($report, new ReportPdf, $vars);
283
+        break;
284
+    }
285 285
 }
Please login to merge, or discard this patch.
relationship.php 1 patch
Indentation   +106 added lines, -106 removed lines patch added patch discarded remove patch
@@ -45,20 +45,20 @@  discard block
 block discarded – undo
45 45
 $person2 = Individual::getInstance($pid2, $WT_TREE);
46 46
 
47 47
 $controller
48
-	->restrictAccess(Module::isActiveChart($WT_TREE, 'relationships_chart'))
49
-	->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
50
-	->addInlineJavascript('autocomplete();');
48
+    ->restrictAccess(Module::isActiveChart($WT_TREE, 'relationships_chart'))
49
+    ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
50
+    ->addInlineJavascript('autocomplete();');
51 51
 
52 52
 if ($person1 && $person2) {
53
-	$controller
54
-		->setPageTitle(I18N::translate(/* I18N: %s are individual’s names */ 'Relationships between %1$s and %2$s', $person1->getFullName(), $person2->getFullName()))
55
-		->pageHeader();
56
-	$paths = $controller->calculateRelationships($person1, $person2, $recursion, (bool) $ancestors);
53
+    $controller
54
+        ->setPageTitle(I18N::translate(/* I18N: %s are individual’s names */ 'Relationships between %1$s and %2$s', $person1->getFullName(), $person2->getFullName()))
55
+        ->pageHeader();
56
+    $paths = $controller->calculateRelationships($person1, $person2, $recursion, (bool) $ancestors);
57 57
 } else {
58
-	$controller
59
-		->setPageTitle(I18N::translate('Relationships'))
60
-		->pageHeader();
61
-	$paths = array();
58
+    $controller
59
+        ->setPageTitle(I18N::translate('Relationships'))
60
+        ->pageHeader();
61
+    $paths = array();
62 62
 }
63 63
 
64 64
 ?>
@@ -143,102 +143,102 @@  discard block
 block discarded – undo
143 143
 <?php
144 144
 
145 145
 if ($person1 && $person2) {
146
-	if (I18N::direction() === 'ltr') {
147
-		$horizontal_arrow = '<br><i class="icon-rarrow"></i>';
148
-		$diagonal1        = Theme::theme()->parameter('image-dline');
149
-		$diagonal2        = Theme::theme()->parameter('image-dline2');
150
-	} else {
151
-		$horizontal_arrow = '<br><i class="icon-larrow"></i>';
152
-		$diagonal1        = Theme::theme()->parameter('image-dline2');
153
-		$diagonal2        = Theme::theme()->parameter('image-dline');
154
-	}
155
-	$up_arrow   = ' <i class="icon-uarrow"></i>';
156
-	$down_arrow = ' <i class="icon-darrow"></i>';
146
+    if (I18N::direction() === 'ltr') {
147
+        $horizontal_arrow = '<br><i class="icon-rarrow"></i>';
148
+        $diagonal1        = Theme::theme()->parameter('image-dline');
149
+        $diagonal2        = Theme::theme()->parameter('image-dline2');
150
+    } else {
151
+        $horizontal_arrow = '<br><i class="icon-larrow"></i>';
152
+        $diagonal1        = Theme::theme()->parameter('image-dline2');
153
+        $diagonal2        = Theme::theme()->parameter('image-dline');
154
+    }
155
+    $up_arrow   = ' <i class="icon-uarrow"></i>';
156
+    $down_arrow = ' <i class="icon-darrow"></i>';
157 157
 
158
-	$num_paths = 0;
159
-	foreach ($paths as $path) {
160
-		// Extract the relationship names between pairs of individuals
161
-		$relationships = $controller->oldStyleRelationshipPath($path);
162
-		if (empty($relationships)) {
163
-			// Cannot see one of the families/individuals, due to privacy;
164
-			continue;
165
-		}
166
-		echo '<h3>', I18N::translate('Relationship: %s', Functions::getRelationshipNameFromPath(implode('', $relationships), $person1, $person2)), '</h3>';
167
-		$num_paths++;
158
+    $num_paths = 0;
159
+    foreach ($paths as $path) {
160
+        // Extract the relationship names between pairs of individuals
161
+        $relationships = $controller->oldStyleRelationshipPath($path);
162
+        if (empty($relationships)) {
163
+            // Cannot see one of the families/individuals, due to privacy;
164
+            continue;
165
+        }
166
+        echo '<h3>', I18N::translate('Relationship: %s', Functions::getRelationshipNameFromPath(implode('', $relationships), $person1, $person2)), '</h3>';
167
+        $num_paths++;
168 168
 
169
-		// Use a table/grid for layout.
170
-		$table = array();
171
-		// Current position in the grid.
172
-		$x     = 0;
173
-		$y     = 0;
174
-		// Extent of the grid.
175
-		$min_y = 0;
176
-		$max_y = 0;
177
-		$max_x = 0;
178
-		// For each node in the path.
179
-		foreach ($path as $n => $xref) {
180
-			if ($n % 2 === 1) {
181
-				switch ($relationships[$n]) {
182
-				case 'hus':
183
-				case 'wif':
184
-				case 'spo':
185
-				case 'bro':
186
-				case 'sis':
187
-				case 'sib':
188
-					$table[$x + 1][$y] = '<div style="background:url(' . Theme::theme()->parameter('image-hline') . ') repeat-x center;  width: 94px; text-align: center"><div class="hline-text" style="height: 32px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px;">' . $horizontal_arrow . '</div></div>';
189
-					$x += 2;
190
-					break;
191
-				case 'son':
192
-				case 'dau':
193
-				case 'chi':
194
-					if ($n > 2 && preg_match('/fat|mot|par/', $relationships[$n - 2])) {
195
-						$table[$x + 1][$y - 1] = '<div style="background:url(' . $diagonal2 . '); width: 64px; height: 64px; text-align: center;"><div style="height: 32px; text-align: end;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px; text-align: start;">' . $down_arrow . '</div></div>';
196
-						$x += 2;
197
-					} else {
198
-						$table[$x][$y - 1] = '<div style="background:url(' . Theme::theme()
199
-								->parameter('image-vline') . ') repeat-y center; height: 64px; text-align: center;"><div class="vline-text" style="display: inline-block; width:50%; line-height: 64px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="display: inline-block; width:50%; line-height: 64px;">' . $down_arrow . '</div></div>';
200
-					}
201
-					$y -= 2;
202
-					break;
203
-				case 'fat':
204
-				case 'mot':
205
-				case 'par':
206
-					if ($n > 2 && preg_match('/son|dau|chi/', $relationships[$n - 2])) {
207
-						$table[$x + 1][$y + 1] = '<div style="background:url(' . $diagonal1 . '); background-position: top right; width: 64px; height: 64px; text-align: center;"><div style="height: 32px; text-align: start;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px; text-align: end;">' . $up_arrow . '</div></div>';
208
-						$x += 2;
209
-					} else {
210
-						$table[$x][$y + 1] = '<div style="background:url(' . Theme::theme()
211
-								->parameter('image-vline') . ') repeat-y center; height: 64px; text-align:center; "><div class="vline-text" style="display: inline-block; width: 50%; line-height: 32px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="display: inline-block; width: 50%; line-height: 32px">' . $up_arrow . '</div></div>';
212
-					}
213
-					$y += 2;
214
-					break;
215
-				}
216
-				$max_x = max($max_x, $x);
217
-				$min_y = min($min_y, $y);
218
-				$max_y = max($max_y, $y);
219
-			} else {
220
-				$individual = Individual::getInstance($xref, $WT_TREE);
221
-				ob_start();
222
-				FunctionsPrint::printPedigreePerson($individual, $show_full);
223
-				$table[$x][$y] = ob_get_clean();
224
-			}
225
-		}
226
-		echo '<table id="relationship-page" style="border-collapse: collapse; margin: 20px 50px;">';
227
-		for ($y = $max_y; $y >= $min_y; --$y) {
228
-			echo '<tr>';
229
-			for ($x = 0; $x <= $max_x; ++$x) {
230
-				echo '<td style="padding: 0;">';
231
-				if (isset($table[$x][$y])) {
232
-					echo $table[$x][$y];
233
-				}
234
-				echo '</td>';
235
-			}
236
-			echo '</tr>';
237
-		}
238
-		echo '</table>';
239
-	}
169
+        // Use a table/grid for layout.
170
+        $table = array();
171
+        // Current position in the grid.
172
+        $x     = 0;
173
+        $y     = 0;
174
+        // Extent of the grid.
175
+        $min_y = 0;
176
+        $max_y = 0;
177
+        $max_x = 0;
178
+        // For each node in the path.
179
+        foreach ($path as $n => $xref) {
180
+            if ($n % 2 === 1) {
181
+                switch ($relationships[$n]) {
182
+                case 'hus':
183
+                case 'wif':
184
+                case 'spo':
185
+                case 'bro':
186
+                case 'sis':
187
+                case 'sib':
188
+                    $table[$x + 1][$y] = '<div style="background:url(' . Theme::theme()->parameter('image-hline') . ') repeat-x center;  width: 94px; text-align: center"><div class="hline-text" style="height: 32px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px;">' . $horizontal_arrow . '</div></div>';
189
+                    $x += 2;
190
+                    break;
191
+                case 'son':
192
+                case 'dau':
193
+                case 'chi':
194
+                    if ($n > 2 && preg_match('/fat|mot|par/', $relationships[$n - 2])) {
195
+                        $table[$x + 1][$y - 1] = '<div style="background:url(' . $diagonal2 . '); width: 64px; height: 64px; text-align: center;"><div style="height: 32px; text-align: end;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px; text-align: start;">' . $down_arrow . '</div></div>';
196
+                        $x += 2;
197
+                    } else {
198
+                        $table[$x][$y - 1] = '<div style="background:url(' . Theme::theme()
199
+                                ->parameter('image-vline') . ') repeat-y center; height: 64px; text-align: center;"><div class="vline-text" style="display: inline-block; width:50%; line-height: 64px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="display: inline-block; width:50%; line-height: 64px;">' . $down_arrow . '</div></div>';
200
+                    }
201
+                    $y -= 2;
202
+                    break;
203
+                case 'fat':
204
+                case 'mot':
205
+                case 'par':
206
+                    if ($n > 2 && preg_match('/son|dau|chi/', $relationships[$n - 2])) {
207
+                        $table[$x + 1][$y + 1] = '<div style="background:url(' . $diagonal1 . '); background-position: top right; width: 64px; height: 64px; text-align: center;"><div style="height: 32px; text-align: start;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="height: 32px; text-align: end;">' . $up_arrow . '</div></div>';
208
+                        $x += 2;
209
+                    } else {
210
+                        $table[$x][$y + 1] = '<div style="background:url(' . Theme::theme()
211
+                                ->parameter('image-vline') . ') repeat-y center; height: 64px; text-align:center; "><div class="vline-text" style="display: inline-block; width: 50%; line-height: 32px;">' . Functions::getRelationshipNameFromPath($relationships[$n], Individual::getInstance($path[$n - 1], $WT_TREE), Individual::getInstance($path[$n + 1], $WT_TREE)) . '</div><div style="display: inline-block; width: 50%; line-height: 32px">' . $up_arrow . '</div></div>';
212
+                    }
213
+                    $y += 2;
214
+                    break;
215
+                }
216
+                $max_x = max($max_x, $x);
217
+                $min_y = min($min_y, $y);
218
+                $max_y = max($max_y, $y);
219
+            } else {
220
+                $individual = Individual::getInstance($xref, $WT_TREE);
221
+                ob_start();
222
+                FunctionsPrint::printPedigreePerson($individual, $show_full);
223
+                $table[$x][$y] = ob_get_clean();
224
+            }
225
+        }
226
+        echo '<table id="relationship-page" style="border-collapse: collapse; margin: 20px 50px;">';
227
+        for ($y = $max_y; $y >= $min_y; --$y) {
228
+            echo '<tr>';
229
+            for ($x = 0; $x <= $max_x; ++$x) {
230
+                echo '<td style="padding: 0;">';
231
+                if (isset($table[$x][$y])) {
232
+                    echo $table[$x][$y];
233
+                }
234
+                echo '</td>';
235
+            }
236
+            echo '</tr>';
237
+        }
238
+        echo '</table>';
239
+    }
240 240
 
241
-	if (!$num_paths) {
242
-		echo '<p>', I18N::translate('No link between the two individuals could be found.'), '</p>';
243
-	}
241
+    if (!$num_paths) {
242
+        echo '<p>', I18N::translate('No link between the two individuals could be found.'), '</p>';
243
+    }
244 244
 }
Please login to merge, or discard this patch.
fanchart.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -26,17 +26,17 @@  discard block
 block discarded – undo
26 26
 global $WT_TREE;
27 27
 
28 28
 if (Filter::getBool('img')) {
29
-	header('Content-Type: image/png');
30
-	echo $controller->generateFanChart('png');
29
+    header('Content-Type: image/png');
30
+    echo $controller->generateFanChart('png');
31 31
 
32
-	return;
32
+    return;
33 33
 }
34 34
 
35 35
 $controller
36
-	->restrictAccess(Module::isActiveChart($WT_TREE, 'fan_chart'))
37
-	->pageHeader()
38
-	->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
39
-	->addInlineJavascript('
36
+    ->restrictAccess(Module::isActiveChart($WT_TREE, 'fan_chart'))
37
+    ->pageHeader()
38
+    ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
39
+    ->addInlineJavascript('
40 40
 		autocomplete();
41 41
 		var WT_FANCHART = (function() {
42 42
 			jQuery("area")
@@ -119,12 +119,12 @@  discard block
 block discarded – undo
119 119
 <?php
120 120
 
121 121
 if ($controller->error_message) {
122
-	echo '<p class="ui-state-error">', $controller->error_message, '</p>';
122
+    echo '<p class="ui-state-error">', $controller->error_message, '</p>';
123 123
 
124
-	return;
124
+    return;
125 125
 }
126 126
 
127 127
 if ($controller->root) {
128
-	echo '<div id="fan_chart">', $controller->generateFanChart('html'), '</div>';
128
+    echo '<div id="fan_chart">', $controller->generateFanChart('html'), '</div>';
129 129
 }
130 130
 echo '</div>';
Please login to merge, or discard this patch.
descendancy.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -32,10 +32,10 @@  discard block
 block discarded – undo
32 32
 
33 33
 $controller = new DescendancyController;
34 34
 $controller
35
-	->restrictAccess(Module::isActiveChart($WT_TREE, 'descendancy_chart'))
36
-	->pageHeader()
37
-	->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
38
-	->addInlineJavascript('autocomplete();');
35
+    ->restrictAccess(Module::isActiveChart($WT_TREE, 'descendancy_chart'))
36
+    ->pageHeader()
37
+    ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
38
+    ->addInlineJavascript('autocomplete();');
39 39
 
40 40
 ?>
41 41
 <div id="descendancy-page"><h2><?php echo $controller->getPageTitle(); ?></h2>
@@ -93,29 +93,29 @@  discard block
 block discarded – undo
93 93
 
94 94
 <?php
95 95
 if ($controller->error_message) {
96
-	echo '<p class="ui-state-error">', $controller->error_message, '</p>';
96
+    echo '<p class="ui-state-error">', $controller->error_message, '</p>';
97 97
 } else {
98
-	switch ($controller->chart_style) {
99
-	case 0: // List
100
-		echo '<ul id="descendancy_chart" class="chart_common">';
101
-		$controller->printChildDescendancy($controller->root, $controller->generations);
102
-		echo '</ul>';
103
-		break;
104
-	case 1: // Booklet
105
-		$show_cousins = true;
106
-		echo '<div id="descendancy_booklet">';
107
-		$controller->printChildFamily($controller->root, $controller->generations);
108
-		echo '</div>';
109
-		break;
110
-	case 2: // Individual list
111
-		$descendants = $controller->individualDescendancy($controller->root, $controller->generations, array());
112
-		echo '<div id="descendancy-list">', FunctionsPrintLists::individualTable($descendants), '</div>';
113
-		break;
114
-	case 3: // Family list
115
-		$descendants = $controller->familyDescendancy($controller->root, $controller->generations, array());
116
-		echo '<div id="descendancy-list">', FunctionsPrintLists::familyTable($descendants), '</div>';
117
-		break;
118
-	}
98
+    switch ($controller->chart_style) {
99
+    case 0: // List
100
+        echo '<ul id="descendancy_chart" class="chart_common">';
101
+        $controller->printChildDescendancy($controller->root, $controller->generations);
102
+        echo '</ul>';
103
+        break;
104
+    case 1: // Booklet
105
+        $show_cousins = true;
106
+        echo '<div id="descendancy_booklet">';
107
+        $controller->printChildFamily($controller->root, $controller->generations);
108
+        echo '</div>';
109
+        break;
110
+    case 2: // Individual list
111
+        $descendants = $controller->individualDescendancy($controller->root, $controller->generations, array());
112
+        echo '<div id="descendancy-list">', FunctionsPrintLists::individualTable($descendants), '</div>';
113
+        break;
114
+    case 3: // Family list
115
+        $descendants = $controller->familyDescendancy($controller->root, $controller->generations, array());
116
+        echo '<div id="descendancy-list">', FunctionsPrintLists::familyTable($descendants), '</div>';
117
+        break;
118
+    }
119 119
 }
120 120
 ?>
121 121
 </div>
Please login to merge, or discard this patch.
autocomplete.php 1 patch
Indentation   +498 added lines, -498 removed lines patch added patch discarded remove patch
@@ -32,470 +32,470 @@  discard block
 block discarded – undo
32 32
 
33 33
 switch ($type) {
34 34
 case 'ASSO': // Associates of an individuals, whose name contains the search terms
35
-	$data = array();
36
-	// Fetch all data, regardless of privacy
37
-	$rows = Database::prepare(
38
-		"SELECT 'INDI' AS type, i_id AS xref, i_gedcom AS gedcom, n_full" .
39
-		" FROM `##individuals`" .
40
-		" JOIN `##name` ON i_id = n_id AND i_file = n_file" .
41
-		" WHERE (n_full LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR n_surn LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND i_file = :tree_id" .
42
-		" ORDER BY n_full COLLATE :collate"
43
-	)->execute(array(
44
-		'term_1'  => $term,
45
-		'term_2'  => $term,
46
-		'tree_id' => $WT_TREE->getTreeId(),
47
-		'collate' => I18N::collation(),
48
-	))->fetchAll();
49
-
50
-	// Filter for privacy and whether they could be alive at the right time
51
-	$event_date = Filter::get('extra');
52
-	$date       = new Date($event_date);
53
-	$event_jd   = $date->julianDay();
54
-	foreach ($rows as $row) {
55
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
56
-		if ($person->canShow()) {
57
-			if ($event_jd) {
58
-				// Exclude individuals who were born after the event.
59
-				$person_birth_jd = $person->getEstimatedBirthDate()->minimumJulianDay();
60
-				if ($person_birth_jd && $person_birth_jd > $event_jd) {
61
-					continue;
62
-				}
63
-				// Exclude individuals who died before the event.
64
-				$person_death_jd = $person->getEstimatedDeathDate()->maximumJulianDay();
65
-				if ($person_death_jd && $person_death_jd < $event_jd) {
66
-					continue;
67
-				}
68
-			}
69
-			// Add the age (if we have it) or the lifespan (if we do not).
70
-			$label = $person->getFullName();
71
-			if ($event_jd && $person->getBirthDate()->isOK()) {
72
-				$label .= ', <span class="age">(' . I18N::translate('Age') . ' ' . Date::getAge($person->getBirthDate(), $date, 0) . ')</span>';
73
-			} else {
74
-				$label .= ', <i>' . $person->getLifeSpan() . '</i>';
75
-			}
76
-			$data[$row->xref] = array('value' => $row->xref, 'label' => $label);
77
-		}
78
-	}
79
-	echo json_encode($data);
80
-
81
-	return;
35
+    $data = array();
36
+    // Fetch all data, regardless of privacy
37
+    $rows = Database::prepare(
38
+        "SELECT 'INDI' AS type, i_id AS xref, i_gedcom AS gedcom, n_full" .
39
+        " FROM `##individuals`" .
40
+        " JOIN `##name` ON i_id = n_id AND i_file = n_file" .
41
+        " WHERE (n_full LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR n_surn LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND i_file = :tree_id" .
42
+        " ORDER BY n_full COLLATE :collate"
43
+    )->execute(array(
44
+        'term_1'  => $term,
45
+        'term_2'  => $term,
46
+        'tree_id' => $WT_TREE->getTreeId(),
47
+        'collate' => I18N::collation(),
48
+    ))->fetchAll();
49
+
50
+    // Filter for privacy and whether they could be alive at the right time
51
+    $event_date = Filter::get('extra');
52
+    $date       = new Date($event_date);
53
+    $event_jd   = $date->julianDay();
54
+    foreach ($rows as $row) {
55
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
56
+        if ($person->canShow()) {
57
+            if ($event_jd) {
58
+                // Exclude individuals who were born after the event.
59
+                $person_birth_jd = $person->getEstimatedBirthDate()->minimumJulianDay();
60
+                if ($person_birth_jd && $person_birth_jd > $event_jd) {
61
+                    continue;
62
+                }
63
+                // Exclude individuals who died before the event.
64
+                $person_death_jd = $person->getEstimatedDeathDate()->maximumJulianDay();
65
+                if ($person_death_jd && $person_death_jd < $event_jd) {
66
+                    continue;
67
+                }
68
+            }
69
+            // Add the age (if we have it) or the lifespan (if we do not).
70
+            $label = $person->getFullName();
71
+            if ($event_jd && $person->getBirthDate()->isOK()) {
72
+                $label .= ', <span class="age">(' . I18N::translate('Age') . ' ' . Date::getAge($person->getBirthDate(), $date, 0) . ')</span>';
73
+            } else {
74
+                $label .= ', <i>' . $person->getLifeSpan() . '</i>';
75
+            }
76
+            $data[$row->xref] = array('value' => $row->xref, 'label' => $label);
77
+        }
78
+    }
79
+    echo json_encode($data);
80
+
81
+    return;
82 82
 
83 83
 case 'CEME': // Cemetery fields, that contain the search term
84
-	$data = array();
85
-	// Fetch all data, regardless of privacy
86
-	$rows = Database::prepare(
87
-		"SELECT i_id AS xref, i_gedcom AS gedcom" .
88
-		" FROM `##individuals`" .
89
-		" WHERE i_gedcom LIKE '%\n2 CEME %' AND i_file = :tree_id" .
90
-		" ORDER BY SUBSTRING_INDEX(i_gedcom, '\n2 CEME ', -1) COLLATE :collation"
91
-	)->execute(array(
92
-		'tree_id'   => $WT_TREE->getTreeId(),
93
-		'collation' => I18N::collation(),
94
-	))->fetchAll();
95
-	// Filter for privacy
96
-	foreach ($rows as $row) {
97
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
98
-		if (preg_match('/\n2 CEME (.*' . preg_quote($term, '/') . '.*)/i', $person->getGedcom(), $match)) {
99
-			if (!in_array($match[1], $data)) {
100
-				$data[] = $match[1];
101
-			}
102
-		}
103
-	}
104
-	echo json_encode($data);
105
-
106
-	return;
84
+    $data = array();
85
+    // Fetch all data, regardless of privacy
86
+    $rows = Database::prepare(
87
+        "SELECT i_id AS xref, i_gedcom AS gedcom" .
88
+        " FROM `##individuals`" .
89
+        " WHERE i_gedcom LIKE '%\n2 CEME %' AND i_file = :tree_id" .
90
+        " ORDER BY SUBSTRING_INDEX(i_gedcom, '\n2 CEME ', -1) COLLATE :collation"
91
+    )->execute(array(
92
+        'tree_id'   => $WT_TREE->getTreeId(),
93
+        'collation' => I18N::collation(),
94
+    ))->fetchAll();
95
+    // Filter for privacy
96
+    foreach ($rows as $row) {
97
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
98
+        if (preg_match('/\n2 CEME (.*' . preg_quote($term, '/') . '.*)/i', $person->getGedcom(), $match)) {
99
+            if (!in_array($match[1], $data)) {
100
+                $data[] = $match[1];
101
+            }
102
+        }
103
+    }
104
+    echo json_encode($data);
105
+
106
+    return;
107 107
 
108 108
 case 'FAM': // Families, whose name contains the search terms
109
-	$data = array();
110
-	// Fetch all data, regardless of privacy
111
-	$rows = get_FAM_rows($WT_TREE, $term);
112
-	// Filter for privacy
113
-	foreach ($rows as $row) {
114
-		$family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
115
-		if ($family->canShowName()) {
116
-			$marriage_year = $family->getMarriageYear();
117
-			if ($marriage_year) {
118
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
119
-			} else {
120
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
121
-			}
122
-		}
123
-	}
124
-	echo json_encode($data);
125
-
126
-	return;
109
+    $data = array();
110
+    // Fetch all data, regardless of privacy
111
+    $rows = get_FAM_rows($WT_TREE, $term);
112
+    // Filter for privacy
113
+    foreach ($rows as $row) {
114
+        $family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
115
+        if ($family->canShowName()) {
116
+            $marriage_year = $family->getMarriageYear();
117
+            if ($marriage_year) {
118
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
119
+            } else {
120
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
121
+            }
122
+        }
123
+    }
124
+    echo json_encode($data);
125
+
126
+    return;
127 127
 
128 128
 case 'GIVN': // Given names, that start with the search term
129
-	// Do not filter by privacy. Given names on their own do not identify individuals.
130
-	echo json_encode(
131
-		Database::prepare(
132
-			"SELECT DISTINCT n_givn" .
133
-			" FROM `##name`" .
134
-			" WHERE n_givn LIKE CONCAT(:term, '%') AND n_file = :tree_id" .
135
-			" ORDER BY n_givn COLLATE :collation"
136
-		)->execute(array(
137
-			'term'      => $term,
138
-			'tree_id'   => $WT_TREE->getTreeId(),
139
-			'collation' => I18N::collation(),
140
-		))->fetchOneColumn()
141
-	);
142
-
143
-	return;
129
+    // Do not filter by privacy. Given names on their own do not identify individuals.
130
+    echo json_encode(
131
+        Database::prepare(
132
+            "SELECT DISTINCT n_givn" .
133
+            " FROM `##name`" .
134
+            " WHERE n_givn LIKE CONCAT(:term, '%') AND n_file = :tree_id" .
135
+            " ORDER BY n_givn COLLATE :collation"
136
+        )->execute(array(
137
+            'term'      => $term,
138
+            'tree_id'   => $WT_TREE->getTreeId(),
139
+            'collation' => I18N::collation(),
140
+        ))->fetchOneColumn()
141
+    );
142
+
143
+    return;
144 144
 
145 145
 case 'INDI': // Individuals, whose name contains the search terms
146
-	$data = array();
147
-	// Fetch all data, regardless of privacy
148
-	$rows = Database::prepare(
149
-		"SELECT i_id AS xref, i_gedcom AS gedcom, n_full" .
150
-		" FROM `##individuals`" .
151
-		" JOIN `##name` ON i_id = n_id AND i_file = n_file" .
152
-		" WHERE (n_full LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR n_surn LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND i_file = :tree_id" .
153
-		" ORDER BY n_full COLLATE :collation"
154
-	)->execute(array(
155
-		'term_1'    => $term,
156
-		'term_2'    => $term,
157
-		'tree_id'   => $WT_TREE->getTreeId(),
158
-		'collation' => I18N::collation(),
159
-	))->fetchAll();
160
-	// Filter for privacy
161
-	foreach ($rows as $row) {
162
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
163
-		if ($person->canShowName()) {
164
-			$data[] = array('value' => $row->xref, 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
165
-		}
166
-	}
167
-	echo json_encode($data);
168
-
169
-	return;
146
+    $data = array();
147
+    // Fetch all data, regardless of privacy
148
+    $rows = Database::prepare(
149
+        "SELECT i_id AS xref, i_gedcom AS gedcom, n_full" .
150
+        " FROM `##individuals`" .
151
+        " JOIN `##name` ON i_id = n_id AND i_file = n_file" .
152
+        " WHERE (n_full LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR n_surn LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND i_file = :tree_id" .
153
+        " ORDER BY n_full COLLATE :collation"
154
+    )->execute(array(
155
+        'term_1'    => $term,
156
+        'term_2'    => $term,
157
+        'tree_id'   => $WT_TREE->getTreeId(),
158
+        'collation' => I18N::collation(),
159
+    ))->fetchAll();
160
+    // Filter for privacy
161
+    foreach ($rows as $row) {
162
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
163
+        if ($person->canShowName()) {
164
+            $data[] = array('value' => $row->xref, 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
165
+        }
166
+    }
167
+    echo json_encode($data);
168
+
169
+    return;
170 170
 
171 171
 case 'NOTE': // Notes which contain the search terms
172
-	$data = array();
173
-	// Fetch all data, regardless of privacy
174
-	$rows = get_NOTE_rows($WT_TREE, $term);
175
-	// Filter for privacy
176
-	foreach ($rows as $row) {
177
-		$note = Note::getInstance($row->xref, $WT_TREE, $row->gedcom);
178
-		if ($note->canShowName()) {
179
-			$data[] = array('value' => $note->getXref(), 'label' => $note->getFullName());
180
-		}
181
-	}
182
-	echo json_encode($data);
183
-
184
-	return;
172
+    $data = array();
173
+    // Fetch all data, regardless of privacy
174
+    $rows = get_NOTE_rows($WT_TREE, $term);
175
+    // Filter for privacy
176
+    foreach ($rows as $row) {
177
+        $note = Note::getInstance($row->xref, $WT_TREE, $row->gedcom);
178
+        if ($note->canShowName()) {
179
+            $data[] = array('value' => $note->getXref(), 'label' => $note->getFullName());
180
+        }
181
+    }
182
+    echo json_encode($data);
183
+
184
+    return;
185 185
 
186 186
 case 'OBJE':
187
-	$data = array();
188
-	// Fetch all data, regardless of privacy
189
-	$rows = get_OBJE_rows($WT_TREE, $term);
190
-	// Filter for privacy
191
-	foreach ($rows as $row) {
192
-		$media = Media::getInstance($row->xref, $WT_TREE, $row->gedcom);
193
-		if ($media->canShowName()) {
194
-			$data[] = array('value' => $row->xref, 'label' => '<img src="' . $media->getHtmlUrlDirect() . '" width="25"> ' . $media->getFullName());
195
-		}
196
-	}
197
-	echo json_encode($data);
198
-
199
-	return;
187
+    $data = array();
188
+    // Fetch all data, regardless of privacy
189
+    $rows = get_OBJE_rows($WT_TREE, $term);
190
+    // Filter for privacy
191
+    foreach ($rows as $row) {
192
+        $media = Media::getInstance($row->xref, $WT_TREE, $row->gedcom);
193
+        if ($media->canShowName()) {
194
+            $data[] = array('value' => $row->xref, 'label' => '<img src="' . $media->getHtmlUrlDirect() . '" width="25"> ' . $media->getFullName());
195
+        }
196
+    }
197
+    echo json_encode($data);
198
+
199
+    return;
200 200
 
201 201
 case 'PLAC': // Place names (with hierarchy), that include the search term
202
-	// Do not filter by privacy. Place names on their own do not identify individuals.
203
-	$data = array();
204
-	foreach (Place::findPlaces($term, $WT_TREE) as $place) {
205
-		$data[] = $place->getGedcomName();
206
-	}
207
-	if (!$data && $WT_TREE->getPreference('GEONAMES_ACCOUNT')) {
208
-		// No place found? Use an external gazetteer
209
-		$url =
210
-			"http://api.geonames.org/searchJSON" .
211
-			"?name_startsWith=" . urlencode($term) .
212
-			"&lang=" . WT_LOCALE .
213
-			"&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC" .
214
-			"&style=full" .
215
-			"&username=" . $WT_TREE->getPreference('GEONAMES_ACCOUNT');
216
-		// try to use curl when file_get_contents not allowed
217
-		if (ini_get('allow_url_fopen')) {
218
-			$json = file_get_contents($url);
219
-		} elseif (function_exists('curl_init')) {
220
-			$ch = curl_init();
221
-			curl_setopt($ch, CURLOPT_URL, $url);
222
-			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
223
-			$json = curl_exec($ch);
224
-			curl_close($ch);
225
-		} else {
226
-			return $data;
227
-		}
228
-		$places = json_decode($json, true);
229
-		if (isset($places['geonames']) && is_array($places['geonames'])) {
230
-			foreach ($places['geonames'] as $k => $place) {
231
-				$data[] = $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName'];
232
-			}
233
-		}
234
-	}
235
-	echo json_encode($data);
236
-
237
-	return;
202
+    // Do not filter by privacy. Place names on their own do not identify individuals.
203
+    $data = array();
204
+    foreach (Place::findPlaces($term, $WT_TREE) as $place) {
205
+        $data[] = $place->getGedcomName();
206
+    }
207
+    if (!$data && $WT_TREE->getPreference('GEONAMES_ACCOUNT')) {
208
+        // No place found? Use an external gazetteer
209
+        $url =
210
+            "http://api.geonames.org/searchJSON" .
211
+            "?name_startsWith=" . urlencode($term) .
212
+            "&lang=" . WT_LOCALE .
213
+            "&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC" .
214
+            "&style=full" .
215
+            "&username=" . $WT_TREE->getPreference('GEONAMES_ACCOUNT');
216
+        // try to use curl when file_get_contents not allowed
217
+        if (ini_get('allow_url_fopen')) {
218
+            $json = file_get_contents($url);
219
+        } elseif (function_exists('curl_init')) {
220
+            $ch = curl_init();
221
+            curl_setopt($ch, CURLOPT_URL, $url);
222
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
223
+            $json = curl_exec($ch);
224
+            curl_close($ch);
225
+        } else {
226
+            return $data;
227
+        }
228
+        $places = json_decode($json, true);
229
+        if (isset($places['geonames']) && is_array($places['geonames'])) {
230
+            foreach ($places['geonames'] as $k => $place) {
231
+                $data[] = $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName'];
232
+            }
233
+        }
234
+    }
235
+    echo json_encode($data);
236
+
237
+    return;
238 238
 
239 239
 case 'PLAC2': // Place names (without hierarchy), that include the search term
240
-	// Do not filter by privacy. Place names on their own do not identify individuals.
241
-	echo json_encode(
242
-		Database::prepare(
243
-			"SELECT p_place" .
244
-			" FROM `##places`" .
245
-			" WHERE p_place LIKE CONCAT('%', :term, '%') AND p_file = :tree_id" .
246
-			" ORDER BY p_place COLLATE :collation"
247
-		)->execute(array(
248
-			'term'      => $term,
249
-			'tree_id'   => $WT_TREE->getTreeId(),
250
-			'collation' => I18N::collation(),
251
-		))->fetchOneColumn()
252
-	);
253
-
254
-	return;
240
+    // Do not filter by privacy. Place names on their own do not identify individuals.
241
+    echo json_encode(
242
+        Database::prepare(
243
+            "SELECT p_place" .
244
+            " FROM `##places`" .
245
+            " WHERE p_place LIKE CONCAT('%', :term, '%') AND p_file = :tree_id" .
246
+            " ORDER BY p_place COLLATE :collation"
247
+        )->execute(array(
248
+            'term'      => $term,
249
+            'tree_id'   => $WT_TREE->getTreeId(),
250
+            'collation' => I18N::collation(),
251
+        ))->fetchOneColumn()
252
+    );
253
+
254
+    return;
255 255
 
256 256
 case 'REPO': // Repositories, that include the search terms
257
-	$data = array();
258
-	// Fetch all data, regardless of privacy
259
-	$rows = get_REPO_rows($WT_TREE, $term);
260
-	// Filter for privacy
261
-	foreach ($rows as $row) {
262
-		$record = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
263
-		if ($record->canShowName()) {
264
-			foreach ($record->getFacts('NAME') as $fact) {
265
-				$data[] = array('value' => $record->getXref(), 'label' => $fact->getValue());
266
-			}
267
-		}
268
-	}
269
-	echo json_encode($data);
270
-
271
-	return;
257
+    $data = array();
258
+    // Fetch all data, regardless of privacy
259
+    $rows = get_REPO_rows($WT_TREE, $term);
260
+    // Filter for privacy
261
+    foreach ($rows as $row) {
262
+        $record = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
263
+        if ($record->canShowName()) {
264
+            foreach ($record->getFacts('NAME') as $fact) {
265
+                $data[] = array('value' => $record->getXref(), 'label' => $fact->getValue());
266
+            }
267
+        }
268
+    }
269
+    echo json_encode($data);
270
+
271
+    return;
272 272
 
273 273
 case 'REPO_NAME': // Repository names, that include the search terms
274
-	$data = array();
275
-	// Fetch all data, regardless of privacy
276
-	$rows = get_REPO_rows($WT_TREE, $term);
277
-	// Filter for privacy
278
-	foreach ($rows as $row) {
279
-		$record = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
280
-		if ($record->canShowName()) {
281
-			$data[] = strip_tags($record->getFullName());
282
-		}
283
-	}
284
-	echo json_encode($data);
285
-
286
-	return;
274
+    $data = array();
275
+    // Fetch all data, regardless of privacy
276
+    $rows = get_REPO_rows($WT_TREE, $term);
277
+    // Filter for privacy
278
+    foreach ($rows as $row) {
279
+        $record = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
280
+        if ($record->canShowName()) {
281
+            $data[] = strip_tags($record->getFullName());
282
+        }
283
+    }
284
+    echo json_encode($data);
285
+
286
+    return;
287 287
 
288 288
 case 'SOUR': // Sources, that include the search terms
289
-	$data = array();
290
-	// Fetch all data, regardless of privacy
291
-	$rows = get_SOUR_rows($WT_TREE, $term);
292
-	// Filter for privacy
293
-	foreach ($rows as $row) {
294
-		$record = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
295
-		if ($record->canShowName()) {
296
-			foreach ($record->getFacts('TITL') as $fact) {
297
-				$data[] = array('value' => $record->getXref(), 'label' => $fact->getValue());
298
-			}
299
-		}
300
-	}
301
-	echo json_encode($data);
302
-
303
-	return;
289
+    $data = array();
290
+    // Fetch all data, regardless of privacy
291
+    $rows = get_SOUR_rows($WT_TREE, $term);
292
+    // Filter for privacy
293
+    foreach ($rows as $row) {
294
+        $record = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
295
+        if ($record->canShowName()) {
296
+            foreach ($record->getFacts('TITL') as $fact) {
297
+                $data[] = array('value' => $record->getXref(), 'label' => $fact->getValue());
298
+            }
299
+        }
300
+    }
301
+    echo json_encode($data);
302
+
303
+    return;
304 304
 
305 305
 case 'PAGE': // Citation details, for a given source, that contain the search term
306
-	$data = array();
307
-	$sid  = Filter::get('extra', WT_REGEX_XREF);
308
-	// Fetch all data, regardless of privacy
309
-	$rows = Database::prepare(
310
-		"SELECT i_id AS xref, i_gedcom AS gedcom" .
311
-		" FROM `##individuals`" .
312
-		" WHERE i_gedcom LIKE CONCAT('%\n_ SOUR @', :xref, '@%', REPLACE(:term, ' ', '%'), '%') AND i_file = :tree_id"
313
-	)->execute(array(
314
-		'xref'    => $sid,
315
-		'term'    => $term,
316
-		'tree_id' => $WT_TREE->getTreeId(),
317
-	))->fetchAll();
318
-	// Filter for privacy
319
-	foreach ($rows as $row) {
320
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
321
-		if (preg_match('/\n1 SOUR @' . $sid . '@(?:\n[2-9].*)*\n2 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $person->getGedcom(), $match)) {
322
-			$data[] = $match[1];
323
-		}
324
-		if (preg_match('/\n2 SOUR @' . $sid . '@(?:\n[3-9].*)*\n3 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $person->getGedcom(), $match)) {
325
-			$data[] = $match[1];
326
-		}
327
-	}
328
-	// Fetch all data, regardless of privacy
329
-	$rows = Database::prepare(
330
-		"SELECT f_id AS xref, f_gedcom AS gedcom" .
331
-		" FROM `##families`" .
332
-		" WHERE f_gedcom LIKE CONCAT('%\n_ SOUR @', :xref, '@%', REPLACE(:term, ' ', '%'), '%') AND f_file = :tree_id"
333
-	)->execute(array(
334
-		'xref'    => $sid,
335
-		'term'    => $term,
336
-		'tree_id' => $WT_TREE->getTreeId(),
337
-	))->fetchAll();
338
-	// Filter for privacy
339
-	foreach ($rows as $row) {
340
-		$family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
341
-		if (preg_match('/\n1 SOUR @' . $sid . '@(?:\n[2-9].*)*\n2 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $family->getGedcom(), $match)) {
342
-			$data[] = $match[1];
343
-		}
344
-		if (preg_match('/\n2 SOUR @' . $sid . '@(?:\n[3-9].*)*\n3 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $family->getGedcom(), $match)) {
345
-			$data[] = $match[1];
346
-		}
347
-	}
348
-	// array_unique() converts the keys from integer to string, which breaks
349
-	// the JSON encoding - so need to call array_values() to convert them
350
-	// back into integers.
351
-	$data = array_values(array_unique($data));
352
-	echo json_encode($data);
353
-
354
-	return;
306
+    $data = array();
307
+    $sid  = Filter::get('extra', WT_REGEX_XREF);
308
+    // Fetch all data, regardless of privacy
309
+    $rows = Database::prepare(
310
+        "SELECT i_id AS xref, i_gedcom AS gedcom" .
311
+        " FROM `##individuals`" .
312
+        " WHERE i_gedcom LIKE CONCAT('%\n_ SOUR @', :xref, '@%', REPLACE(:term, ' ', '%'), '%') AND i_file = :tree_id"
313
+    )->execute(array(
314
+        'xref'    => $sid,
315
+        'term'    => $term,
316
+        'tree_id' => $WT_TREE->getTreeId(),
317
+    ))->fetchAll();
318
+    // Filter for privacy
319
+    foreach ($rows as $row) {
320
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
321
+        if (preg_match('/\n1 SOUR @' . $sid . '@(?:\n[2-9].*)*\n2 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $person->getGedcom(), $match)) {
322
+            $data[] = $match[1];
323
+        }
324
+        if (preg_match('/\n2 SOUR @' . $sid . '@(?:\n[3-9].*)*\n3 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $person->getGedcom(), $match)) {
325
+            $data[] = $match[1];
326
+        }
327
+    }
328
+    // Fetch all data, regardless of privacy
329
+    $rows = Database::prepare(
330
+        "SELECT f_id AS xref, f_gedcom AS gedcom" .
331
+        " FROM `##families`" .
332
+        " WHERE f_gedcom LIKE CONCAT('%\n_ SOUR @', :xref, '@%', REPLACE(:term, ' ', '%'), '%') AND f_file = :tree_id"
333
+    )->execute(array(
334
+        'xref'    => $sid,
335
+        'term'    => $term,
336
+        'tree_id' => $WT_TREE->getTreeId(),
337
+    ))->fetchAll();
338
+    // Filter for privacy
339
+    foreach ($rows as $row) {
340
+        $family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
341
+        if (preg_match('/\n1 SOUR @' . $sid . '@(?:\n[2-9].*)*\n2 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $family->getGedcom(), $match)) {
342
+            $data[] = $match[1];
343
+        }
344
+        if (preg_match('/\n2 SOUR @' . $sid . '@(?:\n[3-9].*)*\n3 PAGE (.*' . str_replace(' ', '.+', preg_quote($term, '/')) . '.*)/i', $family->getGedcom(), $match)) {
345
+            $data[] = $match[1];
346
+        }
347
+    }
348
+    // array_unique() converts the keys from integer to string, which breaks
349
+    // the JSON encoding - so need to call array_values() to convert them
350
+    // back into integers.
351
+    $data = array_values(array_unique($data));
352
+    echo json_encode($data);
353
+
354
+    return;
355 355
 
356 356
 case 'SOUR_TITL': // Source titles, that include the search terms
357
-	$data = array();
358
-	// Fetch all data, regardless of privacy
359
-	$rows = Database::prepare(
360
-		"SELECT s_id AS xref, s_gedcom AS gedcom, s_name" .
361
-		" FROM `##sources`" .
362
-		" WHERE s_name LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND s_file = :tree_id" .
363
-		" ORDER BY s_name COLLATE :collation"
364
-	)->execute(array(
365
-		'term'      => $term,
366
-		'tree_id'   => $WT_TREE->getTreeId(),
367
-		'collation' => I18N::collation(),
368
-	))->fetchAll();
369
-	// Filter for privacy
370
-	foreach ($rows as $row) {
371
-		$source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
372
-		if ($source->canShowName()) {
373
-			$data[] = $row->s_name;
374
-		}
375
-	}
376
-	echo json_encode($data);
377
-
378
-	return;
357
+    $data = array();
358
+    // Fetch all data, regardless of privacy
359
+    $rows = Database::prepare(
360
+        "SELECT s_id AS xref, s_gedcom AS gedcom, s_name" .
361
+        " FROM `##sources`" .
362
+        " WHERE s_name LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND s_file = :tree_id" .
363
+        " ORDER BY s_name COLLATE :collation"
364
+    )->execute(array(
365
+        'term'      => $term,
366
+        'tree_id'   => $WT_TREE->getTreeId(),
367
+        'collation' => I18N::collation(),
368
+    ))->fetchAll();
369
+    // Filter for privacy
370
+    foreach ($rows as $row) {
371
+        $source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
372
+        if ($source->canShowName()) {
373
+            $data[] = $row->s_name;
374
+        }
375
+    }
376
+    echo json_encode($data);
377
+
378
+    return;
379 379
 
380 380
 case 'SURN': // Surnames, that start with the search term
381
-	// Do not filter by privacy. Surnames on their own do not identify individuals.
382
-	echo json_encode(
383
-		Database::prepare(
384
-			"SELECT DISTINCT n_surname" .
385
-			" FROM `##name`" .
386
-			" WHERE n_surname LIKE CONCAT(:term, '%') AND n_file = :tree_id" .
387
-			" ORDER BY n_surname COLLATE :collation"
388
-		)->execute(array(
389
-			'term'      => $term,
390
-			'tree_id'   => $WT_TREE->getTreeId(),
391
-			'collation' => I18N::collation(),
392
-		))->fetchOneColumn()
393
-	);
394
-
395
-	return;
381
+    // Do not filter by privacy. Surnames on their own do not identify individuals.
382
+    echo json_encode(
383
+        Database::prepare(
384
+            "SELECT DISTINCT n_surname" .
385
+            " FROM `##name`" .
386
+            " WHERE n_surname LIKE CONCAT(:term, '%') AND n_file = :tree_id" .
387
+            " ORDER BY n_surname COLLATE :collation"
388
+        )->execute(array(
389
+            'term'      => $term,
390
+            'tree_id'   => $WT_TREE->getTreeId(),
391
+            'collation' => I18N::collation(),
392
+        ))->fetchOneColumn()
393
+    );
394
+
395
+    return;
396 396
 
397 397
 case 'IFSRO':
398
-	$data = array();
399
-	// Fetch all data, regardless of privacy
400
-	$rows = get_INDI_rows($WT_TREE, $term);
401
-	// Filter for privacy
402
-	foreach ($rows as $row) {
403
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
404
-		if ($person->canShowName()) {
405
-			$data[] = array('value' => $person->getXref(), 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
406
-		}
407
-	}
408
-	// Fetch all data, regardless of privacy
409
-	$rows = get_SOUR_rows($WT_TREE, $term);
410
-	// Filter for privacy
411
-	foreach ($rows as $row) {
412
-		$source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
413
-		if ($source->canShowName()) {
414
-			$data[] = array('value' => $source->getXref(), 'label' => $source->getFullName());
415
-		}
416
-	}
417
-	// Fetch all data, regardless of privacy
418
-	$rows = get_REPO_rows($WT_TREE, $term);
419
-	// Filter for privacy
420
-	foreach ($rows as $row) {
421
-		$repository = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
422
-		if ($repository->canShowName()) {
423
-			$data[] = array('value' => $repository->getXref(), 'label' => $repository->getFullName());
424
-		}
425
-	}
426
-	// Fetch all data, regardless of privacy
427
-	$rows = get_OBJE_rows($WT_TREE, $term);
428
-	// Filter for privacy
429
-	foreach ($rows as $row) {
430
-		$media = Media::getInstance($row->xref, $WT_TREE, $row->gedcom);
431
-		if ($media->canShowName()) {
432
-			$data[] = array('value' => $media->getXref(), 'label' => '<img src="' . $media->getHtmlUrlDirect() . '" width="25"> ' . $media->getFullName());
433
-		}
434
-	}
435
-	// Fetch all data, regardless of privacy
436
-	$rows = get_FAM_rows($WT_TREE, $term);
437
-	// Filter for privacy
438
-	foreach ($rows as $row) {
439
-		$family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
440
-		if ($family->canShowName()) {
441
-			$marriage_year = $family->getMarriageYear();
442
-			if ($marriage_year) {
443
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
444
-			} else {
445
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
446
-			}
447
-		}
448
-	}
449
-	// Fetch all data, regardless of privacy
450
-	$rows = get_NOTE_rows($WT_TREE, $term);
451
-	// Filter for privacy
452
-	foreach ($rows as $row) {
453
-		$note = Note::getInstance($row->xref, $WT_TREE, $row->gedcom);
454
-		if ($note->canShowName()) {
455
-			$data[] = array('value' => $note->getXref(), 'label' => $note->getFullName());
456
-		}
457
-	}
458
-	echo json_encode($data);
459
-
460
-	return;
398
+    $data = array();
399
+    // Fetch all data, regardless of privacy
400
+    $rows = get_INDI_rows($WT_TREE, $term);
401
+    // Filter for privacy
402
+    foreach ($rows as $row) {
403
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
404
+        if ($person->canShowName()) {
405
+            $data[] = array('value' => $person->getXref(), 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
406
+        }
407
+    }
408
+    // Fetch all data, regardless of privacy
409
+    $rows = get_SOUR_rows($WT_TREE, $term);
410
+    // Filter for privacy
411
+    foreach ($rows as $row) {
412
+        $source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
413
+        if ($source->canShowName()) {
414
+            $data[] = array('value' => $source->getXref(), 'label' => $source->getFullName());
415
+        }
416
+    }
417
+    // Fetch all data, regardless of privacy
418
+    $rows = get_REPO_rows($WT_TREE, $term);
419
+    // Filter for privacy
420
+    foreach ($rows as $row) {
421
+        $repository = Repository::getInstance($row->xref, $WT_TREE, $row->gedcom);
422
+        if ($repository->canShowName()) {
423
+            $data[] = array('value' => $repository->getXref(), 'label' => $repository->getFullName());
424
+        }
425
+    }
426
+    // Fetch all data, regardless of privacy
427
+    $rows = get_OBJE_rows($WT_TREE, $term);
428
+    // Filter for privacy
429
+    foreach ($rows as $row) {
430
+        $media = Media::getInstance($row->xref, $WT_TREE, $row->gedcom);
431
+        if ($media->canShowName()) {
432
+            $data[] = array('value' => $media->getXref(), 'label' => '<img src="' . $media->getHtmlUrlDirect() . '" width="25"> ' . $media->getFullName());
433
+        }
434
+    }
435
+    // Fetch all data, regardless of privacy
436
+    $rows = get_FAM_rows($WT_TREE, $term);
437
+    // Filter for privacy
438
+    foreach ($rows as $row) {
439
+        $family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
440
+        if ($family->canShowName()) {
441
+            $marriage_year = $family->getMarriageYear();
442
+            if ($marriage_year) {
443
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
444
+            } else {
445
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
446
+            }
447
+        }
448
+    }
449
+    // Fetch all data, regardless of privacy
450
+    $rows = get_NOTE_rows($WT_TREE, $term);
451
+    // Filter for privacy
452
+    foreach ($rows as $row) {
453
+        $note = Note::getInstance($row->xref, $WT_TREE, $row->gedcom);
454
+        if ($note->canShowName()) {
455
+            $data[] = array('value' => $note->getXref(), 'label' => $note->getFullName());
456
+        }
457
+    }
458
+    echo json_encode($data);
459
+
460
+    return;
461 461
 
462 462
 case 'IFS':
463
-	$data = array();
464
-	// Fetch all data, regardless of privacy
465
-	$rows = get_INDI_rows($WT_TREE, $term);
466
-	// Filter for privacy
467
-	foreach ($rows as $row) {
468
-		$person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
469
-		if ($person->canShowName()) {
470
-			$data[] = array('value' => $person->getXref(), 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
471
-		}
472
-	}
473
-	// Fetch all data, regardless of privacy
474
-	$rows = get_SOUR_rows($WT_TREE, $term);
475
-	// Filter for privacy
476
-	foreach ($rows as $row) {
477
-		$source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
478
-		if ($source->canShowName()) {
479
-			$data[] = array('value' => $source->getXref(), 'label' => $source->getFullName());
480
-		}
481
-	}
482
-	// Fetch all data, regardless of privacy
483
-	$rows = get_FAM_rows($WT_TREE, $term);
484
-	// Filter for privacy
485
-	foreach ($rows as $row) {
486
-		$family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
487
-		if ($family->canShowName()) {
488
-			$marriage_year = $family->getMarriageYear();
489
-			if ($marriage_year) {
490
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
491
-			} else {
492
-				$data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
493
-			}
494
-		}
495
-	}
496
-	echo json_encode($data);
497
-
498
-	return;
463
+    $data = array();
464
+    // Fetch all data, regardless of privacy
465
+    $rows = get_INDI_rows($WT_TREE, $term);
466
+    // Filter for privacy
467
+    foreach ($rows as $row) {
468
+        $person = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom);
469
+        if ($person->canShowName()) {
470
+            $data[] = array('value' => $person->getXref(), 'label' => str_replace(array('@N.N.', '@P.N.'), array(I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')), $row->n_full) . ', <i>' . $person->getLifeSpan() . '</i>');
471
+        }
472
+    }
473
+    // Fetch all data, regardless of privacy
474
+    $rows = get_SOUR_rows($WT_TREE, $term);
475
+    // Filter for privacy
476
+    foreach ($rows as $row) {
477
+        $source = Source::getInstance($row->xref, $WT_TREE, $row->gedcom);
478
+        if ($source->canShowName()) {
479
+            $data[] = array('value' => $source->getXref(), 'label' => $source->getFullName());
480
+        }
481
+    }
482
+    // Fetch all data, regardless of privacy
483
+    $rows = get_FAM_rows($WT_TREE, $term);
484
+    // Filter for privacy
485
+    foreach ($rows as $row) {
486
+        $family = Family::getInstance($row->xref, $WT_TREE, $row->gedcom);
487
+        if ($family->canShowName()) {
488
+            $marriage_year = $family->getMarriageYear();
489
+            if ($marriage_year) {
490
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName() . ', <i>' . $marriage_year . '</i>');
491
+            } else {
492
+                $data[] = array('value' => $family->getXref(), 'label' => $family->getFullName());
493
+            }
494
+        }
495
+    }
496
+    echo json_encode($data);
497
+
498
+    return;
499 499
 }
500 500
 
501 501
 /**
@@ -507,19 +507,19 @@  discard block
 block discarded – undo
507 507
  * @return \stdClass[]
508 508
  */
509 509
 function get_FAM_rows(Tree $tree, $term) {
510
-	return Database::prepare(
511
-		"SELECT DISTINCT 'FAM' AS type, f_id AS xref, f_gedcom AS gedcom, husb_name.n_sort, wife_name.n_sort" .
512
-		" FROM `##families`" .
513
-		" JOIN `##name` AS husb_name ON f_husb = husb_name.n_id AND f_file = husb_name.n_file" .
514
-		" JOIN `##name` AS wife_name ON f_wife = wife_name.n_id AND f_file = wife_name.n_file" .
515
-		" WHERE CONCAT(husb_name.n_full, ' ', wife_name.n_full) LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND f_file = :tree_id" .
516
-		" AND husb_name.n_type <> '_MARNM' AND wife_name.n_type <> '_MARNM'" .
517
-		" ORDER BY husb_name.n_sort, wife_name.n_sort COLLATE :collation"
518
-	)->execute(array(
519
-		'term'      => $term,
520
-		'tree_id'   => $tree->getTreeId(),
521
-		'collation' => I18N::collation(),
522
-	))->fetchAll();
510
+    return Database::prepare(
511
+        "SELECT DISTINCT 'FAM' AS type, f_id AS xref, f_gedcom AS gedcom, husb_name.n_sort, wife_name.n_sort" .
512
+        " FROM `##families`" .
513
+        " JOIN `##name` AS husb_name ON f_husb = husb_name.n_id AND f_file = husb_name.n_file" .
514
+        " JOIN `##name` AS wife_name ON f_wife = wife_name.n_id AND f_file = wife_name.n_file" .
515
+        " WHERE CONCAT(husb_name.n_full, ' ', wife_name.n_full) LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND f_file = :tree_id" .
516
+        " AND husb_name.n_type <> '_MARNM' AND wife_name.n_type <> '_MARNM'" .
517
+        " ORDER BY husb_name.n_sort, wife_name.n_sort COLLATE :collation"
518
+    )->execute(array(
519
+        'term'      => $term,
520
+        'tree_id'   => $tree->getTreeId(),
521
+        'collation' => I18N::collation(),
522
+    ))->fetchAll();
523 523
 }
524 524
 
525 525
 /**
@@ -531,16 +531,16 @@  discard block
 block discarded – undo
531 531
  * @return \stdClass[]
532 532
  */
533 533
 function get_INDI_rows(Tree $tree, $term) {
534
-	return Database::prepare(
535
-		"SELECT 'INDI' AS type, i_id AS xref, i_gedcom AS gedcom, n_full" .
536
-		" FROM `##individuals`" .
537
-		" JOIN `##name` ON i_id = n_id AND i_file = n_file" .
538
-		" WHERE n_full LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND i_file = :tree_id ORDER BY n_full COLLATE :collation"
539
-	)->execute(array(
540
-		'term'      => $term,
541
-		'tree_id'   => $tree->getTreeId(),
542
-		'collation' => I18N::collation(),
543
-	))->fetchAll();
534
+    return Database::prepare(
535
+        "SELECT 'INDI' AS type, i_id AS xref, i_gedcom AS gedcom, n_full" .
536
+        " FROM `##individuals`" .
537
+        " JOIN `##name` ON i_id = n_id AND i_file = n_file" .
538
+        " WHERE n_full LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND i_file = :tree_id ORDER BY n_full COLLATE :collation"
539
+    )->execute(array(
540
+        'term'      => $term,
541
+        'tree_id'   => $tree->getTreeId(),
542
+        'collation' => I18N::collation(),
543
+    ))->fetchAll();
544 544
 }
545 545
 
546 546
 /**
@@ -552,17 +552,17 @@  discard block
 block discarded – undo
552 552
  * @return \stdClass[]
553 553
  */
554 554
 function get_NOTE_rows(Tree $tree, $term) {
555
-	return Database::prepare(
556
-		"SELECT o_id AS xref, o_gedcom AS gedcom" .
557
-		" FROM `##other`" .
558
-		" JOIN `##name` ON o_id = n_id AND o_file = n_file" .
559
-		" WHERE o_gedcom LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND o_file = :tree_id AND o_type = 'NOTE'" .
560
-		" ORDER BY n_full COLLATE :collation"
561
-	)->execute(array(
562
-		'term'      => $term,
563
-		'tree_id'   => $tree->getTreeId(),
564
-		'collation' => I18N::collation(),
565
-	))->fetchAll();
555
+    return Database::prepare(
556
+        "SELECT o_id AS xref, o_gedcom AS gedcom" .
557
+        " FROM `##other`" .
558
+        " JOIN `##name` ON o_id = n_id AND o_file = n_file" .
559
+        " WHERE o_gedcom LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND o_file = :tree_id AND o_type = 'NOTE'" .
560
+        " ORDER BY n_full COLLATE :collation"
561
+    )->execute(array(
562
+        'term'      => $term,
563
+        'tree_id'   => $tree->getTreeId(),
564
+        'collation' => I18N::collation(),
565
+    ))->fetchAll();
566 566
 }
567 567
 
568 568
 /**
@@ -574,17 +574,17 @@  discard block
 block discarded – undo
574 574
  * @return \stdClass[]
575 575
  */
576 576
 function get_OBJE_rows(Tree $tree, $term) {
577
-	return Database::prepare(
578
-		"SELECT 'OBJE' AS type, m_id AS xref, m_gedcom AS gedcom" .
579
-		" FROM `##media`" .
580
-		" WHERE (m_titl LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR m_id LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND m_file = :tree_id" .
581
-		" ORDER BY m_titl COLLATE :collation"
582
-	)->execute(array(
583
-		'term_1'    => $term,
584
-		'term_2'    => $term,
585
-		'tree_id'   => $tree->getTreeId(),
586
-		'collation' => I18N::collation(),
587
-	))->fetchAll();
577
+    return Database::prepare(
578
+        "SELECT 'OBJE' AS type, m_id AS xref, m_gedcom AS gedcom" .
579
+        " FROM `##media`" .
580
+        " WHERE (m_titl LIKE CONCAT('%', REPLACE(:term_1, ' ', '%'), '%') OR m_id LIKE CONCAT('%', REPLACE(:term_2, ' ', '%'), '%')) AND m_file = :tree_id" .
581
+        " ORDER BY m_titl COLLATE :collation"
582
+    )->execute(array(
583
+        'term_1'    => $term,
584
+        'term_2'    => $term,
585
+        'tree_id'   => $tree->getTreeId(),
586
+        'collation' => I18N::collation(),
587
+    ))->fetchAll();
588 588
 }
589 589
 
590 590
 /**
@@ -596,17 +596,17 @@  discard block
 block discarded – undo
596 596
  * @return \stdClass[]
597 597
  */
598 598
 function get_REPO_rows(Tree $tree, $term) {
599
-	return Database::prepare(
600
-		"SELECT o_id AS xref, o_gedcom AS gedcom" .
601
-		" FROM `##other`" .
602
-		" JOIN `##name` ON o_id = n_id AND o_file = n_file" .
603
-		" WHERE n_full LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND o_file = :tree_id AND o_type = 'REPO'" .
604
-		" ORDER BY n_full COLLATE :collation"
605
-	)->execute(array(
606
-		'term'      => $term,
607
-		'tree_id'   => $tree->getTreeId(),
608
-		'collation' => I18N::collation(),
609
-	))->fetchAll();
599
+    return Database::prepare(
600
+        "SELECT o_id AS xref, o_gedcom AS gedcom" .
601
+        " FROM `##other`" .
602
+        " JOIN `##name` ON o_id = n_id AND o_file = n_file" .
603
+        " WHERE n_full LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND o_file = :tree_id AND o_type = 'REPO'" .
604
+        " ORDER BY n_full COLLATE :collation"
605
+    )->execute(array(
606
+        'term'      => $term,
607
+        'tree_id'   => $tree->getTreeId(),
608
+        'collation' => I18N::collation(),
609
+    ))->fetchAll();
610 610
 }
611 611
 
612 612
 /**
@@ -618,14 +618,14 @@  discard block
 block discarded – undo
618 618
  * @return \stdClass[]
619 619
  */
620 620
 function get_SOUR_rows(Tree $tree, $term) {
621
-	return Database::prepare(
622
-		"SELECT s_id AS xref, s_gedcom AS gedcom" .
623
-		" FROM `##sources`" .
624
-		" WHERE s_name LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND s_file = :tree_id" .
625
-		" ORDER BY s_name COLLATE :collation"
626
-	)->execute(array(
627
-		'term'      => $term,
628
-		'tree_id'   => $tree->getTreeId(),
629
-		'collation' => I18N::collation(),
630
-	))->fetchAll();
621
+    return Database::prepare(
622
+        "SELECT s_id AS xref, s_gedcom AS gedcom" .
623
+        " FROM `##sources`" .
624
+        " WHERE s_name LIKE CONCAT('%', REPLACE(:term, ' ', '%'), '%') AND s_file = :tree_id" .
625
+        " ORDER BY s_name COLLATE :collation"
626
+    )->execute(array(
627
+        'term'      => $term,
628
+        'tree_id'   => $tree->getTreeId(),
629
+        'collation' => I18N::collation(),
630
+    ))->fetchAll();
631 631
 }
Please login to merge, or discard this patch.
help_text.php 1 patch
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -20,306 +20,306 @@
 block discarded – undo
20 20
 
21 21
 $help = Filter::get('help');
22 22
 switch ($help) {
23
-	//////////////////////////////////////////////////////////////////////////////
24
-	// This is a list of all known gedcom tags. We list them all here so that
25
-	// xgettext() may find them.
26
-	//
27
-	// Tags such as BIRT:PLAC are only used as labels, and do not require help
28
-	// text. These are only used for translating labels.
29
-	//
30
-	// Tags such as _BIRT_CHIL are pseudo-tags, used to create family events.
31
-	//
32
-	// Generally, these tags need to be lists explicitly in FunctionsEdit::add_simple_tag()
33
-	//////////////////////////////////////////////////////////////////////////////
23
+    //////////////////////////////////////////////////////////////////////////////
24
+    // This is a list of all known gedcom tags. We list them all here so that
25
+    // xgettext() may find them.
26
+    //
27
+    // Tags such as BIRT:PLAC are only used as labels, and do not require help
28
+    // text. These are only used for translating labels.
29
+    //
30
+    // Tags such as _BIRT_CHIL are pseudo-tags, used to create family events.
31
+    //
32
+    // Generally, these tags need to be lists explicitly in FunctionsEdit::add_simple_tag()
33
+    //////////////////////////////////////////////////////////////////////////////
34 34
 
35 35
 case 'DATE':
36
-	$title = GedcomTag::getLabel('DATE');
37
-	$dates = array(
38
-		'1900'                                                       => new Date('1900'),
39
-		'JAN 1900'                                                   => new Date('JAN 1900'),
40
-		'FEB 1900'                                                   => new Date('FEB 1900'),
41
-		'MAR 1900'                                                   => new Date('MAR 1900'),
42
-		'APR 1900'                                                   => new Date('APR 1900'),
43
-		'MAY 1900'                                                   => new Date('MAY 1900'),
44
-		'JUN 1900'                                                   => new Date('JUN 1900'),
45
-		'JUL 1900'                                                   => new Date('JUL 1900'),
46
-		'AUG 1900'                                                   => new Date('AUG 1900'),
47
-		'SEP 1900'                                                   => new Date('SEP 1900'),
48
-		'OCT 1900'                                                   => new Date('OCT 1900'),
49
-		'NOV 1900'                                                   => new Date('NOV 1900'),
50
-		'DEC 1900'                                                   => new Date('DEC 1900'),
51
-		'11 DEC 1913'                                                => new Date('11 DEC 1913'),
52
-		'01 FEB 2003'                                                => new Date('01 FEB 2003'),
53
-		'ABT 1900'                                                   => new Date('ABT 1900'),
54
-		'EST 1900'                                                   => new Date('EST 1900'),
55
-		'CAL 1900'                                                   => new Date('CAL 1900'),
56
-		'INT 1900 (...)'                                             => new Date('INT 1900 (...)'),
57
-		'@#DJULIAN@ 44 B.C.'                                         => new Date('@#DJULIAN@ 44 B.C.'),
58
-		'@#DJULIAN@ 14 JAN 1700'                                     => new Date('@#DJULIAN@ 14 JAN 1700'),
59
-		'BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'   => new Date('BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'),
60
-		'@#DJULIAN@ 20 FEB 1742/43'                                  => new Date('@#DJULIAN@ 20 FEB 1742/43'),
61
-		'FROM 1900 TO 1910'                                          => new Date('FROM 1900 TO 1910'),
62
-		'FROM 1900'                                                  => new Date('FROM 1900'),
63
-		'TO 1910'                                                    => new Date('TO 1910'),
64
-		'BET 1900 AND 1910'                                          => new Date('BET 1900 AND 1910'),
65
-		'BET JAN 1900 AND MAR 1900'                                  => new Date('BET JAN 1900 AND MAR 1900'),
66
-		'BET APR 1900 AND JUN 1900'                                  => new Date('BET APR 1900 AND JUN 1900'),
67
-		'BET JUL 1900 AND SEP 1900'                                  => new Date('BET JUL 1900 AND SEP 1900'),
68
-		'BET OCT 1900 AND DEC 1900'                                  => new Date('BET OCT 1900 AND DEC 1900'),
69
-		'AFT 1900'                                                   => new Date('AFT 1900'),
70
-		'BEF 1910'                                                   => new Date('BEF 1910'),
71
-		// Hijri dates
72
-		'@#DHIJRI@ 1497'                                    => new Date('@#DHIJRI@ 1497'),
73
-		'@#DHIJRI@ MUHAR 1497'                              => new Date('@#DHIJRI@ MUHAR 1497'),
74
-		'ABT @#DHIJRI@ SAFAR 1497'                          => new Date('ABT @#DHIJRI@ SAFAR 1497'),
75
-		'BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497' => new Date('BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497'),
76
-		'FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497' => new Date('FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497'),
77
-		'AFT @#DHIJRI@ RAJAB 1497'                          => new Date('AFT @#DHIJRI@ RAJAB 1497'),
78
-		'BEF @#DHIJRI@ SHAAB 1497'                          => new Date('BEF @#DHIJRI@ SHAAB 1497'),
79
-		'ABT @#DHIJRI@ RAMAD 1497'                          => new Date('ABT @#DHIJRI@ RAMAD 1497'),
80
-		'FROM @#DHIJRI@ SHAWW 1497'                         => new Date('FROM @#DHIJRI@ SHAWW 1497'),
81
-		'TO @#DHIJRI@ DHUAQ 1497'                           => new Date('TO @#DHIJRI@ DHUAQ 1497'),
82
-		'@#DHIJRI@ 03 DHUAH 1497'                           => new Date('@#DHIJRI@ 03 DHUAH 1497'),
83
-		// French dates
84
-		'@#DFRENCH R@ 12'                                   => new Date('@#DFRENCH R@ 12'),
85
-		'@#DFRENCH R@ VEND 12'                              => new Date('@#DFRENCH R@ VEND 12'),
86
-		'ABT @#DFRENCH R@ BRUM 12'                          => new Date('ABT @#DFRENCH R@ BRUM 12'),
87
-		'BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12' => new Date('BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12'),
88
-		'FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12' => new Date('FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12'),
89
-		'AFT @#DFRENCH R@ GERM 12'                          => new Date('AFT @#DFRENCH R@ GERM 12'),
90
-		'BEF @#DFRENCH R@ FLOR 12'                          => new Date('BEF @#DFRENCH R@ FLOR 12'),
91
-		'ABT @#DFRENCH R@ PRAI 12'                          => new Date('ABT @#DFRENCH R@ PRAI 12'),
92
-		'FROM @#DFRENCH R@ MESS 12'                         => new Date('FROM @#DFRENCH R@ MESS 12'),
93
-		'TO @#DFRENCH R@ THER 12'                           => new Date('TO @#DFRENCH R@ THER 12'),
94
-		'EST @#DFRENCH R@ FRUC 12'                          => new Date('EST @#DFRENCH R@ FRUC 12'),
95
-		'@#DFRENCH R@ 03 COMP 12'                           => new Date('@#DFRENCH R@ 03 COMP 12'),
96
-		// Jewish dates
97
-		'@#DHEBREW@ 5481'                                 => new Date('@#DHEBREW@ 5481'),
98
-		'@#DHEBREW@ TSH 5481'                             => new Date('@#DHEBREW@ TSH 5481'),
99
-		'ABT @#DHEBREW@ CSH 5481'                         => new Date('ABT @#DHEBREW@ CSH 5481'),
100
-		'BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481' => new Date('BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481'),
101
-		'FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481' => new Date('FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481'),
102
-		'AFT @#DHEBREW@ ADR 5481'                         => new Date('AFT @#DHEBREW@ ADR 5481'),
103
-		'AFT @#DHEBREW@ ADS 5480'                         => new Date('AFT @#DHEBREW@ ADS 5480'),
104
-		'BEF @#DHEBREW@ NSN 5481'                         => new Date('BEF @#DHEBREW@ NSN 5481'),
105
-		'ABT @#DHEBREW@ IYR 5481'                         => new Date('ABT @#DHEBREW@ IYR 5481'),
106
-		'FROM @#DHEBREW@ SVN 5481'                        => new Date('FROM @#DHEBREW@ SVN 5481'),
107
-		'TO @#DHEBREW@ TMZ 5481'                          => new Date('TO @#DHEBREW@ TMZ 5481'),
108
-		'EST @#DHEBREW@ AAV 5481'                         => new Date('EST @#DHEBREW@ AAV 5481'),
109
-		'@#DHEBREW@ 03 ELL 5481'                          => new Date('@#DHEBREW@ 03 ELL 5481'),
110
-	);
36
+    $title = GedcomTag::getLabel('DATE');
37
+    $dates = array(
38
+        '1900'                                                       => new Date('1900'),
39
+        'JAN 1900'                                                   => new Date('JAN 1900'),
40
+        'FEB 1900'                                                   => new Date('FEB 1900'),
41
+        'MAR 1900'                                                   => new Date('MAR 1900'),
42
+        'APR 1900'                                                   => new Date('APR 1900'),
43
+        'MAY 1900'                                                   => new Date('MAY 1900'),
44
+        'JUN 1900'                                                   => new Date('JUN 1900'),
45
+        'JUL 1900'                                                   => new Date('JUL 1900'),
46
+        'AUG 1900'                                                   => new Date('AUG 1900'),
47
+        'SEP 1900'                                                   => new Date('SEP 1900'),
48
+        'OCT 1900'                                                   => new Date('OCT 1900'),
49
+        'NOV 1900'                                                   => new Date('NOV 1900'),
50
+        'DEC 1900'                                                   => new Date('DEC 1900'),
51
+        '11 DEC 1913'                                                => new Date('11 DEC 1913'),
52
+        '01 FEB 2003'                                                => new Date('01 FEB 2003'),
53
+        'ABT 1900'                                                   => new Date('ABT 1900'),
54
+        'EST 1900'                                                   => new Date('EST 1900'),
55
+        'CAL 1900'                                                   => new Date('CAL 1900'),
56
+        'INT 1900 (...)'                                             => new Date('INT 1900 (...)'),
57
+        '@#DJULIAN@ 44 B.C.'                                         => new Date('@#DJULIAN@ 44 B.C.'),
58
+        '@#DJULIAN@ 14 JAN 1700'                                     => new Date('@#DJULIAN@ 14 JAN 1700'),
59
+        'BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'   => new Date('BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'),
60
+        '@#DJULIAN@ 20 FEB 1742/43'                                  => new Date('@#DJULIAN@ 20 FEB 1742/43'),
61
+        'FROM 1900 TO 1910'                                          => new Date('FROM 1900 TO 1910'),
62
+        'FROM 1900'                                                  => new Date('FROM 1900'),
63
+        'TO 1910'                                                    => new Date('TO 1910'),
64
+        'BET 1900 AND 1910'                                          => new Date('BET 1900 AND 1910'),
65
+        'BET JAN 1900 AND MAR 1900'                                  => new Date('BET JAN 1900 AND MAR 1900'),
66
+        'BET APR 1900 AND JUN 1900'                                  => new Date('BET APR 1900 AND JUN 1900'),
67
+        'BET JUL 1900 AND SEP 1900'                                  => new Date('BET JUL 1900 AND SEP 1900'),
68
+        'BET OCT 1900 AND DEC 1900'                                  => new Date('BET OCT 1900 AND DEC 1900'),
69
+        'AFT 1900'                                                   => new Date('AFT 1900'),
70
+        'BEF 1910'                                                   => new Date('BEF 1910'),
71
+        // Hijri dates
72
+        '@#DHIJRI@ 1497'                                    => new Date('@#DHIJRI@ 1497'),
73
+        '@#DHIJRI@ MUHAR 1497'                              => new Date('@#DHIJRI@ MUHAR 1497'),
74
+        'ABT @#DHIJRI@ SAFAR 1497'                          => new Date('ABT @#DHIJRI@ SAFAR 1497'),
75
+        'BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497' => new Date('BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497'),
76
+        'FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497' => new Date('FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497'),
77
+        'AFT @#DHIJRI@ RAJAB 1497'                          => new Date('AFT @#DHIJRI@ RAJAB 1497'),
78
+        'BEF @#DHIJRI@ SHAAB 1497'                          => new Date('BEF @#DHIJRI@ SHAAB 1497'),
79
+        'ABT @#DHIJRI@ RAMAD 1497'                          => new Date('ABT @#DHIJRI@ RAMAD 1497'),
80
+        'FROM @#DHIJRI@ SHAWW 1497'                         => new Date('FROM @#DHIJRI@ SHAWW 1497'),
81
+        'TO @#DHIJRI@ DHUAQ 1497'                           => new Date('TO @#DHIJRI@ DHUAQ 1497'),
82
+        '@#DHIJRI@ 03 DHUAH 1497'                           => new Date('@#DHIJRI@ 03 DHUAH 1497'),
83
+        // French dates
84
+        '@#DFRENCH R@ 12'                                   => new Date('@#DFRENCH R@ 12'),
85
+        '@#DFRENCH R@ VEND 12'                              => new Date('@#DFRENCH R@ VEND 12'),
86
+        'ABT @#DFRENCH R@ BRUM 12'                          => new Date('ABT @#DFRENCH R@ BRUM 12'),
87
+        'BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12' => new Date('BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12'),
88
+        'FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12' => new Date('FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12'),
89
+        'AFT @#DFRENCH R@ GERM 12'                          => new Date('AFT @#DFRENCH R@ GERM 12'),
90
+        'BEF @#DFRENCH R@ FLOR 12'                          => new Date('BEF @#DFRENCH R@ FLOR 12'),
91
+        'ABT @#DFRENCH R@ PRAI 12'                          => new Date('ABT @#DFRENCH R@ PRAI 12'),
92
+        'FROM @#DFRENCH R@ MESS 12'                         => new Date('FROM @#DFRENCH R@ MESS 12'),
93
+        'TO @#DFRENCH R@ THER 12'                           => new Date('TO @#DFRENCH R@ THER 12'),
94
+        'EST @#DFRENCH R@ FRUC 12'                          => new Date('EST @#DFRENCH R@ FRUC 12'),
95
+        '@#DFRENCH R@ 03 COMP 12'                           => new Date('@#DFRENCH R@ 03 COMP 12'),
96
+        // Jewish dates
97
+        '@#DHEBREW@ 5481'                                 => new Date('@#DHEBREW@ 5481'),
98
+        '@#DHEBREW@ TSH 5481'                             => new Date('@#DHEBREW@ TSH 5481'),
99
+        'ABT @#DHEBREW@ CSH 5481'                         => new Date('ABT @#DHEBREW@ CSH 5481'),
100
+        'BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481' => new Date('BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481'),
101
+        'FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481' => new Date('FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481'),
102
+        'AFT @#DHEBREW@ ADR 5481'                         => new Date('AFT @#DHEBREW@ ADR 5481'),
103
+        'AFT @#DHEBREW@ ADS 5480'                         => new Date('AFT @#DHEBREW@ ADS 5480'),
104
+        'BEF @#DHEBREW@ NSN 5481'                         => new Date('BEF @#DHEBREW@ NSN 5481'),
105
+        'ABT @#DHEBREW@ IYR 5481'                         => new Date('ABT @#DHEBREW@ IYR 5481'),
106
+        'FROM @#DHEBREW@ SVN 5481'                        => new Date('FROM @#DHEBREW@ SVN 5481'),
107
+        'TO @#DHEBREW@ TMZ 5481'                          => new Date('TO @#DHEBREW@ TMZ 5481'),
108
+        'EST @#DHEBREW@ AAV 5481'                         => new Date('EST @#DHEBREW@ AAV 5481'),
109
+        '@#DHEBREW@ 03 ELL 5481'                          => new Date('@#DHEBREW@ 03 ELL 5481'),
110
+    );
111 111
 
112
-	foreach ($dates as &$date) {
113
-		$date = strip_tags($date->display(false, null, false));
114
-	}
115
-	// These shortcuts work differently for different languages
116
-	switch (preg_replace('/[^DMY]/', '', str_replace(array('J', 'F'), array('D', 'M'), I18N::dateFormat()))) {
117
-	case 'YMD':
118
-		$example1 = '11/12/1913'; // Note: we ignore the DMY order if it doesn't make sense.
119
-		$example2 = '03/02/01';
120
-		break;
121
-	case 'MDY':
122
-		$example1 = '12/11/1913';
123
-		$example2 = '02/01/03';
124
-		break;
125
-	case 'DMY':
126
-	default:
127
-		$example1 = '11/12/1913';
128
-		$example2 = '01/02/03';
129
-		break;
130
-	}
131
-	$example1 .= '<br>' . str_replace('/', '-', $example1) . '<br>' . str_replace('/', '.', $example1);
132
-	$example2 .= '<br>' . str_replace('/', '-', $example2) . '<br>' . str_replace('/', '.', $example2);
133
-	$text =
134
-		'<p>' . I18N::translate('Dates are stored using English abbreviations and keywords. Shortcuts are available as alternatives to these abbreviations and keywords.') . '</p>' .
135
-		'<table border="1">' .
136
-		'<tr><th>' . I18N::translate('Date') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
137
-		'<tr><td>' . $dates['1900'] . '</td><td><kbd dir="ltr" lang="en">1900</kbd></td><td></td></tr>' .
138
-		'<tr><td>' . $dates['JAN 1900'] . '<br>' . $dates['FEB 1900'] . '<br>' . $dates['MAR 1900'] . '<br>' . $dates['APR 1900'] . '<br>' . $dates['MAY 1900'] . '<br>' . $dates['JUN 1900'] . '<br>' . $dates['JUL 1900'] . '<br>' . $dates['AUG 1900'] . '<br>' . $dates['SEP 1900'] . '<br>' . $dates['OCT 1900'] . '<br>' . $dates['NOV 1900'] . '<br>' . $dates['DEC 1900'] . '</td><td><kbd dir="ltr" lang="en">JAN 1900<br>FEB 1900<br>MAR 1900<br>APR 1900<br>MAY 1900<br>JUN 1900<br>JUL 1900<br>AUG 1900<br>SEP 1900<br>OCT 1900<br>NOV 1900<br>DEC 1900</kbd></td><td></td></tr>' .
139
-		'<tr><td>' . $dates['11 DEC 1913'] . '</td><td><kbd dir="ltr" lang="en">11 DEC 1913</kbd></td><td><kbd dir="ltr" lang="en">' . $example1 . '</kbd></td></tr>' .
140
-		'<tr><td>' . $dates['01 FEB 2003'] . '</td><td><kbd dir="ltr" lang="en">01 FEB 2003</kbd></td><td><kbd dir="ltr" lang="en">' . $example2 . '</kbd></td></tr>' .
141
-		'<tr><td>' . $dates['ABT 1900'] . '</td><td><kbd dir="ltr" lang="en">ABT 1900</kbd></td><td><kbd dir="ltr" lang="en">~1900</kbd></td></tr>' .
142
-		'<tr><td>' . $dates['EST 1900'] . '</td><td><kbd dir="ltr" lang="en">EST 1900</kbd></td><td><kbd dir="ltr" lang="en">*1900</kbd></td></tr>' .
143
-		'<tr><td>' . $dates['CAL 1900'] . '</td><td><kbd dir="ltr" lang="en">CAL 1900</kbd></td><td><kbd dir="ltr" lang="en">#1900</kbd></td></tr>' .
144
-		'<tr><td>' . $dates['INT 1900 (...)'] . '</td><td><kbd dir="ltr" lang="en">INT 1900 (...)</kbd></td><td></td></tr>' .
145
-		'</table>' .
146
-		'<p>' . I18N::translate('Date ranges are used to indicate that an event, such as a birth, happened on an unknown date within a possible range.') . '</p>' .
147
-		'<table border="1">' .
148
-		'<tr><th>' . I18N::translate('Date range') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
149
-		'<tr><td>' . $dates['BET 1900 AND 1910'] . '</td><td><kbd dir="ltr" lang="en">BET 1900 AND 1910</kbd></td><td><kbd dir="ltr" lang="en">1900-1910</kbd></td></tr>' .
150
-		'<tr><td>' . $dates['AFT 1900'] . '</td><td><kbd dir="ltr" lang="en">AFT 1900</kbd></td><td><kbd dir="ltr" lang="en">&gt;1900</kbd></td></tr>' .
151
-		'<tr><td>' . $dates['BEF 1910'] . '</td><td><kbd dir="ltr" lang="en">BEF 1910</kbd></td><td><kbd dir="ltr" lang="en">&lt;1910</kbd></td></tr>' .
152
-		'<tr><td>' . $dates['BET JAN 1900 AND MAR 1900'] . '</td><td><kbd dir="ltr" lang="en">BET JAN 1900 AND MAR 1900</kbd></td><td><kbd dir="ltr" lang="en">Q1 1900</kbd></td></tr>' .
153
-		'<tr><td>' . $dates['BET APR 1900 AND JUN 1900'] . '</td><td><kbd dir="ltr" lang="en">BET APR 1900 AND JUN 1900</kbd></td><td><kbd dir="ltr" lang="en">Q2 1900</kbd></td></tr>' .
154
-		'<tr><td>' . $dates['BET JUL 1900 AND SEP 1900'] . '</td><td><kbd dir="ltr" lang="en">BET JUL 1900 AND SEP 1900</kbd></td><td><kbd dir="ltr" lang="en">Q3 1900</kbd></td></tr>' .
155
-		'<tr><td>' . $dates['BET OCT 1900 AND DEC 1900'] . '</td><td><kbd dir="ltr" lang="en">BET OCT 1900 AND DEC 1900</kbd></td><td><kbd dir="ltr" lang="en">Q4 1900</kbd></td></tr>' .
156
-		'</table>' .
157
-		'<p>' . I18N::translate('Date periods are used to indicate that a fact, such as an occupation, continued for a period of time.') . '</p>' .
158
-		'<table border="1">' .
159
-		'<tr><th>' . I18N::translate('Date period') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
160
-		'<tr><td>' . $dates['FROM 1900 TO 1910'] . '</td><td><kbd dir="ltr" lang="en">FROM 1900 TO 1910</kbd></td><td><kbd dir="ltr" lang="en">1900~1910</kbd></td></tr>' .
161
-		'<tr><td>' . $dates['FROM 1900'] . '</td><td><kbd dir="ltr" lang="en">FROM 1900</kbd></td><td><kbd dir="ltr" lang="en">1900-</kbd></td></tr>' .
162
-		'<tr><td>' . $dates['TO 1910'] . '</td><td><kbd dir="ltr" lang="en">TO 1910</kbd></td><td><kbd dir="ltr" lang="en">-1900</kbd></td></tr>' .
163
-		'</table>' .
164
-		'<p>' . I18N::translate('Simple dates are assumed to be in the gregorian calendar. To specify a date in another calendar, add a keyword before the date. This keyword is optional if the month or year format make the date unambiguous.') . '</p>' .
165
-		'<table border="1">' .
166
-		'<tr><th>' . I18N::translate('Date') . '</th><th>' . I18N::translate('Format') . '</th></tr>' .
167
-		'<tr><th colspan="2">' . I18N::translate('Julian') . '</th></tr>' .
168
-		'<tr><td>' . $dates['@#DJULIAN@ 14 JAN 1700'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 14 JAN 1700</kbd></td></tr>' .
169
-		'<tr><td>' . $dates['@#DJULIAN@ 44 B.C.'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 44 B.C.</kbd></td></tr>' .
170
-		'<tr><td>' . $dates['@#DJULIAN@ 20 FEB 1742/43'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 20 FEB 1742/43</kbd></td></tr>' .
171
-		'<tr><td>' . $dates['BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'] . '</td><td><kbd dir="ltr" lang="en">BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752</kbd></td></tr>' .
172
-		'<tr><th colspan="2">' . I18N::translate('Jewish') . '</th></tr>' .
173
-		'<tr><td>' . $dates['@#DHEBREW@ 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ 5481</kbd></td></tr>' .
174
-		'<tr><td>' . $dates['@#DHEBREW@ TSH 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ TSH 5481</kbd></td></tr>' .
175
-		'<tr><td>' . $dates['ABT @#DHEBREW@ CSH 5481'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHEBREW@ CSH 5481</kbd></td></tr>' .
176
-		'<tr><td>' . $dates['BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481'] . '</td><td><kbd dir="ltr" lang="en">BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481</kbd></td></tr>' .
177
-		'<tr><td>' . $dates['FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481</kbd></td></tr>' .
178
-		'<tr><td>' . $dates['AFT @#DHEBREW@ ADR 5481'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHEBREW@ ADR 5481</kbd></td></tr>' .
179
-		'<tr><td>' . $dates['AFT @#DHEBREW@ ADS 5480'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHEBREW@ ADS 5480</kbd></td></tr>' .
180
-		'<tr><td>' . $dates['BEF @#DHEBREW@ NSN 5481'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DHEBREW@ NSN 5481</kbd></td></tr>' .
181
-		'<tr><td>' . $dates['ABT @#DHEBREW@ IYR 5481'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHEBREW@ IYR 5481</kbd></td></tr>' .
182
-		'<tr><td>' . $dates['FROM @#DHEBREW@ SVN 5481'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHEBREW@ SVN 5481</kbd></td></tr>' .
183
-		'<tr><td>' . $dates['TO @#DHEBREW@ TMZ 5481'] . '</td><td><kbd dir="ltr" lang="en">TO @#DHEBREW@ TMZ 5481</kbd></td></tr>' .
184
-		'<tr><td>' . $dates['EST @#DHEBREW@ AAV 5481'] . '</td><td><kbd dir="ltr" lang="en">EST @#DHEBREW@ AAV 5481</kbd></td></tr>' .
185
-		'<tr><td>' . $dates['@#DHEBREW@ 03 ELL 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ 03 ELL 5481</kbd></td></tr>' .
186
-		'<tr><th colspan="2">' . I18N::translate('Hijri') . '</th></tr>' .
187
-		'<tr><td>' . $dates['@#DHIJRI@ 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ 1497</kbd></td></tr>' .
188
-		'<tr><td>' . $dates['@#DHIJRI@ MUHAR 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ MUHAR 1497</kbd></td></tr>' .
189
-		'<tr><td>' . $dates['ABT @#DHIJRI@ SAFAR 1497'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHIJRI@ SAFAR 1497</kbd></td></tr>' .
190
-		'<tr><td>' . $dates['BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497'] . '</td><td><kbd dir="ltr" lang="en">BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497</kbd></td></tr>' .
191
-		'<tr><td>' . $dates['FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497</kbd></td></tr>' .
192
-		'<tr><td>' . $dates['AFT @#DHIJRI@ RAJAB 1497'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHIJRI@ RAJAB 1497</kbd></td></tr>' .
193
-		'<tr><td>' . $dates['BEF @#DHIJRI@ SHAAB 1497'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DHIJRI@ SHAAB 1497</kbd></td></tr>' .
194
-		'<tr><td>' . $dates['ABT @#DHIJRI@ RAMAD 1497'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHIJRI@ RAMAD 1497</kbd></td></tr>' .
195
-		'<tr><td>' . $dates['FROM @#DHIJRI@ SHAWW 1497'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHIJRI@ SHAWW 1497</kbd></td></tr>' .
196
-		'<tr><td>' . $dates['TO @#DHIJRI@ DHUAQ 1497'] . '</td><td><kbd dir="ltr" lang="en">TO @#DHIJRI@ DHUAQ 1497</kbd></td></tr>' .
197
-		'<tr><td>' . $dates['@#DHIJRI@ 03 DHUAH 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ 03 DHUAH 1497</kbd></td></tr>' .
198
-		'<tr><th colspan="2">' . I18N::translate('French') . '</th></tr>' .
199
-		'<tr><td>' . $dates['@#DFRENCH R@ 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ 12</kbd></td></tr>' .
200
-		'<tr><td>' . $dates['@#DFRENCH R@ VEND 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ VEND 12</kbd></td></tr>' .
201
-		'<tr><td>' . $dates['ABT @#DFRENCH R@ BRUM 12'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DFRENCH R@ BRUM 12</kbd></td></tr>' .
202
-		'<tr><td>' . $dates['BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12'] . '</td><td><kbd dir="ltr" lang="en">BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12</kbd></td></tr>' .
203
-		'<tr><td>' . $dates['FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12</kbd></td></tr>' .
204
-		'<tr><td>' . $dates['AFT @#DFRENCH R@ GERM 12'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DFRENCH R@ GERM 12</kbd></td></tr>' .
205
-		'<tr><td>' . $dates['BEF @#DFRENCH R@ FLOR 12'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DFRENCH R@ FLOR 12</kbd></td></tr>' .
206
-		'<tr><td>' . $dates['ABT @#DFRENCH R@ PRAI 12'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DFRENCH R@ PRAI 12</kbd></td></tr>' .
207
-		'<tr><td>' . $dates['FROM @#DFRENCH R@ MESS 12'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DFRENCH R@ MESS 12</kbd></td></tr>' .
208
-		'<tr><td>' . $dates['TO @#DFRENCH R@ THER 12'] . '</td><td><kbd dir="ltr" lang="en">TO @#DFRENCH R@ THER 12</kbd></td></tr>' .
209
-		'<tr><td>' . $dates['EST @#DFRENCH R@ FRUC 12'] . '</td><td><kbd dir="ltr" lang="en">EST @#DFRENCH R@ FRUC 12</kbd></td></tr>' .
210
-		'<tr><td>' . $dates['@#DFRENCH R@ 03 COMP 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ 03 COMP 12</kbd></td></tr>' .
211
-		'</table>';
212
-	break;
112
+    foreach ($dates as &$date) {
113
+        $date = strip_tags($date->display(false, null, false));
114
+    }
115
+    // These shortcuts work differently for different languages
116
+    switch (preg_replace('/[^DMY]/', '', str_replace(array('J', 'F'), array('D', 'M'), I18N::dateFormat()))) {
117
+    case 'YMD':
118
+        $example1 = '11/12/1913'; // Note: we ignore the DMY order if it doesn't make sense.
119
+        $example2 = '03/02/01';
120
+        break;
121
+    case 'MDY':
122
+        $example1 = '12/11/1913';
123
+        $example2 = '02/01/03';
124
+        break;
125
+    case 'DMY':
126
+    default:
127
+        $example1 = '11/12/1913';
128
+        $example2 = '01/02/03';
129
+        break;
130
+    }
131
+    $example1 .= '<br>' . str_replace('/', '-', $example1) . '<br>' . str_replace('/', '.', $example1);
132
+    $example2 .= '<br>' . str_replace('/', '-', $example2) . '<br>' . str_replace('/', '.', $example2);
133
+    $text =
134
+        '<p>' . I18N::translate('Dates are stored using English abbreviations and keywords. Shortcuts are available as alternatives to these abbreviations and keywords.') . '</p>' .
135
+        '<table border="1">' .
136
+        '<tr><th>' . I18N::translate('Date') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
137
+        '<tr><td>' . $dates['1900'] . '</td><td><kbd dir="ltr" lang="en">1900</kbd></td><td></td></tr>' .
138
+        '<tr><td>' . $dates['JAN 1900'] . '<br>' . $dates['FEB 1900'] . '<br>' . $dates['MAR 1900'] . '<br>' . $dates['APR 1900'] . '<br>' . $dates['MAY 1900'] . '<br>' . $dates['JUN 1900'] . '<br>' . $dates['JUL 1900'] . '<br>' . $dates['AUG 1900'] . '<br>' . $dates['SEP 1900'] . '<br>' . $dates['OCT 1900'] . '<br>' . $dates['NOV 1900'] . '<br>' . $dates['DEC 1900'] . '</td><td><kbd dir="ltr" lang="en">JAN 1900<br>FEB 1900<br>MAR 1900<br>APR 1900<br>MAY 1900<br>JUN 1900<br>JUL 1900<br>AUG 1900<br>SEP 1900<br>OCT 1900<br>NOV 1900<br>DEC 1900</kbd></td><td></td></tr>' .
139
+        '<tr><td>' . $dates['11 DEC 1913'] . '</td><td><kbd dir="ltr" lang="en">11 DEC 1913</kbd></td><td><kbd dir="ltr" lang="en">' . $example1 . '</kbd></td></tr>' .
140
+        '<tr><td>' . $dates['01 FEB 2003'] . '</td><td><kbd dir="ltr" lang="en">01 FEB 2003</kbd></td><td><kbd dir="ltr" lang="en">' . $example2 . '</kbd></td></tr>' .
141
+        '<tr><td>' . $dates['ABT 1900'] . '</td><td><kbd dir="ltr" lang="en">ABT 1900</kbd></td><td><kbd dir="ltr" lang="en">~1900</kbd></td></tr>' .
142
+        '<tr><td>' . $dates['EST 1900'] . '</td><td><kbd dir="ltr" lang="en">EST 1900</kbd></td><td><kbd dir="ltr" lang="en">*1900</kbd></td></tr>' .
143
+        '<tr><td>' . $dates['CAL 1900'] . '</td><td><kbd dir="ltr" lang="en">CAL 1900</kbd></td><td><kbd dir="ltr" lang="en">#1900</kbd></td></tr>' .
144
+        '<tr><td>' . $dates['INT 1900 (...)'] . '</td><td><kbd dir="ltr" lang="en">INT 1900 (...)</kbd></td><td></td></tr>' .
145
+        '</table>' .
146
+        '<p>' . I18N::translate('Date ranges are used to indicate that an event, such as a birth, happened on an unknown date within a possible range.') . '</p>' .
147
+        '<table border="1">' .
148
+        '<tr><th>' . I18N::translate('Date range') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
149
+        '<tr><td>' . $dates['BET 1900 AND 1910'] . '</td><td><kbd dir="ltr" lang="en">BET 1900 AND 1910</kbd></td><td><kbd dir="ltr" lang="en">1900-1910</kbd></td></tr>' .
150
+        '<tr><td>' . $dates['AFT 1900'] . '</td><td><kbd dir="ltr" lang="en">AFT 1900</kbd></td><td><kbd dir="ltr" lang="en">&gt;1900</kbd></td></tr>' .
151
+        '<tr><td>' . $dates['BEF 1910'] . '</td><td><kbd dir="ltr" lang="en">BEF 1910</kbd></td><td><kbd dir="ltr" lang="en">&lt;1910</kbd></td></tr>' .
152
+        '<tr><td>' . $dates['BET JAN 1900 AND MAR 1900'] . '</td><td><kbd dir="ltr" lang="en">BET JAN 1900 AND MAR 1900</kbd></td><td><kbd dir="ltr" lang="en">Q1 1900</kbd></td></tr>' .
153
+        '<tr><td>' . $dates['BET APR 1900 AND JUN 1900'] . '</td><td><kbd dir="ltr" lang="en">BET APR 1900 AND JUN 1900</kbd></td><td><kbd dir="ltr" lang="en">Q2 1900</kbd></td></tr>' .
154
+        '<tr><td>' . $dates['BET JUL 1900 AND SEP 1900'] . '</td><td><kbd dir="ltr" lang="en">BET JUL 1900 AND SEP 1900</kbd></td><td><kbd dir="ltr" lang="en">Q3 1900</kbd></td></tr>' .
155
+        '<tr><td>' . $dates['BET OCT 1900 AND DEC 1900'] . '</td><td><kbd dir="ltr" lang="en">BET OCT 1900 AND DEC 1900</kbd></td><td><kbd dir="ltr" lang="en">Q4 1900</kbd></td></tr>' .
156
+        '</table>' .
157
+        '<p>' . I18N::translate('Date periods are used to indicate that a fact, such as an occupation, continued for a period of time.') . '</p>' .
158
+        '<table border="1">' .
159
+        '<tr><th>' . I18N::translate('Date period') . '</th><th>' . I18N::translate('Format') . '</th><th>' . I18N::translate('Shortcut') . '</th></tr>' .
160
+        '<tr><td>' . $dates['FROM 1900 TO 1910'] . '</td><td><kbd dir="ltr" lang="en">FROM 1900 TO 1910</kbd></td><td><kbd dir="ltr" lang="en">1900~1910</kbd></td></tr>' .
161
+        '<tr><td>' . $dates['FROM 1900'] . '</td><td><kbd dir="ltr" lang="en">FROM 1900</kbd></td><td><kbd dir="ltr" lang="en">1900-</kbd></td></tr>' .
162
+        '<tr><td>' . $dates['TO 1910'] . '</td><td><kbd dir="ltr" lang="en">TO 1910</kbd></td><td><kbd dir="ltr" lang="en">-1900</kbd></td></tr>' .
163
+        '</table>' .
164
+        '<p>' . I18N::translate('Simple dates are assumed to be in the gregorian calendar. To specify a date in another calendar, add a keyword before the date. This keyword is optional if the month or year format make the date unambiguous.') . '</p>' .
165
+        '<table border="1">' .
166
+        '<tr><th>' . I18N::translate('Date') . '</th><th>' . I18N::translate('Format') . '</th></tr>' .
167
+        '<tr><th colspan="2">' . I18N::translate('Julian') . '</th></tr>' .
168
+        '<tr><td>' . $dates['@#DJULIAN@ 14 JAN 1700'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 14 JAN 1700</kbd></td></tr>' .
169
+        '<tr><td>' . $dates['@#DJULIAN@ 44 B.C.'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 44 B.C.</kbd></td></tr>' .
170
+        '<tr><td>' . $dates['@#DJULIAN@ 20 FEB 1742/43'] . '</td><td><kbd dir="ltr" lang="en">@#DJULIAN@ 20 FEB 1742/43</kbd></td></tr>' .
171
+        '<tr><td>' . $dates['BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752'] . '</td><td><kbd dir="ltr" lang="en">BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752</kbd></td></tr>' .
172
+        '<tr><th colspan="2">' . I18N::translate('Jewish') . '</th></tr>' .
173
+        '<tr><td>' . $dates['@#DHEBREW@ 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ 5481</kbd></td></tr>' .
174
+        '<tr><td>' . $dates['@#DHEBREW@ TSH 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ TSH 5481</kbd></td></tr>' .
175
+        '<tr><td>' . $dates['ABT @#DHEBREW@ CSH 5481'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHEBREW@ CSH 5481</kbd></td></tr>' .
176
+        '<tr><td>' . $dates['BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481'] . '</td><td><kbd dir="ltr" lang="en">BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481</kbd></td></tr>' .
177
+        '<tr><td>' . $dates['FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481</kbd></td></tr>' .
178
+        '<tr><td>' . $dates['AFT @#DHEBREW@ ADR 5481'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHEBREW@ ADR 5481</kbd></td></tr>' .
179
+        '<tr><td>' . $dates['AFT @#DHEBREW@ ADS 5480'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHEBREW@ ADS 5480</kbd></td></tr>' .
180
+        '<tr><td>' . $dates['BEF @#DHEBREW@ NSN 5481'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DHEBREW@ NSN 5481</kbd></td></tr>' .
181
+        '<tr><td>' . $dates['ABT @#DHEBREW@ IYR 5481'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHEBREW@ IYR 5481</kbd></td></tr>' .
182
+        '<tr><td>' . $dates['FROM @#DHEBREW@ SVN 5481'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHEBREW@ SVN 5481</kbd></td></tr>' .
183
+        '<tr><td>' . $dates['TO @#DHEBREW@ TMZ 5481'] . '</td><td><kbd dir="ltr" lang="en">TO @#DHEBREW@ TMZ 5481</kbd></td></tr>' .
184
+        '<tr><td>' . $dates['EST @#DHEBREW@ AAV 5481'] . '</td><td><kbd dir="ltr" lang="en">EST @#DHEBREW@ AAV 5481</kbd></td></tr>' .
185
+        '<tr><td>' . $dates['@#DHEBREW@ 03 ELL 5481'] . '</td><td><kbd dir="ltr" lang="en">@#DHEBREW@ 03 ELL 5481</kbd></td></tr>' .
186
+        '<tr><th colspan="2">' . I18N::translate('Hijri') . '</th></tr>' .
187
+        '<tr><td>' . $dates['@#DHIJRI@ 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ 1497</kbd></td></tr>' .
188
+        '<tr><td>' . $dates['@#DHIJRI@ MUHAR 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ MUHAR 1497</kbd></td></tr>' .
189
+        '<tr><td>' . $dates['ABT @#DHIJRI@ SAFAR 1497'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHIJRI@ SAFAR 1497</kbd></td></tr>' .
190
+        '<tr><td>' . $dates['BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497'] . '</td><td><kbd dir="ltr" lang="en">BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497</kbd></td></tr>' .
191
+        '<tr><td>' . $dates['FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497</kbd></td></tr>' .
192
+        '<tr><td>' . $dates['AFT @#DHIJRI@ RAJAB 1497'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DHIJRI@ RAJAB 1497</kbd></td></tr>' .
193
+        '<tr><td>' . $dates['BEF @#DHIJRI@ SHAAB 1497'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DHIJRI@ SHAAB 1497</kbd></td></tr>' .
194
+        '<tr><td>' . $dates['ABT @#DHIJRI@ RAMAD 1497'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DHIJRI@ RAMAD 1497</kbd></td></tr>' .
195
+        '<tr><td>' . $dates['FROM @#DHIJRI@ SHAWW 1497'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DHIJRI@ SHAWW 1497</kbd></td></tr>' .
196
+        '<tr><td>' . $dates['TO @#DHIJRI@ DHUAQ 1497'] . '</td><td><kbd dir="ltr" lang="en">TO @#DHIJRI@ DHUAQ 1497</kbd></td></tr>' .
197
+        '<tr><td>' . $dates['@#DHIJRI@ 03 DHUAH 1497'] . '</td><td><kbd dir="ltr" lang="en">@#DHIJRI@ 03 DHUAH 1497</kbd></td></tr>' .
198
+        '<tr><th colspan="2">' . I18N::translate('French') . '</th></tr>' .
199
+        '<tr><td>' . $dates['@#DFRENCH R@ 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ 12</kbd></td></tr>' .
200
+        '<tr><td>' . $dates['@#DFRENCH R@ VEND 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ VEND 12</kbd></td></tr>' .
201
+        '<tr><td>' . $dates['ABT @#DFRENCH R@ BRUM 12'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DFRENCH R@ BRUM 12</kbd></td></tr>' .
202
+        '<tr><td>' . $dates['BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12'] . '</td><td><kbd dir="ltr" lang="en">BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12</kbd></td></tr>' .
203
+        '<tr><td>' . $dates['FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12</kbd></td></tr>' .
204
+        '<tr><td>' . $dates['AFT @#DFRENCH R@ GERM 12'] . '</td><td><kbd dir="ltr" lang="en">AFT @#DFRENCH R@ GERM 12</kbd></td></tr>' .
205
+        '<tr><td>' . $dates['BEF @#DFRENCH R@ FLOR 12'] . '</td><td><kbd dir="ltr" lang="en">BEF @#DFRENCH R@ FLOR 12</kbd></td></tr>' .
206
+        '<tr><td>' . $dates['ABT @#DFRENCH R@ PRAI 12'] . '</td><td><kbd dir="ltr" lang="en">ABT @#DFRENCH R@ PRAI 12</kbd></td></tr>' .
207
+        '<tr><td>' . $dates['FROM @#DFRENCH R@ MESS 12'] . '</td><td><kbd dir="ltr" lang="en">FROM @#DFRENCH R@ MESS 12</kbd></td></tr>' .
208
+        '<tr><td>' . $dates['TO @#DFRENCH R@ THER 12'] . '</td><td><kbd dir="ltr" lang="en">TO @#DFRENCH R@ THER 12</kbd></td></tr>' .
209
+        '<tr><td>' . $dates['EST @#DFRENCH R@ FRUC 12'] . '</td><td><kbd dir="ltr" lang="en">EST @#DFRENCH R@ FRUC 12</kbd></td></tr>' .
210
+        '<tr><td>' . $dates['@#DFRENCH R@ 03 COMP 12'] . '</td><td><kbd dir="ltr" lang="en">@#DFRENCH R@ 03 COMP 12</kbd></td></tr>' .
211
+        '</table>';
212
+    break;
213 213
 
214 214
 // This help text is used for all NAME components
215 215
 case 'NAME':
216
-	$title = GedcomTag::getLabel('NAME');
217
-	$text  =
218
-		'<p>' .
219
-		I18N::translate('The <b>name</b> field contains the individual’s full name, as they would have spelled it or as it was recorded. This is how it will be displayed on screen. It uses standard genealogy annotations to identify different parts of the name.') .
220
-		'</p>' .
221
-		'<ul><li>' .
222
-		I18N::translate('The surname is enclosed by slashes: <%s>John Paul /Smith/<%s>', 'span style="color:#0000ff;"', '/span') .
223
-		'</li><li>' .
224
-		I18N::translate('If the surname is unknown, use empty slashes: <%s>Mary //<%s>', 'span style="color:#0000ff;"', '/span') .
225
-		'</li><li>' .
226
-		I18N::translate('If an individual has two separate surnames, both should be enclosed by slashes: <%s>José Antonio /Gómez/ /Iglesias/<%s>', 'span style="color:#0000ff;"', '/span') .
227
-		'</li><li>' .
228
-		I18N::translate('If an individual does not have a surname, no slashes are needed: <%s>Jón Einarsson<%s>', 'span style="color:#0000ff;"', '/span') .
229
-		'</li><li>' .
230
-		I18N::translate('If an individual was not known by their first given name, the preferred name should be indicated with an asterisk: <%s>John Paul* /Smith/<%s>', 'span style="color:#0000ff;"', '/span') .
231
-		'</li><li>' .
232
-		I18N::translate('If an individual was known by a nickname which is not part of their formal name, it should be enclosed by quotation marks. For example, <%s>John &quot;Nobby&quot; /Clark/<%s>.', 'span style="color:#0000ff;"', '/span') .
233
-		'</li></ul>';
234
-	break;
216
+    $title = GedcomTag::getLabel('NAME');
217
+    $text  =
218
+        '<p>' .
219
+        I18N::translate('The <b>name</b> field contains the individual’s full name, as they would have spelled it or as it was recorded. This is how it will be displayed on screen. It uses standard genealogy annotations to identify different parts of the name.') .
220
+        '</p>' .
221
+        '<ul><li>' .
222
+        I18N::translate('The surname is enclosed by slashes: <%s>John Paul /Smith/<%s>', 'span style="color:#0000ff;"', '/span') .
223
+        '</li><li>' .
224
+        I18N::translate('If the surname is unknown, use empty slashes: <%s>Mary //<%s>', 'span style="color:#0000ff;"', '/span') .
225
+        '</li><li>' .
226
+        I18N::translate('If an individual has two separate surnames, both should be enclosed by slashes: <%s>José Antonio /Gómez/ /Iglesias/<%s>', 'span style="color:#0000ff;"', '/span') .
227
+        '</li><li>' .
228
+        I18N::translate('If an individual does not have a surname, no slashes are needed: <%s>Jón Einarsson<%s>', 'span style="color:#0000ff;"', '/span') .
229
+        '</li><li>' .
230
+        I18N::translate('If an individual was not known by their first given name, the preferred name should be indicated with an asterisk: <%s>John Paul* /Smith/<%s>', 'span style="color:#0000ff;"', '/span') .
231
+        '</li><li>' .
232
+        I18N::translate('If an individual was known by a nickname which is not part of their formal name, it should be enclosed by quotation marks. For example, <%s>John &quot;Nobby&quot; /Clark/<%s>.', 'span style="color:#0000ff;"', '/span') .
233
+        '</li></ul>';
234
+    break;
235 235
 
236 236
 case 'SURN':
237
-	$title = GedcomTag::getLabel('SURN');
238
-	$text  = '<p>' .
239
-		I18N::translate('The <b>surname</b> field contains a name that is used for sorting and grouping. It can be different to the individual’s actual surname which is always taken from the <b>name</b> field. This field can be used to sort surnames with or without a prefix (Gogh / van Gogh) and to group spelling variations or inflections (Kowalski / Kowalska). If an individual needs to be listed under more than one surname, each name should be separated by a comma.') .
240
-		'</p>';
241
-	break;
237
+    $title = GedcomTag::getLabel('SURN');
238
+    $text  = '<p>' .
239
+        I18N::translate('The <b>surname</b> field contains a name that is used for sorting and grouping. It can be different to the individual’s actual surname which is always taken from the <b>name</b> field. This field can be used to sort surnames with or without a prefix (Gogh / van Gogh) and to group spelling variations or inflections (Kowalski / Kowalska). If an individual needs to be listed under more than one surname, each name should be separated by a comma.') .
240
+        '</p>';
241
+    break;
242 242
 
243 243
 case 'OBJE':
244
-	$title = GedcomTag::getLabel('OBJE');
245
-	$text  =
246
-		'<p>' .
247
-		I18N::translate('A media object is a record in the family tree which contains information about a media file. This information may include a title, a copyright notice, a transcript, privacy restrictions, etc. The media file, such as the photo or video, can be stored locally (on this webserver) or remotely (on a different webserver).') .
248
-		'</p>';
249
-	break;
244
+    $title = GedcomTag::getLabel('OBJE');
245
+    $text  =
246
+        '<p>' .
247
+        I18N::translate('A media object is a record in the family tree which contains information about a media file. This information may include a title, a copyright notice, a transcript, privacy restrictions, etc. The media file, such as the photo or video, can be stored locally (on this webserver) or remotely (on a different webserver).') .
248
+        '</p>';
249
+    break;
250 250
 
251 251
 case 'PLAC':
252
-	$title = GedcomTag::getLabel('PLAC');
253
-	$text  = I18N::translate('Places should be entered according to the standards for genealogy. In genealogy, places are recorded with the most specific information about the place first and then working up to the least specific place last, using commas to separate the different place levels. The level at which you record the place information should represent the levels of government or church where vital records for that place are kept.<br><br>For example, a place like Salt Lake City would be entered as “Salt Lake City, Salt Lake, Utah, USA”.<br><br>Let’s examine each part of this place. The first part, “Salt Lake City,” is the city or township where the event occurred. In some countries, there may be municipalities or districts inside a city which are important to note. In that case, they should come before the city. The next part, “Salt Lake,” is the county. “Utah” is the state, and “USA” is the country. It is important to note each place because genealogy records are kept by the governments of each level.<br><br>If a level of the place is unknown, you should leave a space between the commas. Suppose, in the example above, you didn’t know the county for Salt Lake City. You should then record it like this: “Salt Lake City, , Utah, USA”. Suppose you only know that an individual was born in Utah. You would enter the information like this: “, , Utah, USA”. <br><br>You can use the <b>Find Place</b> link to help you find places that already exist in the database.');
254
-	break;
252
+    $title = GedcomTag::getLabel('PLAC');
253
+    $text  = I18N::translate('Places should be entered according to the standards for genealogy. In genealogy, places are recorded with the most specific information about the place first and then working up to the least specific place last, using commas to separate the different place levels. The level at which you record the place information should represent the levels of government or church where vital records for that place are kept.<br><br>For example, a place like Salt Lake City would be entered as “Salt Lake City, Salt Lake, Utah, USA”.<br><br>Let’s examine each part of this place. The first part, “Salt Lake City,” is the city or township where the event occurred. In some countries, there may be municipalities or districts inside a city which are important to note. In that case, they should come before the city. The next part, “Salt Lake,” is the county. “Utah” is the state, and “USA” is the country. It is important to note each place because genealogy records are kept by the governments of each level.<br><br>If a level of the place is unknown, you should leave a space between the commas. Suppose, in the example above, you didn’t know the county for Salt Lake City. You should then record it like this: “Salt Lake City, , Utah, USA”. Suppose you only know that an individual was born in Utah. You would enter the information like this: “, , Utah, USA”. <br><br>You can use the <b>Find Place</b> link to help you find places that already exist in the database.');
254
+    break;
255 255
 
256 256
 case 'RESN':
257
-	$title = GedcomTag::getLabel('RESN');
258
-	$text  =
259
-		I18N::translate('Restrictions can be added to records and/or facts. They restrict who can view the data and who can edit it.') .
260
-		'<br><br>' .
261
-		I18N::translate('Note that if a user account is linked to a record, then that user will always be able to view that record.');
262
-	break;
257
+    $title = GedcomTag::getLabel('RESN');
258
+    $text  =
259
+        I18N::translate('Restrictions can be added to records and/or facts. They restrict who can view the data and who can edit it.') .
260
+        '<br><br>' .
261
+        I18N::translate('Note that if a user account is linked to a record, then that user will always be able to view that record.');
262
+    break;
263 263
 
264 264
 case 'ROMN':
265
-	$title = GedcomTag::getLabel('ROMN');
266
-	$text  = I18N::translate('In many cultures it is customary to have a traditional name spelled in the traditional characters and also a romanized version of the name as it would be spelled or pronounced in languages based on the Latin alphabet, such as English.<br><br>If you prefer to use a non-Latin alphabet such as Hebrew, Greek, Russian, Chinese, or Arabic to enter the name in the standard name fields, then you can use this field to enter the same name using the Latin alphabet. Both versions of the name will appear in lists and charts.<br><br>Although this field is labeled “Romanized”, it is not restricted to containing only characters based on the Latin alphabet. This might be of use with Japanese names, where three different alphabets may occur.');
267
-	break;
265
+    $title = GedcomTag::getLabel('ROMN');
266
+    $text  = I18N::translate('In many cultures it is customary to have a traditional name spelled in the traditional characters and also a romanized version of the name as it would be spelled or pronounced in languages based on the Latin alphabet, such as English.<br><br>If you prefer to use a non-Latin alphabet such as Hebrew, Greek, Russian, Chinese, or Arabic to enter the name in the standard name fields, then you can use this field to enter the same name using the Latin alphabet. Both versions of the name will appear in lists and charts.<br><br>Although this field is labeled “Romanized”, it is not restricted to containing only characters based on the Latin alphabet. This might be of use with Japanese names, where three different alphabets may occur.');
267
+    break;
268 268
 
269 269
 case '_HEB':
270
-	$title = GedcomTag::getLabel('_HEB');
271
-	$text  = I18N::translate('In many cultures it is customary to have a traditional name spelled in the traditional characters and also a romanized version of the name as it would be spelled or pronounced in languages based on the Latin alphabet, such as English.<br><br>If you prefer to use the Latin alphabet to enter the name in the standard name fields, then you can use this field to enter the same name in the non-Latin alphabet such as Greek, Hebrew, Russian, Arabic, or Chinese. Both versions of the name will appear in lists and charts.<br><br>Although this field is labeled “Hebrew”, it is not restricted to containing only Hebrew characters.');
272
-	break;
270
+    $title = GedcomTag::getLabel('_HEB');
271
+    $text  = I18N::translate('In many cultures it is customary to have a traditional name spelled in the traditional characters and also a romanized version of the name as it would be spelled or pronounced in languages based on the Latin alphabet, such as English.<br><br>If you prefer to use the Latin alphabet to enter the name in the standard name fields, then you can use this field to enter the same name in the non-Latin alphabet such as Greek, Hebrew, Russian, Arabic, or Chinese. Both versions of the name will appear in lists and charts.<br><br>Although this field is labeled “Hebrew”, it is not restricted to containing only Hebrew characters.');
272
+    break;
273 273
 
274
-	//////////////////////////////////////////////////////////////////////////////
275
-	// This section contains all the other help items.
276
-	//////////////////////////////////////////////////////////////////////////////
274
+    //////////////////////////////////////////////////////////////////////////////
275
+    // This section contains all the other help items.
276
+    //////////////////////////////////////////////////////////////////////////////
277 277
 
278 278
 case 'annivers_year_select':
279
-	$title = I18N::translate('Year input box');
280
-	$text  = I18N::translate('This input box lets you change that year of the calendar. Type a year into the box and press <b>Enter</b> to change the calendar to that year.<br><br><b>Advanced features</b> for <b>View the year</b><dl><dt><b>More than one year</b></dt><dd>You can search for dates in a range of years.<br><br>Year ranges are <u>inclusive</u>. This means that the date range extends from 1 January of the first year of the range to 31 December of the last year mentioned. Here are a few examples of year ranges:<br><br><b>1992-5</b> for all events from 1992 to 1995.<br><b>1972-89</b> for all events from 1972 to 1989.<br><b>1610-759</b> for all events from 1610 to 1759.<br><b>1880-1905</b> for all events from 1880 to 1905.<br><b>880-1105</b> for all events from 880 to 1105.<br><br>To see all the events in a given decade or century, you can use <b>?</b> in place of the final digits. For example, <b>197?</b> for all events from 1970 to 1979 or <b>16??</b> for all events from 1600 to 1699.<br><br>Selecting a range of years will change the calendar to the year view.</dd></dl>');
281
-	break;
279
+    $title = I18N::translate('Year input box');
280
+    $text  = I18N::translate('This input box lets you change that year of the calendar. Type a year into the box and press <b>Enter</b> to change the calendar to that year.<br><br><b>Advanced features</b> for <b>View the year</b><dl><dt><b>More than one year</b></dt><dd>You can search for dates in a range of years.<br><br>Year ranges are <u>inclusive</u>. This means that the date range extends from 1 January of the first year of the range to 31 December of the last year mentioned. Here are a few examples of year ranges:<br><br><b>1992-5</b> for all events from 1992 to 1995.<br><b>1972-89</b> for all events from 1972 to 1989.<br><b>1610-759</b> for all events from 1610 to 1759.<br><b>1880-1905</b> for all events from 1880 to 1905.<br><b>880-1105</b> for all events from 880 to 1105.<br><br>To see all the events in a given decade or century, you can use <b>?</b> in place of the final digits. For example, <b>197?</b> for all events from 1970 to 1979 or <b>16??</b> for all events from 1600 to 1699.<br><br>Selecting a range of years will change the calendar to the year view.</dd></dl>');
281
+    break;
282 282
 
283 283
 case 'edit_edit_raw':
284
-	$title = I18N::translate('Edit the raw GEDCOM');
285
-	$text  =
286
-		I18N::translate('This page allows you to bypass the usual forms, and edit the underlying data directly. It is an advanced option, and you should not use it unless you understand the GEDCOM format. If you make a mistake here, it can be difficult to fix.') .
287
-		'<br><br>' .
288
-		/* I18N: %s is a URL */ I18N::translate('You can download a copy of the GEDCOM specification from %s.', '<a href="https://wiki.webtrees.net/w/images-en/Ged551-5.pdf">https://wiki.webtrees.net/w/images-en/Ged551-5.pdf</a>');
289
-	break;
284
+    $title = I18N::translate('Edit the raw GEDCOM');
285
+    $text  =
286
+        I18N::translate('This page allows you to bypass the usual forms, and edit the underlying data directly. It is an advanced option, and you should not use it unless you understand the GEDCOM format. If you make a mistake here, it can be difficult to fix.') .
287
+        '<br><br>' .
288
+        /* I18N: %s is a URL */ I18N::translate('You can download a copy of the GEDCOM specification from %s.', '<a href="https://wiki.webtrees.net/w/images-en/Ged551-5.pdf">https://wiki.webtrees.net/w/images-en/Ged551-5.pdf</a>');
289
+    break;
290 290
 
291 291
 case 'edit_SOUR_EVEN':
292
-	$title = I18N::translate('Associate events with this source');
293
-	$text  = I18N::translate('Each source records specific events, generally for a given date range and for a place jurisdiction. For example a Census records census events and church records record birth, marriage, and death events.<br><br>Select the events that are recorded by this source from the list of events provided. The date should be specified in a range format such as <i>FROM 1900 TO 1910</i>. The place jurisdiction is the name of the lowest jurisdiction that encompasses all lower-level places named in this source. For example, “Oneida, Idaho, USA” would be used as a source jurisdiction place for events occurring in the various towns within Oneida County. “Idaho, USA” would be the source jurisdiction place if the events recorded took place not only in Oneida County but also in other counties in Idaho.');
294
-	break;
292
+    $title = I18N::translate('Associate events with this source');
293
+    $text  = I18N::translate('Each source records specific events, generally for a given date range and for a place jurisdiction. For example a Census records census events and church records record birth, marriage, and death events.<br><br>Select the events that are recorded by this source from the list of events provided. The date should be specified in a range format such as <i>FROM 1900 TO 1910</i>. The place jurisdiction is the name of the lowest jurisdiction that encompasses all lower-level places named in this source. For example, “Oneida, Idaho, USA” would be used as a source jurisdiction place for events occurring in the various towns within Oneida County. “Idaho, USA” would be the source jurisdiction place if the events recorded took place not only in Oneida County but also in other counties in Idaho.');
294
+    break;
295 295
 
296 296
 case 'google_chart_surname':
297
-	$title = I18N::translate('Surname');
298
-	$text  = I18N::translate('The number of occurrences of the specified name will be shown on the map. If you leave this field empty, the most common surname will be used.');
299
-	break;
297
+    $title = I18N::translate('Surname');
298
+    $text  = I18N::translate('The number of occurrences of the specified name will be shown on the map. If you leave this field empty, the most common surname will be used.');
299
+    break;
300 300
 
301 301
 case 'pending_changes':
302
-	$title = I18N::translate('Pending changes');
303
-	$text  =
304
-		'<p>' .
305
-		I18N::translate('When you add, edit, or delete information, the changes are not saved immediately. Instead, they are kept in a “pending” area. These pending changes need to be reviewed by a moderator before they are accepted.') .
306
-		'</p><p>' .
307
-		I18N::translate('This process allows the site’s owner to ensure that the new information follows the site’s standards and conventions, has proper source attributions, etc.') .
308
-		'</p><p>' .
309
-		I18N::translate('Pending changes are only shown when your account has permission to edit. When you sign out, you will no longer be able to see them. Also, pending changes are only shown on certain pages. For example, they are not shown in lists, reports, or search results.') .
310
-		'</p>';
311
-	if (Auth::isAdmin()) {
312
-		$text .=
313
-			'<p>' .
314
-			I18N::translate('Each user account has an option to “automatically accept changes”. When this is enabled, any changes made by that user are saved immediately. Many administrators enable this for their own user account.') .
315
-			'</p>';
316
-	}
317
-	break;
302
+    $title = I18N::translate('Pending changes');
303
+    $text  =
304
+        '<p>' .
305
+        I18N::translate('When you add, edit, or delete information, the changes are not saved immediately. Instead, they are kept in a “pending” area. These pending changes need to be reviewed by a moderator before they are accepted.') .
306
+        '</p><p>' .
307
+        I18N::translate('This process allows the site’s owner to ensure that the new information follows the site’s standards and conventions, has proper source attributions, etc.') .
308
+        '</p><p>' .
309
+        I18N::translate('Pending changes are only shown when your account has permission to edit. When you sign out, you will no longer be able to see them. Also, pending changes are only shown on certain pages. For example, they are not shown in lists, reports, or search results.') .
310
+        '</p>';
311
+    if (Auth::isAdmin()) {
312
+        $text .=
313
+            '<p>' .
314
+            I18N::translate('Each user account has an option to “automatically accept changes”. When this is enabled, any changes made by that user are saved immediately. Many administrators enable this for their own user account.') .
315
+            '</p>';
316
+    }
317
+    break;
318 318
 
319 319
 default:
320
-	$title = I18N::translate('Help');
321
-	$text  = I18N::translate('The help text has not been written for this item.');
322
-	break;
320
+    $title = I18N::translate('Help');
321
+    $text  = I18N::translate('The help text has not been written for this item.');
322
+    break;
323 323
 }
324 324
 // This file is called by a getJSON call so return the data
325 325
 // in correct format
Please login to merge, or discard this patch.
admin_trees_duplicates.php 1 patch
Indentation   +71 added lines, -71 removed lines patch added patch discarded remove patch
@@ -29,119 +29,119 @@
 block discarded – undo
29 29
 
30 30
 $controller = new PageController;
31 31
 $controller
32
-	->restrictAccess(Auth::isManager($WT_TREE))
33
-	->setPageTitle(I18N::translate('Find duplicates') . ' — ' . $WT_TREE->getTitleHtml())
34
-	->pageHeader();
32
+    ->restrictAccess(Auth::isManager($WT_TREE))
33
+    ->setPageTitle(I18N::translate('Find duplicates') . ' — ' . $WT_TREE->getTitleHtml())
34
+    ->pageHeader();
35 35
 
36 36
 $repositories = Database::prepare(
37
-	"SELECT GROUP_CONCAT(n_id) AS xrefs " .
38
-	" FROM `##other`" .
39
-	" JOIN `##name` ON o_id = n_id AND o_file = n_file" .
40
-	" WHERE o_file = :tree_id AND o_type = 'REPO'" .
41
-	" GROUP BY n_full" .
42
-	" HAVING COUNT(n_id) > 1"
37
+    "SELECT GROUP_CONCAT(n_id) AS xrefs " .
38
+    " FROM `##other`" .
39
+    " JOIN `##name` ON o_id = n_id AND o_file = n_file" .
40
+    " WHERE o_file = :tree_id AND o_type = 'REPO'" .
41
+    " GROUP BY n_full" .
42
+    " HAVING COUNT(n_id) > 1"
43 43
 )->execute(array(
44
-	'tree_id' => $WT_TREE->getTreeId(),
44
+    'tree_id' => $WT_TREE->getTreeId(),
45 45
 ))->fetchAll();
46 46
 
47 47
 $repositories = array_map(
48
-	function (\stdClass $x) use ($WT_TREE) {
49
-		$tmp = explode(',', $x->xrefs);
48
+    function (\stdClass $x) use ($WT_TREE) {
49
+        $tmp = explode(',', $x->xrefs);
50 50
 
51
-		return array_map(function ($y) use ($WT_TREE) {
52
-			return Repository::getInstance($y, $WT_TREE);
53
-		}, $tmp);
54
-	}, $repositories
51
+        return array_map(function ($y) use ($WT_TREE) {
52
+            return Repository::getInstance($y, $WT_TREE);
53
+        }, $tmp);
54
+    }, $repositories
55 55
 );
56 56
 
57 57
 $sources = Database::prepare(
58
-	"SELECT GROUP_CONCAT(n_id) AS xrefs " .
59
-	" FROM `##sources`" .
60
-	" JOIN `##name` ON s_id = n_id AND s_file = n_file" .
61
-	" WHERE s_file = :tree_id" .
62
-	" GROUP BY n_full" .
63
-	" HAVING COUNT(n_id) > 1"
58
+    "SELECT GROUP_CONCAT(n_id) AS xrefs " .
59
+    " FROM `##sources`" .
60
+    " JOIN `##name` ON s_id = n_id AND s_file = n_file" .
61
+    " WHERE s_file = :tree_id" .
62
+    " GROUP BY n_full" .
63
+    " HAVING COUNT(n_id) > 1"
64 64
 )->execute(array(
65
-	'tree_id' => $WT_TREE->getTreeId(),
65
+    'tree_id' => $WT_TREE->getTreeId(),
66 66
 ))->fetchAll();
67 67
 
68 68
 $sources = array_map(
69
-	function (\stdClass $x) use ($WT_TREE) {
70
-		$tmp = explode(',', $x->xrefs);
69
+    function (\stdClass $x) use ($WT_TREE) {
70
+        $tmp = explode(',', $x->xrefs);
71 71
 
72
-		return array_map(function ($y) use ($WT_TREE) {
73
-			return Source::getInstance($y, $WT_TREE);
74
-		}, $tmp);
75
-	}, $sources
72
+        return array_map(function ($y) use ($WT_TREE) {
73
+            return Source::getInstance($y, $WT_TREE);
74
+        }, $tmp);
75
+    }, $sources
76 76
 );
77 77
 
78 78
 $individuals = Database::prepare(
79
-	"SELECT DISTINCT GROUP_CONCAT(d_gid ORDER BY d_gid) AS xrefs" .
80
-	" FROM `##dates` AS d" .
81
-	" JOIN `##name` ON d_file = n_file AND d_gid = n_id" .
82
-	" WHERE d_file = :tree_id AND d_fact IN ('BIRT', 'CHR', 'BAPM', 'DEAT', 'BURI')" .
83
-	" GROUP BY d_day, d_month, d_year, d_type, d_fact, n_type, n_full" .
84
-	" HAVING COUNT(DISTINCT d_gid) > 1"
79
+    "SELECT DISTINCT GROUP_CONCAT(d_gid ORDER BY d_gid) AS xrefs" .
80
+    " FROM `##dates` AS d" .
81
+    " JOIN `##name` ON d_file = n_file AND d_gid = n_id" .
82
+    " WHERE d_file = :tree_id AND d_fact IN ('BIRT', 'CHR', 'BAPM', 'DEAT', 'BURI')" .
83
+    " GROUP BY d_day, d_month, d_year, d_type, d_fact, n_type, n_full" .
84
+    " HAVING COUNT(DISTINCT d_gid) > 1"
85 85
 )->execute(array(
86
-	'tree_id' => $WT_TREE->getTreeId(),
86
+    'tree_id' => $WT_TREE->getTreeId(),
87 87
 ))->fetchAll();
88 88
 
89 89
 $individuals = array_map(
90
-	function (\stdClass $x) use ($WT_TREE) {
91
-		$tmp = explode(',', $x->xrefs);
90
+    function (\stdClass $x) use ($WT_TREE) {
91
+        $tmp = explode(',', $x->xrefs);
92 92
 
93
-		return array_map(function ($y) use ($WT_TREE) {
94
-			return Individual::getInstance($y, $WT_TREE);
95
-		}, $tmp);
96
-	}, $individuals
93
+        return array_map(function ($y) use ($WT_TREE) {
94
+            return Individual::getInstance($y, $WT_TREE);
95
+        }, $tmp);
96
+    }, $individuals
97 97
 );
98 98
 
99 99
 $families = Database::prepare(
100
-	"SELECT GROUP_CONCAT(f_id) AS xrefs " .
101
-	" FROM `##families`" .
102
-	" WHERE f_file = :tree_id" .
103
-	" GROUP BY LEAST(f_husb, f_wife), GREATEST(f_husb, f_wife)" .
104
-	" HAVING COUNT(f_id) > 1"
100
+    "SELECT GROUP_CONCAT(f_id) AS xrefs " .
101
+    " FROM `##families`" .
102
+    " WHERE f_file = :tree_id" .
103
+    " GROUP BY LEAST(f_husb, f_wife), GREATEST(f_husb, f_wife)" .
104
+    " HAVING COUNT(f_id) > 1"
105 105
 )->execute(array(
106
-	'tree_id' => $WT_TREE->getTreeId(),
106
+    'tree_id' => $WT_TREE->getTreeId(),
107 107
 ))->fetchAll();
108 108
 
109 109
 $families = array_map(
110
-	function (\stdClass $x) use ($WT_TREE) {
111
-		$tmp = explode(',', $x->xrefs);
110
+    function (\stdClass $x) use ($WT_TREE) {
111
+        $tmp = explode(',', $x->xrefs);
112 112
 
113
-		return array_map(function ($y) use ($WT_TREE) {
114
-			return Family::getInstance($y, $WT_TREE);
115
-		}, $tmp);
116
-	}, $families
113
+        return array_map(function ($y) use ($WT_TREE) {
114
+            return Family::getInstance($y, $WT_TREE);
115
+        }, $tmp);
116
+    }, $families
117 117
 );
118 118
 
119 119
 $media = Database::prepare(
120
-	"SELECT GROUP_CONCAT(m_id) AS xrefs " .
121
-	" FROM `##media`" .
122
-	" WHERE m_file = :tree_id" .
123
-	" GROUP BY m_titl" .
124
-	" HAVING COUNT(m_id) > 1"
120
+    "SELECT GROUP_CONCAT(m_id) AS xrefs " .
121
+    " FROM `##media`" .
122
+    " WHERE m_file = :tree_id" .
123
+    " GROUP BY m_titl" .
124
+    " HAVING COUNT(m_id) > 1"
125 125
 )->execute(array(
126
-	'tree_id' => $WT_TREE->getTreeId(),
126
+    'tree_id' => $WT_TREE->getTreeId(),
127 127
 ))->fetchAll();
128 128
 
129 129
 $media = array_map(
130
-	function (\stdClass $x) use ($WT_TREE) {
131
-		$tmp = explode(',', $x->xrefs);
130
+    function (\stdClass $x) use ($WT_TREE) {
131
+        $tmp = explode(',', $x->xrefs);
132 132
 
133
-		return array_map(function ($y) use ($WT_TREE) {
134
-			return Media::getInstance($y, $WT_TREE);
135
-		}, $tmp);
136
-	}, $media
133
+        return array_map(function ($y) use ($WT_TREE) {
134
+            return Media::getInstance($y, $WT_TREE);
135
+        }, $tmp);
136
+    }, $media
137 137
 );
138 138
 
139 139
 $all_duplicates = array(
140
-	I18N::translate('Repositories')  => $repositories,
141
-	I18N::translate('Sources')       => $sources,
142
-	I18N::translate('Individuals')   => $individuals,
143
-	I18N::translate('Families')      => $families,
144
-	I18N::translate('Media objects') => $media,
140
+    I18N::translate('Repositories')  => $repositories,
141
+    I18N::translate('Sources')       => $sources,
142
+    I18N::translate('Individuals')   => $individuals,
143
+    I18N::translate('Families')      => $families,
144
+    I18N::translate('Media objects') => $media,
145 145
 );
146 146
 
147 147
 ?>
Please login to merge, or discard this patch.
addmedia.php 1 patch
Indentation   +533 added lines, -533 removed lines patch added patch discarded remove patch
@@ -49,27 +49,27 @@  discard block
 block discarded – undo
49 49
 
50 50
 $controller = new SimpleController;
51 51
 $controller
52
-	->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
53
-	->addInlineJavascript('autocomplete();')
54
-	->restrictAccess(Auth::isMember($WT_TREE));
52
+    ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
53
+    ->addInlineJavascript('autocomplete();')
54
+    ->restrictAccess(Auth::isMember($WT_TREE));
55 55
 
56 56
 $disp  = true;
57 57
 $media = Media::getInstance($pid, $WT_TREE);
58 58
 if ($media) {
59
-	$disp = $media->canShow();
59
+    $disp = $media->canShow();
60 60
 }
61 61
 if ($action == 'update' || $action == 'create') {
62
-	if ($linktoid) {
63
-		$disp = GedcomRecord::getInstance($linktoid, $WT_TREE)->canShow();
64
-	}
62
+    if ($linktoid) {
63
+        $disp = GedcomRecord::getInstance($linktoid, $WT_TREE)->canShow();
64
+    }
65 65
 }
66 66
 
67 67
 if (!Auth::isEditor($WT_TREE) || !$disp) {
68
-	$controller
69
-		->pageHeader()
70
-		->addInlineJavascript('closePopupAndReloadParent();');
68
+    $controller
69
+        ->pageHeader()
70
+        ->addInlineJavascript('closePopupAndReloadParent();');
71 71
 
72
-	return;
72
+    return;
73 73
 }
74 74
 
75 75
 // There is a lot of common code in the create and update cases…
@@ -77,337 +77,337 @@  discard block
 block discarded – undo
77 77
 
78 78
 switch ($action) {
79 79
 case 'create': // Save the information from the “showcreateform” action
80
-	$controller->setPageTitle(I18N::translate('Create a media object'));
81
-
82
-	// Validate the media folder
83
-	$folderName = str_replace('\\', '/', $folder);
84
-	$folderName = trim($folderName, '/');
85
-	if ($folderName == '.') {
86
-		$folderName = '';
87
-	}
88
-	if ($folderName) {
89
-		$folderName .= '/';
90
-		// Not allowed to use “../”
91
-		if (strpos('/' . $folderName, '/../') !== false) {
92
-			FlashMessages::addMessage('Folder names are not allowed to include “../”');
93
-			break;
94
-		}
95
-	}
96
-
97
-	// Make sure the media folder exists
98
-	if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
99
-		if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
100
-			FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)));
101
-		} else {
102
-			FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger');
103
-			break;
104
-		}
105
-	}
106
-
107
-	// Managers can create new media paths (subfolders). Users must use existing folders.
108
-	if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
109
-		if (Auth::isManager($WT_TREE)) {
110
-			if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
111
-				FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)));
112
-			} else {
113
-				FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger');
114
-				break;
115
-			}
116
-		} else {
117
-			// Regular users should not have seen this option - so no need for an error message.
118
-			break;
119
-		}
120
-	}
121
-
122
-	// The media folder exists. Now create a thumbnail folder to match it.
123
-	if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
124
-		if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
125
-			FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger');
126
-			break;
127
-		}
128
-	}
129
-
130
-	// A thumbnail file with no main image?
131
-	if (!empty($_FILES['thumbnail']['name']) && empty($_FILES['mediafile']['name'])) {
132
-		// Assume the user used the wrong field, and treat this as a main image
133
-		$_FILES['mediafile'] = $_FILES['thumbnail'];
134
-		unset($_FILES['thumbnail']);
135
-	}
136
-
137
-	// Thumbnail files must contain images.
138
-	if (!empty($_FILES['thumbnail']['name']) && !preg_match('/^image/', $_FILES['thumbnail']['type'])) {
139
-		FlashMessages::addMessage(I18N::translate('Thumbnail files must contain images.'));
140
-		break;
141
-	}
142
-
143
-	// User-specified filename?
144
-	if ($tag[0] == 'FILE' && $text[0]) {
145
-		$filename = $text[0];
146
-	}
147
-	// Use the name of the uploaded file?
148
-	// If no filename specified, use the name of the uploaded file?
149
-	if (!$filename && !empty($_FILES['mediafile']['name'])) {
150
-		$filename = $_FILES['mediafile']['name'];
151
-	}
152
-
153
-	// Validate the media path and filename
154
-	if (preg_match('/^https?:\/\//i', $text[0], $match)) {
155
-		// External media needs no further validation
156
-		$fileName   = $filename;
157
-		$folderName = '';
158
-		unset($_FILES['mediafile'], $_FILES['thumbnail']);
159
-	} elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) {
160
-		// Local media files cannot contain certain special characters
161
-		FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1]));
162
-		break;
163
-	} elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) {
164
-		// Do not allow obvious script files.
165
-		FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1]));
166
-		break;
167
-	} elseif (!$filename) {
168
-		FlashMessages::addMessage(I18N::translate('No media file was provided.'));
169
-		break;
170
-	} else {
171
-		$fileName = $filename;
172
-	}
173
-
174
-	// Now copy the file to the correct location.
175
-	if (!empty($_FILES['mediafile']['name'])) {
176
-		$serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName . $fileName;
177
-		if (file_exists($serverFileName)) {
178
-			FlashMessages::addMessage(I18N::translate('The file %s already exists. Use another filename.', $folderName . $fileName));
179
-			break;
180
-		}
181
-		if (move_uploaded_file($_FILES['mediafile']['tmp_name'], $serverFileName)) {
182
-			Log::addMediaLog('Media file ' . $serverFileName . ' uploaded');
183
-		} else {
184
-			FlashMessages::addMessage(
185
-				I18N::translate('There was an error uploading your file.') .
186
-				'<br>' .
187
-				Functions::fileUploadErrorText($_FILES['mediafile']['error'])
188
-			);
189
-			break;
190
-		}
191
-
192
-		// Now copy the (optional) thumbnail
193
-		if (!empty($_FILES['thumbnail']['name']) && preg_match('/^image\/(png|gif|jpeg)/', $_FILES['thumbnail']['type'], $match)) {
194
-			// Thumbnails have either
195
-			// (a) the same filename as the main image
196
-			// (b) the same filename as the main image - but with a .png extension
197
-			if ($match[1] == 'png' && !preg_match('/\.(png)$/i', $fileName)) {
198
-				$thumbFile = preg_replace('/\.[a-z0-9]{3,5}$/', '.png', $fileName);
199
-			} else {
200
-				$thumbFile = $fileName;
201
-			}
202
-			$serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName . $thumbFile;
203
-			if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $serverFileName)) {
204
-				Log::addMediaLog('Thumbnail file ' . $serverFileName . ' uploaded');
205
-			}
206
-		}
207
-	}
208
-
209
-	$controller->pageHeader();
210
-	// Build the gedcom record
211
-	$newged = "0 @new@ OBJE";
212
-	if ($tag[0] == 'FILE') {
213
-		// The admin has an edit field to change the filename
214
-		$text[0] = $folderName . $fileName;
215
-	} else {
216
-		// Users keep the original filename
217
-		$newged .= "\n1 FILE " . $folderName . $fileName;
218
-	}
219
-
220
-	$newged = FunctionsEdit::handleUpdates($newged);
221
-
222
-	$new_media = $WT_TREE->createRecord($newged);
223
-	if ($linktoid) {
224
-		$record = GedcomRecord::getInstance($linktoid, $WT_TREE);
225
-		$record->createFact('1 OBJE @' . $new_media->getXref() . '@', true);
226
-		Log::addEditLog('Media ID ' . $new_media->getXref() . " successfully added to $linktoid.");
227
-		$controller->addInlineJavascript('closePopupAndReloadParent();');
228
-	} else {
229
-		Log::addEditLog('Media ID ' . $new_media->getXref() . ' successfully added.');
230
-		$controller->addInlineJavascript('openerpasteid("' . $new_media->getXref() . '");');
231
-	}
232
-	echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>';
233
-
234
-	return;
80
+    $controller->setPageTitle(I18N::translate('Create a media object'));
81
+
82
+    // Validate the media folder
83
+    $folderName = str_replace('\\', '/', $folder);
84
+    $folderName = trim($folderName, '/');
85
+    if ($folderName == '.') {
86
+        $folderName = '';
87
+    }
88
+    if ($folderName) {
89
+        $folderName .= '/';
90
+        // Not allowed to use “../”
91
+        if (strpos('/' . $folderName, '/../') !== false) {
92
+            FlashMessages::addMessage('Folder names are not allowed to include “../”');
93
+            break;
94
+        }
95
+    }
96
+
97
+    // Make sure the media folder exists
98
+    if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
99
+        if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
100
+            FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)));
101
+        } else {
102
+            FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger');
103
+            break;
104
+        }
105
+    }
106
+
107
+    // Managers can create new media paths (subfolders). Users must use existing folders.
108
+    if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
109
+        if (Auth::isManager($WT_TREE)) {
110
+            if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
111
+                FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)));
112
+            } else {
113
+                FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger');
114
+                break;
115
+            }
116
+        } else {
117
+            // Regular users should not have seen this option - so no need for an error message.
118
+            break;
119
+        }
120
+    }
121
+
122
+    // The media folder exists. Now create a thumbnail folder to match it.
123
+    if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
124
+        if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
125
+            FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger');
126
+            break;
127
+        }
128
+    }
129
+
130
+    // A thumbnail file with no main image?
131
+    if (!empty($_FILES['thumbnail']['name']) && empty($_FILES['mediafile']['name'])) {
132
+        // Assume the user used the wrong field, and treat this as a main image
133
+        $_FILES['mediafile'] = $_FILES['thumbnail'];
134
+        unset($_FILES['thumbnail']);
135
+    }
136
+
137
+    // Thumbnail files must contain images.
138
+    if (!empty($_FILES['thumbnail']['name']) && !preg_match('/^image/', $_FILES['thumbnail']['type'])) {
139
+        FlashMessages::addMessage(I18N::translate('Thumbnail files must contain images.'));
140
+        break;
141
+    }
142
+
143
+    // User-specified filename?
144
+    if ($tag[0] == 'FILE' && $text[0]) {
145
+        $filename = $text[0];
146
+    }
147
+    // Use the name of the uploaded file?
148
+    // If no filename specified, use the name of the uploaded file?
149
+    if (!$filename && !empty($_FILES['mediafile']['name'])) {
150
+        $filename = $_FILES['mediafile']['name'];
151
+    }
152
+
153
+    // Validate the media path and filename
154
+    if (preg_match('/^https?:\/\//i', $text[0], $match)) {
155
+        // External media needs no further validation
156
+        $fileName   = $filename;
157
+        $folderName = '';
158
+        unset($_FILES['mediafile'], $_FILES['thumbnail']);
159
+    } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) {
160
+        // Local media files cannot contain certain special characters
161
+        FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1]));
162
+        break;
163
+    } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) {
164
+        // Do not allow obvious script files.
165
+        FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1]));
166
+        break;
167
+    } elseif (!$filename) {
168
+        FlashMessages::addMessage(I18N::translate('No media file was provided.'));
169
+        break;
170
+    } else {
171
+        $fileName = $filename;
172
+    }
173
+
174
+    // Now copy the file to the correct location.
175
+    if (!empty($_FILES['mediafile']['name'])) {
176
+        $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName . $fileName;
177
+        if (file_exists($serverFileName)) {
178
+            FlashMessages::addMessage(I18N::translate('The file %s already exists. Use another filename.', $folderName . $fileName));
179
+            break;
180
+        }
181
+        if (move_uploaded_file($_FILES['mediafile']['tmp_name'], $serverFileName)) {
182
+            Log::addMediaLog('Media file ' . $serverFileName . ' uploaded');
183
+        } else {
184
+            FlashMessages::addMessage(
185
+                I18N::translate('There was an error uploading your file.') .
186
+                '<br>' .
187
+                Functions::fileUploadErrorText($_FILES['mediafile']['error'])
188
+            );
189
+            break;
190
+        }
191
+
192
+        // Now copy the (optional) thumbnail
193
+        if (!empty($_FILES['thumbnail']['name']) && preg_match('/^image\/(png|gif|jpeg)/', $_FILES['thumbnail']['type'], $match)) {
194
+            // Thumbnails have either
195
+            // (a) the same filename as the main image
196
+            // (b) the same filename as the main image - but with a .png extension
197
+            if ($match[1] == 'png' && !preg_match('/\.(png)$/i', $fileName)) {
198
+                $thumbFile = preg_replace('/\.[a-z0-9]{3,5}$/', '.png', $fileName);
199
+            } else {
200
+                $thumbFile = $fileName;
201
+            }
202
+            $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName . $thumbFile;
203
+            if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $serverFileName)) {
204
+                Log::addMediaLog('Thumbnail file ' . $serverFileName . ' uploaded');
205
+            }
206
+        }
207
+    }
208
+
209
+    $controller->pageHeader();
210
+    // Build the gedcom record
211
+    $newged = "0 @new@ OBJE";
212
+    if ($tag[0] == 'FILE') {
213
+        // The admin has an edit field to change the filename
214
+        $text[0] = $folderName . $fileName;
215
+    } else {
216
+        // Users keep the original filename
217
+        $newged .= "\n1 FILE " . $folderName . $fileName;
218
+    }
219
+
220
+    $newged = FunctionsEdit::handleUpdates($newged);
221
+
222
+    $new_media = $WT_TREE->createRecord($newged);
223
+    if ($linktoid) {
224
+        $record = GedcomRecord::getInstance($linktoid, $WT_TREE);
225
+        $record->createFact('1 OBJE @' . $new_media->getXref() . '@', true);
226
+        Log::addEditLog('Media ID ' . $new_media->getXref() . " successfully added to $linktoid.");
227
+        $controller->addInlineJavascript('closePopupAndReloadParent();');
228
+    } else {
229
+        Log::addEditLog('Media ID ' . $new_media->getXref() . ' successfully added.');
230
+        $controller->addInlineJavascript('openerpasteid("' . $new_media->getXref() . '");');
231
+    }
232
+    echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>';
233
+
234
+    return;
235 235
 
236 236
 case 'update': // Save the information from the “editmedia” action
237
-	$controller->setPageTitle(I18N::translate('Edit the media object'));
238
-
239
-	// Validate the media folder
240
-	$folderName = str_replace('\\', '/', $folder);
241
-	$folderName = trim($folderName, '/');
242
-	if ($folderName == '.') {
243
-		$folderName = '';
244
-	}
245
-	if ($folderName) {
246
-		$folderName .= '/';
247
-		// Not allowed to use “../”
248
-		if (strpos('/' . $folderName, '/../') !== false) {
249
-			FlashMessages::addMessage('Folder names are not allowed to include “../”');
250
-			break;
251
-		}
252
-	}
253
-
254
-	// Make sure the media folder exists
255
-	if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
256
-		if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
257
-			FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)));
258
-		} else {
259
-			FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger');
260
-			break;
261
-		}
262
-	}
263
-
264
-	// Managers can create new media paths (subfolders). Users must use existing folders.
265
-	if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
266
-		if (Auth::isManager($WT_TREE)) {
267
-			if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
268
-				FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)));
269
-			} else {
270
-				FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger');
271
-				break;
272
-			}
273
-		} else {
274
-			// Regular users should not have seen this option - so no need for an error message.
275
-			break;
276
-		}
277
-	}
278
-
279
-	// The media folder exists. Now create a thumbnail folder to match it.
280
-	if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
281
-		if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
282
-			FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger');
283
-			break;
284
-		}
285
-	}
286
-
287
-	// Validate the media path and filename
288
-	if (preg_match('/^https?:\/\//i', $filename, $match)) {
289
-		// External media needs no further validation
290
-		$fileName   = $filename;
291
-		$folderName = '';
292
-		unset($_FILES['mediafile'], $_FILES['thumbnail']);
293
-	} elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) {
294
-		// Local media files cannot contain certain special characters
295
-		FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1]));
296
-		break;
297
-	} elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) {
298
-		// Do not allow obvious script files.
299
-		FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1]));
300
-		break;
301
-	} elseif (!$filename) {
302
-		FlashMessages::addMessage(I18N::translate('No media file was provided.'));
303
-		break;
304
-	} else {
305
-		$fileName = $filename;
306
-	}
307
-
308
-	$oldFilename = $media->getFilename();
309
-	$newFilename = $folderName . $fileName;
310
-
311
-	// Cannot rename local to external or vice-versa
312
-	if (Functions::isFileExternal($oldFilename) != Functions::isFileExternal($filename)) {
313
-		FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
314
-		break;
315
-	}
316
-
317
-	$messages  = false;
318
-	$move_file = false;
319
-
320
-	// Move files on disk (if we can) to reflect the change to the GEDCOM data
321
-	if (!$media->isExternal()) {
322
-		$oldServerFile  = $media->getServerFilename('main');
323
-		$oldServerThumb = $media->getServerFilename('thumb');
324
-
325
-		$newmedia       = new Media("xxx", "0 @xxx@ OBJE\n1 FILE " . $newFilename, null, $WT_TREE);
326
-		$newServerFile  = $newmedia->getServerFilename('main');
327
-		$newServerThumb = $newmedia->getServerFilename('thumb');
328
-
329
-		// We could be either renaming an existing file, or updating a record (with no valid file) to point to a new file
330
-		if ($oldServerFile !== $newServerFile) {
331
-			//-- check if the file is used in more than one gedcom
332
-			//-- do not allow it to be moved or renamed if it is
333
-			if (!$media->isExternal() && FunctionsDb::isMediaUsedInOtherTree($media->getFilename(), $WT_TREE->getTreeId())) {
334
-				FlashMessages::addMessage(I18N::translate('This file is linked to another family tree on this server. It cannot be deleted, moved, or renamed until these links have been removed.'));
335
-				break;
336
-			}
337
-
338
-			$move_file = true;
339
-			if (!file_exists($newServerFile) || md5_file($oldServerFile) === md5_file($newServerFile)) {
340
-				try {
341
-					rename($oldServerFile, $newServerFile);
342
-					FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
343
-				} catch (\ErrorException $ex) {
344
-					FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
345
-				}
346
-				$messages = true;
347
-			}
348
-			if (!file_exists($newServerFile)) {
349
-				FlashMessages::addMessage(I18N::translate('The media file %s does not exist.', Html::filename($newFilename)));
350
-				$messages = true;
351
-			}
352
-		}
353
-		if ($oldServerThumb != $newServerThumb) {
354
-			$move_file = true;
355
-			if (!file_exists($newServerThumb) || md5_file($oldServerFile) == md5_file($newServerThumb)) {
356
-				try {
357
-					rename($oldServerThumb, $newServerThumb);
358
-					FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
359
-				} catch (\ErrorException $ex) {
360
-					FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
361
-				}
362
-				$messages = true;
363
-			}
364
-			if (!file_exists($newServerThumb)) {
365
-				FlashMessages::addMessage(I18N::translate('The thumbnail file %s does not exist.', Html::filename($newFilename)));
366
-				$messages = true;
367
-			}
368
-		}
369
-	}
370
-
371
-	// Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges()
372
-	$glevels = array_merge(array('1'), $glevels);
373
-	$tag     = array_merge(array('FILE'), $tag);
374
-	$islink  = array_merge(array(0), $islink);
375
-	$text    = array_merge(array($newFilename), $text);
376
-
377
-	$record = GedcomRecord::getInstance($pid, $WT_TREE);
378
-	$newrec = "0 @$pid@ OBJE\n";
379
-	$newrec = FunctionsEdit::handleUpdates($newrec);
380
-	$record->updateRecord($newrec, $update_CHAN);
381
-
382
-	if ($move_file) {
383
-		// We've moved a file. Therefore we must approve the change, as rejecting
384
-		// the change will create broken references.
385
-		FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId());
386
-	}
387
-
388
-	if ($pid && $linktoid) {
389
-		$record = GedcomRecord::getInstance($linktoid, $WT_TREE);
390
-		$record->createFact('1 OBJE @' . $pid . '@', true);
391
-		Log::addEditLog('Media ID ' . $pid . " successfully added to $linktoid.");
392
-	}
393
-	$controller->pageHeader();
394
-	if ($messages) {
395
-		echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>';
396
-	} else {
397
-		$controller->addInlineJavascript('closePopupAndReloadParent();');
398
-	}
399
-
400
-	return;
237
+    $controller->setPageTitle(I18N::translate('Edit the media object'));
238
+
239
+    // Validate the media folder
240
+    $folderName = str_replace('\\', '/', $folder);
241
+    $folderName = trim($folderName, '/');
242
+    if ($folderName == '.') {
243
+        $folderName = '';
244
+    }
245
+    if ($folderName) {
246
+        $folderName .= '/';
247
+        // Not allowed to use “../”
248
+        if (strpos('/' . $folderName, '/../') !== false) {
249
+            FlashMessages::addMessage('Folder names are not allowed to include “../”');
250
+            break;
251
+        }
252
+    }
253
+
254
+    // Make sure the media folder exists
255
+    if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
256
+        if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
257
+            FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)));
258
+        } else {
259
+            FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger');
260
+            break;
261
+        }
262
+    }
263
+
264
+    // Managers can create new media paths (subfolders). Users must use existing folders.
265
+    if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
266
+        if (Auth::isManager($WT_TREE)) {
267
+            if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) {
268
+                FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)));
269
+            } else {
270
+                FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger');
271
+                break;
272
+            }
273
+        } else {
274
+            // Regular users should not have seen this option - so no need for an error message.
275
+            break;
276
+        }
277
+    }
278
+
279
+    // The media folder exists. Now create a thumbnail folder to match it.
280
+    if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
281
+        if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) {
282
+            FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger');
283
+            break;
284
+        }
285
+    }
286
+
287
+    // Validate the media path and filename
288
+    if (preg_match('/^https?:\/\//i', $filename, $match)) {
289
+        // External media needs no further validation
290
+        $fileName   = $filename;
291
+        $folderName = '';
292
+        unset($_FILES['mediafile'], $_FILES['thumbnail']);
293
+    } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) {
294
+        // Local media files cannot contain certain special characters
295
+        FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1]));
296
+        break;
297
+    } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) {
298
+        // Do not allow obvious script files.
299
+        FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1]));
300
+        break;
301
+    } elseif (!$filename) {
302
+        FlashMessages::addMessage(I18N::translate('No media file was provided.'));
303
+        break;
304
+    } else {
305
+        $fileName = $filename;
306
+    }
307
+
308
+    $oldFilename = $media->getFilename();
309
+    $newFilename = $folderName . $fileName;
310
+
311
+    // Cannot rename local to external or vice-versa
312
+    if (Functions::isFileExternal($oldFilename) != Functions::isFileExternal($filename)) {
313
+        FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
314
+        break;
315
+    }
316
+
317
+    $messages  = false;
318
+    $move_file = false;
319
+
320
+    // Move files on disk (if we can) to reflect the change to the GEDCOM data
321
+    if (!$media->isExternal()) {
322
+        $oldServerFile  = $media->getServerFilename('main');
323
+        $oldServerThumb = $media->getServerFilename('thumb');
324
+
325
+        $newmedia       = new Media("xxx", "0 @xxx@ OBJE\n1 FILE " . $newFilename, null, $WT_TREE);
326
+        $newServerFile  = $newmedia->getServerFilename('main');
327
+        $newServerThumb = $newmedia->getServerFilename('thumb');
328
+
329
+        // We could be either renaming an existing file, or updating a record (with no valid file) to point to a new file
330
+        if ($oldServerFile !== $newServerFile) {
331
+            //-- check if the file is used in more than one gedcom
332
+            //-- do not allow it to be moved or renamed if it is
333
+            if (!$media->isExternal() && FunctionsDb::isMediaUsedInOtherTree($media->getFilename(), $WT_TREE->getTreeId())) {
334
+                FlashMessages::addMessage(I18N::translate('This file is linked to another family tree on this server. It cannot be deleted, moved, or renamed until these links have been removed.'));
335
+                break;
336
+            }
337
+
338
+            $move_file = true;
339
+            if (!file_exists($newServerFile) || md5_file($oldServerFile) === md5_file($newServerFile)) {
340
+                try {
341
+                    rename($oldServerFile, $newServerFile);
342
+                    FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
343
+                } catch (\ErrorException $ex) {
344
+                    FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
345
+                }
346
+                $messages = true;
347
+            }
348
+            if (!file_exists($newServerFile)) {
349
+                FlashMessages::addMessage(I18N::translate('The media file %s does not exist.', Html::filename($newFilename)));
350
+                $messages = true;
351
+            }
352
+        }
353
+        if ($oldServerThumb != $newServerThumb) {
354
+            $move_file = true;
355
+            if (!file_exists($newServerThumb) || md5_file($oldServerFile) == md5_file($newServerThumb)) {
356
+                try {
357
+                    rename($oldServerThumb, $newServerThumb);
358
+                    FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
359
+                } catch (\ErrorException $ex) {
360
+                    FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename)));
361
+                }
362
+                $messages = true;
363
+            }
364
+            if (!file_exists($newServerThumb)) {
365
+                FlashMessages::addMessage(I18N::translate('The thumbnail file %s does not exist.', Html::filename($newFilename)));
366
+                $messages = true;
367
+            }
368
+        }
369
+    }
370
+
371
+    // Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges()
372
+    $glevels = array_merge(array('1'), $glevels);
373
+    $tag     = array_merge(array('FILE'), $tag);
374
+    $islink  = array_merge(array(0), $islink);
375
+    $text    = array_merge(array($newFilename), $text);
376
+
377
+    $record = GedcomRecord::getInstance($pid, $WT_TREE);
378
+    $newrec = "0 @$pid@ OBJE\n";
379
+    $newrec = FunctionsEdit::handleUpdates($newrec);
380
+    $record->updateRecord($newrec, $update_CHAN);
381
+
382
+    if ($move_file) {
383
+        // We've moved a file. Therefore we must approve the change, as rejecting
384
+        // the change will create broken references.
385
+        FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId());
386
+    }
387
+
388
+    if ($pid && $linktoid) {
389
+        $record = GedcomRecord::getInstance($linktoid, $WT_TREE);
390
+        $record->createFact('1 OBJE @' . $pid . '@', true);
391
+        Log::addEditLog('Media ID ' . $pid . " successfully added to $linktoid.");
392
+    }
393
+    $controller->pageHeader();
394
+    if ($messages) {
395
+        echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>';
396
+    } else {
397
+        $controller->addInlineJavascript('closePopupAndReloadParent();');
398
+    }
399
+
400
+    return;
401 401
 case 'showmediaform':
402
-	$controller->setPageTitle(I18N::translate('Create a media object'));
403
-	$action = 'create';
404
-	break;
402
+    $controller->setPageTitle(I18N::translate('Create a media object'));
403
+    $action = 'create';
404
+    break;
405 405
 case 'editmedia':
406
-	$controller->setPageTitle(I18N::translate('Edit the media object'));
407
-	$action = 'update';
408
-	break;
406
+    $controller->setPageTitle(I18N::translate('Edit the media object'));
407
+    $action = 'update';
408
+    break;
409 409
 default:
410
-	throw new \Exception('Bad $action (' . $action . ') in addmedia.php');
410
+    throw new \Exception('Bad $action (' . $action . ') in addmedia.php');
411 411
 }
412 412
 
413 413
 $controller->pageHeader();
@@ -418,140 +418,140 @@  discard block
 block discarded – undo
418 418
 echo '<input type="hidden" name="ged" value="', $WT_TREE->getNameHtml(), '">';
419 419
 echo '<input type="hidden" name="pid" value="', $pid, '">';
420 420
 if ($linktoid) {
421
-	echo '<input type="hidden" name="linktoid" value="', $linktoid, '">';
421
+    echo '<input type="hidden" name="linktoid" value="', $linktoid, '">';
422 422
 }
423 423
 echo '<table class="facts_table">';
424 424
 echo '<tr><td class="topbottombar" colspan="2">';
425 425
 echo $controller->getPageTitle(), FunctionsPrint::helpLink('OBJE');
426 426
 echo '</td></tr>';
427 427
 if (!$linktoid && $action == 'create') {
428
-	echo '<tr><td class="descriptionbox wrap width25">';
429
-	echo I18N::translate('Enter an individual, family, or source ID');
430
-	echo '</td><td class="optionbox wrap"><input type="text" data-autocomplete-type="IFS" name="linktoid" id="linktoid" size="6" value="">';
431
-	echo ' ', FunctionsPrint::printFindIndividualLink('linktoid');
432
-	echo ' ', FunctionsPrint::printFindFamilyLink('linktoid');
433
-	echo ' ', FunctionsPrint::printFindSourceLink('linktoid');
434
-	echo '<p class="small text-muted">', I18N::translate('Enter or search for the ID of the individual, family, or source to which this media object should be linked.'), '</p></td></tr>';
428
+    echo '<tr><td class="descriptionbox wrap width25">';
429
+    echo I18N::translate('Enter an individual, family, or source ID');
430
+    echo '</td><td class="optionbox wrap"><input type="text" data-autocomplete-type="IFS" name="linktoid" id="linktoid" size="6" value="">';
431
+    echo ' ', FunctionsPrint::printFindIndividualLink('linktoid');
432
+    echo ' ', FunctionsPrint::printFindFamilyLink('linktoid');
433
+    echo ' ', FunctionsPrint::printFindSourceLink('linktoid');
434
+    echo '<p class="small text-muted">', I18N::translate('Enter or search for the ID of the individual, family, or source to which this media object should be linked.'), '</p></td></tr>';
435 435
 }
436 436
 
437 437
 if ($media) {
438
-	$gedrec = $media->getGedcom();
438
+    $gedrec = $media->getGedcom();
439 439
 } else {
440
-	$gedrec = '';
440
+    $gedrec = '';
441 441
 }
442 442
 
443 443
 // 1 FILE
444 444
 if (preg_match('/\n\d (FILE.*)/', $gedrec, $match)) {
445
-	$gedfile = $match[1];
445
+    $gedfile = $match[1];
446 446
 } elseif ($filename) {
447
-	$gedfile = 'FILE ' . $filename;
447
+    $gedfile = 'FILE ' . $filename;
448 448
 } else {
449
-	$gedfile = 'FILE';
449
+    $gedfile = 'FILE';
450 450
 }
451 451
 
452 452
 if ($gedfile == 'FILE') {
453
-	// Box for user to choose to upload file from local computer
454
-	echo '<tr><td class="descriptionbox wrap width25">';
455
-	echo I18N::translate('Media file to upload') . '</td><td class="optionbox wrap"><input type="file" name="mediafile" onchange="updateFormat(this.value);" size="40"></td></tr>';
456
-	// Check for thumbnail generation support
457
-	if (Auth::isManager($WT_TREE)) {
458
-		echo '<tr><td class="descriptionbox wrap width25">';
459
-		echo I18N::translate('Thumbnail to upload') . '</td><td class="optionbox wrap"><input type="file" name="thumbnail" size="40">';
460
-		echo '<p class="small text-muted">', I18N::translate('Choose the thumbnail image that you want to upload. Although thumbnails can be generated automatically for images, you may wish to generate your own thumbnail, especially for other media types. For example, you can provide a still image from a video, or a photograph of the individual who made an audio recording.'), '</p>';
461
-		echo '</td></tr>';
462
-	}
453
+    // Box for user to choose to upload file from local computer
454
+    echo '<tr><td class="descriptionbox wrap width25">';
455
+    echo I18N::translate('Media file to upload') . '</td><td class="optionbox wrap"><input type="file" name="mediafile" onchange="updateFormat(this.value);" size="40"></td></tr>';
456
+    // Check for thumbnail generation support
457
+    if (Auth::isManager($WT_TREE)) {
458
+        echo '<tr><td class="descriptionbox wrap width25">';
459
+        echo I18N::translate('Thumbnail to upload') . '</td><td class="optionbox wrap"><input type="file" name="thumbnail" size="40">';
460
+        echo '<p class="small text-muted">', I18N::translate('Choose the thumbnail image that you want to upload. Although thumbnails can be generated automatically for images, you may wish to generate your own thumbnail, especially for other media types. For example, you can provide a still image from a video, or a photograph of the individual who made an audio recording.'), '</p>';
461
+        echo '</td></tr>';
462
+    }
463 463
 }
464 464
 
465 465
 // Filename on server
466 466
 $isExternal = Functions::isFileExternal($gedfile);
467 467
 if ($gedfile == 'FILE') {
468
-	if (Auth::isManager($WT_TREE)) {
469
-		FunctionsEdit::addSimpleTag(
470
-			"1 $gedfile",
471
-			'',
472
-			I18N::translate('Filename on server'),
473
-			'<p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '<br>' . I18N::translate('You may enter a URL, beginning with “http://”.') . '</p>'
474
-		);
475
-	}
476
-	$folder = '';
468
+    if (Auth::isManager($WT_TREE)) {
469
+        FunctionsEdit::addSimpleTag(
470
+            "1 $gedfile",
471
+            '',
472
+            I18N::translate('Filename on server'),
473
+            '<p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '<br>' . I18N::translate('You may enter a URL, beginning with “http://”.') . '</p>'
474
+        );
475
+    }
476
+    $folder = '';
477 477
 } else {
478
-	if ($isExternal) {
479
-		$fileName = substr($gedfile, 5);
480
-		$folder   = '';
481
-	} else {
482
-		$tmp      = substr($gedfile, 5);
483
-		$fileName = basename($tmp);
484
-		$folder   = dirname($tmp);
485
-		if ($folder === '.') {
486
-			$folder = '';
487
-		}
488
-	}
489
-
490
-	echo '<tr>';
491
-	echo '<td class="descriptionbox wrap width25">';
492
-	echo I18N::translate('Filename on server');
493
-	echo '</td>';
494
-	echo '<td class="optionbox wrap wrap">';
495
-	if (Auth::isManager($WT_TREE)) {
496
-		echo '<input name="filename" type="text" value="' . Filter::escapeHtml($fileName) . '" size="40"';
497
-		if ($isExternal) {
498
-			echo '>';
499
-		} else {
500
-			echo '><p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '</p>';
501
-		}
502
-	} else {
503
-		echo $fileName;
504
-		echo '<input name="filename" type="hidden" value="' . Filter::escapeHtml($fileName) . '" size="40">';
505
-	}
506
-	echo '</td>';
507
-	echo '</tr>';
478
+    if ($isExternal) {
479
+        $fileName = substr($gedfile, 5);
480
+        $folder   = '';
481
+    } else {
482
+        $tmp      = substr($gedfile, 5);
483
+        $fileName = basename($tmp);
484
+        $folder   = dirname($tmp);
485
+        if ($folder === '.') {
486
+            $folder = '';
487
+        }
488
+    }
489
+
490
+    echo '<tr>';
491
+    echo '<td class="descriptionbox wrap width25">';
492
+    echo I18N::translate('Filename on server');
493
+    echo '</td>';
494
+    echo '<td class="optionbox wrap wrap">';
495
+    if (Auth::isManager($WT_TREE)) {
496
+        echo '<input name="filename" type="text" value="' . Filter::escapeHtml($fileName) . '" size="40"';
497
+        if ($isExternal) {
498
+            echo '>';
499
+        } else {
500
+            echo '><p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '</p>';
501
+        }
502
+    } else {
503
+        echo $fileName;
504
+        echo '<input name="filename" type="hidden" value="' . Filter::escapeHtml($fileName) . '" size="40">';
505
+    }
506
+    echo '</td>';
507
+    echo '</tr>';
508 508
 }
509 509
 
510 510
 // Box for user to choose the folder to store the image
511 511
 if (!$isExternal) {
512
-	echo '<tr><td class="descriptionbox wrap width25">';
513
-	echo I18N::translate('Folder name on server'), '</td><td class="optionbox wrap">';
514
-	//-- don’t let regular users change the location of media items
515
-	if ($action !== 'update' || Auth::isManager($WT_TREE)) {
516
-		$mediaFolders = QueryMedia::folderList();
517
-		echo '<select name="folder_list" onchange="document.newmedia.folder.value=this.options[this.selectedIndex].value;">';
518
-		echo '<option ';
519
-		if ($folder == '') {
520
-			echo 'selected';
521
-		}
522
-		echo ' value=""> ', I18N::translate('Choose: '), ' </option>';
523
-		if (Auth::isAdmin()) {
524
-			echo '<option value="other" disabled>', I18N::translate('Other folder… please type in'), "</option>";
525
-		}
526
-		foreach ($mediaFolders as $f) {
527
-			echo '<option value="', $f, '" ';
528
-			if ($folder == $f) {
529
-				echo 'selected';
530
-			}
531
-			echo '>', $f, "</option>";
532
-		}
533
-		echo '</select>';
534
-	} else {
535
-		echo $folder;
536
-	}
537
-	if (Auth::isAdmin()) {
538
-		echo '<br><input type="text" name="folder" size="40" value="', $folder, '">';
539
-		if ($gedfile === 'FILE') {
540
-			echo '<p class="small text-muted">', I18N::translate('This entry is ignored if you have entered a URL into the filename field.'), '</p>';
541
-		}
542
-	} else {
543
-		echo '<input name="folder" type="hidden" value="', Filter::escapeHtml($folder), '">';
544
-	}
545
-	echo '<p class="small text-muted">', I18N::translate('If you have a large number of media files, you can organize them into folders and subfolders.'), '</p>'; echo '</td></tr>';
512
+    echo '<tr><td class="descriptionbox wrap width25">';
513
+    echo I18N::translate('Folder name on server'), '</td><td class="optionbox wrap">';
514
+    //-- don’t let regular users change the location of media items
515
+    if ($action !== 'update' || Auth::isManager($WT_TREE)) {
516
+        $mediaFolders = QueryMedia::folderList();
517
+        echo '<select name="folder_list" onchange="document.newmedia.folder.value=this.options[this.selectedIndex].value;">';
518
+        echo '<option ';
519
+        if ($folder == '') {
520
+            echo 'selected';
521
+        }
522
+        echo ' value=""> ', I18N::translate('Choose: '), ' </option>';
523
+        if (Auth::isAdmin()) {
524
+            echo '<option value="other" disabled>', I18N::translate('Other folder… please type in'), "</option>";
525
+        }
526
+        foreach ($mediaFolders as $f) {
527
+            echo '<option value="', $f, '" ';
528
+            if ($folder == $f) {
529
+                echo 'selected';
530
+            }
531
+            echo '>', $f, "</option>";
532
+        }
533
+        echo '</select>';
534
+    } else {
535
+        echo $folder;
536
+    }
537
+    if (Auth::isAdmin()) {
538
+        echo '<br><input type="text" name="folder" size="40" value="', $folder, '">';
539
+        if ($gedfile === 'FILE') {
540
+            echo '<p class="small text-muted">', I18N::translate('This entry is ignored if you have entered a URL into the filename field.'), '</p>';
541
+        }
542
+    } else {
543
+        echo '<input name="folder" type="hidden" value="', Filter::escapeHtml($folder), '">';
544
+    }
545
+    echo '<p class="small text-muted">', I18N::translate('If you have a large number of media files, you can organize them into folders and subfolders.'), '</p>'; echo '</td></tr>';
546 546
 } else {
547
-	echo '<input name="folder" type="hidden" value="">';
547
+    echo '<input name="folder" type="hidden" value="">';
548 548
 }
549 549
 
550 550
 // 1 FILE / 2 FORM
551 551
 if (preg_match('/\n(2 FORM .*)/', $gedrec, $match)) {
552
-	$gedform = $match[1];
552
+    $gedform = $match[1];
553 553
 } else {
554
-	$gedform = '2 FORM';
554
+    $gedform = '2 FORM';
555 555
 }
556 556
 $formid = FunctionsEdit::addSimpleTag($gedform);
557 557
 
@@ -573,45 +573,45 @@  discard block
 block discarded – undo
573 573
 
574 574
 // 1 FILE / 2 FORM / 3 TYPE
575 575
 if (preg_match('/\n(3 TYPE .*)/', $gedrec, $match)) {
576
-	$gedtype = $match[1];
576
+    $gedtype = $match[1];
577 577
 } else {
578
-	$gedtype = '3 TYPE photo'; // default to ‘Photo’
578
+    $gedtype = '3 TYPE photo'; // default to ‘Photo’
579 579
 }
580 580
 FunctionsEdit::addSimpleTag($gedtype);
581 581
 
582 582
 // 1 FILE / 2 TITL
583 583
 if (preg_match('/\n(2 TITL .*)/', $gedrec, $match)) {
584
-	$gedtitl = $match[1];
584
+    $gedtitl = $match[1];
585 585
 } else {
586
-	$gedtitl = '2 TITL';
586
+    $gedtitl = '2 TITL';
587 587
 }
588 588
 FunctionsEdit::addSimpleTag($gedtitl);
589 589
 
590 590
 // 1 FILE / 2 TITL / 3 _HEB
591 591
 if (strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), '_HEB') !== false) {
592
-	if (preg_match('/\n(3 _HEB .*)/', $gedrec, $match)) {
593
-		$gedtitl = $match[1];
594
-	} else {
595
-		$gedtitl = '3 _HEB';
596
-	}
597
-	FunctionsEdit::addSimpleTag($gedtitl);
592
+    if (preg_match('/\n(3 _HEB .*)/', $gedrec, $match)) {
593
+        $gedtitl = $match[1];
594
+    } else {
595
+        $gedtitl = '3 _HEB';
596
+    }
597
+    FunctionsEdit::addSimpleTag($gedtitl);
598 598
 }
599 599
 
600 600
 // 1 FILE / 2 TITL / 3 ROMN
601 601
 if (strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), 'ROMN') !== false) {
602
-	if (preg_match('/\n(3 ROMN .*)/', $gedrec, $match)) {
603
-		$gedtitl = $match[1];
604
-	} else {
605
-		$gedtitl = '3 ROMN';
606
-	}
607
-	FunctionsEdit::addSimpleTag($gedtitl);
602
+    if (preg_match('/\n(3 ROMN .*)/', $gedrec, $match)) {
603
+        $gedtitl = $match[1];
604
+    } else {
605
+        $gedtitl = '3 ROMN';
606
+    }
607
+    FunctionsEdit::addSimpleTag($gedtitl);
608 608
 }
609 609
 
610 610
 // 1 _PRIM
611 611
 if (preg_match('/\n(1 _PRIM .*)/', $gedrec, $match)) {
612
-	$gedprim = $match[1];
612
+    $gedprim = $match[1];
613 613
 } else {
614
-	$gedprim = '1 _PRIM';
614
+    $gedprim = '1 _PRIM';
615 615
 }
616 616
 FunctionsEdit::addSimpleTag($gedprim);
617 617
 
@@ -623,87 +623,87 @@  discard block
 block discarded – undo
623 623
 $sourceDATE  = '';
624 624
 $sourceQUAY  = '';
625 625
 if (!empty($gedrec)) {
626
-	preg_match_all('/\n(1 (?!FILE|FORM|TYPE|TITL|_PRIM|_THUM|CHAN|DATA).*(\n[2-9] .*)*)/', $gedrec, $matches);
627
-	foreach ($matches[1] as $subrec) {
628
-		$pieces = explode("\n", $subrec);
629
-		foreach ($pieces as $piece) {
630
-			$ft = preg_match("/(\d) (\w+)(.*)/", $piece, $match);
631
-			if ($ft == 0) {
632
-				continue;
633
-			}
634
-			$subLevel = $match[1];
635
-			$fact     = trim($match[2]);
636
-			$event    = trim($match[3]);
637
-			if ($fact === 'NOTE' || $fact === 'TEXT') {
638
-				$event .= Functions::getCont($subLevel + 1, $subrec);
639
-			}
640
-			if ($sourceSOUR !== '' && $subLevel <= $sourceLevel) {
641
-				// Get rid of all saved Source data
642
-				FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR);
643
-				FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE);
644
-				FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT);
645
-				FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE'));
646
-				FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY);
647
-				$sourceSOUR = '';
648
-			}
649
-
650
-			if ($fact === 'SOUR') {
651
-				$sourceLevel = $subLevel;
652
-				$sourceSOUR  = $event;
653
-				$sourcePAGE  = '';
654
-				$sourceTEXT  = '';
655
-				$sourceDATE  = '';
656
-				$sourceQUAY  = '';
657
-				continue;
658
-			}
659
-
660
-			// Save all incoming data about this source reference
661
-			if ($sourceSOUR !== '') {
662
-				if ($fact === 'PAGE') {
663
-					$sourcePAGE = $event;
664
-					continue;
665
-				}
666
-				if ($fact === 'TEXT') {
667
-					$sourceTEXT = $event;
668
-					continue;
669
-				}
670
-				if ($fact === 'DATE') {
671
-					$sourceDATE = $event;
672
-					continue;
673
-				}
674
-				if ($fact === 'QUAY') {
675
-					$sourceQUAY = $event;
676
-					continue;
677
-				}
678
-				continue;
679
-			}
680
-
681
-			// Output anything that isn’t part of a source reference
682
-			if (!empty($fact) && $fact !== 'CONC' && $fact !== 'CONT' && $fact !== 'DATA') {
683
-				FunctionsEdit::addSimpleTag($subLevel . ' ' . $fact . ' ' . $event);
684
-			}
685
-		}
686
-	}
687
-
688
-	if ($sourceSOUR !== '') {
689
-		// Get rid of all saved Source data
690
-		FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR);
691
-		FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE);
692
-		FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT);
693
-		FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE'));
694
-		FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY);
695
-	}
626
+    preg_match_all('/\n(1 (?!FILE|FORM|TYPE|TITL|_PRIM|_THUM|CHAN|DATA).*(\n[2-9] .*)*)/', $gedrec, $matches);
627
+    foreach ($matches[1] as $subrec) {
628
+        $pieces = explode("\n", $subrec);
629
+        foreach ($pieces as $piece) {
630
+            $ft = preg_match("/(\d) (\w+)(.*)/", $piece, $match);
631
+            if ($ft == 0) {
632
+                continue;
633
+            }
634
+            $subLevel = $match[1];
635
+            $fact     = trim($match[2]);
636
+            $event    = trim($match[3]);
637
+            if ($fact === 'NOTE' || $fact === 'TEXT') {
638
+                $event .= Functions::getCont($subLevel + 1, $subrec);
639
+            }
640
+            if ($sourceSOUR !== '' && $subLevel <= $sourceLevel) {
641
+                // Get rid of all saved Source data
642
+                FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR);
643
+                FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE);
644
+                FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT);
645
+                FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE'));
646
+                FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY);
647
+                $sourceSOUR = '';
648
+            }
649
+
650
+            if ($fact === 'SOUR') {
651
+                $sourceLevel = $subLevel;
652
+                $sourceSOUR  = $event;
653
+                $sourcePAGE  = '';
654
+                $sourceTEXT  = '';
655
+                $sourceDATE  = '';
656
+                $sourceQUAY  = '';
657
+                continue;
658
+            }
659
+
660
+            // Save all incoming data about this source reference
661
+            if ($sourceSOUR !== '') {
662
+                if ($fact === 'PAGE') {
663
+                    $sourcePAGE = $event;
664
+                    continue;
665
+                }
666
+                if ($fact === 'TEXT') {
667
+                    $sourceTEXT = $event;
668
+                    continue;
669
+                }
670
+                if ($fact === 'DATE') {
671
+                    $sourceDATE = $event;
672
+                    continue;
673
+                }
674
+                if ($fact === 'QUAY') {
675
+                    $sourceQUAY = $event;
676
+                    continue;
677
+                }
678
+                continue;
679
+            }
680
+
681
+            // Output anything that isn’t part of a source reference
682
+            if (!empty($fact) && $fact !== 'CONC' && $fact !== 'CONT' && $fact !== 'DATA') {
683
+                FunctionsEdit::addSimpleTag($subLevel . ' ' . $fact . ' ' . $event);
684
+            }
685
+        }
686
+    }
687
+
688
+    if ($sourceSOUR !== '') {
689
+        // Get rid of all saved Source data
690
+        FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR);
691
+        FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE);
692
+        FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT);
693
+        FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE'));
694
+        FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY);
695
+    }
696 696
 }
697 697
 if (Auth::isAdmin() && $action === 'update') {
698
-	echo '<tr><td class="descriptionbox wrap width25">';
699
-	echo GedcomTag::getLabel('CHAN'), '</td><td class="optionbox wrap">';
700
-	if ($NO_UPDATE_CHAN) {
701
-		echo '<input type="checkbox" checked name="preserve_last_changed">';
702
-	} else {
703
-		echo '<input type="checkbox" name="preserve_last_changed">';
704
-	}
705
-	echo I18N::translate('Keep the existing “last change” information'), '<br>';
706
-	echo '</td></tr>';
698
+    echo '<tr><td class="descriptionbox wrap width25">';
699
+    echo GedcomTag::getLabel('CHAN'), '</td><td class="optionbox wrap">';
700
+    if ($NO_UPDATE_CHAN) {
701
+        echo '<input type="checkbox" checked name="preserve_last_changed">';
702
+    } else {
703
+        echo '<input type="checkbox" name="preserve_last_changed">';
704
+    }
705
+    echo I18N::translate('Keep the existing “last change” information'), '<br>';
706
+    echo '</td></tr>';
707 707
 }
708 708
 echo '</table>';
709 709
 FunctionsEdit::printAddLayer('SOUR', 1);
Please login to merge, or discard this patch.