summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGreg Roach <fisharebest@gmail.com>2017-03-07 12:02:25 +0000
committerGreg Roach <fisharebest@gmail.com>2017-06-17 16:17:44 +0100
commit15d603e7c7c15d20f055d3d9c38d6b133453c5be (patch)
tree14cd348cd8d2cbb465626429334a9558c0bf5a43 /app
parent95664b44addad5559917902d85518988a3ea7bc4 (diff)
downloadwebtrees-15d603e7c7c15d20f055d3d9c38d6b133453c5be.tar.gz
webtrees-15d603e7c7c15d20f055d3d9c38d6b133453c5be.tar.bz2
webtrees-15d603e7c7c15d20f055d3d9c38d6b133453c5be.zip
jQuery-3, Bootstrap-4, FontAwesome-4.7, Select2-4, remove popup windows
Diffstat (limited to 'app')
-rw-r--r--app/Auth.php11
-rw-r--r--app/Bootstrap4.php192
-rw-r--r--app/Census/AbstractCensusColumn.php101
-rw-r--r--app/Census/AbstractCensusColumnCondition.php79
-rw-r--r--app/Census/Census.php1
-rw-r--r--app/Census/CensusColumnAge.php7
-rw-r--r--app/Census/CensusColumnAgeFemale.php7
-rw-r--r--app/Census/CensusColumnAgeFemale5Years.php7
-rw-r--r--app/Census/CensusColumnAgeMale.php7
-rw-r--r--app/Census/CensusColumnAgeMale5Years.php7
-rw-r--r--app/Census/CensusColumnAgeMarried.php5
-rw-r--r--app/Census/CensusColumnBirthDate.php5
-rw-r--r--app/Census/CensusColumnBirthDay.php5
-rw-r--r--app/Census/CensusColumnBirthDayDotMonthYear.php5
-rw-r--r--app/Census/CensusColumnBirthDayMonthSlashYear.php5
-rw-r--r--app/Census/CensusColumnBirthDaySlashMonth.php5
-rw-r--r--app/Census/CensusColumnBirthDaySlashMonthYear.php5
-rw-r--r--app/Census/CensusColumnBirthMonth.php5
-rw-r--r--app/Census/CensusColumnBirthPlace.php5
-rw-r--r--app/Census/CensusColumnBirthPlaceSimple.php5
-rw-r--r--app/Census/CensusColumnBirthYear.php5
-rw-r--r--app/Census/CensusColumnBornForeignParts.php5
-rw-r--r--app/Census/CensusColumnChildrenBornAlive.php7
-rw-r--r--app/Census/CensusColumnChildrenDied.php7
-rw-r--r--app/Census/CensusColumnChildrenLiving.php7
-rw-r--r--app/Census/CensusColumnConditionDanish.php1
-rw-r--r--app/Census/CensusColumnConditionEnglish.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchFemme.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchFille.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchGarcon.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchHomme.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchVeuf.php1
-rw-r--r--app/Census/CensusColumnConditionFrenchVeuve.php1
-rw-r--r--app/Census/CensusColumnConditionUs.php1
-rw-r--r--app/Census/CensusColumnFatherBirthPlace.php5
-rw-r--r--app/Census/CensusColumnFatherBirthPlaceSimple.php5
-rw-r--r--app/Census/CensusColumnFatherForeign.php5
-rw-r--r--app/Census/CensusColumnFullName.php5
-rw-r--r--app/Census/CensusColumnGivenNameInitial.php5
-rw-r--r--app/Census/CensusColumnGivenNames.php5
-rw-r--r--app/Census/CensusColumnInterface.php5
-rw-r--r--app/Census/CensusColumnMarriedWithinYear.php5
-rw-r--r--app/Census/CensusColumnMonthIfBornWithinYear.php5
-rw-r--r--app/Census/CensusColumnMonthIfMarriedWithinYear.php5
-rw-r--r--app/Census/CensusColumnMotherBirthPlace.php5
-rw-r--r--app/Census/CensusColumnMotherBirthPlaceSimple.php5
-rw-r--r--app/Census/CensusColumnMotherForeign.php5
-rw-r--r--app/Census/CensusColumnNationality.php18
-rw-r--r--app/Census/CensusColumnNull.php5
-rw-r--r--app/Census/CensusColumnOccupation.php5
-rw-r--r--app/Census/CensusColumnRelationToHead.php9
-rw-r--r--app/Census/CensusColumnRelationToHeadGerman.php9
-rw-r--r--app/Census/CensusColumnReligion.php5
-rw-r--r--app/Census/CensusColumnSexMF.php17
-rw-r--r--app/Census/CensusColumnSexMK.php1
-rw-r--r--app/Census/CensusColumnSexMZ.php1
-rw-r--r--app/Census/CensusColumnSurname.php5
-rw-r--r--app/Census/CensusColumnSurnameGivenNameInitial.php3
-rw-r--r--app/Census/CensusColumnSurnameGivenNames.php5
-rw-r--r--app/Census/CensusColumnYearsMarried.php7
-rw-r--r--app/Census/CensusInterface.php1
-rw-r--r--app/Census/CensusOfCzechRepublic.php1
-rw-r--r--app/Census/CensusOfCzechRepublic1880.php1
-rw-r--r--app/Census/CensusOfCzechRepublic1921.php1
-rw-r--r--app/Census/CensusOfDenmark.php1
-rw-r--r--app/Census/CensusOfDenmark1787.php1
-rw-r--r--app/Census/CensusOfDenmark1801.php1
-rw-r--r--app/Census/CensusOfDenmark1803.php1
-rw-r--r--app/Census/CensusOfDenmark1834.php1
-rw-r--r--app/Census/CensusOfDenmark1835.php1
-rw-r--r--app/Census/CensusOfDenmark1840.php1
-rw-r--r--app/Census/CensusOfDenmark1845.php1
-rw-r--r--app/Census/CensusOfDenmark1850.php1
-rw-r--r--app/Census/CensusOfDenmark1855.php1
-rw-r--r--app/Census/CensusOfDenmark1860.php1
-rw-r--r--app/Census/CensusOfDenmark1870.php1
-rw-r--r--app/Census/CensusOfDenmark1880.php1
-rw-r--r--app/Census/CensusOfDenmark1885.php1
-rw-r--r--app/Census/CensusOfDenmark1890.php1
-rw-r--r--app/Census/CensusOfDenmark1901.php1
-rw-r--r--app/Census/CensusOfDenmark1906.php1
-rw-r--r--app/Census/CensusOfDenmark1911.php1
-rw-r--r--app/Census/CensusOfDenmark1916.php1
-rw-r--r--app/Census/CensusOfDenmark1921.php1
-rw-r--r--app/Census/CensusOfDenmark1925.php1
-rw-r--r--app/Census/CensusOfDenmark1930.php1
-rw-r--r--app/Census/CensusOfDenmark1940.php1
-rw-r--r--app/Census/CensusOfDeutschland.php1
-rw-r--r--app/Census/CensusOfDeutschland1819.php3
-rw-r--r--app/Census/CensusOfDeutschland1867.php3
-rw-r--r--app/Census/CensusOfDeutschland1900.php3
-rw-r--r--app/Census/CensusOfDeutschland1919.php3
-rw-r--r--app/Census/CensusOfDeutschlandNL1867.php5
-rw-r--r--app/Census/CensusOfEngland.php1
-rw-r--r--app/Census/CensusOfEngland1841.php1
-rw-r--r--app/Census/CensusOfEngland1851.php1
-rw-r--r--app/Census/CensusOfEngland1861.php1
-rw-r--r--app/Census/CensusOfEngland1871.php1
-rw-r--r--app/Census/CensusOfEngland1881.php1
-rw-r--r--app/Census/CensusOfEngland1891.php1
-rw-r--r--app/Census/CensusOfEngland1901.php1
-rw-r--r--app/Census/CensusOfEngland1911.php1
-rw-r--r--app/Census/CensusOfFrance.php1
-rw-r--r--app/Census/CensusOfFrance1831.php1
-rw-r--r--app/Census/CensusOfFrance1836.php1
-rw-r--r--app/Census/CensusOfFrance1841.php1
-rw-r--r--app/Census/CensusOfFrance1846.php1
-rw-r--r--app/Census/CensusOfFrance1851.php1
-rw-r--r--app/Census/CensusOfFrance1856.php1
-rw-r--r--app/Census/CensusOfFrance1861.php1
-rw-r--r--app/Census/CensusOfFrance1866.php1
-rw-r--r--app/Census/CensusOfFrance1872.php1
-rw-r--r--app/Census/CensusOfFrance1876.php1
-rw-r--r--app/Census/CensusOfFrance1881.php1
-rw-r--r--app/Census/CensusOfFrance1886.php1
-rw-r--r--app/Census/CensusOfFrance1891.php1
-rw-r--r--app/Census/CensusOfFrance1896.php1
-rw-r--r--app/Census/CensusOfFrance1901.php1
-rw-r--r--app/Census/CensusOfFrance1906.php1
-rw-r--r--app/Census/CensusOfFrance1911.php1
-rw-r--r--app/Census/CensusOfFrance1921.php1
-rw-r--r--app/Census/CensusOfFrance1926.php1
-rw-r--r--app/Census/CensusOfFrance1931.php1
-rw-r--r--app/Census/CensusOfFrance1936.php1
-rw-r--r--app/Census/CensusOfFrance1946.php1
-rw-r--r--app/Census/CensusOfScotland.php1
-rw-r--r--app/Census/CensusOfScotland1841.php1
-rw-r--r--app/Census/CensusOfScotland1851.php1
-rw-r--r--app/Census/CensusOfScotland1861.php1
-rw-r--r--app/Census/CensusOfScotland1871.php1
-rw-r--r--app/Census/CensusOfScotland1881.php1
-rw-r--r--app/Census/CensusOfScotland1891.php1
-rw-r--r--app/Census/CensusOfScotland1901.php1
-rw-r--r--app/Census/CensusOfScotland1911.php1
-rw-r--r--app/Census/CensusOfUnitedStates.php1
-rw-r--r--app/Census/CensusOfUnitedStates1790.php1
-rw-r--r--app/Census/CensusOfUnitedStates1800.php1
-rw-r--r--app/Census/CensusOfUnitedStates1810.php1
-rw-r--r--app/Census/CensusOfUnitedStates1820.php1
-rw-r--r--app/Census/CensusOfUnitedStates1830.php1
-rw-r--r--app/Census/CensusOfUnitedStates1840.php1
-rw-r--r--app/Census/CensusOfUnitedStates1850.php1
-rw-r--r--app/Census/CensusOfUnitedStates1860.php1
-rw-r--r--app/Census/CensusOfUnitedStates1870.php1
-rw-r--r--app/Census/CensusOfUnitedStates1880.php1
-rw-r--r--app/Census/CensusOfUnitedStates1890.php1
-rw-r--r--app/Census/CensusOfUnitedStates1900.php1
-rw-r--r--app/Census/CensusOfUnitedStates1910.php1
-rw-r--r--app/Census/CensusOfUnitedStates1920.php1
-rw-r--r--app/Census/CensusOfUnitedStates1930.php1
-rw-r--r--app/Census/CensusOfUnitedStates1940.php1
-rw-r--r--app/Census/CensusOfWales.php1
-rw-r--r--app/Census/CensusOfWales1841.php1
-rw-r--r--app/Census/CensusOfWales1851.php1
-rw-r--r--app/Census/CensusOfWales1861.php1
-rw-r--r--app/Census/CensusOfWales1871.php1
-rw-r--r--app/Census/CensusOfWales1881.php1
-rw-r--r--app/Census/CensusOfWales1891.php1
-rw-r--r--app/Census/CensusOfWales1901.php1
-rw-r--r--app/Census/CensusOfWales1911.php1
-rw-r--r--app/Census/CensusPlaceInterface.php1
-rw-r--r--app/Census/RegisterOfEngland1939.php1
-rw-r--r--app/Census/RegisterOfWales1939.php1
-rw-r--r--app/Controller/AncestryController.php97
-rw-r--r--app/Controller/BranchesController.php7
-rw-r--r--app/Controller/ChartController.php24
-rw-r--r--app/Controller/CompactController.php31
-rw-r--r--app/Controller/DescendancyController.php27
-rw-r--r--app/Controller/FamilyBookController.php10
-rw-r--r--app/Controller/FamilyController.php22
-rw-r--r--app/Controller/GedcomRecordController.php4
-rw-r--r--app/Controller/HourglassController.php54
-rw-r--r--app/Controller/IndividualController.php324
-rw-r--r--app/Controller/IndividualListController.php569
-rw-r--r--app/Controller/LifespanController.php15
-rw-r--r--app/Controller/MediaController.php8
-rw-r--r--app/Controller/NoteController.php4
-rw-r--r--app/Controller/PageController.php58
-rw-r--r--app/Controller/PedigreeController.php12
-rw-r--r--app/Controller/RepositoryController.php12
-rw-r--r--app/Controller/SearchController.php102
-rw-r--r--app/Controller/SimpleController.php57
-rw-r--r--app/Controller/SourceController.php12
-rw-r--r--app/Controller/TimelineController.php12
-rw-r--r--app/Database.php67
-rw-r--r--app/Datatables.php180
-rw-r--r--app/Filter.php82
-rw-r--r--app/FlashMessages.php6
-rw-r--r--app/FontAwesome.php113
-rw-r--r--app/Functions/FunctionsCharts.php171
-rw-r--r--app/Functions/FunctionsDb.php8
-rw-r--r--app/Functions/FunctionsEdit.php1705
-rw-r--r--app/Functions/FunctionsPrint.php204
-rw-r--r--app/Functions/FunctionsPrintFacts.php72
-rw-r--r--app/Functions/FunctionsPrintLists.php201
-rw-r--r--app/GedcomCode/GedcomCodeName.php2
-rw-r--r--app/GedcomCode/GedcomCodePedi.php2
-rw-r--r--app/Html.php32
-rw-r--r--app/I18N.php27
-rw-r--r--app/Individual.php17
-rw-r--r--app/Mail.php24
-rw-r--r--app/Menu.php74
-rw-r--r--app/Module/AbstractModule.php25
-rw-r--r--app/Module/AlbumModule.php16
-rw-r--r--app/Module/BatchUpdate/BatchUpdateBasePlugin.php17
-rw-r--r--app/Module/BatchUpdate/BatchUpdateMarriedNamesPlugin.php4
-rw-r--r--app/Module/BatchUpdate/BatchUpdateSearchReplacePlugin.php20
-rw-r--r--app/Module/BatchUpdateModule.php35
-rw-r--r--app/Module/CensusAssistantModule.php962
-rw-r--r--app/Module/ChartsBlockModule.php65
-rw-r--r--app/Module/ClippingsCartModule.php145
-rw-r--r--app/Module/FamilyNavigatorModule.php10
-rw-r--r--app/Module/FamilyTreeFavoritesModule.php40
-rw-r--r--app/Module/FamilyTreeNewsModule.php16
-rw-r--r--app/Module/FamilyTreeStatisticsModule.php272
-rw-r--r--app/Module/FrequentlyAskedQuestionsModule.php64
-rw-r--r--app/Module/GoogleMapsModule.php4101
-rw-r--r--app/Module/HtmlBlockModule.php132
-rw-r--r--app/Module/IndividualFactsTabModule.php17
-rw-r--r--app/Module/IndividualSidebarModule.php23
-rw-r--r--app/Module/InteractiveTree/TreeView.php2
-rw-r--r--app/Module/InteractiveTreeModule.php9
-rw-r--r--app/Module/LifespansChartModule.php2
-rw-r--r--app/Module/LoggedInUsersModule.php4
-rw-r--r--app/Module/LoginBlockModule.php12
-rw-r--r--app/Module/MediaTabModule.php15
-rw-r--r--app/Module/NotesTabModule.php24
-rw-r--r--app/Module/OnThisDayModule.php63
-rw-r--r--app/Module/RecentChangesModule.php90
-rw-r--r--app/Module/RelationshipsChartModule.php46
-rw-r--r--app/Module/RelativesTabModule.php125
-rw-r--r--app/Module/ResearchTaskModule.php132
-rw-r--r--app/Module/ReviewChangesModule.php59
-rw-r--r--app/Module/SiteMapModule.php29
-rw-r--r--app/Module/SlideShowModule.php211
-rw-r--r--app/Module/SourcesTabModule.php17
-rw-r--r--app/Module/StoriesModule.php138
-rw-r--r--app/Module/ThemeSelectModule.php2
-rw-r--r--app/Module/TopGivenNamesModule.php33
-rw-r--r--app/Module/TopPageViewsModule.php19
-rw-r--r--app/Module/TopSurnamesModule.php33
-rw-r--r--app/Module/UpcomingAnniversariesModule.php91
-rw-r--r--app/Module/UserJournalModule.php15
-rw-r--r--app/Module/UserMessagesModule.php27
-rw-r--r--app/Module/UserWelcomeModule.php12
-rw-r--r--app/Module/WelcomeBlockModule.php13
-rw-r--r--app/Module/YahrzeitModule.php54
-rw-r--r--app/Place.php20
-rw-r--r--app/Report/ReportHtml.php4
-rw-r--r--app/Schema/Migration0.php2
-rw-r--r--app/Schema/Migration18.php2
-rw-r--r--app/Schema/Migration30.php1
-rw-r--r--app/Select2.php725
-rw-r--r--app/Site.php49
-rw-r--r--app/SpecialChars/AbstractSpecialChars.php54
-rw-r--r--app/SpecialChars/SpecialCharsAf.php46
-rw-r--r--app/SpecialChars/SpecialCharsAr.php36
-rw-r--r--app/SpecialChars/SpecialCharsCs.php46
-rw-r--r--app/SpecialChars/SpecialCharsDa.php46
-rw-r--r--app/SpecialChars/SpecialCharsDe.php46
-rw-r--r--app/SpecialChars/SpecialCharsEl.php48
-rw-r--r--app/SpecialChars/SpecialCharsEn.php48
-rw-r--r--app/SpecialChars/SpecialCharsEs.php46
-rw-r--r--app/SpecialChars/SpecialCharsEu.php46
-rw-r--r--app/SpecialChars/SpecialCharsFi.php46
-rw-r--r--app/SpecialChars/SpecialCharsFr.php46
-rw-r--r--app/SpecialChars/SpecialCharsGd.php46
-rw-r--r--app/SpecialChars/SpecialCharsHaw.php46
-rw-r--r--app/SpecialChars/SpecialCharsHe.php36
-rw-r--r--app/SpecialChars/SpecialCharsHu.php46
-rw-r--r--app/SpecialChars/SpecialCharsInterface.php45
-rw-r--r--app/SpecialChars/SpecialCharsIs.php46
-rw-r--r--app/SpecialChars/SpecialCharsIt.php46
-rw-r--r--app/SpecialChars/SpecialCharsLt.php46
-rw-r--r--app/SpecialChars/SpecialCharsNl.php46
-rw-r--r--app/SpecialChars/SpecialCharsNn.php46
-rw-r--r--app/SpecialChars/SpecialCharsPl.php46
-rw-r--r--app/SpecialChars/SpecialCharsPt.php46
-rw-r--r--app/SpecialChars/SpecialCharsRu.php48
-rw-r--r--app/SpecialChars/SpecialCharsSk.php46
-rw-r--r--app/SpecialChars/SpecialCharsSl.php46
-rw-r--r--app/SpecialChars/SpecialCharsSv.php46
-rw-r--r--app/SpecialChars/SpecialCharsTr.php46
-rw-r--r--app/SpecialChars/SpecialCharsVi.php52
-rw-r--r--app/Stats.php32
-rw-r--r--app/Theme/AbstractTheme.php303
-rw-r--r--app/Theme/AdministrationTheme.php103
-rw-r--r--app/Theme/CloudsTheme.php98
-rw-r--r--app/Theme/ColorsTheme.php63
-rw-r--r--app/Theme/FabTheme.php70
-rw-r--r--app/Theme/MinimalTheme.php89
-rw-r--r--app/Theme/ThemeInterface.php21
-rw-r--r--app/Theme/WebtreesTheme.php55
-rw-r--r--app/Theme/XeneaTheme.php71
-rw-r--r--app/Tree.php44
-rw-r--r--app/User.php55
296 files changed, 7472 insertions, 8182 deletions
diff --git a/app/Auth.php b/app/Auth.php
index 8b18a5ea81..b87b5378d5 100644
--- a/app/Auth.php
+++ b/app/Auth.php
@@ -136,17 +136,6 @@ class Auth {
}
/**
- * Is the current visitor a search engine? The global is set in session.php
- *
- * @return bool
- */
- public static function isSearchEngine() {
- global $SEARCH_SPIDER;
-
- return $SEARCH_SPIDER;
- }
-
- /**
* The ID of the authenticated user, from the current session.
*
* @return string|null
diff --git a/app/Bootstrap4.php b/app/Bootstrap4.php
new file mode 100644
index 0000000000..fd9c55f93e
--- /dev/null
+++ b/app/Bootstrap4.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2017 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+namespace Fisharebest\Webtrees;
+
+/**
+ * Helper functions to generate markup for Bootstrap 4.
+ *
+ * @link https://www.getbootstrap.com
+ */
+class Bootstrap4 extends Html {
+ /**
+ * Generate a badge containing a count of items.
+ *
+ * @param array $items
+ */
+ public static function badgeCount(array $items) {
+ if (empty($items)) {
+ return '';
+ } else {
+ return '<span class="badge badge-default">' . I18N::number(count($items)) . '</span>';
+ }
+ }
+
+ /**
+ * Generate a breadcrumb trail.
+ *
+ * @param array $hierarchy
+ * @param string $active
+ *
+ * @return string
+ */
+ public static function breadcrumbs(array $hierarchy, $active) {
+ $html = '<ol class="breadcrumb">';
+
+ foreach ($hierarchy as $url => $label) {
+ $html .= '<li class="breadcrumb-item"><a href="' . $url . '">' . $label . '</a></li>';
+ }
+
+ $html .= '<li class="breadcrumb-item active">' . $active . '</li></ol>';
+
+ return $html;
+ }
+
+ /**
+ * Generate a checkbox.
+ *
+ * @param string $label
+ * @param bool $inline
+ * @param string[] $attributes
+ *
+ * @return string
+ */
+ public static function checkbox($label, $inline, $attributes = []) {
+ if ($inline) {
+ $class = 'form-check form-check-inline';
+ } else {
+ $class = 'form-check';
+ }
+
+ $input_attributes = self::attributes([
+ 'class' => 'form-check-input',
+ 'type' => 'checkbox',
+ 'value' => '1',
+ ] + $attributes);
+
+ return
+ '<div class="' . $class . '">' .
+ '<label class="form-check-label">' .
+ '<input ' . $input_attributes . '> ' . Filter::escapeHtml($label) .
+ '</label>' .
+ '</div>';
+ }
+
+ /**
+ * Create a set of radio buttons for a form
+ *
+ * @param string $name The ID for the form element
+ * @param string[] $values Array of value=>display items
+ * @param string $selected The currently selected item
+ * @param bool $inline
+ * @param string[] $attributes
+ *
+ * @return string
+ */
+ public static function radioButtons($name, $values, $selected, $inline, $attributes = []) {
+ // An empty string is not the same as zero (but is the same as NULL).
+ if ($selected === null) {
+ $selected = '0';
+ }
+
+ if ($inline) {
+ $class = 'form-check form-check-inline';
+ } else {
+ $class = 'form-check';
+ }
+
+ $html = '';
+ foreach ($values as $value => $label) {
+ $input_attributes = self::attributes([
+ 'class' => 'form-check-input',
+ 'type' => 'radio',
+ 'name' => $name,
+ 'value' => $value,
+ 'checked' => (string) $value === (string) $selected,
+ ] + $attributes);
+
+ $html .=
+ '<div class="' . $class . '">' .
+ '<label class="form-check-label">' .
+ '<input ' . $input_attributes . '> ' . Filter::escapeHtml($label) .
+ '</label>' .
+ '</div>';
+ }
+
+ return $html;
+ }
+
+ /**
+ * Create a <select> control for a form.
+ *
+ * @param string[] $options
+ * @param string $selected
+ * @param string[] $attributes
+ *
+ * @return string
+ */
+ public static function select($options, $selected, $attributes = []) {
+ $html = '';
+ foreach ($options as $value => $option) {
+ $option_attributes = self::attributes([
+ 'value' => $value,
+ 'selected' => (string) $value === (string) $selected,
+ ]);
+
+ $html .= '<option ' . $option_attributes . '>' . Filter::escapeHtml($option) . '</option>';
+ }
+
+ if (empty($attributes['class'])) {
+ $attributes['class'] = 'form-control';
+ } else {
+ $attributes['class'] .= ' form-control';
+ }
+
+ $select_attributes = self::attributes($attributes);
+
+ return '<select ' . $select_attributes . '>' . $html . '</select>';
+ }
+
+ /**
+ * Create a multiple <select> control for a form.
+ *
+ * @param string[] $options
+ * @param string[] $selected
+ * @param string[] $attributes
+ *
+ * @return string
+ */
+ public static function multiSelect($options, $selected, $attributes = []) {
+ $html = '';
+ foreach ($options as $value => $option) {
+ $option_attributes = self::attributes([
+ 'value' => $value,
+ 'selected' => in_array((string) $value, $selected),
+ ]);
+
+ $html .= '<option ' . $option_attributes . '>' . Filter::escapeHtml($option) . '</option>';
+ }
+
+ if (empty($attributes['class'])) {
+ $attributes['class'] = 'form-control';
+ } else {
+ $attributes['class'] .= ' form-control';
+ }
+
+ $select_attributes = self::attributes($attributes);
+
+ return '<select ' . $select_attributes . ' multiple>' . $html . '</select>';
+ }
+}
diff --git a/app/Census/AbstractCensusColumn.php b/app/Census/AbstractCensusColumn.php
index 90434fcf5e..8cf36fe303 100644
--- a/app/Census/AbstractCensusColumn.php
+++ b/app/Census/AbstractCensusColumn.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -55,28 +56,6 @@ class AbstractCensusColumn {
}
/**
- * Extract the country (last part) of a place name.
- *
- * @param string $place - e.g. "London, England"
- *
- * @return string - e.g. "England"
- */
- protected function lastPartOfPlace($place) {
- $place = explode(', ', $place);
-
- return end($place);
- }
-
- /**
- * When did this census occur
- *
- * @return Date
- */
- public function date() {
- return new Date($this->census->censusDate());
- }
-
- /**
* Find the father of an individual
*
* @param Individual $individual
@@ -111,32 +90,6 @@ class AbstractCensusColumn {
}
/**
- * Remove the country of a place name, where it is the same as the census place
- *
- * @param string $place - e.g. "London, England"
- *
- * @return string - e.g. "London" (for census of England) and "London, England" elsewhere
- */
- protected function notCountry($place) {
- $parts = explode(', ', $place);
-
- if (end($parts) === $this->place()) {
- return implode(', ', array_slice($parts, 0, -1));
- } else {
- return $place;
- }
- }
-
- /**
- * Where did this census occur
- *
- * @return string
- */
- public function place() {
- return $this->census->censusPlace();
- }
-
- /**
* Find the current spouse family of an individual
*
* @param Individual $individual
@@ -155,13 +108,24 @@ class AbstractCensusColumn {
if (empty($families)) {
return null;
} else {
- usort($families, function (Family $x, Family $y) { return Date::compare($x->getMarriageDate(), $y->getMarriageDate()); });
+ usort($families, function (Family $x, Family $y) {
+ return Date::compare($x->getMarriageDate(), $y->getMarriageDate());
+ });
return end($families);
}
}
/**
+ * When did this census occur
+ *
+ * @return Date
+ */
+ public function date() {
+ return new Date($this->census->censusDate());
+ }
+
+ /**
* The full version of the column's name.
*
* @return string
@@ -169,4 +133,43 @@ class AbstractCensusColumn {
public function title() {
return $this->title;
}
+
+ /**
+ * Extract the country (last part) of a place name.
+ *
+ * @param string $place - e.g. "London, England"
+ *
+ * @return string - e.g. "England"
+ */
+ protected function lastPartOfPlace($place) {
+ $place = explode(', ', $place);
+
+ return end($place);
+ }
+
+ /**
+ * Remove the country of a place name, where it is the same as the census place
+ *
+ * @param string $place - e.g. "London, England"
+ *
+ * @return string - e.g. "London" (for census of England) and "London, England" elsewhere
+ */
+ protected function notCountry($place) {
+ $parts = explode(', ', $place);
+
+ if (end($parts) === $this->place()) {
+ return implode(', ', array_slice($parts, 0, -1));
+ } else {
+ return $place;
+ }
+ }
+
+ /**
+ * Where did this census occur
+ *
+ * @return string
+ */
+ public function place() {
+ return $this->census->censusPlace();
+ }
}
diff --git a/app/Census/AbstractCensusColumnCondition.php b/app/Census/AbstractCensusColumnCondition.php
index 47fe7b0fa3..aabd4624fd 100644
--- a/app/Census/AbstractCensusColumnCondition.php
+++ b/app/Census/AbstractCensusColumnCondition.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -26,7 +27,7 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
protected $husband = '';
/* Text to display for married females */
- protected $wife = '';
+ protected $wife = '';
/* Text to display for unmarried males */
protected $bachelor = '';
@@ -35,13 +36,13 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
protected $spinster = '';
/* Text to display for male children */
- protected $boy = '';
+ protected $boy = '';
/* Text to display for female children */
protected $girl = '';
/* Text to display for divorced males */
- protected $divorce = '';
+ protected $divorce = '';
/* Text to display for divorced females */
protected $divorcee = '';
@@ -50,7 +51,7 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
protected $widower = '';
/* Text to display for widowed females */
- protected $widow = '';
+ protected $widow = '';
/* At what age is this individual recorded as an adult */
protected $age_adult = 15;
@@ -58,8 +59,8 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -86,6 +87,19 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
}
/**
+ * Is the individual a child.
+ *
+ * @param Individual $individual
+ *
+ * @return bool
+ */
+ private function isChild(Individual $individual) {
+ $age = (int)Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
+
+ return $age < $this->age_adult;
+ }
+
+ /**
* How is this condition written in a census column.
*
* @param string $sex
@@ -107,11 +121,11 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
*
* @return string
*/
- private function conditionDivorced($sex) {
+ private function conditionSingle($sex) {
if ($sex === 'F') {
- return $this->divorcee;
+ return $this->spinster;
} else {
- return $this->divorce;
+ return $this->bachelor;
}
}
@@ -122,27 +136,23 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
*
* @return string
*/
- private function conditionMarried($sex) {
+ private function conditionDivorced($sex) {
if ($sex === 'F') {
- return $this->wife;
+ return $this->divorcee;
} else {
- return $this->husband;
+ return $this->divorce;
}
}
/**
- * How is this condition written in a census column.
+ * Is the individual dead.
*
- * @param string $sex
+ * @param Individual $individual
*
- * @return string
+ * @return bool
*/
- private function conditionSingle($sex) {
- if ($sex === 'F') {
- return $this->spinster;
- } else {
- return $this->bachelor;
- }
+ private function isDead(Individual $individual) {
+ return $individual->getDeathDate()->isOK() && Date::compare($individual->getDeathDate(), $this->date()) < 0;
}
/**
@@ -161,26 +171,17 @@ abstract class AbstractCensusColumnCondition extends AbstractCensusColumn implem
}
/**
- * Is the individual a child.
- *
- * @param Individual $individual
- *
- * @return bool
- */
- private function isChild(Individual $individual) {
- $age = (int) Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
-
- return $age < $this->age_adult;
- }
-
- /**
- * Is the individual dead.
+ * How is this condition written in a census column.
*
- * @param Individual $individual
+ * @param string $sex
*
- * @return bool
+ * @return string
*/
- private function isDead(Individual $individual) {
- return $individual->getDeathDate()->isOK() && Date::compare($individual->getDeathDate(), $this->date()) < 0;
+ private function conditionMarried($sex) {
+ if ($sex === 'F') {
+ return $this->wife;
+ } else {
+ return $this->husband;
+ }
}
}
diff --git a/app/Census/Census.php b/app/Census/Census.php
index 7393d75015..4e1b7b7759 100644
--- a/app/Census/Census.php
+++ b/app/Census/Census.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnAge.php b/app/Census/CensusColumnAge.php
index b4cc9705e8..294a326089 100644
--- a/app/Census/CensusColumnAge.php
+++ b/app/Census/CensusColumnAge.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,12 +26,12 @@ class CensusColumnAge extends AbstractCensusColumn implements CensusColumnInterf
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
public function generate(Individual $individual, Individual $head = null) {
- return (string) Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
+ return (string)Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
}
}
diff --git a/app/Census/CensusColumnAgeFemale.php b/app/Census/CensusColumnAgeFemale.php
index 3866de1714..17bfad324f 100644
--- a/app/Census/CensusColumnAgeFemale.php
+++ b/app/Census/CensusColumnAgeFemale.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnAgeFemale extends AbstractCensusColumn implements CensusColumn
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -34,7 +35,7 @@ class CensusColumnAgeFemale extends AbstractCensusColumn implements CensusColumn
if ($individual->getSex() === 'M') {
return '';
} else {
- return (string) Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
+ return (string)Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
}
}
}
diff --git a/app/Census/CensusColumnAgeFemale5Years.php b/app/Census/CensusColumnAgeFemale5Years.php
index fe974b8d74..a1cde3d0ed 100644
--- a/app/Census/CensusColumnAgeFemale5Years.php
+++ b/app/Census/CensusColumnAgeFemale5Years.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnAgeFemale5Years extends AbstractCensusColumn implements Census
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -39,7 +40,7 @@ class CensusColumnAgeFemale5Years extends AbstractCensusColumn implements Census
$years -= $years % 5;
}
- return (string) $years;
+ return (string)$years;
}
}
}
diff --git a/app/Census/CensusColumnAgeMale.php b/app/Census/CensusColumnAgeMale.php
index 9ff08810bb..3603edf118 100644
--- a/app/Census/CensusColumnAgeMale.php
+++ b/app/Census/CensusColumnAgeMale.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnAgeMale extends AbstractCensusColumn implements CensusColumnIn
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -34,7 +35,7 @@ class CensusColumnAgeMale extends AbstractCensusColumn implements CensusColumnIn
if ($individual->getSex() === 'F') {
return '';
} else {
- return (string) Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
+ return (string)Date::getAge($individual->getEstimatedBirthDate(), $this->date(), 0);
}
}
}
diff --git a/app/Census/CensusColumnAgeMale5Years.php b/app/Census/CensusColumnAgeMale5Years.php
index 85185fcef2..d8aa64981e 100644
--- a/app/Census/CensusColumnAgeMale5Years.php
+++ b/app/Census/CensusColumnAgeMale5Years.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnAgeMale5Years extends AbstractCensusColumn implements CensusCo
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -39,7 +40,7 @@ class CensusColumnAgeMale5Years extends AbstractCensusColumn implements CensusCo
$years -= $years % 5;
}
- return (string) $years;
+ return (string)$years;
}
}
}
diff --git a/app/Census/CensusColumnAgeMarried.php b/app/Census/CensusColumnAgeMarried.php
index 1ba40266bb..d42d3094c7 100644
--- a/app/Census/CensusColumnAgeMarried.php
+++ b/app/Census/CensusColumnAgeMarried.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnAgeMarried extends AbstractCensusColumn implements CensusColum
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDate.php b/app/Census/CensusColumnBirthDate.php
index 0a01d68e89..3724bf371b 100644
--- a/app/Census/CensusColumnBirthDate.php
+++ b/app/Census/CensusColumnBirthDate.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDate extends AbstractCensusColumn implements CensusColumn
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDay.php b/app/Census/CensusColumnBirthDay.php
index 0a481b89b8..338a7910c2 100644
--- a/app/Census/CensusColumnBirthDay.php
+++ b/app/Census/CensusColumnBirthDay.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDay extends AbstractCensusColumn implements CensusColumnI
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDayDotMonthYear.php b/app/Census/CensusColumnBirthDayDotMonthYear.php
index 89034a025b..3ae029f24d 100644
--- a/app/Census/CensusColumnBirthDayDotMonthYear.php
+++ b/app/Census/CensusColumnBirthDayDotMonthYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDayDotMonthYear extends AbstractCensusColumn implements C
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDayMonthSlashYear.php b/app/Census/CensusColumnBirthDayMonthSlashYear.php
index c7a447c73b..2a89eb6ce7 100644
--- a/app/Census/CensusColumnBirthDayMonthSlashYear.php
+++ b/app/Census/CensusColumnBirthDayMonthSlashYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDayMonthSlashYear extends AbstractCensusColumn implements
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDaySlashMonth.php b/app/Census/CensusColumnBirthDaySlashMonth.php
index 745c3867a3..f7b0cb9e9c 100644
--- a/app/Census/CensusColumnBirthDaySlashMonth.php
+++ b/app/Census/CensusColumnBirthDaySlashMonth.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDaySlashMonth extends AbstractCensusColumn implements Cen
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthDaySlashMonthYear.php b/app/Census/CensusColumnBirthDaySlashMonthYear.php
index cb42dda8c2..c8a51113df 100644
--- a/app/Census/CensusColumnBirthDaySlashMonthYear.php
+++ b/app/Census/CensusColumnBirthDaySlashMonthYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthDaySlashMonthYear extends AbstractCensusColumn implements
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthMonth.php b/app/Census/CensusColumnBirthMonth.php
index f4809811c9..7989a95f9f 100644
--- a/app/Census/CensusColumnBirthMonth.php
+++ b/app/Census/CensusColumnBirthMonth.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthMonth extends AbstractCensusColumn implements CensusColum
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthPlace.php b/app/Census/CensusColumnBirthPlace.php
index 41c49404fb..413f1d1796 100644
--- a/app/Census/CensusColumnBirthPlace.php
+++ b/app/Census/CensusColumnBirthPlace.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthPlace extends AbstractCensusColumn implements CensusColum
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthPlaceSimple.php b/app/Census/CensusColumnBirthPlaceSimple.php
index 82b22e4078..424d4976a6 100644
--- a/app/Census/CensusColumnBirthPlaceSimple.php
+++ b/app/Census/CensusColumnBirthPlaceSimple.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthPlaceSimple extends CensusColumnBirthPlace implements Cen
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBirthYear.php b/app/Census/CensusColumnBirthYear.php
index 5e173b1011..03a68893fb 100644
--- a/app/Census/CensusColumnBirthYear.php
+++ b/app/Census/CensusColumnBirthYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBirthYear extends AbstractCensusColumn implements CensusColumn
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnBornForeignParts.php b/app/Census/CensusColumnBornForeignParts.php
index 4bef3f6fc3..6efbd4e37e 100644
--- a/app/Census/CensusColumnBornForeignParts.php
+++ b/app/Census/CensusColumnBornForeignParts.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnBornForeignParts extends AbstractCensusColumn implements Censu
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnChildrenBornAlive.php b/app/Census/CensusColumnChildrenBornAlive.php
index 72187fdaf5..be94893e8c 100644
--- a/app/Census/CensusColumnChildrenBornAlive.php
+++ b/app/Census/CensusColumnChildrenBornAlive.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnChildrenBornAlive extends AbstractCensusColumn implements Cens
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -48,6 +49,6 @@ class CensusColumnChildrenBornAlive extends AbstractCensusColumn implements Cens
}
}
- return (string) $count;
+ return (string)$count;
}
}
diff --git a/app/Census/CensusColumnChildrenDied.php b/app/Census/CensusColumnChildrenDied.php
index 69e169f2f0..d14be0a7ca 100644
--- a/app/Census/CensusColumnChildrenDied.php
+++ b/app/Census/CensusColumnChildrenDied.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnChildrenDied extends AbstractCensusColumn implements CensusCol
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -50,6 +51,6 @@ class CensusColumnChildrenDied extends AbstractCensusColumn implements CensusCol
}
}
- return (string) $count;
+ return (string)$count;
}
}
diff --git a/app/Census/CensusColumnChildrenLiving.php b/app/Census/CensusColumnChildrenLiving.php
index 5e616416ab..9e76079d8c 100644
--- a/app/Census/CensusColumnChildrenLiving.php
+++ b/app/Census/CensusColumnChildrenLiving.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnChildrenLiving extends AbstractCensusColumn implements CensusC
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -49,6 +50,6 @@ class CensusColumnChildrenLiving extends AbstractCensusColumn implements CensusC
}
}
- return (string) $count;
+ return (string)$count;
}
}
diff --git a/app/Census/CensusColumnConditionDanish.php b/app/Census/CensusColumnConditionDanish.php
index 09ea74de69..c50b2ed88a 100644
--- a/app/Census/CensusColumnConditionDanish.php
+++ b/app/Census/CensusColumnConditionDanish.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionEnglish.php b/app/Census/CensusColumnConditionEnglish.php
index b1c2dafd20..c51ef638bd 100644
--- a/app/Census/CensusColumnConditionEnglish.php
+++ b/app/Census/CensusColumnConditionEnglish.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchFemme.php b/app/Census/CensusColumnConditionFrenchFemme.php
index 6071285f34..fd4fba73a8 100644
--- a/app/Census/CensusColumnConditionFrenchFemme.php
+++ b/app/Census/CensusColumnConditionFrenchFemme.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchFille.php b/app/Census/CensusColumnConditionFrenchFille.php
index 7680302a8b..58ba091bbf 100644
--- a/app/Census/CensusColumnConditionFrenchFille.php
+++ b/app/Census/CensusColumnConditionFrenchFille.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchGarcon.php b/app/Census/CensusColumnConditionFrenchGarcon.php
index fa03ad5c62..2dd8cfa264 100644
--- a/app/Census/CensusColumnConditionFrenchGarcon.php
+++ b/app/Census/CensusColumnConditionFrenchGarcon.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchHomme.php b/app/Census/CensusColumnConditionFrenchHomme.php
index ef1f6e7dc7..146a7d0a1b 100644
--- a/app/Census/CensusColumnConditionFrenchHomme.php
+++ b/app/Census/CensusColumnConditionFrenchHomme.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchVeuf.php b/app/Census/CensusColumnConditionFrenchVeuf.php
index 032f5edce9..c899dd6c09 100644
--- a/app/Census/CensusColumnConditionFrenchVeuf.php
+++ b/app/Census/CensusColumnConditionFrenchVeuf.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionFrenchVeuve.php b/app/Census/CensusColumnConditionFrenchVeuve.php
index 39a85286e1..b8e12ce673 100644
--- a/app/Census/CensusColumnConditionFrenchVeuve.php
+++ b/app/Census/CensusColumnConditionFrenchVeuve.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnConditionUs.php b/app/Census/CensusColumnConditionUs.php
index a3a6215009..f82aa99cf2 100644
--- a/app/Census/CensusColumnConditionUs.php
+++ b/app/Census/CensusColumnConditionUs.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnFatherBirthPlace.php b/app/Census/CensusColumnFatherBirthPlace.php
index b1bff18baa..bff10a4fa1 100644
--- a/app/Census/CensusColumnFatherBirthPlace.php
+++ b/app/Census/CensusColumnFatherBirthPlace.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnFatherBirthPlace extends AbstractCensusColumn implements Censu
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnFatherBirthPlaceSimple.php b/app/Census/CensusColumnFatherBirthPlaceSimple.php
index 2204a152b2..92bbd209d0 100644
--- a/app/Census/CensusColumnFatherBirthPlaceSimple.php
+++ b/app/Census/CensusColumnFatherBirthPlaceSimple.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnFatherBirthPlaceSimple extends CensusColumnFatherBirthPlace im
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnFatherForeign.php b/app/Census/CensusColumnFatherForeign.php
index f277f4e0ea..88f931f20c 100644
--- a/app/Census/CensusColumnFatherForeign.php
+++ b/app/Census/CensusColumnFatherForeign.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnFatherForeign extends AbstractCensusColumn implements CensusCo
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnFullName.php b/app/Census/CensusColumnFullName.php
index 4f74ca2ebc..0a1ed60090 100644
--- a/app/Census/CensusColumnFullName.php
+++ b/app/Census/CensusColumnFullName.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnFullName extends AbstractCensusColumn implements CensusColumnI
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnGivenNameInitial.php b/app/Census/CensusColumnGivenNameInitial.php
index 775a057f6a..33c8324852 100644
--- a/app/Census/CensusColumnGivenNameInitial.php
+++ b/app/Census/CensusColumnGivenNameInitial.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnGivenNameInitial extends AbstractCensusColumn implements Censu
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnGivenNames.php b/app/Census/CensusColumnGivenNames.php
index 8f862661ba..54eb17787d 100644
--- a/app/Census/CensusColumnGivenNames.php
+++ b/app/Census/CensusColumnGivenNames.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnGivenNames extends AbstractCensusColumn implements CensusColum
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnInterface.php b/app/Census/CensusColumnInterface.php
index 49c0658242..347646afa0 100644
--- a/app/Census/CensusColumnInterface.php
+++ b/app/Census/CensusColumnInterface.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -39,8 +40,8 @@ interface CensusColumnInterface {
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMarriedWithinYear.php b/app/Census/CensusColumnMarriedWithinYear.php
index 14f889d7b7..4604b3edbb 100644
--- a/app/Census/CensusColumnMarriedWithinYear.php
+++ b/app/Census/CensusColumnMarriedWithinYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMarriedWithinYear extends AbstractCensusColumn implements Cens
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMonthIfBornWithinYear.php b/app/Census/CensusColumnMonthIfBornWithinYear.php
index 18101cab39..7ff6df0899 100644
--- a/app/Census/CensusColumnMonthIfBornWithinYear.php
+++ b/app/Census/CensusColumnMonthIfBornWithinYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMonthIfBornWithinYear extends AbstractCensusColumn implements
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMonthIfMarriedWithinYear.php b/app/Census/CensusColumnMonthIfMarriedWithinYear.php
index cbef48a473..aeebec0283 100644
--- a/app/Census/CensusColumnMonthIfMarriedWithinYear.php
+++ b/app/Census/CensusColumnMonthIfMarriedWithinYear.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMonthIfMarriedWithinYear extends AbstractCensusColumn implemen
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMotherBirthPlace.php b/app/Census/CensusColumnMotherBirthPlace.php
index a90e335158..e75bb7a62a 100644
--- a/app/Census/CensusColumnMotherBirthPlace.php
+++ b/app/Census/CensusColumnMotherBirthPlace.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMotherBirthPlace extends AbstractCensusColumn implements Censu
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMotherBirthPlaceSimple.php b/app/Census/CensusColumnMotherBirthPlaceSimple.php
index 83185ffba6..b510bba726 100644
--- a/app/Census/CensusColumnMotherBirthPlaceSimple.php
+++ b/app/Census/CensusColumnMotherBirthPlaceSimple.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMotherBirthPlaceSimple extends CensusColumnMotherBirthPlace im
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnMotherForeign.php b/app/Census/CensusColumnMotherForeign.php
index 6ea62660f6..3c9760c90f 100644
--- a/app/Census/CensusColumnMotherForeign.php
+++ b/app/Census/CensusColumnMotherForeign.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnMotherForeign extends AbstractCensusColumn implements CensusCo
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnNationality.php b/app/Census/CensusColumnNationality.php
index f537726569..ec9cffe82d 100644
--- a/app/Census/CensusColumnNationality.php
+++ b/app/Census/CensusColumnNationality.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -23,18 +24,19 @@ use Fisharebest\Webtrees\Individual;
*/
class CensusColumnNationality extends AbstractCensusColumn implements CensusColumnInterface {
/** @var array Convert a country name to a nationality */
- private $nationalities = [
- 'England' => 'British',
- 'Scotland' => 'British',
- 'Wales' => 'British',
- 'Deutschland' => 'Deutsch',
- ];
+ private $nationalities
+ = [
+ 'England' => 'British',
+ 'Scotland' => 'British',
+ 'Wales' => 'British',
+ 'Deutschland' => 'Deutsch',
+ ];
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnNull.php b/app/Census/CensusColumnNull.php
index 9fda03f1ca..a30b7f1847 100644
--- a/app/Census/CensusColumnNull.php
+++ b/app/Census/CensusColumnNull.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnNull extends AbstractCensusColumn implements CensusColumnInter
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnOccupation.php b/app/Census/CensusColumnOccupation.php
index ce7b6c1d0e..bea00f0723 100644
--- a/app/Census/CensusColumnOccupation.php
+++ b/app/Census/CensusColumnOccupation.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnOccupation extends AbstractCensusColumn implements CensusColum
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnRelationToHead.php b/app/Census/CensusColumnRelationToHead.php
index c215f45ffc..69b74a6d21 100644
--- a/app/Census/CensusColumnRelationToHead.php
+++ b/app/Census/CensusColumnRelationToHead.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Functions\Functions;
@@ -25,15 +26,13 @@ class CensusColumnRelationToHead extends AbstractCensusColumn implements CensusC
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
public function generate(Individual $individual, Individual $head = null) {
- if ($head === null) {
- return '';
- } elseif ($individual == $head) {
+ if ($head === null || $individual === $head) {
return 'head';
} else {
return Functions::getCloseRelationshipName($head, $individual);
diff --git a/app/Census/CensusColumnRelationToHeadGerman.php b/app/Census/CensusColumnRelationToHeadGerman.php
index 34604451d5..edc785676a 100644
--- a/app/Census/CensusColumnRelationToHeadGerman.php
+++ b/app/Census/CensusColumnRelationToHeadGerman.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Functions\Functions;
@@ -25,15 +26,13 @@ class CensusColumnRelationToHeadGerman extends AbstractCensusColumn implements C
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
public function generate(Individual $individual, Individual $head = null) {
- if ($head === null) {
- return '';
- } elseif ($individual == $head) {
+ if ($head === null || $individual === $head) {
return 'Haushaltungsvorstand';
} else {
return Functions::getCloseRelationshipName($head, $individual);
diff --git a/app/Census/CensusColumnReligion.php b/app/Census/CensusColumnReligion.php
index d2cf758892..8b09d31b6f 100644
--- a/app/Census/CensusColumnReligion.php
+++ b/app/Census/CensusColumnReligion.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -26,8 +27,8 @@ class CensusColumnReligion extends AbstractCensusColumn implements CensusColumnI
*
* @todo Look for RELI tags (or subtags?)
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnSexMF.php b/app/Census/CensusColumnSexMF.php
index e213989a42..59659bbad4 100644
--- a/app/Census/CensusColumnSexMF.php
+++ b/app/Census/CensusColumnSexMF.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -30,19 +31,19 @@ class CensusColumnSexMF extends AbstractCensusColumn implements CensusColumnInte
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
public function generate(Individual $individual, Individual $head = null) {
switch ($individual->getSex()) {
- case 'M':
- return $this->male;
- case 'F':
- return $this->female;
- default:
- return '';
+ case 'M':
+ return $this->male;
+ case 'F':
+ return $this->female;
+ default:
+ return '';
}
}
}
diff --git a/app/Census/CensusColumnSexMK.php b/app/Census/CensusColumnSexMK.php
index 6f5c703cd4..f79d3bf52b 100644
--- a/app/Census/CensusColumnSexMK.php
+++ b/app/Census/CensusColumnSexMK.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnSexMZ.php b/app/Census/CensusColumnSexMZ.php
index bf7cf38291..55a6ebb4b6 100644
--- a/app/Census/CensusColumnSexMZ.php
+++ b/app/Census/CensusColumnSexMZ.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusColumnSurname.php b/app/Census/CensusColumnSurname.php
index 1f4512762f..5b4d7b3cdb 100644
--- a/app/Census/CensusColumnSurname.php
+++ b/app/Census/CensusColumnSurname.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnSurname extends AbstractCensusColumn implements CensusColumnIn
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnSurnameGivenNameInitial.php b/app/Census/CensusColumnSurnameGivenNameInitial.php
index ee44cf1fe1..58e39cb8f6 100644
--- a/app/Census/CensusColumnSurnameGivenNameInitial.php
+++ b/app/Census/CensusColumnSurnameGivenNameInitial.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -25,7 +26,7 @@ class CensusColumnSurnameGivenNameInitial extends CensusColumnFullName {
* Generate the likely value of this census column, based on available information.
*
* @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnSurnameGivenNames.php b/app/Census/CensusColumnSurnameGivenNames.php
index 4b6991599e..5ed9e910fa 100644
--- a/app/Census/CensusColumnSurnameGivenNames.php
+++ b/app/Census/CensusColumnSurnameGivenNames.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Individual;
@@ -24,8 +25,8 @@ class CensusColumnSurnameGivenNames extends AbstractCensusColumn implements Cens
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
diff --git a/app/Census/CensusColumnYearsMarried.php b/app/Census/CensusColumnYearsMarried.php
index dc101397d7..38cf0a472d 100644
--- a/app/Census/CensusColumnYearsMarried.php
+++ b/app/Census/CensusColumnYearsMarried.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
use Fisharebest\Webtrees\Date;
@@ -25,8 +26,8 @@ class CensusColumnYearsMarried extends AbstractCensusColumn implements CensusCol
/**
* Generate the likely value of this census column, based on available information.
*
- * @param Individual $individual
- * @param Individual|null $head
+ * @param Individual $individual
+ * @param Individual $head
*
* @return string
*/
@@ -44,7 +45,7 @@ class CensusColumnYearsMarried extends AbstractCensusColumn implements CensusCol
if ($marriage_date === null) {
return '';
} else {
- return (string) Date::getAge($marriage_date, $this->date(), 0);
+ return (string)Date::getAge($marriage_date, $this->date(), 0);
}
}
}
diff --git a/app/Census/CensusInterface.php b/app/Census/CensusInterface.php
index d263eab0a3..9d8eec30c9 100644
--- a/app/Census/CensusInterface.php
+++ b/app/Census/CensusInterface.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfCzechRepublic.php b/app/Census/CensusOfCzechRepublic.php
index 54d85134be..acb2bc7ec0 100644
--- a/app/Census/CensusOfCzechRepublic.php
+++ b/app/Census/CensusOfCzechRepublic.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfCzechRepublic1880.php b/app/Census/CensusOfCzechRepublic1880.php
index 961b8649ff..ed7f429fa2 100644
--- a/app/Census/CensusOfCzechRepublic1880.php
+++ b/app/Census/CensusOfCzechRepublic1880.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfCzechRepublic1921.php b/app/Census/CensusOfCzechRepublic1921.php
index dae915f292..79278b695c 100644
--- a/app/Census/CensusOfCzechRepublic1921.php
+++ b/app/Census/CensusOfCzechRepublic1921.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark.php b/app/Census/CensusOfDenmark.php
index bcf0c2ffd7..232dfd0b16 100644
--- a/app/Census/CensusOfDenmark.php
+++ b/app/Census/CensusOfDenmark.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1787.php b/app/Census/CensusOfDenmark1787.php
index 16e1443c6d..ad55a91c99 100644
--- a/app/Census/CensusOfDenmark1787.php
+++ b/app/Census/CensusOfDenmark1787.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1801.php b/app/Census/CensusOfDenmark1801.php
index 51ba42f343..c7cc21ea34 100644
--- a/app/Census/CensusOfDenmark1801.php
+++ b/app/Census/CensusOfDenmark1801.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1803.php b/app/Census/CensusOfDenmark1803.php
index 99031969ce..2d2f4c973f 100644
--- a/app/Census/CensusOfDenmark1803.php
+++ b/app/Census/CensusOfDenmark1803.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1834.php b/app/Census/CensusOfDenmark1834.php
index 75e74cdc22..60353621ed 100644
--- a/app/Census/CensusOfDenmark1834.php
+++ b/app/Census/CensusOfDenmark1834.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1835.php b/app/Census/CensusOfDenmark1835.php
index b164ef3840..74f09fa086 100644
--- a/app/Census/CensusOfDenmark1835.php
+++ b/app/Census/CensusOfDenmark1835.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1840.php b/app/Census/CensusOfDenmark1840.php
index 9415111a40..06a750034f 100644
--- a/app/Census/CensusOfDenmark1840.php
+++ b/app/Census/CensusOfDenmark1840.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1845.php b/app/Census/CensusOfDenmark1845.php
index d50bee94c8..8bdf738438 100644
--- a/app/Census/CensusOfDenmark1845.php
+++ b/app/Census/CensusOfDenmark1845.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1850.php b/app/Census/CensusOfDenmark1850.php
index a06d6f6647..de4698465a 100644
--- a/app/Census/CensusOfDenmark1850.php
+++ b/app/Census/CensusOfDenmark1850.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1855.php b/app/Census/CensusOfDenmark1855.php
index 37e7edd30f..c4ad4dae75 100644
--- a/app/Census/CensusOfDenmark1855.php
+++ b/app/Census/CensusOfDenmark1855.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1860.php b/app/Census/CensusOfDenmark1860.php
index 169ecfb2fd..d5a9a6ff99 100644
--- a/app/Census/CensusOfDenmark1860.php
+++ b/app/Census/CensusOfDenmark1860.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1870.php b/app/Census/CensusOfDenmark1870.php
index 8b645ebf94..db8ad00d05 100644
--- a/app/Census/CensusOfDenmark1870.php
+++ b/app/Census/CensusOfDenmark1870.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1880.php b/app/Census/CensusOfDenmark1880.php
index b28445003b..7156d3ba7b 100644
--- a/app/Census/CensusOfDenmark1880.php
+++ b/app/Census/CensusOfDenmark1880.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1885.php b/app/Census/CensusOfDenmark1885.php
index e21929c568..2cf2e64e18 100644
--- a/app/Census/CensusOfDenmark1885.php
+++ b/app/Census/CensusOfDenmark1885.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1890.php b/app/Census/CensusOfDenmark1890.php
index 5158d255cc..064b2fca6d 100644
--- a/app/Census/CensusOfDenmark1890.php
+++ b/app/Census/CensusOfDenmark1890.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1901.php b/app/Census/CensusOfDenmark1901.php
index ae658f13e1..5fd31fba52 100644
--- a/app/Census/CensusOfDenmark1901.php
+++ b/app/Census/CensusOfDenmark1901.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1906.php b/app/Census/CensusOfDenmark1906.php
index 6aed17336e..36e714bc51 100644
--- a/app/Census/CensusOfDenmark1906.php
+++ b/app/Census/CensusOfDenmark1906.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1911.php b/app/Census/CensusOfDenmark1911.php
index 2c0666113b..95e54546f2 100644
--- a/app/Census/CensusOfDenmark1911.php
+++ b/app/Census/CensusOfDenmark1911.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1916.php b/app/Census/CensusOfDenmark1916.php
index 49891e9a47..c21d7eb4c5 100644
--- a/app/Census/CensusOfDenmark1916.php
+++ b/app/Census/CensusOfDenmark1916.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1921.php b/app/Census/CensusOfDenmark1921.php
index b2d0faaadd..160ac3c8ca 100644
--- a/app/Census/CensusOfDenmark1921.php
+++ b/app/Census/CensusOfDenmark1921.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1925.php b/app/Census/CensusOfDenmark1925.php
index 3d68266129..bdafedda7c 100644
--- a/app/Census/CensusOfDenmark1925.php
+++ b/app/Census/CensusOfDenmark1925.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1930.php b/app/Census/CensusOfDenmark1930.php
index c1e7a9cee1..14b4eda001 100644
--- a/app/Census/CensusOfDenmark1930.php
+++ b/app/Census/CensusOfDenmark1930.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDenmark1940.php b/app/Census/CensusOfDenmark1940.php
index c380c3ef7f..a723038600 100644
--- a/app/Census/CensusOfDenmark1940.php
+++ b/app/Census/CensusOfDenmark1940.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDeutschland.php b/app/Census/CensusOfDeutschland.php
index e227f26790..9561274646 100644
--- a/app/Census/CensusOfDeutschland.php
+++ b/app/Census/CensusOfDeutschland.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfDeutschland1819.php b/app/Census/CensusOfDeutschland1819.php
index 7e6e168820..b9b799039c 100644
--- a/app/Census/CensusOfDeutschland1819.php
+++ b/app/Census/CensusOfDeutschland1819.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
@@ -35,7 +36,7 @@ class CensusOfDeutschland1819 extends CensusOfDeutschland implements CensusInter
*/
public function censusPlace() {
return 'Mecklenburg-Schwerin, Deutschland';
- }
+ }
/**
* The columns of the census.
diff --git a/app/Census/CensusOfDeutschland1867.php b/app/Census/CensusOfDeutschland1867.php
index cc964dc298..5918099a7a 100644
--- a/app/Census/CensusOfDeutschland1867.php
+++ b/app/Census/CensusOfDeutschland1867.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
@@ -35,7 +36,7 @@ class CensusOfDeutschland1867 extends CensusOfDeutschland implements CensusInter
*/
public function censusPlace() {
return 'Mecklenburg-Schwerin, Deutschland';
- }
+ }
/**
* The columns of the census.
diff --git a/app/Census/CensusOfDeutschland1900.php b/app/Census/CensusOfDeutschland1900.php
index 37a0ef98da..a8ffb19ebc 100644
--- a/app/Census/CensusOfDeutschland1900.php
+++ b/app/Census/CensusOfDeutschland1900.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
@@ -35,7 +36,7 @@ class CensusOfDeutschland1900 extends CensusOfDeutschland implements CensusInter
*/
public function censusPlace() {
return 'Mecklenburg-Schwerin, Deutschland';
- }
+ }
/**
* The columns of the census.
diff --git a/app/Census/CensusOfDeutschland1919.php b/app/Census/CensusOfDeutschland1919.php
index c319feeab8..9cdde360de 100644
--- a/app/Census/CensusOfDeutschland1919.php
+++ b/app/Census/CensusOfDeutschland1919.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
@@ -35,7 +36,7 @@ class CensusOfDeutschland1919 extends CensusOfDeutschland implements CensusInter
*/
public function censusPlace() {
return 'Mecklenburg-Schwerin, Deutschland';
- }
+ }
/**
* The columns of the census.
diff --git a/app/Census/CensusOfDeutschlandNL1867.php b/app/Census/CensusOfDeutschlandNL1867.php
index 9ce646b441..b558cc6de4 100644
--- a/app/Census/CensusOfDeutschlandNL1867.php
+++ b/app/Census/CensusOfDeutschlandNL1867.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
@@ -27,7 +28,7 @@ class CensusOfDeutschlandNL1867 extends CensusOfDeutschland implements CensusInt
public function censusDate() {
return '03 DEC 1867';
}
-
+
/**
* Where did this census occur, in GEDCOM format.
*
@@ -35,7 +36,7 @@ class CensusOfDeutschlandNL1867 extends CensusOfDeutschland implements CensusInt
*/
public function censusPlace() {
return 'Mecklenburg-Schwerin (Nachtragsliste), Deutschland';
- }
+ }
/**
* The columns of the census.
diff --git a/app/Census/CensusOfEngland.php b/app/Census/CensusOfEngland.php
index a18a6c5a4c..3874de608b 100644
--- a/app/Census/CensusOfEngland.php
+++ b/app/Census/CensusOfEngland.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1841.php b/app/Census/CensusOfEngland1841.php
index f362c8d5cc..eaa700e1f7 100644
--- a/app/Census/CensusOfEngland1841.php
+++ b/app/Census/CensusOfEngland1841.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1851.php b/app/Census/CensusOfEngland1851.php
index 995d797c81..43a3f50aab 100644
--- a/app/Census/CensusOfEngland1851.php
+++ b/app/Census/CensusOfEngland1851.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1861.php b/app/Census/CensusOfEngland1861.php
index fc8638e987..39a1c0fbe1 100644
--- a/app/Census/CensusOfEngland1861.php
+++ b/app/Census/CensusOfEngland1861.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1871.php b/app/Census/CensusOfEngland1871.php
index 1de14d19a6..a40af86a90 100644
--- a/app/Census/CensusOfEngland1871.php
+++ b/app/Census/CensusOfEngland1871.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1881.php b/app/Census/CensusOfEngland1881.php
index 639f69944d..f561303088 100644
--- a/app/Census/CensusOfEngland1881.php
+++ b/app/Census/CensusOfEngland1881.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1891.php b/app/Census/CensusOfEngland1891.php
index 589ff61aaf..fff4b07741 100644
--- a/app/Census/CensusOfEngland1891.php
+++ b/app/Census/CensusOfEngland1891.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1901.php b/app/Census/CensusOfEngland1901.php
index 2b3ef91b23..386c7f3e1d 100644
--- a/app/Census/CensusOfEngland1901.php
+++ b/app/Census/CensusOfEngland1901.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfEngland1911.php b/app/Census/CensusOfEngland1911.php
index d6ca8fffb0..464995c6ba 100644
--- a/app/Census/CensusOfEngland1911.php
+++ b/app/Census/CensusOfEngland1911.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance.php b/app/Census/CensusOfFrance.php
index fceb519867..a6cd7eb8b1 100644
--- a/app/Census/CensusOfFrance.php
+++ b/app/Census/CensusOfFrance.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1831.php b/app/Census/CensusOfFrance1831.php
index 6f9bb71c0e..f0cbe18469 100644
--- a/app/Census/CensusOfFrance1831.php
+++ b/app/Census/CensusOfFrance1831.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1836.php b/app/Census/CensusOfFrance1836.php
index 1fb9895485..d4c68be723 100644
--- a/app/Census/CensusOfFrance1836.php
+++ b/app/Census/CensusOfFrance1836.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1841.php b/app/Census/CensusOfFrance1841.php
index 2e107e8d3c..3fec4d8dd8 100644
--- a/app/Census/CensusOfFrance1841.php
+++ b/app/Census/CensusOfFrance1841.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1846.php b/app/Census/CensusOfFrance1846.php
index 2496e694aa..8c1a389d81 100644
--- a/app/Census/CensusOfFrance1846.php
+++ b/app/Census/CensusOfFrance1846.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1851.php b/app/Census/CensusOfFrance1851.php
index c92402693a..7a5dd10cc4 100644
--- a/app/Census/CensusOfFrance1851.php
+++ b/app/Census/CensusOfFrance1851.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1856.php b/app/Census/CensusOfFrance1856.php
index c066530f9b..ca466d5e0c 100644
--- a/app/Census/CensusOfFrance1856.php
+++ b/app/Census/CensusOfFrance1856.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1861.php b/app/Census/CensusOfFrance1861.php
index a8e4b8cb48..4f8985596d 100644
--- a/app/Census/CensusOfFrance1861.php
+++ b/app/Census/CensusOfFrance1861.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1866.php b/app/Census/CensusOfFrance1866.php
index cf6f7fcf72..ab96b39c8f 100644
--- a/app/Census/CensusOfFrance1866.php
+++ b/app/Census/CensusOfFrance1866.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1872.php b/app/Census/CensusOfFrance1872.php
index ea776ed3e2..477f7856b2 100644
--- a/app/Census/CensusOfFrance1872.php
+++ b/app/Census/CensusOfFrance1872.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1876.php b/app/Census/CensusOfFrance1876.php
index d10b55a307..0612636dd0 100644
--- a/app/Census/CensusOfFrance1876.php
+++ b/app/Census/CensusOfFrance1876.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1881.php b/app/Census/CensusOfFrance1881.php
index a9ce887eaa..46cd8d0699 100644
--- a/app/Census/CensusOfFrance1881.php
+++ b/app/Census/CensusOfFrance1881.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1886.php b/app/Census/CensusOfFrance1886.php
index 2bbc6f2aa7..9265265137 100644
--- a/app/Census/CensusOfFrance1886.php
+++ b/app/Census/CensusOfFrance1886.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1891.php b/app/Census/CensusOfFrance1891.php
index ddd486f72f..0bbc10631f 100644
--- a/app/Census/CensusOfFrance1891.php
+++ b/app/Census/CensusOfFrance1891.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1896.php b/app/Census/CensusOfFrance1896.php
index 687f9aeb0c..25bfc224e0 100644
--- a/app/Census/CensusOfFrance1896.php
+++ b/app/Census/CensusOfFrance1896.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1901.php b/app/Census/CensusOfFrance1901.php
index 51cbe6e32b..0fcc7c75a7 100644
--- a/app/Census/CensusOfFrance1901.php
+++ b/app/Census/CensusOfFrance1901.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1906.php b/app/Census/CensusOfFrance1906.php
index 389c025c80..4ff0146ed7 100644
--- a/app/Census/CensusOfFrance1906.php
+++ b/app/Census/CensusOfFrance1906.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1911.php b/app/Census/CensusOfFrance1911.php
index 2bf2becaa9..3e69e8e579 100644
--- a/app/Census/CensusOfFrance1911.php
+++ b/app/Census/CensusOfFrance1911.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1921.php b/app/Census/CensusOfFrance1921.php
index 5778d195d9..9856ab17af 100644
--- a/app/Census/CensusOfFrance1921.php
+++ b/app/Census/CensusOfFrance1921.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1926.php b/app/Census/CensusOfFrance1926.php
index 1ea7d11c81..d1b704709e 100644
--- a/app/Census/CensusOfFrance1926.php
+++ b/app/Census/CensusOfFrance1926.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1931.php b/app/Census/CensusOfFrance1931.php
index b8a099a26a..076a5d6872 100644
--- a/app/Census/CensusOfFrance1931.php
+++ b/app/Census/CensusOfFrance1931.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1936.php b/app/Census/CensusOfFrance1936.php
index b945b5e7d7..01eed1b8f5 100644
--- a/app/Census/CensusOfFrance1936.php
+++ b/app/Census/CensusOfFrance1936.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfFrance1946.php b/app/Census/CensusOfFrance1946.php
index c958a8b94f..c8f7b5d9b0 100644
--- a/app/Census/CensusOfFrance1946.php
+++ b/app/Census/CensusOfFrance1946.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland.php b/app/Census/CensusOfScotland.php
index 88d5de2b62..ad54650fcb 100644
--- a/app/Census/CensusOfScotland.php
+++ b/app/Census/CensusOfScotland.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1841.php b/app/Census/CensusOfScotland1841.php
index 1cf105330a..66ddbadc5c 100644
--- a/app/Census/CensusOfScotland1841.php
+++ b/app/Census/CensusOfScotland1841.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1851.php b/app/Census/CensusOfScotland1851.php
index ea579be922..8c066fa712 100644
--- a/app/Census/CensusOfScotland1851.php
+++ b/app/Census/CensusOfScotland1851.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1861.php b/app/Census/CensusOfScotland1861.php
index 4824601f19..ed628ac2d3 100644
--- a/app/Census/CensusOfScotland1861.php
+++ b/app/Census/CensusOfScotland1861.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1871.php b/app/Census/CensusOfScotland1871.php
index 81a09b5167..55bf666a02 100644
--- a/app/Census/CensusOfScotland1871.php
+++ b/app/Census/CensusOfScotland1871.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1881.php b/app/Census/CensusOfScotland1881.php
index 6801233876..25344794a1 100644
--- a/app/Census/CensusOfScotland1881.php
+++ b/app/Census/CensusOfScotland1881.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1891.php b/app/Census/CensusOfScotland1891.php
index afd12247ae..fa65406e15 100644
--- a/app/Census/CensusOfScotland1891.php
+++ b/app/Census/CensusOfScotland1891.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1901.php b/app/Census/CensusOfScotland1901.php
index 9c35c8c6a9..d12d3b52f6 100644
--- a/app/Census/CensusOfScotland1901.php
+++ b/app/Census/CensusOfScotland1901.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfScotland1911.php b/app/Census/CensusOfScotland1911.php
index 6b07b8e1c6..142a389341 100644
--- a/app/Census/CensusOfScotland1911.php
+++ b/app/Census/CensusOfScotland1911.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates.php b/app/Census/CensusOfUnitedStates.php
index da12abee05..0513e3ed71 100644
--- a/app/Census/CensusOfUnitedStates.php
+++ b/app/Census/CensusOfUnitedStates.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1790.php b/app/Census/CensusOfUnitedStates1790.php
index 6ab3951160..4e922b08f0 100644
--- a/app/Census/CensusOfUnitedStates1790.php
+++ b/app/Census/CensusOfUnitedStates1790.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1800.php b/app/Census/CensusOfUnitedStates1800.php
index a70e7d61ef..cb4b12c1f5 100644
--- a/app/Census/CensusOfUnitedStates1800.php
+++ b/app/Census/CensusOfUnitedStates1800.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1810.php b/app/Census/CensusOfUnitedStates1810.php
index f0e32ebdb9..c2c2e1d3fe 100644
--- a/app/Census/CensusOfUnitedStates1810.php
+++ b/app/Census/CensusOfUnitedStates1810.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1820.php b/app/Census/CensusOfUnitedStates1820.php
index 54aa12d898..7027f9e989 100644
--- a/app/Census/CensusOfUnitedStates1820.php
+++ b/app/Census/CensusOfUnitedStates1820.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1830.php b/app/Census/CensusOfUnitedStates1830.php
index bd033a9b72..1bac28786f 100644
--- a/app/Census/CensusOfUnitedStates1830.php
+++ b/app/Census/CensusOfUnitedStates1830.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1840.php b/app/Census/CensusOfUnitedStates1840.php
index 6fcb413d51..64ddd90b23 100644
--- a/app/Census/CensusOfUnitedStates1840.php
+++ b/app/Census/CensusOfUnitedStates1840.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1850.php b/app/Census/CensusOfUnitedStates1850.php
index dd5acb410b..695b48327b 100644
--- a/app/Census/CensusOfUnitedStates1850.php
+++ b/app/Census/CensusOfUnitedStates1850.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1860.php b/app/Census/CensusOfUnitedStates1860.php
index 2512514a50..ab420a3720 100644
--- a/app/Census/CensusOfUnitedStates1860.php
+++ b/app/Census/CensusOfUnitedStates1860.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1870.php b/app/Census/CensusOfUnitedStates1870.php
index 671538912e..6d28d1c7ae 100644
--- a/app/Census/CensusOfUnitedStates1870.php
+++ b/app/Census/CensusOfUnitedStates1870.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1880.php b/app/Census/CensusOfUnitedStates1880.php
index 0888c0686c..125ea59d62 100644
--- a/app/Census/CensusOfUnitedStates1880.php
+++ b/app/Census/CensusOfUnitedStates1880.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1890.php b/app/Census/CensusOfUnitedStates1890.php
index 8bd6dc42f1..046ee578ea 100644
--- a/app/Census/CensusOfUnitedStates1890.php
+++ b/app/Census/CensusOfUnitedStates1890.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1900.php b/app/Census/CensusOfUnitedStates1900.php
index 6498f29026..7101463fa5 100644
--- a/app/Census/CensusOfUnitedStates1900.php
+++ b/app/Census/CensusOfUnitedStates1900.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1910.php b/app/Census/CensusOfUnitedStates1910.php
index 3dbb4eee99..661ef1bdff 100644
--- a/app/Census/CensusOfUnitedStates1910.php
+++ b/app/Census/CensusOfUnitedStates1910.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1920.php b/app/Census/CensusOfUnitedStates1920.php
index f838fedbb4..89e6afc562 100644
--- a/app/Census/CensusOfUnitedStates1920.php
+++ b/app/Census/CensusOfUnitedStates1920.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1930.php b/app/Census/CensusOfUnitedStates1930.php
index fbe59bedd2..c8a3f961bc 100644
--- a/app/Census/CensusOfUnitedStates1930.php
+++ b/app/Census/CensusOfUnitedStates1930.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfUnitedStates1940.php b/app/Census/CensusOfUnitedStates1940.php
index ae166d1cfd..2959b43164 100644
--- a/app/Census/CensusOfUnitedStates1940.php
+++ b/app/Census/CensusOfUnitedStates1940.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales.php b/app/Census/CensusOfWales.php
index e23e0ab597..b283116e4a 100644
--- a/app/Census/CensusOfWales.php
+++ b/app/Census/CensusOfWales.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1841.php b/app/Census/CensusOfWales1841.php
index 8229f9a679..7443307dac 100644
--- a/app/Census/CensusOfWales1841.php
+++ b/app/Census/CensusOfWales1841.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1851.php b/app/Census/CensusOfWales1851.php
index dcf63d5502..82c0752bc9 100644
--- a/app/Census/CensusOfWales1851.php
+++ b/app/Census/CensusOfWales1851.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1861.php b/app/Census/CensusOfWales1861.php
index f14b0c0727..7afdcfc374 100644
--- a/app/Census/CensusOfWales1861.php
+++ b/app/Census/CensusOfWales1861.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1871.php b/app/Census/CensusOfWales1871.php
index 528eb8e4b6..37999aceec 100644
--- a/app/Census/CensusOfWales1871.php
+++ b/app/Census/CensusOfWales1871.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1881.php b/app/Census/CensusOfWales1881.php
index ab6214f174..fe46fba12e 100644
--- a/app/Census/CensusOfWales1881.php
+++ b/app/Census/CensusOfWales1881.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1891.php b/app/Census/CensusOfWales1891.php
index 23d32ee5d6..f4bf2727c5 100644
--- a/app/Census/CensusOfWales1891.php
+++ b/app/Census/CensusOfWales1891.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1901.php b/app/Census/CensusOfWales1901.php
index 9afde9dc18..ae23d7fcad 100644
--- a/app/Census/CensusOfWales1901.php
+++ b/app/Census/CensusOfWales1901.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusOfWales1911.php b/app/Census/CensusOfWales1911.php
index 832b63d398..0608511a2a 100644
--- a/app/Census/CensusOfWales1911.php
+++ b/app/Census/CensusOfWales1911.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/CensusPlaceInterface.php b/app/Census/CensusPlaceInterface.php
index 3b566ba619..af3afc8b1f 100644
--- a/app/Census/CensusPlaceInterface.php
+++ b/app/Census/CensusPlaceInterface.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/RegisterOfEngland1939.php b/app/Census/RegisterOfEngland1939.php
index 06a6ebf132..9448952531 100644
--- a/app/Census/RegisterOfEngland1939.php
+++ b/app/Census/RegisterOfEngland1939.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Census/RegisterOfWales1939.php b/app/Census/RegisterOfWales1939.php
index 9022934a48..115146e34a 100644
--- a/app/Census/RegisterOfWales1939.php
+++ b/app/Census/RegisterOfWales1939.php
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Census;
/**
diff --git a/app/Controller/AncestryController.php b/app/Controller/AncestryController.php
index 1091af49b7..6ddb44ca8d 100644
--- a/app/Controller/AncestryController.php
+++ b/app/Controller/AncestryController.php
@@ -16,8 +16,10 @@
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsCharts;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
+use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Theme;
@@ -45,15 +47,6 @@ class AncestryController extends ChartController {
$this->show_cousins = Filter::getInteger('show_cousins', 0, 1);
$this->chart_style = Filter::get('chart_style', '[0123]', '0');
$this->generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $this->tree()->getPreference('MAX_PEDIGREE_GENERATIONS'), $this->tree()->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
-
- if ($this->root && $this->root->canShowName()) {
- $this->setPageTitle(
- /* I18N: %s is an individual’s name */
- I18N::translate('Ancestors of %s', $this->root->getFullName())
- );
- } else {
- $this->setPageTitle(I18N::translate('Ancestors'));
- }
}
/**
@@ -63,19 +56,19 @@ class AncestryController extends ChartController {
* @param int $sosa
* @param int $generations
*/
- public function printChildAscendancy(Individual $individual, $sosa, $generations) {
- echo '<li>';
+ private function printChildAscendancy(Individual $individual, $sosa, $generations) {
+ echo '<li class="wt-ancestors-chart-list-item">';
echo '<table><tbody><tr><td>';
if ($sosa === 1) {
- echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent'), '"></td><td>';
+ echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="3" width="15"></td><td>';
} else {
echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="3" width="2">';
- echo '<img src="', Theme::theme()->parameter('image-hline'), '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent') - 2, '"></td><td>';
+ echo '<img src="', Theme::theme()->parameter('image-hline'), '" height="3" width="13"></td><td>';
}
- FunctionsPrint::printPedigreePerson($individual, $this->showFull());
+ FunctionsPrint::printPedigreePerson($individual);
echo '</td><td>';
if ($sosa > 1) {
- FunctionsCharts::printUrlArrow('?rootid=' . $individual->getXref() . '&amp;PEDIGREE_GENERATIONS=' . $this->generations . '&amp;show_full=' . $this->showFull() . '&amp;chart_style=' . $this->chart_style . '&amp;ged=' . $individual->getTree()->getNameUrl(), I18N::translate('Ancestors of %s', $individual->getFullName()), 3);
+ echo FontAwesome::linkIcon('arrow-down', I18N::translate('Ancestors of %s', $individual->getFullName()), ['href' => '?rootid=' . $individual->getXref() . '&amp;PEDIGREE_GENERATIONS=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;ged=' . $individual->getTree()->getNameUrl()]);
}
echo '</td><td class="details1">&nbsp;<span class="person_box' . ($sosa === 1 ? 'NN' : ($sosa % 2 ? 'F' : '')) . '">', I18N::number($sosa), '</span> ';
echo '</td><td class="details1">&nbsp;', FunctionsCharts::getSosaName($sosa), '</td>';
@@ -86,7 +79,7 @@ class AncestryController extends ChartController {
if ($family && $generations > 0) {
// Marriage details
echo '<span class="details1">';
- echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="', Theme::theme()->parameter('chart-descendancy-indent'), '"><a href="#" onclick="return expand_layer(\'sosa_', $sosa, '\');" class="top"><i id="sosa_', $sosa, '_img" class="icon-minus" title="', I18N::translate('View this family'), '"></i></a>';
+ echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="15"><a href="#" onclick="return expand_layer(\'sosa_', $sosa, '\');" class="top"><i id="sosa_', $sosa, '_img" class="icon-minus" title="', I18N::translate('View this family'), '"></i></a>';
echo ' <span class="person_box">', I18N::number($sosa * 2), '</span> ', I18N::translate('and');
echo ' <span class="person_boxF">', I18N::number($sosa * 2 + 1), '</span>';
if ($family->canShow()) {
@@ -95,7 +88,7 @@ class AncestryController extends ChartController {
}
}
echo '</span>';
- echo '<ul id="sosa_', $sosa, '" class="generation">';
+ echo '<ul class="wt-ancestors-chart-list" id="sosa_', $sosa, '">';
if ($family->getHusband()) {
$this->printChildAscendancy($family->getHusband(), $sosa * 2, $generations - 1);
}
@@ -106,4 +99,74 @@ class AncestryController extends ChartController {
}
echo '</li>';
}
+
+ /**
+ * Get the title of this chart
+ *
+ * @return string
+ */
+ public function getPageTitle() {
+ if ($this->root !== null && $this->root->canShowName()) {
+ return /* I18N: %s is an individual’s name */ I18N::translate('Ancestors of %s', $this->root->getFullName());
+ } else {
+ return I18N::translate('Ancestors');
+ }
+ }
+
+ /**
+ * Get the content of this chart
+ *
+ * @return string
+ */
+ public function getChart() {
+ if ($this->root === null || !$this->root->canShowName()) {
+ return '<p>' . I18N::translate('This individual does not exist or you do not have permission to view it.') . '</p>';
+ }
+
+ switch ($this->chart_style) {
+ case 0:
+ // List
+ return
+ '<ul class="chart_common">' .
+ $this->printChildAscendancy($this->root, 1, $this->generations - 1) .
+ '</ul>';
+
+ case 1:
+ // Booklet
+ // first page : show indi facts
+ FunctionsPrint::printPedigreePerson($this->root);
+ // process the tree
+ $ancestors = $this->sosaAncestors($this->generations - 1);
+ $ancestors = array_filter($ancestors); // The SOSA array includes empty placeholders
+
+ foreach ($ancestors as $sosa => $individual) {
+ foreach ($individual->getChildFamilies() as $family) {
+ FunctionsCharts::printSosaFamily($family->getXref(), $individual->getXref(), $sosa, '', '', '', $this->show_cousins);
+ }
+ }
+ break;
+
+ case 2:
+ // Individual list
+ $ancestors = $this->sosaAncestors($this->generations);
+ $ancestors = array_filter($ancestors); // The SOSA array includes empty placeholders
+
+ return FunctionsPrintLists::individualTable($ancestors, 'sosa');
+
+ case 3:
+ // Family list
+ $ancestors = $this->sosaAncestors($this->generations - 1);
+ $ancestors = array_filter($ancestors); // The SOSA array includes empty placeholders
+ $families = [];
+ foreach ($ancestors as $individual) {
+ foreach ($individual->getChildFamilies() as $family) {
+ $families[$family->getXref()] = $family;
+ }
+ }
+
+ return FunctionsPrintLists::familyTable($families);
+ }
+
+ return '';
+ }
}
diff --git a/app/Controller/BranchesController.php b/app/Controller/BranchesController.php
index 847c54c8f3..42f95e5be3 100644
--- a/app/Controller/BranchesController.php
+++ b/app/Controller/BranchesController.php
@@ -20,7 +20,6 @@ use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\GedcomCode\GedcomCodePedi;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Soundex;
@@ -50,7 +49,7 @@ class BranchesController extends PageController {
public function __construct() {
parent::__construct();
- $this->surname = Filter::get('surname', null, '');
+ $this->surname = Filter::get('surname');
$this->soundex_std = Filter::getBool('soundex_std');
$this->soundex_dm = Filter::getBool('soundex_dm');
@@ -207,7 +206,7 @@ class BranchesController extends PageController {
$sosa = array_search($individual, $this->ancestors, true);
if ($sosa !== false) {
$sosa_class = 'search_hit';
- $sosa_html = ' <a class="details1 ' . $individual->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="relationship.php?pid2=' . $this->ancestors[1]->getXref() . '&amp;pid1=' . $individual->getXref() . '">' . $sosa . '</a>' . self::sosaGeneration($sosa);
+ $sosa_html = ' <a class="details1 ' . $individual->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="relationship.php?pid2=' . $this->ancestors[1]->getXref() . '&amp;pid1=' . $individual->getXref() . '" rel="nofollow">' . $sosa . '</a>' . self::sosaGeneration($sosa);
} else {
$sosa_class = '';
$sosa_html = '';
@@ -243,7 +242,7 @@ class BranchesController extends PageController {
$sosa = array_search($spouse, $this->ancestors, true);
if ($sosa) {
$sosa_class = 'search_hit';
- $sosa_html = ' <a class="details1 ' . $spouse->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="relationship.php?pid2=' . $this->ancestors[1]->getXref() . '&amp;pid1=' . $spouse->getXref() . '"> ' . $sosa . ' </a>' . self::sosaGeneration($sosa);
+ $sosa_html = ' <a class="details1 ' . $spouse->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="relationship.php?pid2=' . $this->ancestors[1]->getXref() . '&amp;pid1=' . $spouse->getXref() . '" rel="nofollow"> ' . $sosa . ' </a>' . self::sosaGeneration($sosa);
} else {
$sosa_class = '';
$sosa_html = '';
diff --git a/app/Controller/ChartController.php b/app/Controller/ChartController.php
index 898f78bdd2..d321e2ef07 100644
--- a/app/Controller/ChartController.php
+++ b/app/Controller/ChartController.php
@@ -27,9 +27,6 @@ class ChartController extends PageController {
/** @var Individual Who is chart about? */
public $root;
- /** @var bool determines the detail shown in the personbox */
- private $show_full;
-
/** @var string An error message, in case we cannot construct the chart */
public $error_message;
@@ -54,17 +51,9 @@ class ChartController extends PageController {
$this->error_message = I18N::translate('This individual does not exist or you do not have permission to view it.');
}
- // Extract parameter from form
- $this->show_full = Filter::getInteger('show_full', 0, 1, $this->tree()->getPreference('PEDIGREE_FULL_DETAILS'));
-
$this->box = new \stdClass();
- if ($this->showFull()) {
- $this->box->width = Theme::theme()->parameter('chart-box-x');
- $this->box->height = Theme::theme()->parameter('chart-box-y');
- } else {
- $this->box->width = Theme::theme()->parameter('compact-chart-box-x');
- $this->box->height = Theme::theme()->parameter('compact-chart-box-y');
- }
+ $this->box->width = Theme::theme()->parameter('chart-box-x');
+ $this->box->height = Theme::theme()->parameter('chart-box-y');
}
/**
@@ -117,15 +106,6 @@ class ChartController extends PageController {
}
/**
- * Function showFull
- *
- * @return bool
- */
- public function showFull() {
- return $this->show_full;
- }
-
- /**
* Function boxDimensions
*
* @return \stdClass
diff --git a/app/Controller/CompactController.php b/app/Controller/CompactController.php
index 3108cd7011..699d5ab162 100644
--- a/app/Controller/CompactController.php
+++ b/app/Controller/CompactController.php
@@ -16,6 +16,7 @@
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\I18N;
/**
@@ -104,34 +105,18 @@ class CompactController extends ChartController {
/**
* Get an arrow, pointing to other generations.
*
- * @param int $n
- * @param string $arrow_dir
+ * @param int $sosa
+ * @param string $class
*
* @return string
*/
- public function sosaArrow($n, $arrow_dir) {
- $indi = $this->treeid[$n];
-
- $arrow_dir = substr($arrow_dir, 0, 1);
- if (I18N::direction() === 'rtl') {
- if ($arrow_dir === 'l') {
- $arrow_dir = 'r';
- } elseif ($arrow_dir === 'r') {
- $arrow_dir = 'l';
- }
- }
+ public function sosaArrow($sosa, $class) {
+ $indi = $this->treeid[$sosa];
- if ($indi) {
- $title = I18N::translate('Compact tree of %s', $indi->getFullName());
- $text = '<a class="icon-' . $arrow_dir . 'arrow" title="' . strip_tags($title) . '" href="?rootid=' . $indi->getXref();
- if ($this->show_thumbs) {
- $text .= '&amp;show_thumbs=' . $this->show_thumbs;
- }
- $text .= '"></a>';
+ if ($indi !== null) {
+ return FontAwesome::linkIcon($class, I18N::translate('Compact tree of %s', $indi->getFullName()), ['href' => $indi->getRawUrl()]);
} else {
- $text = '<i class="icon-' . $arrow_dir . 'arrow"></i>';
+ return FontAwesome::decorativeIcon($class);
}
-
- return $text;
}
}
diff --git a/app/Controller/DescendancyController.php b/app/Controller/DescendancyController.php
index c95c0717b4..2397b9cacf 100644
--- a/app/Controller/DescendancyController.php
+++ b/app/Controller/DescendancyController.php
@@ -17,6 +17,7 @@ namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsCharts;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\GedcomTag;
@@ -78,7 +79,7 @@ class DescendancyController extends ChartController {
return;
}
foreach ($person->getSpouseFamilies() as $family) {
- FunctionsCharts::printSosaFamily($family->getXref(), '', -1, $label, $person->getXref(), $gpid, 0, $this->showFull());
+ FunctionsCharts::printSosaFamily($family->getXref(), '', -1, $label, $person->getXref(), $gpid, 0);
$i = 1;
foreach ($family->getChildren() as $child) {
$this->printChildFamily($child, $depth - 1, $label . ($i++) . '.', $person->getXref());
@@ -96,12 +97,12 @@ class DescendancyController extends ChartController {
echo '<li>';
echo '<table><tr><td>';
if ($depth == $this->generations) {
- echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent'), '" alt=""></td><td>';
+ echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="15"></td><td>';
} else {
echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="3">';
- echo '<img src="' . Theme::theme()->parameter('image-hline') . '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent') - 3, '"></td><td>';
+ echo '<img src="' . Theme::theme()->parameter('image-hline') . '" height="3" width="', 12, '"></td><td>';
}
- FunctionsPrint::printPedigreePerson($person, $this->showFull());
+ FunctionsPrint::printPedigreePerson($person);
echo '</td>';
// check if child has parents and add an arrow
@@ -109,7 +110,7 @@ class DescendancyController extends ChartController {
echo '<td>';
foreach ($person->getChildFamilies() as $cfamily) {
foreach ($cfamily->getSpouses() as $parent) {
- FunctionsCharts::printUrlArrow('?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;show_full=' . $this->showFull() . '&amp;ged=' . $parent->getTree()->getNameUrl(), I18N::translate('Start at parents'), 2);
+ echo FontAwesome::linkIcon('arrow-up', I18N::translate('Start at parents'), ['href' => '?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;ged=' . $parent->getTree()->getNameUrl()]);
// only show the arrow for one of the parents
break;
}
@@ -117,9 +118,7 @@ class DescendancyController extends ChartController {
// d'Aboville child number
$level = $this->generations - $depth;
- if ($this->showFull()) {
- echo '<br><br>&nbsp;';
- }
+ echo '<br><br>&nbsp;';
echo '<span dir="ltr">'; //needed so that RTL languages will display this properly
if (!isset($this->dabo_num[$level])) {
$this->dabo_num[$level] = 0;
@@ -162,7 +161,7 @@ class DescendancyController extends ChartController {
$uid = Uuid::uuid4(); // create a unique ID
// print marriage info
echo '<li>';
- echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="', Theme::theme()->parameter('chart-descendancy-indent') + 4, '">';
+ echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="', 19, '">';
echo '<span class="details1">';
echo '<a href="#" onclick="expand_layer(\'' . $uid . '\'); return false;" class="top"><i id="' . $uid . '_img" class="icon-minus" title="' . I18N::translate('View this family') . '"></i></a>';
if ($family->canShow()) {
@@ -174,10 +173,10 @@ class DescendancyController extends ChartController {
// print spouse
$spouse = $family->getSpouse($person);
- echo '<ul id="' . $uid . '" class="generation">';
+ echo '<ul id="' . $uid . '">';
echo '<li>';
echo '<table><tr><td>';
- FunctionsPrint::printPedigreePerson($spouse, $this->showFull());
+ FunctionsPrint::printPedigreePerson($spouse);
echo '</td>';
// check if spouse has parents and add an arrow
@@ -186,15 +185,13 @@ class DescendancyController extends ChartController {
if ($spouse) {
foreach ($spouse->getChildFamilies() as $cfamily) {
foreach ($cfamily->getSpouses() as $parent) {
- FunctionsCharts::printUrlArrow('?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;show_full=' . $this->showFull() . '&amp;ged=' . $parent->getTree()->getNameUrl(), I18N::translate('Start at parents'), 2);
+ echo FontAwesome::linkIcon('arrow-up', I18N::translate('Start at parents'), ['href' => '?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;ged=' . $parent->getTree()->getNameUrl()]);
// only show the arrow for one of the parents
break;
}
}
}
- if ($this->showFull()) {
- echo '<br><br>&nbsp;';
- }
+ echo '<br><br>&nbsp;';
echo '</td></tr>';
// children
diff --git a/app/Controller/FamilyBookController.php b/app/Controller/FamilyBookController.php
index 49ed8bab22..93a002c4b6 100644
--- a/app/Controller/FamilyBookController.php
+++ b/app/Controller/FamilyBookController.php
@@ -150,7 +150,7 @@ class FamilyBookController extends ChartController {
}
echo '<table><tr><td>';
if ($person) {
- FunctionsPrint::printPedigreePerson($person, $this->showFull());
+ FunctionsPrint::printPedigreePerson($person);
echo '</td><td>',
'<img class="line2" src="', Theme::theme()->parameter('image-hline'), '" width="8" height="3">';
} else {
@@ -164,7 +164,7 @@ class FamilyBookController extends ChartController {
foreach ($person->getSpouseFamilies() as $family) {
$spouse = $family->getSpouse($person);
echo '</td></tr><tr><td>';
- FunctionsPrint::printPedigreePerson($spouse, $this->showFull());
+ FunctionsPrint::printPedigreePerson($spouse);
$numkids += 0.95;
echo '</td><td>';
}
@@ -257,7 +257,7 @@ class FamilyBookController extends ChartController {
'<td>';
$lh = $savlh; // restore original line height
//-- print the father box
- FunctionsPrint::printPedigreePerson($family->getHusband(), $this->showFull());
+ FunctionsPrint::printPedigreePerson($family->getHusband());
echo '</td>';
if ($family->getHusband()) {
echo '<td>';
@@ -280,7 +280,7 @@ class FamilyBookController extends ChartController {
'<td><img class="line4" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>',
'<td>';
//-- print the mother box
- FunctionsPrint::printPedigreePerson($family->getWife(), $this->showFull());
+ FunctionsPrint::printPedigreePerson($family->getWife());
echo '</td>';
if ($family->getWife()) {
echo '<td>';
@@ -347,7 +347,7 @@ class FamilyBookController extends ChartController {
*/
private function printEmptyBox() {
- echo $this->showFull() ? Theme::theme()->individualBoxEmpty() : Theme::theme()->individualBoxSmallEmpty();
+ echo Theme::theme()->individualBoxEmpty();
}
/**
diff --git a/app/Controller/FamilyController.php b/app/Controller/FamilyController.php
index 500ddc2532..0b0caf50b8 100644
--- a/app/Controller/FamilyController.php
+++ b/app/Controller/FamilyController.php
@@ -74,20 +74,14 @@ class FamilyController extends GedcomRecordController {
if (Auth::isEditor($this->record->getTree())) {
// edit_fam / members
- $menu->addSubmenu(new Menu(I18N::translate('Change family members'), '#', 'menu-fam-change', [
- 'onclick' => 'return change_family_members("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Change family members'), 'edit_interface.php?action=changefamily&ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-fam-change'));
// edit_fam / add child
- $menu->addSubmenu(new Menu(I18N::translate('Add a child to this family'), '#', 'menu-fam-addchil', [
- 'onclick' => 'return add_child_to_family("' . $this->record->getXref() . '", "U");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Add a child to this family'), 'edit_interface.php?action=add_child_to_family&amp;ged=' . $this->record->getTree()->getNameHtml() .'&amp;xref=' . $this->record->getXref() . '&amp;gender=U', 'menu-fam-addchil'));
// edit_fam / reorder_children
if ($this->record->getNumberOfChildren() > 1) {
- $menu->addSubmenu(new Menu(I18N::translate('Re-order children'), '#', 'menu-fam-orderchil', [
- 'onclick' => 'return reorder_children("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Re-order children'), 'edit_interface.php?action=reorder_children&amp;ged=' . $this->record->getTree()->getNameHtml() .'&amp;xref=' . $this->record->getXref(), 'menu-fam-orderchil'));
}
// delete
@@ -98,9 +92,7 @@ class FamilyController extends GedcomRecordController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-fam-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-fam-editraw'));
}
return $menu;
@@ -146,13 +138,13 @@ class FamilyController extends GedcomRecordController {
echo '<tr><td class="descriptionbox">';
echo I18N::translate('Note');
echo '</td><td class="optionbox">';
- echo "<a href=\"#\" onclick=\"return add_new_record('" . $this->record->getXref() . "','NOTE');\">", I18N::translate('Add a note'), '</a>';
+ echo '<a href="edit_interface.php?action=add&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref() . '&amp;fact=NOTE">', I18N::translate('Add a note'), '</a>';
echo '</td></tr>';
echo '<tr><td class="descriptionbox">';
echo I18N::translate('Shared note');
echo '</td><td class="optionbox">';
- echo "<a href=\"#\" onclick=\"return add_new_record('" . $this->record->getXref() . "','SHARED_NOTE');\">", I18N::translate('Add a shared note'), '</a>';
+ echo '<a href="edit_interface.php?action=add&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref() . '&amp;fact=SHARED_NOTE">', I18N::translate('Add a shared note'), '</a>';
echo '</td></tr>';
if ($this->record->getTree()->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($this->record->getTree())) {
@@ -169,7 +161,7 @@ class FamilyController extends GedcomRecordController {
echo '<tr><td class="descriptionbox">';
echo I18N::translate('Source');
echo '</td><td class="optionbox">';
- echo "<a href=\"#\" onclick=\"return add_new_record('" . $this->record->getXref() . "','SOUR');\">", I18N::translate('Add a source citation'), '</a>';
+ echo '<a href="edit_interface.php?action=add&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref() . '&amp;fact=SOUR">', I18N::translate('Add a source citation'), '</a>';
echo '</td></tr>';
}
}
diff --git a/app/Controller/GedcomRecordController.php b/app/Controller/GedcomRecordController.php
index 4efb0dadff..67e1440d1e 100644
--- a/app/Controller/GedcomRecordController.php
+++ b/app/Controller/GedcomRecordController.php
@@ -106,9 +106,7 @@ class GedcomRecordController extends PageController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-record-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-record-editraw'));
}
// delete
diff --git a/app/Controller/HourglassController.php b/app/Controller/HourglassController.php
index 27c6fa04ca..899439c3d0 100644
--- a/app/Controller/HourglassController.php
+++ b/app/Controller/HourglassController.php
@@ -43,29 +43,21 @@ class HourglassController extends ChartController {
/** @var string An arrow that points to the end of the line. */
private $right_arrow;
- /** @var bool Can the Javascript be loaded by the controller. */
- private $canLoadJS;
-
- const LINK = "<a class='%s' href='%s' data-parms='%s-%s-%s'></a>";
- const SWITCH_LINK = "<a href='hourglass.php?rootid=%s&amp;show_spouse=%s&amp;show_full=%s&amp;generations=%s' class='name1'>%s</a>";
+ const LINK = "<a class='%s' href='%s' data-parms='%s-%s'></a>";
+ const SWITCH_LINK = "<a href='hourglass.php?rootid=%s&amp;show_spouse=%s&amp;generations=%s' class='name1'>%s</a>";
/**
* Create the hourglass controller.
*
* @param string $rootid
- * @param bool $show_full
- * @param bool $loadJS
*/
- public function __construct($rootid = '', $show_full = true, $loadJS = true) {
-
+ public function __construct($rootid = '') {
parent::__construct();
// Extract parameters from
$this->show_spouse = Filter::getInteger('show_spouse', 0, 1, 0);
$this->generations = Filter::getInteger('generations', 2, $this->tree()->getPreference('MAX_DESCENDANCY_GENERATIONS'), 3);
- $this->canLoadJS = $loadJS;
-
//-- flip the arrows for RTL languages
if (I18N::direction() === 'ltr') {
$this->left_arrow = 'icon-larrow';
@@ -123,7 +115,7 @@ class HourglassController extends ChartController {
echo '<td><img class="line4" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3"></td>';
echo '<td>';
//-- print the father box
- FunctionsPrint::printPedigreePerson($family->getHusband(), $this->showFull());
+ FunctionsPrint::printPedigreePerson($family->getHusband());
echo '</td>';
if ($family->getHusband()) {
$ARID = $family->getHusband()->getXref();
@@ -131,7 +123,7 @@ class HourglassController extends ChartController {
//-- print an Ajax arrow on the last generation of the adult male
if ($count == $this->generations - 1 && $family->getHusband()->getChildFamilies()) {
- printf(self::LINK, $this->right_arrow, $ARID, 'asc', $this->showFull(), $this->show_spouse);
+ printf(self::LINK, $this->right_arrow, $ARID, 'asc', $this->show_spouse);
}
//-- recursively get the father’s family
$this->printPersonPedigree($family->getHusband(), $count + 1);
@@ -155,7 +147,7 @@ class HourglassController extends ChartController {
'<td><img class="line4" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3"></td>',
'<td>';
//-- print the mother box
- FunctionsPrint::printPedigreePerson($family->getWife(), $this->showFull());
+ FunctionsPrint::printPedigreePerson($family->getWife());
echo '</td>';
if ($family->getWife()) {
$ARID = $family->getWife()->getXref();
@@ -163,7 +155,7 @@ class HourglassController extends ChartController {
//-- print an ajax arrow on the last generation of the adult female
if ($count == $this->generations - 1 && $family->getWife()->getChildFamilies()) {
- printf(self::LINK, $this->right_arrow, $ARID, 'asc', $this->showFull(), $this->show_spouse);
+ printf(self::LINK, $this->right_arrow, $ARID, 'asc', $this->show_spouse);
}
//-- recursively print the mother’s family
$this->printPersonPedigree($family->getWife(), $count + 1);
@@ -181,7 +173,7 @@ class HourglassController extends ChartController {
*/
private function printEmptyBox() {
- return $this->showFull() ? Theme::theme()->individualBoxEmpty() : Theme::theme()->individualBoxSmallEmpty();
+ return Theme::theme()->individualBoxEmpty();
}
/**
@@ -277,7 +269,7 @@ class HourglassController extends ChartController {
if ($kcount == 0) {
echo "</td><td style='width:", $this->getBoxDimensions()->width, "px'>";
} else {
- printf(self::LINK, $this->left_arrow, $pid, 'desc', $this->showFull(), $this->show_spouse);
+ printf(self::LINK, $this->left_arrow, $pid, 'desc', $this->show_spouse);
//-- move the arrow up to line up with the correct box
if ($this->show_spouse) {
echo str_repeat('<br><br><br>', count($families));
@@ -287,14 +279,14 @@ class HourglassController extends ChartController {
}
echo '<table id="table2_' . $pid . '"><tr><td>';
- FunctionsPrint::printPedigreePerson($person, $this->showFull());
+ FunctionsPrint::printPedigreePerson($person);
echo '</td><td><img class="line2" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3">';
//----- Print the spouse
if ($this->show_spouse) {
foreach ($families as $family) {
echo "</td></tr><tr><td style='text-align:$otablealign'>";
- FunctionsPrint::printPedigreePerson($family->getSpouse($person), $this->showFull());
+ FunctionsPrint::printPedigreePerson($family->getSpouse($person));
$numkids++;
echo '</td><td></td>';
}
@@ -326,10 +318,10 @@ class HourglassController extends ChartController {
echo "<span class='name1'>" . I18N::translate('Family') . '</span>';
$spouse = $family->getSpouse($person);
if ($spouse) {
- printf(self::SWITCH_LINK, $spouse->getXref(), $this->show_spouse, $this->showFull(), $this->generations, $spouse->getFullName());
+ printf(self::SWITCH_LINK, $spouse->getXref(), $this->show_spouse, $this->generations, $spouse->getFullName());
}
foreach ($family->getChildren() as $child) {
- printf(self::SWITCH_LINK, $child->getXref(), $this->show_spouse, $this->showFull(), $this->generations, $child->getFullName());
+ printf(self::SWITCH_LINK, $child->getXref(), $this->show_spouse, $this->generations, $child->getFullName());
}
}
@@ -339,11 +331,11 @@ class HourglassController extends ChartController {
echo "<span class='name1'>" . I18N::translate('Parents') . '</span>';
$husb = $family->getHusband();
if ($husb) {
- printf(self::SWITCH_LINK, $husb->getXref(), $this->show_spouse, $this->showFull(), $this->generations, $husb->getFullName());
+ printf(self::SWITCH_LINK, $husb->getXref(), $this->show_spouse, $this->generations, $husb->getFullName());
}
$wife = $family->getWife();
if ($wife) {
- printf(self::SWITCH_LINK, $wife->getXref(), $this->show_spouse, $this->showFull(), $this->generations, $wife->getFullName());
+ printf(self::SWITCH_LINK, $wife->getXref(), $this->show_spouse, $this->generations, $wife->getFullName());
}
}
@@ -357,7 +349,7 @@ class HourglassController extends ChartController {
echo $num > 1 ? I18N::translate('Siblings') : I18N::translate('Sibling');
echo '</span>';
foreach ($siblings as $child) {
- printf(self::SWITCH_LINK, $child->getXref(), $this->show_spouse, $this->showFull(), $this->generations, $child->getFullName());
+ printf(self::SWITCH_LINK, $child->getXref(), $this->show_spouse, $this->generations, $child->getFullName());
}
}
}
@@ -407,10 +399,12 @@ class HourglassController extends ChartController {
/**
* setup all of the javascript that is needed for the hourglass chart
+ *
+ * @return string
*/
public function setupJavascript() {
- $js = "
- var WT_HOURGLASS_CHART = (function() {
+ return "
+ (function() {
function sizeLines() {
$('.tvertline').each(function(i,e) {
var pid = e.id.split('_').pop();
@@ -438,7 +432,7 @@ class HourglassController extends ChartController {
var self = $(this),
parms = self.data('parms').split('-'),
id = self.attr('href');
- jQuery('#td_'+id).load('hourglass_ajax.php?rootid='+ id +'&generations=1&type='+parms[0]+'&show_full='+(parseInt(parms[1]) ? 1:0) +'&show_spouse='+(parseInt(parms[2]) ? 1:0), function(){
+ $('#td_'+id).load('hourglass_ajax.php?rootid='+ id +'&generations=1&type='+parms[0]+'&show_spouse='+(parseInt(parms[1]) ? 1:0), function(){
sizeLines();
});
});
@@ -446,11 +440,5 @@ class HourglassController extends ChartController {
sizeLines();
})();
";
-
- if ($this->canLoadJS) {
- $this->addInlineJavascript($js);
- } else {
- return $js;
- }
}
}
diff --git a/app/Controller/IndividualController.php b/app/Controller/IndividualController.php
index 5c883040f4..37f58bd217 100644
--- a/app/Controller/IndividualController.php
+++ b/app/Controller/IndividualController.php
@@ -16,10 +16,10 @@
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Auth;
-use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeName;
@@ -28,7 +28,7 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
use Fisharebest\Webtrees\Module;
-use Fisharebest\Webtrees\User;
+use Fisharebest\Webtrees\Module\ModuleTabInterface;
/**
* Controller for the individual page
@@ -40,9 +40,6 @@ class IndividualController extends GedcomRecordController {
/** @var int Count of names. */
public $total_names = 0;
- /** ModuleTabInterface[] List of tabs to show */
- public $tabs;
-
/**
* Startup activity
*
@@ -54,7 +51,6 @@ class IndividualController extends GedcomRecordController {
// If we can display the details, add them to the page header
if ($this->record && $this->record->canShow()) {
$this->setPageTitle($this->record->getFullName() . ' ' . $this->record->getLifeSpan());
- $this->tabs = Module::getActiveTabs($this->record->getTree());
}
}
@@ -92,176 +88,177 @@ class IndividualController extends GedcomRecordController {
}
/**
+ * Which tabs should we show on this individual's page.
+ * We don't show empty tabs.
+ *
+ * @return ModuleTabInterface[]
+ */
+ public function getTabs() {
+ $active_tabs = Module::getActiveTabs($this->record->getTree());
+
+ return array_filter($active_tabs, function(ModuleTabInterface $tab) { return $tab->hasTabContent(); });
+ }
+
+ /**
* Handle AJAX requests - to generate the tab content
*/
public function ajaxRequest() {
- // Search engines should not make AJAX requests
- if (Auth::isSearchEngine()) {
- http_response_code(403);
- exit;
- }
+ header('Content-Type: text/html; charset=UTF-8');
- // Initialise tabs
- $tab = Filter::get('module');
+ $tab = Filter::get('module');
+ $tabs = $this->getTabs();
- // A request for a non-existant tab?
- if (array_key_exists($tab, $this->tabs)) {
- $mod = $this->tabs[$tab];
- } else {
+ if (!array_key_exists($tab, $tabs)) {
http_response_code(404);
- exit;
- }
-
- header('Content-Type: text/html; charset=UTF-8'); // AJAX calls do not have the meta tag headers and need this set
- header('X-Robots-Tag: noindex,follow'); // AJAX pages should not show up in search results, any links can be followed though
-
- echo $mod->getTabContent();
-
- if (WT_DEBUG_SQL) {
- echo Database::getQueryLog();
+ } else {
+ echo $tabs[$tab]->getTabContent();
}
}
/**
- * print information for a name record
+ * Format a name record
+ *
+ * @param int $primary
+ * @param Fact $fact
*
- * @param Fact $event the event object
+ * @return string
*/
- public function printNameRecord(Fact $event) {
- $factrec = $event->getGedcom();
+ public function formatNameRecord($n, Fact $fact) {
+ $individual = $fact->getParent();
- // Create a dummy record, so we can extract the formatted NAME value from the event.
+ // Create a dummy record, so we can extract the formatted NAME value from it.
$dummy = new Individual(
'xref',
- "0 @xref@ INDI\n1 DEAT Y\n" . $factrec,
+ "0 @xref@ INDI\n1 DEAT Y\n" . $fact->getGedcom(),
null,
- $event->getParent()->getTree()
+ $individual->getTree()
);
- $all_names = $dummy->getAllNames();
- $primary_name = $all_names[0];
+ $dummy->setPrimaryName(0); // Make sure we use the name from "1 NAME"
+
+ $container_class = 'card';
+ $content_class = 'collapse';
+ $aria = 'false';
- $this->name_count++;
- if ($this->name_count > 1) { echo '<h3 class="name_two">', $dummy->getFullName(), '</h3>'; } // Other names accordion element
- echo '<div class="indi_name_details';
- if ($event->isPendingDeletion()) {
- echo ' old';
+ if ($n === 0) {
+ $content_class = 'collapse show';
+ $aria = 'true';
}
- if ($event->isPendingAddition()) {
- echo ' new';
+ if ($fact->isPendingDeletion()) {
+ $container_class .= ' old';
+ } elseif ($fact->isPendingAddition()) {
+ $container_class .= ' new';
}
- echo '">';
- echo '<div class="name1">';
+ ob_start();
echo '<dl><dt class="label">', I18N::translate('Name'), '</dt>';
- $dummy->setPrimaryName(0);
- echo '<dd class="field">', $dummy->getFullName();
- if ($this->name_count == 1) {
- if (Auth::isAdmin()) {
- $user = User::findByGenealogyRecord($this->record);
- if ($user) {
- echo '<span> - <a class="warning" href="admin_users.php?filter=' . Filter::escapeHtml($user->getUserName()) . '">' . Filter::escapeHtml($user->getUserName()) . '</a></span>';
- }
- }
- }
- if ($this->record->canEdit() && !$event->isPendingDeletion()) {
- echo "<div class=\"deletelink noprint\"><a class=\"deleteicon\" href=\"#\" onclick=\"return delete_fact('" . I18N::translate('Are you sure you want to delete this fact?') . "', '" . $this->record->getXref() . "', '" . $event->getFactId() . "');\" title=\"" . I18N::translate('Delete this name') . '"><span class="link_text">' . I18N::translate('Delete this name') . '</span></a></div>';
- echo "<div class=\"editlink noprint\"><a href=\"#\" class=\"editicon\" onclick=\"edit_name('" . $this->record->getXref() . "', '" . $event->getFactId() . "'); return false;\" title=\"" . I18N::translate('Edit the name') . '"><span class="link_text">' . I18N::translate('Edit the name') . '</span></a></div>';
- }
- echo '</dd>';
- echo '</dl>';
- echo '</div>';
- $ct = preg_match_all('/\n2 (\w+) (.*)/', $factrec, $nmatch, PREG_SET_ORDER);
+ echo '<dd class="field">', $dummy->getFullName(), '</dd>';
+ $ct = preg_match_all('/\n2 (\w+) (.*)/', $fact->getGedcom(), $nmatch, PREG_SET_ORDER);
for ($i = 0; $i < $ct; $i++) {
- echo '<div>';
- $fact = $nmatch[$i][1];
- if ($fact != 'SOUR' && $fact != 'NOTE' && $fact != 'SPFX') {
- echo '<dl><dt class="label">', GedcomTag::getLabel($fact, $this->record), '</dt>';
- echo '<dd class="field">'; // Before using dir="auto" on this field, note that Gecko treats this as an inline element but WebKit treats it as a block element
- if (isset($nmatch[$i][2])) {
- $name = Filter::escapeHtml($nmatch[$i][2]);
- $name = str_replace('/', '', $name);
- $name = preg_replace('/(\S*)\*/', '<span class="starredname">\\1</span>', $name);
- switch ($fact) {
- case 'TYPE':
- echo GedcomCodeName::getValue($name, $this->record);
- break;
- case 'SURN':
- // The SURN field is not necessarily the surname.
- // Where it is not a substring of the real surname, show it after the real surname.
- $surname = Filter::escapeHtml($primary_name['surname']);
- if (strpos($primary_name['surname'], str_replace(',', ' ', $nmatch[$i][2])) !== false) {
- echo '<span dir="auto">' . $surname . '</span>';
- } else {
- echo I18N::translate('%1$s (%2$s)', '<span dir="auto">' . $surname . '</span>', '<span dir="auto">' . $name . '</span>');
- }
- break;
- default:
- echo '<span dir="auto">' . $name . '</span>';
- break;
- }
+ $tag = $nmatch[$i][1];
+ if ($tag != 'SOUR' && $tag != 'NOTE' && $tag != 'SPFX') {
+ echo '<dt class="label">', GedcomTag::getLabel($tag, $this->record), '</dt>';
+ echo '<dd class="field">'; // Before using dir="auto" on this field, note that Gecko treats this as an inline element but WebKit treats it as a block element
+ if (isset($nmatch[$i][2])) {
+ $name = Filter::escapeHtml($nmatch[$i][2]);
+ $name = str_replace('/', '', $name);
+ $name = preg_replace('/(\S*)\*/', '<span class="starredname">\\1</span>', $name);
+ switch ($tag) {
+ case 'TYPE':
+ echo GedcomCodeName::getValue($name, $this->record);
+ break;
+ case 'SURN':
+ // The SURN field is not necessarily the surname.
+ // Where it is not a substring of the real surname, show it after the real surname.
+ $surname = Filter::escapeHtml($dummy->getAllNames()[0]['surname']);
+ if (strpos($dummy->getAllNames()[0]['surname'], str_replace(',', ' ', $nmatch[$i][2])) !== false) {
+ echo '<span dir="auto">' . $surname . '</span>';
+ } else {
+ echo I18N::translate('%1$s (%2$s)', '<span dir="auto">' . $surname . '</span>', '<span dir="auto">' . $name . '</span>');
}
- echo '</dd>';
- echo '</dl>';
+ break;
+ default:
+ echo '<span dir="auto">' . $name . '</span>';
+ break;
+ }
}
- echo '</div>';
+ echo '</dd>';
+ echo '</dl>';
+ }
+ }
+ if (preg_match("/\n2 SOUR/", $fact->getGedcom())) {
+ echo '<div id="indi_sour" class="clearfloat">', FunctionsPrintFacts::printFactSources($fact->getGedcom(), 2), '</div>';
}
- if (preg_match("/\n2 SOUR/", $factrec)) {
- echo '<div id="indi_sour" class="clearfloat">', FunctionsPrintFacts::printFactSources($factrec, 2), '</div>';
+ if (preg_match("/\n2 NOTE/", $fact->getGedcom())) {
+ echo '<div id="indi_note" class="clearfloat">', FunctionsPrint::printFactNotes($fact->getGedcom(), 2), '</div>';
}
- if (preg_match("/\n2 NOTE/", $factrec)) {
- echo '<div id="indi_note" class="clearfloat">', FunctionsPrint::printFactNotes($factrec, 2), '</div>';
+ $content = ob_get_clean();
+
+ if ($this->record->canEdit() && !$fact->isPendingDeletion()) {
+ $edit_links =
+ FontAwesome::linkIcon('delete', I18N::translate('Delete this name'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $this->record->getXref() . '", "' . $fact->getFactId() . '");']) .
+ FontAwesome::linkIcon('edit', I18N::translate('Edit the name'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=editname&xref=' . $this->record->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $this->record->getTree()->getNameHtml()]);
+ } else {
+ $edit_links = '';
}
- echo '</div>';
+
+ return '
+ <div class="' . $container_class . '">
+ <div class="card-header" role="tab" id="name-header-' . $n . '">
+ <a data-toggle="collapse" data-parent="#individual-names" href="#name-content-' . $n . '" aria-expanded="' . $aria . '" aria-controls="name-content-' . $n . '">' . $dummy->getFullName() . '</a>
+ ' . $edit_links . '
+ </div>
+ <div id="name-content-' . $n . '" class="' . $content_class . '" role="tabpanel" aria-labelledby="name-header-' . $n . '">
+ <div class="card-block">' . $content . '</div>
+ </div>
+ </div>';
}
/**
* print information for a sex record
*
* @param Fact $event the Event object
+ *
+ * @return string
*/
- public function printSexRecord(Fact $event) {
- $sex = $event->getValue();
- if (empty($sex)) {
- $sex = 'U';
- }
- echo '<span id="sex" class="';
- if ($event->isPendingDeletion()) {
- echo 'old ';
- }
- if ($event->isPendingAddition()) {
- echo 'new ';
- }
- switch ($sex) {
+ public function formatSexRecord(Fact $fact) {
+ $individual = $fact->getParent();
+
+ switch ($fact->getValue()) {
case 'M':
- echo 'male_gender"';
- if ($event->canEdit()) {
- echo ' title="', I18N::translate('Male'), ' - ', I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
- } else {
- echo ' title="', I18N::translate('Male'), '">';
- }
+ $sex = I18N::translate('Male');
break;
case 'F':
- echo 'female_gender"';
- if ($event->canEdit()) {
- echo ' title="', I18N::translate('Female'), ' - ', I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
- } else {
- echo ' title="', I18N::translate('Female'), '">';
- }
+ $sex = I18N::translate('Female');
break;
default:
- echo 'unknown_gender"';
- if ($event->canEdit()) {
- echo ' title="', I18N::translateContext('unknown gender', 'Unknown'), ' - ', I18N::translate('Edit'), '"';
- echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
- } else {
- echo ' title="', I18N::translateContext('unknown gender', 'Unknown'), '">';
- }
+ $sex = I18N::translateContext('unknown gender', 'Unknown');
break;
}
- echo '</span>';
+
+ $container_class = 'card';
+ if ($fact->isPendingDeletion()) {
+ $container_class .= ' old';
+ } elseif ($fact->isPendingAddition()) {
+ $container_class .= ' new';
+ }
+
+ if ($individual->canEdit() && !$fact->isPendingDeletion()) {
+ $edit_links = FontAwesome::linkIcon('edit', I18N::translate('Edit the gender'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=edit&xref=' . $individual->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $individual->getTree()->getNameHtml() ]);
+
+ } else {
+ $edit_links = '';
+ }
+
+ return '
+ <div class="' . $container_class . '">
+ <div class="card-header" role="tab" id="name-header-add">
+ <div class="card-title mb-0">
+ <b>' . I18N::translate('Gender') . '</b> ' . $sex . $edit_links . '
+ </div>
+ </div>
+ </div>';
}
+
/**
* get edit menu
*/
@@ -273,30 +270,20 @@ class IndividualController extends GedcomRecordController {
$menu = new Menu(I18N::translate('Edit'), '#', 'menu-indi');
if (Auth::isEditor($this->record->getTree())) {
- $menu->addSubmenu(new Menu(I18N::translate('Add a name'), '#', 'menu-indi-addname', [
- 'onclick' => 'return add_name("' . $this->record->getXref() . '");',
- ]));
-
$has_sex_record = false;
foreach ($this->record->getFacts() as $fact) {
if ($fact->getTag() === 'SEX' && $fact->canEdit()) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), '#', 'menu-indi-editsex', [
- 'onclick' => 'return edit_record("' . $this->record->getXref() . '", "' . $fact->getFactId() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), 'edit_interface.php?action=edit&amp;xref=' . $this->record->getXref() . '&amp;fact_id=' . $fact->getFactId() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-indi-editsex'));
$has_sex_record = true;
break;
}
}
if (!$has_sex_record) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), '#', 'menu-indi-editsex', [
- 'onclick' => 'return add_new_record("' . $this->record->getXref() . '", "SEX");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), 'edit_interface.php?action=add&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref() . '&amp;fact=SEX', 'menu-indi-editsex'));
}
if (count($this->record->getSpouseFamilies()) > 1) {
- $menu->addSubmenu(new Menu(I18N::translate('Re-order families'), '#', 'menu-indi-orderfam', [
- 'onclick' => 'return reorder_families("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Re-order families'), 'edit_interface.php?action=reorder_fams&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-indi-orderfam'));
}
// delete
@@ -307,9 +294,7 @@ class IndividualController extends GedcomRecordController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-indi-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-indi-editraw'));
}
return $menu;
@@ -365,34 +350,27 @@ class IndividualController extends GedcomRecordController {
* @return string
*/
public function getSideBarContent() {
- global $controller;
-
- $html = '';
- $active = 0;
- $n = 0;
- foreach (Module::getActiveSidebars($this->record->getTree()) as $mod) {
- if ($mod->hasSidebarContent()) {
- $html .= '<h3 id="' . $mod->getName() . '"><a href="#">' . $mod->getTitle() . '</a></h3>';
- $html .= '<div id="sb_content_' . $mod->getName() . '">' . $mod->getSidebarContent() . '</div>';
- // The family navigator should be opened by default
- if ($mod->getName() == 'family_nav') {
- $active = $n;
- }
- ++$n;
+ $html = '';
+ foreach (Module::getActiveSidebars($this->record->getTree()) as $module) {
+ if ($module->hasSidebarContent()) {
+ $class = $module->getName() === 'family_nav' ? 'collapse show' : 'collapse';
+ $aria = $module->getName() === 'family_nav' ? 'true' : 'false';
+ $html .= '
+ <div class="card">
+ <div class="card-header" role="tab" id="sidebar-header-' . $module->getName() . '">
+ <div class="card-title mb-0">
+ <a data-toggle="collapse" data-parent="#sidebar" href="#sidebar-content-' . $module->getName() . '" aria-expanded="' . $aria . '" aria-controls="sidebar-content-' . $module->getName() . '">' . $module->getTitle() . '</a>
+ </div>
+ </div>
+ <div id="sidebar-content-' . $module->getName() . '" class="' . $class . '" role="tabpanel" aria-labelledby="sidebar-header-' . $module->getName() . '">
+ <div class="card-block">' . $module->getSidebarContent() . '</div>
+ </div>
+ </div>';
}
}
if ($html) {
- $controller
- ->addInlineJavascript('
- jQuery("#sidebarAccordion").accordion({
- active:' . $active . ',
- heightStyle: "content",
- collapsible: true,
- });
- ');
-
- return '<div id="sidebar"><div id="sidebarAccordion">' . $html . '</div></div>';
+ return '<div id="sidebar" role="tablist">' . $html . '</div>';
} else {
return '';
}
diff --git a/app/Controller/IndividualListController.php b/app/Controller/IndividualListController.php
new file mode 100644
index 0000000000..854aba88aa
--- /dev/null
+++ b/app/Controller/IndividualListController.php
@@ -0,0 +1,569 @@
+<?php
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2017 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+namespace Fisharebest\Webtrees\Controller;
+
+use Fisharebest\Webtrees\Database;
+use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Individual;
+
+/**
+ * Controller for the individual list
+ */
+class IndividualListController extends PageController {
+ /**
+ * Get a list of initial letters, for lists of names.
+ *
+ * @param string $locale Return the alphabet for this locale
+ *
+ * @return string[]
+ */
+ private function getAlphabetForLocale($locale) {
+ switch ($locale) {
+ case 'ar':
+ return [
+ 'ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی',
+ ];
+ case 'cs':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'CH', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ];
+ case 'da':
+ case 'nb':
+ case 'nn':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Æ', 'Ø', 'Å',
+ ];
+ case 'el':
+ return [
+ 'Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω',
+ ];
+ case 'es':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'Ñ', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ];
+ case 'et':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'Z', 'Ž', 'T', 'U', 'V', 'W', 'Õ', 'Ä', 'Ö', 'Ü', 'X', 'Y',
+ ];
+ case 'fi':
+ case 'sv':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Å', 'Ä', 'Ö',
+ ];
+ case 'he':
+ return [
+ 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק', 'ר', 'ש', 'ת',
+ ];
+ case 'hu':
+ return [
+ 'A', 'B', 'C', 'CS', 'D', 'DZ', 'DZS', 'E', 'F', 'G', 'GY', 'H', 'I', 'J', 'K', 'L', 'LY', 'M', 'N', 'NY', 'O', 'Ö', 'P', 'Q', 'R', 'S', 'SZ', 'T', 'TY', 'U', 'Ü', 'V', 'W', 'X', 'Y', 'Z', 'ZS',
+ ];
+ case 'lt':
+ return [
+ 'A', 'Ą', 'B', 'C', 'Č', 'D', 'E', 'Ę', 'Ė', 'F', 'G', 'H', 'I', 'Y', 'Į', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'Š', 'T', 'U', 'Ų', 'Ū', 'V', 'Z', 'Ž',
+ ];
+ case 'nl':
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'IJ',
+ ];
+ case 'pl':
+ return [
+ 'A', 'B', 'C', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Ł', 'M', 'N', 'O', 'Ó', 'P', 'Q', 'R', 'S', 'Ś', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ź', 'Ż',
+ ];
+ case 'ro':
+ return [
+ 'A', 'Ă', 'Â', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'Î', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Ş', 'T', 'Ţ', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ];
+ case 'ru':
+ return [
+ 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я',
+ ];
+ case 'sk':
+ return [
+ 'A', 'Á', 'Ä', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'F', 'G', 'H', 'I', 'Í', 'J', 'K', 'L', 'Ľ', 'Ĺ', 'M', 'N', 'Ň', 'O', 'Ó', 'Ô', 'P', 'Q', 'R', 'Ŕ', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž',
+ ];
+ case 'sl':
+ return [
+ 'A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž',
+ ];
+ case 'sr':
+ return [
+ 'A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž',
+ ];
+ case 'tr':
+ return [
+ 'A', 'B', 'C', 'Ç', 'D', 'E', 'F', 'G', 'Ğ', 'H', 'I', 'İ', 'J', 'K', 'L', 'M', 'N', 'O', 'Ö', 'P', 'R', 'S', 'Ş', 'T', 'U', 'Ü', 'V', 'Y', 'Z',
+ ];
+ default:
+ return [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ];
+ }
+ }
+
+ /**
+ * Get the initial letter of a name, taking care of multi-letter sequences and equivalences.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function initialLetter($name) {
+ $name = I18N::strtoupper($name);
+ switch (WT_LOCALE) {
+ case 'cs':
+ if (substr($name, 0, 2) == 'CH') {
+ return 'CH';
+ }
+ break;
+ case 'da':
+ case 'nb':
+ case 'nn':
+ if (substr($name, 0, 2) == 'AA') {
+ return 'Å';
+ }
+ break;
+ case 'hu':
+ if (substr($name, 0, 2) == 'CS') {
+ return 'CS';
+ } elseif (substr($name, 0, 3) == 'DZS') {
+ return 'DZS';
+ } elseif (substr($name, 0, 2) == 'DZ') {
+ return 'DZ';
+ } elseif (substr($name, 0, 2) == 'GY') {
+ return 'GY';
+ } elseif (substr($name, 0, 2) == 'LY') {
+ return 'LY';
+ } elseif (substr($name, 0, 2) == 'NY') {
+ return 'NY';
+ } elseif (substr($name, 0, 2) == 'SZ') {
+ return 'SZ';
+ } elseif (substr($name, 0, 2) == 'TY') {
+ return 'TY';
+ } elseif (substr($name, 0, 2) == 'ZS') {
+ return 'ZS';
+ }
+ break;
+ case 'nl':
+ if (substr($name, 0, 2) == 'IJ') {
+ return 'IJ';
+ }
+ break;
+ }
+ // No special rules - just take the first character
+ return mb_substr($name, 0, 1);
+ }
+
+ /**
+ * Generate SQL to match a given letter, taking care of cases that
+ * are not covered by the collation setting.
+ *
+ * We must consider:
+ * potential substrings, such as Czech "CH" and "C"
+ * equivalent letters, such as Danish "AA" and "Å"
+ *
+ * We COULD write something that handles all languages generically,
+ * but its performance would most likely be poor.
+ *
+ * For languages that don't appear in this list, we could write
+ * simpler versions of the surnameAlpha() and givenAlpha() functions,
+ * but it gives no noticable improvement in performance.
+ *
+ * @param string $field
+ * @param string $letter
+ *
+ * @return string
+ */
+ private function getInitialSql($field, $letter) {
+ switch (WT_LOCALE) {
+ case 'cs':
+ switch ($letter) {
+ case 'C': return $field . " LIKE 'C%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'CH%' COLLATE " . I18N::collation();
+ }
+ break;
+ case 'da':
+ case 'nb':
+ case 'nn':
+ switch ($letter) {
+ // AA gets listed under Å
+ case 'A': return $field . " LIKE 'A%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'AA%' COLLATE " . I18N::collation();
+ case 'Å': return "(" . $field . " LIKE 'Å%' COLLATE " . I18N::collation() . " OR " . $field . " LIKE 'AA%' COLLATE " . I18N::collation() . ")";
+ }
+ break;
+ case 'hu':
+ switch ($letter) {
+ case 'C': return $field . " LIKE 'C%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'CS%' COLLATE " . I18N::collation();
+ case 'D': return $field . " LIKE 'D%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'DZ%' COLLATE " . I18N::collation();
+ case 'DZ': return $field . " LIKE 'DZ%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'DZS%' COLLATE " . I18N::collation();
+ case 'G': return $field . " LIKE 'G%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'GY%' COLLATE " . I18N::collation();
+ case 'L': return $field . " LIKE 'L%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'LY%' COLLATE " . I18N::collation();
+ case 'N': return $field . " LIKE 'N%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'NY%' COLLATE " . I18N::collation();
+ case 'S': return $field . " LIKE 'S%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'SZ%' COLLATE " . I18N::collation();
+ case 'T': return $field . " LIKE 'T%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'TY%' COLLATE " . I18N::collation();
+ case 'Z': return $field . " LIKE 'Z%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'ZS%' COLLATE " . I18N::collation();
+ }
+ break;
+ case 'nl':
+ switch ($letter) {
+ case 'I': return $field . " LIKE 'I%' COLLATE " . I18N::collation() . " AND " . $field . " NOT LIKE 'IJ%' COLLATE " . I18N::collation();
+ }
+ break;
+ }
+
+ // Easy cases: the MySQL collation rules take care of it
+ return "$field LIKE CONCAT('@'," . Database::quote($letter) . ",'%') COLLATE " . I18N::collation() . " ESCAPE '@'";
+ }
+
+ /**
+ * Get a list of initial surname letters for indilist.php and famlist.php
+ *
+ * @param bool $marnm if set, include married names
+ * @param bool $fams if set, only consider individuals with FAMS records
+ * @param bool $totals if set, count the number of names beginning with each letter
+ *
+ * @return int[]
+ */
+ public function surnameAlpha($marnm, $fams, $totals = true) {
+ $alphas = [];
+
+ $sql =
+ "SELECT SQL_CACHE COUNT(n_id)" .
+ " FROM `##name` " .
+ ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") .
+ " WHERE n_file=" . $this->tree()->getTreeId() .
+ ($marnm ? "" : " AND n_type!='_MARNM'");
+
+ // Fetch all the letters in our alphabet, whether or not there
+ // are any names beginning with that letter. It looks better to
+ // show the full alphabet, rather than omitting rare letters such as X
+ foreach ($this->getAlphabetForLocale(WT_LOCALE) as $letter) {
+ $count = 1;
+ if ($totals) {
+ $count = Database::prepare($sql . " AND " . $this->getInitialSql('n_surn', $letter))->fetchOne();
+ }
+ $alphas[$letter] = $count;
+ }
+
+ // Now fetch initial letters that are not in our alphabet,
+ // including "@" (for "@N.N.") and "" for no surname.
+ $sql =
+ "SELECT SQL_CACHE initial, count FROM (SELECT UPPER(LEFT(n_surn, 1)) AS initial, COUNT(n_id) AS count" .
+ " FROM `##name` " .
+ ($fams ? " JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") .
+ " WHERE n_file = :tree_id AND n_surn <> ''" .
+ ($marnm ? "" : " AND n_type != '_MARNM'");
+
+ $args = [
+ 'tree_id' => $this->tree()->getTreeId(),
+ ];
+
+ foreach ($this->getAlphabetForLocale(WT_LOCALE) as $n => $letter) {
+ $sql .= " AND n_surn COLLATE :collate_" . $n . " NOT LIKE :letter_" . $n;
+ $args['collate_' . $n] = I18N::collation();
+ $args['letter_' . $n] = $letter . '%';
+ }
+ $sql .= " GROUP BY UPPER(LEFT(n_surn, 1))) AS subquery ORDER BY initial = '', initial = '@', initial";
+ foreach (Database::prepare($sql)->execute($args)->fetchAssoc() as $alpha => $count) {
+ $alphas[$alpha] = $count;
+ }
+
+ // Names with no surname
+ $sql =
+ "SELECT SQL_CACHE COUNT(n_id)" .
+ " FROM `##name` " .
+ ($fams ? " JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") .
+ " WHERE n_file = :tree_id AND n_surn = ''" .
+ ($marnm ? "" : " AND n_type != '_MARNM'");
+
+ $args = [
+ 'tree_id' => $this->tree()->getTreeId(),
+ ];
+
+ $count_no_surname = (int) Database::prepare($sql)->execute($args)->fetchOne();
+ if ($count_no_surname !== 0) {
+ // Special code to indicate "no surname"
+ $alphas[','] = $count_no_surname;
+ }
+
+ return $alphas;
+ }
+
+ /**
+ * Get a list of initial given name letters for indilist.php and famlist.php
+ *
+ * @param string $surn if set, only consider people with this surname
+ * @param string $salpha if set, only consider surnames starting with this letter
+ * @param bool $marnm if set, include married names
+ * @param bool $fams if set, only consider individuals with FAMS records
+ *
+ * @return int[]
+ */
+ public function givenAlpha($surn, $salpha, $marnm, $fams) {
+ $alphas = [];
+
+ $sql =
+ "SELECT SQL_CACHE COUNT(DISTINCT n_id)" .
+ " FROM `##name`" .
+ ($fams ? " JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : "") .
+ " WHERE n_file=" . $this->tree()->getTreeId() . " " .
+ ($marnm ? "" : " AND n_type!='_MARNM'");
+
+ if ($surn) {
+ $sql .= " AND n_surn=" . Database::quote($surn) . " COLLATE '" . I18N::collation() . "'";
+ } elseif ($salpha == ',') {
+ $sql .= " AND n_surn=''";
+ } elseif ($salpha == '@') {
+ $sql .= " AND n_surn='@N.N.'";
+ } elseif ($salpha) {
+ $sql .= " AND " . $this->getInitialSql('n_surn', $salpha);
+ } else {
+ // All surnames
+ $sql .= " AND n_surn NOT IN ('', '@N.N.')";
+ }
+
+ // Fetch all the letters in our alphabet, whether or not there
+ // are any names beginning with that letter. It looks better to
+ // show the full alphabet, rather than omitting rare letters such as X
+ foreach ($this->getAlphabetForLocale(WT_LOCALE) as $letter) {
+ $count = Database::prepare($sql . " AND " . $this->getInitialSql('n_givn', $letter))->fetchOne();
+ $alphas[$letter] = $count;
+ }
+
+ // Now fetch initial letters that are not in our alphabet,
+ // including "@" (for "@N.N.") and "" for no surname
+ $sql =
+ "SELECT SQL_CACHE initial, total FROM (SELECT UPPER(LEFT(n_givn, 1)) AS initial, COUNT(DISTINCT n_id) AS total" .
+ " FROM `##name` " .
+ ($fams ? " JOIN `##link` ON (n_id = l_from AND n_file = l_file AND l_type = 'FAMS') " : "") .
+ " WHERE n_file = :tree_id" .
+ ($marnm ? "" : " AND n_type != '_MARNM'");
+
+ $args = [
+ 'tree_id' => $this->tree()->getTreeId(),
+ ];
+
+ if ($surn) {
+ $sql .= " AND n_surn COLLATE :collate_1 = :surn";
+ $args['collate_1'] = I18N::collation();
+ $args['surn'] = $surn;
+ } elseif ($salpha === ',') {
+ $sql .= " AND n_surn = ''";
+ } elseif ($salpha === '@') {
+ $sql .= " AND n_surn = '@N.N.'";
+ } elseif ($salpha) {
+ $sql .= " AND " . $this->getInitialSql('n_surn', $salpha);
+ } else {
+ // All surnames
+ $sql .= " AND n_surn NOT IN ('', '@N.N.')";
+ }
+
+ foreach ($this->getAlphabetForLocale(WT_LOCALE) as $letter) {
+ $sql .= " AND n_givn NOT LIKE '" . $letter . "%' COLLATE " . I18N::collation();
+ }
+ $sql .= " GROUP BY UPPER(LEFT(n_givn, 1))) AS subquery ORDER BY initial = '@', initial = '', initial";
+
+ foreach (Database::prepare($sql)->execute($args)->fetchAssoc() as $alpha => $count) {
+ $alphas[$alpha] = $count;
+ }
+
+ return $alphas;
+ }
+
+ /**
+ * Get a list of actual surnames and variants, based on a "root" surname.
+ *
+ * @param string $surn if set, only fetch people with this surname
+ * @param string $salpha if set, only consider surnames starting with this letter
+ * @param bool $marnm if set, include married names
+ * @param bool $fams if set, only consider individuals with FAMS records
+ *
+ * @return array
+ */
+ public function surnames($surn, $salpha, $marnm, $fams) {
+ $sql =
+ "SELECT SQL_CACHE n2.n_surn, n1.n_surname, n1.n_id" .
+ " FROM `##name` n1 " .
+ ($fams ? " JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") .
+ " JOIN (SELECT n_surn COLLATE :collate_0 AS n_surn, n_file FROM `##name`" .
+ " WHERE n_file = :tree_id" .
+ ($marnm ? "" : " AND n_type != '_MARNM'");
+
+ $args = [
+ 'tree_id' => $this->tree()->getTreeId(),
+ 'collate_0' => I18N::collation(),
+ ];
+
+ if ($surn) {
+ $sql .= " AND n_surn COLLATE :collate_1 = :surn";
+ $args['collate_1'] = I18N::collation();
+ $args['surn'] = $surn;
+ } elseif ($salpha === ',') {
+ $sql .= " AND n_surn = ''";
+ } elseif ($salpha === '@') {
+ $sql .= " AND n_surn = '@N.N.'";
+ } elseif ($salpha) {
+ $sql .= " AND " . $this->getInitialSql('n_surn', $salpha);
+ } else {
+ // All surnames
+ $sql .= " AND n_surn NOT IN ('', '@N.N.')";
+ }
+ $sql .= " GROUP BY n_surn COLLATE :collate_2, n_file) AS n2 ON (n1.n_surn = n2.n_surn COLLATE :collate_3 AND n1.n_file = n2.n_file)";
+ $args['collate_2'] = I18N::collation();
+ $args['collate_3'] = I18N::collation();
+
+ $list = [];
+ foreach (Database::prepare($sql)->execute($args)->fetchAll() as $row) {
+ $list[I18N::strtoupper($row->n_surn)][$row->n_surname][$row->n_id] = true;
+ }
+
+ return $list;
+ }
+
+ /**
+ * Fetch a list of individuals with specified names
+ *
+ * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@"
+ * To search for names with no surnames, use $salpha=","
+ *
+ * @param string $surn if set, only fetch people with this surname
+ * @param string $salpha if set, only fetch surnames starting with this letter
+ * @param string $galpha if set, only fetch given names starting with this letter
+ * @param bool $marnm if set, include married names
+ * @param bool $fams if set, only fetch individuals with FAMS records
+ *
+ * @return Individual[]
+ */
+ public function individuals($surn, $salpha, $galpha, $marnm, $fams) {
+ $sql =
+ "SELECT i_id AS xref, i_gedcom AS gedcom, n_full " .
+ "FROM `##individuals` " .
+ "JOIN `##name` ON n_id = i_id AND n_file = i_file " .
+ ($fams ? "JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") .
+ "WHERE n_file = :tree_id " .
+ ($marnm ? "" : "AND n_type != '_MARNM'");
+
+ $args = [
+ 'tree_id' => $this->tree()->getTreeId(),
+ ];
+
+ if ($surn) {
+ $sql .= " AND n_surn COLLATE :collate_1 = :surn";
+ $args['collate_1'] = I18N::collation();
+ $args['surn'] = $surn;
+ } elseif ($salpha === ',') {
+ $sql .= " AND n_surn = ''";
+ } elseif ($salpha === '@') {
+ $sql .= " AND n_surn = '@N.N.'";
+ } elseif ($salpha) {
+ $sql .= " AND " . $this->getInitialSql('n_surn', $salpha);
+ } else {
+ // All surnames
+ $sql .= " AND n_surn NOT IN ('', '@N.N.')";
+ }
+ if ($galpha) {
+ $sql .= " AND " . $this->getInitialSql('n_givn', $galpha);
+ }
+
+ $sql .= " ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE :collate_2, CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE :collate_3";
+ $args['collate_2'] = I18N::collation();
+ $args['collate_3'] = I18N::collation();
+
+ $list = [];
+ $rows = Database::prepare($sql)->execute($args)->fetchAll();
+ foreach ($rows as $row) {
+ $person = Individual::getInstance($row->xref, $this->tree(), $row->gedcom);
+ // The name from the database may be private - check the filtered list...
+ foreach ($person->getAllNames() as $n => $name) {
+ if ($name['fullNN'] == $row->n_full) {
+ $person->setPrimaryName($n);
+ // We need to clone $person, as we may have multiple references to the
+ // same person in this list, and the "primary name" would otherwise
+ // be shared amongst all of them.
+ $list[] = clone $person;
+ break;
+ }
+ }
+ }
+
+ return $list;
+ }
+
+ /**
+ * Fetch a list of families with specified names
+ *
+ * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@"
+ * To search for names with no surnames, use $salpha=","
+ *
+ * @param string $surn if set, only fetch people with this surname
+ * @param string $salpha if set, only fetch surnames starting with this letter
+ * @param string $galpha if set, only fetch given names starting with this letter
+ * @param bool $marnm if set, include married names
+ *
+ * @return Family[]
+ */
+ public function families($surn, $salpha, $galpha, $marnm) {
+ $list = [];
+ foreach ($this->individuals($surn, $salpha, $galpha, $marnm, true) as $indi) {
+ foreach ($indi->getSpouseFamilies() as $family) {
+ $list[$family->getXref()] = $family;
+ }
+ }
+ usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
+
+ return $list;
+ }
+
+ /**
+ * Some initial letters have a special meaning
+ *
+ * @param string $initial
+ *
+ * @return string
+ */
+ public function givenNameInitial($initial) {
+ switch ($initial) {
+ case '@':
+ return I18N::translateContext('Unknown given name', '…');
+ break;
+ default:
+ return Filter::escapeHtml($initial);
+ break;
+ }
+ }
+
+ /**
+ * Some initial letters have a special meaning
+ *
+ * @param string $initial
+ *
+ * @return string
+ */
+ public function surnameInitial($initial) {
+ switch ($initial) {
+ case '@':
+ return I18N::translateContext('Unknown surname', '…');
+ break;
+ case ',':
+ return I18N::translate('None');
+ break;
+ default:
+ return Filter::escapeHtml($initial);
+ break;
+ }
+ }
+}
diff --git a/app/Controller/LifespanController.php b/app/Controller/LifespanController.php
index af6fb5e5d3..6d47b2576a 100644
--- a/app/Controller/LifespanController.php
+++ b/app/Controller/LifespanController.php
@@ -516,19 +516,4 @@ class LifespanController extends PageController {
return $caldate;
}
-
- /**
- * Function getCalendarOptionList
- *
- * @return string
- */
- public function getCalendarOptionList() {
- $html = '';
- foreach (Date::calendarNames() as $calendar => $name) {
- $selected = $this->calendar === $calendar ? 'selected' : '';
- $html .= sprintf('<option dir="auto" value="%s" %s>%s</option>', $calendar, $selected, $name);
- }
-
- return $html;
- }
}
diff --git a/app/Controller/MediaController.php b/app/Controller/MediaController.php
index bc2f5789d2..9bd47a9d75 100644
--- a/app/Controller/MediaController.php
+++ b/app/Controller/MediaController.php
@@ -40,9 +40,7 @@ class MediaController extends GedcomRecordController {
$menu = new Menu(I18N::translate('Edit'), '#', 'menu-obje');
if (Auth::isEditor($this->record->getTree())) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the media object'), '#', 'menu-obje-edit', [
- 'onclick' => 'window.open("addmedia.php?action=editmedia&pid=' . $this->record->getXref() . '", "_blank", edit_window_specs)',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the media object'), 'addmedia.php?action=editmedia&pid=' . $this->record->getXref() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-obje-edit'));
// main link displayed on page
if (Module::getModuleByName('GEDFact_assistant')) {
@@ -71,9 +69,7 @@ class MediaController extends GedcomRecordController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-obje-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-obje-editraw'));
}
return $menu;
diff --git a/app/Controller/NoteController.php b/app/Controller/NoteController.php
index 4c0e6f4281..c58232d750 100644
--- a/app/Controller/NoteController.php
+++ b/app/Controller/NoteController.php
@@ -36,9 +36,7 @@ class NoteController extends GedcomRecordController {
$menu = new Menu(I18N::translate('Edit'), '#', 'menu-note');
if (Auth::isEditor($this->record->getTree())) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the note'), '#', 'menu-note-edit', [
- 'onclick' => 'return edit_note("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the note'), 'edit_interface.php?action=editnote&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-note-edit'));
// delete
$menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-note-del', [
diff --git a/app/Controller/PageController.php b/app/Controller/PageController.php
index 7a62a3716f..8c9986509f 100644
--- a/app/Controller/PageController.php
+++ b/app/Controller/PageController.php
@@ -34,9 +34,6 @@ class PageController extends BaseController {
/** @var string <head><title> $page_title </title></head> */
private $page_title = WT_WEBTREES;
- /** @var bool Is this a popup window? */
- private $popup;
-
/**
* What should this page show in the browser’s title bar?
*
@@ -103,35 +100,15 @@ class PageController extends BaseController {
public function pageFooter() {
echo
Theme::theme()->footerContainer() .
- '<!--[if lt IE 9]><script src="' . WT_JQUERY_JS_URL . '"></script><![endif]-->' .
- '<!--[if gte IE 9]><!--><script src="' . WT_JQUERY2_JS_URL . '"></script><!--<![endif]-->' .
- '<script src="' . WT_JQUERYUI_JS_URL . '"></script>' .
- '<script src="' . WT_WEBTREES_JS_URL . '"></script>' .
- $this->getJavascript() .
- Theme::theme()->hookFooterExtraJavascript() .
- (WT_DEBUG_SQL ? Database::getQueryLog() : '') .
- '</body>' .
- '</html>' . PHP_EOL .
- '<!-- webtrees: ' . WT_VERSION . ' -->' .
- '<!-- Execution time: ' . I18N::number(microtime(true) - WT_START_TIME, 3) . ' seconds -->' .
- '<!-- Memory: ' . I18N::number(memory_get_peak_usage(true) / 1024) . ' KB -->' .
- '<!-- SQL queries: ' . I18N::number(Database::getQueryCount()) . ' -->';
- }
-
- /**
- * Print the page footer, using the theme
- * Note that popup windows are deprecated
- */
- public function pageFooterPopupWindow() {
- echo
- Theme::theme()->footerContainerPopupWindow() .
- '<!--[if lt IE 9]><script src="' . WT_JQUERY_JS_URL . '"></script><![endif]-->' .
- '<!--[if gte IE 9]><!--><script src="' . WT_JQUERY2_JS_URL . '"></script><!--<![endif]-->' .
- '<script src="' . WT_JQUERYUI_JS_URL . '"></script>' .
+ '<script src="' . WT_JQUERY_JS_URL . '"></script>' .
+ '<script src="' . WT_TETHER_JS_URL . '"></script>' .
+ '<script src="' . WT_BOOTSTRAP_JS_URL . '"></script>' .
+ '<script src="' . WT_DATATABLES_JS_URL . '"></script>' .
+ '<script src="' . WT_DATATABLES_BOOTSTRAP_JS_URL . '"></script>' .
+ '<script src="' . WT_SELECT2_JS_URL . '"></script>' .
'<script src="' . WT_WEBTREES_JS_URL . '"></script>' .
$this->getJavascript() .
Theme::theme()->hookFooterExtraJavascript() .
- (WT_DEBUG_SQL ? Database::getQueryLog() : '') .
'</body>' .
'</html>' . PHP_EOL .
'<!-- webtrees: ' . WT_VERSION . ' -->' .
@@ -143,15 +120,9 @@ class PageController extends BaseController {
/**
* Print the page header, using the theme
*
- * @param bool $popup Is this a popup window
- *
* @return $this
*/
- public function pageHeader($popup = false) {
- global $WT_TREE;
-
- $this->popup = $popup;
-
+ public function pageHeader() {
// Give Javascript access to some PHP constants
$this->addInlineJavascript('
var WT_STATIC_URL = "' . Filter::escapeJs(WT_STATIC_URL) . '";
@@ -160,24 +131,15 @@ class PageController extends BaseController {
var textDirection = "' . Filter::escapeJs(I18N::direction()) . '";
var WT_SCRIPT_NAME = "' . Filter::escapeJs(WT_SCRIPT_NAME) . '";
var WT_LOCALE = "' . Filter::escapeJs(WT_LOCALE) . '";
- var WT_CSRF_TOKEN = "' . Filter::escapeJs(Filter::getCsrfToken()) . '";
', self::JS_PRIORITY_HIGH);
Theme::theme()->sendHeaders();
echo Theme::theme()->doctype();
echo Theme::theme()->html();
echo Theme::theme()->head($this);
-
- if ($this->popup) {
- echo Theme::theme()->bodyHeaderPopupWindow();
- // We've displayed the header - display the footer automatically
- register_shutdown_function([$this, 'pageFooterPopupWindow'], $this->popup);
-
- } else {
- echo Theme::theme()->bodyHeader();
- // We've displayed the header - display the footer automatically
- register_shutdown_function([$this, 'pageFooter'], $this->popup);
- }
+ echo Theme::theme()->bodyHeader();
+ // We've displayed the header - display the footer automatically
+ register_shutdown_function([$this, 'pageFooter']);
return $this;
}
diff --git a/app/Controller/PedigreeController.php b/app/Controller/PedigreeController.php
index 36c6734f38..f626c43b3e 100644
--- a/app/Controller/PedigreeController.php
+++ b/app/Controller/PedigreeController.php
@@ -32,7 +32,7 @@ class PedigreeController extends ChartController {
const LANDSCAPE = 1;
const OLDEST_AT_TOP = 2;
const OLDEST_AT_BOTTOM = 3;
- const MENU_ITEM = '<a href="pedigree.php?rootid=%s&amp;show_full=%s&amp;PEDIGREE_GENERATIONS=%s&amp;orientation=%s" class="%s noprint">%s</a>';
+ const MENU_ITEM = '<a href="pedigree.php?rootid=%s&amp;PEDIGREE_GENERATIONS=%s&amp;orientation=%s" class="%s">%s</a>';
/**
* Next and previous generation arrow size
@@ -257,17 +257,17 @@ class PedigreeController extends ChartController {
$families = $this->root->getSpouseFamilies();
$html = '';
if (!empty($families)) {
- $html = sprintf('<div id="childarrow"><a href="#" class="menuselect noprint %s"></a><div id="childbox">', $this->arrows->menu);
+ $html = sprintf('<div id="childarrow"><a href="#" class="menuselect %s"></a><div id="childbox">', $this->arrows->menu);
foreach ($families as $family) {
$html .= '<span class="name1">' . I18N::translate('Family') . '</span>';
$spouse = $family->getSpouse($this->root);
if ($spouse) {
- $html .= sprintf(self::MENU_ITEM, $spouse->getXref(), $this->showFull(), $this->generations, $this->orientation, 'name1', $spouse->getFullName());
+ $html .= sprintf(self::MENU_ITEM, $spouse->getXref(), $this->generations, $this->orientation, 'name1', $spouse->getFullName());
}
$children = $family->getChildren();
foreach ($children as $sibling) {
- $html .= sprintf(self::MENU_ITEM, $sibling->getXref(), $this->showFull(), $this->generations, $this->orientation, 'name1', $sibling->getFullName());
+ $html .= sprintf(self::MENU_ITEM, $sibling->getXref(), $this->generations, $this->orientation, 'name1', $sibling->getFullName());
}
}
//-- echo the siblings
@@ -280,7 +280,7 @@ class PedigreeController extends ChartController {
$html .= count($siblings) > 1 ? I18N::translate('Siblings') : I18N::translate('Sibling');
$html .= '</span>';
foreach ($siblings as $sibling) {
- $html .= sprintf(self::MENU_ITEM, $sibling->getXref(), $this->showFull(), $this->generations, $this->orientation, 'name1', $sibling->getFullName());
+ $html .= sprintf(self::MENU_ITEM, $sibling->getXref(), $this->generations, $this->orientation, 'name1', $sibling->getFullName());
}
}
}
@@ -310,7 +310,7 @@ class PedigreeController extends ChartController {
if ($index > (int) ($this->treesize / 2) + (int) ($this->treesize / 4)) {
$rootParentId++;
}
- $html .= sprintf(self::MENU_ITEM, $this->nodes[$rootParentId]['indi']->getXref(), $this->showFull(), $this->generations, $this->orientation, $this->arrows->prevGen, '');
+ $html .= sprintf(self::MENU_ITEM, $this->nodes[$rootParentId]['indi']->getXref(), $this->generations, $this->orientation, $this->arrows->prevGen, '');
$html .= '</div>';
} else {
$html .= '<div class="spacer"></div>';
diff --git a/app/Controller/RepositoryController.php b/app/Controller/RepositoryController.php
index 625019b524..8b0194b24d 100644
--- a/app/Controller/RepositoryController.php
+++ b/app/Controller/RepositoryController.php
@@ -40,14 +40,10 @@ class RepositoryController extends GedcomRecordController {
$fact = $this->record->getFirstFact('NAME');
if ($fact) {
// Edit existing name
- $menu->addSubmenu(new Menu(I18N::translate('Edit the repository'), '#', 'menu-repo-edit', [
- 'onclick' => 'return edit_record("' . $this->record->getXref() . '", "' . $fact->getFactId() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the repository'), 'edit_interface.php?action=edit&amp;xref=' . $this->record->getXref() . '&amp;fact_id=' . $fact->getFactId() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-repo-edit'));
} else {
// Add new name
- $menu->addSubmenu(new Menu(I18N::translate('Edit the repository'), '#', 'menu-repo-edit', [
- 'onclick' => 'return add_fact("' . $this->record->getXref() . '", "NAME");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the repository'), 'edit_interface.php?action=add&amp;fact=NAME&amp;xref=' . $this->record->getXref() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-repo-edit'));
}
}
@@ -60,9 +56,7 @@ class RepositoryController extends GedcomRecordController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-repo-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-repo-editraw'));
}
// add to favorites
diff --git a/app/Controller/SearchController.php b/app/Controller/SearchController.php
index 938db309ee..a00a8a9b75 100644
--- a/app/Controller/SearchController.php
+++ b/app/Controller/SearchController.php
@@ -16,6 +16,7 @@
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Config;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
@@ -506,43 +507,70 @@ class SearchController extends PageController {
*/
public function printResults() {
if ($this->action !== 'replace' && ($this->query || $this->firstname || $this->lastname || $this->place)) {
- if ($this->myindilist || $this->myfamlist || $this->mysourcelist || $this->mynotelist) {
- $this->addInlineJavascript('$("#search-result-tabs").tabs();');
- $this->addInlineJavascript('$("#search-result-tabs").css("visibility", "visible");');
- $this->addInlineJavascript('$(".loading-image").css("display", "none");');
- echo '<br>';
- echo '<div class="loading-image"></div>';
- echo '<div id="search-result-tabs"><ul>';
- if (!empty($this->myindilist)) {
- echo '<li><a href="#individual-results-tab">', I18N::translate('Individuals'), '</a></li>';
- }
- if (!empty($this->myfamlist)) {
- echo '<li><a href="#families-results-tab">', I18N::translate('Families'), '</a></li>';
- }
- if (!empty($this->mysourcelist)) {
- echo '<li><a href="#sources-results-tab">', I18N::translate('Sources'), '</a></li>';
- }
- if (!empty($this->mynotelist)) {
- echo '<li><a href="#notes-results-tab">', I18N::translate('Notes'), '</a></li>';
- }
- echo '</ul>';
- if (!empty($this->myindilist)) {
- echo '<div id="individual-results-tab">', FunctionsPrintLists::individualTable($this->myindilist), '</div>';
- }
- if (!empty($this->myfamlist)) {
- echo '<div id="families-results-tab">', FunctionsPrintLists::familyTable($this->myfamlist), '</div>';
- }
- if (!empty($this->mysourcelist)) {
- echo '<div id="sources-results-tab">', FunctionsPrintLists::sourceTable($this->mysourcelist), '</div>';
- }
- if (!empty($this->mynotelist)) {
- echo '<div id="notes-results-tab">', FunctionsPrintLists::noteTable($this->mynotelist), '</div>';
- }
- echo '</div>';
- } else {
- // One or more search terms were specified, but no results were found.
- echo '<div class="warning center">' . I18N::translate('No results found.') . '</div>';
- }
+ ?>
+ <div class="wt-page-content">
+ <ul class="nav nav-tabs" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link active<?= empty($this->myindilist) ? ' text-muted' : '' ?>" data-toggle="tab" role="tab" href="#individuals">
+ <?= I18N::translate('Individuals') ?>
+ <?= Bootstrap4::badgeCount($this->myindilist) ?>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link<?= empty($this->myfamlist) ? ' text-muted' : '' ?>" data-toggle="tab" role="tab" href="#families">
+ <?= I18N::translate('Families') ?>
+ <?= Bootstrap4::badgeCount($this->myfamlist) ?>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link<?= empty($this->mysourcelist) ? ' text-muted' : '' ?>" data-toggle="tab" role="tab" href="#sources">
+ <?= I18N::translate('Sources') ?>
+ <?= Bootstrap4::badgeCount($this->mysourcelist) ?>
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link<?= empty($this->mynotelist) ? ' text-muted' : '' ?>" data-toggle="tab" role="tab" href="#notes">
+ <?= I18N::translate('Notes') ?>
+ <?= Bootstrap4::badgeCount($this->mynotelist) ?>
+ </a>
+ </li>
+ </ul>
+
+ <div class="tab-content">
+ <div class="tab-pane fade show active" role="tabpanel" id="individuals">
+ <?php if (empty($this->myindilist)): ?>
+ <p><?= I18N::translate('No results found.') ?></p>
+ <?php else: ?>
+ <?= FunctionsPrintLists::individualTable($this->myindilist) ?>
+ <?php endif ?>
+ </div>
+
+ <div class="tab-pane fade" role="tabpanel" id="families">
+ <?php if (empty($this->myfamlist)): ?>
+ <p><?= I18N::translate('No results found.') ?></p>
+ <?php else: ?>
+ <?= FunctionsPrintLists::familyTable($this->myfamlist) ?>
+ <?php endif ?>
+ </div>
+
+ <div class="tab-pane fade" role="tabpanel" id="sources">
+ <?php if (empty($this->mysourcelist)): ?>
+ <p><?= I18N::translate('No results found.') ?></p>
+ <?php else: ?>
+ <?= FunctionsPrintLists::sourceTable($this->mysourcelist) ?>
+ <?php endif ?>
+ </div>
+
+ <div class="tab-pane fade" role="tabpanel" id="notes">
+ <?php if (empty($this->mynotelist)): ?>
+ <p><?= I18N::translate('No results found.') ?></p>
+ <?php else: ?>
+ <?= FunctionsPrintLists::noteTable($this->mynotelist) ?>
+ <?php endif ?>
+ </div>
+ </div>
+ </div>
+ <?php
}
}
}
diff --git a/app/Controller/SimpleController.php b/app/Controller/SimpleController.php
deleted file mode 100644
index 0f3d7cd554..0000000000
--- a/app/Controller/SimpleController.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\Controller;
-
-/**
- * Controller for all popup pages
- */
-class SimpleController extends PageController {
- /**
- * Create content for a popup window.
- * The page title is not used by all browsers.
- */
- public function __construct() {
- parent::__construct();
- $this->setPageTitle(WT_WEBTREES);
- }
-
- /**
- * Simple (i.e. popup) windows are deprecated.
- *
- * @param bool $popup
- *
- * @return $this
- */
- public function pageHeader($popup = true) {
- return parent::pageHeader($popup);
- }
-
- /**
- * Restrict access
- *
- * @param bool $condition
- *
- * @return $this
- */
- public function restrictAccess($condition) {
- if ($condition !== true) {
- $this->addInlineJavascript('opener.window.location.reload(); window.close();');
- exit;
- }
-
- return $this;
- }
-}
diff --git a/app/Controller/SourceController.php b/app/Controller/SourceController.php
index c40090d94e..da30a8d39c 100644
--- a/app/Controller/SourceController.php
+++ b/app/Controller/SourceController.php
@@ -39,14 +39,10 @@ class SourceController extends GedcomRecordController {
$fact = $this->record->getFirstFact('TITL');
if ($fact) {
// Edit existing name
- $menu->addSubmenu(new Menu(I18N::translate('Edit the source'), '#', 'menu-sour-edit', [
- 'onclick' => 'return edit_record("' . $this->record->getXref() . '", "' . $fact->getFactId() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the source'), 'edit_interface.php?action=edit&amp;xref=' . $this->record->getXref() . '&amp;fact_id=' . $fact->getFactId() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-sour-edit'));
} else {
// Add new name
- $menu->addSubmenu(new Menu(I18N::translate('Edit the source'), '#', 'menu-sour-edit', [
- 'onclick' => 'return add_fact("' . $this->record->getXref() . '", "TITL");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the source'), 'edit_interface.php?action=add&amp;fact=TITL&amp;xref=' . $this->record->getXref() . '&amp;ged=' . $this->record->getTree()->getNameHtml(), 'menu-sour-edit'));
}
// delete
@@ -57,9 +53,7 @@ class SourceController extends GedcomRecordController {
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
- $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-sour-editraw', [
- 'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
- ]));
+ $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&amp;ged=' . $this->record->getTree()->getNameHtml() . '&amp;xref=' . $this->record->getXref(), 'menu-sour-editraw'));
}
return $menu;
diff --git a/app/Controller/TimelineController.php b/app/Controller/TimelineController.php
index c1b01e3d2b..11f5134a26 100644
--- a/app/Controller/TimelineController.php
+++ b/app/Controller/TimelineController.php
@@ -73,8 +73,10 @@ class TimelineController extends PageController {
$this->baseyear = (int) date('Y');
- $pids = Filter::getArray('pids', WT_REGEX_XREF);
$remove = Filter::get('remove', WT_REGEX_XREF);
+ $newpid = Filter::get('newpid', WT_REGEX_XREF);
+ $pids = Filter::getArray('pids', WT_REGEX_XREF);
+ $pids[] = $newpid;
foreach (array_unique(array_filter($pids)) as $pid) {
if ($pid !== $remove) {
@@ -148,7 +150,7 @@ class TimelineController extends PageController {
* @param Fact $event
*/
public function printTimeFact(Fact $event) {
- global $basexoffset, $baseyoffset, $factcount, $placements;
+ global $factcount, $placements;
$desc = $event->getValue();
// check if this is a family fact
@@ -158,8 +160,8 @@ class TimelineController extends PageController {
$year = $date->y;
$month = max(1, $date->m);
$day = max(1, $date->d);
- $xoffset = $basexoffset + 22;
- $yoffset = $baseyoffset + (($year - $this->baseyear) * $this->scale) - ($this->scale);
+ $xoffset = 0 + 22;
+ $yoffset = 0 + (($year - $this->baseyear) * $this->scale) - ($this->scale);
$yoffset = $yoffset + (($month / 12) * $this->scale);
$yoffset = $yoffset + (($day / 30) * ($this->scale / 12));
$yoffset = (int) ($yoffset);
@@ -259,7 +261,7 @@ class TimelineController extends PageController {
}
}
// Print the diagonal line
- echo '<div id="dbox' . $factcount . '" style="position:absolute; ' . (I18N::direction() === 'ltr' ? 'left: ' . ($basexoffset + 25) : 'right: ' . ($basexoffset + 25)) . 'px; top:' . ($dyoffset) . 'px; font-size: 8pt; height: ' . abs($tyoffset) . 'px; width: ' . abs($tyoffset) . 'px;';
+ echo '<div id="dbox' . $factcount . '" style="position:absolute; ' . (I18N::direction() === 'ltr' ? 'left: ' . (0 + 25) : 'right: ' . (0 + 25)) . 'px; top:' . ($dyoffset) . 'px; font-size: 8pt; height: ' . abs($tyoffset) . 'px; width: ' . abs($tyoffset) . 'px;';
echo ' background-image: url(\'' . Theme::theme()->parameter($img) . '\');';
echo ' background-position: 0% ' . $ypos . ';">';
echo '</div>';
diff --git a/app/Database.php b/app/Database.php
index b482c17a64..60645f92df 100644
--- a/app/Database.php
+++ b/app/Database.php
@@ -131,53 +131,37 @@ class Database {
*
* @param string $query
* @param int $rows
- * @param float $microtime
+ * @param float $microseconds
* @param string[] $bind_variables
*/
- public static function logQuery($query, $rows, $microtime, $bind_variables) {
- if (WT_DEBUG_SQL) {
- // Full logging
- // Trace
- $trace = debug_backtrace();
- array_shift($trace);
- array_shift($trace);
- foreach ($trace as $n => $frame) {
- if (isset($frame['file']) && isset($frame['line'])) {
- $trace[$n] = basename($frame['file']) . ':' . $frame['line'] . ' ' . $frame['function'];
- } else {
- unset($trace[$n]);
- }
+ public static function logQuery($query, $rows, $microseconds, $bind_variables) {
+ // Trace
+ $trace = debug_backtrace();
+ array_shift($trace);
+ array_shift($trace);
+ foreach ($trace as $n => $frame) {
+ if (isset($frame['file']) && isset($frame['line'])) {
+ $trace[$n] = basename($frame['file']) . ':' . $frame['line'] . ' ' . $frame['function'];
+ } else {
+ unset($trace[$n]);
}
- $stack = '<abbr title="' . Filter::escapeHtml(implode(' / ', $trace)) . '">' . (count(self::$log) + 1) . '</abbr>';
- // Bind variables
- foreach ($bind_variables as $key => $value) {
- if (is_null($value)) {
- $value = 'NULL';
- } elseif (!is_integer($value)) {
- $value = '\'' . $value . '\'';
- }
- if (is_integer($key)) {
- $query = preg_replace('/\?/', $value, $query, 1);
- } else {
- $query = str_replace(':' . $key, $value, $query);
- }
+ }
+ $stack = '<abbr title="' . Filter::escapeHtml(implode(' / ', $trace)) . '">' . (count(self::$log) + 1) . '</abbr>';
+ // Bind variables
+ foreach ($bind_variables as $key => $value) {
+ if (is_null($value)) {
+ $value = 'NULL';
+ } elseif (!is_integer($value)) {
+ $value = '\'' . $value . '\'';
}
- // Highlight slow queries
- $microtime *= 1000; // convert to milliseconds
- if ($microtime > 1000) {
- $microtime = sprintf('<span style="background-color: #ff0000;">%.3f</span>', $microtime);
- } elseif ($microtime > 100) {
- $microtime = sprintf('<span style="background-color: #ffa500;">%.3f</span>', $microtime);
- } elseif ($microtime > 1) {
- $microtime = sprintf('<span style="background-color: #ffff00;">%.3f</span>', $microtime);
+ if (is_integer($key)) {
+ $query = preg_replace('/\?/', $value, $query, 1);
} else {
- $microtime = sprintf('%.3f', $microtime);
+ $query = str_replace(':' . $key, $value, $query);
}
- self::$log[] = "<tr><td>{$stack}</td><td>{$query}</td><td>{$rows}</td><td>{$microtime}</td></tr>";
- } else {
- // Just log query count for statistics
- self::$log[] = true;
}
+ $milliseconds = sprintf('%.3f', $microseconds * 1000);
+ self::$log[] = '<tr><td>' .$stack . '</td><td>' . $query . '</td><td>' . $rows . '</td><td>' . $milliseconds . '</td></tr>';
}
/**
@@ -306,7 +290,8 @@ class Database {
/** @var MigrationInterface $migration */
$migration = new $class;
$migration->upgrade();
- Site::setPreference($schema_name, ++$current_version);
+ $current_version++;
+ Site::setPreference($schema_name, (string) $current_version);
$updates_applied = true;
}
} catch (PDOException $ex) {
diff --git a/app/Datatables.php b/app/Datatables.php
new file mode 100644
index 0000000000..7418118f58
--- /dev/null
+++ b/app/Datatables.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2017 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+namespace Fisharebest\Webtrees;
+
+use Fisharebest\Webtrees\Functions\FunctionsEdit;
+
+/**
+ * Helper functions to generate markup for Datatables.
+ *
+ * @link https://www.datatables.net
+ */
+class Datatables {
+ /**
+ * Generate the HTML attributes for I18N.
+ *
+ * @return string[]
+ */
+ private static function defaultAttributes() {
+ return [
+ 'style' => 'display:none;', // Hide until processed, to prevent FOUC.
+ ];
+ }
+
+ /**
+ * Generate the HTML attributes for I18N.
+ *
+ * @param int[] $lengths
+ *
+ * @return string[]
+ */
+ private static function languageAttributes(array $lengths = [10, 25, 100, -1]) {
+ $length_menu = FunctionsEdit::numericOptions($lengths);
+
+ $language = [
+ 'paginate' => [
+ 'first' => /* I18N: A button label, first page */ I18N::translate('first'),
+ 'last' => /* I18N: A button label, last page */ I18N::translate('last'),
+ 'next' => /* I18N: A button label, next page */ I18N::translate('next'),
+ 'previous' => /* I18N: A button label, previous page */ I18N::translate('previous'),
+ ],
+ 'emptyTable' => I18N::translate('No records to display'),
+ 'info' => /* I18N: %s are placeholders for numbers */ I18N::translate('Showing %1$s to %2$s of %3$s', '_START_', '_END_', '_TOTAL_'),
+ 'infoEmpty' => I18N::translate('Showing %1$s to %2$s of %3$s', 0, 0, 0),
+ 'infoFiltered' => /* I18N: %s is a number */ I18N::translate('(filtered from %s total entries)', '_MAX_'),
+ 'lengthMenu' => /* I18N: %s is a number of records per page */ I18N::translate('Display %s', '_MENU_'),
+ 'loadingRecords' => I18N::translate('Loading…'),
+ 'processing' => I18N::translate('Calculating…'),
+ 'search' => I18N::translate('Filter'),
+ 'zeroRecords' => I18N::translate('No records to display'),
+ ];
+
+ return [
+ 'data-language' => json_encode($language),
+ 'data-length-menu' => json_encode([array_keys($length_menu), array_values($length_menu)])
+ ];
+ }
+
+ /**
+ * Generate the HTML attributes for a table of events.
+ *
+ * @return string
+ */
+ public static function eventTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-event',
+ //'data-columns' => '[{ type: "text" }, { type: "num" }, { type: "num" }, { type: "text" }]',
+ 'data-columns' => '[null, null, null, null]',
+ 'data-info' => 'false',
+ 'data-paging' => 'false',
+ 'data-searching' => 'false',
+ 'data-state-save' => 'true',
+ ] + self::languageAttributes());
+ }
+
+ /**
+ * Generate the HTML attributes for a table of given names.
+ *
+ * @return string
+ */
+ public static function givenNameTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-given-name',
+ //'data-columns' => '[{ type: "text" }, { type: "num" }]',
+ 'data-columns' => '[null, null]',
+ 'data-info' => 'false',
+ 'data-paging' => 'false',
+ 'data-searching' => 'false',
+ 'data-state-save' => 'true',
+ ]);
+ }
+
+ /**
+ * Generate the HTML attributes for a table of notes.
+ *
+ * @return string
+ */
+ public static function noteTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-note',
+ //'data-columns' => '[{ type: "text" }, { type: "text" }, { type: "num" }, { type: "num" }, { type: "num" }, { type: "text" }, { sorting: false }]',
+ 'data-columns' => '[null, null, null, null, null, null, null]',
+ 'data-state-save' => 'true',
+ ] + self::defaultAttributes() + self::languageAttributes());
+ }
+
+ /**
+ * Generate the HTML attributes for a table of research tasks.
+ *
+ * @return string
+ */
+ public static function researchTaskTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-research-task',
+ //'data-columns' => '[{ type: "num" }, { type: "text" }, { type: "text" }, { type: "text" }]',
+ 'data-columns' => '[null, null, null, null]',
+ 'data-info' => 'false',
+ 'data-paging' => 'false',
+ 'data-searching' => 'false',
+ 'data-state-save' => 'true',
+ ] + self::languageAttributes());
+ }
+
+ /**
+ * Generate the HTML attributes for a table of repositories.
+ *
+ * @return string
+ */
+ public static function repositoryTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-repository',
+ //'data-columns' => '[{ type: "text" }, { type: "num" }, { type: "text" }, { sorting: false }]',
+ 'data-columns' => '[null, null, null, null]',
+ 'data-state-save' => 'true',
+ ] + self::languageAttributes());
+ }
+
+ /**
+ * Generate the HTML attributes for a table of sources.
+ *
+ * @return string
+ */
+ public static function sourceTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-source',
+ //'data-columns' => '[{ type: "text" }, { type: "text" }, { type: "num" }, { type: "num" }, { type: "num" }, { type: "num" }, { type: "text" }, { sorting: false }]',
+ 'data-columns' => '[null, null, null, null, null, null, null, null]',
+ 'data-state-save' => 'true',
+ ] + self::languageAttributes());
+ }
+
+ /**
+ * Generate the HTML attributes for a table of surnames.
+ *
+ * @return string
+ */
+ public static function surnameTableAttributes() {
+ return Html::attributes([
+ 'class' => 'table table-bordered table-sm table-responsive datatables table-surname',
+ //'data-columns' => '[{ type: "text" }, { type: "num" }]',
+ 'data-columns' => '[null, null]',
+ 'data-info' => 'false',
+ 'data-paging' => 'false',
+ 'data-searching' => 'false',
+ 'data-state-save' => 'true',
+ ]);
+ }
+}
diff --git a/app/Filter.php b/app/Filter.php
index 284caf3688..5da8b12363 100644
--- a/app/Filter.php
+++ b/app/Filter.php
@@ -106,8 +106,8 @@ class Filter {
/**
* Format block-level text such as notes or transcripts, etc.
*
- * @param string $text
- * @param Tree $WT_TREE
+ * @param string $text
+ * @param Tree $WT_TREE
*
* @return string
*/
@@ -171,11 +171,11 @@ class Filter {
* @param string $source
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return string|null
+ * @return string
*/
- private static function input($source, $variable, $regexp = null, $default = null) {
+ private static function input($source, $variable, $regexp = null, $default = '') {
if ($regexp) {
return filter_input(
$source,
@@ -210,11 +210,11 @@ class Filter {
* @param string $source
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
* @return string[]
*/
- private static function inputArray($source, $variable, $regexp = null, $default = null) {
+ private static function inputArray($source, $variable, $regexp = null, $default = '') {
if ($regexp) {
return filter_input_array($source, [
$variable => [
@@ -244,11 +244,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function get($variable, $regexp = null, $default = null) {
+ public static function get($variable, $regexp = null, $default = '') {
return self::input(INPUT_GET, $variable, $regexp, $default);
}
@@ -257,11 +257,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
* @return string[]
*/
- public static function getArray($variable, $regexp = null, $default = null) {
+ public static function getArray($variable, $regexp = null, $default = '') {
return self::inputArray(INPUT_GET, $variable, $regexp, $default);
}
@@ -293,24 +293,24 @@ class Filter {
/**
* Validate email GET parameters
*
- * @param string $variable
- * @param string|null $default
+ * @param string $variable
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function getEmail($variable, $default = null) {
+ public static function getEmail($variable, $default = '') {
return filter_input(INPUT_GET, $variable, FILTER_VALIDATE_EMAIL) ?: $default;
}
/**
* Validate URL GET parameters
*
- * @param string $variable
- * @param string|null $default
+ * @param string $variable
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function getUrl($variable, $default = null) {
+ public static function getUrl($variable, $default = '') {
return filter_input(INPUT_GET, $variable, FILTER_VALIDATE_URL) ?: $default;
}
@@ -319,11 +319,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function post($variable, $regexp = null, $default = null) {
+ public static function post($variable, $regexp = null, $default = '') {
return self::input(INPUT_POST, $variable, $regexp, $default);
}
@@ -332,11 +332,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return string[]
+ * @return string[]|string[][]
*/
- public static function postArray($variable, $regexp = null, $default = null) {
+ public static function postArray($variable, $regexp = null, $default = '') {
return self::inputArray(INPUT_POST, $variable, $regexp, $default);
}
@@ -368,24 +368,24 @@ class Filter {
/**
* Validate email POST parameters
*
- * @param string $variable
- * @param string|null $default
+ * @param string $variable
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function postEmail($variable, $default = null) {
+ public static function postEmail($variable, $default = '') {
return filter_input(INPUT_POST, $variable, FILTER_VALIDATE_EMAIL) ?: $default;
}
/**
* Validate URL GET parameters
*
- * @param string $variable
- * @param string|null $default
+ * @param string $variable
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function postUrl($variable, $default = null) {
+ public static function postUrl($variable, $default = '') {
return filter_input(INPUT_POST, $variable, FILTER_VALIDATE_URL) ?: $default;
}
@@ -394,11 +394,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function cookie($variable, $regexp = null, $default = null) {
+ public static function cookie($variable, $regexp = null, $default = '') {
return self::input(INPUT_COOKIE, $variable, $regexp, $default);
}
@@ -407,11 +407,11 @@ class Filter {
*
* @param string $variable
* @param string|null $regexp
- * @param string|null $default
+ * @param string $default
*
- * @return null|string
+ * @return string
*/
- public static function server($variable, $regexp = null, $default = null) {
+ public static function server($variable, $regexp = null, $default = '') {
// On some servers, variables that are present in $_SERVER cannot be
// found via filter_input(INPUT_SERVER). Instead, they are found via
// filter_input(INPUT_ENV). Since we cannot rely on filter_input(),
@@ -458,7 +458,7 @@ $_SERVER[$variable]))) {
* @return bool
*/
public static function checkCsrf() {
- if (self::post('csrf') !== self::getCsrfToken()) {
+ if (isset($_SERVER['HTTP_X_CSRF_TOKEN']) && $_SERVER['HTTP_X_CSRF_TOKEN'] !== self::getCsrfToken()) {
// Oops. Something is not quite right
Log::addAuthenticationLog('CSRF mismatch - session expired or malicious attack');
FlashMessages::addMessage(I18N::translate('This form has expired. Try again.'), 'error');
diff --git a/app/FlashMessages.php b/app/FlashMessages.php
index 2fdc28de57..6d9b0b7bf4 100644
--- a/app/FlashMessages.php
+++ b/app/FlashMessages.php
@@ -15,6 +15,8 @@
*/
namespace Fisharebest\Webtrees;
+use stdClass;
+
/**
* Generate messages in one request and display them in the next.
*/
@@ -29,7 +31,7 @@ class FlashMessages {
* @param string $status "success", "info", "warning" or "danger"
*/
public static function addMessage($text, $status = 'info') {
- $message = new \stdClass;
+ $message = new stdClass;
$message->text = $text;
$message->status = $status;
@@ -41,7 +43,7 @@ class FlashMessages {
/**
* Get the current messages, and remove them from session storage.
*
- * @return string[]
+ * @return stdClass[]
*/
public static function getMessages() {
$messages = Session::get(self::FLASH_KEY, []);
diff --git a/app/FontAwesome.php b/app/FontAwesome.php
new file mode 100644
index 0000000000..dc14073fba
--- /dev/null
+++ b/app/FontAwesome.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2017 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Fisharebest\Webtrees;
+
+/**
+ * Helper functions to generate markup for FontAwesome.
+ *
+ * @link http://fontawesome.io/accessibility
+ */
+class FontAwesome extends Html {
+ /** Which font-awesome icon to use for which action/entity */
+ const ICONS = [
+ // Application icons
+ 'add' => 'fa fa-plus wt-icon-add',
+ 'calendar' => 'fa fa-calendar wt-icon-calendar',
+ 'cancel' => 'fa fa-close wt-icon-cancel',
+ 'coordinates' => 'fa fa-map-marker wt-icon-coordinates',
+ 'copy' => 'fa fa-copy wt-icon-copy',
+ 'delete' => 'fa fa-trash-o wt-icon-delete',
+ 'download' => 'fa fa-download wt-icon-download',
+ 'edit' => 'fa fa-pencil wt-icon-edit',
+ 'help' => 'fa fa-info-circle wt-icon-help',
+ 'email' => 'fa fa-envelope-o wt-icon-email',
+ 'keyboard' => 'fa fa-keyboard-o wt-icon-keyboard',
+ 'pin' => 'fa fa-thumb-tack wt-icon-pin',
+ 'preferences' => 'fa fa-wrench wt-icon-preferences',
+ 'save' => 'fa fa-check wt-icon-save',
+ 'warning' => 'fa fa-warning wt-icon-warning',
+ // Arrows (start/end variants require fontawesome-rtl library)
+ 'arrow-down' => 'fa fa-arrow-down wt-icon-arrow-down',
+ 'arrow-end' => 'fa fa-arrow-end wt-icon-arrow-end',
+ 'arrow-start' => 'fa fa-arrow-start wt-icon-arrow-start',
+ 'arrow-up' => 'fa fa-arrow-up wt-icon-arrow-up',
+ // GEDCOM records
+ 'family' => 'fa fa-users wt-icon-family',
+ 'individual' => 'fa fa-user wt-icon-individual',
+ 'note' => 'fa fa-sticky-note-o wt-icon-note',
+ 'media' => 'fa fa-file-imate-o wt-icon-media',
+ 'repository' => 'fa fa-institution wt-icon-repository',
+ 'source' => 'fa fa-file-text-o wt-icon-source',
+ 'submitter' => 'fa fa-user-o wt-icon-submitter',
+ 'upload' => 'fa fa-upload wt-icon-upload',
+ // External sites and applications
+ 'bing-maps' => 'fa fa-icon-map-o wt-icon-bing-maps',
+ 'google-maps' => 'fa fa-icon-map-o wt-icon-google-maps',
+ 'openstreetmap' => 'fa fa-icon-map-o wt-icon-openstreetmap',
+ ];
+
+ /**
+ * Generate a decorative icon.
+ *
+ * These icons are shown in addition to other text, and should be ignored
+ * by assistive technology.
+ *
+ * @param string $icon The icon to show
+ * @param string[] $attributes Additional HTML attributes
+ *
+ * @return string
+ */
+ public static function decorativeIcon($icon, $attributes = []) {
+ $attributes['class'] = self::ICONS[$icon];
+ $attributes['aria-hidden'] = 'true';
+
+ return '<i ' . self::attributes($attributes) . '></i>';
+ }
+
+ /**
+ * Generate a semantic icon.
+ *
+ * These icons convey meaning, such as status/type/mode, and need
+ * to allow assistive technology to display this meaning.
+ *
+ * @param string $icon The icon to show
+ * @param string $title The meaning of the icon
+ * @param string[] $attributes Additional HTML attributes
+ *
+ * @return string
+ */
+ public static function semanticIcon($icon, $title, $attributes = []) {
+ $attributes['title'] = $title;
+
+ return self::decorativeIcon($icon, $attributes) . '<span class="sr-only">' . $title . '</span>';
+ }
+
+ /**
+ * Generate a link icon.
+ *
+ * @param string $icon The icon to show
+ * @param string $title The meaning of the icon
+ * @param string[] $attributes Additional HTML attributes
+ *
+ * @return string
+ */
+ public static function linkIcon($icon, $title, $attributes = []) {
+ $attributes['aria-label'] = strip_tags($title);
+
+ return '<a ' . self::attributes($attributes) . '>' . self::decorativeIcon($icon, ['title' => $title]) . '</a>';
+ }
+}
diff --git a/app/Functions/FunctionsCharts.php b/app/Functions/FunctionsCharts.php
index cc40b154e7..4abdc6751e 100644
--- a/app/Functions/FunctionsCharts.php
+++ b/app/Functions/FunctionsCharts.php
@@ -17,6 +17,7 @@ namespace Fisharebest\Webtrees\Functions;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Family;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Theme;
@@ -28,35 +29,26 @@ class FunctionsCharts {
/**
* print a table cell with sosa number
*
- * @param int $sosa
- * @param string $pid optional pid
- * @param string $arrowDirection direction of link arrow
+ * @param int $sosa
+ * @param string $pid optional pid
+ * @param string $icon which arrow to use
*/
- public static function printSosaNumber($sosa, $pid = '', $arrowDirection = 'up') {
- if (substr($sosa, -1, 1) == '.') {
+ public static function printSosaNumber($sosa, $pid = '', $icon = '') {
+ if (substr($sosa, -1, 1) === '.') {
$personLabel = substr($sosa, 0, -1);
} else {
$personLabel = $sosa;
}
- if ($arrowDirection == 'blank') {
+ if ($icon == '') {
$visibility = 'hidden';
} else {
$visibility = 'normal';
}
echo '<td class="subheaders center" style="vertical-align: middle; text-indent: 0px; margin-top: 0px; white-space: nowrap; visibility: ', $visibility, ';">';
echo $personLabel;
- if ($sosa != '1' && $pid != '') {
- if ($arrowDirection == 'left') {
- $dir = 0;
- } elseif ($arrowDirection == 'right') {
- $dir = 1;
- } elseif ($arrowDirection == 'down') {
- $dir = 3;
- } else {
- $dir = 2; // either 'blank' or 'up'
- }
+ if ($sosa != '1' && $pid !== '') {
echo '<br>';
- self::printUrlArrow('#' . $pid, $pid, $dir);
+ echo FontAwesome::linkIcon($icon, $pid, ['href' => '#' . $pid]);
}
echo '</td>';
}
@@ -69,15 +61,10 @@ class FunctionsCharts {
* @param string $label indi label (descendancy booklet)
* @param string $parid parent ID (descendancy booklet)
* @param string $gparid gd-parent ID (descendancy booklet)
- * @param bool $show_full large or small box
*/
- public static function printFamilyParents(Family $family, $sosa = 0, $label = '', $parid = '', $gparid = '', $show_full = true) {
+ public static function printFamilyParents(Family $family, $sosa = 0, $label = '', $parid = '', $gparid = '') {
- if ($show_full) {
- $pbheight = Theme::theme()->parameter('chart-box-y') + 14;
- } else {
- $pbheight = Theme::theme()->parameter('compact-chart-box-y') + 14;
- }
+ $pbheight = Theme::theme()->parameter('chart-box-y') + 14;
$husb = $family->getHusband();
if ($husb) {
@@ -104,12 +91,12 @@ class FunctionsCharts {
if ($parid) {
if ($husb->getXref() == $parid) {
- self::printSosaNumber($label);
+ self::printSosaNumber($label, '', 'arrow-up');
} else {
- self::printSosaNumber($label, '', 'blank');
+ self::printSosaNumber($label, '', 'arrow-up');
}
} elseif ($sosa) {
- self::printSosaNumber($sosa * 2);
+ self::printSosaNumber($sosa * 2, '', 'arrow-up');
}
if ($husb->isPendingAddtion()) {
echo '<td class="facts_value new">';
@@ -118,7 +105,7 @@ class FunctionsCharts {
} else {
echo '<td>';
}
- FunctionsPrint::printPedigreePerson($husb, $show_full);
+ FunctionsPrint::printPedigreePerson($husb);
echo '</td></tr></table>';
echo '</td>';
// husband’s parents
@@ -131,26 +118,26 @@ class FunctionsCharts {
if ($hfam && $hfam->getHusband()) {
echo '<table border="0"><tr>';
if ($sosa > 0) {
- self::printSosaNumber($sosa * 4, $hfam->getHusband()->getXref(), 'down');
+ self::printSosaNumber($sosa * 4, $hfam->getHusband()->getXref(), 'arrow-down');
}
if (!empty($gparid) && $hfam->getHusband()->getXref() == $gparid) {
- self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.');
+ self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.', '', 'arrow-up');
}
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getHusband(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getHusband());
echo '</td></tr></table>';
} elseif ($hfam && !$hfam->getHusband()) {
// Empty box for grandfather
echo '<table border="0"><tr>';
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getHusband(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getHusband());
echo '</td></tr></table>';
}
echo '</td>';
}
if ($hfam && ($sosa != -1)) {
echo '<td rowspan="2">';
- self::printUrlArrow(($sosa == 0 ? '?famid=' . $hfam->getXref() . '&amp;ged=' . $hfam->getTree()->getNameUrl() : '#' . $hfam->getXref()), $hfam->getXref(), 1);
+ echo FontAwesome::linkIcon('arrow-end', $hfam->getXref(), ['href' => ($sosa == 0 ? '?famid=' . $hfam->getXref() . '&amp;ged=' . $hfam->getTree()->getNameUrl() : '#' . $hfam->getXref())]);
echo '</td>';
}
if ($hfam) {
@@ -159,19 +146,19 @@ class FunctionsCharts {
if ($hfam && $hfam->getWife()) {
echo '<table border=\'0\'><tr>';
if ($sosa > 0) {
- self::printSosaNumber($sosa * 4 + 1, $hfam->getWife()->getXref(), 'down');
+ self::printSosaNumber($sosa * 4 + 1, $hfam->getWife()->getXref(), 'arrow-down');
}
if (!empty($gparid) && $hfam->getWife()->getXref() == $gparid) {
- self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.');
+ self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.', '', 'arrow-up');
}
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getWife(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getWife());
echo '</td></tr></table>';
} elseif ($hfam && !$hfam->getWife()) {
// Empty box for grandmother
echo '<table border="0"><tr>';
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getWife(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getWife());
echo '</td></tr></table>';
}
echo '</td>';
@@ -195,12 +182,12 @@ class FunctionsCharts {
echo '<table><tr>';
if ($parid) {
if ($wife->getXref() == $parid) {
- self::printSosaNumber($label);
+ self::printSosaNumber($label, '', 'arrow-up');
} else {
- self::printSosaNumber($label, '', 'blank');
+ self::printSosaNumber($label, '', 'arrow-up');
}
} elseif ($sosa) {
- self::printSosaNumber($sosa * 2 + 1);
+ self::printSosaNumber($sosa * 2 + 1, '', 'arrow-up');
}
if ($wife->isPendingAddtion()) {
echo '<td class="facts_value new">';
@@ -209,7 +196,7 @@ class FunctionsCharts {
} else {
echo '<td>';
}
- FunctionsPrint::printPedigreePerson($wife, $show_full);
+ FunctionsPrint::printPedigreePerson($wife);
echo '</td></tr></table>';
echo '</td>';
// wife’s parents
@@ -222,26 +209,27 @@ class FunctionsCharts {
if ($hfam && $hfam->getHusband()) {
echo '<table><tr>';
if ($sosa > 0) {
- self::printSosaNumber($sosa * 4 + 2, $hfam->getHusband()->getXref(), 'down');
+ self::printSosaNumber($sosa * 4 + 2, $hfam->getHusband()->getXref(), 'arrow-down');
}
if (!empty($gparid) && $hfam->getHusband()->getXref() == $gparid) {
- self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.');
+ self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.', '', 'arrow-up');
}
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getHusband(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getHusband());
echo '</td></tr></table>';
} elseif ($hfam && !$hfam->getHusband()) {
// Empty box for grandfather
echo '<table border="0"><tr>';
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getHusband(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getHusband());
echo '</td></tr></table>';
}
echo '</td>';
}
if ($hfam && ($sosa != -1)) {
echo '<td rowspan="2">';
- self::printUrlArrow(($sosa == 0 ? '?famid=' . $hfam->getXref() . '&amp;ged=' . $hfam->getTree()->getNameUrl() : '#' . $hfam->getXref()), $hfam->getXref(), 1);
+ echo FontAwesome::linkIcon('arrow-end', $hfam->getXref(), ['href' => ($sosa == 0 ? '?famid=' . $hfam->getXref() . '&amp;ged=' . $hfam->getTree()->getNameUrl() : '#' . $hfam->getXref())]);
+
echo '</td>';
}
if ($hfam) {
@@ -250,19 +238,19 @@ class FunctionsCharts {
if ($hfam && $hfam->getWife()) {
echo '<table><tr>';
if ($sosa > 0) {
- self::printSosaNumber($sosa * 4 + 3, $hfam->getWife()->getXref(), 'down');
+ self::printSosaNumber($sosa * 4 + 3, $hfam->getWife()->getXref(), 'arrow-down');
}
if (!empty($gparid) && $hfam->getWife()->getXref() == $gparid) {
- self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.');
+ self::printSosaNumber(trim(substr($label, 0, -3), '.') . '.', 'arrow-up');
}
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getWife(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getWife());
echo '</td></tr></table>';
} elseif ($hfam && !$hfam->getWife()) {
// Empty box for grandmother
echo '<table border="0"><tr>';
echo '<td>';
- FunctionsPrint::printPedigreePerson($hfam->getWife(), $show_full);
+ FunctionsPrint::printPedigreePerson($hfam->getWife());
echo '</td></tr></table>';
}
echo '</td>';
@@ -278,15 +266,9 @@ class FunctionsCharts {
* @param int $sosa child sosa number
* @param string $label indi label (descendancy booklet)
* @param int $show_cousins display cousins on chart
- * @param bool $show_full large or small box
*/
- public static function printFamilyChildren(Family $family, $childid = '', $sosa = 0, $label = '', $show_cousins = 0, $show_full = true) {
-
- if ($show_full) {
- $bheight = Theme::theme()->parameter('chart-box-y');
- } else {
- $bheight = Theme::theme()->parameter('compact-chart-box-y');
- }
+ public static function printFamilyChildren(Family $family, $childid = '', $sosa = 0, $label = '', $show_cousins = 0) {
+ $bheight = Theme::theme()->parameter('chart-box-y');
$pbheight = $bheight + 14;
@@ -307,9 +289,9 @@ class FunctionsCharts {
if ($sosa == 0 && Auth::isEditor($family->getTree())) {
echo '<br>';
- echo "<a href=\"#\" onclick=\"return add_child_to_family('", $family->getXref(), "', 'U');\">" . I18N::translate('Add a child to this family') . '</a>';
- echo ' <a class="icon-sex_m_15x15" href="#" onclick="return add_child_to_family(\'', $family->getXref(), '\', \'M\');" title="', I18N::translate('son'), '"></a>';
- echo ' <a class="icon-sex_f_15x15" href="#" onclick="return add_child_to_family(\'', $family->getXref(), '\', \'F\');" title="', I18N::translate('daughter'), '"></a>';
+ echo '<a href="edit_interface.php?action=add_child_to_family&amp;ged=' . $family->getTree()->getNameHtml() .'&amp;xref=' . $family->getXref() . '&amp;gender=U">' . I18N::translate('Add a child to this family') . '</a>';
+ echo ' <a class="icon-sex_m_15x15" href="edit_interface.php?action=add_child_to_family&amp;ged=' . $family->getTree()->getNameHtml() .'&amp;xref=' . $family->getXref() . '&amp;gender=M" title="', I18N::translate('son'), '"></a>';
+ echo ' <a class="icon-sex_f_15x15" href="edit_interface.php?action=add_child_to_family&amp;ged=' . $family->getTree()->getNameHtml() .'&amp;xref=' . $family->getXref() . '&amp;gender=F" title="', I18N::translate('daughter'), '"></a>';
echo '<br><br>';
}
echo '</td>';
@@ -324,11 +306,11 @@ class FunctionsCharts {
echo '<tr>';
if ($sosa != 0) {
if ($child->getXref() == $childid) {
- self::printSosaNumber($sosa, $childid);
+ self::printSosaNumber($sosa, $childid, 'arrow-up');
} elseif (empty($label)) {
- self::printSosaNumber('');
+ self::printSosaNumber('', '', 'arrow-up');
} else {
- self::printSosaNumber($label . ($nchi++) . '.');
+ self::printSosaNumber($label . ($nchi++) . '.', '', 'arrow-up');
}
}
if ($child->isPendingAddtion()) {
@@ -338,7 +320,7 @@ class FunctionsCharts {
} else {
echo '<td>';
}
- FunctionsPrint::printPedigreePerson($child, $show_full);
+ FunctionsPrint::printPedigreePerson($child);
echo '</td>';
if ($sosa != 0) {
// loop for all families where current child is a spouse
@@ -384,7 +366,7 @@ class FunctionsCharts {
echo '–', $div->getDate()->minimumDate()->format('%Y');
}
}
- echo '<br><img width="100%" class="line5" height="3" src="' . Theme::theme()->parameter('image-hline') . '" alt="">';
+ echo '<br><img width="100%" class="line5" height="3" src="' . Theme::theme()->parameter('image-hline') . '">';
echo '</td>';
// spouse information
echo '<td style="vertical-align: center;';
@@ -393,11 +375,11 @@ class FunctionsCharts {
} else {
echo '">';
}
- FunctionsPrint::printPedigreePerson($spouse, $show_full);
+ FunctionsPrint::printPedigreePerson($spouse);
echo '</td>';
// cousins
if ($show_cousins) {
- self::printCousins($famid_child, $show_full);
+ self::printCousins($famid_child);
}
}
}
@@ -423,9 +405,8 @@ class FunctionsCharts {
* @param string $parid parent ID (descendancy booklet)
* @param string $gparid gd-parent ID (descendancy booklet)
* @param int $show_cousins display cousins on chart
- * @param bool $show_full large or small box
*/
- public static function printSosaFamily($famid, $childid, $sosa, $label = '', $parid = '', $gparid = '', $show_cousins = 0, $show_full = true) {
+ public static function printSosaFamily($famid, $childid, $sosa, $label = '', $parid = '', $gparid = '', $show_cousins = 0) {
global $WT_TREE;
echo '<hr>';
@@ -433,44 +414,15 @@ class FunctionsCharts {
if (!empty($famid)) {
echo '<a name="', $famid, '"></a>';
}
- self::printFamilyParents(Family::getInstance($famid, $WT_TREE), $sosa, $label, $parid, $gparid, $show_full);
+ self::printFamilyParents(Family::getInstance($famid, $WT_TREE), $sosa, $label, $parid, $gparid);
echo '<br>';
echo '<table><tr><td>';
- self::printFamilyChildren(Family::getInstance($famid, $WT_TREE), $childid, $sosa, $label, $show_cousins, $show_full);
+ self::printFamilyChildren(Family::getInstance($famid, $WT_TREE), $childid, $sosa, $label, $show_cousins);
echo '</td></tr></table>';
echo '<br>';
}
/**
- * print an arrow to a new url
- *
- * @param string $url target url
- * @param string $label arrow label
- * @param int $dir arrow direction 0=left 1=right 2=up 3=down (default=2)
- */
- public static function printUrlArrow($url, $label, $dir = 2) {
- if ($url === '') {
- return;
- }
-
- // arrow direction
- $adir = $dir;
- if (I18N::direction() === 'rtl' && $dir === 0) {
- $adir = 1;
- }
- if (I18N::direction() === 'rtl' && $dir === 1) {
- $adir = 0;
- }
-
- // arrow style 0 1 2 3
- $array_style = ['icon-larrow', 'icon-rarrow', 'icon-uarrow', 'icon-darrow'];
- $astyle = $array_style[$adir];
-
- // Labels include people’s names, which may contain markup
- echo '<a href="' . $url . '" title="' . strip_tags($label) . '" class="' . $astyle . '"></a>';
- }
-
- /**
* builds and returns sosa relationship name in the active language
*
* @param string $sosa sosa number
@@ -495,22 +447,15 @@ class FunctionsCharts {
/**
* print cousins list
*
- * @param string $famid family ID
- * @param bool $show_full large or small box
+ * @param string $famid family ID
*/
- public static function printCousins($famid, $show_full = true) {
+ public static function printCousins($famid) {
global $WT_TREE;
- if ($show_full) {
- $bheight = Theme::theme()->parameter('chart-box-y');
- } else {
- $bheight = Theme::theme()->parameter('compact-chart-box-y');
- }
-
+ $bheight = Theme::theme()->parameter('chart-box-y');
$family = Family::getInstance($famid, $WT_TREE);
$fchildren = $family->getChildren();
-
- $kids = count($fchildren);
+ $kids = count($fchildren);
echo '<td>';
if ($kids) {
@@ -532,7 +477,7 @@ class FunctionsCharts {
echo ' style="padding-left: 2px;"';
}
echo ' src="', Theme::theme()->parameter('image-hline'), '"></td><td>';
- FunctionsPrint::printPedigreePerson($fchil, $show_full);
+ FunctionsPrint::printPedigreePerson($fchil);
echo '</td></tr>';
if ($i < $ctkids) {
echo '<tr>';
diff --git a/app/Functions/FunctionsDb.php b/app/Functions/FunctionsDb.php
index 85a09fff25..c69c530fdd 100644
--- a/app/Functions/FunctionsDb.php
+++ b/app/Functions/FunctionsDb.php
@@ -82,10 +82,8 @@ class FunctionsDb {
foreach ($rows as $row) {
$list[] = Source::getInstance($row->xref, $tree, $row->gedcom);
}
- $list = array_filter($list, function (Source $x) { return $x->canShowName(); });
- usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
- return $list;
+ return array_filter($list, function (Source $x) { return $x->canShowName(); });
}
/**
@@ -106,10 +104,8 @@ class FunctionsDb {
foreach ($rows as $row) {
$list[] = Repository::getInstance($row->xref, $tree, $row->gedcom);
}
- $list = array_filter($list, function (Repository $x) { return $x->canShowName(); });
- usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
- return $list;
+ return array_filter($list, function (Repository $x) { return $x->canShowName(); });
}
/**
diff --git a/app/Functions/FunctionsEdit.php b/app/Functions/FunctionsEdit.php
index 9f57670e44..feb2d3eab1 100644
--- a/app/Functions/FunctionsEdit.php
+++ b/app/Functions/FunctionsEdit.php
@@ -16,6 +16,7 @@
namespace Fisharebest\Webtrees\Functions;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Census\Census;
use Fisharebest\Webtrees\Census\CensusOfCzechRepublic;
use Fisharebest\Webtrees\Census\CensusOfDenmark;
@@ -30,6 +31,7 @@ use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeAdop;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeName;
use Fisharebest\Webtrees\GedcomCode\GedcomCodePedi;
@@ -43,9 +45,12 @@ use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Media;
use Fisharebest\Webtrees\Module;
+use Fisharebest\Webtrees\Module\CensusAssistantModule;
use Fisharebest\Webtrees\Note;
use Fisharebest\Webtrees\Repository;
+use Fisharebest\Webtrees\Select2;
use Fisharebest\Webtrees\Source;
+use Fisharebest\Webtrees\Tree;
use Fisharebest\Webtrees\User;
use Rhumsaa\Uuid\Uuid;
@@ -54,118 +59,104 @@ use Rhumsaa\Uuid\Uuid;
*/
class FunctionsEdit {
/**
- * Create a <select> control for a form.
+ * Function edit_language_checkboxes
*
- * @param string $name
- * @param string[] $values
- * @param string|null $empty
- * @param string $selected
- * @param string $extra
+ * @param string $parameter_name
+ * @param array $accepted_languages
*
* @return string
*/
- public static function selectEditControl($name, $values, $empty, $selected, $extra = '') {
- if (is_null($empty)) {
- $html = '';
- } else {
- if (empty($selected)) {
- $html = '<option value="" selected>' . Filter::escapeHtml($empty) . '</option>';
- } else {
- $html = '<option value="">' . Filter::escapeHtml($empty) . '</option>';
- }
- }
- // A completely empty list would be invalid, and break various things
- if (empty($values) && empty($html)) {
- $html = '<option value=""></option>';
- }
- foreach ($values as $key => $value) {
- // PHP array keys are cast to integers! Cast them back
- if ((string) $key === (string) $selected) {
- $html .= '<option value="' . Filter::escapeHtml($key) . '" selected dir="auto">' . Filter::escapeHtml($value) . '</option>';
- } else {
- $html .= '<option value="' . Filter::escapeHtml($key) . '" dir="auto">' . Filter::escapeHtml($value) . '</option>';
- }
- }
- if (substr($name, -2) === '[]') {
- // id attribute is not used for arrays
- return '<select name="' . $name . '" ' . $extra . '>' . $html . '</select>';
- } else {
- return '<select id="' . $name . '" name="' . $name . '" ' . $extra . '>' . $html . '</select>';
+ public static function editLanguageCheckboxes($parameter_name, $accepted_languages) {
+ $html = '';
+ foreach (I18N::activeLocales() as $locale) {
+ $html .= '<div class="checkbox">';
+ $html .= '<label title="' . $locale->languageTag() . '">';
+ $html .= '<input type="checkbox" name="' . $parameter_name . '[]" value="' . $locale->languageTag() . '"';
+ $html .= in_array($locale->languageTag(), $accepted_languages) ? ' checked>' : '>';
+ $html .= $locale->endonym();
+ $html .= '</label>';
+ $html .= '</div>';
}
+
+ return $html;
}
/**
- * Create a set of radio buttons for a form
+ * A list of access levels (e.g. for an edit control).
*
- * @param string $name The ID for the form element
- * @param string[] $values Array of value=>display items
- * @param string $selected The currently selected item
- * @param string $extra Additional markup for the label
+ * @return string[]
+ */
+ public static function optionsAccessLevels() {
+ return [
+ Auth::PRIV_PRIVATE => I18N::translate('Show to visitors'),
+ Auth::PRIV_USER => I18N::translate('Show to members'),
+ Auth::PRIV_NONE => I18N::translate('Show to managers'),
+ Auth::PRIV_HIDE => I18N::translate('Hide from everyone'),
+ ];
+ }
+
+ /**
+ * A list of active languages (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function radioButtons($name, $values, $selected, $extra = '') {
- $html = '';
- foreach ($values as $key => $value) {
- $html .=
- '<label ' . $extra . '>' .
- '<input type="radio" name="' . $name . '" value="' . Filter::escapeHtml($key) . '"';
- // PHP array keys are cast to integers! Cast them back
- if ((string) $key === (string) $selected) {
- $html .= ' checked';
- }
- $html .= '>' . Filter::escapeHtml($value) . '</label>';
+ public static function optionsActiveLanguages() {
+ $languages = [];
+ foreach (I18N::activeLocales() as $locale) {
+ $languages[$locale->languageTag()] = $locale->endonym();
}
- return $html;
+ return $languages;
}
/**
- * Print an edit control for a Yes/No field
+ * A list of calendar conversions (e.g. for an edit control).
*
- * @param string $name
- * @param bool $selected
- * @param string $extra
- *
- * @return string
+ * @return string[]
*/
- public static function editFieldYesNo($name, $selected = false, $extra = '') {
- return self::radioButtons(
- $name, [I18N::translate('no'), I18N::translate('yes')], $selected, $extra
- );
+ public static function optionsCalendarConversions() {
+ return ['none' => I18N::translate('No calendar conversion')] + Date::calendarNames();
}
/**
- * Print an edit control for a checkbox.
- *
- * @param string $name
- * @param bool $is_checked
- * @param string $extra
+ * A list of contact methods (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function checkbox($name, $is_checked = false, $extra = '') {
- return '<input type="checkbox" name="' . $name . '" value="1" ' . ($is_checked ? 'checked ' : '') . $extra . '>';
+ public static function optionsContactMethods() {
+ return [
+ 'messaging' => I18N::translate('Internal messaging'),
+ 'messaging2' => I18N::translate('Internal messaging with emails'),
+ 'messaging3' => I18N::translate('webtrees sends emails with no storage'),
+ 'mailto' => I18N::translate('Mailto link'),
+ 'none' => I18N::translate('No contact'),
+ ];
}
/**
- * Print an edit control for a checkbox, with a hidden field to store one of the two states.
- * By default, a checkbox is either set, or not sent.
- * This function gives us a three options, set, unset or not sent.
- * Useful for dynamically generated forms where we don't know what elements are present.
+ * A list of hide/show options (e.g. for an edit control).
*
- * @param string $name
- * @param int $is_checked 0 or 1
- * @param string $extra
+ * @return string[]
+ */
+ public static function optionsHideShow() {
+ return [
+ '0' => I18N::translate('no'),
+ '1' => I18N::translate('yes'),
+ ];
+ }
+
+ /**
+ * A list of installed languages (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function twoStateCheckbox($name, $is_checked = 0, $extra = '') {
- return
- '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . ($is_checked ? 1 : 0) . '">' .
- '<input type="checkbox" name="' . $name . '-GUI-ONLY" value="1"' .
- ($is_checked ? ' checked' : '') .
- ' onclick="document.getElementById(\'' . $name . '\').value=(this.checked?1:0);" ' . $extra . '>';
+ public static function optionsInstalledLanguages() {
+ $languages = [];
+ foreach (I18N::installedLocales() as $locale) {
+ $languages[$locale->languageTag()] = $locale->endonym();
+ }
+
+ return $languages;
}
/**
@@ -187,296 +178,352 @@ class FunctionsEdit {
}
/**
- * Function edit_language_checkboxes
+ * A list of no/yes options (e.g. for an edit control).
*
- * @param string $parameter_name
- * @param array $accepted_languages
+ * @return string[]
+ */
+ public static function optionsNoYes() {
+ return [
+ '0' => I18N::translate('no'),
+ '1' => I18N::translate('yes'),
+ ];
+ }
+
+ /**
+ * A list of GEDCOM relationships (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function editLanguageCheckboxes($parameter_name, $accepted_languages) {
- $html = '';
- foreach (I18N::activeLocales() as $locale) {
- $html .= '<div class="checkbox">';
- $html .= '<label title="' . $locale->languageTag() . '">';
- $html .= '<input type="checkbox" name="' . $parameter_name . '[]" value="' . $locale->languageTag() . '"';
- $html .= in_array($locale->languageTag(), $accepted_languages) ? ' checked>' : '>';
- $html .= $locale->endonym();
- $html .= '</label>';
- $html .= '</div>';
+ public static function optionsRelationships($relationship) {
+ $relationships = GedcomCodeRela::getValues();
+ // The user is allowed to specify values that aren't in the list.
+ if (!array_key_exists($relationship, $relationships)) {
+ $relationships[$relationship] = I18N::translate($relationship);
}
- return $html;
+ return $relationships;
}
/**
- * Print an edit control for access level.
- *
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * A list of registration rules (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function editFieldAccessLevel($name, $selected = '', $extra = '') {
- $ACCESS_LEVEL = [
- Auth::PRIV_PRIVATE => I18N::translate('Show to visitors'),
- Auth::PRIV_USER => I18N::translate('Show to members'),
- Auth::PRIV_NONE => I18N::translate('Show to managers'),
- Auth::PRIV_HIDE => I18N::translate('Hide from everyone'),
+ public static function optionsRegistrationRules() {
+ return [
+ 0 => I18N::translate('No predefined text'),
+ 1 => I18N::translate('Predefined text that states all users can request a user account'),
+ 2 => I18N::translate('Predefined text that states admin will decide on each request for a user account'),
+ 3 => I18N::translate('Predefined text that states only family members can request a user account'),
+ 4 => I18N::translate('Choose user defined welcome text typed below'),
];
-
- return self::selectEditControl($name, $ACCESS_LEVEL, null, $selected, $extra);
}
/**
- * Print an edit control for a RESN field.
+ * A list of GEDCOM restrictions (e.g. for an edit control).
*
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * @param bool $include_empty
*
- * @return string
+ * @return string[]
*/
- public static function editFieldRestriction($name, $selected = '', $extra = '') {
- $RESN = [
- '' => '',
+ public static function optionsRestrictions($include_empty) {
+ $options = [
'none' => I18N::translate('Show to visitors'), // Not valid GEDCOM, but very useful
'privacy' => I18N::translate('Show to members'),
'confidential' => I18N::translate('Show to managers'),
'locked' => I18N::translate('Only managers can edit'),
];
- return self::selectEditControl($name, $RESN, null, $selected, $extra);
+ if ($include_empty) {
+ $options = ['' => ''] + $options;
+ }
+
+ return $options;
}
/**
- * Print an edit control for a contact method field.
- *
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * A list mail transport options (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function editFieldContact($name, $selected = '', $extra = '') {
- // Different ways to contact the users
- $CONTACT_METHODS = [
- 'messaging' => I18N::translate('Internal messaging'),
- 'messaging2' => I18N::translate('Internal messaging with emails'),
- 'messaging3' => I18N::translate('webtrees sends emails with no storage'),
- 'mailto' => I18N::translate('Mailto link'),
- 'none' => I18N::translate('No contact'),
+ public static function optionsMailTransports() {
+ return [
+ 'internal' => I18N::translate('Use PHP mail to send messages'),
+ 'external' => I18N::translate('Use SMTP to send messages'),
];
+ }
- return self::selectEditControl($name, $CONTACT_METHODS, null, $selected, $extra);
+ /**
+ * A list SSL modes (e.g. for an edit control).
+ *
+ * @return string[]
+ */
+ public static function optionsSslModes() {
+ return [
+ 'none' => I18N::translate('none'),
+ /* I18N: Secure Sockets Layer - a secure communications protocol*/ 'ssl' => I18N::translate('ssl'),
+ /* I18N: Transport Layer Security - a secure communications protocol */ 'tls' => I18N::translate('tls'),
+ ];
}
/**
- * Print an edit control for a language field.
+ * A list of temple options (e.g. for an edit control).
*
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * @return string[]
+ */
+ public static function optionsTemples() {
+ return ['' => I18N::translate('No temple - living ordinance')] + GedcomCodeTemp::templeNames();
+ }
+
+ /**
+ * A list of user options (e.g. for an edit control).
*
- * @return string
+ * @return string[]
*/
- public static function editFieldLanguage($name, $selected = '', $extra = '') {
- $languages = [];
- foreach (I18N::activeLocales() as $locale) {
- $languages[$locale->languageTag()] = $locale->endonym();
+ public static function optionsUsers() {
+ $options = ['' => '-'];
+
+ foreach (User::all() as $user) {
+ $options[$user->getUserName()] = $user->getRealName() . ' - ' . $user->getUserName();
}
- return self::selectEditControl($name, $languages, null, $selected, $extra);
+ return $options;
}
/**
- * Print an edit control for a range of integers.
+ * Create a form control to select a family.
*
- * @param string $name
- * @param string $selected
- * @param int $min
- * @param int $max
- * @param string $extra
+ * @param Family|null $family
+ * @param string[] $attributes
*
* @return string
*/
- public static function editFieldInteger($name, $selected = '', $min, $max, $extra = '') {
- $array = [];
- for ($i = $min; $i <= $max; ++$i) {
- $array[$i] = I18N::number($i);
+ public static function formControlFamily(Family $family = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($family !== null) {
+ $value = $family->getXref();
+ $options = [$value => Select2::familyValue($family)];
}
- return self::selectEditControl($name, $array, null, $selected, $extra);
+ return Bootstrap4::select($options, $value, Select2::familyConfig() + $attributes);
}
/**
- * Print an edit control for a username.
+ * Create a form control to select a flag.
*
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * @param string $flag
+ * @param string[] $attributes
*
* @return string
*/
- public static function editFieldUsername($name, $selected = '', $extra = '') {
- $users = [];
- foreach (User::all() as $user) {
- $users[$user->getUserName()] = $user->getRealName() . ' - ' . $user->getUserName();
- }
- // The currently selected user may not exist
- if ($selected && !array_key_exists($selected, $users)) {
- $users[$selected] = $selected;
+ public static function formControlFlag($flag, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($flag !== '') {
+ $value = $flag;
+ $options = [$value => Select2::flagValue($flag)];
}
- return self::selectEditControl($name, $users, '-', $selected, $extra);
+ return Bootstrap4::select($options, $value, Select2::flagConfig() + $attributes);
}
/**
- * Print an edit control for a ADOP field.
+ * Create a form control to select an individual.
*
- * @param string $name
- * @param string $selected
- * @param string $extra
* @param Individual|null $individual
+ * @param string[] $attributes
*
* @return string
*/
- public static function editFieldAdoption($name, $selected = '', $extra = '', Individual $individual = null) {
- return self::selectEditControl($name, GedcomCodeAdop::getValues($individual), null, $selected, $extra);
+ public static function formControlIndividual(Individual $individual = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($individual !== null) {
+ $value = $individual->getXref();
+ $options = [$value => Select2::individualValue($individual)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::individualConfig() + $attributes);
}
/**
- * Print an edit control for a PEDI field.
+ * Create a form control to select a media object.
*
- * @param string $name
- * @param string $selected
- * @param string $extra
- * @param Individual|null $individual
+ * @param Media|null $media
+ * @param string[] $attributes
*
* @return string
*/
- public static function editFieldPedigree($name, $selected = '', $extra = '', Individual $individual = null) {
- return self::selectEditControl($name, GedcomCodePedi::getValues($individual), '', $selected, $extra);
+ public static function formControlMediaObject(Media $media = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($media !== null) {
+ $value = $media->getXref();
+ $options = [$value => Select2::mediaObjectValue($media)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::mediaObjectConfig() + $attributes);
}
/**
- * Print an edit control for a NAME TYPE field.
+ * Create a form control to select a note.
*
- * @param string $name
- * @param string $selected
- * @param string $extra
- * @param Individual|null $individual
+ * @param Note|null $note
+ * @param string[]|null $attributes
*
* @return string
*/
- public static function editFieldNameType($name, $selected = '', $extra = '', Individual $individual = null) {
- return self::selectEditControl($name, GedcomCodeName::getValues($individual), '', $selected, $extra);
+ public static function formControlNote(Note $note = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($note !== null) {
+ $value = $note->getXref();
+ $options = [$value => Select2::noteValue($note)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::noteConfig() + $attributes);
}
/**
- * Print an edit control for a RELA field.
+ * Create a form control to select a place.
*
- * @param string $name
- * @param string $selected
- * @param string $extra
+ * @param string $place
+ * @param string[] $attributes
*
* @return string
*/
- public static function editFieldRelationship($name, $selected = '', $extra = '') {
- $rela_codes = GedcomCodeRela::getValues();
- // The user is allowed to specify values that aren't in the list.
- if (!array_key_exists($selected, $rela_codes)) {
- $rela_codes[$selected] = I18N::translate($selected);
+ public static function formControlPlace($place, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($place !== '') {
+ $options = [$place => $place];
}
- return self::selectEditControl($name, $rela_codes, '', $selected, $extra);
+ return Bootstrap4::select($options, $value, Select2::placeConfig() + $attributes);
}
/**
- * Remove all links from $gedrec to $xref, and any sub-tags.
+ * Create a form control to select a repository.
*
- * @param string $gedrec
- * @param string $xref
+ * @param Repository|null $repository
+ * @param string[] $attributes
*
* @return string
*/
- public static function removeLinks($gedrec, $xref) {
- $gedrec = preg_replace('/\n1 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[2-9].*)*/', '', $gedrec);
- $gedrec = preg_replace('/\n2 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[3-9].*)*/', '', $gedrec);
- $gedrec = preg_replace('/\n3 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[4-9].*)*/', '', $gedrec);
- $gedrec = preg_replace('/\n4 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[5-9].*)*/', '', $gedrec);
- $gedrec = preg_replace('/\n5 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[6-9].*)*/', '', $gedrec);
+ public static function formControlRepository(Repository $repository = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
- return $gedrec;
+ if ($repository !== null) {
+ $value = $repository->getXref();
+ $options = [$value => Select2::repositoryValue($repository)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::repositoryConfig() + $attributes);
}
/**
- * Generates javascript code for calendar popup in user’s language.
+ * Create a form control to select a source.
*
- * @param string $id
+ * @param Source|null $source
+ * @param string[] $attributes
*
* @return string
*/
- public static function printCalendarPopup($id) {
- return
- ' <a href="#" onclick="cal_toggleDate(\'caldiv' . $id . '\', \'' . $id . '\'); return false;" class="icon-button_calendar" title="' . I18N::translate('Select a date') . '"></a>' .
- '<div id="caldiv' . $id . '" style="position:absolute;visibility:hidden;background-color:white;z-index:1000;"></div>';
+ public static function formControlSource(Source $source = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($source !== null) {
+ $value = $source->getXref();
+ $options = [$value => Select2::sourceValue($source)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::sourceConfig() + $attributes);
}
/**
- * An HTML link to create a new media object.
+ * Create a form control to select a submitter.
*
- * @param string $element_id
+ * @param GedcomRecord|null $submitter
+ * @param string[] $attributes
*
* @return string
*/
- public static function printAddNewMediaLink($element_id) {
- return '<a href="#" onclick="pastefield=document.getElementById(\'' . $element_id . '\'); window.open(\'addmedia.php?action=showmediaform\', \'_blank\', edit_window_specs); return false;" class="icon-button_addmedia" title="' . I18N::translate('Create a media object') . '"></a>';
+ public static function formControlSubmitter(GedcomRecord $submitter = null, array $attributes = []) {
+ $value = '';
+ $options = ['' => ''];
+
+ if ($submitter !== null) {
+ $value = $submitter->getXref();
+ $options = [$value => Select2::submitterValue($submitter)];
+ }
+
+ return Bootstrap4::select($options, $value, Select2::submitterConfig() + $attributes);
}
/**
- * An HTML link to create a new repository.
+ * Remove all links from $gedrec to $xref, and any sub-tags.
*
- * @param string $element_id
+ * @param string $gedrec
+ * @param string $xref
*
* @return string
*/
- public static function printAddNewRepositoryLink($element_id) {
- return '<a href="#" onclick="addnewrepository(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addrepository" title="' . I18N::translate('Create a repository') . '"></a>';
+ public static function removeLinks($gedrec, $xref) {
+ $gedrec = preg_replace('/\n1 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[2-9].*)*/', '', $gedrec);
+ $gedrec = preg_replace('/\n2 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[3-9].*)*/', '', $gedrec);
+ $gedrec = preg_replace('/\n3 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[4-9].*)*/', '', $gedrec);
+ $gedrec = preg_replace('/\n4 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[5-9].*)*/', '', $gedrec);
+ $gedrec = preg_replace('/\n5 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[6-9].*)*/', '', $gedrec);
+
+ return $gedrec;
}
/**
- * An HTML link to create a new note.
+ * Input addon to generate a calendar widget.
*
- * @param string $element_id
+ * @param string $id
*
* @return string
*/
- public static function printAddNewNoteLink($element_id) {
- return '<a href="#" onclick="addnewnote(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addnote" title="' . I18N::translate('Create a shared note') . '"></a>';
+ public static function inputAddonCalendar($id) {
+ return
+ '<span class="input-group-addon">' .
+ FontAwesome::linkIcon('calendar', I18N::translate('Select a date'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return calendarWidget("caldiv' . $id . '", "' . $id . '");']) .
+ '</span>';
}
/**
- * An HTML link to edit a note.
+ * Input addon to select a special characterr using a virtual keyboard
*
- * @param string $note_id
+ * @param string $id
*
* @return string
*/
- public static function printEditNoteLink($note_id) {
- return '<a href="#" onclick="edit_note(\'' . $note_id . '\'); return false;" class="icon-button_note" title="' . I18N::translate('Edit the shared note') . '"></a>';
+ public static function inputAddonKeyboard($id) {
+ return
+ '<span class="input-group-addon">' .
+ FontAwesome::linkIcon('keyboard', I18N::translate('Find a special character'), ['class' => 'btn btn-link wt-osk-trigger', 'href' => '#', 'data-id' => $id]) .
+ '</span>';
}
/**
- * An HTML link to create a new source.
+ * Input addon to generate a help link.
*
- * @param string $element_id
+ * @param string $fact
*
* @return string
*/
- public static function printAddNewSourceLink($element_id) {
- return '<a href="#" onclick="addnewsource(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addsource" title="' . I18N::translate('Create a source') . '"></a>';
+ public static function inputAddonHelp($fact) {
+ return '<span class="input-group-addon">' . FunctionsPrint::helpLink($fact) . '</span>';
}
/**
@@ -499,40 +546,35 @@ class FunctionsEdit {
* @return string
*/
public static function addSimpleTag($tag, $upperlevel = '', $label = '', $extra = null, Individual $person = null) {
- global $tags, $main_fact, $xref, $bdm, $action, $WT_TREE;
+ global $tags, $xref, $bdm, $action, $WT_TREE;
- // Keep track of SOUR fields, so we can reference them in subsequent PAGE fields.
- static $source_element_id;
+ // Some form fields need access to previous form fields.
+ static $previous_ids = ['SOUR' => '', 'PLAC' => ''];
- $subnamefacts = ['NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX', '_MARNM_SURN'];
preg_match('/^(?:(\d+) (' . WT_REGEX_TAG . ') ?(.*))/', $tag, $match);
list(, $level, $fact, $value) = $match;
- $level = (int) $level;
- // element name : used to POST data
- if ($level === 0) {
+ if ($level === '0') {
if ($upperlevel) {
- $element_name = $upperlevel . '_' . $fact;
+ $name = $upperlevel . '_' . $fact;
} else {
- $element_name = $fact;
+ $name = $fact;
}
} else {
- $element_name = 'text[]';
- }
- if ($level === 1) {
- $main_fact = $fact;
+ $name = 'text[]';
}
- // element id : used by javascript functions
- if ($level === 0) {
- $element_id = $fact;
+ if ($level === '0') {
+ $id = $fact;
} else {
- $element_id = $fact . Uuid::uuid4();
+ $id = $fact . Uuid::uuid4();
}
if ($upperlevel) {
- $element_id = $upperlevel . '_' . $fact . Uuid::uuid4();
+ $id = $upperlevel . '_' . $fact . Uuid::uuid4();
}
+ $previous_ids[$fact] = $id;
+
// field value
$islink = (substr($value, 0, 1) === '@' && substr($value, 0, 2) !== '@#');
if ($islink) {
@@ -549,18 +591,27 @@ class FunctionsEdit {
$fact = 'NOTE';
}
- // label
- echo '<tr id="', $element_id, '_tr"';
- if ($fact === 'DATA' || $fact === 'MAP' || ($fact === 'LATI' || $fact === 'LONG') && $value === '') {
- echo ' style="display:none;"';
+ $row_class = 'form-group row';
+ switch ($fact) {
+ case 'DATA':
+ case 'MAP':
+ // These GEDCOM tags should have no data, just child tags.
+ if ($value === '') {
+ $row_class .= ' hidden-xs-up';
+ }
+ break;
+ case 'LATI':
+ case 'LONG':
+ // Indicate that this row is a child of a previous row, so we can expand/collapse them.
+ $row_class .= ' child_of_' . $previous_ids['PLAC'];
+ if ($value === '') {
+ $row_class .= ' collapse';
+ }
+ break;
}
- echo '>';
- if (in_array($fact, $subnamefacts) || $fact === 'LATI' || $fact === 'LONG') {
- echo '<td class="optionbox wrap width25">';
- } else {
- echo '<td class="descriptionbox wrap width25">';
- }
+ echo '<div class="' . $row_class . '">';
+ echo '<label class="col-sm-3 col-form-label" for="' . $id . '">';
// tag name
if ($label) {
@@ -582,9 +633,6 @@ class FunctionsEdit {
echo FunctionsPrint::helpLink($fact);
}
break;
- case 'DATE':
- case 'PLAC':
- case 'RESN':
case 'ROMN':
case 'SURN':
case '_HEB':
@@ -593,25 +641,15 @@ class FunctionsEdit {
}
}
// tag level
- if ($level > 0) {
+ if ($level !== '0') {
echo '<input type="hidden" name="glevels[]" value="', $level, '">';
echo '<input type="hidden" name="islink[]" value="', $islink, '">';
echo '<input type="hidden" name="tag[]" value="', $fact, '">';
}
- echo '</td>';
+ echo '</label>';
// value
- echo '<td class="optionbox wrap">';
-
- // retrieve linked NOTE
- if ($fact === 'NOTE' && $islink) {
- $note1 = Note::getInstance($value, $WT_TREE);
- if ($note1) {
- $noterec = $note1->getGedcom();
- preg_match('/' . $value . '/i', $noterec, $notematch);
- $value = $notematch[0];
- }
- }
+ echo '<div class="col-sm-9">';
// Show names for spouses in MARR/HUSB/AGE and MARR/WIFE/AGE
if ($fact === 'HUSB' || $fact === 'WIFE') {
@@ -628,74 +666,124 @@ class FunctionsEdit {
}
if (in_array($fact, Config::emptyFacts()) && ($value === '' || $value === 'Y' || $value === 'y')) {
- echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" value="', $value, '">';
- if ($level <= 1) {
- echo '<input type="checkbox" ';
- if ($value) {
- echo 'checked';
- }
- echo ' onclick="document.getElementById(\'' . $element_id . '\').value = (this.checked) ? \'Y\' : \'\';">';
- echo I18N::translate('yes');
- }
+ echo '<input type="hidden" id="', $id, '" name="', $name, '" value="', $value, '">';
if ($fact === 'CENS' && $value === 'Y') {
echo self::censusDateSelector(WT_LOCALE, $xref);
- if (Module::getModuleByName('GEDFact_assistant') && GedcomRecord::getInstance($xref, $WT_TREE) instanceof Individual) {
- echo
- '<div></div><a href="#" style="display: none;" id="assistant-link" onclick="return activateCensusAssistant();">' .
- I18N::translate('Create a shared note using the census assistant') .
- '</a></div>';
+
+ /** @var CensusAssistantModule $census_assistant */
+ $census_assistant = Module::getModuleByName('GEDFact_assistant');
+ $record = Individual::getInstance($xref, $WT_TREE);
+ if ($census_assistant !== null && $record instanceof Individual) {
+ $census_assistant->createCensusAssistant($record);
}
}
-
- } elseif ($fact === 'TEMP') {
- echo self::selectEditControl($element_name, GedcomCodeTemp::templeNames(), I18N::translate('No temple - living ordinance'), $value);
+ } elseif ($fact === 'NPFX' || $fact === 'NSFX' || $fact === 'SPFX' || $fact === 'NICK') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" oninput="updatewholename()">';
+ } elseif ($fact === 'GIVN') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" data-autocomplete-type="GIVN" oninput="updatewholename()" autofocus>';
+ } elseif ($fact === 'SURN' || $fact === '_MARNM_SURN') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" data-autocomplete-type="SURN" oninput="updatewholename()">';
} elseif ($fact === 'ADOP') {
- echo self::editFieldAdoption($element_name, $value, '', $person);
+ echo Bootstrap4::select(GedcomCodeAdop::getValues($person), $value, ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'ALIA') {
+ echo self::formControlIndividual(Individual::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'ASSO' || $fact === '_ASSO') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" onclick="createNewRecord(' . $id . ')" title="' . I18N::translate('Create an individual') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlIndividual(Individual::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ if ($level === '1') {
+ echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this individual, such as a friend or an employer.') . '</p>';
+ } else {
+ echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this fact or event, such as a witness or a priest.') . '</p>';
+ }
+ } elseif ($fact === 'DATE') {
+ echo '<div class="input-group">';
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" oninput="valid_date(this)">';
+ echo self::inputAddonCalendar($id);
+ echo self::inputAddonHelp('DATE');
+ echo '</div>';
+ echo '<div id="caldiv' . $id . '" style="position:absolute;visibility:hidden;background-color:white;z-index:1000"></div>';
+ echo '<p class="text-muted">' . (new Date($value))->display() . '</p>';
+ } elseif ($fact === 'FAMC') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-family" data-element-id="' . $id . '" title="' . I18N::translate('Create a family') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlFamily(Family::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ } elseif ($fact === 'LATI') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" oninput="valid_lati_long(this, \'N\', \'S\')">';
+ } elseif ($fact === 'LONG') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" oninput="valid_lati_long(this, \'E\', \'W\')">';
+ } elseif ($fact === 'NOTE' && $islink) {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-note-object" data-element-id="' . $id . '" title="' . I18N::translate('Create a shared note') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlNote(Note::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ } elseif ($fact === 'OBJE') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-media-object" data-element-id="' . $id . '" title="' . I18N::translate('Create a media object') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlMediaObject(Media::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ } elseif ($fact === 'PAGE') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" data-autocomplete-type="PAGE" data-autocomplete-extra="#' . $previous_ids['SOUR'] . '">';
} elseif ($fact === 'PEDI') {
- echo self::editFieldPedigree($element_name, $value, '', $person);
- } elseif ($fact === 'STAT') {
- echo self::selectEditControl($element_name, GedcomCodeStat::statusNames($upperlevel), '', $value);
- } elseif ($fact === 'RELA') {
- echo self::editFieldRelationship($element_name, strtolower($value));
+ echo Bootstrap4::select(GedcomCodePedi::getValues($person), $value, ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'PLAC') {
+ echo '<div class="input-group">';
+ echo self::formControlPlace($value, ['id' => $id, 'name' => $name]);
+ echo '<span class="input-group-addon">' . FontAwesome::linkIcon('coordinates', I18N::translate('Latitude') . ' / ' . I18N::translate('Longitude'), ['data-toggle' => 'collapse', 'data-target' => '.child_of_' . $id]) . '</span>';
+ echo self::inputAddonHelp('PLAC');
+ echo '</div>';
+ if (Module::getModuleByName('places_assistant')) {
+ \PlacesAssistantModule::setup_place_subfields($id);
+ \PlacesAssistantModule::print_place_subfields($id);
+ }
} elseif ($fact === 'QUAY') {
- echo self::selectEditControl($element_name, GedcomCodeQuay::getValues(), '', $value);
- } elseif ($fact === '_WT_USER') {
- echo self::editFieldUsername($element_name, $value);
+ echo Bootstrap4::select(GedcomCodeQuay::getValues(), $value, ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'RELA') {
+ echo Bootstrap4::select(FunctionsEdit::optionsRelationships($value), $value, ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'REPO') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-repository" data-element-id="' . $id . '" title="' . I18N::translate('Create a repository') . '"><i class="fa fa-plus"></i></button></span>' . self::formControlRepository(Individual::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
} elseif ($fact === 'RESN') {
- echo self::editFieldRestriction($element_name, $value);
+ echo '<div class="input-group">';
+ echo Bootstrap4::select(FunctionsEdit::optionsRestrictions(true), $value, ['id' => $id, 'name' => $name]);
+ echo self::inputAddonHelp('RESN');
+ echo '</span>';
+ echo '</div>';
+ } elseif ($fact === 'SEX') {
+ echo Bootstrap4::radioButtons($name, ['M' => I18N::translate('Male'), 'F' => I18N::translate('Female'), 'U' => I18N::translateContext('unknown gender', 'Unknown')], $value, true);
+ } elseif ($fact === 'SOUR') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-source" data-element-id="' . $id . '" title="' . I18N::translate('Create a source') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlSource(Source::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ } elseif ($fact === 'STAT') {
+ echo Bootstrap4::select(GedcomCodeStat::statusNames($upperlevel), $value);
+ } elseif ($fact === 'SUBM') {
+ echo
+ '<div class="input-group">' .
+ '<span class="input-group-btn"><button class="btn btn-secondary" type="button" data-toggle="modal" data-target="#modal-create-submitter" data-element-id="' . $id . '" title="' . I18N::translate('Create a submitter') . '"><i class="fa fa-plus"></i></button></span>' .
+ self::formControlSubmitter(GedcomRecord::getInstance($value, $WT_TREE), ['id' => $id, 'name' => $name]) .
+ '</div>';
+ } elseif ($fact === 'TEMP') {
+ echo Bootstrap4::select(FunctionsEdit::optionsTemples(), $value, ['id' => $id, 'name' => $name]);
+ } elseif ($fact === 'TIME') {
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '" pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . /* I18N: Examples of valid time formats (hours:minutes:seconds) */ I18N::translate('hh:mm or hh:mm:ss') . '">';
+ } elseif ($fact === '_WT_USER') {
+ echo Bootstrap4::select(FunctionsEdit::optionsUsers(), $value, ['id' => $id, 'name' => $name]);
} elseif ($fact === '_PRIM') {
- echo '<select id="', $element_id, '" name="', $element_name, '" >';
- echo '<option value=""></option>';
- echo '<option value="Y" ';
- if ($value === 'Y') {
- echo ' selected';
- }
- echo '>', /* I18N: option in list box “always use this image” */
- I18N::translate('always'), '</option>';
- echo '<option value="N" ';
- if ($value === 'N') {
- echo 'selected';
- }
- echo '>', /* I18N: option in list box “never use this image” */
- I18N::translate('never'), '</option>';
- echo '</select>';
+ echo Bootstrap4::select(['' => '', 'Y' => I18N::translate('always'), 'N' => I18N::translate('never')], $value, ['id' => $id, 'name' => $name]);
echo '<p class="small text-muted">', I18N::translate('Use this image for charts and on the individual’s page.'), '</p>';
- } elseif ($fact === 'SEX') {
- echo '<select id="', $element_id, '" name="', $element_name, '"><option value="M" ';
- if ($value === 'M') {
- echo 'selected';
- }
- echo '>', I18N::translate('Male'), '</option><option value="F" ';
- if ($value === 'F') {
- echo 'selected';
- }
- echo '>', I18N::translate('Female'), '</option><option value="U" ';
- if ($value === 'U' || empty($value)) {
- echo 'selected';
- }
- echo '>', I18N::translateContext('unknown gender', 'Unknown'), '</option></select>';
- } elseif ($fact === 'TYPE' && $level === 3) {
+ } elseif ($fact === 'TYPE' && $level === '3') {
//-- Build the selector for the Media 'TYPE' Fact
echo '<select name="text[]"><option selected value="" ></option>';
$selectedValue = strtolower($value);
@@ -710,101 +798,28 @@ class FunctionsEdit {
echo '>', $typeValue, '</option>';
}
echo '</select>';
- } elseif (($fact === 'NAME' && $upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') || $fact === '_MARNM') {
- // Populated in javascript from sub-tags
- echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" onchange="updateTextName(\'', $element_id, '\');" value="', Filter::escapeHtml($value), '" class="', $fact, '">';
- echo '<span id="', $element_id, '_display" dir="auto">', Filter::escapeHtml($value), '</span>';
- echo ' <a href="#edit_name" onclick="convertHidden(\'', $element_id, '\'); return false;" class="icon-edit_indi" title="' . I18N::translate('Edit the name') . '"></a>';
- } else {
- // textarea
+ } elseif (($fact !== 'NAME' || $upperlevel === 'REPO' || $upperlevel === 'UNKNOWN') && $fact !== '_MARNM') {
if ($fact === 'TEXT' || $fact === 'ADDR' || ($fact === 'NOTE' && !$islink)) {
- echo '<textarea id="', $element_id, '" name="', $element_name, '" dir="auto">', Filter::escapeHtml($value), '</textarea><br>';
+ echo '<div class="input-group">';
+ echo '<textarea class="form-control" id="', $id, '" name="', $name, '" dir="auto">', Filter::escapeHtml($value), '</textarea>';
+ echo self::inputAddonKeyboard($id);
+ echo '</div>';
} else {
- // text
// If using GEDFact-assistant window
- if ($action === 'addnewnote_assisted') {
- echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" style="width:4.1em;" dir="ltr"';
- } else {
- echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" dir="ltr"';
- }
- echo ' class="', $fact, '"';
- if (in_array($fact, $subnamefacts)) {
- echo ' onblur="updatewholename();" onkeyup="updatewholename();"';
- }
-
- // Extra markup for specific fact types
- switch ($fact) {
- case 'ALIA':
- case 'ASSO':
- case '_ASSO':
- echo ' data-autocomplete-type="ASSO" data-autocomplete-extra="input.DATE"';
- break;
- case 'DATE':
- echo ' onblur="valid_date(this);" onmouseout="valid_date(this);"';
- break;
- case 'GIVN':
- echo ' autofocus data-autocomplete-type="GIVN"';
- break;
- case 'LATI':
- echo ' onblur="valid_lati_long(this, \'N\', \'S\');" onmouseout="valid_lati_long(this, \'N\', \'S\');"';
- break;
- case 'LONG':
- echo ' onblur="valid_lati_long(this, \'E\', \'W\');" onmouseout="valid_lati_long(this, \'E\', \'W\');"';
- break;
- case 'NOTE':
- // Shared notes. Inline notes are handled elsewhere.
- echo ' data-autocomplete-type="NOTE"';
- break;
- case 'OBJE':
- echo ' data-autocomplete-type="OBJE"';
- break;
- case 'PAGE':
- echo ' data-autocomplete-type="PAGE" data-autocomplete-extra="#' . $source_element_id . '"';
- break;
- case 'PLAC':
- echo ' data-autocomplete-type="PLAC"';
- break;
- case 'REPO':
- echo ' data-autocomplete-type="REPO"';
- break;
- case 'SOUR':
- $source_element_id = $element_id;
- echo ' data-autocomplete-type="SOUR"';
- break;
- case 'SURN':
- case '_MARNM_SURN':
- echo ' data-autocomplete-type="SURN"';
- break;
- case 'TIME':
- echo ' pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . /* I18N: Examples of valid time formats (hours:minutes:seconds) */
- I18N::translate('hh:mm or hh:mm:ss') . '"';
- break;
- }
- echo '>';
- }
-
- $tmp_array = ['TYPE', 'TIME', 'NOTE', 'SOUR', 'REPO', 'OBJE', 'ASSO', '_ASSO', 'AGE'];
-
- // split PLAC
- if ($fact === 'PLAC') {
- echo '<div id="', $element_id, '_pop" style="display: inline;">';
- echo FunctionsPrint::printSpecialCharacterLink($element_id), ' ', FunctionsPrint::printFindPlaceLink($element_id);
- echo '<span onclick="$(\'tr[id^=', $upperlevel, '_LATI],tr[id^=', $upperlevel, '_LONG],tr[id^=LATI],tr[id^=LONG]\').toggle(\'fast\'); return false;" class="icon-target" title="', I18N::translate('Latitude'), ' / ', I18N::translate('Longitude'), '"></span>';
- echo '</div>';
- if (Module::getModuleByName('places_assistant')) {
- \PlacesAssistantModule::setup_place_subfields($element_id);
- \PlacesAssistantModule::print_place_subfields($element_id);
- }
- } elseif (!in_array($fact, $tmp_array)) {
- echo FunctionsPrint::printSpecialCharacterLink($element_id);
+ echo '<input class="form-control" type="text" id="', $id, '" name="', $name, '" value="', Filter::escapeHtml($value), '">';
}
+ } else {
+ // Populated in javascript from sub-tags
+ echo '<input type="hidden" id="', $id, '" name="', $name, '" oninput="updateTextName(\'', $id, '\')" value="', Filter::escapeHtml($value), '" class="', $fact, '">';
+ echo '<span id="', $id, '_display" dir="auto">', Filter::escapeHtml($value), '</span>';
+ echo ' <a href="#edit_name" onclick="convertHidden(\'', $id, '\'); return false" class="icon-edit_indi" title="' . I18N::translate('Edit the name') . '"></a>';
}
// MARRiage TYPE : hide text field and show a selection list
- if ($fact === 'TYPE' && $level === 2 && $tags[0] === 'MARR') {
+ if ($fact === 'TYPE' && $level === '2' && $tags[0] === 'MARR') {
echo '<script>';
- echo 'document.getElementById(\'', $element_id, '\').style.display=\'none\'';
+ echo 'document.getElementById(\'', $id, '\').style.display=\'none\'';
echo '</script>';
- echo '<select id="', $element_id, '_sel" onchange="document.getElementById(\'', $element_id, '\').value=this.value;" >';
+ echo '<select id="', $id, '_sel" oninput="document.getElementById(\'', $id, '\').value=this.value" >';
foreach (['Unknown', 'Civil', 'Religious', 'Partners'] as $key) {
if ($key === 'Unknown') {
echo '<option value="" ';
@@ -821,32 +836,15 @@ class FunctionsEdit {
echo '</select>';
} elseif ($fact === 'TYPE' && $level === 0) {
// NAME TYPE : hide text field and show a selection list
- $onchange = 'onchange="document.getElementById(\'' . $element_id . '\').value=this.value;"';
- echo self::editFieldNameType($element_name, $value, $onchange, $person);
- echo '<script>document.getElementById("', $element_id, '").style.display="none";</script>';
+ echo Bootstrap4::select(GedcomCodeName::getValues($person), $value, ['id' => $id, 'name' => $name, 'oninput' => 'document.getElementById(\'' . $id . '\').value=this.value"']);
+ echo '<script>document.getElementById("', $id, '").style.display="none";</script>';
}
// popup links
switch ($fact) {
- case 'DATE':
- echo self::printCalendarPopup($element_id);
- break;
- case 'FAMC':
- case 'FAMS':
- echo FunctionsPrint::printFindFamilyLink($element_id);
- break;
- case 'ALIA':
- case 'ASSO':
- case '_ASSO':
- echo FunctionsPrint::printFindIndividualLink($element_id, $element_id . '_description');
- break;
- case 'FILE':
- FunctionsPrint::printFindMediaLink($element_id, '0file');
- break;
case 'SOUR':
- echo FunctionsPrint::printFindSourceLink($element_id, $element_id . '_description'), ' ', self::printAddNewSourceLink($element_id);
//-- checkboxes to apply '1 SOUR' to BIRT/MARR/DEAT as '2 SOUR'
- if ($level === 1) {
+ if ($level === '1') {
echo '<br>';
switch ($WT_TREE->getPreference('PREFER_LEVEL2_SOURCES')) {
case '2': // records
@@ -892,87 +890,17 @@ class FunctionsEdit {
}
}
break;
- case 'REPO':
- echo FunctionsPrint::printFindRepositoryLink($element_id), ' ', self::printAddNewRepositoryLink($element_id);
- break;
- case 'NOTE':
- // Shared Notes Icons ========================================
- if ($islink) {
- // Print regular Shared Note icons ---------------------------
- echo ' ', FunctionsPrint::printFindNoteLink($element_id, $element_id . '_description'), ' ', self::printAddNewNoteLink($element_id);
- if ($value) {
- echo ' ', self::printEditNoteLink($value);
- }
- }
- break;
- case 'OBJE':
- echo FunctionsPrint::printFindMediaLink($element_id, '1media');
- if (!$value) {
- echo ' ', self::printAddNewMediaLink($element_id);
- $value = 'new';
- }
- break;
}
- echo '<div id="' . $element_id . '_description">';
-
- // current value
- if ($fact === 'DATE') {
- $date = new Date($value);
- echo $date->display();
- }
- if (($fact === 'ASSO' || $fact === '_ASSO') && $value === '') {
- if ($level === 1) {
- echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this individual, such as a friend or an employer.') . '</p>';
- } else {
- echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this fact or event, such as a witness or a priest.') . '</p>';
- }
- }
-
- if ($value && $value !== 'new' && $islink) {
- switch ($fact) {
- case 'ALIA':
- case 'ASSO':
- case '_ASSO':
- $tmp = Individual::getInstance($value, $WT_TREE);
- if ($tmp) {
- echo ' ', $tmp->getFullName();
- }
- break;
- case 'SOUR':
- $tmp = Source::getInstance($value, $WT_TREE);
- if ($tmp) {
- echo ' ', $tmp->getFullName();
- }
- break;
- case 'NOTE':
- $tmp = Note::getInstance($value, $WT_TREE);
- if ($tmp) {
- echo ' ', $tmp->getFullName();
- }
- break;
- case 'OBJE':
- $tmp = Media::getInstance($value, $WT_TREE);
- if ($tmp) {
- echo ' ', $tmp->getFullName();
- }
- break;
- case 'REPO':
- $tmp = Repository::getInstance($value, $WT_TREE);
- if ($tmp) {
- echo ' ', $tmp->getFullName();
- }
- break;
- }
- }
+ echo '<div id="' . $id . '_description">';
// pastable values
if ($fact === 'FORM' && $upperlevel === 'OBJE') {
- FunctionsPrint::printAutoPasteLink($element_id, Config::fileFormats());
+ FunctionsPrint::printAutoPasteLink($id, Config::fileFormats());
}
- echo '</div>', $extra, '</td></tr>';
+ echo '</div>', $extra, '</div></div>';
- return $element_id;
+ return $id;
}
/**
@@ -986,7 +914,7 @@ class FunctionsEdit {
global $controller;
// Show more likely census details at the top of the list.
- switch (WT_LOCALE) {
+ switch ($locale) {
case 'cs':
$census_places = [new CensusOfCzechRepublic];
break;
@@ -1019,27 +947,13 @@ class FunctionsEdit {
$controller->addInlineJavascript('
function selectCensus(el) {
- var option = jQuery(":selected", el);
- jQuery("input.DATE", jQuery(el).closest("table")).val(option.val());
- jQuery("input.PLAC", jQuery(el).closest("table")).val(option.data("place"));
- jQuery("input.census-class", jQuery(el).closest("table")).val(option.data("census"));
- if (option.data("place")) {
- jQuery("#assistant-link").show();
- } else {
- jQuery("#assistant-link").hide();
- }
- }
- function set_pid_array(pa) {
- jQuery("#pid_array").val(pa);
- }
- function activateCensusAssistant() {
- if (jQuery("#newshared_note_img").hasClass("icon-plus")) {
- expand_layer("newshared_note");
- }
- var field = jQuery("#newshared_note input.NOTE")[0];
- var xref = jQuery("input[name=xref]").val();
- var census = jQuery(".census-assistant-selector :selected").data("census");
- return addnewnote_assisted(field, xref, census);
+ var option = $(":selected", el);
+ $("input[id^=CENS_DATE]", $(el).closest("form")).val(option.val());
+ //$("input[id^=CENS_PLAC]", $(el).closest("form")).val(option.data("place"));
+ var place = option.data("place");
+ $("select[id^=CENS_PLAC]", $(el).closest("form")).select2().empty().append(new Option(place, place)).val(place).trigger("change");
+
+ $("input.census-class", $(el).closest("form")).val(option.data("census"));
}
');
@@ -1056,15 +970,14 @@ class FunctionsEdit {
}
return
- '<input type="hidden" id="pid_array" name="pid_array" value="">' .
- '<select class="census-assistant-selector" onchange="selectCensus(this);">' . $options . '</select>';
+ '<select id="census-selector" class="form-control" onchange="selectCensus(this)">' . $options . '</select>';
}
/**
* Prints collapsable fields to add ASSO/RELA, SOUR, OBJE, etc.
*
* @param string $tag
- * @param int $level
+ * @param int $level
* @param string $parent_tag
*/
public static function printAddLayer($tag, $level = 2, $parent_tag = '') {
@@ -1072,95 +985,48 @@ class FunctionsEdit {
switch ($tag) {
case 'SOUR':
- echo '<a href="#" onclick="return expand_layer(\'newsource\');"><i id="newsource_img" class="icon-plus"></i> ', I18N::translate('Add a source citation'), '</a>';
- echo '<br>';
- echo '<div id="newsource" style="display: none;">';
- echo '<table class="facts_table">';
- // 2 SOUR
+ echo '<h3>', I18N::translate('Add a source citation'), '</h3>';
self::addSimpleTag($level . ' SOUR @');
- // 3 PAGE
self::addSimpleTag(($level + 1) . ' PAGE');
- // 3 DATA
self::addSimpleTag(($level + 1) . ' DATA');
- // 4 TEXT
self::addSimpleTag(($level + 2) . ' TEXT');
if ($WT_TREE->getPreference('FULL_SOURCES')) {
- // 4 DATE
self::addSimpleTag(($level + 2) . ' DATE', '', GedcomTag::getLabel('DATA:DATE'));
- // 3 QUAY
self::addSimpleTag(($level + 1) . ' QUAY');
}
- // 3 OBJE
self::addSimpleTag(($level + 1) . ' OBJE');
- // 3 SHARED_NOTE
self::addSimpleTag(($level + 1) . ' SHARED_NOTE');
- echo '</table></div>';
break;
case 'ASSO':
case 'ASSO2':
- //-- Add a new ASSOciate
- if ($tag === 'ASSO') {
- echo "<a href=\"#\" onclick=\"return expand_layer('newasso');\"><i id=\"newasso_img\" class=\"icon-plus\"></i> ", I18N::translate('Add an associate'), '</a>';
- echo '<br>';
- echo '<div id="newasso" style="display: none;">';
- } else {
- echo "<a href=\"#\" onclick=\"return expand_layer('newasso2');\"><i id=\"newasso2_img\" class=\"icon-plus\"></i> ", I18N::translate('Add an associate'), '</a>';
- echo '<br>';
- echo '<div id="newasso2" style="display: none;">';
- }
- echo '<table class="facts_table">';
- // 2 ASSO
+ echo '<h3>', I18N::translate('Add an associate'), '</h3>';
self::addSimpleTag($level . ' _ASSO @');
- // 3 RELA
self::addSimpleTag(($level + 1) . ' RELA');
- // 3 NOTE
self::addSimpleTag(($level + 1) . ' NOTE');
- // 3 SHARED_NOTE
self::addSimpleTag(($level + 1) . ' SHARED_NOTE');
- echo '</table></div>';
break;
case 'NOTE':
- //-- Retrieve existing note or add new note to fact
- echo "<a href=\"#\" onclick=\"return expand_layer('newnote');\"><i id=\"newnote_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a note'), '</a>';
- echo '<br>';
- echo '<div id="newnote" style="display: none;">';
- echo '<table class="facts_table">';
- // 2 NOTE
+ echo '<h3>', I18N::translate('Add a note'), '</h3>';
self::addSimpleTag($level . ' NOTE');
- echo '</table></div>';
break;
case 'SHARED_NOTE':
- echo "<a href=\"#\" onclick=\"return expand_layer('newshared_note');\"><i id=\"newshared_note_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a shared note'), '</a>';
- echo '<br>';
- echo '<div id="newshared_note" style="display: none;">';
- echo '<table class="facts_table">';
- // 2 SHARED NOTE
+ echo '<h3>', I18N::translate('Add a shared note'), '</h3>';
self::addSimpleTag($level . ' SHARED_NOTE', $parent_tag);
- echo '</table></div>';
break;
case 'OBJE':
if ($WT_TREE->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($WT_TREE)) {
- echo "<a href=\"#\" onclick=\"return expand_layer('newobje');\"><i id=\"newobje_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a media object'), '</a>';
- echo '<br>';
- echo '<div id="newobje" style="display: none;">';
- echo '<table class="facts_table">';
+ echo '<h3>', I18N::translate('Add a media object'), '</h3>';
self::addSimpleTag($level . ' OBJE');
- echo '</table></div>';
}
break;
case 'RESN':
- echo "<a href=\"#\" onclick=\"return expand_layer('newresn');\"><i id=\"newresn_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a restriction'), '</a>';
- echo '<br>';
- echo '<div id="newresn" style="display: none;">';
- echo '<table class="facts_table">';
- // 2 RESN
+ echo '<h3>', I18N::translate('Add a restriction'), '</h3>';
self::addSimpleTag($level . ' RESN');
- echo '</table></div>';
break;
}
}
@@ -1829,4 +1695,651 @@ class FunctionsEdit {
}
}
}
+
+ /**
+ * Simple forms to create the essential fields of new records.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public static function createRecordFormModals(Tree $tree) {
+ ?>
+
+ <!-- Form to create a new family -->
+ <div class="modal wt-modal-create-record" id="modal-create-family">
+ <form id="form-create-family"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-family">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a family from existing individuals') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label class="col-form-label" for="husband">
+ <?= I18N::translate('Husband') ?>
+ </label>
+ <?= self::formControlIndividual(null, ['id' => 'husband', 'name' => 'husband']) ?>
+ </div>
+ <div class="form-group">
+ <label class="col-form-label" for="wife">
+ <?= I18N::translate('Wife') ?>
+ </label>
+ <?= self::formControlIndividual(null, ['id' => 'wife', 'name' => 'wife']) ?>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- Form to create a new media object -->
+ <div class="modal wt-modal-create-record" id="modal-create-media-object">
+ <form id="form-create-media-object"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-media-object">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a media object') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="file">
+ <?= I18N::translate('Media file to upload') ?>
+ </label>
+ <div class="col-sm-10">
+ <input type="file" class="form-control" id="file" name="file">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="type">
+ <?= I18N::translate('Filename on server') ?>
+ </label>
+ <div class="col-sm-10">
+ <div class="form-check">
+ <label class="form-check-label">
+ <input class="form-check-input" type="radio" name="auto" value="0" checked>
+ <span class="input-group">
+ <input class="form-control" type="text" placeholder="<?= I18N::translate('Folder name on server') ?>">
+ <span class="input-group-addon">/</span>
+ <input class="form-control" type="text" placeholder="<?= I18N::translate('Same as uploaded file') ?>">
+ </span>
+ </label>
+ </div>
+ <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>
+ <div class="form-check">
+ <label class="form-check-label">
+ <input class="form-check-input" type="radio" name="auto" value="1">
+ <?= I18N::translate('Create a unique filename') ?>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="title">
+ <?= I18N::translate('Title') ?>
+ </label>
+ <div class="col-sm-10">
+ <input type="text" class="form-control" name="title" id="title">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="type">
+ <?= I18N::translate('Media type') ?>
+ </label>
+ <div class="col-sm-10">
+ <?= Bootstrap4::select(['' => ''] + GedcomTag::getFileFormTypes(), '') ?>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="note">
+ <?= I18N::translate('Note') ?>
+ </label>
+ <div class="col-sm-10">
+ <textarea class="form-control" id="note" name="note"></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- Form to create a new note object -->
+ <div class="modal wt-modal-create-record" id="modal-create-note-object">
+ <form id="form-create-note-object"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-note-object">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a shared note') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label class="col-form-label" for="note">
+ <?= GedcomTag::getLabel('NOTE') ?>
+ </label>
+ <textarea class="form-control" id="note" name="note"></textarea>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- Form to create a new repository -->
+ <div class="modal wt-modal-create-record" id="modal-create-repository">
+ <form id="form-create-repository"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-repository">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a repository') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label class="col-form-label" for="repository-name">
+ <?= GedcomTag::getLabel('REPO:NAME') ?>
+ </label>
+ <input class="form-control" type="text" id="repository-name" name="repository_name" required>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- Form to create a new source -->
+ <div class="modal wt-modal-create-record" id="modal-create-source">
+ <form id="form-create-source"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-source">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a source') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="source-title">
+ <?= I18N::translate('Title') ?>
+ </label>
+ <div class="col-sm-10">
+ <input class="form-control" type="text" id="source-title" name="TITL" required>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="source-abbreviation">
+ <?= I18N::translate('Abbreviation') ?>
+ </label>
+ <div class="col-sm-10">
+ <input class="form-control" type="text" id="source-abbreviation" name="ABBR">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="source-author">
+ <?= I18N::translate('Author') ?>
+ </label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="source-author" name="AUTH">
+ </div>
+ <label class="col-form-label col-sm-2" for="source-publication">
+ <?= I18N::translate('Publication') ?>
+ </label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="source-publication" name="PUBL">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="source-repository">
+ <?= I18N::translate('Repository') ?>
+ </label>
+ <div class="col-sm-4">
+ <?= self::formControlRepository(null, ['id' => 'source-repository', 'name' => 'REPO']) ?>
+ </div>
+ <label class="col-form-label col-sm-2" for="source-call-number">
+ <?= I18N::translate('Call number') ?>
+ </label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="source-call-number" name="CALN">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2" for="source-text">
+ <?= I18N::translate('Text') ?>
+ </label>
+ <div class="col-sm-10">
+ <textarea class="form-control" rows="2" id="source-text" name="TEXT"></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- Form to create a new submitter -->
+ <div class="modal wt-modal-create-record" id="modal-create-submitter">
+ <form id="form-create-submitter"><!-- This form is posted using jQuery -->
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="action" value="create-submitter">
+ <input type="hidden" name="ged" value="<?= $tree->getNameHtml() ?>">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title"><?= I18N::translate('Create a submitter') ?></h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?= I18N::translate('close') ?>">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label class="col-form-label" for="submitter-name">
+ <?= GedcomTag::getLabel('SUBM:NAME') ?>
+ </label>
+ <input class="form-control" type="text" id="submitter-name" name="submitter_name" required>
+ </div>
+ <div class="form-group">
+ <label class="col-form-label" for="submitter-address">
+ <?= GedcomTag::getLabel('SUBM:ADDR') ?>
+ </label>
+ <input class="form-control" type="text" id="submitter-address" name="submitter_address">
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('save') ?>
+ <?= I18N::translate('save') ?>
+ </button>
+ <button type="button" class="btn btn-text" data-dismiss="modal">
+ <?= FontAwesome::decorativeIcon('cancel') ?>
+ <?= I18N::translate('cancel') ?>
+ </button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <!-- On screen keyboard -->
+ <div class="card wt-osk">
+ <div class="card-header">
+ <div class="card-title">
+ <button type="button" class="btn btn-primary">&times;</button>
+
+ <button type="button" class="btn btn-secondary wt-osk-pin-button" data-toggle="button" aria-pressed="false"><?= FontAwesome::semanticIcon('pin', I18N::translate('Keep open')) ?></button>
+
+ <button type="button" class="btn btn-secondary wt-osk-shift-button" data-toggle="button" aria-pressed="false">a &harr; A</button>
+
+ <div class="btn-group" data-toggle="buttons">
+ <label class="btn btn-secondary active" dir="ltr">
+ <input type="radio" class="wt-osk-script-button" checked autocomplete="off" data-script="latn"> Abcd
+ </label>
+ <label class="btn btn-secondary" dir="ltr">
+ <input type="radio" class="wt-osk-script-button" autocomplete="off" data-script="cyrl"> &Acy;&bcy;&gcy;&dcy;
+ </label>
+ <label class="btn btn-secondary" dir="ltr">
+ <input type="radio" class="wt-osk-script-button" autocomplete="off" data-script="grek"> &Alpha;&beta;&gamma;&delta;
+ </label>
+ <label class="btn btn-secondary" dir="rtl">
+ <input type="radio" class="wt-osk-script-button" autocomplete="off" data-script="arab"> &#x627;&#x628;&#x629;&#x62a;
+ </label>
+ <label class="btn btn-secondary" dir="rtl">
+ <input type="radio" class="wt-osk-script-button" autocomplete="off" data-script="hebr"> &#x5d0;&#x5d1;&#x5d2;&#x5d3;
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="card-block wt-osk-keys">
+ <!-- Quotation marks -->
+ <div class="wt-osk-group">
+ <span class="wt-osk-key">&lsquo;<sup class="wt-osk-key-shift">&ldquo;</sup></span>
+ <span class="wt-osk-key">&rsquo;<sup class="wt-osk-key-shift">&rdquo;</sup></span>
+ <span class="wt-osk-key">&lsaquo;<sup class="wt-osk-key-shift">&ldquo;</sup></span>
+ <span class="wt-osk-key">&rsaquo;<sup class="wt-osk-key-shift">&raquo;</sup></span>
+ <span class="wt-osk-key">&sbquo;<sup class="wt-osk-key-shift">&bdquo;</sup></span>
+ <span class="wt-osk-key">&prime;<sup class="wt-osk-key-shift">&Prime;</sup></span>
+ </div>
+ <!-- Symbols and punctuation -->
+ <div class="wt-osk-group">
+ <span class="wt-osk-key">&copy;</span>
+ <span class="wt-osk-key">&deg;</span>
+ <span class="wt-osk-key">&hellip;</span>
+ <span class="wt-osk-key">&middot;<sup class="wt-osk-key-shift">&bullet;</sup></span>
+ <span class="wt-osk-key">&ndash;<sup class="wt-osk-key-shift">&mdash;</sup></span>
+ <span class="wt-osk-key">&dagger;<sup class="wt-osk-key-shift">&ddagger;</sup></span>
+ <span class="wt-osk-key">&sect;<sup class="wt-osk-key-shift">&para;</sup></span>
+ <span class="wt-osk-key">&iquest;<sup class="wt-osk-key-shift">&iexcl;</sup></span>
+ </div>
+ <!-- Letter A with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&agrave;<sup class="wt-osk-key-shift">&Agrave;</sup></span>
+ <span class="wt-osk-key">&aacute;<sup class="wt-osk-key-shift">&Aacute;</sup></span>
+ <span class="wt-osk-key">&acirc;<sup class="wt-osk-key-shift">&Acirc;</sup></span>
+ <span class="wt-osk-key">&atilde;<sup class="wt-osk-key-shift">&Atilde;</sup></span>
+ <span class="wt-osk-key">&aring;<sup class="wt-osk-key-shift">&Aring;</sup></span>
+ <span class="wt-osk-key">&aogon;<sup class="wt-osk-key-shift">&Aogon;</sup></span>
+ <span class="wt-osk-key">&aelig;<sup class="wt-osk-key-shift">&AElig;</sup></span>
+ <span class="wt-osk-key">&ordf;</span>
+ </div>
+ <!-- Letter C with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&ccedil;<sup class="wt-osk-key-shift">&Ccedil;</sup></span>
+ <span class="wt-osk-key">&ccaron;<sup class="wt-osk-key-shift">&Ccaron;</sup></span>
+ </div>
+ <!-- Letter D with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&Dcaron;<sup class="wt-osk-key-shift">&Dcaron;</sup></span>
+ </div>
+ <!-- Letter E with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&egrave;<sup class="wt-osk-key-shift">&Egrave;</sup></span>
+ <span class="wt-osk-key">&eacute;<sup class="wt-osk-key-shift">&Eacute;</sup></span>
+ <span class="wt-osk-key">&ecirc;<sup class="wt-osk-key-shift">&Ecirc;</sup></span>
+ <span class="wt-osk-key">&euml;<sup class="wt-osk-key-shift">&Euml;</sup></span>
+ <span class="wt-osk-key">&eogon;<sup class="wt-osk-key-shift">&Eogon;</sup></span>
+ </div>
+ <!-- Letter G with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&gbreve;<sup class="wt-osk-key-shift">&Gbreve;</sup></span>
+ </div>
+ <!-- Letter I with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&igrave;<sup class="wt-osk-key-shift">&Igrave;</sup></span>
+ <span class="wt-osk-key">&iacute;<sup class="wt-osk-key-shift">&Iacute;</sup></span>
+ <span class="wt-osk-key">&icirc;<sup class="wt-osk-key-shift">&Icirc;</sup></span>
+ <span class="wt-osk-key">&iuml;<sup class="wt-osk-key-shift">&Iuml;</sup></span>
+ <span class="wt-osk-key">&iogon;<sup class="wt-osk-key-shift">&Iogon;</sup></span>
+ <span class="wt-osk-key">&inodot;<sup class="wt-osk-key-shift">&Idot;</sup></span>
+ <span class="wt-osk-key">&ijlig;<sup class="wt-osk-key-shift">&IJlig;</sup></span>
+ </div>
+ <!-- Letter L with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&lcaron;<sup class="wt-osk-key-shift">&Lcaron;</sup></span>
+ <span class="wt-osk-key">&lacute;<sup class="wt-osk-key-shift">&Lacute;</sup></span>
+ <span class="wt-osk-key">&lstrok;<sup class="wt-osk-key-shift">&Lstrok;</sup></span>
+ </div>
+ <!-- Letter N with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&napos;</span>
+ <span class="wt-osk-key">&ntilde;<sup class="wt-osk-key-shift">&Ntilde;</sup></span>
+ <span class="wt-osk-key">&ncaron;<sup class="wt-osk-key-shift">&Ncaron;</sup></span>
+ </div>
+ <!-- Letter O with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&ograve;<sup class="wt-osk-key-shift">&Ograve;</sup></span>
+ <span class="wt-osk-key">&oacute;<sup class="wt-osk-key-shift">&Oacute;</sup></span>
+ <span class="wt-osk-key">&ocirc;<sup class="wt-osk-key-shift">&Ocirc;</sup></span>
+ <span class="wt-osk-key">&otilde;<sup class="wt-osk-key-shift">&Otilde;</sup></span>
+ <span class="wt-osk-key">&ouml;<sup class="wt-osk-key-shift">&Ouml;</sup></span>
+ <span class="wt-osk-key">&oslash;<sup class="wt-osk-key-shift">&Oslash;</sup></span>
+ <span class="wt-osk-key">&oelig;<sup class="wt-osk-key-shift">&OElig;</sup></span>
+ <span class="wt-osk-key">&ordm;</span>
+ </div>
+ <!-- Letter T with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&tcaron;<sup class="wt-osk-key-shift">&Tcaron;</sup></span>
+ </div>
+ <!-- Letter R with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&racute;<sup class="wt-osk-key-shift">&Racute;</sup></span>
+ <span class="wt-osk-key">&rcaron;<sup class="wt-osk-key-shift">&Rcaron;</sup></span>
+ </div>
+ <!-- Letter S with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&scaron;<sup class="wt-osk-key-shift">&Scaron;</sup></span>
+ <span class="wt-osk-key">&scedil;<sup class="wt-osk-key-shift">&Scedil;</sup></span>
+ <span class="wt-osk-key">&#x17F;</sup></span>
+ </div>
+ <!-- Letter U with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&ugrave;<sup class="wt-osk-key-shift">&Ugrave;</sup></span>
+ <span class="wt-osk-key">&uacute;<sup class="wt-osk-key-shift">&Uacute;</sup></span>
+ <span class="wt-osk-key">&ucirc;<sup class="wt-osk-key-shift">&Ucirc;</sup></span>
+ <span class="wt-osk-key">&utilde;<sup class="wt-osk-key-shift">&Utilde;</sup></span>
+ <span class="wt-osk-key">&umacr;<sup class="wt-osk-key-shift">&Umacr;</sup></span>
+ <span class="wt-osk-key">&uogon;<sup class="wt-osk-key-shift">&Uogon;</sup></span>
+ </div>
+ <!-- Letter Y with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&yacute;<sup class="wt-osk-key-shift">&Yacute;</sup></span>
+ </div>
+ <!-- Letter Z with diacritic -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&zdot;<sup class="wt-osk-key-shift">&Zdot;</sup></span>
+ <span class="wt-osk-key">&zcaron;<sup class="wt-osk-key-shift">&Zcaron;</sup></span>
+ </div>
+ <!-- Esszet, Eth and Thorn -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-latn" dir="ltr">
+ <span class="wt-osk-key">&szlig;<sup class="wt-osk-key-shift">&#7838;</sup></span>
+ <span class="wt-osk-key">&eth;<sup class="wt-osk-key-shift">&ETH;</sup></span>
+ <span class="wt-osk-key">&thorn;<sup class="wt-osk-key-shift">&THORN;</sup></span>
+ </div>
+ <!-- Extra Cyrillic characters -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-cyrl" dir="ltr" hidden>
+ <span class="wt-osk-key">&iocy;<sup class="wt-osk-key-shift">&IOcy;</sup></span>
+ <span class="wt-osk-key">&djcy;<sup class="wt-osk-key-shift">&DJcy;</sup></span>
+ <span class="wt-osk-key">&gjcy;<sup class="wt-osk-key-shift">&GJcy;</sup></span>
+ <span class="wt-osk-key">&jukcy;<sup class="wt-osk-key-shift">&Jukcy;</sup></span>
+ <span class="wt-osk-key">&dscy;<sup class="wt-osk-key-shift">&DScy;</sup></span>
+ <span class="wt-osk-key">&iukcy;<sup class="wt-osk-key-shift">&Iukcy;</sup></span>
+ <span class="wt-osk-key">&yicy;<sup class="wt-osk-key-shift">&YIcy;</sup></span>
+ <span class="wt-osk-key">&jsercy;<sup class="wt-osk-key-shift">&Jsercy;</sup></span>
+ <span class="wt-osk-key">&ljcy;<sup class="wt-osk-key-shift">&LJcy;</sup></span>
+ <span class="wt-osk-key">&njcy;<sup class="wt-osk-key-shift">&NJcy;</sup></span>
+ <span class="wt-osk-key">&tshcy;<sup class="wt-osk-key-shift">&TSHcy;</sup></span>
+ <span class="wt-osk-key">&kjcy;<sup class="wt-osk-key-shift">&KJcy;</sup></span>
+ <span class="wt-osk-key">&ubrcy;<sup class="wt-osk-key-shift">&Ubrcy;</sup></span>
+ <span class="wt-osk-key">&dzcy;<sup class="wt-osk-key-shift">&DZcy;</sup></span>
+ </div>
+ <!-- Cyrillic alphabet -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-cyrl" dir="ltr" hidden>
+ <span class="wt-osk-key">&acy;<sup class="wt-osk-key-shift">&Acy;</sup></span>
+ <span class="wt-osk-key">&bcy;<sup class="wt-osk-key-shift">&Bcy;</sup></span>
+ <span class="wt-osk-key">&gcy;<sup class="wt-osk-key-shift">&Gcy;</sup></span>
+ <span class="wt-osk-key">&dcy;<sup class="wt-osk-key-shift">&Dcy;</sup></span>
+ <span class="wt-osk-key">&iecy;<sup class="wt-osk-key-shift">&IEcy;</sup></span>
+ <span class="wt-osk-key">&zhcy;<sup class="wt-osk-key-shift">&ZHcy;</sup></span>
+ <span class="wt-osk-key">&zcy;<sup class="wt-osk-key-shift">&Zcy;</sup></span>
+ <span class="wt-osk-key">&icy;<sup class="wt-osk-key-shift">&Icy;</sup></span>
+ <span class="wt-osk-key">&jcy;<sup class="wt-osk-key-shift">&Jcy;</sup></span>
+ <span class="wt-osk-key">&kcy;<sup class="wt-osk-key-shift">&Kcy;</sup></span>
+ <span class="wt-osk-key">&lcy;<sup class="wt-osk-key-shift">&Lcy;</sup></span>
+ <span class="wt-osk-key">&mcy;<sup class="wt-osk-key-shift">&Mcy;</sup></span>
+ <span class="wt-osk-key">&ncy;<sup class="wt-osk-key-shift">&Ncy;</sup></span>
+ <span class="wt-osk-key">&ocy;<sup class="wt-osk-key-shift">&Ocy;</sup></span>
+ <span class="wt-osk-key">&pcy;<sup class="wt-osk-key-shift">&Pcy;</sup></span>
+ <span class="wt-osk-key">&scy;<sup class="wt-osk-key-shift">&Scy;</sup></span>
+ <span class="wt-osk-key">&tcy;<sup class="wt-osk-key-shift">&Tcy;</sup></span>
+ <span class="wt-osk-key">&ucy;<sup class="wt-osk-key-shift">&Ucy;</sup></span>
+ <span class="wt-osk-key">&ucy;<sup class="wt-osk-key-shift">&Ucy;</sup></span>
+ <span class="wt-osk-key">&fcy;<sup class="wt-osk-key-shift">&Fcy;</sup></span>
+ <span class="wt-osk-key">&khcy;<sup class="wt-osk-key-shift">&KHcy;</sup></span>
+ <span class="wt-osk-key">&tscy;<sup class="wt-osk-key-shift">&TScy;</sup></span>
+ <span class="wt-osk-key">&chcy;<sup class="wt-osk-key-shift">&CHcy;</sup></span>
+ <span class="wt-osk-key">&shcy;<sup class="wt-osk-key-shift">&SHcy;</sup></span>
+ <span class="wt-osk-key">&shchcy;<sup class="wt-osk-key-shift">&SHCHcy;</sup></span>
+ <span class="wt-osk-key">&hardcy;<sup class="wt-osk-key-shift">&HARDcy;</sup></span>
+ <span class="wt-osk-key">&ycy;<sup class="wt-osk-key-shift">&Ycy;</sup></span>
+ <span class="wt-osk-key">&softcy;<sup class="wt-osk-key-shift">&SOFTcy;</sup></span>
+ <span class="wt-osk-key">&ecy;<sup class="wt-osk-key-shift">&Ecy;</sup></span>
+ <span class="wt-osk-key">&yucy;<sup class="wt-osk-key-shift">&YUcy;</sup></span>
+ <span class="wt-osk-key">&yacy;<sup class="wt-osk-key-shift">&YAcy;</sup></span>
+ </div>
+ <!-- Greek alphabet -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-grek" dir="ltr" hidden>
+ <span class="wt-osk-key">&alpha;<sup class="wt-osk-key-shift">&Alpha;</sup></span>
+ <span class="wt-osk-key">&beta;<sup class="wt-osk-key-shift">&Beta;</sup></span>
+ <span class="wt-osk-key">&gamma;<sup class="wt-osk-key-shift">&Gamma;</sup></span>
+ <span class="wt-osk-key">&delta;<sup class="wt-osk-key-shift">&Delta;</sup></span>
+ <span class="wt-osk-key">&epsilon;<sup class="wt-osk-key-shift">&Epsilon;</sup></span>
+ <span class="wt-osk-key">&zeta;<sup class="wt-osk-key-shift">&Zeta;</sup></span>
+ <span class="wt-osk-key">&eta;<sup class="wt-osk-key-shift">&eta;</sup></span>
+ <span class="wt-osk-key">&theta;<sup class="wt-osk-key-shift">&Theta;</sup></span>
+ <span class="wt-osk-key">&iota;<sup class="wt-osk-key-shift">&Iota;</sup></span>
+ <span class="wt-osk-key">&kappa;<sup class="wt-osk-key-shift">&Kappa;</sup></span>
+ <span class="wt-osk-key">&lambda;<sup class="wt-osk-key-shift">&Lambda;</sup></span>
+ <span class="wt-osk-key">&mu;<sup class="wt-osk-key-shift">&Mu;</sup></span>
+ <span class="wt-osk-key">&nu;<sup class="wt-osk-key-shift">&Nu;</sup></span>
+ <span class="wt-osk-key">&xi;<sup class="wt-osk-key-shift">&Xi;</sup></span>
+ <span class="wt-osk-key">&omicron;<sup class="wt-osk-key-shift">&Omicron;</sup></span>
+ <span class="wt-osk-key">&pi;<sup class="wt-osk-key-shift">&Pi;</sup></span>
+ <span class="wt-osk-key">&rho;<sup class="wt-osk-key-shift">&Rho;</sup></span>
+ <span class="wt-osk-key">&sigma;<sup class="wt-osk-key-shift">&Sigma;</sup></span>
+ <span class="wt-osk-key">&tau;<sup class="wt-osk-key-shift">&Tau;</sup></span>
+ <span class="wt-osk-key">&upsilon;<sup class="wt-osk-key-shift">&Upsilon;</sup></span>
+ <span class="wt-osk-key">&phi;<sup class="wt-osk-key-shift">&Phi;</sup></span>
+ <span class="wt-osk-key">&chi;<sup class="wt-osk-key-shift">&chi;</sup></span>
+ <span class="wt-osk-key">&psi;<sup class="wt-osk-key-shift">&Psi;</sup></span>
+ <span class="wt-osk-key">&omega;<sup class="wt-osk-key-shift">&Omega;</sup></span>
+ </div>
+ <!-- Arabic alphabet -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-arab" dir="rtl" hidden>
+ <span class="wt-osk-key">ا</span>
+ <span class="wt-osk-key">ب</span>
+ <span class="wt-osk-key">ت</span>
+ <span class="wt-osk-key">ثج</span>
+ <span class="wt-osk-key">ح</span>
+ <span class="wt-osk-key">خ</span>
+ <span class="wt-osk-key">د</span>
+ <span class="wt-osk-key">ذ</span>
+ <span class="wt-osk-key">ر</span>
+ <span class="wt-osk-key">ز</span>
+ <span class="wt-osk-key">س</span>
+ <span class="wt-osk-key">ش</span>
+ <span class="wt-osk-key">ص</span>
+ <span class="wt-osk-key">ض</span>
+ <span class="wt-osk-key">ط</span>
+ <span class="wt-osk-key">ظ</span>
+ <span class="wt-osk-key">ع</span>
+ <span class="wt-osk-key">غ</span>
+ <span class="wt-osk-key">ف</span>
+ <span class="wt-osk-key">ق</span>
+ <span class="wt-osk-key">ك</span>
+ <span class="wt-osk-key">ل</span>
+ <span class="wt-osk-key">من</span>
+ <span class="wt-osk-key">ه</span>
+ <span class="wt-osk-key">و</span>
+ <span class="wt-osk-key">ي</span>
+ <span class="wt-osk-key">آ</span>
+ <span class="wt-osk-key">ة</span>
+ <span class="wt-osk-key">ى</span>
+ <span class="wt-osk-key">ی</span>
+ </div>
+ <!-- Hebrew alphabet -->
+ <div class="wt-osk-group wt-osk-script wt-osk-script-hebr" dir="rtl" hidden>
+ <span class="wt-osk-key">&#x5d0;</span>
+ <span class="wt-osk-key">&#x5d1;</span>
+ <span class="wt-osk-key">&#x5d2;</span>
+ <span class="wt-osk-key">&#x5d3;</span>
+ <span class="wt-osk-key">&#x5d4;</span>
+ <span class="wt-osk-key">&#x5d5;</span>
+ <span class="wt-osk-key">&#x5d6;</span>
+ <span class="wt-osk-key">&#x5d7;</span>
+ <span class="wt-osk-key">&#x5d8;</span>
+ <span class="wt-osk-key">&#x5d9;</span>
+ <span class="wt-osk-key">&#x5da;</span>
+ <span class="wt-osk-key">&#x5db;</span>
+ <span class="wt-osk-key">&#x5dc;</span>
+ <span class="wt-osk-key">&#x5dd;</span>
+ <span class="wt-osk-key">&#x5de;</span>
+ <span class="wt-osk-key">&#x5df;</span>
+ <span class="wt-osk-key">&#x5e0;</span>
+ <span class="wt-osk-key">&#x5e1;</span>
+ <span class="wt-osk-key">&#x5e2;</span>
+ <span class="wt-osk-key">&#x5e3;</span>
+ <span class="wt-osk-key">&#x5e4;</span>
+ <span class="wt-osk-key">&#x5e5;</span>
+ <span class="wt-osk-key">&#x5e6;</span>
+ <span class="wt-osk-key">&#x5e7;</span>
+ <span class="wt-osk-key">&#x5e8;</span>
+ <span class="wt-osk-key">&#x5e9;</span>
+ <span class="wt-osk-key">&#x5ea;</span>
+ <span class="wt-osk-key">&#x5f0;</span>
+ <span class="wt-osk-key">&#x5f1;</span>
+ <span class="wt-osk-key">&#x5f2;</span>
+ <span class="wt-osk-key">&#x5f3;</span>
+ <span class="wt-osk-key">&#x5f4;</span>
+ </div>
+ </div>
+ </div>
+ <?php
+ }
}
diff --git a/app/Functions/FunctionsPrint.php b/app/Functions/FunctionsPrint.php
index 9a0d24b149..fa0de25f13 100644
--- a/app/Functions/FunctionsPrint.php
+++ b/app/Functions/FunctionsPrint.php
@@ -15,12 +15,13 @@
*/
namespace Fisharebest\Webtrees\Functions;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Config;
-use Fisharebest\Webtrees\Controller\SearchController;
use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeStat;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeTemp;
use Fisharebest\Webtrees\GedcomRecord;
@@ -33,7 +34,6 @@ use Fisharebest\Webtrees\Note;
use Fisharebest\Webtrees\Place;
use Fisharebest\Webtrees\Session;
use Fisharebest\Webtrees\Theme;
-use Fisharebest\Webtrees\Tree;
use Rhumsaa\Uuid\Uuid;
/**
@@ -45,23 +45,13 @@ class FunctionsPrint {
*
* find and print a given individuals information for a pedigree chart
*
- * @param Individual $person The person to print
- * @param bool $show_full The style to print the box in, 0 for smaller boxes, 1 for larger boxes
+ * @param Individual $person The person to print
*/
- public static function printPedigreePerson(Individual $person = null, $show_full = true) {
-
- if ($show_full) {
- if ($person === null) {
- echo Theme::theme()->individualBoxEmpty();
- } else {
- echo Theme::theme()->individualBox($person);
- }
+ public static function printPedigreePerson(Individual $person = null) {
+ if ($person) {
+ echo Theme::theme()->individualBox($person);
} else {
- if ($person === null) {
- echo Theme::theme()->individualBoxSmallEmpty();
- } else {
- echo Theme::theme()->individualBoxSmall($person);
- }
+ echo Theme::theme()->individualBoxEmpty();
}
}
@@ -187,54 +177,32 @@ class FunctionsPrint {
* Print a link for a popup help window.
*
* @param string $help_topic
- * @param string $module
*
* @return string
*/
- public static function helpLink($help_topic, $module = '') {
- return '<span class="icon-help" onclick="helpDialog(\'' . $help_topic . '\',\'' . $module . '\'); return false;">&nbsp;</span>';
- }
+ public static function helpLink($help_topic) {
+ $title = '';
+ $text = '';
+ require 'help_text.php';
- /**
- * Print an external help link to the wiki site.
- *
- * @deprecated - nothing should be so complicated that it needs lengthy instructions!
- *
- * @param string $topic
- *
- * @return string
- */
- public static function wikiHelpLink($topic) {
- return '<a class="help icon-wiki" href="' . WT_WEBTREES_WIKI . $topic . '" title="' . I18N::translate('webtrees wiki') . '"></a>';
- }
-
- /**
- * When a user has searched for text, highlight any matches in
- * the displayed string.
- *
- * @param string $string
- *
- * @return string
- */
- public static function highlightSearchHits($string) {
- global $controller;
-
- if ($controller instanceof SearchController && $controller->query) {
- // TODO: when a search contains multiple words, we search independently.
- // e.g. searching for "FOO BAR" will find records containing both FOO and BAR.
- // However, we only highlight the original search string, not the search terms.
- // The controller needs to provide its "query_terms" array.
- $regex = [];
- foreach ([$controller->query] as $search_term) {
- $regex[] = preg_quote($search_term, '/');
- }
- // Match these strings, provided they do not occur inside HTML tags
- $regex = '(' . implode('|', $regex) . ')(?![^<]*>)';
-
- return preg_replace('/' . $regex . '/i', '<span class="search_hit">$1</span>', $string);
- } else {
- return $string;
- }
+ return
+ FontAwesome::linkIcon('help', I18N::translate('Help'), ['class' => 'btn btn-link', 'data-toggle' => 'modal', 'href' => '#', 'data-target' => '#wt-help-modal']) . '
+ <div class="modal fade" id="wt-help-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h3 class="modal-title" id="wt-modal-title">' . $title . '</h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="'. I18N::translate('close') .'">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">' . $text . '</div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">' . I18N::translate('close') . '</button>
+ </div>
+ </div>
+ </div>
+ </div>';
}
/**
@@ -463,9 +431,9 @@ class FunctionsPrint {
if ($map_lati && $map_long) {
$map_lati = trim(strtr($map_lati, 'NSEW,�', ' - -. ')); // S5,6789 ==> -5.6789
$map_long = trim(strtr($map_long, 'NSEW,�', ' - -. ')); // E3.456� ==> 3.456
- $html .= ' <a rel="nofollow" href="https://maps.google.com/maps?q=' . $map_lati . ',' . $map_long . '" class="icon-googlemaps" title="' . I18N::translate('Google Maps™') . '"></a>';
- $html .= ' <a rel="nofollow" href="https://www.bing.com/maps/?lvl=15&cp=' . $map_lati . '~' . $map_long . '" class="icon-bing" title="' . I18N::translate('Bing Maps™') . '"></a>';
- $html .= ' <a rel="nofollow" href="https://www.openstreetmap.org/#map=15/' . $map_lati . '/' . $map_long . '" class="icon-osm" title="' . I18N::translate('OpenStreetMap™') . '"></a>';
+ $html .= FontAwesome::linkIcon('google-maps', I18N::translate('Google Maps™'), ['class' => 'btn btn-link', 'url' => 'https://maps.google.com/maps?q=' . $map_lati . ',' . $map_long, 'rel' => 'nofollow']);
+ $html .= FontAwesome::linkIcon('bing-maps', I18N::translate('Bing Maps™'), ['class' => 'btn btn-link', 'url' => 'https://www.bing.com/maps/?lvl=15&cp=' . $map_lati . '~' . $map_long, 'rel' => 'nofollow']);
+ $html .= FontAwesome::linkIcon('openstreetmap', I18N::translate('OpenStreetMap™'), ['class' => 'btn btn-link', 'url' => 'https://www.openstreetmap.org/#map=15/' . $map_lati . '/' . $map_long, 'rel' => 'nofollow']);
}
if (preg_match('/\d NOTE (.*)/', $placerec, $match)) {
$html .= '<br>' . self::printFactNotes($placerec, 3);
@@ -544,7 +512,7 @@ class FunctionsPrint {
if ($fact['type'] == $type || $fact['type'] == 'all') {
if ($newRow) {
$newRow = false;
- echo '<tr class="noprint"><td class="descriptionbox">';
+ echo '<tr><td class="descriptionbox">';
echo I18N::translate('Add from clipboard'), '</td>';
echo '<td class="optionbox wrap"><form name="newFromClipboard" onsubmit="return false;">';
echo '<select id="newClipboardFact">';
@@ -607,12 +575,15 @@ class FunctionsPrint {
uasort($translated_addfacts, function ($x, $y) {
return I18N::strcasecmp(I18N::translate($x), I18N::translate($y));
});
- echo '<tr class="noprint"><td class="descriptionbox">';
+ echo '<tr><td class="descriptionbox">';
echo I18N::translate('Fact or event');
echo '</td>';
echo '<td class="optionbox wrap">';
- echo '<form name="newfactform" onsubmit="return false;">';
- echo '<select id="newfact" name="newfact">';
+ echo '<form action="edit_interface.php">';
+ echo '<input type="hidden" name="action" value="add">';
+ echo '<input type="hidden" name="xref" value="' . $id . '">';
+ echo '<input type="hidden" name="ged" value="' . $WT_TREE->getNameHtml() . '">';
+ echo '<select name="fact">';
echo '<option value="" disabled selected>' . I18N::translate('&lt;select&gt;') . '</option>';
foreach ($translated_addfacts as $fact => $fact_name) {
echo '<option value="', $fact, '">', $fact_name, '</option>';
@@ -622,12 +593,13 @@ class FunctionsPrint {
echo '<option value="EVEN">', I18N::translate('Custom event'), '</option>';
}
echo '</select>';
- echo '<input type="button" value="', /* I18N: A button label. */ I18N::translate('add'), '" onclick="add_record(\'' . $id . '\', \'newfact\');">';
+ echo '<input type="submit" value="', /* I18N: A button label. */ I18N::translate('add'), '">';
+ echo '</form>';
echo '<span class="quickfacts">';
foreach ($quickfacts as $fact) {
- echo '<a href="#" onclick="add_new_record(\'' . $id . '\', \'' . $fact . '\');return false;">', GedcomTag::getLabel($fact), '</a>';
+ echo '<a href="edit_interface.php?action=add&amp;fact=' . $fact . '&amp;xref=' . $id . '&amp;ged=' . $WT_TREE->getNameHtml() . '">', GedcomTag::getLabel($fact), '</a>';
}
- echo '</span></form>';
+ echo '</span>';
echo '</td></tr>';
}
@@ -666,47 +638,6 @@ class FunctionsPrint {
}
/**
- * HTML link to find an individual.
- *
- * @param string $element_id
- * @param string $indiname
- * @param Tree $tree
- *
- * @return string
- */
- public static function printFindIndividualLink($element_id, $indiname = '', $tree = null) {
- global $WT_TREE;
-
- if ($tree === null) {
- $tree = $WT_TREE;
- }
-
- return '<a href="#" onclick="findIndi(document.getElementById(\'' . $element_id . '\'), document.getElementById(\'' . $indiname . '\'), \'' . $tree->getNameHtml() . '\'); return false;" class="icon-button_indi" title="' . I18N::translate('Find an individual') . '"></a>';
- }
-
- /**
- * HTML link to find a place.
- *
- * @param string $element_id
- *
- * @return string
- */
- public static function printFindPlaceLink($element_id) {
- return '<a href="#" onclick="findPlace(document.getElementById(\'' . $element_id . '\'), WT_GEDCOM); return false;" class="icon-button_place" title="' . I18N::translate('Find a place') . '"></a>';
- }
-
- /**
- * HTML link to find a family.
- *
- * @param string $element_id
- *
- * @return string
- */
- public static function printFindFamilyLink($element_id) {
- return '<a href="#" onclick="findFamily(document.getElementById(\'' . $element_id . '\'), WT_GEDCOM); return false;" class="icon-button_family" title="' . I18N::translate('Find a family') . '"></a>';
- }
-
- /**
* HTML link to open the special character window.
*
* @param string $element_id
@@ -714,7 +645,7 @@ class FunctionsPrint {
* @return string
*/
public static function printSpecialCharacterLink($element_id) {
- return '<span onclick="findSpecialChar(document.getElementById(\'' . $element_id . '\')); if (window.updatewholename) { updatewholename(); } return false;" class="icon-button_keyboard" title="' . I18N::translate('Find a special character') . '"></span>';
+ return FontAwesome::linkIcon('keyboard', I18N::translate('Find a special character'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'findSpecialChar(document.getElementById("' . $element_id . '")); if (window.updatewholename) { updatewholename(); } return false;']);
}
/**
@@ -734,53 +665,6 @@ class FunctionsPrint {
}
/**
- * HTML link to find a source.
- *
- * @param string $element_id
- * @param string $sourcename
- *
- * @return string
- */
- public static function printFindSourceLink($element_id, $sourcename = '') {
- return '<a href="#" onclick="findSource(document.getElementById(\'' . $element_id . '\'), document.getElementById(\'' . $sourcename . '\'), WT_GEDCOM); return false;" class="icon-button_source" title="' . I18N::translate('Find a source') . '"></a>';
- }
-
- /**
- * HTML link to find a note.
- *
- * @param string $element_id
- * @param string $notename
- *
- * @return string
- */
- public static function printFindNoteLink($element_id, $notename = '') {
- return '<a href="#" onclick="findnote(document.getElementById(\'' . $element_id . '\'), document.getElementById(\'' . $notename . '\'), \'WT_GEDCOM\'); return false;" class="icon-button_find" title="' . I18N::translate('Find a shared note') . '"></a>';
- }
-
- /**
- * HTML link to find a repository.
- *
- * @param string $element_id
- *
- * @return string
- */
- public static function printFindRepositoryLink($element_id) {
- return '<a href="#" onclick="findRepository(document.getElementById(\'' . $element_id . '\'), WT_GEDCOM); return false;" class="icon-button_repository" title="' . I18N::translate('Find a repository') . '"></a>';
- }
-
- /**
- * HTML link to find a media object.
- *
- * @param string $element_id
- * @param string $choose
- *
- * @return string
- */
- public static function printFindMediaLink($element_id, $choose = '') {
- return '<a href="#" onclick="findMedia(document.getElementById(\'' . $element_id . '\'), \'' . $choose . '\', WT_GEDCOM); return false;" class="icon-button_media" title="' . I18N::translate('Find a media object') . '"></a>';
- }
-
- /**
* HTML link to find a fact.
*
* @param string $element_id
diff --git a/app/Functions/FunctionsPrintFacts.php b/app/Functions/FunctionsPrintFacts.php
index 7f470280d0..a700031866 100644
--- a/app/Functions/FunctionsPrintFacts.php
+++ b/app/Functions/FunctionsPrintFacts.php
@@ -20,6 +20,7 @@ use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeAdop;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeQuay;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeRela;
@@ -171,36 +172,11 @@ class FunctionsPrintFacts {
if ($fact->getFactId() != 'histo' && $fact->canEdit()) {
?>
- <a
- href="#"
- title="<?= I18N::translate('Edit') ?>"
- onclick="return edit_record('<?= $parent->getXref() ?>', '<?= $fact->getFactId() ?>');"
- ><?= $label ?></a>
+ <?= $label ?>
<div class="editfacts">
- <div class="editlink">
- <a
- href="#"
- title="<?= I18N::translate('Edit') ?>"
- class="editicon"
- onclick="return edit_record('<?= $parent->getXref() ?>', '<?= $fact->getFactId() ?>');"
- ><span class="link_text"><?= I18N::translate('Edit') ?></span></a>
- </div>
- <div class="copylink">
- <a
- href="#"
- title="<?= I18N::translate('Copy') ?>"
- class="copyicon"
- onclick="return copy_fact('<?= $parent->getXref() ?>', '<?= $fact->getFactId() ?>');"
- ><span class="link_text"><?= I18N::translate('Copy') ?></span></a>
- </div>
- <div class="deletelink">
- <a
- href="#"
- title="<?= I18N::translate('Delete') ?>"
- class="deleteicon"
- onclick="return delete_fact('<?= I18N::translate('Are you sure you want to delete this fact?') ?>', '<?= $parent->getXref() ?>', '<?= $fact->getFactId() ?>');"
- ><span class="link_text"><?= I18N::translate('Delete') ?></span></a>
- </div>
+ <?= FontAwesome::linkIcon('edit', I18N::translate('Edit'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=edit&xref=' . $parent->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $parent->getTree()->getNameHtml()]) ?>
+ <?= FontAwesome::linkIcon('copy', I18N::translate('Copy'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return copy_fact("' . $parent->getXref() . '", "' . $fact->getFactId() . '");']) ?>
+ <?= FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $parent->getXref() . '", "' . $fact->getFactId() . '");']) ?>
</div>
<?php
} else {
@@ -790,7 +766,7 @@ class FunctionsPrintFacts {
echo GedcomTag::getLabel($factname, $parent);
}
} elseif ($can_edit) {
- echo "<a onclick=\"return edit_record('$pid', '$fact_id');\" href=\"#\" title=\"", I18N::translate('Edit'), '">';
+ echo '<a href="edit_interface.php?action=edit&amp;xref=' . $parent->getXref() . '&amp;fact_id=' . $fact->getFactId() . '&amp;ged=' . $parent->getTree()->getNameHtml() . '" title="', I18N::translate('Edit'), '">';
if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) {
if ($level == 1) {
echo '<i class="icon-source"></i> ';
@@ -802,11 +778,10 @@ class FunctionsPrintFacts {
// Inline sources can't be edited. Attempting to save one will convert it
// into a link, and delete it.
// e.g. "1 SOUR my source" becomes "1 SOUR @my source@" which does not exist.
- echo "<div class=\"editlink\"><a class=\"editicon\" onclick=\"return edit_record('$pid', '$fact_id');\" href=\"#\" title=\"" . I18N::translate('Edit') . '"><span class="link_text">' . I18N::translate('Edit') . '</span></a></div>';
- echo '<div class="copylink"><a class="copyicon" href="#" onclick="return copy_fact(\'', $pid, '\', \'', $fact_id, '\');" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>';
+ echo FontAwesome::linkIcon('edit', I18N::translate('Edit'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=edit&xref=' . $parent->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $parent->getTree()->getNameHtml()]);
+ echo FontAwesome::linkIcon('copy', I18N::translate('Copy'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return copy_fact("' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
}
- echo "<div class=\"deletelink\"><a class=\"deleteicon\" onclick=\"return delete_fact('" . I18N::translate('Are you sure you want to delete this fact?') . "', '$pid', '$fact_id');\" href=\"#\" title=\"" . I18N::translate('Delete') . '"><span class="link_text">' . I18N::translate('Delete') . '</span></a></div>';
- echo '</div>';
+ echo FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
} else {
echo GedcomTag::getLabel($factname, $parent);
}
@@ -1009,24 +984,17 @@ class FunctionsPrintFacts {
echo '<tr><td class="descriptionbox ', $styleadd, ' width20">';
}
if ($can_edit) {
- echo '<a onclick="return edit_record(\'', $pid, '\', \'', $fact_id, '\');" href="#" title="', I18N::translate('Edit'), '">';
if ($level < 2) {
- if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) {
- echo '<i class="icon-note"></i> ';
- }
- if ($note) {
+ if ($note instanceof Note) {
echo GedcomTag::getLabel('SHARED_NOTE');
+ echo FontAwesome::linkIcon('note', I18N::translate('View'), ['class' => 'btn btn-link', 'href' => $note->getRawUrl()]);
} else {
echo GedcomTag::getLabel('NOTE');
}
- echo '</a>';
echo '<div class="editfacts">';
- echo "<div class=\"editlink\"><a class=\"editicon\" onclick=\"return edit_record('$pid', '$fact_id');\" href=\"#\" title=\"" . I18N::translate('Edit') . '"><span class="link_text">' . I18N::translate('Edit') . '</span></a></div>';
- echo '<div class="copylink"><a class="copyicon" href="#" onclick="return copy_fact(\'', $pid, '\', \'', $fact_id, '\');" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>';
- echo "<div class=\"deletelink\"><a class=\"deleteicon\" onclick=\"return delete_fact('" . I18N::translate('Are you sure you want to delete this fact?') . "', '$pid', '$fact_id');\" href=\"#\" title=\"" . I18N::translate('Delete') . '"><span class="link_text">' . I18N::translate('Delete') . '</span></a></div>';
- if ($note) {
- echo '<a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a>';
- }
+ echo FontAwesome::linkIcon('edit', I18N::translate('Edit'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=edit&xref=' . $parent->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $parent->getTree()->getNameHtml()]);
+ echo FontAwesome::linkIcon('copy', I18N::translate('Copy'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return copy_fact("' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
+ echo FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
echo '</div>';
}
} else {
@@ -1057,8 +1025,7 @@ class FunctionsPrintFacts {
// Note is already printed
echo GedcomTag::getLabel($factname, $parent);
if ($note) {
- echo '<div class="editfacts"><a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a></div>';
-
+ echo FontAwesome::linkIcon('note', I18N::translate('View'), ['class' => 'btn btn-link', 'href' => $note->getRawUrl()]);
}
}
}
@@ -1166,12 +1133,11 @@ class FunctionsPrintFacts {
echo GedcomTag::getLabel($factname, $parent);
}
} elseif ($can_edit) {
- echo '<a onclick="window.open(\'addmedia.php?action=editmedia&amp;pid=', $media->getXref(), '\', \'_blank\', edit_window_specs); return false;" href="#" title="', I18N::translate('Edit'), '">';
- echo GedcomTag::getLabel($factname, $parent), '</a>';
+ echo GedcomTag::getLabel($factname, $parent);
echo '<div class="editfacts">';
- echo '<div class="editlink"><a class="editicon" onclick="window.open(\'addmedia.php?action=editmedia&amp;pid=', $media->getXref(), '\', \'_blank\', edit_window_specs); return false;" href="#" title="', I18N::translate('Edit'), '"><span class="link_text">', I18N::translate('Edit'), '</span></a></div>';
- echo '<div class="copylink"><a class="copyicon" href="#" onclick="jQuery.post(\'action.php\',{action:\'copy-fact\', type:\'\', factgedcom:\'' . rawurlencode($factrec) . '\'},function(){location.reload();})" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>';
- echo '<div class="deletelink"><a class="deleteicon" onclick="return delete_fact(\'', I18N::translate('Are you sure you want to delete this fact?'), '\', \'', $parent->getXref(), '\', \'', $fact->getFactId(), '\');" href="#" title="', I18N::translate('Delete'), '"><span class="link_text">', I18N::translate('Delete'), '</span></a></div>';
+ echo FontAwesome::linkIcon('edit', I18N::translate('Edit'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'window.open("addmedia.php?action=editmedia&pid=' . $media->getXref() . '"); return false;']);
+ echo FontAwesome::linkIcon('copy', I18N::translate('Copy'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return copy_fact("' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
+ echo FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $parent->getXref() . '", "' . $fact->getFactId() . '");']);
echo '</div>';
} else {
echo GedcomTag::getLabel($factname, $parent);
diff --git a/app/Functions/FunctionsPrintLists.php b/app/Functions/FunctionsPrintLists.php
index fef6593191..158ed11e8b 100644
--- a/app/Functions/FunctionsPrintLists.php
+++ b/app/Functions/FunctionsPrintLists.php
@@ -17,10 +17,12 @@ namespace Fisharebest\Webtrees\Functions;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Database;
+use Fisharebest\Webtrees\Datatables;
use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
@@ -79,14 +81,10 @@ class FunctionsPrintLists {
$table_id = 'table-indi-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
$("#' . $table_id . '").dataTable( {
dom: \'<"H"<"filtersH_' . $table_id . '">T<"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\',
' . I18N::datatablesI18N() . ',
- jQueryUI: true,
autoWidth: false,
processing: true,
retrieve: true,
@@ -139,9 +137,6 @@ class FunctionsPrintLists {
col.search(btn.data("filter-value")).draw();
}
});
-
- $(".indi-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
');
$stats = new Stats($WT_TREE);
@@ -162,7 +157,6 @@ class FunctionsPrintLists {
}
$html = '
- <div class="loading-image"></div>
<div class="indi-list">
<table id="' . $table_id . '">
<thead>
@@ -348,7 +342,7 @@ class FunctionsPrintLists {
$class = '';
$sex_image = '';
}
- $html .= '<a ' . $title . ' href="' . $individual->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
+ $html .= '<a ' . $title . ' href="' . $individual->getHtmlUrl() . '"' . $class . '>' . $name['full'] . '</a>' . $sex_image . '<br>';
}
$html .= $individual->getPrimaryParentsNames('parents details1', 'none');
$html .= '</td>';
@@ -359,7 +353,7 @@ class FunctionsPrintLists {
// SOSA
$html .= '<td class="center" data-sort="' . $key . '">';
if ($option === 'sosa') {
- $html .= '<a href="relationship.php?pid1=' . $indiviudals[1] . '&amp;pid2=' . $individual->getXref() . '" title="' . I18N::translate('Relationships') . '">' . I18N::number($key) . '</a>';
+ $html .= '<a href="relationship.php?pid1=' . $indiviudals[1] . '&amp;pid2=' . $individual->getXref() . '" title="' . I18N::translate('Relationships') . '" rel="nofollow">' . I18N::number($key) . '</a>';
}
$html .= '</td>';
@@ -391,7 +385,7 @@ class FunctionsPrintLists {
$html .= '<br>';
}
$html .= '<a href="' . $tmp->getURL() . '" title="' . strip_tags($tmp->getFullName()) . '">';
- $html .= FunctionsPrint::highlightSearchHits($tmp->getShortName()) . '</a>';
+ $html .= $tmp->getShortName() . '</a>';
}
$html .= '</td>';
@@ -430,7 +424,7 @@ class FunctionsPrintLists {
$age_at_death = '';
$age_at_death_sort = PHP_INT_MAX;
}
- $html .= '<td class="center" data-sort="' . $age_at_death_sort . '">' . $age_at_death . '</td>';
+ $html .= '<td class="center" data-sort="' . $age_at_death_sort . '">' . I18N::number($age_at_death) . '</td>';
// Death place
$html .= '<td>';
@@ -440,7 +434,7 @@ class FunctionsPrintLists {
$html .= '<br>';
}
$html .= '<a href="' . $tmp->getURL() . '" title="' . strip_tags($tmp->getFullName()) . '">';
- $html .= FunctionsPrint::highlightSearchHits($tmp->getShortName()) . '</a>';
+ $html .= $tmp->getShortName() . '</a>';
}
$html .= '</td>';
@@ -522,14 +516,10 @@ class FunctionsPrintLists {
$table_id = 'table-fam-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
$("#' . $table_id . '").dataTable( {
dom: \'<"H"<"filtersH_' . $table_id . '"><"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\',
' . I18N::datatablesI18N() . ',
- jQueryUI: true,
autoWidth: false,
processing: true,
retrieve: true,
@@ -580,9 +570,6 @@ class FunctionsPrintLists {
col.search(btn.data("filter-value")).draw();
}
});
-
- $(".fam-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
');
$stats = new Stats($WT_TREE);
@@ -601,7 +588,6 @@ class FunctionsPrintLists {
}
$html = '
- <div class="loading-image"></div>
<div class="fam-list">
<table id="' . $table_id . '">
<thead>
@@ -794,7 +780,7 @@ class FunctionsPrintLists {
}
// Only show married names if they are the name we are filtering by.
if ($name['type'] != '_MARNM' || $num == $husb->getPrimaryName()) {
- $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
+ $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . $name['full'] . '</a>' . $sex_image . '<br>';
}
}
// Husband parents
@@ -837,7 +823,7 @@ class FunctionsPrintLists {
}
// Only show married names if they are the name we are filtering by.
if ($name['type'] != '_MARNM' || $num == $wife->getPrimaryName()) {
- $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
+ $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . $name['full'] . '</a>' . $sex_image . '<br>';
}
}
// Wife parents
@@ -893,7 +879,7 @@ class FunctionsPrintLists {
$html .= '<br>';
}
$html .= '<a href="' . $tmp->getURL() . '" title="' . strip_tags($tmp->getFullName()) . '">';
- $html .= FunctionsPrint::highlightSearchHits($tmp->getShortName()) . '</a>';
+ $html .= $tmp->getShortName() . '</a>';
}
$html .= '</td>';
@@ -986,8 +972,6 @@ class FunctionsPrintLists {
* @return string
*/
public static function sourceTable($sources) {
- global $WT_TREE, $controller;
-
// Count the number of linked records. These numbers include private records.
// It is not good to bypass privacy, but many servers do not have the resources
// to process privacy for every record in the tree
@@ -1003,40 +987,8 @@ class FunctionsPrintLists {
$count_notes = Database::prepare(
"SELECT CONCAT(l_to, '@', l_file), COUNT(*) FROM `##other` JOIN `##link` ON l_from = o_id AND l_file = o_file AND o_type = 'NOTE' AND l_type = 'SOUR' GROUP BY l_to, l_file"
)->fetchAssoc();
-
- $html = '';
- $table_id = 'table-sour-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
- $("#' . $table_id . '").dataTable( {
- dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
- ' . I18N::datatablesI18N() . ',
- jQueryUI: true,
- autoWidth: false,
- processing: true,
- columns: [
- /* Title */ { type: "text" },
- /* Author */ { type: "text" },
- /* Individuals */ { type: "num" },
- /* Families */ { type: "num" },
- /* Media objects */ { type: "num" },
- /* Notes */ { type: "num" },
- /* Last change */ { visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . ' },
- /* Delete */ { visible: ' . (Auth::isManager($WT_TREE) ? 'true' : 'false') . ', sortable: false }
- ],
- displayLength: 20,
- pagingType: "full_numbers"
- });
- $(".source-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
- ');
-
- $html .= '<div class="loading-image"></div>';
- $html .= '<div class="source-list">';
- $html .= '<table id="' . $table_id . '"><thead><tr>';
+ $html = '';
+ $html .= '<table ' . Datatables::sourceTableAttributes() . '><thead><tr>';
$html .= '<th>' . I18N::translate('Title') . '</th>';
$html .= '<th>' . I18N::translate('Author') . '</th>';
$html .= '<th>' . I18N::translate('Individuals') . '</th>';
@@ -1067,9 +1019,9 @@ class FunctionsPrintLists {
$html .= '<br>';
}
if ($n == $source->getPrimaryName()) {
- $html .= '<a class="name2" href="' . $source->getHtmlUrl() . '">' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>';
+ $html .= '<a class="name2" href="' . $source->getHtmlUrl() . '">' . $name['full'] . '</a>';
} else {
- $html .= '<a href="' . $source->getHtmlUrl() . '">' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>';
+ $html .= '<a href="' . $source->getHtmlUrl() . '">' . $name['full'] . '</a>';
}
}
$html .= '</td>';
@@ -1080,7 +1032,7 @@ class FunctionsPrintLists {
} else {
$author = '';
}
- $html .= '<td data-sort="' . Filter::escapeHtml($author) . '">' . FunctionsPrint::highlightSearchHits($author) . '</td>';
+ $html .= '<td data-sort="' . Filter::escapeHtml($author) . '">' . $author . '</td>';
$key = $source->getXref() . '@' . $source->getTree()->getTreeId();
// Count of linked individuals
$num = array_key_exists($key, $count_individuals) ? $count_individuals[$key] : 0;
@@ -1097,10 +1049,10 @@ class FunctionsPrintLists {
// Last change
$html .= '<td data-sort="' . $source->lastChangeTimestamp(true) . '">' . $source->lastChangeTimestamp() . '</td>';
// Delete
- $html .= '<td><a href="#" title="' . I18N::translate('Delete') . '" class="deleteicon" onclick="return delete_record(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($source->getFullName()))) . "', '" . $source->getXref() . '\');"><span class="link_text">' . I18N::translate('Delete') . '</span></a></td>';
+ $html .= '<td>' . FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($source->getFullName()))) . '", "' . $source->getXref() . '");']) . '</td>';
$html .= '</tr>';
}
- $html .= '</tbody></table></div>';
+ $html .= '</tbody></table>';
return $html;
}
@@ -1113,8 +1065,6 @@ class FunctionsPrintLists {
* @return string
*/
public static function noteTable($notes) {
- global $WT_TREE, $controller;
-
// Count the number of linked records. These numbers include private records.
// It is not good to bypass privacy, but many servers do not have the resources
// to process privacy for every record in the tree
@@ -1132,37 +1082,7 @@ class FunctionsPrintLists {
)->fetchAssoc();
$html = '';
- $table_id = 'table-note-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
- $("#' . $table_id . '").dataTable({
- dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
- ' . I18N::datatablesI18N() . ',
- jQueryUI: true,
- autoWidth: false,
- processing: true,
- columns: [
- /* Title */ { type: "text" },
- /* Individuals */ { type: "num" },
- /* Families */ { type: "num" },
- /* Media objects */ { type: "num" },
- /* Sources */ { type: "num" },
- /* Last change */ { type: "num", visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . ' },
- /* Delete */ { visible: ' . (Auth::isManager($WT_TREE) ? 'true' : 'false') . ', sortable: false }
- ],
- displayLength: 20,
- pagingType: "full_numbers"
- });
- $(".note-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
- ');
-
- $html .= '<div class="loading-image"></div>';
- $html .= '<div class="note-list">';
- $html .= '<table id="' . $table_id . '"><thead><tr>';
+ $html .= '<table ' . Datatables::noteTableAttributes() . '><thead><tr>';
$html .= '<th>' . I18N::translate('Title') . '</th>';
$html .= '<th>' . I18N::translate('Individuals') . '</th>';
$html .= '<th>' . I18N::translate('Families') . '</th>';
@@ -1186,7 +1106,7 @@ class FunctionsPrintLists {
}
$html .= '<tr' . $class . '>';
// Count of linked notes
- $html .= '<td data-sort="' . Filter::escapeHtml($note->getSortName()) . '"><a class="name2" href="' . $note->getHtmlUrl() . '">' . FunctionsPrint::highlightSearchHits($note->getFullName()) . '</a></td>';
+ $html .= '<td data-sort="' . Filter::escapeHtml($note->getSortName()) . '"><a class="name2" href="' . $note->getHtmlUrl() . '">' . $note->getFullName() . '</a></td>';
$key = $note->getXref() . '@' . $note->getTree()->getTreeId();
// Count of linked individuals
$num = array_key_exists($key, $count_individuals) ? $count_individuals[$key] : 0;
@@ -1203,10 +1123,10 @@ class FunctionsPrintLists {
// Last change
$html .= '<td data-sort="' . $note->lastChangeTimestamp(true) . '">' . $note->lastChangeTimestamp() . '</td>';
// Delete
- $html .= '<td><a href="#" title="' . I18N::translate('Delete') . '" class="deleteicon" onclick="return delete_record(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($note->getFullName()))) . "', '" . $note->getXref() . '\');"><span class="link_text">' . I18N::translate('Delete') . '</span></a></td>';
+ $html .= '<td>' . FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($note->getFullName()))) . '", "' . $note->getXref() . '");']) . '</td>';
$html .= '</tr>';
}
- $html .= '</tbody></table></div>';
+ $html .= '</tbody></table>';
return $html;
}
@@ -1219,8 +1139,6 @@ class FunctionsPrintLists {
* @return string
*/
public static function repositoryTable($repositories) {
- global $WT_TREE, $controller;
-
// Count the number of linked records. These numbers include private records.
// It is not good to bypass privacy, but many servers do not have the resources
// to process privacy for every record in the tree
@@ -1228,36 +1146,8 @@ class FunctionsPrintLists {
"SELECT CONCAT(l_to, '@', l_file), COUNT(*) FROM `##sources` JOIN `##link` ON l_from = s_id AND l_file = s_file AND l_type = 'REPO' GROUP BY l_to, l_file"
)->fetchAssoc();
- $html = '';
- $table_id = 'table-repo-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
- $("#' . $table_id . '").dataTable({
- dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
- ' . I18N::datatablesI18N() . ',
- jQueryUI: true,
- autoWidth: false,
- processing: true,
- columns: [
- /* Name */ { type: "text" },
- /* Sources */ { type: "num" },
- /* Last change */ { visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . ' },
- /* Delete */ { visible: ' . (Auth::isManager($WT_TREE) ? 'true' : 'false') . ', sortable: false }
- ],
- displayLength: 20,
- pagingType: "full_numbers"
- });
- $(".repo-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
- ');
-
- $html .= '<div class="loading-image"></div>';
- $html .= '<div class="repo-list">';
- $html .= '<table id="' . $table_id . '"><thead><tr>';
- $html .= '<th>' . I18N::translate('Repository name') . '</th>';
+ $html = '';
+ $html .= '<table ' . Datatables::repositoryTableAttributes() . '><thead><tr>'; $html .= '<th>' . I18N::translate('Repository name') . '</th>';
$html .= '<th>' . I18N::translate('Sources') . '</th>';
$html .= '<th>' . I18N::translate('Last change') . '</th>';
$html .= '<th>' . I18N::translate('Delete') . '</th>';
@@ -1283,9 +1173,9 @@ class FunctionsPrintLists {
$html .= '<br>';
}
if ($n == $repository->getPrimaryName()) {
- $html .= '<a class="name2" href="' . $repository->getHtmlUrl() . '">' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>';
+ $html .= '<a class="name2" href="' . $repository->getHtmlUrl() . '">' . $name['full'] . '</a>';
} else {
- $html .= '<a href="' . $repository->getHtmlUrl() . '">' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>';
+ $html .= '<a href="' . $repository->getHtmlUrl() . '">' . $name['full'] . '</a>';
}
}
$html .= '</td>';
@@ -1296,7 +1186,7 @@ class FunctionsPrintLists {
// Last change
$html .= '<td data-sort="' . $repository->lastChangeTimestamp(true) . '">' . $repository->lastChangeTimestamp() . '</td>';
// Delete
- $html .= '<td><a href="#" title="' . I18N::translate('Delete') . '" class="deleteicon" onclick="return delete_record(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($repository->getFullName()))) . "', '" . $repository->getXref() . '\');"><span class="link_text">' . I18N::translate('Delete') . '</span></a></td>';
+ $html .= '<td>' . FontAwesome::linkIcon('delete', I18N::translate('Delete'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($repository->getFullName()))) . '", "' . $repository->getXref() . '");']) . '</td>';
$html .= '</tr>';
}
$html .= '</tbody></table></div>';
@@ -1317,14 +1207,10 @@ class FunctionsPrintLists {
$html = '';
$table_id = 'table-obje-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
$("#' . $table_id . '").dataTable({
dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
' . I18N::datatablesI18N() . ',
- jQueryUI: true,
autoWidth:false,
processing: true,
columns: [
@@ -1338,11 +1224,8 @@ class FunctionsPrintLists {
displayLength: 20,
pagingType: "full_numbers"
});
- $(".media-list").css("visibility", "visible");
- $(".loading-image").css("display", "none");
');
- $html .= '<div class="loading-image"></div>';
$html .= '<div class="media-list">';
$html .= '<table id="' . $table_id . '"><thead><tr>';
$html .= '<th>' . I18N::translate('Media') . '</th>';
@@ -1369,8 +1252,7 @@ class FunctionsPrintLists {
$html .= '<td>' . $media_object->displayImage() . '</td>';
// Media object name(s)
$html .= '<td data-sort="' . Filter::escapeHtml($media_object->getSortName()) . '">';
- $html .= '<a href="' . $media_object->getHtmlUrl() . '" class="list_item name2">';
- $html .= FunctionsPrint::highlightSearchHits($name) . '</a>';
+ $html .= '<a href="' . $media_object->getHtmlUrl() . '" class="list_item name2">' . $name . '</a>';
if (Auth::isEditor($media_object->getTree())) {
$html .= '<br><a href="' . $media_object->getHtmlUrl() . '">' . basename($media_object->getFilename()) . '</a>';
}
@@ -1405,28 +1287,7 @@ class FunctionsPrintLists {
* @return string
*/
public static function surnameTable($surnames, $script, Tree $tree) {
- global $controller;
-
$html = '';
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
- $(".surname-list").dataTable({
- dom: "t",
- jQueryUI: true,
- autoWidth: false,
- ' . I18N::datatablesI18N() . ',
- paging: false,
- sorting: [[0, "asc"]],
- columns: [
- /* Surname */ { type: "text" },
- /* Count */ { type: "num" }
- ]
- });
- ');
-
if ($script == 'famlist.php') {
$col_heading = I18N::translate('Spouses');
} else {
@@ -1434,7 +1295,7 @@ class FunctionsPrintLists {
}
$html .=
- '<table class="surname-list">' .
+ '<table ' . Datatables::surnameTableAttributes() . '>' .
'<thead>' .
'<tr>' .
'<th>' . I18N::translate('Surname') . '</th>' .
@@ -1468,7 +1329,7 @@ class FunctionsPrintLists {
foreach ($surns as $indis) {
$subtotal += count($indis);
}
- $html .= '<td class="center" data-sort="' . $subtotal . '">';
+ $html .= '<td class="text-center" data-sort="' . $subtotal . '">';
foreach ($surns as $indis) {
$html .= I18N::number(count($indis)) . '<br>';
}
@@ -1622,10 +1483,7 @@ class FunctionsPrintLists {
$html = '';
$table_id = 'table-even-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
- jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
$("#' . $table_id . '").dataTable({
dom: "t",
' . I18N::datatablesI18N() . ',
@@ -1634,7 +1492,6 @@ class FunctionsPrintLists {
lengthChange: false,
filter: false,
info: true,
- jQueryUI: true,
sorting: [[ ' . ($sort_by == 'alpha' ? 0 : 1) . ', "asc"]],
columns: [
/* Name */ { type: "text" },
diff --git a/app/GedcomCode/GedcomCodeName.php b/app/GedcomCode/GedcomCodeName.php
index 08fc3198b9..a11a3c72c6 100644
--- a/app/GedcomCode/GedcomCodeName.php
+++ b/app/GedcomCode/GedcomCodeName.php
@@ -156,7 +156,7 @@ class GedcomCodeName {
* @return string[]
*/
public static function getValues(GedcomRecord $record = null) {
- $values = [];
+ $values = ['' => ''];
foreach (self::$TYPES as $type) {
$values[$type] = self::getValue($type, $record);
}
diff --git a/app/GedcomCode/GedcomCodePedi.php b/app/GedcomCode/GedcomCodePedi.php
index 1191ec88d9..8f28e5d03b 100644
--- a/app/GedcomCode/GedcomCodePedi.php
+++ b/app/GedcomCode/GedcomCodePedi.php
@@ -104,7 +104,7 @@ class GedcomCodePedi {
* @return string[]
*/
public static function getValues(GedcomRecord $record = null) {
- $values = [];
+ $values = ['' => ''];
foreach (self::$TYPES as $type) {
$values[$type] = self::getValue($type, $record);
}
diff --git a/app/Html.php b/app/Html.php
index 629824a6cb..a1f37ae007 100644
--- a/app/Html.php
+++ b/app/Html.php
@@ -20,6 +20,36 @@ namespace Fisharebest\Webtrees;
*/
class Html {
/**
+ * Escape a string for inclusion within HTML.
+ *
+ * @param $string
+ *
+ * @return string
+ */
+ protected static function escape($string) {
+ return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
+ }
+
+ /**
+ * Convert an array of HTML attributes to an HTML string.
+ *
+ * @param array $attributes
+ *
+ * @return string
+ */
+ public static function attributes(array $attributes) {
+ $html = [];
+ foreach ($attributes as $key => $value) {
+ if (is_string($value) || is_integer($value)) {
+ $html[] = self::escape($key) . '="' . self::escape($value) . '"';
+ } elseif ($value !== false) {
+ $html[] = self::escape($key);
+ }
+ }
+
+ return implode(' ', $html);
+ }
+ /**
* Filenames are (almost?) always LTR, even on RTL systems.
*
* @param string $filename
@@ -27,6 +57,6 @@ class Html {
* @return string
*/
public static function filename($filename) {
- return '<samp class="filename" dir="ltr">' . Filter::escapeHtml($filename) . '</samp>';
+ return '<samp class="filename" dir="ltr">' . self::escape($filename) . '</samp>';
}
}
diff --git a/app/I18N.php b/app/I18N.php
index 49b818b2f3..7ae0a0f8a9 100644
--- a/app/I18N.php
+++ b/app/I18N.php
@@ -27,6 +27,7 @@ use Fisharebest\Localization\Locale\LocaleEnUs;
use Fisharebest\Localization\Locale\LocaleInterface;
use Fisharebest\Localization\Translation;
use Fisharebest\Localization\Translator;
+use Fisharebest\Webtrees\Functions\FunctionsEdit;
/**
* Internationalization (i18n) and localization (l10n).
@@ -112,7 +113,7 @@ class I18N {
public static function activeLocales() {
$code_list = Site::getPreference('LANGUAGES');
- if (empty($code_list)) {
+ if ($code_list === '') {
$codes = self::DEFAULT_LOCALES;
} else {
$codes = explode(',', $code_list);
@@ -167,20 +168,8 @@ class I18N {
*
* @return string
*/
- public static function datatablesI18N(array $lengths = null) {
- if ($lengths === null) {
- $lengths = [10, 20, 30, 50, 100, -1];
- }
-
- $length_menu = '';
- foreach ($lengths as $length) {
- $length_menu .=
- '<option value="' . $length . '">' .
- ($length === -1 ? /* I18N: listbox option, e.g. “10,25,50,100,all” */ self::translate('All') : self::number($length)) .
- '</option>';
- }
- $length_menu = '<select>' . $length_menu . '</select>';
- $length_menu = /* I18N: Display %s [records per page], %s is a placeholder for listbox containing numeric options */ self::translate('Display %s', $length_menu);
+ public static function datatablesI18N(array $lengths = [10, 20, 30, 50, 100, -1]) {
+ $length_options = Bootstrap4::select(FunctionsEdit::numericOptions($lengths), 10);
return
'"formatNumber": function(n) { return String(n).replace(/[0-9]/g, function(w) { return ("' . self::$locale->digits('0123456789') . '")[+w]; }); },' .
@@ -195,7 +184,7 @@ class I18N {
' "info": "' . /* I18N: %s are placeholders for numbers */ self::translate('Showing %1$s to %2$s of %3$s', '_START_', '_END_', '_TOTAL_') . '",' .
' "infoEmpty": "' . self::translate('Showing %1$s to %2$s of %3$s', self::$locale->digits('0'), self::$locale->digits('0'), self::$locale->digits('0')) . '",' .
' "infoFiltered": "' . /* I18N: %s is a placeholder for a number */ self::translate('(filtered from %s total entries)', '_MAX_') . '",' .
- ' "lengthMenu": "' . Filter::escapeJs($length_menu) . '",' .
+ ' "lengthMenu": "' . Filter::escapeJs(/* I18N: %s is a number of records per page */ self::translate('Display %s', $length_options)) . '",' .
' "loadingRecords": "' . self::translate('Loading…') . '",' .
' "processing": "' . self::translate('Loading…') . '",' .
' "search": "' . self::translate('Filter') . '",' .
@@ -310,16 +299,16 @@ class I18N {
/**
* Initialise the translation adapter with a locale setting.
*
- * @param string|null $code Use this locale/language code, or choose one automatically
+ * @param string $code Use this locale/language code, or choose one automatically
*
* @return string $string
*/
- public static function init($code = null) {
+ public static function init($code = '') {
global $WT_TREE;
mb_internal_encoding('UTF-8');
- if ($code !== null) {
+ if ($code !== '') {
// Create the specified locale
self::$locale = Locale::create($code);
} else {
diff --git a/app/Individual.php b/app/Individual.php
index 6a716ffcf9..87ba15c43b 100644
--- a/app/Individual.php
+++ b/app/Individual.php
@@ -538,18 +538,25 @@ class Individual extends GedcomRecord {
/**
* Get the range of years in which a individual lived. e.g. “1870–”, “1870–1920”, “–1920”.
- * Provide the full date using a tooltip.
+ * Provide the place and full date using a tooltip.
* For consistent layout in charts, etc., show just a “–” when no dates are known.
* Note that this is a (non-breaking) en-dash, and not a hyphen.
*
* @return string
*/
public function getLifeSpan() {
+ // Just the first part of the place name
+ $birth_place = preg_replace('/,.*/', '', $this->getBirthPlace());
+ $death_place = preg_replace('/,.*/', '', $this->getDeathPlace());
+ // Remove markup from dates
+ $birth_date = strip_tags($this->getBirthDate()->display());
+ $death_date = strip_tags($this->getDeathDate()->display());
+
return
/* I18N: A range of years, e.g. “1870–”, “1870–1920”, “–1920” */ I18N::translate(
'%1$s–%2$s',
- '<span title="' . strip_tags($this->getBirthDate()->display()) . '">' . $this->getBirthDate()->minimumDate()->format('%Y') . '</span>',
- '<span title="' . strip_tags($this->getDeathDate()->display()) . '">' . $this->getDeathDate()->minimumDate()->format('%Y') . '</span>'
+ '<span title="' . $birth_place . ' ' . $birth_date . '">' . $this->getBirthYear() . '</span>',
+ '<span title="' . $death_place . ' ' . $death_date . '">' . $this->getDeathYear() . '</span>'
);
}
@@ -882,7 +889,7 @@ class Individual extends GedcomRecord {
case 0:
return null;
case 1:
- return reset($families);
+ return $families[0];
default:
// If there is more than one FAMC record, choose the preferred parents:
// a) records with '2 _PRIMARY'
@@ -905,7 +912,7 @@ class Individual extends GedcomRecord {
}
// d) any record
- return reset($families);
+ return $families[0];
}
}
diff --git a/app/Mail.php b/app/Mail.php
index a6645c5eef..54c32fefb3 100644
--- a/app/Mail.php
+++ b/app/Mail.php
@@ -103,20 +103,20 @@ class Mail {
case 'sendmail':
return Swift_SendmailTransport::newInstance();
case 'external':
- $transport = Swift_SmtpTransport::newInstance()
- ->setHost(Site::getPreference('SMTP_HOST'))
- ->setPort(Site::getPreference('SMTP_PORT'))
- ->setLocalDomain(Site::getPreference('SMTP_HELO'));
+ $transport = Swift_SmtpTransport::newInstance()
+ ->setHost(Site::getPreference('SMTP_HOST'))
+ ->setPort(Site::getPreference('SMTP_PORT'))
+ ->setLocalDomain(Site::getPreference('SMTP_HELO'));
- if (Site::getPreference('SMTP_AUTH')) {
- $transport
- ->setUsername(Site::getPreference('SMTP_AUTH_USER'))
- ->setPassword(Site::getPreference('SMTP_AUTH_PASS'));
- }
+ if (Site::getPreference('SMTP_AUTH') === '1') {
+ $transport
+ ->setUsername(Site::getPreference('SMTP_AUTH_USER'))
+ ->setPassword(Site::getPreference('SMTP_AUTH_PASS'));
+ }
- if (Site::getPreference('SMTP_SSL') !== 'none') {
- $transport->setEncryption(Site::getPreference('SMTP_SSL'));
- }
+ if (Site::getPreference('SMTP_SSL') !== 'none') {
+ $transport->setEncryption(Site::getPreference('SMTP_SSL'));
+ }
return $transport;
default:
diff --git a/app/Menu.php b/app/Menu.php
index 2ca5ee0133..161d50f08a 100644
--- a/app/Menu.php
+++ b/app/Menu.php
@@ -15,8 +15,6 @@
*/
namespace Fisharebest\Webtrees;
-use Rhumsaa\Uuid\Uuid;
-
/**
* System for generating menus.
*/
@@ -64,35 +62,33 @@ class Menu {
}
/**
- * Convert this menu to an HTML list, for easy rendering of
- * lists of menus/nulls.
- *
- * @return string
- */
- public function __toString() {
- return $this->getMenuAsList();
- }
-
- /**
- * Render this menu using Bootstrap markup
+ * Render this menu using Bootstrap4 markup
*
* @return string
*/
- public function bootstrap() {
+ public function bootstrap4() {
if ($this->submenus) {
$submenus = '';
foreach ($this->submenus as $submenu) {
- $submenus .= $submenu->bootstrap();
+ $attrs = '';
+ foreach ($submenu->attrs as $key => $value) {
+ $attrs .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
+ }
+
+ $class = trim('dropdown-item ' . $submenu->class);
+ $submenus .= '<a class="' . $class . '" href="' . $submenu->link . '"' . $attrs . '>' . $submenu->label . '</a>';
}
+ $class = trim('nav-item dropdown ' . $this->class);
+
return
- '<li class="' . $this->class . ' dropdown">' .
- '<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">' .
+ '<li class="' . $class . '">' .
+ '<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">' .
$this->label .
- ' <span class="caret"></span></a>' .
- '<ul class="dropdown-menu" role="menu">' .
+ '<span class="caret"></span></a>' .
+ '<div class="dropdown-menu" role="menu">' .
$submenus .
- '</ul>' .
+ '</div>' .
'</li>';
} else {
$attrs = '';
@@ -100,7 +96,9 @@ class Menu {
$attrs .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
}
- return '<li class="' . $this->class . '"><a href="' . $this->link . '"' . $attrs . '>' . $this->label . '</a></li>';
+ $class = trim('nav-item ' . $this->class);
+
+ return '<li class="' . $class . '"><a class="nav-link" href="' . $this->link . '"' . $attrs . '>' . $this->label . '</a></li>';
}
}
@@ -217,40 +215,6 @@ class Menu {
}
/**
- * Render this menu using javascript popups..
- *
- * @return string
- */
- public function getMenu() {
- $menu_id = 'menu-' . Uuid::uuid4();
- $sub_menu_id = 'sub-' . $menu_id;
-
- $html = '<a href="' . $this->link . '"';
- foreach ($this->attrs as $key => $value) {
- $html .= ' ' . $key . '="' . Filter::escapeHtml($value) . '"';
- }
- if (!empty($this->submenus)) {
- $html .= ' onmouseover="show_submenu(\'' . $sub_menu_id . '\', \'' . $menu_id . '\');"';
- $html .= ' onmouseout="timeout_submenu(\'' . $sub_menu_id . '\');"';
- }
- $html .= '>' . $this->label . '</a>';
-
- if (!empty($this->submenus)) {
- $html .= '<div id="' . $sub_menu_id . '" class="' . $this->submenuclass . '"';
- $html .= ' style="position: absolute; visibility: hidden; z-index: 100; text-align: ' . (I18N::direction() === 'ltr' ? 'left' : 'right') . '"';
- $html .= ' onmouseover="show_submenu(\'' . $this->parentmenu . '\'); show_submenu(\'' . $sub_menu_id . '\');"';
- $html .= ' onmouseout="timeout_submenu(\'' . $sub_menu_id . '\');">';
- foreach ($this->submenus as $submenu) {
- $submenu->parentmenu = $sub_menu_id;
- $html .= $submenu->getMenu();
- }
- $html .= '</div>';
- }
-
- return '<div id="' . $menu_id . '" class="' . $this->menuclass . '">' . $html . '</div>';
- }
-
- /**
* Render this menu as an HTML list
*
* @return string
diff --git a/app/Module/AbstractModule.php b/app/Module/AbstractModule.php
index d4e57525a3..01d53a9244 100644
--- a/app/Module/AbstractModule.php
+++ b/app/Module/AbstractModule.php
@@ -149,9 +149,9 @@ abstract class AbstractModule {
* @param string $setting_name
* @param string $default
*
- * @return string|null
+ * @return string
*/
- public function getSetting($setting_name, $default = null) {
+ public function getPreference($setting_name, $default = '') {
$this->loadAllSettings();
if (array_key_exists($setting_name, $this->settings)) {
@@ -169,28 +169,21 @@ abstract class AbstractModule {
*
* @param string $setting_name
* @param string $setting_value
+ *
+ * @return $this
*/
- public function setSetting($setting_name, $setting_value) {
+ public function setPreference($setting_name, $setting_value) {
$this->loadAllSettings();
- if ($setting_value === null) {
- Database::prepare(
- "DELETE FROM `##module_setting` WHERE module_name = ? AND setting_name = ?"
- )->execute([$this->getName(), $setting_name]);
- unset($this->settings[$setting_name]);
- } elseif (!array_key_exists($setting_name, $this->settings)) {
- Database::prepare(
- "INSERT INTO `##module_setting` (module_name, setting_name, setting_value) VALUES (?, ?, ?)"
- )->execute([$this->getName(), $setting_name, $setting_value]);
- $this->settings[$setting_name] = $setting_value;
- } elseif ($setting_value != $this->settings[$setting_name]) {
+ if ($setting_value !== $this->getPreference($setting_name)) {
Database::prepare(
"UPDATE `##module_setting` SET setting_value = ? WHERE module_name = ? AND setting_name = ?"
)->execute([$setting_value, $this->getName(), $setting_name]);
+
$this->settings[$setting_name] = $setting_value;
- } else {
- // Setting already exists, but with the same value - do nothing.
}
+
+ return $this;
}
/**
diff --git a/app/Module/AlbumModule.php b/app/Module/AlbumModule.php
index 76d36aace0..d7580f457f 100644
--- a/app/Module/AlbumModule.php
+++ b/app/Module/AlbumModule.php
@@ -91,23 +91,22 @@ class AlbumModule extends AbstractModule implements ModuleTabInterface {
$html = '<div id="' . $this->getName() . '_content">';
//Show Lightbox-Album header Links
if (Auth::isEditor($WT_TREE)) {
- $html .= '<table class="facts_table"><tr class="noprint"><td class="descriptionbox rela">';
+ $html .= '<table class="facts_table"><tr><td class="descriptionbox rela">';
// Add a media object
if ($WT_TREE->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($WT_TREE)) {
$html .= '<span><a href="#" onclick="window.open(\'addmedia.php?action=showmediaform&linktoid=' . $controller->record->getXref() . '\', \'_blank\', \'resizable=1,scrollbars=1,top=50,height=780,width=600\');return false;">';
- $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_add.png" id="head_icon" class="icon" title="' . I18N::translate('Add a media object') . '" alt="' . I18N::translate('Add a media object') . '">';
+ $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_add.png" id="head_icon" class="icon" title="' . I18N::translate('Add a media object') . '">';
$html .= I18N::translate('Add a media object');
$html .= '</a></span>';
// Link to an existing item
$html .= '<span><a href="#" onclick="window.open(\'inverselink.php?linktoid=' . $controller->record->getXref() . '&linkto=person\', \'_blank\', \'resizable=1,scrollbars=1,top=50,height=300,width=450\');">';
- $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_link.png" id="head_icon" class="icon" title="' . I18N::translate('Link to an existing media object') . '" alt="' . I18N::translate('Link to an existing media object') . '">';
+ $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_link.png" id="head_icon" class="icon" title="' . I18N::translate('Link to an existing media object') . '">';
$html .= I18N::translate('Link to an existing media object');
$html .= '</a></span>';
}
if (Auth::isManager($WT_TREE) && $this->getMedia()) {
- // Popup Reorder Media
- $html .= '<span><a href="#" onclick="reorder_media(\'' . $controller->record->getXref() . '\')">';
- $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/images.png" id="head_icon" class="icon" title="' . I18N::translate('Re-order media') . '" alt="' . I18N::translate('Re-order media') . '">';
+ $html .= '<span><a href="edit_interface.php?action=reorder_media&amp;ged=' . $controller->record->getTree()->getNameHtml() . '&amp;xref=' . $controller->record->getXref() . '">';
+ $html .= '<img src="' . Theme::theme()->assetUrl() . 'images/images.png" id="head_icon" class="icon" title="' . I18N::translate('Re-order media') . '">';
$html .= I18N::translate('Re-order media');
$html .= '</a></span>';
}
@@ -196,11 +195,12 @@ class AlbumModule extends AbstractModule implements ModuleTabInterface {
}
$html .= '<li class="album-list-item">';
$html .= '<div class="album-image">' . $media->displayImage() . '</div>';
- $html .= '<div class="album-title">' . $menu->getMenu() . '</div>';
+ $html .= '<div class="album-title">' . $menu->bootstrap4() . '</div>';
$html .= '</li>';
}
$html .= '</ul>';
$html .= '</td></tr></table>';
+ $html .= '</div>';
return $html;
}
@@ -256,7 +256,7 @@ class AlbumModule extends AbstractModule implements ModuleTabInterface {
* @return bool
*/
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/**
diff --git a/app/Module/BatchUpdate/BatchUpdateBasePlugin.php b/app/Module/BatchUpdate/BatchUpdateBasePlugin.php
index 59c339eb78..8e8277bf4e 100644
--- a/app/Module/BatchUpdate/BatchUpdateBasePlugin.php
+++ b/app/Module/BatchUpdate/BatchUpdateBasePlugin.php
@@ -17,8 +17,8 @@ namespace Fisharebest\Webtrees\Module\BatchUpdate;
use Fisharebest\Algorithm\MyersDiff;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Module\BatchUpdateModule;
@@ -58,10 +58,10 @@ class BatchUpdateBasePlugin {
*/
public function getOptionsForm() {
return
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Keep the existing “last change” information') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Keep the existing “last change” information') . '</label>' .
'<div class="col-sm-9">' .
- FunctionsEdit::radioButtons('chan', [0 => I18N::translate('no'), 1 => I18N::translate('yes')], ($this->chan ? 1 : 0), 'class="radio-inline" onchange="this.form.submit();"') .
+ Bootstrap4::radioButtons('chan', [0 => I18N::translate('no'), 1 => I18N::translate('yes')], ($this->chan ? 1 : 0), true, ['onchange' => 'this.form.submit();']) .
'</div></div>';
}
@@ -112,7 +112,7 @@ class BatchUpdateBasePlugin {
}
}
- return '<pre class="gedcom-data">' . self::createEditLinks(implode("\n", $diff_lines)) . '</pre>';
+ return '<pre class="gedcom-data">' . self::createEditLinks(implode("\n", $diff_lines), $record) . '</pre>';
}
/**
@@ -140,14 +140,15 @@ class BatchUpdateBasePlugin {
/**
* Converted gedcom links into editable links
*
- * @param string $gedrec
+ * @param string $gedrec
+ * @param GedcomRecord $record
*
* @return string
*/
- public static function createEditLinks($gedrec) {
+ public static function createEditLinks($gedrec, GedcomRecord $record) {
return preg_replace(
"/@([^#@\n]+)@/m",
- '<a href="#" onclick="return edit_raw(\'\\1\');">@\\1@</a>',
+ '<a href="edit_interface.php?action=editraw&amp;ged=' . $record->getTree()->getNameHtml() . '&amp;xref=' . $record->getXref() .'">@\\1@</a>',
$gedrec
);
}
diff --git a/app/Module/BatchUpdate/BatchUpdateMarriedNamesPlugin.php b/app/Module/BatchUpdate/BatchUpdateMarriedNamesPlugin.php
index dc968389ce..0684500f8f 100644
--- a/app/Module/BatchUpdate/BatchUpdateMarriedNamesPlugin.php
+++ b/app/Module/BatchUpdate/BatchUpdateMarriedNamesPlugin.php
@@ -149,8 +149,8 @@ class BatchUpdateMarriedNamesPlugin extends BatchUpdateBasePlugin {
*/
public function getOptionsForm() {
return
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Surname option') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Surname option') . '</label>' .
'<div class="col-sm-9">' .
'<select class="form-control" name="surname" onchange="reset_reload();">' .
'<option value="replace" ' .
diff --git a/app/Module/BatchUpdate/BatchUpdateSearchReplacePlugin.php b/app/Module/BatchUpdate/BatchUpdateSearchReplacePlugin.php
index 8d429f3e67..4c0bab1c38 100644
--- a/app/Module/BatchUpdate/BatchUpdateSearchReplacePlugin.php
+++ b/app/Module/BatchUpdate/BatchUpdateSearchReplacePlugin.php
@@ -15,8 +15,8 @@
*/
namespace Fisharebest\Webtrees\Module\BatchUpdate;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\I18N;
/**
@@ -143,20 +143,20 @@ class BatchUpdateSearchReplacePlugin extends BatchUpdateBasePlugin {
];
return
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Search text/pattern') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Search text/pattern') . '</label>' .
'<div class="col-sm-9">' .
'<input class="form-control" name="search" size="40" value="' . Filter::escapeHtml($this->search) .
'" onchange="this.form.submit();">' .
'</div></div>' .
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Replacement text') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Replacement text') . '</label>' .
'<div class="col-sm-9">' .
'<input class="form-control" name="replace" size="40" value="' . Filter::escapeHtml($this->replace) .
'" onchange="this.form.submit();"></td></tr>' .
'</div></div>' .
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Search method') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Search method') . '</label>' .
'<div class="col-sm-9">' .
'<select class="form-control" name="method" onchange="this.form.submit();">' .
'<option value="exact" ' . ($this->method == 'exact' ? 'selected' : '') . '>' . I18N::translate('Exact text') . '</option>' .
@@ -166,10 +166,10 @@ class BatchUpdateSearchReplacePlugin extends BatchUpdateBasePlugin {
'</select>' .
'<p class="small text-muted">' . $descriptions[$this->method] . '</p>' . $this->error .
'</div></div>' .
- '<div class="form-group">' .
- '<label class="control-label col-sm-3">' . I18N::translate('Case insensitive') . '</label>' .
+ '<div class="row form-group">' .
+ '<label class="col-sm-3 col-form-label">' . I18N::translate('Case insensitive') . '</label>' .
'<div class="col-sm-9">' .
- FunctionsEdit::radioButtons('case', ['I' => I18N::translate('no'), 'i' => I18N::translate('yes')], ($this->case ? 'i' : 'I'), 'class="radio-inline" onchange="this.form.submit();"') .
+ Bootstrap4::radioButtons('case', ['I' => I18N::translate('no'), 'i' => I18N::translate('yes')], ($this->case ? 'i' : 'I'), true, ['onchange' => 'this.form.submit();']) .
'<p class="small text-muted">' . /* I18N: Help text for "Case insensitive" searches */ I18N::translate('Match both upper and lower case letters.') . '</p>' .
'</div></div>' .
parent::getOptionsForm();
diff --git a/app/Module/BatchUpdateModule.php b/app/Module/BatchUpdateModule.php
index a341c6c1cd..0b75a33907 100644
--- a/app/Module/BatchUpdateModule.php
+++ b/app/Module/BatchUpdateModule.php
@@ -16,11 +16,11 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
@@ -186,28 +186,27 @@ class BatchUpdateModule extends AbstractModule implements ModuleConfigInterface
->pageHeader();
echo $this->getJavascript();
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h2><?php echo $controller->getPageTitle(); ?></h2>
+ <h1><?= $controller->getPageTitle() ?></h1>
- <form id="batch_update_form" class="form-horizontal" action="module.php" method="get">
+ <form id="batch_update_form" class="form-horizontal" action="module.php">
<input type="hidden" name="mod" value="batch_update">
<input type="hidden" name="mod_action" value="admin_batch_update">
<input type="hidden" name="xref" value="' . $this->xref . '">
<input type="hidden" name="action" value=""><?php // will be set by javascript for next update ?>
<input type="hidden" name="data" value=""><?php // will be set by javascript for next update ?>
- <div class="form-group">
- <label class="control-label col-sm-3"><?php echo I18N::translate('Family tree') ?></label>
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label"><?= I18N::translate('Family tree') ?></label>
<div class="col-sm-9">
- <?php echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), '', $WT_TREE->getName(), 'class="form-control" onchange="reset_reload();"') ?>
+ <?= Bootstrap4::select(Tree::getNameList(), $WT_TREE->getName(), ['id' => 'ged', 'name' => 'ged', 'onchange' => 'reset_reload();']) ?>
</div>
</div>
- <div class="form-group">
- <label class="control-label col-sm-3"><?php echo I18N::translate('Batch update') ?></label>
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label"><?= I18N::translate('Batch update') ?></label>
<div class="col-sm-9">
<select class="form-control" name="plugin" onchange="reset_reload();">
<?php if (!$this->plugin): ?>
@@ -242,15 +241,15 @@ class BatchUpdateModule extends AbstractModule implements ModuleConfigInterface
<?php if ($this->curr_xref): ?>
<?php // Create an object, so we can get the latest version of the name. ?>
<?php $this->record = GedcomRecord::getInstance($this->curr_xref, $WT_TREE) ?>
- <div class="form-group">
+ <div class="row form-group">
<?= self::createSubmitButton(I18N::translate('previous'), $this->prev_xref) ?>
- <?= self::createSubmitButton(I18N::translate('next'), $this->next_xref) ?>
+ <?= self::createSubmitButton(I18N::translate('next'), $this->next_xref) ?>
</div>
- <div class="form-group">
+ <div class="row form-group">
<a class="lead" href="<?= $this->record->getHtmlUrl() ?>"><?= $this->record->getFullName() ?></a>
- <?= $this->PLUGIN->getActionPreview($this->record) ?>
+ <?= $this->PLUGIN->getActionPreview($this->record) ?>
</div>
- <div class="form-group">
+ <div class="row form-group">
<?= implode(' ', $this->PLUGIN->getActionButtons($this->curr_xref, $this->record)) ?>
</div>
<?php else: ?>
diff --git a/app/Module/CensusAssistantModule.php b/app/Module/CensusAssistantModule.php
index b54ae8c411..d681171106 100644
--- a/app/Module/CensusAssistantModule.php
+++ b/app/Module/CensusAssistantModule.php
@@ -13,17 +13,18 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Census\Census;
use Fisharebest\Webtrees\Census\CensusInterface;
-use Fisharebest\Webtrees\Controller\SimpleController;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\Functions;
use Fisharebest\Webtrees\Functions\FunctionsDb;
+use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
@@ -34,171 +35,361 @@ use Fisharebest\Webtrees\Soundex;
* Class CensusAssistantModule
*/
class CensusAssistantModule extends AbstractModule {
- /** {@inheritdoc} */
- public function getTitle() {
- return /* I18N: Name of a module */ I18N::translate('Census assistant');
- }
+ /** {@inheritdoc} */
+ public function getTitle() {
+ return /* I18N: Name of a module */
+ I18N::translate('Census assistant');
+ }
+
+ /** {@inheritdoc} */
+ public function getDescription() {
+ return /* I18N: Description of the “Census assistant” module */
+ I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
+ }
+
+ /**
+ * This is a general purpose hook, allowing modules to respond to routes
+ * of the form module.php?mod=FOO&mod_action=BAR
+ *
+ * @param string $mod_action
+ */
+ public function modAction($mod_action) {
+ global $WT_TREE;
+
+ switch ($mod_action) {
+ case 'census-header':
+ header('Content-Type: text/html; charset=utf8');
+ $census = Filter::get('census');
+ echo $this->censusTableHeader(new $census);
+ break;
+
+ case 'census-individual':
+ header('Content-Type: text/html; charset=utf8');
+ $census = Filter::get('census');
+ $individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
+ $head = Individual::getInstance(Filter::get('head'), $WT_TREE);
+ echo $this->censusTableRow(new $census, $individual, $head);
+ break;
+
+ case 'media_find':
+ self::mediaFind();
+ break;
+ case 'media_query_3a':
+ self::mediaQuery();
+ break;
+ default:
+ http_response_code(404);
+ }
+ }
+
+ /**
+ * @param Individual $individual
+ * @param CensusInterface $census
+ */
+ public function createCensusAssistant(Individual $individual) {
+ ?>
+
+ <div id="census-assistant-link" hidden>
+ <a href="#">
+ <?= I18N::translate('Create a shared note using the census assistant') ?>
+ </a>
+ </div>
+
+ <div id="census-assistant" hidden>
+ <input type="hidden" name="ca_census" id="ca-census">
+ <div class="form-group">
+ <div class="input-group">
+ <label for="census-assistant-title" class="input-group-addon">
+ <?= I18N::translate('Title') ?>
+ </label>
+ <input class="form-control" id="ca-title" name="ca_title" value="">
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="form-group col-sm-6">
+ <div class="input-group">
+ <label for="census-assistant-citation" class="input-group-addon">
+ <?= I18N::translate('Citation') ?>
+ </label>
+ <input class="form-control" id="census-assistant-citation" name="ca_citation">
+ </div>
+ </div>
+
+ <div class="form-group col-sm-6">
+ <div class="input-group">
+ <label for="census-assistant-place" class="input-group-addon">
+ <?= I18N::translate('Place') ?>
+ </label>
+ <input class="form-control" id="census-assistant-place" name="ca_place">
+ </div>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="input-group">
+ <span class="input-group-addon"><?= I18N::translate('Individuals') ?></span>
+ <?= FunctionsEdit::formControlIndividual($individual, ['id' => 'census-assistant-individual', 'style' => 'width:100%']) ?>
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-primary" id="census-assistant-add">
+ <?= FontAwesome::semanticIcon('add', I18N::translate('Add')) ?>
+ </button>
+ </span>
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-primary" id="census-assistant-head"
+ title="<?= I18N::translate('Head of household') ?>">
+ <?= FontAwesome::semanticIcon('individual', I18N::translate('Head of household')) ?>
+ </button>
+ </span>
+ </div>
+ </div>
+
+ <table class="table table-bordered table-small table-responsive wt-census-assistant-table"
+ id="census-assistant-table">
+ <thead class="wt-census-assistant-header"></thead>
+ <tbody class="wt-census-assistant-body"></tbody>
+ </table>
+
+ <div class="form-group">
+ <div class="input-group">
+ <label for="census-assistant-notes" class="input-group-addon">
+ <?= I18N::translate('Notes') ?>
+ </label>
+ <input class="form-control" id="census-assistant-notes" name="ca_notes">
+ </div>
+ </div>
+ </div>
+
+ <script>
+ // When a census date/place is selected, activate the census-assistant
+ function censusAssistantSelect () {
+ var censusAssistantLink = document.querySelector('#census-assistant-link');
+ var censusAssistant = document.querySelector('#census-assistant');
+ var censusOption = this.options[this.selectedIndex];
+ var census = censusOption.dataset.census;
+ var censusPlace = censusOption.dataset.place;
+ var censusYear = censusOption.value.substr(-4);
+
+ if (censusOption.value !== '') {
+ censusAssistantLink.removeAttribute('hidden');
+ } else {
+ censusAssistantLink.setAttribute('hidden', '');
+ }
+
+ censusAssistant.setAttribute('hidden', '');
+ document.querySelector('#ca-census').value = census;
+ document.querySelector('#ca-title').value = censusYear + ' ' + censusPlace + ' - <?= I18N::translate('Census transcript') ?> - <?= strip_tags($individual->getFullName()) ?> - <?= I18N::translate('Household') ?>';
+
+ fetch('module.php?mod=GEDFact_assistant&mod_action=census-header&census=' + census)
+ .then(function (response) {
+ return response.text();
+ })
+ .then(function (text) {
+ document.querySelector('#census-assistant-table thead').innerHTML = text;
+ document.querySelector('#census-assistant-table tbody').innerHTML = '';
+ });
+ }
- /** {@inheritdoc} */
- public function getDescription() {
- return /* I18N: Description of the “Census assistant” module */ I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
- }
+ // When the census assistant is activated, show the input fields
+ function censusAssistantLink () {
+ document.querySelector('#census-selector').setAttribute('hidden', '');
+ this.setAttribute('hidden', '');
+ document.getElementById('census-assistant').removeAttribute('hidden');
+ // Set the current individual as the head of household.
+ censusAssistantHead();
- /**
- * This is a general purpose hook, allowing modules to respond to routes
- * of the form module.php?mod=FOO&mod_action=BAR
- *
- * @param string $mod_action
- */
- public function modAction($mod_action) {
- switch ($mod_action) {
- case 'census_find':
- self::censusFind();
- break;
- case 'media_find':
- self::mediaFind();
- break;
- case 'media_query_3a':
- self::mediaQuery();
- break;
- default:
- http_response_code(404);
- }
- }
+ return false;
+ }
- /**
- * Find an individual.
- */
- private static function censusFind() {
- global $WT_TREE;
+ // Add the currently selected individual to the census
+ function censusAssistantAdd () {
+ var censusSelector = document.querySelector('#census-selector');
+ var census = censusSelector.options[censusSelector.selectedIndex].dataset.census;
+ var indi_selector = document.querySelector('#census-assistant-individual');
+ var xref = indi_selector.options[indi_selector.selectedIndex].value;
+ var headTd = document.querySelector('#census-assistant-table td');
+ var head = headTd === null ? xref : headTd.innerHTML;
- $controller = new SimpleController;
- $filter = Filter::get('filter');
- $action = Filter::get('action');
- $census = Filter::get('census');
- $census = new $census;
+ fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + head, {credentials: 'same-origin'})
+ .then(function (response) {
+ return response.text();
+ })
+ .then(function (text) {
+ document.querySelector('#census-assistant-table tbody').innerHTML += text;
+ });
- $controller
- ->restrictAccess($census instanceof CensusInterface)
- ->setPageTitle(I18N::translate('Find an individual'))
- ->pageHeader();
+ return false;
+ }
- echo '<table class="list_table width90" border="0">';
- echo '<tr><td style="padding: 10px;" class="facts_label03 width90">';
- echo I18N::translate('Find an individual');
- echo '</td>';
- echo '</table>';
- echo '<br>';
+ // Set the currently selected individual as the head of household
+ function censusAssistantHead () {
+ var censusSelector = document.querySelector('#census-selector');
+ var census = censusSelector.options[censusSelector.selectedIndex].dataset.census;
+ var indi_selector = document.querySelector('#census-assistant-individual');
+ var xref = indi_selector.options[indi_selector.selectedIndex].value;
- if ($action == 'filter') {
- $filter = trim($filter);
- $filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
+ fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + xref, {credentials: 'same-origin'})
+ .then(function (response) {
+ return response.text();
+ })
+ .then(function (text) {
+ document.querySelector('#census-assistant-table tbody').innerHTML = text;
+ });
- // Output Individual for GEDFact Assistant ======================
- echo '<table class="list_table width90">';
- $myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
- if ($myindilist) {
- echo '<tr><td class="list_value_wrap"><ul>';
- usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
- foreach ($myindilist as $indi) {
- echo '<li>';
- echo '<a href="#" onclick="window.opener.appendCensusRow(\'' . Filter::escapeJs(self::censusTableRow($census, $indi, null)) . '\'); window.close();">';
- echo '<b>' . $indi->getFullName() . '</b>';
- echo '</a>';
- echo $indi->formatFirstMajorFact(WT_EVENTS_BIRT, 1);
- echo $indi->formatFirstMajorFact(WT_EVENTS_DEAT, 1);
- echo '<hr>';
- echo '</li>';
- }
- echo '</ul></td></tr>';
- } else {
- echo '<tr><td class="list_value_wrap">';
- echo I18N::translate('No results found.');
- echo '</td></tr>';
- }
- echo '<tr><td>';
- echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
- echo '</td></tr>';
- echo '</table>';
- }
- }
+ return false;
+ }
- /**
- * Find a media object.
- */
- private static function mediaFind() {
- global $WT_TREE;
+ document.querySelector('#census-selector').addEventListener('change', censusAssistantSelect);
+ document.querySelector('#census-assistant-link').addEventListener('click', censusAssistantLink);
+ document.querySelector('#census-assistant-add').addEventListener('click', censusAssistantAdd);
+ document.querySelector('#census-assistant-head').addEventListener('click', censusAssistantHead);
+ </script>
+ <?php
+ }
- $controller = new SimpleController;
- $filter = Filter::get('filter');
- $multiple = Filter::getBool('multiple');
+ /**
+ * @param Individual $individual
+ * @param string $newged
+ *
+ * @return string
+ */
+ public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
+ $ca_title = Filter::post('ca_title');
+ $ca_place = Filter::post('ca_place');
+ $ca_citation = Filter::post('ca_citation');
+ $ca_individuals = Filter::postArray('ca_individuals');
+ $ca_notes = Filter::post('ca_notes');
+ $ca_census = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
- $controller
- ->setPageTitle(I18N::translate('Find an individual'))
- ->pageHeader();
+ if ($ca_census !== '' && !empty($ca_individuals)) {
+ $census = new $ca_census;
- ?>
- <script>
- function pasterow(id, name, gend, yob, age, bpl) {
- window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
- }
+ $note_text = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
+ $note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
+ $note = $individual->getTree()->createRecord($note_gedcom);
- function pasteid(id, name, thumb) {
- if (thumb) {
- window.opener.paste_id(id, name, thumb);
- <?php if (!$multiple) { echo 'window.close();'; } ?>
- } else {
- // GEDFact_assistant ========================
- if (window.opener.document.getElementById('addlinkQueue')) {
- window.opener.insertRowToTable(id, name);
- }
- window.opener.paste_id(id);
- if (window.opener.pastename) {
- window.opener.pastename(name);
- }
- <?php if (!$multiple) { echo 'window.close();'; } ?>
- }
- }
- function checknames(frm) {
- if (document.forms[0].subclick) {
- button = document.forms[0].subclick.value;
- } else {
- button = "";
- }
- if (frm.filter.value.length < 2 && button !== "all") {
- alert("<?= I18N::translate('Please enter more than one character.') ?>");
- frm.filter.focus();
- return false;
- }
- if (button=="all") {
- frm.filter.value = "";
- }
- return true;
- }
- </script>
+ $newged .= "\n2 NOTE @" . $note->getXref() . '@';
- <?php
- echo '<div>';
- echo '<table class="list_table width90" border="0">';
- echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
- echo $controller->getPageTitle();
- echo '</td>';
- echo '</tr>';
- echo '</table>';
- echo '<br>';
- echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
- echo '<br>';
+ // Add the census fact to the rest of the household
+ foreach (array_keys($ca_individuals) as $xref) {
+ if ($xref !== $individual->getXref()) {
+ Individual::getInstance($xref, $individual->getTree())
+ ->updateFact($fact_id, $newged, !$keep_chan);
+ }
+ }
+ }
- $filter = trim($filter);
- $filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
- echo '<table class="tabs_table width90"><tr>';
- $myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
- if ($myindilist) {
- echo '<td class="list_value_wrap"><ul>';
- usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
- foreach ($myindilist as $indi) {
- $nam = Filter::escapeHtml($indi->getFullName());
- echo "<li><a href=\"#\" onclick=\"pasterow(
+ return $newged;
+ }
+
+ /**
+ * @param CensusInterface $census
+ * @param string $ca_title
+ * @param string $ca_place
+ * @param string $ca_citation
+ * @param string[][] $ca_individuals
+ * @param string $ca_notes
+ *
+ * @return string
+ */
+ private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
+ $text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n.start_formatted_area.\n\n";
+
+ foreach ($census->columns() as $n => $column) {
+ if ($n > 0) {
+ $text .= '|';
+ }
+ $text .= '.b.' . $column->abbreviation();
+ }
+
+ foreach ($ca_individuals as $xref => $columns) {
+ $text .= "\n" . implode('|', $columns);
+ }
+
+ return $text . "\n.end_formatted_area.\n\n" . $ca_notes;
+ }
+
+ /**
+ * Find a media object.
+ */
+ private static function mediaFind() {
+ global $WT_TREE;
+
+ $controller = new SimpleController;
+ $filter = Filter::get('filter');
+ $multiple = Filter::getBool('multiple');
+
+ $controller
+ ->setPageTitle(I18N::translate('Find an individual'))
+ ->pageHeader();
+
+ ?>
+ <script>
+ function pasterow (id, name, gend, yob, age, bpl) {
+ window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
+ }
+
+ function pasteid (id, name, thumb) {
+ if (thumb) {
+ window.opener.paste_id(id, name, thumb);
+ <?php if (!$multiple) {
+ echo 'window.close();';
+ } ?>
+ } else {
+ // GEDFact_assistant ========================
+ if (window.opener.document.getElementById('addlinkQueue')) {
+ window.opener.insertRowToTable(id, name);
+ }
+ window.opener.paste_id(id);
+ if (window.opener.pastename) {
+ window.opener.pastename(name);
+ }
+ <?php if (!$multiple) {
+ echo 'window.close();';
+ } ?>
+ }
+ }
+
+ function checknames (frm) {
+ if (document.forms[0].subclick) {
+ button = document.forms[0].subclick.value;
+ } else {
+ button = '';
+ }
+ if (frm.filter.value.length < 2 && button !== 'all') {
+ alert('<?= I18N::translate('Please enter more than one character.') ?>');
+ frm.filter.focus();
+ return false;
+ }
+ if (button == 'all') {
+ frm.filter.value = '';
+ }
+ return true;
+ }
+ </script>
+
+ <?php
+ echo '<div>';
+ echo '<table class="list_table width90" border="0">';
+ echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
+ echo $controller->getPageTitle();
+ echo '</td>';
+ echo '</tr>';
+ echo '</table>';
+ echo '<br>';
+ echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
+ echo '<br>';
+
+ $filter = trim($filter);
+ $filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
+ echo '<table class="tabs_table width90"><tr>';
+ $myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
+ if ($myindilist) {
+ echo '<td class="list_value_wrap"><ul>';
+ usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
+ foreach ($myindilist as $indi) {
+ $nam = Filter::escapeHtml($indi->getFullName());
+ echo "<li><a href=\"#\" onclick=\"pasterow(
'" . $indi->getXref() . "' ,
'" . $nam . "' ,
'" . $indi->getSex() . "' ,
@@ -207,304 +398,199 @@ class CensusAssistantModule extends AbstractModule {
'" . $indi->getBirthPlace() . "'); return false;\">
<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
- $born = I18N::translate('Birth');
- echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
- echo '<hr>';
- }
- echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
- } else {
- echo '<td class="list_value_wrap">';
- echo I18N::translate('No results found.');
- echo '</td></tr>';
- }
- echo '</table>';
- echo '</div>';
- }
-
- /**
- * Search for a media object.
- */
- private static function mediaQuery() {
- global $WT_TREE;
-
- $iid2 = Filter::get('iid', WT_REGEX_XREF);
-
- $controller = new SimpleController;
- $controller
- ->setPageTitle(I18N::translate('Link to an existing media object'))
- ->pageHeader();
-
- $record = GedcomRecord::getInstance($iid2, $WT_TREE);
- if ($record) {
- $headjs = '';
- if ($record instanceof Family) {
- if ($record->getHusband()) {
- $headjs = $record->getHusband()->getXref();
- } elseif ($record->getWife()) {
- $headjs = $record->getWife()->getXref();
- }
- }
- ?>
- <script>
- function insertId() {
- if (window.opener.document.getElementById('addlinkQueue')) {
- // alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
- window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
- window.close();
- }
- }
- </script>
- <?php
- } else {
- ?>
- <script>
- function insertId() {
- window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
- window.close();
- }
- </script>
- <?php
- }
- ?>
- <script>window.onLoad = insertId();</script>
- <?php
- }
-
- /**
- * Convert custom markup into HTML
- *
- * @param Note $note
- *
- * @return string
- */
- public static function formatCensusNote(Note $note) {
- global $WT_TREE;
-
- if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
- // This looks like a census-assistant shared note
- $title = Filter::escapeHtml($match[1]);
- $preamble = Filter::escapeHtml($match[2]);
- $header = Filter::escapeHtml($match[3]);
- $data = Filter::escapeHtml($match[4]);
- $postamble = Filter::escapeHtml($match[5]);
+ $born = I18N::translate('Birth');
+ echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
+ echo '<hr>';
+ }
+ echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
+ } else {
+ echo '<td class="list_value_wrap">';
+ echo I18N::translate('No results found.');
+ echo '</td></tr>';
+ }
+ echo '</table>';
+ echo '</div>';
+ }
- // Get the column headers for the census to which this note refers
- // requires the fact place & date to match the specific census
- // censusPlace() (Soundex match) and censusDate() functions
- $fmt_headers = [];
- $linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
- $firstRecord = array_shift($linkedRecords);
- if ($firstRecord) {
- $countryCode = '';
- $date = '';
- foreach ($firstRecord->getFacts('CENS') as $fact) {
- if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
- $date = $fact->getAttribute('DATE');
- $place = explode(',', strip_tags($fact->getPlace()->getFullName()));
- $countryCode = Soundex::daitchMokotoff(array_pop($place));
- break;
- }
- }
+ /**
+ * Search for a media object.
+ */
+ private static function mediaQuery() {
+ global $WT_TREE;
- foreach (Census::allCensusPlaces() as $censusPlace) {
- if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
- foreach ($censusPlace->allCensusDates() as $census) {
- if ($census->censusDate() == $date) {
- foreach ($census->columns() as $column) {
- $abbrev = $column->abbreviation();
- if ($abbrev) {
- $description = $column->title() ? $column->title() : I18N::translate('Description unavailable');
- $fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
- }
- }
- break 2;
- }
- }
- }
- }
- }
- // Substitute header labels and format as HTML
- $thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
- $thead = str_replace('.b.', '', $thead);
+ $iid2 = Filter::get('iid', WT_REGEX_XREF);
- // Format data as HTML
- $tbody = '';
- foreach (explode("\n", $data) as $row) {
- $tbody .= '<tr>';
- foreach (explode('|', $row) as $column) {
- $tbody .= '<td>' . $column . '</td>';
- }
- $tbody .= '</tr>';
- }
+ $controller = new SimpleController;
+ $controller
+ ->setPageTitle(I18N::translate('Link to an existing media object'))
+ ->pageHeader();
- return
- $title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
- '<div class="markdown">' .
- '<p>' . $preamble . '</p>' .
- '<table>' .
- '<thead>' . $thead . '</thead>' .
- '<tbody>' . $tbody . '</tbody>' .
- '</table>' .
- '<p>' . $postamble . '</p>' .
- '</div>';
- } else {
- // Not a census-assistant shared note - apply default formatting
- return Filter::formatText($note->getNote(), $WT_TREE);
- }
- }
+ $record = GedcomRecord::getInstance($iid2, $WT_TREE);
+ if ($record) {
+ $headjs = '';
+ if ($record instanceof Family) {
+ if ($record->getHusband()) {
+ $headjs = $record->getHusband()->getXref();
+ } elseif ($record->getWife()) {
+ $headjs = $record->getWife()->getXref();
+ }
+ }
+ ?>
+ <script>
+ function insertId () {
+ if (window.opener.document.getElementById('addlinkQueue')) {
+ // alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
+ window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
+ window.close();
+ }
+ }
+ </script>
+ <?php
+ } else {
+ ?>
+ <script>
+ function insertId () {
+ window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
+ window.close();
+ }
+ </script>
+ <?php
+ }
+ ?>
+ <script>window.onLoad = insertId();</script>
+ <?php
+ }
- /**
- * Generate an HTML row of data for the census header
- *
- * Add prefix cell (store XREF and drag/drop)
- * Add suffix cell (delete button)
- *
- * @param CensusInterface $census
- *
- * @return string
- */
- public static function censusTableHeader(CensusInterface $census) {
- $html = '';
- foreach ($census->columns() as $column) {
- $html .= '<th title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
- }
+ /**
+ * Convert custom markup into HTML
+ *
+ * @param Note $note
+ *
+ * @return string
+ */
+ public static function formatCensusNote(Note $note) {
+ if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
+ // This looks like a census-assistant shared note
+ $title = Filter::escapeHtml($match[1]);
+ $preamble = Filter::escapeHtml($match[2]);
+ $header = Filter::escapeHtml($match[3]);
+ $data = Filter::escapeHtml($match[4]);
+ $postamble = Filter::escapeHtml($match[5]);
- return '<tr><th hidden></th>' . $html . '<th></th></tr>';
- }
+ // Get the column headers for the census to which this note refers
+ // requires the fact place & date to match the specific census
+ // censusPlace() (Soundex match) and censusDate() functions
+ $fmt_headers = [];
+ /** @var GedcomRecord[] $linkedRecords */
+ $linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
+ $firstRecord = array_shift($linkedRecords);
+ if ($firstRecord) {
+ $countryCode = '';
+ $date = '';
+ foreach ($firstRecord->getFacts('CENS') as $fact) {
+ if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
+ $date = $fact->getAttribute('DATE');
+ $place = explode(',', strip_tags($fact->getPlace()->getFullName()));
+ $countryCode = Soundex::daitchMokotoff(array_pop($place));
+ break;
+ }
+ }
- /**
- * Generate an HTML row of data for the census
- *
- * Add prefix cell (store XREF and drag/drop)
- * Add suffix cell (delete button)
- *
- * @param CensusInterface $census
- *
- * @return string
- */
- public static function censusTableEmptyRow(CensusInterface $census) {
- return '<tr><td hidden></td>' . str_repeat('<td><input type="text"></td>', count($census->columns())) . '<td><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
- }
+ foreach (Census::allCensusPlaces() as $censusPlace) {
+ if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
+ foreach ($censusPlace->allCensusDates() as $census) {
+ if ($census->censusDate() == $date) {
+ foreach ($census->columns() as $column) {
+ $abbrev = $column->abbreviation();
+ if ($abbrev) {
+ $description = $column->title() ? $column->title() : I18N::translate('Description unavailable');
+ $fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
+ }
+ }
+ break 2;
+ }
+ }
+ }
+ }
+ }
+ // Substitute header labels and format as HTML
+ $thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
+ $thead = str_replace('.b.', '', $thead);
- /**
- * Generate an HTML row of data for the census
- *
- * Add prefix cell (store XREF and drag/drop)
- * Add suffix cell (delete button)
- *
- * @param CensusInterface $census
- * @param Individual $individual
- * @param Individual|null $head
- *
- * @return string
- */
- public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head = null) {
- $html = '';
- foreach ($census->columns() as $column) {
- $html .= '<td><input type="text" value="' . $column->generate($individual, $head) . '"></td>';
- }
+ // Format data as HTML
+ $tbody = '';
+ foreach (explode("\n", $data) as $row) {
+ $tbody .= '<tr>';
+ foreach (explode('|', $row) as $column) {
+ $tbody .= '<td>' . $column . '</td>';
+ }
+ $tbody .= '</tr>';
+ }
- return '<tr><td hidden>' . $individual->getXref() . '</td>' . $html . '<td><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
- }
+ return
+ $title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
+ '<div class="markdown">' .
+ '<p>' . $preamble . '</p>' .
+ '<table>' .
+ '<thead>' . $thead . '</thead>' .
+ '<tbody>' . $tbody . '</tbody>' .
+ '</table>' .
+ '<p>' . $postamble . '</p>' .
+ '</div>';
+ } else {
+ // Not a census-assistant shared note - apply default formatting
+ return Filter::formatText($note->getNote(), $note->getTree());
+ }
+ }
- /**
- * Create a family on the census navigator.
- *
- * @param CensusInterface $census
- * @param Family $family
- * @param Individual $head
- *
- * @return string
- */
- public static function censusNavigatorFamily(CensusInterface $census, Family $family, Individual $head) {
- $headImg2 = '<i class="icon-button_head" title="' . I18N::translate('Head of household') . '"></i>';
+ /**
+ * Generate an HTML row of data for the census header
+ * Add prefix cell (store XREF and drag/drop)
+ * Add suffix cell (delete button)
+ *
+ * @param CensusInterface $census
+ *
+ * @return string
+ */
+ public static function censusTableHeader(CensusInterface $census) {
+ $html = '';
+ foreach ($census->columns() as $column) {
+ $html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
+ }
- foreach ($family->getSpouses() as $spouse) {
- $menu = new Menu(Functions::getCloseRelationshipName($head, $spouse));
- foreach ($spouse->getChildFamilies() as $grandparents) {
- foreach ($grandparents->getSpouses() as $grandparent) {
- $submenu = new Menu(
- Functions::getCloseRelationshipName($head, $grandparent) . ' - ' . $grandparent->getFullName(),
- '#',
- '',
- ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $grandparent, $head)) . '");']
- );
- $submenu->addClass('submenuitem', '');
- $menu->addSubmenu($submenu);
- $menu->addClass('', 'submenu');
- }
- }
+ return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
+ }
- ?>
- <tr>
- <td class="optionbox">
- <?= $menu->getMenu() ?>
- </td>
- <td class="facts_value nowrap">
- <a href="#" onclick="return appendCensusRow('<?= Filter::escapeJs(self::censusTableRow($census, $spouse, $head)) ?>');">
- <?= $spouse->getFullName() ?>
- </a>
- </td>
- <td class="facts_value">
- <?php if ($head !== $spouse): ?>
- <a href="edit_interface.php?action=addnewnote_assisted&amp;noteid=newnote&amp;xref=<?= $spouse->getXref() ?>&amp;gedcom=<?= $spouse->getTree()->getNameUrl() ?>&amp;census=<?= get_class($census) ?>">
- <?= $headImg2 ?>
- </a>
- <?php endif ?>
- </td>
- </tr>
- <?php
- }
+ /**
+ * Generate an HTML row of data for the census
+ * Add prefix cell (store XREF and drag/drop)
+ * Add suffix cell (delete button)
+ *
+ * @param CensusInterface $census
+ *
+ * @return string
+ */
+ public static function censusTableEmptyRow(CensusInterface $census) {
+ return '<tr class="wt-census-assistant-row"><td hidden></td>' . str_repeat('<td class="wt-census-assistant-field"><input type="text" class="form-control wt-census-assistant-form-control"></td>', count($census->columns())) . '<td><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
+ }
- foreach ($family->getChildren() as $child) {
- $menu = new Menu(Functions::getCloseRelationshipName($head, $child));
- foreach ($child->getSpouseFamilies() as $spouse_family) {
- foreach ($spouse_family->getSpouses() as $spouse_family_spouse) {
- if ($spouse_family_spouse != $child) {
- $submenu = new Menu(
- Functions::getCloseRelationshipName($head, $spouse_family_spouse) . ' - ' . $spouse_family_spouse->getFullName(),
- '#',
- '',
- ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_spouse, $head)) . '");']
- );
- $submenu->addClass('submenuitem', '');
- $menu->addSubmenu($submenu);
- $menu->addClass('', 'submenu');
- }
- }
- foreach ($spouse_family->getChildren() as $spouse_family_child) {
- $submenu = new Menu(
- Functions::getCloseRelationshipName($head, $spouse_family_child) . ' - ' . $spouse_family_child->getFullName(),
- '#',
- '',
- ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_child, $head)) . '");']
- );
- $submenu->addClass('submenuitem', '');
- $menu->addSubmenu($submenu);
- $menu->addClass('', 'submenu');
- }
- }
+ /**
+ * Generate an HTML row of data for the census
+ * Add prefix cell (store XREF and drag/drop)
+ * Add suffix cell (delete button)
+ *
+ * @param CensusInterface $census
+ * @param Individual $individual
+ * @param Individual $head
+ *
+ * @return string
+ */
+ public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
+ $html = '';
+ foreach ($census->columns() as $column) {
+ $html .= '<td class="wt-census-assistant-field"><input class="form-control wt-census-assistant-form-control" type="text" value="' . $column->generate($individual, $head) . '" name="ca_individuals[' . $individual->getXref() . '][]"></td>';
+ }
- ?>
- <tr>
- <td class="optionbox">
- <?= $menu->getMenu() ?>
- </td>
- <td class="facts_value">
- <a href="#" onclick="return appendCensusRow('<?= Filter::escapeJs(self::censusTableRow($census, $child, $head)) ?>');">
- <?= $child->getFullName() ?>
- </a>
- </td>
- <td class="facts_value">
- <?php if ($head !== $child): ?>
- <a href="edit_interface.php?action=addnewnote_assisted&amp;noteid=newnote&amp;xref=<?= $child->getXref() ?>&amp;gedcom=<?= $child->getTree()->getNameUrl() ?>&amp;census=<?= get_class($census) ?>">
- <?= $headImg2 ?>
- </a>
- <?php endif ?>
- </td>
- </tr>
- <?php
- }
- echo '<tr><td><br></td></tr>';
- }
+ return '<tr class="wt-census-assistant-row"><td class="wt-census-assistant-field" hidden>' . $individual->getXref() . '</td>' . $html . '<td class="wt-census-assistant-field"><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
+ }
}
diff --git a/app/Module/ChartsBlockModule.php b/app/Module/ChartsBlockModule.php
index b6c3817505..be95f48989 100644
--- a/app/Module/ChartsBlockModule.php
+++ b/app/Module/ChartsBlockModule.php
@@ -16,8 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\HourglassController;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\I18N;
@@ -54,11 +56,10 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
$PEDIGREE_ROOT_ID = $WT_TREE->getPreference('PEDIGREE_ROOT_ID');
$gedcomid = $WT_TREE->getUserPreference(Auth::user(), 'gedcomid');
- $details = $this->getBlockSetting($block_id, 'details', '0');
$type = $this->getBlockSetting($block_id, 'type', 'pedigree');
$pid = $this->getBlockSetting($block_id, 'pid', Auth::check() ? ($gedcomid ? $gedcomid : $PEDIGREE_ROOT_ID) : $PEDIGREE_ROOT_ID);
- foreach (['details', 'type', 'pid', 'block'] as $name) {
+ foreach (['type', 'pid'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -74,7 +75,7 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype == 'gedcom' && Auth::isManager($WT_TREE) || $ctype == 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -84,12 +85,12 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
switch ($type) {
case 'pedigree':
$title .= I18N::translate('Pedigree of %s', $person->getFullName());
- $chartController = new HourglassController($person->getXref(), $details, false);
+ $chartController = new HourglassController($person->getXref());
$controller->addInlineJavascript($chartController->setupJavascript());
$content .= '<table cellspacing="0" cellpadding="0" border="0"><tr>';
$content .= '<td>';
ob_start();
- FunctionsPrint::printPedigreePerson($person, $details);
+ FunctionsPrint::printPedigreePerson($person);
$content .= ob_get_clean();
$content .= '</td>';
$content .= '<td>';
@@ -101,7 +102,7 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
break;
case 'descendants':
$title .= I18N::translate('Descendants of %s', $person->getFullName());
- $chartController = new HourglassController($person->getXref(), $details, false);
+ $chartController = new HourglassController($person->getXref());
$controller->addInlineJavascript($chartController->setupJavascript());
ob_start();
$chartController->printDescendency($person, 1, false);
@@ -109,7 +110,7 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
break;
case 'hourglass':
$title .= I18N::translate('Hourglass chart of %s', $person->getFullName());
- $chartController = new HourglassController($person->getXref(), $details, false);
+ $chartController = new HourglassController($person->getXref());
$controller->addInlineJavascript($chartController->setupJavascript());
$content .= '<table cellspacing="0" cellpadding="0" border="0"><tr>';
$content .= '<td>';
@@ -172,12 +173,10 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
$gedcomid = $WT_TREE->getUserPreference(Auth::user(), 'gedcomid');
if (Filter::postBool('save') && Filter::checkCsrf()) {
- $this->setBlockSetting($block_id, 'details', Filter::postBool('details'));
$this->setBlockSetting($block_id, 'type', Filter::post('type', 'pedigree|descendants|hourglass|treenav', 'pedigree'));
$this->setBlockSetting($block_id, 'pid', Filter::post('pid', WT_REGEX_XREF));
}
- $details = $this->getBlockSetting($block_id, 'details', '0');
$type = $this->getBlockSetting($block_id, 'type', 'pedigree');
$pid = $this->getBlockSetting($block_id, 'pid', Auth::check() ? ($gedcomid ? $gedcomid : $PEDIGREE_ROOT_ID) : $PEDIGREE_ROOT_ID);
@@ -189,43 +188,25 @@ class ChartsBlockModule extends AbstractModule implements ModuleBlockInterface {
];
uasort($charts, 'Fisharebest\Webtrees\I18N::strcasecmp');
- $controller
- ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
- ->addInlineJavascript('autocomplete();');
- ?>
- <tr>
- <td class="descriptionbox wrap width33">
+ ?>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="type">
<?= I18N::translate('Chart type') ?>
- </td>
- <td class="optionbox">
- <?php echo FunctionsEdit::selectEditControl('type', $charts, null, $type); ?>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap width33">
- <?= I18N::translate('Show details') ?>
- </td>
- <td class="optionbox">
- <?php echo FunctionsEdit::editFieldYesNo('details', $details); ?>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap width33">
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select($charts, $type, ['id' => 'type', 'name' => 'type']) ?>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="pid">
<label for="pid">
<?= I18N::translate('Individual') ?>
</label>
- </td>
- <td class="optionbox">
- <input data-autocomplete-type="INDI" type="text" name="pid" id="pid" value="<?= $pid ?>" size="5">
- <?php
- echo FunctionsPrint::printFindIndividualLink('pid');
- $root = Individual::getInstance($pid, $WT_TREE);
- if ($root) {
- echo ' <span class="list_item">', $root->getFullName(), $root->formatFirstMajorFact(WT_EVENTS_BIRT, 1), '</span>';
- }
- ?>
- </td>
- </tr>
+ </label>
+ <div class="col-sm-9">
+ <?= FunctionsEdit::formControlIndividual(Individual::getInstance($pid, $WT_TREE), ['id' => 'pid', 'name' => 'pid']) ?>
+ </div>
+ </div>
<?php
}
}
diff --git a/app/Module/ClippingsCartModule.php b/app/Module/ClippingsCartModule.php
index c7b1c47b24..2af66fd8b3 100644
--- a/app/Module/ClippingsCartModule.php
+++ b/app/Module/ClippingsCartModule.php
@@ -19,7 +19,6 @@ use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
@@ -78,9 +77,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
$controller = new PageController;
$controller
->setPageTitle($this->getTitle())
- ->pageHeader()
- ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
- ->addInlineJavascript('autocomplete();');
+ ->pageHeader();
echo '<script>';
echo 'function radAncestors(elementid) {var radFamilies=document.getElementById(elementid);radFamilies.checked=true;}';
@@ -93,17 +90,17 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
if ($clip_ctrl->action == 'add') {
$record = GedcomRecord::getInstance($clip_ctrl->id, $WT_TREE);
if ($clip_ctrl->type === 'FAM') { ?>
- <form action="module.php" method="get">
+ <form action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
- <input type="hidden" name="id" value="<?php echo $clip_ctrl->id; ?>">
- <input type="hidden" name="type" value="<?php echo $clip_ctrl->type; ?>">
+ <input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
+ <input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
<input type="hidden" name="action" value="add1">
<table>
<thead>
<tr>
<td class="topbottombar">
- <?php echo I18N::translate('Add to the clippings cart'); ?>
+ <?= I18N::translate('Add to the clippings cart') ?>
</td>
</tr>
</thead>
@@ -111,44 +108,44 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<tr>
<td class="optionbox">
<input type="radio" name="others" value="parents">
- <?php echo $record->getFullName(); ?>
+ <?= $record->getFullName() ?>
</td>
</tr>
<tr>
<td class="optionbox">
<input type="radio" name="others" value="members" checked>
- <?php echo /* I18N: %s is a family (husband + wife) */
- I18N::translate('%s and their children', $record->getFullName()); ?>
+ <?= /* I18N: %s is a family (husband + wife) */
+ I18N::translate('%s and their children', $record->getFullName()) ?>
</td>
</tr>
<tr>
<td class="optionbox">
<input type="radio" name="others" value="descendants">
- <?php echo /* I18N: %s is a family (husband + wife) */
- I18N::translate('%s and their descendants', $record->getFullName()); ?>
+ <?= /* I18N: %s is a family (husband + wife) */
+ I18N::translate('%s and their descendants', $record->getFullName()) ?>
</td>
</tr>
</tbody>
<tfoot>
<tr>
- <td class="topbottombar"><input type="submit" value="<?php echo I18N::translate('continue'); ?>">
+ <td class="topbottombar"><input type="submit" value="<?= I18N::translate('continue') ?>">
</td>
</tr>
</tfoot>
</table>
</form>
<?php } elseif ($clip_ctrl->type === 'INDI') { ?>
- <form action="module.php" method="get">
+ <form action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
- <input type="hidden" name="id" value="<?php echo $clip_ctrl->id; ?>">
- <input type="hidden" name="type" value="<?php echo $clip_ctrl->type; ?>">
+ <input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
+ <input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
<input type="hidden" name="action" value="add1">
<table>
<thead>
<tr>
<td class="topbottombar">
- <?php echo I18N::translate('Add to the clippings cart'); ?>
+ <?= I18N::translate('Add to the clippings cart') ?>
</td>
</tr>
</thead>
@@ -157,7 +154,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<td class="optionbox">
<label>
<input type="radio" name="others" checked value="none">
- <?php echo $record->getFullName(); ?>
+ <?= $record->getFullName() ?>
</label>
</td>
</tr>
@@ -208,8 +205,8 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
?>
</label>
<br>
- <?php echo I18N::translate('Number of generations'); ?>
- <input type="text" size="5" name="level1" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('ancestors');">
+ <?= I18N::translate('Number of generations') ?>
+ <input type="text" size="5" name="level1" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestors');">
</td>
</tr>
<tr>
@@ -227,8 +224,8 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
?>
</label>
<br>
- <?php echo I18N::translate('Number of generations'); ?>
- <input type="text" size="5" name="level2" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('ancestorsfamilies');">
+ <?= I18N::translate('Number of generations') ?>
+ <input type="text" size="5" name="level2" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestorsfamilies');">
</td>
</tr>
<tr>
@@ -246,32 +243,32 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
?>
</label>
<br>
- <?php echo I18N::translate('Number of generations'); ?>
- <input type="text" size="5" name="level3" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('descendants');">
+ <?= I18N::translate('Number of generations') ?>
+ <input type="text" size="5" name="level3" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('descendants');">
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="topbottombar">
- <input type="submit" value="<?php echo I18N::translate('continue'); ?>">
+ <input type="submit" value="<?= I18N::translate('continue') ?>">
</td>
</tr>
</tfoot>
</table>
</form>
<?php } elseif ($clip_ctrl->type === 'SOUR') { ?>
- <form action="module.php" method="get">
+ <form action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
- <input type="hidden" name="id" value="<?php echo $clip_ctrl->id; ?>">
- <input type="hidden" name="type" value="<?php echo $clip_ctrl->type; ?>">
+ <input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
+ <input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
<input type="hidden" name="action" value="add1">
<table>
<thead>
<tr>
<td class="topbottombar">
- <?php echo I18N::translate('Add to the clippings cart'); ?>
+ <?= I18N::translate('Add to the clippings cart') ?>
</td>
</tr>
</thead>
@@ -280,7 +277,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<td class="optionbox">
<label>
<input type="radio" name="others" checked value="none">
- <?php echo $record->getFullName(); ?>
+ <?= $record->getFullName() ?>
</label>
</td>
</tr>
@@ -288,8 +285,8 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<td class="optionbox">
<label>
<input type="radio" name="others" value="linked">
- <?php echo /* I18N: %s is the name of a source */
- I18N::translate('%s and the individuals that reference it.', $record->getFullName()); ?>
+ <?= /* I18N: %s is the name of a source */
+ I18N::translate('%s and the individuals that reference it.', $record->getFullName()) ?>
</label>
</td>
</tr>
@@ -297,7 +294,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<tfoot>
<tr>
<td class="topbottombar">
- <input type="submit" value="<?php echo I18N::translate('continue'); ?>">
+ <input type="submit" value="<?= I18N::translate('continue') ?>">
</td>
</tr>
</tfoot>
@@ -310,14 +307,14 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
if ($clip_ctrl->action != 'add') {
echo I18N::translate('The clippings cart allows you to take extracts from this family tree and download them as a GEDCOM file.');
?>
- <form method="get" name="addin" action="module.php">
+ <form name="addin" action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
<table>
<thead>
<tr>
<td colspan="2" class="topbottombar">
- <?php echo I18N::translate('Add to the clippings cart'); ?>
+ <?= I18N::translate('Add to the clippings cart') ?>
</td>
</tr>
</thead>
@@ -328,10 +325,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="5">
</td>
<td class="optionbox">
- <?php echo FunctionsPrint::printFindIndividualLink('cart_item_id'); ?>
- <?php echo FunctionsPrint::printFindFamilyLink('cart_item_id'); ?>
- <?php echo FunctionsPrint::printFindSourceLink('cart_item_id', ''); ?>
- <input type="submit" value="<?php echo /* I18N: A button label. */ I18N::translate('add'); ?>">
+ <input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
</td>
</tr>
</tbody>
@@ -348,29 +342,29 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
$pid = Filter::get('pid', WT_REGEX_XREF);
if ($clip_ctrl->action !== 'download' && $clip_ctrl->action !== 'add') { ?>
- <form method="get" action="module.php">
+ <form action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
<input type="hidden" name="action" value="download">
- <input type="hidden" name="pid" value="<?php echo $pid; ?>">
+ <input type="hidden" name="pid" value="<?= $pid ?>">
<table>
<tr>
<td colspan="2" class="topbottombar">
- <h2><?php echo I18N::translate('Download'); ?></h2>
+ <h2><?= I18N::translate('Download') ?></h2>
</td>
</tr>
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('To reduce the size of the download, you can compress the data into a .ZIP file. You will need to uncompress the .ZIP file before you can use it.'); ?>
+ <?= I18N::translate('To reduce the size of the download, you can compress the data into a .ZIP file. You will need to uncompress the .ZIP file before you can use it.') ?>
</td>
<td class="optionbox wrap">
<input type="checkbox" name="Zip" value="yes">
- <?php echo I18N::translate('Zip file(s)'); ?>
+ <?= I18N::translate('Zip file(s)') ?>
</td>
</tr>
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('Include media (automatically zips files)'); ?>
+ <?= I18N::translate('Include media (automatically zips files)') ?>
</td>
<td class="optionbox">
<input type="checkbox" name="IncludeMedia" value="yes">
@@ -380,37 +374,37 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<?php if (Auth::isManager($WT_TREE)) { ?>
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('Apply privacy settings'); ?>
+ <?= I18N::translate('Apply privacy settings') ?>
</td>
<td class="optionbox">
<input type="radio" name="privatize_export" value="none" checked>
- <?php echo I18N::translate('None'); ?>
+ <?= I18N::translate('None') ?>
<br>
<input type="radio" name="privatize_export" value="gedadmin">
- <?php echo I18N::translate('Manager'); ?>
+ <?= I18N::translate('Manager') ?>
<br>
<input type="radio" name="privatize_export" value="user">
- <?php echo I18N::translate('Member'); ?>
+ <?= I18N::translate('Member') ?>
<br>
<input type="radio" name="privatize_export" value="visitor">
- <?php echo I18N::translate('Visitor'); ?>
+ <?= I18N::translate('Visitor') ?>
</td>
</tr>
<?php } elseif (Auth::isMember($WT_TREE)) { ?>
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('Apply privacy settings'); ?>
+ <?= I18N::translate('Apply privacy settings') ?>
</td>
<td class="optionbox">
- <input type="radio" name="privatize_export" value="user" checked> <?php echo I18N::translate('Member'); ?><br>
- <input type="radio" name="privatize_export" value="visitor"> <?php echo I18N::translate('Visitor'); ?>
+ <input type="radio" name="privatize_export" value="user" checked> <?= I18N::translate('Member') ?><br>
+ <input type="radio" name="privatize_export" value="visitor"> <?= I18N::translate('Visitor') ?>
</td>
</tr>
<?php } ?>
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('Convert from UTF-8 to ISO-8859-1'); ?>
+ <?= I18N::translate('Convert from UTF-8 to ISO-8859-1') ?>
</td>
<td class="optionbox">
<input type="checkbox" name="convert" value="yes">
@@ -419,31 +413,31 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<tr>
<td class="descriptionbox width50 wrap">
- <?php echo I18N::translate('Add the GEDCOM media path to filenames'); ?>
+ <?= I18N::translate('Add the GEDCOM media path to filenames') ?>
</td>
<td class="optionbox">
- <input type="checkbox" name="conv_path" value="<?php echo Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')); ?>">
- <span dir="auto"><?php echo Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')); ?></span>
+ <input type="checkbox" name="conv_path" value="<?= Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) ?>">
+ <span dir="auto"><?= Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) ?></span>
</td>
</tr>
<tr>
<td class="topbottombar" colspan="2">
- <input type="submit" value="<?php echo /* I18N: A button label. */ I18N::translate('download'); ?>">
+ <input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('download') ?>">
</td>
</tr>
</table>
</form>
<br>
- <form method="get" name="addin" action="module.php">
+ <form name="addin" action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
<table>
<thead>
<tr>
<td colspan="2" class="topbottombar" style="text-align:center; ">
- <?php echo I18N::translate('Add to the clippings cart'); ?>
+ <?= I18N::translate('Add to the clippings cart') ?>
</td>
</tr>
</thead>
@@ -454,10 +448,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="8">
</td>
<td class="optionbox">
- <?php echo FunctionsPrint::printFindIndividualLink('cart_item_id'); ?>
- <?php echo FunctionsPrint::printFindFamilyLink('cart_item_id'); ?>
- <?php echo FunctionsPrint::printFindSourceLink('cart_item_id'); ?>
- <input type="submit" value="<?php echo /* I18N: A button label. */ I18N::translate('add'); ?>">
+ <input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
</td>
</tr>
</tbody>
@@ -465,7 +456,7 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<tr>
<th colspan="2">
<a href="module.php?mod=clippings&amp;mod_action=index&amp;action=empty">
- <?php echo I18N::translate('Empty the clippings cart'); ?>
+ <?= I18N::translate('Empty the clippings cart') ?>
</a>
</th>
</tr>
@@ -476,13 +467,13 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
<?php } ?>
<h2>
- <?php echo I18N::translate('Family tree clippings cart'); ?>
+ <?= I18N::translate('Family tree clippings cart') ?>
</h2>
<table id="mycart" class="sortable list_table width100">
<thead>
<tr>
- <th class="list_label"><?php echo I18N::translate('Record'); ?></th>
- <th class="list_label"><?php echo I18N::translate('Remove'); ?></th>
+ <th class="list_label"><?= I18N::translate('Record') ?></th>
+ <th class="list_label"><?= I18N::translate('Remove') ?></th>
</tr>
</thead>
<tbody>
@@ -516,12 +507,12 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
?>
<tr>
<td class="list_value">
- <i class="<?php echo $icon; ?>"></i>
+ <i class="<?= $icon ?>"></i>
<?php
echo '<a href="', $record->getHtmlUrl(), '">', $record->getFullName(), '</a>';
?>
</td>
- <td class="list_value center vmiddle"><a href="module.php?mod=clippings&amp;mod_action=index&amp;action=remove&amp;id=<?php echo $xref; ?>" class="icon-remove" title="<?php echo I18N::translate('Remove'); ?>"></a></td>
+ <td class="list_value center vmiddle"><a href="module.php?mod=clippings&amp;mod_action=index&amp;action=remove&amp;id=<?= $xref ?>" class="icon-remove" title="<?= I18N::translate('Remove') ?>"></a></td>
</tr>
<?php
}
@@ -556,10 +547,10 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
$submenus = [];
if (isset($controller->record)) {
- $submenus[] = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippingscart', ['rel' => 'nofollow']);
+ $submenus[] = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippings-cart', ['rel' => 'nofollow']);
}
if (!empty($controller->record) && $controller->record->canShow()) {
- $submenus[] = new Menu(I18N::translate('Add to the clippings cart'), 'module.php?mod=clippings&amp;mod_action=index&amp;action=add&amp;id=' . $controller->record->getXref(), 'menu-clippingsadd', ['rel' => 'nofollow']);
+ $submenus[] = new Menu(I18N::translate('Add to the clippings cart'), 'module.php?mod=clippings&amp;mod_action=index&amp;action=add&amp;id=' . $controller->record->getXref(), 'menu-clippings-add', ['rel' => 'nofollow']);
}
if ($submenus) {
@@ -591,8 +582,8 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
global $controller;
$controller->addInlineJavascript('
- jQuery("#sb_clippings_content").on("click", ".add_cart, .remove_cart", function() {
- jQuery("#sb_clippings_content").load(this.href);
+ $("#sb_clippings_content").on("click", ".add_cart, .remove_cart", function() {
+ $("#sb_clippings_content").load(this.href);
return false;
});
');
@@ -742,10 +733,10 @@ class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface,
$out = '<script>';
$out .= 'function cancelDownload() {
var link = "module.php?mod=' . $this->getName() . '&mod_action=ajax&pid=' . $pid . '";
- jQuery("#sb_clippings_content").load(link);
+ $("#sb_clippings_content").load(link);
}';
$out .= '</script>';
- $out .= '<form method="get" action="module.php">
+ $out .= '<form action="module.php">
<input type="hidden" name="mod" value="clippings">
<input type="hidden" name="mod_action" value="index">
<input type="hidden" name="pid" value="' . $pid . '">
diff --git a/app/Module/FamilyNavigatorModule.php b/app/Module/FamilyNavigatorModule.php
index 958493d6b9..d830ebf284 100644
--- a/app/Module/FamilyNavigatorModule.php
+++ b/app/Module/FamilyNavigatorModule.php
@@ -124,12 +124,13 @@ class FamilyNavigatorModule extends AbstractModule implements ModuleSidebarInter
<?php
foreach ($family->getSpouses() as $spouse) {
$menu = new Menu(Functions::getCloseRelationshipName($controller->record, $spouse));
- $menu->addClass('', 'submenu flyout');
$menu->addSubmenu(new Menu($this->getParents($spouse)));
?>
<tr>
<td class="facts_label">
- <?= $menu->getMenu() ?>
+ <ul class="nav">
+ <?= $menu->bootstrap4() ?>
+ </ul>
</td>
<td class="center <?= $controller->getPersonStyle($spouse) ?> nam">
<?php if ($spouse->canShow()): ?>
@@ -149,12 +150,13 @@ class FamilyNavigatorModule extends AbstractModule implements ModuleSidebarInter
foreach ($family->getChildren() as $child) {
$menu = new Menu(Functions::getCloseRelationshipName($controller->record, $child));
- $menu->addClass('', 'submenu flyout');
$menu->addSubmenu(new Menu($this->getFamily($child)));
?>
<tr>
<td class="facts_label">
- <?= $menu->getMenu() ?>
+ <ul class="nav">
+ <?= $menu->bootstrap4() ?>
+ </ul>
</td>
<td class="center <?= $controller->getPersonStyle($child) ?> nam">
<?php if ($child->canShow()): ?>
diff --git a/app/Module/FamilyTreeFavoritesModule.php b/app/Module/FamilyTreeFavoritesModule.php
index 4cbf00e667..3ddb032e0c 100644
--- a/app/Module/FamilyTreeFavoritesModule.php
+++ b/app/Module/FamilyTreeFavoritesModule.php
@@ -18,8 +18,6 @@ namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
-use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
@@ -124,14 +122,6 @@ class FamilyTreeFavoritesModule extends AbstractModule implements ModuleBlockInt
break;
}
- $block = $this->getBlockSetting($block_id, 'block', '0');
-
- foreach (['block'] as $name) {
- if (array_key_exists($name, $cfg)) {
- $$name = $cfg[$name];
- }
- }
-
$userfavs = $this->getFavorites($ctype === 'user' ? Auth::id() : $WT_TREE->getTreeId());
if (!is_array($userfavs)) {
$userfavs = [];
@@ -141,12 +131,6 @@ class FamilyTreeFavoritesModule extends AbstractModule implements ModuleBlockInt
$class = $this->getName() . '_block';
$title = $this->getTitle();
- if (Auth::check()) {
- $controller
- ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
- ->addInlineJavascript('autocomplete();');
- }
-
$content = '';
if ($userfavs) {
foreach ($userfavs as $key => $favorite) {
@@ -211,12 +195,6 @@ class FamilyTreeFavoritesModule extends AbstractModule implements ModuleBlockInt
$content .= '<input type="radio" name="fav_category" value="record" checked onclick="$(\'#gid' . $uniqueID . '\').removeAttr(\'disabled\'); $(\'#url, #favtitle\').attr(\'disabled\',\'disabled\').val(\'\');">';
$content .= '<label for="gid' . $uniqueID . '">' . I18N::translate('Enter an individual, family, or source ID') . '</label>';
$content .= '<input class="pedigree_form" data-autocomplete-type="IFSRO" type="text" name="gid" id="gid' . $uniqueID . '" size="5" value="">';
- $content .= ' ' . FunctionsPrint::printFindIndividualLink('gid' . $uniqueID);
- $content .= ' ' . FunctionsPrint::printFindFamilyLink('gid' . $uniqueID);
- $content .= ' ' . FunctionsPrint::printFindSourceLink('gid' . $uniqueID);
- $content .= ' ' . FunctionsPrint::printFindRepositoryLink('gid' . $uniqueID);
- $content .= ' ' . FunctionsPrint::printFindNoteLink('gid' . $uniqueID);
- $content .= ' ' . FunctionsPrint::printFindMediaLink('gid' . $uniqueID);
$content .= '</div>';
$content .= '<div class="add_fav_url">';
$content .= '<input type="radio" name="fav_category" value="url" onclick="$(\'#url, #favtitle\').removeAttr(\'disabled\'); $(\'#gid' . $uniqueID . '\').attr(\'disabled\',\'disabled\').val(\'\');">';
@@ -230,10 +208,6 @@ class FamilyTreeFavoritesModule extends AbstractModule implements ModuleBlockInt
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -275,19 +249,7 @@ class FamilyTreeFavoritesModule extends AbstractModule implements ModuleBlockInt
*
* @param int $block_id
*/
- public function configureBlock($block_id) {
- if (Filter::postBool('save') && Filter::checkCsrf()) {
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
- }
-
- $block = $this->getBlockSetting($block_id, 'block', '0');
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
- }
+ public function configureBlock($block_id) {}
/**
* Delete a favorite from the database
diff --git a/app/Module/FamilyTreeNewsModule.php b/app/Module/FamilyTreeNewsModule.php
index 2067fece55..a26b6b88c7 100644
--- a/app/Module/FamilyTreeNewsModule.php
+++ b/app/Module/FamilyTreeNewsModule.php
@@ -40,7 +40,6 @@ class FamilyTreeNewsModule extends AbstractModule implements ModuleBlockInterfac
parent::__construct($directory);
// Create/update the database tables.
- // NOTE: if we want to set any module-settings, we'll need to move this.
Database::updateSchema(self::SCHEMA_MIGRATION_PREFIX, self::SCHEMA_SETTING_NAME, self::SCHEMA_TARGET_VERSION);
}
@@ -74,15 +73,6 @@ class FamilyTreeNewsModule extends AbstractModule implements ModuleBlockInterfac
public function getBlock($block_id, $template = true, $cfg = []) {
global $ctype, $WT_TREE;
- switch (Filter::get('action')) {
- case 'deletenews':
- $news_id = Filter::get('news_id');
- if ($news_id) {
- Database::prepare("DELETE FROM `##news` WHERE news_id = ?")->execute([$news_id]);
- }
- break;
- }
-
$more_news = Filter::getInteger('more_news');
$limit = 5 * (1 + $more_news);
@@ -119,15 +109,15 @@ class FamilyTreeNewsModule extends AbstractModule implements ModuleBlockInterfac
$content .= $article->body;
if (Auth::isManager($WT_TREE)) {
$content .= '<hr>';
- $content .= '<a href="#" onclick="window.open(\'editnews.php?news_id=\'+' . $article->news_id . ', \'_blank\', news_window_specs); return false;">' . I18N::translate('Edit') . '</a>';
+ $content .= '<a href="editnews.php?news_id=' . $article->news_id . '&amp;ctype=gedcom&amp;ged=' . $WT_TREE->getNameHtml() . '">' . I18N::translate('Edit') . '</a>';
$content .= ' | ';
- $content .= '<a href="index.php?action=deletenews&amp;news_id=' . $article->news_id . '&amp;ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
+ $content .= '<a href="editnews.php?action=delete&amp;news_id=' . $article->news_id . '&amp;ctype=gedcom&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
}
$content .= '</div>';
}
if (Auth::isManager($WT_TREE)) {
- $content .= '<a href="#" onclick="window.open(\'editnews.php?gedcom_id=' . $WT_TREE->getTreeId() . '\', \'_blank\', news_window_specs); return false;">' . I18N::translate('Add a news article') . '</a>';
+ $content .= '<p><a href="editnews.php?ctype=gedcom&amp;ged=' . $WT_TREE->getNameUrl() . '">' . I18N::translate('Add a news article') . '</a></p>';
}
if ($count > $limit) {
diff --git a/app/Module/FamilyTreeStatisticsModule.php b/app/Module/FamilyTreeStatisticsModule.php
index d8bf5fd050..a8ea0d2671 100644
--- a/app/Module/FamilyTreeStatisticsModule.php
+++ b/app/Module/FamilyTreeStatisticsModule.php
@@ -16,7 +16,9 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsDb;
use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
use Fisharebest\Webtrees\I18N;
@@ -74,10 +76,7 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn
$stat_most_chil = $this->getBlockSetting($block_id, 'stat_most_chil', '1');
$stat_avg_chil = $this->getBlockSetting($block_id, 'stat_avg_chil', '1');
- // This can be overriden when embedding in an HTML block
- $block = '0';
-
- foreach (['show_common_surnames', 'number_common_surnames', 'stat_indi', 'stat_fam', 'stat_sour', 'stat_media', 'stat_surname', 'stat_events', 'stat_users', 'stat_first_birth', 'stat_last_birth', 'stat_first_death', 'stat_last_death', 'stat_long_life', 'stat_avg_life', 'stat_most_chil', 'stat_avg_chil', 'block'] as $name) {
+ foreach (['show_common_surnames', 'number_common_surnames', 'stat_indi', 'stat_fam', 'stat_sour', 'stat_media', 'stat_surname', 'stat_events', 'stat_users', 'stat_first_birth', 'stat_last_birth', 'stat_first_death', 'stat_last_death', 'stat_long_life', 'stat_avg_life', 'stat_most_chil', 'stat_avg_chil'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -86,7 +85,7 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -135,65 +134,47 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn
}
$content .= '</div></div>';
}
- if (!$block) {
- $content .= '</div><div class="facts_table stat-table2">';
- }
+ $content .= '</div><div class="facts_table stat-table2">';
if ($stat_first_birth) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstBirthYear() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->firstBirth() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->firstBirth() . '</div>';
$content .= '</div>';
}
if ($stat_last_birth) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastBirthYear() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->lastBirth() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->lastBirth() . '</div>';
$content .= '</div>';
}
if ($stat_first_death) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstDeathYear() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->firstDeath() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->firstDeath() . '</div>';
$content .= '</div>';
}
if ($stat_last_death) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastDeathYear() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->lastDeath() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->lastDeath() . '</div>';
$content .= '</div>';
}
if ($stat_long_life) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Individual who lived the longest') . '</div><div class="facts_value stats_value stat-cell">' . $stats->longestLifeAge() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->longestLife() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->longestLife() . '</div>';
$content .= '</div>';
}
if ($stat_avg_life) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average age at death') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageLifespan() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . I18N::translate('Males') . ':&nbsp;' . $stats->averageLifespanMale();
- $content .= '&nbsp;&nbsp;&nbsp;' . I18N::translate('Females') . ':&nbsp;' . $stats->averageLifespanFemale() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . I18N::translate('Males') . ':&nbsp;' . $stats->averageLifespanMale();
+ $content .= '&nbsp;&nbsp;&nbsp;' . I18N::translate('Females') . ':&nbsp;' . $stats->averageLifespanFemale() . '</div>';
$content .= '</div>';
}
- if ($stat_most_chil && !$block) {
+ if ($stat_most_chil) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Family with the most children') . '</div><div class="facts_value stats_value stat-cell">' . $stats->largestFamilySize() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left">' . $stats->largestFamily() . '</div>';
- }
+ $content .= '<div class="facts_value stat-cell left">' . $stats->largestFamily() . '</div>';
$content .= '</div>';
}
if ($stat_avg_chil) {
$content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average number of children per family') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageChildren() . '</div>';
- if (!$block) {
- $content .= '<div class="facts_value stat-cell left"></div>';
- }
+ $content .= '<div class="facts_value stat-cell left"></div>';
$content .= '</div>';
}
$content .= '</div>';
@@ -290,167 +271,68 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn
$stat_avg_chil = $this->getBlockSetting($block_id, 'stat_avg_chil', '1');
?>
- <tr>
- <td class="descriptionbox wrap width33">
- <label for="show-last-update">
- <?= /* I18N: label for yes/no option */ I18N::translate('Show date of last update') ?>
- </label>
- </td>
- <td class="optionbox">
- <input type="checkbox" value="yes" id="show-last-update" name="show_last_update" <?= $show_last_update ? 'checked' : '' ?>>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap width33">
- <?= I18N::translate('Statistics') ?>
- </td>
- <td class="optionbox">
- <table>
- <tbody>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_indi" <?= $stat_indi ? 'checked' : '' ?>>
- <?= I18N::translate('Individuals') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_first_birth" <?= $stat_first_birth ? 'checked' : '' ?>>
- <?= I18N::translate('Earliest birth year') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_surname" <?= $stat_surname ? 'checked' : '' ?>>
- <?= I18N::translate('Total surnames') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_last_birth" <?= $stat_last_birth ? 'checked' : '' ?>>
- <?= I18N::translate('Latest birth year') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_fam" <?= $stat_fam ? 'checked' : '' ?>>
- <?= I18N::translate('Families') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_first_death" <?= $stat_first_death ? 'checked' : '' ?>>
- <?= I18N::translate('Earliest death year') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_sour" <?= $stat_sour ? 'checked' : '' ?>>
- <?= I18N::translate('Sources') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_last_death" <?= $stat_last_death ? 'checked' : '' ?>>
- <?= I18N::translate('Latest death year') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_media" <?= $stat_media ? 'checked' : '' ?>>
- <?= I18N::translate('Media objects') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_long_life" <?= $stat_long_life ? 'checked' : '' ?>>
- <?= I18N::translate('Individual who lived the longest') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_repo" <?= $stat_repo ? 'checked' : '' ?>>
- <?= I18N::translate('Repositories') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_avg_life" <?= $stat_avg_life ? 'checked' : '' ?>>
- <?= I18N::translate('Average age at death') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_events" <?= $stat_events ? 'checked' : '' ?>>
- <?= I18N::translate('Total events') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_most_chil" <?= $stat_most_chil ? 'checked' : '' ?>>
- <?= I18N::translate('Family with the most children') ?>
- </label>
- </td>
- </tr>
- <tr>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_users" <?= $stat_users ? 'checked' : '' ?>>
- <?= I18N::translate('Total users') ?>
- </label>
- </td>
- <td>
- <label>
- <input type="checkbox" value="yes" name="stat_avg_chil" <?= $stat_avg_chil ? 'checked' : '' ?>>
- <?= I18N::translate('Average number of children per family') ?>
- </label>
- </td>
- </tr>
- </tbody>
- </table>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap width33">
- <label for="show-common-surnames">
- <?= I18N::translate('Most common surnames') ?>
- </label>
- </td>
- <td class="optionbox">
- <input type="checkbox" value="yes" id="show-common-surnames" name="show_common_surnames" <?= $show_common_surnames ? 'checked' : '' ?>>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap width33">
- <label for="number-of-surnames">
- <?= /* I18N: ... to show in a list */ I18N::translate('Number of surnames') ?>
- </label>
- </td>
- <td class="optionbox">
- <input
- id="number-of-surnames"
- maxlength="5"
- name="number_of_surnames"
- pattern="[1-9][0-9]*"
- required
- type="text"
- value="<?= Filter::escapeHtml($number_of_surnames) ?>"
- >
- </td>
- </tr>
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= I18N::translate('Last change') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::checkbox(/* I18N: label for yes/no option */ I18N::translate('Show date of last update'), false, ['name' => 'show_last_update', 'checked' => (bool) $show_last_update]) ?>
+ </div>
+ </div>
+ </fieldset>
+
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= I18N::translate('Statistics') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::checkbox(I18N::translate('Individuals'), false, ['name' => 'stat_indi', 'checked' => (bool) $stat_indi]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Total surnames'), false, ['name' => 'stat_surname', 'checked' => (bool) $stat_surname]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Families'), false, ['name' => 'stat_fam', 'checked' => (bool) $stat_fam]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Sources'), false, ['name' => 'stat_sour', 'checked' => (bool) $stat_sour]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Media objects'), false, ['name' => 'stat_media', 'checked' => (bool) $stat_media]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Repositories'), false, ['name' => 'stat_repo', 'checked' => (bool) $stat_repo]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Total events'), false, ['name' => 'stat_events', 'checked' => (bool) $stat_events]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Total users'), false, ['name' => 'stat_users', 'checked' => (bool) $stat_users]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Earliest birth year'), false, ['name' => 'stat_first_birth', 'checked' => (bool) $stat_first_birth]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Latest birth year'), false, ['name' => 'stat_last_birth', 'checked' => (bool) $stat_last_birth]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Earliest death year'), false, ['name' => 'stat_first_death', 'checked' => (bool) $stat_first_death]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Latest death year'), false, ['name' => 'stat_last_death', 'checked' => (bool) $stat_last_death]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Individual who lived the longest'), false, ['name' => 'stat_long_life', 'checked' => (bool) $stat_long_life]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Average age at death'), false, ['name' => 'stat_avg_life', 'checked' => (bool) $stat_avg_life]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Family with the most children'), false, ['name' => 'stat_most_chil', 'checked' => (bool) $stat_most_chil]) ?>
+ <?= Bootstrap4::checkbox(I18N::translate('Average number of children per family'), false, ['name' => 'stat_avg_chil', 'checked' => (bool) $stat_avg_chil]) ?>
+ </div>
+ </div>
+ </fieldset>
+
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <label for="show_common_surnames">
+ <?= I18N::translate('Surnames') ?>
+ </label>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::checkbox(I18N::translate('Most common surnames'), false, ['name' => 'show_common_surnames', 'checked' => (bool) $show_common_surnames]) ?>
+ <label for="number_of_surnames">
+ <?= /* I18N: ... to show in a list */ I18N::translate('Number of surnames') ?>
+ <input
+ class="form-control"
+ id="number_of_surnames"
+ maxlength="5"
+ name="number_of_surnames"
+ pattern="[1-9][0-9]*"
+ required
+ type="text"
+ value="<?= Filter::escapeHtml($number_of_surnames) ?>"
+ >
+ </label>
+ </div>
+ </div>
+ </fieldset>
<?php
}
}
diff --git a/app/Module/FrequentlyAskedQuestionsModule.php b/app/Module/FrequentlyAskedQuestionsModule.php
index 8e57a42bfd..2b75941b9a 100644
--- a/app/Module/FrequentlyAskedQuestionsModule.php
+++ b/app/Module/FrequentlyAskedQuestionsModule.php
@@ -16,6 +16,7 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
@@ -156,22 +157,21 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
CkeditorModule::enableEditor($controller);
}
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ 'module.php?mod=' . $this->getName() . '&mod_action=admin_config' => $this->getTitle(),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li><a href="module.php?mod=<?php echo $this->getName(); ?>&mod_action=admin_config"><?php echo I18N::translate('Frequently asked questions'); ?></a>
- </li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h1><?php echo $controller->getPageTitle(); ?></h1>
- <form name="faq" class="form-horizontal" method="post" action="module.php?mod=<?php echo $this->getName(); ?>&amp;mod_action=admin_edit_save">
- <?php echo Filter::getCsrf(); ?>
- <input type="hidden" name="block_id" value="<?php echo $block_id; ?>">
+ <h1><?= $controller->getPageTitle() ?></h1>
- <div class="form-group">
- <label for="header" class="col-sm-3 control-label">
+ <form name="faq" class="form-horizontal" method="post" action="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit_save">
+ <?= Filter::getCsrf() ?>
+ <input type="hidden" name="block_id" value="<?= $block_id ?>">
+
+ <div class="row form-group">
+ <label for="header" class="col-sm-3 col-form-label">
<?= I18N::translate('Question') ?>
</label>
@@ -181,8 +181,8 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
</div>
</div>
- <div class="form-group">
- <label for="faqbody" class="col-sm-3 control-label">
+ <div class="row form-group">
+ <label for="faqbody" class="col-sm-3 col-form-label">
<?= I18N::translate('Answer') ?>
</label>
@@ -191,8 +191,8 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
</div>
</div>
- <div class="form-group">
- <label for="xref" class="col-sm-3 control-label">
+ <div class="row form-group">
+ <label for="xref" class="col-sm-3 col-form-label">
<?= /* I18N: Label for a configuration option */ I18N::translate('Show this block for which languages') ?>
</label>
@@ -201,8 +201,8 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
</div>
</div>
- <div class="form-group">
- <label for="block_order" class="col-sm-3 control-label">
+ <div class="row form-group">
+ <label for="block_order" class="col-sm-3 col-form-label">
<?= I18N::translate('Sort order') ?>
</label>
@@ -211,21 +211,21 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
</div>
</div>
- <div class="form-group">
- <label for="gedcom_id" class="col-sm-3 control-label">
+ <div class="row form-group">
+ <label for="gedcom_id" class="col-sm-3 col-form-label">
<?= I18N::translate('Family tree') ?>
</label>
<div class="col-sm-9">
- <?php echo FunctionsEdit::selectEditControl('gedcom_id', Tree::getIdList(), I18N::translate('All'), $gedcom_id, 'class="form-control"'); ?>
+ <?= Bootstrap4::select(['' => I18N::translate('All')] + Tree::getIdList(), $gedcom_id, ['id' => 'gedcom_id', 'name' => 'gedcom_id']) ?>
<p class="small text-muted">
<?= /* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('An FAQ can be displayed on just one of the family trees, or on all the family trees.') ?>
</p>
</div>
</div>
- <div class="form-group">
- <div class="col-sm-offset-3 col-sm-9">
+ <div class="row form-group">
+ <div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-primary">
<i class="fa fa-check"></i>
<?= I18N::translate('save') ?>
@@ -359,7 +359,7 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
'tree_id_2' => $WT_TREE->getTreeId(),
])->fetchAll();
- echo '<h2 class="center">', I18N::translate('Frequently asked questions');
+ echo '<h2 class="wt-page-title">', I18N::translate('Frequently asked questions');
if (Auth::isManager($WT_TREE)) {
echo ' — <a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_config">', I18N::translate('edit'), '</a>';
}
@@ -432,13 +432,13 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
'tree_id' => $WT_TREE->getTreeId(),
])->fetchOne();
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h2><?php echo $controller->getPageTitle(); ?></h2>
+
+ <h1><?= $controller->getPageTitle() ?></h1>
<p>
<?= /* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('FAQs are lists of questions and answers, which allow you to explain the site’s rules, policies, and procedures to your visitors. Questions are typically concerned with privacy, copyright, user-accounts, unsuitable content, requirement for source-citations, etc.') ?>
<?= I18N::translate('You may use HTML to format the answer and to add links to other websites.') ?>
@@ -451,7 +451,7 @@ class FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMen
</label>
<input type="hidden" name="mod" value="<?= $this->getName() ?>">
<input type="hidden" name="mod_action" value="admin_config">
- <?php echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), null, $WT_TREE->getName(), 'class="form-control"'); ?>
+ <?= Bootstrap4::select(Tree::getNameList(), $WT_TREE->getName(), ['id' => 'ged', 'name' => 'ged']) ?>
<input type="submit" class="btn btn-primary" value="<?= I18N::translate('show') ?>">
</form>
</p>
diff --git a/app/Module/GoogleMapsModule.php b/app/Module/GoogleMapsModule.php
index 359aa8e395..9396be4021 100644
--- a/app/Module/GoogleMapsModule.php
+++ b/app/Module/GoogleMapsModule.php
@@ -16,27 +16,28 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\ChartController;
use Fisharebest\Webtrees\Controller\PageController;
-use Fisharebest\Webtrees\Controller\SimpleController;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\FlashMessages;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\Functions;
use Fisharebest\Webtrees\Functions\FunctionsCharts;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
-use Fisharebest\Webtrees\Functions\FunctionsPrint;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Log;
use Fisharebest\Webtrees\Menu;
use Fisharebest\Webtrees\Module;
+use Fisharebest\Webtrees\Session;
use Fisharebest\Webtrees\Stats;
use Fisharebest\Webtrees\Tree;
use PDO;
+use stdClass;
/**
* Class GoogleMapsModule
@@ -94,24 +95,43 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
public function modAction($mod_action) {
Database::updateSchema(self::SCHEMA_MIGRATION_PREFIX, self::SCHEMA_SETTING_NAME, self::SCHEMA_TARGET_VERSION);
+ // Some actions ard admin-only.
+ if (strpos($mod_action, 'admin') === 0 && !Auth::isAdmin()) {
+ header('Location: ' . WT_BASE_URL);
+
+ return;
+ }
+
switch ($mod_action) {
case 'admin_config':
$this->config();
break;
- case 'flags':
- $this->flags();
- break;
case 'pedigree_map':
$this->pedigreeMap();
break;
- case 'admin_placecheck':
- $this->adminPlaceCheck();
- break;
case 'admin_places':
$this->adminPlaces();
break;
- case 'places_edit':
- $this->placesEdit();
+ case 'admin_place_edit':
+ $this->adminPlaceEdit();
+ break;
+ case 'admin_place_save':
+ $this->adminPlaceSave();
+ break;
+ case 'admin_download':
+ $this->adminDownload();
+ break;
+ case 'admin_upload':
+ $this->adminUploadForm();
+ break;
+ case 'admin_upload_action':
+ $this->adminUploadAction();
+ break;
+ case 'admin_import_action':
+ $this->adminImportAction();
+ break;
+ case 'admin_delete_action':
+ $this->adminDeleteAction();
break;
default:
http_response_code(404);
@@ -136,15 +156,15 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
global $controller;
$controller->addInlineJavascript("
- jQuery('head').append('<link type=\"text/css\" href =\"" . WT_STATIC_URL . WT_MODULES_DIR . "googlemap/css/wt_v3_googlemap.css\" rel=\"stylesheet\">');
+ $('head').append('<link type=\"text/css\" href =\"" . WT_STATIC_URL . WT_MODULES_DIR . "googlemap/css/wt_v3_googlemap.css\" rel=\"stylesheet\">');
");
ob_start();
?>
- <script src="<?php echo $this->googleMapsScript() ?>"></script>
+ <script src="<?= $this->googleMapsScript() ?>"></script>
<script>
- var minZoomLevel = <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
- var maxZoomLevel = <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
+ var minZoomLevel = <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
+ var maxZoomLevel = <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
var startZoomLevel = maxZoomLevel;
</script>
<?php
@@ -175,16 +195,15 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
$html .= $mapdata;
$html .= '</div>';
if (Auth::isAdmin()) {
- $html .= '<div class="gm-options noprint">';
+ $html .= '<div class="gm-options">';
$html .= '<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_config">' . I18N::translate('Google Maps™ preferences') . '</a>';
$html .= ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_places">' . I18N::translate('Geographic data') . '</a>';
- $html .= ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_placecheck">' . I18N::translate('Place check') . '</a>';
$html .= '</div>';
}
$html .= '<script>loadMap();</script>';
$html .= '</div>';
} else {
- $html = '<div class="facts_value noprint">' . I18N::translate('No map data exists for this individual') . '</div>';
+ $html = '<div class="facts_value">' . I18N::translate('No map data exists for this individual') . '</div>';
if (Auth::isAdmin()) {
$html .= '<div style="text-align: center;"><a href="module.php?mod=googlemap&amp;mod_action=admin_config">' . I18N::translate('Google Maps™ preferences') . '</a></div>';
}
@@ -214,7 +233,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
return new Menu(
I18N::translate('Pedigree map'),
'module.php?mod=googlemap&amp;mod_action=pedigree_map&amp;rootid=' . $individual->getXref() . '&amp;ged=' . $individual->getTree()->getNameUrl(),
- 'menu-chart-pedigree_map',
+ 'menu-chart-pedigreemap',
['rel' => 'nofollow']
);
}
@@ -235,37 +254,32 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
*/
private function config() {
$controller = new PageController;
- $controller
- ->restrictAccess(Auth::isAdmin())
- ->setPageTitle(I18N::translate('Google Maps™'));
+ $controller->setPageTitle(I18N::translate('Google Maps™'));
if (Filter::post('action') === 'update') {
- $this->setSetting('GM_API_KEY', Filter::post('GM_API_KEY'));
- $this->setSetting('GM_MAP_TYPE', Filter::post('GM_MAP_TYPE'));
- $this->setSetting('GM_MIN_ZOOM', Filter::post('GM_MIN_ZOOM'));
- $this->setSetting('GM_MAX_ZOOM', Filter::post('GM_MAX_ZOOM'));
- $this->setSetting('GM_PLACE_HIERARCHY', Filter::post('GM_PLACE_HIERARCHY'));
- $this->setSetting('GM_PH_XSIZE', Filter::post('GM_PH_XSIZE'));
- $this->setSetting('GM_PH_YSIZE', Filter::post('GM_PH_YSIZE'));
- $this->setSetting('GM_PH_MARKER', Filter::post('GM_PH_MARKER'));
- $this->setSetting('GM_PREFIX_1', Filter::post('GM_PREFIX_1'));
- $this->setSetting('GM_PREFIX_2', Filter::post('GM_PREFIX_2'));
- $this->setSetting('GM_PREFIX_3', Filter::post('GM_PREFIX_3'));
- $this->setSetting('GM_PREFIX_4', Filter::post('GM_PREFIX_4'));
- $this->setSetting('GM_PREFIX_5', Filter::post('GM_PREFIX_5'));
- $this->setSetting('GM_PREFIX_6', Filter::post('GM_PREFIX_6'));
- $this->setSetting('GM_PREFIX_7', Filter::post('GM_PREFIX_7'));
- $this->setSetting('GM_PREFIX_8', Filter::post('GM_PREFIX_8'));
- $this->setSetting('GM_PREFIX_9', Filter::post('GM_PREFIX_9'));
- $this->setSetting('GM_POSTFIX_1', Filter::post('GM_POSTFIX_1'));
- $this->setSetting('GM_POSTFIX_2', Filter::post('GM_POSTFIX_2'));
- $this->setSetting('GM_POSTFIX_3', Filter::post('GM_POSTFIX_3'));
- $this->setSetting('GM_POSTFIX_4', Filter::post('GM_POSTFIX_4'));
- $this->setSetting('GM_POSTFIX_5', Filter::post('GM_POSTFIX_5'));
- $this->setSetting('GM_POSTFIX_6', Filter::post('GM_POSTFIX_6'));
- $this->setSetting('GM_POSTFIX_7', Filter::post('GM_POSTFIX_7'));
- $this->setSetting('GM_POSTFIX_8', Filter::post('GM_POSTFIX_8'));
- $this->setSetting('GM_POSTFIX_9', Filter::post('GM_POSTFIX_9'));
+ $this->setPreference('GM_API_KEY', Filter::post('GM_API_KEY'));
+ $this->setPreference('GM_MIN_ZOOM', Filter::post('GM_MIN_ZOOM'));
+ $this->setPreference('GM_MAX_ZOOM', Filter::post('GM_MAX_ZOOM'));
+ $this->setPreference('GM_PLACE_HIERARCHY', Filter::post('GM_PLACE_HIERARCHY'));
+ $this->setPreference('GM_PH_MARKER', Filter::post('GM_PH_MARKER'));
+ $this->setPreference('GM_PREFIX_1', Filter::post('GM_PREFIX_1'));
+ $this->setPreference('GM_PREFIX_2', Filter::post('GM_PREFIX_2'));
+ $this->setPreference('GM_PREFIX_3', Filter::post('GM_PREFIX_3'));
+ $this->setPreference('GM_PREFIX_4', Filter::post('GM_PREFIX_4'));
+ $this->setPreference('GM_PREFIX_5', Filter::post('GM_PREFIX_5'));
+ $this->setPreference('GM_PREFIX_6', Filter::post('GM_PREFIX_6'));
+ $this->setPreference('GM_PREFIX_7', Filter::post('GM_PREFIX_7'));
+ $this->setPreference('GM_PREFIX_8', Filter::post('GM_PREFIX_8'));
+ $this->setPreference('GM_PREFIX_9', Filter::post('GM_PREFIX_9'));
+ $this->setPreference('GM_POSTFIX_1', Filter::post('GM_POSTFIX_1'));
+ $this->setPreference('GM_POSTFIX_2', Filter::post('GM_POSTFIX_2'));
+ $this->setPreference('GM_POSTFIX_3', Filter::post('GM_POSTFIX_3'));
+ $this->setPreference('GM_POSTFIX_4', Filter::post('GM_POSTFIX_4'));
+ $this->setPreference('GM_POSTFIX_5', Filter::post('GM_POSTFIX_5'));
+ $this->setPreference('GM_POSTFIX_6', Filter::post('GM_POSTFIX_6'));
+ $this->setPreference('GM_POSTFIX_7', Filter::post('GM_POSTFIX_7'));
+ $this->setPreference('GM_POSTFIX_8', Filter::post('GM_POSTFIX_8'));
+ $this->setPreference('GM_POSTFIX_9', Filter::post('GM_POSTFIX_9'));
FlashMessages::addMessage(I18N::translate('The preferences for the module “%s” have been updated.', $this->getTitle()), 'success');
header('Location: ' . WT_BASE_URL . 'module.php?mod=googlemap&mod_action=admin_config');
@@ -275,193 +289,148 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
$controller->pageHeader();
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel') ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration') ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle() ?></li>
- </ol>
-
- <ul class="nav nav-tabs nav-justified" role="tablist">
- <li role="presentation" class="active">
- <a href="#" role="tab">
- <?php echo I18N::translate('Google Maps™ preferences') ?>
- </a>
- </li>
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_places">
- <?php echo I18N::translate('Geographic data') ?>
- </a>
- </li>
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_placecheck">
- <?php echo I18N::translate('Place check') ?>
- </a>
- </li>
- </ul>
- <h2><?php echo I18N::translate('Google Maps™ preferences') ?></h2>
+ <h2><?= I18N::translate('Google Maps™ preferences') ?></h2>
<form class="form-horizontal" method="post" name="configform" action="module.php?mod=googlemap&mod_action=admin_config">
<input type="hidden" name="action" value="update">
- <!-- GM_MAP_TYPE -->
- <div class="form-group">
- <label class="control-label col-sm-3" for="GM_API_KEY">
- <?php echo /* I18N: https://en.wikipedia.org/wiki/API_key */ I18N::translate('API key') ?>
- </label>
+ <div class="row form-group">
+ <div class="col-sm-3 col-form-label">
+ <?= I18N::translate('Geographic data') ?>
+ </div>
<div class="col-sm-9">
- <input id="GM_API_KEY" class="form-control" type="text" name="GM_API_KEY" value="<?php echo $this->getSetting('GM_API_KEY') ?>">
- <p class="small text-muted"><?php echo I18N::translate('Google allows a small number of anonymous map requests per day. If you need more than this, you will need a Google account and an API key.') ?>
- <a href="https://developers.google.com/maps/documentation/javascript/get-api-key">
- <?php echo /* I18N: https://en.wikipedia.org/wiki/API_key */ I18N::translate('Get an API key from Google.') ?>
- </a>
- </p>
+ <a class="btn btn-primary" href="module.php?mod=googlemap&amp;mod_action=admin_places">
+ <?= FontAwesome::decorativeIcon('edit') ?>
+ <?= I18N::translate('edit') ?>
+ </a>
</div>
</div>
- <div class="form-group">
- <label class="control-label col-sm-3" for="GM_MAP_TYPE">
- <?php echo I18N::translate('Default map type') ?>
+ <!-- GM_API_KEY -->
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="GM_API_KEY">
+ <?= /* I18N: https://en.wikipedia.org/wiki/API_key */ I18N::translate('API key') ?>
</label>
<div class="col-sm-9">
- <?php
- $options = [
- 'ROADMAP' => I18N::translate('Map'),
- 'SATELLITE' => I18N::translate('Satellite'),
- 'HYBRID' => I18N::translate('Hybrid'),
- 'TERRAIN' => I18N::translate('Terrain'),
- ];
- echo FunctionsEdit::selectEditControl('GM_MAP_TYPE', $options, null, $this->getSetting('GM_MAP_TYPE'), 'class="form-control"');
- ?>
+ <input id="GM_API_KEY" class="form-control" type="text" name="GM_API_KEY" value="<?= $this->getPreference('GM_API_KEY') ?>">
+ <p class="small text-muted"><?= I18N::translate('Google allows a small number of anonymous map requests per day. If you need more than this, you will need a Google account and an API key.') ?>
+ <a href="https://developers.google.com/maps/documentation/javascript/get-api-key">
+ <?= /* I18N: https://en.wikipedia.org/wiki/API_key */ I18N::translate('Get an API key from Google.') ?>
+ </a>
+ </p>
</div>
</div>
<!-- GM_MIN_ZOOM / GM_MAX_ZOOM -->
<fieldset class="form-group">
- <legend class="control-label col-sm-3">
- <?php echo I18N::translate('Zoom level of map') ?>
- </legend>
- <div class="col-sm-9">
- <div class="row">
- <div class="col-sm-6">
- <div class="input-group">
- <label class="input-group-addon" for="GM_MIN_ZOOM"><?php echo I18N::translate('minimum') ?></label>
- <?php echo FunctionsEdit::selectEditControl('GM_MIN_ZOOM', array_combine(range(self::GM_MIN_ZOOM_MINIMUM, self::GM_MIN_ZOOM_MAXIMUM), range(self::GM_MIN_ZOOM_MINIMUM, self::GM_MIN_ZOOM_MAXIMUM)), null, $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT), 'class="form-control"') ?>
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= I18N::translate('Zoom level of map') ?>
+ </legend>
+ <div class="col-sm-9">
+ <div class="row">
+ <div class="col-sm-6">
+ <div class="input-group">
+ <label class="input-group-addon" for="GM_MIN_ZOOM"><?= I18N::translate('minimum') ?></label>
+ <?= Bootstrap4::select(array_combine(range(self::GM_MIN_ZOOM_MINIMUM, self::GM_MIN_ZOOM_MAXIMUM), range(self::GM_MIN_ZOOM_MINIMUM, self::GM_MIN_ZOOM_MAXIMUM)), $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT), ['id' => 'GM_MIN_ZOOM', 'name' => 'GM_MIN_ZOOM']) ?>
+ </div>
</div>
- </div>
- <div class="col-sm-6">
- <div class="input-group">
- <label class="input-group-addon" for="GM_MAX_ZOOM"><?php echo I18N::translate('maximum') ?></label>
- <?php echo FunctionsEdit::selectEditControl('GM_MAX_ZOOM', array_combine(range(self::GM_MAX_ZOOM_MINIMUM, self::GM_MAX_ZOOM_MAXIMUM), range(self::GM_MAX_ZOOM_MINIMUM, self::GM_MAX_ZOOM_MAXIMUM)), null, $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT), 'class="form-control"') ?>
+ <div class="col-sm-6">
+ <div class="input-group">
+ <label class="input-group-addon" for="GM_MAX_ZOOM"><?= I18N::translate('maximum') ?></label>
+ <?= Bootstrap4::select(array_combine(range(self::GM_MAX_ZOOM_MINIMUM, self::GM_MAX_ZOOM_MAXIMUM), range(self::GM_MAX_ZOOM_MINIMUM, self::GM_MAX_ZOOM_MAXIMUM)), $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT), ['id' => 'GM_MAX_ZOOM', 'name' => 'GM_MAX_ZOOM']) ?>
+ </div>
</div>
</div>
+ <p class="small text-muted"><?= I18N::translate('Minimum and maximum zoom level for the Google map. 1 is the full map, 15 is single house. Note that 15 is only available in certain areas.') ?></p>
</div>
- <p class="small text-muted"><?php echo I18N::translate('Minimum and maximum zoom level for the Google map. 1 is the full map, 15 is single house. Note that 15 is only available in certain areas.') ?></p>
</div>
</fieldset>
<!-- GM_PREFIX / GM_POSTFIX -->
<fieldset class="form-group">
- <legend class="control-label col-sm-3">
- <?php echo I18N::translate('Optional prefixes and suffixes') ?>
- </legend>
- <div class="col-sm-9">
- <div class="row">
- <div class ="col-sm-6">
- <p class="form-control-static"><strong><?php echo I18N::translate('Prefixes') ?></strong></p>
- <?php for ($level = 1; $level < 10; $level++): ?>
- <?php
- if ($level == 1) {
- $label = I18N::translate('Country');
- } else {
- $label = I18N::translate('Level') . ' ' . $level;
- }
- ?>
- <div class="input-group">
- <label class="input-group-addon" for="GM_PREFIX_<?php echo $level ?>"><?php echo $label ?></label>
- <input class="form-control" type="text" name="GM_PREFIX_<?php echo $level ?>" value="<?php echo $this->getSetting('GM_PREFIX_' . $level) ?>">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= I18N::translate('Optional prefixes and suffixes') ?>
+ </legend>
+ <div class="col-sm-9">
+ <div class="row">
+ <div class ="col-sm-6">
+ <p class="form-control-static"><strong><?= I18N::translate('Prefixes') ?></strong></p>
+ <?php for ($level = 1; $level < 10; $level++): ?>
+ <?php
+ if ($level == 1) {
+ $label = I18N::translate('Country');
+ } else {
+ $label = I18N::translate('Level') . ' ' . $level;
+ }
+ ?>
+ <div class="input-group">
+ <label class="input-group-addon" for="GM_PREFIX_<?= $level ?>"><?= $label ?></label>
+ <input class="form-control" type="text" name="GM_PREFIX_<?= $level ?>" value="<?= $this->getPreference('GM_PREFIX_' . $level) ?>">
+ </div>
+ <?php endfor ?>
</div>
- <?php endfor ?>
- </div>
- <div class="col-sm-6">
- <p class="form-control-static"><strong><?php echo I18N::translate('Suffixes') ?></strong></p>
- <?php for ($level = 1; $level < 10; $level++): ?>
- <?php
- if ($level == 1) {
- $label = I18N::translate('Country');
- } else {
- $label = I18N::translate('Level') . ' ' . $level;
- }
- ?>
- <div class="input-group">
- <label class="input-group-addon" for="GM_POSTFIX_<?php echo $level ?>"><?php echo $label ?></label>
- <input class="form-control" type="text" name="GM_POSTFIX_<?php echo $level ?>" value="<?php echo $this->getSetting('GM_POSTFIX_' . $level) ?>">
+ <div class="col-sm-6">
+ <p class="form-control-static"><strong><?= I18N::translate('Suffixes') ?></strong></p>
+ <?php for ($level = 1; $level < 10; $level++): ?>
+ <?php
+ if ($level == 1) {
+ $label = I18N::translate('Country');
+ } else {
+ $label = I18N::translate('Level') . ' ' . $level;
+ }
+ ?>
+ <div class="input-group">
+ <label class="input-group-addon" for="GM_POSTFIX_<?= $level ?>"><?= $label ?></label>
+ <input class="form-control" type="text" name="GM_POSTFIX_<?= $level ?>" value="<?= $this->getPreference('GM_POSTFIX_' . $level) ?>">
+ </div>
+ <?php endfor ?>
</div>
- <?php endfor ?>
</div>
+ <p class="small text-muted"><?= I18N::translate('Some place names may be written with optional prefixes and suffixes. For example “Orange” versus “Orange County”. If the family tree contains the full place names, but the geographic database contains the short place names, then you should specify a list of the prefixes and suffixes to be disregarded. Multiple values should be separated with semicolons. For example “County;County of” or “Township;Twp;Twp.”.') ?></p>
</div>
- <p class="small text-muted"><?php echo I18N::translate('Some place names may be written with optional prefixes and suffixes. For example “Orange” versus “Orange County”. If the family tree contains the full place names, but the geographic database contains the short place names, then you should specify a list of the prefixes and suffixes to be disregarded. Multiple values should be separated with semicolons. For example “County;County of” or “Township;Twp;Twp.”.') ?></p>
</div>
</fieldset>
- <h3><?php echo I18N::translate('Place hierarchy') ?></h3>
+ <h3><?= I18N::translate('Place hierarchy') ?></h3>
<!-- GM_PLACE_HIERARCHY -->
<fieldset class="form-group">
- <legend class="control-label col-sm-3">
- <?php echo I18N::translate('Use Google Maps™ for the place hierarchy') ?>
- </legend>
- <div class="col-sm-9">
- <?php echo FunctionsEdit::editFieldYesNo('GM_PLACE_HIERARCHY', $this->getSetting('GM_PLACE_HIERARCHY'), 'class="radio-inline"') ?>
- </div>
- </fieldset>
-
- <!-- GM_PH_XSIZE / GM_PH_YSIZE -->
- <fieldset class="form-group">
- <legend class="control-label col-sm-3">
- <?php echo I18N::translate('Size of map (in pixels)') ?>
- </legend>
- <div class="col-sm-9">
- <div class="row">
- <div class="col-sm-6">
- <div class="input-group">
- <label class="input-group-addon" for="GM_PH_XSIZE"><?php echo I18N::translate('Width') ?></label>
- <input id="GM_PH_XSIZE" class="form-control" type="text" name="GM_PH_XSIZE" value="<?php echo $this->getSetting('GM_PH_XSIZE') ?>">
- </div>
- </div>
- <div class="col-sm-6">
- <div class="input-group">
- <label class="input-group-addon" for="GM_PH_YSIZE"><?php echo I18N::translate('Height') ?></label>
- <input id="GM_PH_YSIZE" class="form-control" type="text" name="GM_PH_YSIZE" value="<?php echo $this->getSetting('GM_PH_YSIZE') ?>">
- </div>
- </div>
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= I18N::translate('Use Google Maps™ for the place hierarchy') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('GM_PLACE_HIERARCHY', [I18N::translate('no'), I18N::translate('yes')], $this->getPreference('GM_PLACE_HIERARCHY'), true) ?>
</div>
</div>
</fieldset>
<!-- GM_PH_MARKER -->
- <div class="form-group">
- <label class="control-label col-sm-3" for="GM_PH_MARKER">
- <?php echo I18N::translate('Type of place markers in the place hierarchy') ?>
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="GM_PH_MARKER">
+ <?= I18N::translate('Type of place markers in the place hierarchy') ?>
</label>
<div class="col-sm-9">
<?php
- $ph_options = [
- 'G_DEFAULT_ICON' => I18N::translate('Standard'),
- 'G_FLAG' => I18N::translate('Flag'),
- ];
- echo FunctionsEdit::selectEditControl('GM_PH_MARKER', $ph_options, null, $this->getSetting('GM_PH_MARKER'), 'class="form-control"');
+ echo Bootstrap4::select(['G_DEFAULT_ICON' => I18N::translate('Standard'), 'G_FLAG' => I18N::translate('Flag')], $this->getPreference('GM_PH_MARKER'), ['id' => 'GM_PH_MARKER', 'name' => 'GM_PH_MARKER']);
?>
</div>
</div>
<!-- SAVE BUTTON -->
- <div class="form-group">
- <div class="col-sm-offset-3 col-sm-9">
+ <div class="row form-group">
+ <div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-primary">
<i class="fa fa-check"></i>
- <?php echo I18N::translate('save') ?>
+ <?= I18N::translate('save') ?>
</button>
</div>
</div>
@@ -475,1083 +444,587 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
* @return string
*/
private function googleMapsScript() {
- $key = $this->getSetting('GM_API_KEY');
+ $key = $this->getPreference('GM_API_KEY');
return 'https://maps.googleapis.com/maps/api/js?v=3&amp;key=' . $key . '&amp;language=' . WT_LOCALE;
}
/**
- * Select a flag.
- */
- private function flags() {
- global $WT_TREE;
-
- $controller = new SimpleController;
- $controller
- ->setPageTitle(I18N::translate('Select flag'))
- ->pageHeader();
-
- $stats = new Stats($WT_TREE);
- $countries = $stats->getAllCountries();
- $action = Filter::post('action');
- $countrySelected = Filter::get('countrySelected', null, 'Countries');
- $stateSelected = Filter::get('stateSelected', null, 'States');
-
- $country = [];
- if (is_dir(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/flags')) {
- $files = glob(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/flags/*.png');
- foreach ($files as $file) {
- $country[] = basename($file, '.png');
- }
- }
-
- if ($countrySelected == 'Countries') {
- $flags = $country;
- } else {
- $flags = [];
- if (is_dir(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags')) {
- $files = glob(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags/*.png');
- foreach ($files as $file) {
- $flags[] = basename($file, '.png');
- }
- }
- }
-
- $flags_s = [];
- if ($stateSelected != 'States' && is_dir(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags/' . $stateSelected)) {
- $files = glob(WT_ROOT . WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags/' . $stateSelected . '/*.png');
- foreach ($files as $file) {
- $flags_s[] = basename($file, '.png');
- }
- }
-
- if ($action == 'ChangeFlag' && Filter::post('FLAGS') !== null) {
- ?>
- <script>
- <?php if (Filter::post('selcountry') == 'Countries') { ?>
- window.opener.document.editplaces.icon.value = 'places/flags/<?php echo $flags[Filter::post('FLAGS')] ?>.png';
- window.opener.document.getElementById('flagsDiv').innerHTML = "<img src=\"<?php echo WT_STATIC_URL . WT_MODULES_DIR ?>googlemap/places/flags/<?php echo $country[Filter::post('FLAGS')] ?>.png\">&nbsp;&nbsp;<a href=\"#\" onclick=\"change_icon();return false;\"><?php echo I18N::translate('Change flag') ?></a>&nbsp;&nbsp;<a href=\"#\" onclick=\"remove_icon();return false;\"><?php echo I18N::translate('Remove flag') ?></a>";
- <?php } elseif (Filter::post('selstate') != 'States') { ?>
- window.opener.document.editplaces.icon.value = 'places/<?php echo $countrySelected . '/flags/' . Filter::post('selstate') . '/' . $flags_s[Filter::post('FLAGS')] ?>.png';
- window.opener.document.getElementById('flagsDiv').innerHTML = "<img src=\"<?php echo WT_STATIC_URL . WT_MODULES_DIR ?>googlemap/places/<?php echo $countrySelected . '/flags/' . Filter::post('selstate') . '/' . $flags_s[Filter::post('FLAGS')] ?>.png\">&nbsp;&nbsp;<a href=\"#\" onclick=\"change_icon();return false;\"><?php echo I18N::translate('Change flag') ?></a>&nbsp;&nbsp;<a href=\"#\" onclick=\"remove_icon();return false;\"><?php echo I18N::translate('Remove flag') ?></a>";
- <?php } else { ?>
- window.opener.document.editplaces.icon.value = "places/<?php echo $countrySelected . '/flags/' . $flags[Filter::post('FLAGS')] ?>.png";
- window.opener.document.getElementById('flagsDiv').innerHTML = "<img src=\"<?php echo WT_STATIC_URL . WT_MODULES_DIR ?>googlemap/places/<?php echo $countrySelected . '/flags/' . $flags[Filter::post('FLAGS')] ?>.png\">&nbsp;&nbsp;<a href=\"#\" onclick=\"change_icon();return false;\"><?php echo I18N::translate('Change flag') ?></a>&nbsp;&nbsp;<a href=\"#\" onclick=\"remove_icon();return false;\"><?php echo I18N::translate('Remove flag') ?></a>";
- <?php } ?>
- window.opener.updateMap();
- window.close();
- </script>
- <?php
- return;
- } else {
- ?>
- <script>
- function selectCountry() {
- if (document.flags.COUNTRYSELECT.value == 'Countries') {
- window.location="module.php?mod=googlemap&mod_action=flags&countrySelected=Countries";
- } else if (document.flags.STATESELECT.value != 'States') {
- window.location="module.php?mod=googlemap&mod_action=flags&countrySelected=" + document.flags.COUNTRYSELECT.value + "&stateSelected=" + document.flags.STATESELECT.value;
- } else {
- window.location="module.php?mod=googlemap&mod_action=flags&countrySelected=" + document.flags.COUNTRYSELECT.value;
- }
- }
- </script>
- <?php
- }
- $countryList = [];
-
- foreach ($country as $item) {
- if (is_dir(WT_MODULES_DIR . 'googlemap/places/' . $item . '/flags')) {
- if (isset($countries[$item])) {
- $countryList[$item] = $countries[$item];
- } else {
- $countryList[$item] = $item;
- }
- }
- }
- asort($countryList);
- $stateList = [];
-
- if ($countrySelected != 'Countries') {
- $placesDir = scandir(WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags/');
- foreach ($flags as $flag) {
- if (in_array($flag, $placesDir)) {
- $rep = opendir(WT_MODULES_DIR . 'googlemap/places/' . $countrySelected . '/flags/' . $flag . '/');
- while ($file = readdir($rep)) {
- $stateList[$flag] = $flag;
- }
- closedir($rep);
- }
- }
- asort($stateList);
- }
-
- ?>
- <h4><?php echo I18N::translate('Change flag') ?></h4>
-
- <p class="small text-muted">
- <?php echo I18N::translate('Using the pull down menu it is possible to select a country, of which a flag can be selected. If no flags are shown, then there are no flags defined for this country.') ?>
- </p>
-
- <form method="post" id="flags" name="flags" action="module.php?mod=googlemap&amp;mod_action=flags&amp;countrySelected=<?php echo $countrySelected ?>&amp;stateSelected=<?php echo $stateSelected ?>">
- <input type="hidden" name="action" value="ChangeFlag">
- <input type="hidden" name="selcountry" value="<?php echo $countrySelected ?>">
- <input type="hidden" name="selstate" value="<?php echo $stateSelected ?>">
- <table class="facts_table" style="margin: 0 auto 20px">
- <tr>
- <td class="optionbox" colspan="4">
- <select name="COUNTRYSELECT" dir="ltr" onchange="selectCountry()">
- <option value="Countries"><?php echo I18N::translate('Countries') ?></option>
- <?php foreach ($countryList as $country_key => $country_name) {
- echo '<option value="', $country_key, '" ';
- if ($countrySelected == $country_key) {
- echo 'selected';
- }
- echo '>', $country_name, '</option>';
- } ?>
- </select>
- </td>
- </tr>
-
- <?php
- $i = 0;
- $path = WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/places/';
- $path .= $countrySelected == 'Countries' ? 'flags/' : $countrySelected . '/flags/';
- foreach (array_chunk($flags, 4) as $row) {
- echo '<tr>';
- foreach ($row as $flag) {
- if ($flag != 'blank') {
- if (isset($countries[$flag])) {
- $title = $countries[$flag];
- } else {
- $title = $flag;
- }
- } else {
- $title = $countries['???'];
- }
- echo '<td>';
- echo '<input type="radio" dir="ltr" name="FLAGS" value="' . $i++ . '">';
- echo '<img style="width:25px; height:15px; margin-right:15px" src="' . $path . $flag . '.png" alt="' . $flag . '" title="' . $title . '">';
- echo $flag . '</td>';
-
- }
-
- echo str_repeat('<td></td>', 4 - count($row));
- echo '</tr>';
- }
-
- echo'<tr style="visibility:' . (($countrySelected == 'Countries' || count($stateList) == 0) ? 'hidden' : 'visible') . '">';
- ?>
-
- <td class="optionbox" colspan="4">
- <select name="STATESELECT" dir="ltr" onchange="selectCountry()">
- <option value="States"><?php echo /* I18N: Part of a country, state/region/county */ I18N::translate('Subdivision') ?></option>
- <?php foreach ($stateList as $state_key => $state_name) {
- echo '<option value="', $state_key, '" ';
- if ($stateSelected == $state_key) {
- echo 'selected';
- }
- echo '>', $state_name, '</option>';
- } ?>
- </select>
- </td>
- </tr>
-
- <?php
-
- $i = 0;
- if (!empty($flags_s)) {
- foreach (array_chunk($flags_s, 4) as $row) {
- echo '<tr>';
- foreach ($row as $flag) {
- echo '<td><input type="radio" dir="ltr" name="FLAGS" value="', $i++, '"><img src="', WT_STATIC_URL . WT_MODULES_DIR, 'googlemap/places/', $countrySelected, '/flags/', $stateSelected, '/', $flag, '.png">&nbsp;&nbsp;', $flag, '</td>';
- }
- echo str_repeat('<td></td>', 4 - count($row));
- echo '</tr>';
- }
- }
-
- ?>
-
- </table>
- <p id="save-cancel">
- <input type="submit" class="save" value="<?php echo I18N::translate('save') ?>">
- <input type="button" class="cancel" value="<?php echo I18N::translate('close') ?>" onclick="window.close();">
- </p>
- </form>
- <?php
- }
-
- /**
* Display a map showing the origins of ones ancestors.
*/
private function pedigreeMap() {
global $controller, $WT_TREE;
- $MAX_PEDIGREE_GENERATIONS = $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS');
- // Limit this to match available number of icons.
+ $controller = new ChartController();
+ $controller->restrictAccess(Module::isActiveChart($WT_TREE, 'googlemap'));
+
+ // Limit this to match available number of icons.
// 8 generations equals 255 individuals
+ $MAX_PEDIGREE_GENERATIONS = $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS');
$MAX_PEDIGREE_GENERATIONS = min($MAX_PEDIGREE_GENERATIONS, 8);
+ $generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $MAX_PEDIGREE_GENERATIONS, $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
+ $this->treesize = pow(2, $generations) - 1;
+ $this->ancestors = array_values($controller->sosaAncestors($generations));
- $controller = new ChartController();
- $generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $MAX_PEDIGREE_GENERATIONS, $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
- $this->treesize = pow(2, $generations) - 1;
- $this->ancestors = array_values($controller->sosaAncestors($generations));
+ // Only generate the content for interactive users (not search robots).
+ if (Filter::getBool('ajax') && Session::has('initiated')) {
+ // count records by type
+ $curgen = 1;
+ $priv = 0;
+ $count = 0;
+ $miscount = 0;
+ $missing = [];
- $controller
- ->setPageTitle(/* I18N: %s is an individual’s name */ I18N::translate('Pedigree map of %s', $controller->root->getFullName()))
- ->pageHeader()
- ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
- /* prepending the module css in the page head allows the theme to over-ride it*/
- ->addInlineJavascript("
- jQuery('head').prepend('<link type=\"text/css\" href =\"" . WT_STATIC_URL . WT_MODULES_DIR . "googlemap/css/wt_v3_googlemap.css\" rel=\"stylesheet\">');
- autocomplete();" .
- $this->pedigreeMapJavascript()
- );
-
- echo '<div id="pedigreemap-page"><h2>', $controller->getPageTitle(), '</h2>';
-
- // -- print the form to change the number of displayed generations
- ?>
- <form name="people" method="get" action="?">
- <input type="hidden" name="ged" value="<?php echo $WT_TREE->getNameHtml() ?>">
- <input type="hidden" name="mod" value="googlemap">
- <input type="hidden" name="mod_action" value="pedigree_map">
- <table class="list_table">
- <tr>
- <td class="descriptionbox wrap">
- <label for="rootid">
- <?php echo I18N::translate('Individual') ?>
- </label>
- </td>
- <td class="optionbox">
- <input class="pedigree_form" data-autocomplete-type="INDI" type="text" id="rootid" name="rootid" size="3" value="<?php echo $controller->root->getXref() ?>">
- <?php echo FunctionsPrint::printFindIndividualLink('rootid') ?>
- </td>
- <td class="topbottombar" rowspan="2">
- <input type="submit" value="<?php echo /* I18N: A button label. */ I18N::translate('view') ?>">
- </td>
- </tr>
- <tr>
- <td class="descriptionbox wrap">
- <label for="PEDIGREE_GENERATIONS">
- <?php echo I18N::translate('Generations') ?>
- </label>
- </td>
- <td class="optionbox">
- <select name="PEDIGREE_GENERATIONS" id="PEDIGREE_GENERATIONS">
- <?php
- for ($p = 3; $p <= $MAX_PEDIGREE_GENERATIONS; $p++) {
- echo '<option value="', $p, '" ';
- if ($p == $generations) {
- echo 'selected';
- }
- echo '>', $p, '</option>';
- }
- ?>
- </select>
- </td>
- </tr>
- </table>
- </form>
- <!-- end of form -->
-
- <!-- count records by type -->
- <?php
- $curgen = 1;
- $priv = 0;
- $count = 0;
- $miscount = 0;
- $missing = [];
-
- $latlongval = [];
- $lat = [];
- $lon = [];
- for ($i = 0; $i < ($this->treesize); $i++) {
- // -- check to see if we have moved to the next generation
- if ($i + 1 >= pow(2, $curgen)) {
- $curgen++;
- }
- $person = $this->ancestors[$i];
- if (!empty($person)) {
- $name = $person->getFullName();
- if ($name == I18N::translate('Private')) {
- $priv++;
- }
- $place = $person->getBirthPlace();
- if (empty($place)) {
- $latlongval[$i] = null;
- } else {
- $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
+ $latlongval = [];
+ $lat = [];
+ $lon = [];
+ for ($i = 0; $i < ($this->treesize); $i++) {
+ // -- check to see if we have moved to the next generation
+ if ($i + 1 >= pow(2, $curgen)) {
+ $curgen++;
}
- if ($latlongval[$i]) {
- $lat[$i] = strtr($latlongval[$i]->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
- $lon[$i] = strtr($latlongval[$i]->pl_long, ['N' => '', 'S' => '-', ',' => '.']);
- if ($lat[$i] && $lon[$i]) {
- $count++;
+ $person = $this->ancestors[$i];
+ if (!empty($person)) {
+ $name = $person->getFullName();
+ if ($name == I18N::translate('Private')) {
+ $priv++;
+ }
+ $place = $person->getBirthPlace();
+ if (empty($place)) {
+ $latlongval[$i] = null;
+ } else {
+ $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
+ }
+ if ($latlongval[$i]) {
+ $lat[$i] = strtr($latlongval[$i]->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
+ $lon[$i] = strtr($latlongval[$i]->pl_long, ['N' => '', 'S' => '-', ',' => '.']);
+ if ($lat[$i] && $lon[$i]) {
+ $count++;
+ } else {
+ // The place is in the table but has empty values
+ if ($name) {
+ $missing[] = '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
+ $miscount++;
+ }
+ }
} else {
- // The place is in the table but has empty values
+ // There was no place, or not listed in the map table
if ($name) {
$missing[] = '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
$miscount++;
}
}
- } else {
- // There was no place, or not listed in the map table
- if ($name) {
- $missing[] = '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
- $miscount++;
- }
}
}
- }
- //<!-- end of count records by type -->
- //<!-- start of map display -->
- echo '<div class="gm-pedigree-map">';
- echo '<div class="gm-wrapper">';
- echo '<div class="gm-map"><i class="icon-loading-large"></i></div>';
- echo '<div class="gm-ancestors"></div>';
- echo '</div>';
-
- if (Auth::isAdmin()) {
- echo '<div class="gm-options noprint">';
- echo '<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_config">' . I18N::translate('Google Maps™ preferences') . '</a>';
- echo ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_places">' . I18N::translate('Geographic data') . '</a>';
- echo ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_placecheck">' . I18N::translate('Place check') . '</a>';
+ //<!-- end of count records by type -->
+ //<!-- start of map display -->
+ echo '<div class="gm-pedigree-map">';
+ echo '<div class="gm-wrapper">';
+ echo '<div class="gm-map wt-ajax-load"></div>';
+ echo '<div class="gm-ancestors"></div>';
echo '</div>';
- }
- // display info under map
- echo '<hr>';
- // print summary statistics
- if (isset($curgen)) {
- $total = pow(2, $curgen) - 1;
- echo '<div>';
- echo I18N::plural(
- '%1$s individual displayed, out of the normal total of %2$s, from %3$s generations.',
- '%1$s individuals displayed, out of the normal total of %2$s, from %3$s generations.',
- $count,
- I18N::number($count), I18N::number($total), I18N::number($curgen)
- );
- echo '</div>';
- if ($priv) {
- echo '<div>' . I18N::plural('%s individual is private.', '%s individuals are private.', $priv, $priv), '</div>';
+ if (Auth::isAdmin()) {
+ echo '<div class="gm-options">';
+ echo '<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_config">' . I18N::translate('Google Maps™ preferences') . '</a>';
+ echo ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_places">' . I18N::translate('Geographic data') . '</a>';
+ echo '</div>';
}
- if ($count + $priv != $total) {
- if ($miscount == 0) {
- echo '<div>' . I18N::translate('No ancestors in the database.'), '</div>';
- } else {
- echo '<div>' . /* I18N: %1$s is a count of individuals, %2$s is a list of their names */ I18N::plural(
- '%1$s individual is missing birthplace map coordinates: %2$s.',
- '%1$s individuals are missing birthplace map coordinates: %2$s.',
- $miscount, I18N::number($miscount), implode(I18N::$list_separator, $missing)),
+ // display info under map
+ echo '<hr>';
+
+ // print summary statistics
+ if (isset($curgen)) {
+ $total = pow(2, $curgen) - 1;
+ echo '<div>';
+ echo I18N::plural(
+ '%1$s individual displayed, out of the normal total of %2$s, from %3$s generations.',
+ '%1$s individuals displayed, out of the normal total of %2$s, from %3$s generations.',
+ $count,
+ I18N::number($count), I18N::number($total), I18N::number($curgen)
+ );
+ echo '</div>';
+ if ($priv) {
+ echo '<div>' . I18N::plural('%s individual is private.', '%s individuals are private.', $priv, $priv), '</div>';
+ }
+ if ($count + $priv != $total) {
+ if ($miscount == 0) {
+ echo '<div>' . I18N::translate('No ancestors in the database.'), '</div>';
+ } else {
+ echo '<div>' . /* I18N: %1$s is a count of individuals, %2$s is a list of their names */ I18N::plural(
+ '%1$s individual is missing birthplace map coordinates: %2$s.',
+ '%1$s individuals are missing birthplace map coordinates: %2$s.',
+ $miscount, I18N::number($miscount), implode(I18N::$list_separator, $missing)),
'</div>';
+ }
}
}
- }
- echo '</div>';
- echo '</div>';
- echo '<script src="', $this->googleMapsScript(), '"></script>';
- }
+ echo '</div>';
+ echo '</div>';
+ ?>
+ <script>
+ function initialiZePedigreeMap() {
+ // this variable will collect the html which will eventually be placed in the side bar
+ var gm_ancestors_html = "";
+ // arrays to hold copies of the markers and html used by the side bar
+ // because the function closure trick doesnt work there
+ var gmarkers = [];
+ var index = 0;
+ var lastlinkid;
+ var infowindow = new google.maps.InfoWindow({});
+ // === Create an associative array of GIcons()
+ var gicons = [];
+ gicons["1"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon1.png"
+ };
+ gicons["2"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon2.png"
+ };
+ gicons["2L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon2L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["2R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon2R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["2Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR+"googlemap/images/icon2Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["2Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon2Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["3"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon3.png"
+ };
+ gicons["3L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon3L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["3R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon3R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["3Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon3Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["3Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon3Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["4"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon4.png"
+ };
+ gicons["4L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon4L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["4R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon4R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["4Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon4Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["4Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon4Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["5"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon5.png"
+ };
+ gicons["5L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon5L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["5R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon5R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["5Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon5Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["5Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon5Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["6"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon6.png"
+ };
+ gicons["6L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon6L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["6R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon6R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["6Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon6Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["6Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon6Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["7"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon7.png"
+ };
+ gicons["7L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon7L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["7R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon7R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["7Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon7Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["7Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon7Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ gicons["8"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon8.png"
+ };
+ gicons["8L"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon8L.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(28, 28)
+ };
+ gicons["8R"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon8R.png",
+ size: new google.maps.Size(32, 32),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(4, 28)
+ };
+ gicons["8Ls"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon8Ls.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(22, 22)
+ };
+ gicons["8Rs"] = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + "googlemap/images/icon8Rs.png",
+ size: new google.maps.Size(24, 24),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(2, 22)
+ };
+ // / A function to create the marker and set up the event window
+ function createMarker(point, name, html, mhtml, icontype) {
+ // Create a marker with the requested icon
+ var marker = new google.maps.Marker({
+ icon: gicons[icontype],
+ map: pm_map,
+ position: point,
+ id: index,
+ zIndex: 0
+ });
+ google.maps.event.addListener(marker, "click", function() {
+ infowindow.close();
+ infowindow.setContent(mhtml);
+ infowindow.open(pm_map, marker);
+ var el = $(".gm-ancestor[data-marker=" + marker.id + "]");
+ if(el.hasClass("person_box")) {
+ el
+ .removeClass("person_box")
+ .addClass("gm-ancestor-visited");
+ infowindow.close();
+ } else {
+ el
+ .addClass("person_box")
+ .removeClass("gm-ancestor-visited");
+ }
+ var anchor = infowindow.getAnchor();
+ lastlinkid = anchor ? anchor.id : null;
+ });
+ // save the info we need to use later for the side bar
+ gmarkers[index] = marker;
+ gm_ancestors_html += "<div data-marker =" + index++ + " class=\"gm-ancestor\">" + html +"</div>";
- /**
- * Create the Javascript to activate the map.
- *
- * @return string
- */
- private function pedigreeMapJavascript() {
+ return marker;
+ }
+ // create the map
+ var myOptions = {
+ zoom: 6,
+ minZoom: <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>,
+ maxZoom: <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>,
+ center: new google.maps.LatLng(0, 0),
+ mapTypeId: google.maps.MapTypeId.TERRAIN, // ROADMAP, SATELLITE, HYBRID, TERRAIN
+ mapTypeControlOptions: {
+ style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
+ },
+ navigationControlOptions: {
+ position: google.maps.ControlPosition.TOP_RIGHT, // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
+ style: google.maps.NavigationControlStyle.SMALL // ANDROID, DEFAULT, SMALL, ZOOM_PAN
+ },
+ scrollwheel: true
+ };
+ var pm_map = new google.maps.Map(document.querySelector(".gm-map"), myOptions);
+ google.maps.event.addListener(pm_map, "click", function() {
+ $(".gm-ancestor.person_box")
+ .removeClass("person_box")
+ .addClass("gm-ancestor-visited");
+ infowindow.close();
+ lastlinkid = null;
+ });
+ // create the map bounds
+ var bounds = new google.maps.LatLngBounds();
+ <?php
+ // add the points
+ $curgen = 1;
+ $count = 0;
+ $colored_line = [
+ '1' => '#FF0000',
+ '2' => '#0000FF',
+ '3' => '#00FF00',
+ '4' => '#FFFF00',
+ '5' => '#00FFFF',
+ '6' => '#FF00FF',
+ '7' => '#C0C0FF',
+ '8' => '#808000',
+ ];
+ $lat = [];
+ $lon = [];
+ $latlongval = [];
+ for ($i = 0; $i < $this->treesize; $i++) {
+ // moved up to grab the sex of the individuals
+ $person = $this->ancestors[$i];
+ if ($person) {
+ $name = $person->getFullName();
- $js = '
- // this variable will collect the html which will eventually be placed in the side bar
- var gm_ancestors_html = "";
- // arrays to hold copies of the markers and html used by the side bar
- // because the function closure trick doesnt work there
- var gmarkers = [];
- var index = 0;
- var lastlinkid;
- var infowindow = new google.maps.InfoWindow({});
- // === Create an associative array of GIcons()
- var gicons = [];
- gicons["1"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon1.png"
- }
- gicons["2"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon2.png"
- }
- gicons["2L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon2L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["2R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon2R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["2Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon2Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["2Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon2Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["3"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon3.png"
- }
- gicons["3L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon3L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["3R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon3R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["3Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon3Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["3Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon3Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["4"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon4.png"
- }
- gicons["4L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon4L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["4R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon4R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["4Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon4Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["4Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon4Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["5"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon5.png"
- }
- gicons["5L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon5L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["5R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon5R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["5Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon5Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["5Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon5Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["6"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon6.png"
- }
- gicons["6L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon6L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["6R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon6R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["6Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon6Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["6Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon6Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["7"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon7.png"
- }
- gicons["7L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon7L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["7R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon7R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["7Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon7Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["7Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon7Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- gicons["8"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon8.png"
- }
- gicons["8L"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon8L.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(28, 28) // Image anchor
- };
- gicons["8R"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon8R.png",
- size: new google.maps.Size(32, 32), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(4, 28) // Image anchor
- };
- gicons["8Ls"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon8Ls.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(22, 22) // Image anchor
- };
- gicons["8Rs"] = {
- url: WT_STATIC_URL+WT_MODULES_DIR+"googlemap/images/icon8Rs.png",
- size: new google.maps.Size(24, 24), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(2, 22) // Image anchor
- };
- // / A function to create the marker and set up the event window
- function createMarker(point, name, html, mhtml, icontype) {
- // Create a marker with the requested icon
- var marker = new google.maps.Marker({
- icon: gicons[icontype],
- map: pm_map,
- position: point,
- id: index,
- zIndex: 0
- });
- google.maps.event.addListener(marker, "click", function() {
- infowindow.close();
- infowindow.setContent(mhtml);
- infowindow.open(pm_map, marker);
- var el = jQuery(".gm-ancestor[data-marker=" + marker.id + "]");
- if(el.hasClass("person_box")) {
- el
- .removeClass("person_box")
- .addClass("gm-ancestor-visited");
- infowindow.close();
- } else {
- el
- .addClass("person_box")
- .removeClass("gm-ancestor-visited");
- }
- var anchor = infowindow.getAnchor();
- lastlinkid = anchor ? anchor.id : null;
- });
- // save the info we need to use later for the side bar
- gmarkers[index] = marker;
- gm_ancestors_html += "<div data-marker =" + index++ + " class=\"gm-ancestor\">" + html +"</div>";
+ // -- check to see if we have moved to the next generation
+ if ($i + 1 >= pow(2, $curgen)) {
+ $curgen++;
+ }
- return marker;
- };
- // create the map
- var myOptions = {
- zoom: 6,
- minZoom: ' . $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) . ',
- maxZoom: ' . $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) . ',
- center: new google.maps.LatLng(0, 0),
- mapTypeId: google.maps.MapTypeId.TERRAIN, // ROADMAP, SATELLITE, HYBRID, TERRAIN
- mapTypeControlOptions: {
- style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
- },
- navigationControlOptions: {
- position: google.maps.ControlPosition.TOP_RIGHT, // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
- style: google.maps.NavigationControlStyle.SMALL // ANDROID, DEFAULT, SMALL, ZOOM_PAN
- },
- scrollwheel: true
- };
- var pm_map = new google.maps.Map(document.querySelector(".gm-map"), myOptions);
- google.maps.event.addListener(pm_map, "click", function() {
- jQuery(".gm-ancestor.person_box")
- .removeClass("person_box")
- .addClass("gm-ancestor-visited");
- infowindow.close();
- lastlinkid = null;
- });
- // create the map bounds
- var bounds = new google.maps.LatLngBounds();';
- // add the points
- $curgen = 1;
- $count = 0;
- $colored_line = [
- '1' => '#FF0000',
- '2' => '#0000FF',
- '3' => '#00FF00',
- '4' => '#FFFF00',
- '5' => '#00FFFF',
- '6' => '#FF00FF',
- '7' => '#C0C0FF',
- '8' => '#808000',
- ];
- $lat = [];
- $lon = [];
- $latlongval = [];
- for ($i = 0; $i < $this->treesize; $i++) {
- // moved up to grab the sex of the individuals
- $person = $this->ancestors[$i];
- if ($person) {
- $name = $person->getFullName();
+ $relationship = FunctionsCharts::getSosaName($i + 1);
- // -- check to see if we have moved to the next generation
- if ($i + 1 >= pow(2, $curgen)) {
- $curgen++;
- }
+ // get thumbnail image
+ if ($person->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
+ $image = $person->displayImage();
+ } else {
+ $image = '';
+ }
- $relationship = FunctionsCharts::getSosaName($i + 1);
+ $event = '<img src="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/images/sq' . $curgen . '.png" width="10" height="10"> ';
+ $event .= '<strong>' . $relationship . '</strong>';
- // get thumbnail image
- if ($person->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
- $image = $person->displayImage();
- } else {
- $image = '';
- }
+ $birth = $person->getFirstFact('BIRT');
+ $data = Filter::escapeJs($image . '<div class="gm-ancestor-link">' . $event . ' <span><a href="' . $person->getHtmlUrl() . '">' . $name . '</a></span>');
+ $data .= $birth ? Filter::escapeJs($birth->summary()) : '';
+ $data .= '</div>';
- $event = '<img src="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/images/sq' . $curgen . '.png" width="10" height="10"> ';
- $event .= '<strong>' . $relationship . '</strong>';
+ $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
+ if ($latlongval[$i]) {
+ $lat[$i] = (float) strtr($latlongval[$i]->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
+ $lon[$i] = (float) strtr($latlongval[$i]->pl_long, ['E' => '', 'W' => '-', ',' => '.']);
+ if ($lat[$i] || $lon[$i]) {
+ $marker_number = $curgen;
+ $dups = 0;
+ for ($k = 0; $k < $i; $k++) {
+ if ($latlongval[$i] == $latlongval[$k]) {
+ $dups++;
+ switch ($dups) {
+ case 1:
+ $marker_number = $curgen . 'L';
+ break;
+ case 2:
+ $marker_number = $curgen . 'R';
+ break;
+ case 3:
+ $marker_number = $curgen . 'Ls';
+ break;
+ case 4:
+ $marker_number = $curgen . 'Rs';
+ break;
+ case 5: //adjust position where markers have same coodinates
+ default:
+ $marker_number = $curgen;
+ $lon[$i] += 0.0025;
+ $lat[$i] += 0.0025;
+ break;
+ }
+ }
+ }
- $birth = $person->getFirstFact('BIRT');
- $data = Filter::escapeJs($image . '<div class="gm-ancestor-link">' . $event . ' <span><a href="' . $person->getHtmlUrl() . '">' . $name . '</a></span>');
- $data .= $birth ? Filter::escapeJs($birth->summary()) : '';
- $data .= '</div>';
+ ?>
+ var point = new google.maps.LatLng(<?= $lat[$i] ?>, <?= $lon[$i] ?>);
+ var marker = createMarker(point, "<?= Filter::escapeJs($name) ?>", "<?= $data ?>", "<div class=\"gm-info-window\"><?= $data ?></div>", "<?= $marker_number ?>");
+ <?php
+ // Construct the polygon lines
+ $to_child = (intval(($i - 1) / 2)); // Draw a line from parent to child
+ if (array_key_exists($to_child, $lat) && $lat[$to_child] != 0 && $lon[$to_child] != 0) {
+ ?>
+ var linecolor;
+ var plines;
+ var lines = [
+ new google.maps.LatLng(<?= $lat[$i] ?>, <?= $lon[$i] ?>),
+ new google.maps.LatLng(<?= $lat[$to_child] ?>, <?= $lon[$to_child] ?>)
+ ];
+ linecolor = "<?= $colored_line[$curgen] ?>";
+ plines = new google.maps.Polygon({
+ paths: lines,
+ strokeColor: linecolor,
+ strokeOpacity: 0.8,
+ strokeWeight: 3,
+ fillColor: "#FF0000",
+ fillOpacity: 0.1
+ });
+ plines.setMap(pm_map);
+ <?php
+ }
+ // Extend and fit marker bounds
- $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
- if ($latlongval[$i]) {
- $lat[$i] = (float) strtr($latlongval[$i]->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
- $lon[$i] = (float) strtr($latlongval[$i]->pl_long, ['E' => '', 'W' => '-', ',' => '.']);
- if ($lat[$i] || $lon[$i]) {
- $marker_number = $curgen;
- $dups = 0;
- for ($k = 0; $k < $i; $k++) {
- if ($latlongval[$i] == $latlongval[$k]) {
- $dups++;
- switch ($dups) {
- case 1:
- $marker_number = $curgen . 'L';
- break;
- case 2:
- $marker_number = $curgen . 'R';
- break;
- case 3:
- $marker_number = $curgen . 'Ls';
- break;
- case 4:
- $marker_number = $curgen . 'Rs';
- break;
- case 5: //adjust position where markers have same coodinates
- default:
- $marker_number = $curgen;
- $lon[$i] += 0.0025;
- $lat[$i] += 0.0025;
- break;
+ ?>
+ bounds.extend(point);
+ <?php
+ $count++;
}
}
+ } else {
+ $latlongval[$i] = null;
}
-
- $js .= 'var point = new google.maps.LatLng(' . $lat[$i] . ',' . $lon[$i] . ');';
- $js .= 'var marker = createMarker(point, "' . Filter::escapeJs($name) . '","' . $data . '", "';
- $js .= '<div class=\"gm-info-window\">' . $data . '</div>", "' . $marker_number . '");';
- // Construct the polygon lines
- $to_child = (intval(($i - 1) / 2)); // Draw a line from parent to child
- if (array_key_exists($to_child, $lat) && $lat[$to_child] != 0 && $lon[$to_child] != 0) {
- $js .= '
- var linecolor;
- var plines;
- var lines = [new google.maps.LatLng(' . $lat[$i] . ',' . $lon[$i] . '),
- new google.maps.LatLng(' . $lat[$to_child] . ',' . $lon[$to_child] . ')];
- linecolor = "' . $colored_line[$curgen] . '";
- plines = new google.maps.Polygon({
- paths: lines,
- strokeColor: linecolor,
- strokeOpacity: 0.8,
- strokeWeight: 3,
- fillColor: "#FF0000",
- fillOpacity: 0.1
- });
- plines.setMap(pm_map);';
- }
- // Extend and fit marker bounds
-
- $js .= 'bounds.extend(point);';
- $count++;
}
- }
- } else {
- $latlongval[$i] = null;
- }
- }
- $js .= '
- pm_map.setCenter(bounds.getCenter());
- pm_map.fitBounds(bounds);
- google.maps.event.addListenerOnce(pm_map, "bounds_changed", function(event) {
- var maxZoom = ' . $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) . ';
- if (this.getZoom() > maxZoom) {
- this.setZoom(maxZoom);
- }
- });
+ ?>
+ pm_map.setCenter(bounds.getCenter());
+ pm_map.fitBounds(bounds);
+ google.maps.event.addListenerOnce(pm_map, "bounds_changed", function(event) {
+ var maxZoom = <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
+ if (this.getZoom() > maxZoom) {
+ this.setZoom(maxZoom);
+ }
+ });
- // Close the sidebar highlight when the infowindow is closed
- google.maps.event.addListener(infowindow, "closeclick", function() {
- jQuery(".gm-ancestor[data-marker=" + lastlinkid + "]").toggleClass("gm-ancestor-visited person_box");
- lastlinkid = null;
- });
- // put the assembled gm_ancestors_html contents into the gm-ancestors div
- document.querySelector(".gm-ancestors").innerHTML = gm_ancestors_html;
+ // Close the sidebar highlight when the infowindow is closed
+ google.maps.event.addListener(infowindow, "closeclick", function() {
+ $(".gm-ancestor[data-marker=" + lastlinkid + "]").toggleClass("gm-ancestor-visited person_box");
+ lastlinkid = null;
+ });
+ // put the assembled gm_ancestors_html contents into the gm-ancestors div
+ document.querySelector(".gm-ancestors").innerHTML = gm_ancestors_html;
- jQuery(".gm-ancestor-link")
- .on("click", "a", function(e) {
- e.stopPropagation();
- })
- .on("click", function(e) {
- if (lastlinkid != null) {
- jQuery(".gm-ancestor[data-marker=" + lastlinkid + "]").toggleClass("person_box gm-ancestor-visited");
+ $(".gm-ancestor-link")
+ .on("click", "a", function(e) {
+ e.stopPropagation();
+ })
+ .on("click", function(e) {
+ if (lastlinkid !== null) {
+ $(".gm-ancestor[data-marker=" + lastlinkid + "]").toggleClass("person_box gm-ancestor-visited");
+ }
+ var target = $(this).closest(".gm-ancestor").data("marker");
+ google.maps.event.trigger(gmarkers[target], "click");
+ });
}
- var target = jQuery(this).closest(".gm-ancestor").data("marker");
- google.maps.event.trigger(gmarkers[target], "click");
- });
- ';
-
- return $js;
- }
-
- /**
- * Check places for missing data, etc.
- */
- private function adminPlaceCheck() {
- global $WT_TREE;
-
- $gedcom_id = Filter::get('gedcom_id', null, $WT_TREE->getTreeId());
- $country = Filter::get('country', '.+', 'XYZ');
- $state = Filter::get('state', '.+', 'XYZ');
- $matching = Filter::getBool('matching');
-
- $controller = new PageController;
- $controller
- ->restrictAccess(Auth::isAdmin())
- ->setPageTitle(I18N::translate('Google Maps™'))
- ->pageHeader();
-
- ?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel') ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration') ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle() ?></li>
- </ol>
-
- <ul class="nav nav-tabs nav-justified" role="tablist">
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_config" role="tab">
- <?php echo I18N::translate('Google Maps™ preferences') ?>
- </a>
- </li>
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_places">
- <?php echo I18N::translate('Geographic data') ?>
- </a>
- </li>
- <li role="presentation" class="active">
- <a href="#">
- <?php echo I18N::translate('Place check') ?>
- </a>
- </li>
- </ul>
- <?php
-
- echo '<h2>', I18N::translate('Place check'), '</h2>';
-
- // User options
- $rows = Database::prepare("SELECT pl_id, pl_place FROM `##placelocation` WHERE pl_level=0 ORDER BY pl_place")->fetchAssoc();
-
- echo '<form name="placecheck" class="form form-inline">';
- echo '<input type="hidden" name="mod" value="', $this->getName(), '">';
- echo '<input type="hidden" name="mod_action" value="admin_placecheck">';
- echo '<div class="form-group">';
- echo '<label for="gedcom_id">', I18N::translate('Family tree'), '</label> ';
- echo FunctionsEdit::selectEditControl('gedcom_id', Tree::getIdList(), null, $gedcom_id, ' onchange="this.form.submit();" class="form-control"'), ' ';
- echo '<label for="country">', I18N::translate('Country'), '</label> ';
- echo '<select id="country" name="country" onchange="this.form.submit();" class="form-control"> ';
- echo '<option value="XYZ">', I18N::translate('All'), '</option>';
- foreach ($rows as $id => $place) {
- echo '<option value="', Filter::escapeHtml($place), '" ';
- if ($place == $country) {
- echo 'selected';
- $par_id = $id;
- }
- echo '>', Filter::escapeHtml($place), '</option>';
- }
- echo '</select> ';
- if ($country != 'XYZ') {
- echo '<label for="state">', /* I18N: Part of a country, state/region/county */ I18N::translate('Subdivision'), '</label> ';
- echo '<select name="state" onchange="this.form.submit();" class="form-control">';
- echo '<option value="XYZ">', I18N::translate('All'), '</option>';
- $places = Database::prepare("SELECT pl_place FROM `##placelocation` WHERE pl_parent_id=? ORDER BY pl_place")
- ->execute([$par_id])
- ->fetchOneColumn();
- foreach ($places as $place) {
- echo '<option value="', Filter::escapeHtml($place), '" ', $place == $state ? 'selected' : '', '>', Filter::escapeHtml($place), '</option>';
- }
- echo '</select> ';
- }
- echo '<div class="checkbox-inline">';
- echo '<label for="matching">';
- echo '<input type="checkbox" name="matching" value="1" onchange="this.form.submit();" ', ($matching ? 'checked' : ''), '>';
- echo I18N::translate('Include fully matched places');
- echo '</label>';
- echo '</div></div>';
- echo '</form>';
- echo '<hr>';
-
- //Select all '2 PLAC ' tags in the file and create array
- $place_list = [];
- $ged_data = Database::prepare("SELECT i_gedcom FROM `##individuals` WHERE i_gedcom LIKE ? AND i_file=?")
- ->execute(["%\n2 PLAC %", $gedcom_id])
- ->fetchOneColumn();
- foreach ($ged_data as $ged_datum) {
- preg_match_all('/\n2 PLAC (.+)/', $ged_datum, $matches);
- foreach ($matches[1] as $match) {
- $place_list[$match] = true;
- }
- }
- $ged_data = Database::prepare("SELECT f_gedcom FROM `##families` WHERE f_gedcom LIKE ? AND f_file=?")
- ->execute(["%\n2 PLAC %", $gedcom_id])
- ->fetchOneColumn();
- foreach ($ged_data as $ged_datum) {
- preg_match_all('/\n2 PLAC (.+)/', $ged_datum, $matches);
- foreach ($matches[1] as $match) {
- $place_list[$match] = true;
- }
- }
- // Unique list of places
- $place_list = array_keys($place_list);
+ </script>
+ <script src="<?= $this->googleMapsScript() ?>&amp;callback=initialiZePedigreeMap"></script>
+ <?php
- // Apply_filter
- if ($country == 'XYZ') {
- $filter = '.*$';
- } else {
- $filter = preg_quote($country) . '$';
- if ($state != 'XYZ') {
- $filter = preg_quote($state) . ', ' . $filter;
- }
+ return;
}
- $place_list = preg_grep('/' . $filter . '/', $place_list);
- //sort the array, limit to unique values, and count them
- usort($place_list, '\Fisharebest\Webtrees\I18N::strcasecmp');
- $i = count($place_list);
+ $controller
+ ->setPageTitle(/* I18N: %s is an individual’s name */ I18N::translate('Pedigree map of %s', $controller->root->getFullName()))
+ /* prepending the module css in the page head allows the theme to over-ride it*/
+ ->addInlineJavascript('$("head").prepend(\'<link type="text/css" href ="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/css/wt_v3_googlemap.css" rel="stylesheet">\');')
+ ->addInlineJavascript('$(".wt-page-content").load(document.location + "&ajax=1");')
+ ->pageHeader();
+?>
- //calculate maximum no. of levels to display
- $x = 0;
- $max = 0;
- while ($x < $i) {
- $levels = explode(',', $place_list[$x]);
- $parts = count($levels);
- if ($parts > $max) {
- $max = $parts;
- }
- $x++; }
- $x = 0;
+ <div id="pedigreemap-page">
+ <h2><?= $controller->getPageTitle() ?></h2>
- //scripts for edit, add and refresh
- ?>
- <script>
- function edit_place_location(placeid) {
- window.open('module.php?mod=googlemap&mod_action=places_edit&action=update&placeid='+placeid, '_blank', gmap_window_specs);
- return false;
- }
+ <form class="wt-page-options wt-page-options-pedigree-map hidden-print">
+ <input type="hidden" name="ged" value="<?= $WT_TREE->getNameHtml() ?>">
+ <input type="hidden" name="mod" value="googlemap">
+ <input type="hidden" name="mod_action" value="pedigree_map">
- function add_place_location(placeid) {
- window.open('module.php?mod=googlemap&mod_action=places_edit&action=add&placeid='+placeid, '_blank', gmap_window_specs);
- return false;
- }
- </script>
- <?php
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label wt-page-options-label" for="rootid">
+ <?= I18N::translate('Individual') ?>
+ </label>
+ <div class="col-sm-9 wt-page-options-value">
+ <?= FunctionsEdit::formControlIndividual($controller->root, ['id' => 'rootid', 'name' => 'rootid']) ?>
+ </div>
+ </div>
- //start to produce the display table
- echo '<table class="table table-bordered table-condensed table-hover"><thead><tr>';
- echo '<th rowspan="3">', I18N::translate('Place'), '</th>';
- echo '<th colspan="', $max * 3, '">', I18N::translate('Geographic data'), '</th></tr>';
- echo '<tr>';
- for ($cols = 0; $cols < $max; ++$cols) {
- if ($cols == 0) {
- echo '<th colspan="3">', I18N::translate('Country'), '</th>';
- } else {
- echo '<th colspan="3">', I18N::translate('Level'), ' ', $cols + 1, '</th>';
- }
- }
- echo '</tr><tr>';
- for ($cols = 0; $cols < $max; ++$cols) {
- echo '<th>', GedcomTag::getLabel('PLAC'), '</th>';
- echo '<th>', I18N::translate('Latitude'), '</th>';
- echo '<th>', I18N::translate('Longitude'), '</th>';
- }
- echo '</tr></thead><tbody>';
- $countrows = 0;
- $matched = [];
- while ($x < $i) {
- $placestr = '';
- $levels = explode(', ', $place_list[$x]);
- $parts = count($levels);
- $levels = array_reverse($levels);
- $placestr .= '<a href="placelist.php?action=show';
- foreach ($levels as $pindex => $ppart) {
- $placestr .= '&amp;parent[' . $pindex . ']=' . urlencode($ppart);
- }
- $placestr .= '">' . $place_list[$x] . '</a>';
- $gedplace = '<tr><td>' . $placestr . '</td>';
- $z = 0;
- $id = 0;
- $level = 0;
- $matched[$x] = 0; // used to exclude places where the gedcom place is matched at all levels
- $mapstr_edit = '<a href="#" dir="auto" onclick="edit_place_location(\'';
- $mapstr_add = '<a href="#" dir="auto" onclick="add_place_location(\'';
- $mapstr3 = '';
- $mapstr4 = '';
- $mapstr5 = '\')" title=\'';
- $mapstr6 = '\' >';
- $mapstr7 = '\')">';
- $mapstr8 = '</a>';
- $plac = [];
- $lati = [];
- $long = [];
- while ($z < $parts) {
- if ($levels[$z] == '') {
- $levels[$z] = 'unknown'; // GoogleMap module uses "unknown" while GEDCOM uses , ,
- }
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label wt-page-options-label" for="PEDIGREE_GENERATIONS">
+ <?= I18N::translate('Generations') ?>
+ </label>
+ <div class="col-sm-9 wt-page-options-value">
+ <?= Bootstrap4::select(FunctionsEdit::numericOptions(range(2, $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS'))), $generations, ['id' => 'PEDIGREE_GENERATIONS', 'name' => 'PEDIGREE_GENERATIONS']) ?>
+ </div>
+ </div>
- $placelist = $this->createPossiblePlaceNames($levels[$z], $z + 1); // add the necessary prefix/postfix values to the place name
- foreach ($placelist as $key => $placename) {
- $row =
- Database::prepare("SELECT pl_id, pl_place, pl_long, pl_lati, pl_zoom FROM `##placelocation` WHERE pl_level=? AND pl_parent_id=? AND pl_place LIKE ? ORDER BY pl_place")
- ->execute([$z, $id, $placename])
- ->fetchOneRow(PDO::FETCH_ASSOC);
- if (!empty($row['pl_id'])) {
- $row['pl_placerequested'] = $levels[$z]; // keep the actual place name that was requested so we can display that instead of what is in the db
- break;
- }
- }
- if ($row['pl_id'] != '') {
- $id = $row['pl_id'];
- }
+ <div class="row form-group">
+ <div class="col-sm-3 wt-page-options-label"></div>
+ <div class="col-sm-9 wt-page-options-value">
+ <input class="btn btn-primary" type="submit" value="<?= /* I18N: A button label. */ I18N::translate('view') ?>">
+ </div>
+ </div>
+ </form>
- if ($row['pl_place'] != '') {
- $placestr2 = $mapstr_edit . $id . '&amp;level=' . $level . $mapstr3 . $mapstr5 . I18N::translate('Zoom') . ' ' . $row['pl_zoom'] . $mapstr6 . $row['pl_placerequested'] . $mapstr8;
- if ($row['pl_place'] === 'unknown') {
- $matched[$x]++;
- }
- } else {
- if ($levels[$z] === 'unknown') {
- $placestr2 = $mapstr_add . $id . '&amp;level=' . $level . $mapstr3 . $mapstr7 . '<strong>' . I18N::translate('unknown') . '</strong>' . $mapstr8; $matched[$x]++;
- } else {
- $placestr2 = $mapstr_add . $id . '&amp;place_name=' . urlencode($levels[$z]) . '&amp;level=' . $level . $mapstr3 . $mapstr7 . '<span class="danger">' . $levels[$z] . '</span>' . $mapstr8; $matched[$x]++;
- }
- }
- $plac[$z] = '<td>' . $placestr2 . '</td>';
- if ($row['pl_lati'] == '0' && $row['pl_long'] == '0') {
- $lati[$z] = '<td class="danger">0</td>';
- } elseif ($row['pl_lati'] != '') {
- $lati[$z] = '<td>' . $row['pl_lati'] . '</td>';
- } else {
- $lati[$z] = '<td class="danger"><i class="fa fa-warning"></i></td>';
- $matched[$x]++;
- }
- if ($row['pl_lati'] == '0' && $row['pl_long'] == '0') {
- $long[$z] = '<td class="danger">0</td>';
- } elseif ($row['pl_long'] != '') {
- $long[$z] = '<td>' . $row['pl_long'] . '</td>';
- } else {
- $long[$z] = '<td class="danger"><i class="fa fa-warning"></i></td>';
- $matched[$x]++;
- }
- $level++;
- $mapstr3 = $mapstr3 . '&amp;parent[' . $z . ']=' . Filter::escapeJs($row['pl_placerequested']);
- $mapstr4 = $mapstr4 . '&amp;parent[' . $z . ']=' . Filter::escapeJs($levels[$z]);
- $z++;
- }
- if ($matching) {
- $matched[$x] = 1;
- }
- if ($matched[$x] != 0) {
- echo $gedplace;
- $z = 0;
- while ($z < $max) {
- if ($z < $parts) {
- echo $plac[$z];
- echo $lati[$z];
- echo $long[$z];
- } else {
- echo '<td></td>';
- echo '<td></td>';
- echo '<td></td>';
- }
- $z++;
- }
- echo '</tr>';
- $countrows++;
- }
- $x++;
- }
- echo '</tbody>';
- echo '<tfoot>';
- echo '<tr>';
- echo '<td colspan="', (1 + 3 * $max), '">', /* I18N: A count of places */ I18N::translate('Total places: %s', I18N::number($countrows)), '</td>';
- echo '</tr>';
- echo '</tfoot>';
- echo '</table>';
+ <div class="wt-ajax-load wt-page-content"></div>
+ <?php
}
/**
@@ -1661,9 +1134,9 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
private function createPossiblePlaceNames($placename, $level) {
$retlist = [];
if ($level <= 9) {
- $retlist = $this->removePrefixAndSuffixFromPlaceName($this->getSetting('GM_PREFIX_' . $level), $this->getSetting('GM_POSTFIX_' . $level), $placename, $retlist); // Remove both
- $retlist = $this->removePrefixFromPlaceName($this->getSetting('GM_PREFIX_' . $level), $placename, $retlist); // Remove prefix
- $retlist = $this->removeSuffixFromPlaceName($this->getSetting('GM_POSTFIX_' . $level), $placename, $retlist); // Remove suffix
+ $retlist = $this->removePrefixAndSuffixFromPlaceName($this->getPreference('GM_PREFIX_' . $level), $this->getPreference('GM_POSTFIX_' . $level), $placename, $retlist); // Remove both
+ $retlist = $this->removePrefixFromPlaceName($this->getPreference('GM_PREFIX_' . $level), $placename, $retlist); // Remove prefix
+ $retlist = $this->removeSuffixFromPlaceName($this->getPreference('GM_POSTFIX_' . $level), $placename, $retlist); // Remove suffix
}
$retlist[] = $placename; // Exact
@@ -1766,7 +1239,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
* @return string
*/
private function buildIndividualMap(Individual $indi) {
- $GM_MAX_ZOOM = $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT);
+ $GM_MAX_ZOOM = $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT);
$facts = $indi->getFacts();
foreach ($indi->getSpouseFamilies() as $family) {
$facts = array_merge($facts, $family->getFacts());
@@ -1944,10 +1417,10 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
// Create the map and mapOptions
var mapOptions = {
zoom: 7,
- minZoom: <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT); ?>,
- maxZoom: <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT); ?>,
+ minZoom: <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>,
+ maxZoom: <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>,
center: map_center,
- mapTypeId: google.maps.MapTypeId.<?php echo $this->getSetting('GM_MAP_TYPE') ?>,
+ mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
},
@@ -1968,24 +1441,24 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
// Add the markers to the map
// Group the markers by location
- var locations = <?php echo json_encode($unique_places) ?>;
+ var locations = <?= json_encode($unique_places) ?>;
// Set the Marker bounds
var bounds = new google.maps.LatLngBounds();
- var zoomLevel = <?php echo $GM_MAX_ZOOM ?>;
+ var zoomLevel = <?= $GM_MAX_ZOOM ?>;
jQuery.each(locations, function(index, location) {
var point = new google.maps.LatLng(location.lat, location.lng); // Place Latitude, Longitude
var html =
- '<div class="gm-info-window">' +
- '<div class="gm-info-window-header">' + location.place + '</div>' +
- '<ul class="gm-tabs">' +
- '<li class="gm-tab gm-tab-active" id="gm-tab-events"><a href="#"><?php echo I18N::translate('Events') ?></a></li>' +
- '</ul>' +
- '<div class="gm-panes">' +
- '<div class="gm-pane" id="gm-pane-events">' + location.events + '</div>' +
- '</div>' +
- '</div>';
+ '<div class="gm-info-window">' +
+ '<div class="gm-info-window-header">' + location.place + '</div>' +
+ '<ul class="gm-tabs">' +
+ '<li class="gm-tab gm-tab-active" id="gm-tab-events"><a href="#"><?= I18N::translate('Events') ?></a></li>' +
+ '</ul>' +
+ '<div class="gm-panes">' +
+ '<div class="gm-pane" id="gm-pane-events">' + location.events + '</div>' +
+ '</div>' +
+ '</div>';
createMarker(point, html, location.tooltip, location.pl_icon);
bounds.extend(point);
@@ -2155,29 +1628,19 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
echo '<table style="margin:auto; border-collapse: collapse;">';
echo '<tr style="vertical-align:top;"><td>';
- echo '<div id="place_map" style="border:1px solid gray; width:', $this->getSetting('GM_PH_XSIZE'), 'px; height:', $this->getSetting('GM_PH_YSIZE'), 'px; ';
- echo '"><i class="icon-loading-large"></i></div>';
+ echo '<div id="gm-hierarchy-map" class="wt-ajax-load"></div>';
echo '<script src="', $this->googleMapsScript(), '"></script>';
$plzoom = $latlng['pl_zoom']; // Map zoom level
if (Auth::isAdmin()) {
- $placecheck_url = 'module.php?mod=googlemap&amp;mod_action=admin_placecheck';
- if ($parent && isset($parent[0])) {
- $placecheck_url .= '&amp;country=' . $parent[0];
- if (isset($parent[1])) {
- $placecheck_url .= '&amp;state=' . $parent[1];
- }
- }
$adminplaces_url = 'module.php?mod=googlemap&amp;mod_action=admin_places';
if ($latlng && isset($latlng['pl_id'])) {
$adminplaces_url .= '&amp;parent=' . $latlng['pl_id'];
}
$update_places_url = 'admin_trees_places.php?ged=' . $WT_TREE->getNameHtml() . '&amp;search=' . urlencode(implode(', ', array_reverse($parent)));
echo '<div class="gm-options">';
- echo '<a href="module.php?mod=googlemap&amp;mod_action=admin_config">', I18N::translate('Google Maps™ preferences'), '</a>';
- echo ' | <a href="' . $adminplaces_url . '">' . I18N::translate('Geographic data') . '</a>';
- echo ' | <a href="' . $placecheck_url . '">' . I18N::translate('Place check') . '</a>';
+ echo '<a href="' . $adminplaces_url . '">' . I18N::translate('Geographic data') . '</a>';
echo ' | <a href="' . $update_places_url . '">' . I18N::translate('Update place names') . '</a>';
echo '</div>';
}
@@ -2216,43 +1679,43 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
/**
* Print the flags and markers.
*
- * @param string[] $place2
+ * @param stdClass $place2
* @param int $level
* @param string[] $parent
* @param int $levelm
* @param string $linklevels
*/
- private function printGoogleMapMarkers($place2, $level, $parent, $levelm, $linklevels) {
+ private function printGoogleMapMarkers(stdClass $place2, $level, $parent, $levelm, $linklevels) {
echo 'var icon_url = null;';
- if (!$place2['lati'] || !$place2['long']) {
+ if (!$place2->pl_lati || !$place2->pl_long) {
echo 'var icon_url ="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/images/marker_yellow.png";';
echo 'var point = new google.maps.LatLng(0, 0);';
echo 'var marker = createMarker(point, "<div style=\"width: 250px;\"><a href=\"?action=find', $linklevels, '&amp;parent[' . $level . ']=';
- if ($place2['place'] == 'Unknown') {
+ if ($place2->pl_place == 'Unknown') {
echo '\"><br>';
} else {
- echo addslashes($place2['place']), '\"><br>';
+ echo addslashes($place2->pl_place), '\"><br>';
}
- if (($place2['icon'] !== null) && ($place2['icon'] !== '')) {
- echo '<img src=\"', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2['icon'], '\">&nbsp;&nbsp;';
+ if ($place2->pl_icon !== null && $place2->pl_icon !== '') {
+ echo '<img src=\"', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2->pl_icon, '\">&nbsp;&nbsp;';
}
- if ($place2['place'] == 'Unknown') {
+ if ($place2->pl_place == 'Unknown') {
echo I18N::translate('unknown');
} else {
- echo addslashes($place2['place']);
+ echo addslashes($place2->pl_place);
}
echo '</a>';
- $parent[$level] = $place2['place'];
+ $parent[$level] = $place2->pl_place;
$this->printHowManyPeople($level + 1, $parent);
echo '<br>', I18N::translate('This place has no coordinates');
if (Auth::isAdmin()) {
echo '<br><a href=\"module.php?mod=googlemap&amp;mod_action=admin_places&amp;parent=', $levelm, '&amp;display=inactive\">', I18N::translate('Geographic data'), '</a>';
}
- echo '</div>", icon_url, "', str_replace(['&lrm;', '&rlm;'], [WT_UTF8_LRM, WT_UTF8_RLM], addslashes($place2['place'])), '");';
+ echo '</div>", icon_url, "', str_replace(['&lrm;', '&rlm;'], [WT_UTF8_LRM, WT_UTF8_RLM], addslashes($place2->pl_place)), '");';
} else {
- $lati = strtr($place2['lati'], ['N' => '', 'S' => '-', ',' => '.']);
- $long = strtr($place2['long'], ['E' => '', 'W' => '-', ',' => '.']);
+ $lati = strtr($place2->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
+ $long = strtr($place2->pl_long, ['E' => '', 'W' => '-', ',' => '.']);
//delete leading zero
if ($lati >= 0) {
$lati = abs($lati);
@@ -2265,28 +1728,28 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
$long = '-' . abs($long);
}
- if ($place2['icon'] !== null && $place2['icon'] !== '' && $this->getSetting('GM_PH_MARKER') === 'G_FLAG') {
- echo 'icon_url = "', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2['icon'], '";';
+ if ($place2->pl_icon !== null && $place2->pl_icon !== '' && $this->getPreference('GM_PH_MARKER') === 'G_FLAG') {
+ echo 'icon_url = "', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2->pl_icon, '";';
}
echo 'var point = new google.maps.LatLng(', $lati, ', ', $long, ');';
echo 'var marker = createMarker(point, "<div style=\"width: 250px;\"><a href=\"?action=find', $linklevels;
echo '&amp;parent[', $level, ']=';
- if ($place2['place'] !== 'Unknown') {
- echo Filter::escapeJs($place2['place']);
+ if ($place2->pl_place !== 'Unknown') {
+ echo Filter::escapeJs($place2->pl_place);
}
echo '\"><br>';
- if ($place2['icon'] !== null && $place2['icon'] !== '') {
- echo '<img src=\"', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2['icon'], '\">&nbsp;&nbsp;';
+ if ($place2->pl_icon !== null && $place2->pl_icon !== '') {
+ echo '<img src=\"', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place2->pl_icon, '\">&nbsp;&nbsp;';
}
- if ($place2['place'] === 'Unknown') {
+ if ($place2->pl_place === 'Unknown') {
echo I18N::translate('unknown');
} else {
- echo Filter::escapeJs($place2['place']);
+ echo Filter::escapeJs($place2->pl_place);
}
echo '</a>';
- $parent[$level] = $place2['place'];
+ $parent[$level] = $place2->pl_place;
$this->printHowManyPeople($level + 1, $parent);
- echo '</div>", icon_url, "', Filter::escapeJs($place2['place']), '");';
+ echo '</div>", icon_url, "', Filter::escapeJs($place2->pl_place), '");';
}
}
@@ -2303,7 +1766,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
global $plzoom, $controller;
$controller->addInlineJavascript('
- jQuery("head").append(\'<link rel="stylesheet" type="text/css" href="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/css/wt_v3_googlemap.css" />\');
+ $("head").append(\'<link rel="stylesheet" type="text/css" href="' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/css/wt_v3_googlemap.css" />\');
var numMarkers = "' . $numfound . '";
var mapLevel = "' . $level . '";
var placezoom = "' . $plzoom . '";
@@ -2321,11 +1784,11 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
// Create the map and mapOptions
var mapOptions = {
- minZoom: ' . $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) . ',
- maxZoom: ' . $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) . ',
+ minZoom: ' . $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) . ',
+ maxZoom: ' . $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) . ',
zoom: 8,
center: map_center,
- mapTypeId: google.maps.MapTypeId.' . $this->getSetting('GM_MAP_TYPE') . ',
+ mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
},
@@ -2336,7 +1799,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
},
scrollwheel: true
};
- map = new google.maps.Map(document.getElementById("place_map"), mapOptions);
+ map = new google.maps.Map(document.getElementById("gm-hierarchy-map"), mapOptions);
// Close any infowindow when map is clicked
google.maps.event.addListener(map, "click", function() {
@@ -2365,7 +1828,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
var iconImage = {
url: icon,
size: new google.maps.Size(20, 34),
- origin: new google.maps.Point(0,0),
+ origin: new google.maps.Point(0,0),
anchor: new google.maps.Point(9, 34)
};
}
@@ -2416,11 +1879,11 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
if ($numfound == 0 && $level > 0) {
// show the current place on the map
- $place = Database::prepare("SELECT pl_id AS place_id, pl_place AS place, pl_lati AS lati, pl_long AS `long`, pl_zoom AS zoom, pl_icon AS icon FROM `##placelocation` WHERE pl_id=?")
+ $place = Database::prepare("SELECT * FROM `##placelocation` WHERE pl_id = ?")
->execute([$levelm])
- ->fetch(PDO::FETCH_ASSOC);
+ ->fetchOneRow();
- if ($place) {
+ if ($place !== null) {
// re-calculate the hierarchy information required to display the current place
$thisloc = $parent;
array_pop($thisloc);
@@ -2453,13 +1916,12 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
// note: this implode/array_fill code generates one '?' for each entry in the $placeidlist array
$placelist =
Database::prepare(
- "SELECT pl_id as place_id, pl_place as place, pl_lati as lati, pl_long as `long`, pl_zoom as zoom, pl_icon as icon" .
- " FROM `##placelocation` WHERE pl_id IN (" . implode(',', array_fill(0, count($placeidlist), '?')) . ')'
+ "SELECT * FROM `##placelocation` WHERE pl_id IN (" . implode(',', array_fill(0, count($placeidlist), '?')) . ')'
)->execute($placeidlist)
- ->fetchAll(PDO::FETCH_ASSOC);
+ ->fetchAll();
foreach ($placelist as $place) {
- $this->printGoogleMapMarkers($place, $level, $parent, $place['place_id'], $linklevels);
+ $this->printGoogleMapMarkers($place, $level, $parent, $place->pl_id, $linklevels);
}
}
$controller->addInlineJavascript(ob_get_clean());
@@ -2508,6 +1970,9 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
/**
* Find all of the places in the hierarchy
*
+ * NOTE: the "inactive" filter ignores the hierarchy, so that "Paris, France"
+ * will match "Paris, Texas, United States". A fully accurate match would be slow.
+ *
* @param int $parent_id
* @param bool $inactive
*
@@ -2516,7 +1981,7 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
private function getPlaceListLocation($parent_id, $inactive = false) {
if ($inactive) {
$rows = Database::prepare(
- "SELECT pl_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" .
+ "SELECT pl_id, pl_parent_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" .
" FROM `##placelocation`" .
" WHERE pl_parent_id = :parent_id" .
" ORDER BY pl_place COLLATE :collation"
@@ -2526,9 +1991,9 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
])->fetchAll();
} else {
$rows = Database::prepare(
- "SELECT DISTINCT pl_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" .
+ "SELECT DISTINCT pl_id, pl_parent_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" .
" FROM `##placelocation`" .
- " INNER JOIN `##places` ON `##placelocation`.pl_place=`##places`.p_place" .
+ " JOIN `##places` ON `##placelocation`.pl_place = `##places`.p_place" .
" WHERE pl_parent_id = :parent_id" .
" ORDER BY pl_place COLLATE :collation"
)->execute([
@@ -2539,13 +2004,45 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
$placelist = [];
foreach ($rows as $row) {
+ // Find/count places without co-ordinates
+ $children =
+ Database::prepare(
+ "SELECT SQL_CACHE COUNT(*) AS total, SUM(" .
+ " p1.pl_place IS NOT NULL AND IFNULL(p1.pl_lati, '') IN ('N0', '') AND IFNULL(p1.pl_long, '') IN ('E0', '') OR " .
+ " p2.pl_place IS NOT NULL AND IFNULL(p2.pl_lati, '') IN ('N0', '') AND IFNULL(p2.pl_long, '') IN ('E0', '') OR " .
+ " p3.pl_place IS NOT NULL AND IFNULL(p3.pl_lati, '') IN ('N0', '') AND IFNULL(p3.pl_long, '') IN ('E0', '') OR " .
+ " p4.pl_place IS NOT NULL AND IFNULL(p4.pl_lati, '') IN ('N0', '') AND IFNULL(p4.pl_long, '') IN ('E0', '') OR " .
+ " p5.pl_place IS NOT NULL AND IFNULL(p5.pl_lati, '') IN ('N0', '') AND IFNULL(p5.pl_long, '') IN ('E0', '') OR " .
+ " p6.pl_place IS NOT NULL AND IFNULL(p6.pl_lati, '') IN ('N0', '') AND IFNULL(p6.pl_long, '') IN ('E0', '') OR " .
+ " p7.pl_place IS NOT NULL AND IFNULL(p7.pl_lati, '') IN ('N0', '') AND IFNULL(p7.pl_long, '') IN ('E0', '') OR " .
+ " p8.pl_place IS NOT NULL AND IFNULL(p8.pl_lati, '') IN ('N0', '') AND IFNULL(p8.pl_long, '') IN ('E0', '') OR " .
+ " p9.pl_place IS NOT NULL AND IFNULL(p9.pl_lati, '') IN ('N0', '') AND IFNULL(p9.pl_long, '') IN ('E0', '')) AS missing" .
+ " FROM `##placelocation` AS p1" .
+ " LEFT JOIN `##placelocation` AS p2 ON (p2.pl_parent_id = p1.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p3 ON (p3.pl_parent_id = p2.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p4 ON (p4.pl_parent_id = p3.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p5 ON (p5.pl_parent_id = p4.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p6 ON (p6.pl_parent_id = p5.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p7 ON (p7.pl_parent_id = p6.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p8 ON (p8.pl_parent_id = p7.pl_id)" .
+ " LEFT JOIN `##placelocation` AS p9 ON (p9.pl_parent_id = p8.pl_id)" .
+ " WHERE p1.pl_parent_id = :parent_id"
+ )
+ ->execute([
+ 'parent_id' => $row->pl_id,
+ ])->fetchOneRow();
+
$placelist[] = [
- 'place_id' => $row->pl_id,
- 'place' => $row->pl_place,
- 'lati' => $row->pl_lati,
- 'long' => $row->pl_long,
- 'zoom' => $row->pl_zoom,
- 'icon' => $row->pl_icon,
+ 'place_id' => (int) $row->pl_id,
+ 'parent_id' => (int) $row->pl_parent_id,
+ 'place' => $row->pl_place,
+ 'lati' => $row->pl_lati,
+ 'long' => $row->pl_long,
+ 'zoom' => (int) $row->pl_zoom,
+ 'icon' => $row->pl_icon,
+ 'is_empty' => ($row->pl_lati === null || $row->pl_lati === 'N0') && ($row->pl_long === null || $row->pl_long === 'E0'),
+ 'children' => (int) $children->total,
+ 'missing' => (int) $children->missing,
];
}
@@ -2609,616 +2106,961 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
}
/**
- * Edit places.
+ * Show a form with options to upload a CSV file
*/
- private function placesEdit() {
- $GM_MAX_ZOOM = $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT);
+ private function adminUploadForm() {
+ $parent_id = (int) Filter::get('parent_id');
+ $inactive = (int) Filter::get('inactive');
- $action = Filter::post('action', null, Filter::get('action'));
- $placeid = Filter::post('placeid', null, Filter::get('placeid'));
- $place_name = Filter::post('place_name', null, Filter::get('place_name'));
- $placeid = (int) $placeid; // Convert empty string to zero
- $place_icon = '';
- $controller = new SimpleController;
+ $controller = new PageController;
$controller
- ->restrictAccess(Auth::isAdmin())
- ->setPageTitle(I18N::translate('Geographic data'))
- ->addInlineJavascript('jQuery("<link>", {rel: "stylesheet", type: "text/css", href: "' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/css/wt_v3_googlemap.css"}).appendTo("head");')
+ ->setPageTitle(I18N::translate('Upload geographic data'))
->pageHeader();
- $where_am_i = $this->placeIdToHierarchy($placeid);
- $level = count($where_am_i);
-
- if ($action == 'addrecord' && Auth::isAdmin()) {
- $statement =
- Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ $this->getConfigLink() => $this->getTitle(),
+ 'module.php?mod=googlemap&mod_action=admin_places' => I18N::translate('Geographic data'),
+ ], $controller->getPageTitle());
- if ((Filter::post('LONG_CONTROL') == '') || (Filter::post('NEW_PLACE_LONG') == '') || (Filter::post('NEW_PLACE_LATI') == '')) {
- $statement->execute([$this->getHighestIndex() + 1, $placeid, $level, Filter::post('NEW_PLACE_NAME'), null, null, Filter::post('NEW_ZOOM_FACTOR'), Filter::post('icon')]);
- } else {
- $statement->execute([$this->getHighestIndex() + 1, $placeid, $level, Filter::post('NEW_PLACE_NAME'), Filter::post('LONG_CONTROL') . Filter::post('NEW_PLACE_LONG'), Filter::post('LATI_CONTROL') . Filter::post('NEW_PLACE_LATI'), Filter::post('NEW_ZOOM_FACTOR'), Filter::post('icon')]);
- }
+ $placefiles = $this->findFiles(WT_MODULES_DIR . 'googlemap/extra');
+ sort($placefiles);
- $controller->addInlineJavascript('closePopupAndReloadParent();');
+ ?>
+ <h1><?= $controller->getPageTitle() ?></h1>
- return;
- }
+ <form method="post" action="module.php?mod=googlemap&amp;mod_action=admin_upload_action" enctype="multipart/form-data">
+ <input type="hidden" name="parent_id" value="<?= $parent_id ?>">
+ <input type="hidden" name="inactive" value="<?= $inactive ?>">
- if ($action == 'updaterecord' && Auth::isAdmin()) {
- $statement =
- Database::prepare("UPDATE `##placelocation` SET pl_place=?, pl_lati=?, pl_long=?, pl_zoom=?, pl_icon=? WHERE pl_id=?");
+ <!-- PLACES FILE -->
+ <div class="row form-group">
+ <label class="col-form-label col-sm-4" for="placesfile">
+ <?= I18N::translate('A file on your computer') ?>
+ </label>
+ <div class="col-sm-8">
+ <input id="placesfile" type="file" name="placesfile" class="form-control">
+ </div>
+ </div>
- if ((Filter::post('LONG_CONTROL') == '') || (Filter::post('NEW_PLACE_LONG') == '') || (Filter::post('NEW_PLACE_LATI') == '')) {
- $statement->execute([Filter::post('NEW_PLACE_NAME'), null, null, (int) Filter::post('NEW_ZOOM_FACTOR'), Filter::post('icon'), $placeid]);
- } else {
- $statement->execute([Filter::post('NEW_PLACE_NAME'), Filter::post('LATI_CONTROL') . Filter::post('NEW_PLACE_LATI'), Filter::post('LONG_CONTROL') . Filter::post('NEW_PLACE_LONG'), Filter::post('NEW_ZOOM_FACTOR'), Filter::post('icon'), $placeid]);
- }
+ <!-- LOCAL FILE -->
+ <div class="row form-group">
+ <label class="col-form-label col-sm-4" for="localfile">
+ <?= I18N::translate('A file on the server') ?>
+ </label>
+ <div class="col-sm-8">
+ <div class="input-group">
+ <span class="input-group-addon">
+ <?= WT_MODULES_DIR . 'googlemap/extra/' ?>
+ </span>
+ <?php
+ foreach ($placefiles as $p => $placefile) {
+ unset($placefiles[$p]);
+ $p = Filter::escapeHtml($placefile);
+ if (substr($placefile, 0, 1) == '/') {
+ $placefiles[$p] = substr($placefile, 1);
+ } else {
+ $placefiles[$p] = $placefile;
+ }
+ }
+ echo Bootstrap4::select($placefiles, '', ['id' => 'localfile', ['id' => 'localfile']]);
+ ?>
+ </div>
+ </div>
+ </div>
- $controller->addInlineJavascript('closePopupAndReloadParent();');
+ <!-- CLEAR DATABASE -->
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-4">
+ <?= I18N::translate('Delete all existing geographic data before importing the file.') ?>
+ </legend>
+ <div class="col-sm-8">
+ <?= Bootstrap4::radioButtons('cleardatabase', [I18N::translate('no'), I18N::translate('yes')], '0', true) ?>
+ </div>
+ </div>
+ </fieldset>
- return;
- }
+ <!-- UPDATE ONLY -->
+ <fieldset class="form-group">
- if ($action === 'update') {
- // --- find the place in the file
- $row =
- Database::prepare("SELECT pl_place, pl_lati, pl_long, pl_icon, pl_parent_id, pl_level, pl_zoom FROM `##placelocation` WHERE pl_id=?")
- ->execute([$placeid])
- ->fetchOneRow();
- $place_name = $row->pl_place;
- $place_icon = $row->pl_icon;
- $selected_country = explode('/', $place_icon);
- if (isset($selected_country[1]) && $selected_country[1] !== 'flags') {
- $selected_country = $selected_country[1];
- } else {
- $selected_country = 'Countries';
- }
- $parent_id = $row->pl_parent_id;
- $level = $row->pl_level;
- $zoomfactor = $row->pl_zoom;
- $parent_lati = 0.0;
- $parent_long = 0.0;
- if ($row->pl_lati !== null && $row->pl_long !== null) {
- $place_lati = (float) (str_replace(['N', 'S', ','], ['', '-', '.'], $row->pl_lati));
- $place_long = (float) (str_replace(['E', 'W', ','], ['', '-', '.'], $row->pl_long));
- } else {
- $place_lati = 0.0;
- $place_long = 0.0;
- $zoomfactor = 1;
- }
+ <div class="row">
+ <legend class="col-form-legend col-sm-4">
+ <?= I18N::translate('Do not create new locations, just import coordinates for existing locations.') ?>
+ </legend>
+ <div class="col-sm-8">
+ <?= Bootstrap4::radioButtons('updateonly', [I18N::translate('no'), I18N::translate('yes')], '0', true) ?>
+ </div>
+ </div>
+ </fieldset>
- do {
- $row =
- Database::prepare("SELECT pl_lati, pl_long, pl_parent_id, pl_zoom FROM `##placelocation` WHERE pl_id=?")
- ->execute([$parent_id])
- ->fetchOneRow();
- if (!$row) {
- break;
- }
- if ($row->pl_lati !== null && $row->pl_long !== null) {
- $parent_lati = (float) (str_replace(['N', 'S', ','], ['', '-', '.'], $row->pl_lati));
- $parent_long = (float) (str_replace(['E', 'W', ','], ['', '-', '.'], $row->pl_long));
- if ($zoomfactor == 1) {
- $zoomfactor = $row->pl_zoom;
- }
- }
- $parent_id = $row->pl_parent_id;
- } while ($row->pl_parent_id != 0 && $row->pl_lati === null && $row->pl_long === null);
+ <!-- OVERWRITE DATA -->
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-4">
+ <?= I18N::translate('Overwrite existing coordinates.') ?>
+ </legend>
+ <div class="col-sm-8">
+ <?= Bootstrap4::radioButtons('overwritedata', [I18N::translate('no'), I18N::translate('yes')], '0', true) ?>
+ </div>
+ </div>
+ </fieldset>
- echo '<b>', Filter::escapeHtml(str_replace('Unknown', I18N::translate('unknown'), implode(I18N::$list_separator, array_reverse($where_am_i, true)))), '</b><br>';
- }
+ <!-- SAVE BUTTON -->
+ <div class="row form-group">
+ <div class="offset-sm-4 col-sm-8">
+ <button type="submit" class="btn btn-primary">
+ <i class="fa fa-check"></i>
+ <?= I18N::translate('continue') ?>
+ </button>
+ </div>
+ </div>
+ </form>
+ <?php
+ }
- if ($action === 'add') {
- // --- find the parent place in the file
- if ($placeid != 0) {
- $place_lati = 0.0;
- $place_long = 0.0;
- $zoomfactor = 1;
- $parent_lati = 0.0;
- $parent_long = 0.0;
- $parent_id = $placeid;
- do {
- $row =
- Database::prepare("SELECT pl_lati, pl_long, pl_parent_id, pl_zoom, pl_level FROM `##placelocation` WHERE pl_id=?")
- ->execute([$parent_id])
- ->fetchOneRow();
- if ($row->pl_lati !== null && $row->pl_long !== null) {
- $parent_lati = strtr($row->pl_lati, ['N' => '', 'S' => '-', ',' => '.']);
- $parent_long = strtr($row->pl_long, ['E' => '', 'W' => '-', ',' => '.']);
- $zoomfactor = min($row->pl_zoom, $GM_MAX_ZOOM);
- $level = $row->pl_level + 1;
- }
- $parent_id = $row->pl_parent_id;
- } while ($row->pl_parent_id != 0 && $row->pl_lati === null && $row->pl_long === null);
- } else {
- $place_lati = 0.0;
- $place_long = 0.0;
- $parent_lati = 0.0;
- $parent_long = 0.0;
- $parent_id = 0;
- $level = 0;
- $zoomfactor = $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT);
- }
- $selected_country = 'Countries';
+ /**
+ * Delete a geographic place.
+ */
+ private function adminDeleteAction() {
+ $place_id = (int) Filter::post('place_id');
+ $parent_id = (int) Filter::post('parent_id');
+ $inactive = (int) Filter::post('inactive');
- if ($place_name == '') {
- echo '<b>', I18N::translate('unknown');
- } else {
- echo '<b>', $place_name;
- }
- if (count($where_am_i) > 0) {
- echo ', ', Filter::escapeHtml(str_replace('Unknown', I18N::translate('unknown'), implode(I18N::$list_separator, array_reverse($where_am_i, true)))), '</b><br>';
- }
- echo '</b><br>';
+ try {
+ Database::prepare(
+ "DELETE FROM `##placelocation` WHERE pl_id = :place_id"
+ )->execute([
+ 'place_id' => $place_id,
+ ]);
+ } catch (\Exception $ex) {
+ FlashMessages::addMessage(I18N::translate('Location not removed: this location contains sub-locations'),'danger');
}
- ?>
+ header('Location: ' . WT_BASE_URL . 'module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $parent_id . '&inactive=' . $inactive);
+ }
- <script src="<?php echo $this->googleMapsScript() ?>"></script>
- <script>
- var map;
- var marker;
- var zoom;
- var pl_name = '<?php echo Filter::escapeJs($place_name) ?>';
- <?php if ($place_lati !== 0.0 && $place_long !== 0.0) { ?>
- var latlng = new google.maps.LatLng(<?php echo $place_lati ?>, <?php echo $place_long ?>);
- <?php } else {?>
- var latlng = new google.maps.LatLng(<?php echo $parent_lati ?>, <?php echo $parent_long ?>);
- <?php } ?>
- var pl_zoom = <?php echo $zoomfactor ?>;
- var polygon1;
- var polygon2;
- var geocoder;
- var mapType;
+ /**
+ * Import places from GEDCOM data.
+ */
+ private function adminImportAction() {
+ }
- var infowindow = new google.maps.InfoWindow({
- //
- });
+ /**
+ * Upload a CSV file.
+ */
+ private function adminUploadAction() {
+ global $WT_TREE;
- function geocodePosition(pos) {
- geocoder.geocode({
- latLng: pos
- }, function(responses) {
- if (responses && responses.length > 0) {
- updateMarkerAddress(responses[0].formatted_address);
- } else {
- updateMarkerAddress('Cannot determine address at this location.');
+ $country_names = [];
+ $stats = new Stats($WT_TREE);
+ foreach ($stats->iso3166() as $key => $value) {
+ $country_names[$key] = I18N::translate($key);
+ }
+ if (Filter::postBool('cleardatabase')) {
+ Database::exec("DELETE FROM `##placelocation` WHERE 1=1");
+ }
+ if (!empty($_FILES['placesfile']['tmp_name'])) {
+ $lines = file($_FILES['placesfile']['tmp_name']);
+ } elseif (!empty($_REQUEST['localfile'])) {
+ $lines = file(WT_MODULES_DIR . 'googlemap/extra' . $_REQUEST['localfile']);
+ }
+ // Strip BYTE-ORDER-MARK, if present
+ if (!empty($lines[0]) && substr($lines[0], 0, 3) === WT_UTF8_BOM) {
+ $lines[0] = substr($lines[0], 3);
+ }
+ asort($lines);
+ $highestIndex = $this->getHighestIndex();
+ $placelist = [];
+ $j = 0;
+ $maxLevel = 0;
+ foreach ($lines as $p => $placerec) {
+ $fieldrec = explode(';', $placerec);
+ if ($fieldrec[0] > $maxLevel) {
+ $maxLevel = $fieldrec[0];
+ }
+ }
+ $fields = count($fieldrec);
+ $set_icon = true;
+ if (!is_dir(WT_MODULES_DIR . 'googlemap/places/flags/')) {
+ $set_icon = false;
+ }
+ foreach ($lines as $p => $placerec) {
+ $fieldrec = explode(';', $placerec);
+ if (is_numeric($fieldrec[0]) && $fieldrec[0] <= $maxLevel) {
+ $placelist[$j] = [];
+ $placelist[$j]['place'] = '';
+ for ($ii = $fields - 4; $ii > 1; $ii--) {
+ if ($fieldrec[0] > $ii - 2) {
+ $placelist[$j]['place'] .= $fieldrec[$ii] . ',';
}
- });
+ }
+ foreach ($country_names as $countrycode => $countryname) {
+ if ($countrycode == strtoupper($fieldrec[1])) {
+ $fieldrec[1] = $countryname;
+ break;
+ }
+ }
+ $placelist[$j]['place'] .= $fieldrec[1];
+ $placelist[$j]['long'] = $fieldrec[$fields - 4];
+ $placelist[$j]['lati'] = $fieldrec[$fields - 3];
+ $placelist[$j]['zoom'] = $fieldrec[$fields - 2];
+ if ($set_icon) {
+ $placelist[$j]['icon'] = trim($fieldrec[$fields - 1]);
+ } else {
+ $placelist[$j]['icon'] = '';
+ }
+ $j = $j + 1;
}
+ }
- /**
- * Redraw the map, centered and zoomed on the selected point.
- *
- * @param event
- */
- function updateMap(event) {
- var point;
- var zoom = parseInt(document.editplaces.NEW_ZOOM_FACTOR.value);
- var latitude;
- var longitude;
-
- if ((document.editplaces.NEW_PLACE_LATI.value == '') ||
- (document.editplaces.NEW_PLACE_LONG.value == '')) {
- latitude = parseFloat(document.editplaces.parent_lati.value).toFixed(5);
- longitude = parseFloat(document.editplaces.parent_long.value).toFixed(5);
- point = new google.maps.LatLng(latitude, longitude);
- } else {
- latitude = parseFloat(document.editplaces.NEW_PLACE_LATI.value).toFixed(5);
- longitude = parseFloat(document.editplaces.NEW_PLACE_LONG.value).toFixed(5);
- document.editplaces.NEW_PLACE_LATI.value = latitude;
- document.editplaces.NEW_PLACE_LONG.value = longitude;
+ $prevPlace = '';
+ $prevLati = '';
+ $prevLong = '';
+ $placelistUniq = [];
+ $j = 0;
+ foreach ($placelist as $k => $place) {
+ if ($place['place'] != $prevPlace) {
+ $placelistUniq[$j] = [];
+ $placelistUniq[$j]['place'] = $place['place'];
+ $placelistUniq[$j]['lati'] = $place['lati'];
+ $placelistUniq[$j]['long'] = $place['long'];
+ $placelistUniq[$j]['zoom'] = $place['zoom'];
+ $placelistUniq[$j]['icon'] = $place['icon'];
+ $j = $j + 1;
+ } elseif (($place['place'] == $prevPlace) && (($place['lati'] != $prevLati) || ($place['long'] != $prevLong))) {
+ if (($placelistUniq[$j - 1]['lati'] == 0) || ($placelistUniq[$j - 1]['long'] == 0)) {
+ $placelistUniq[$j - 1]['lati'] = $place['lati'];
+ $placelistUniq[$j - 1]['long'] = $place['long'];
+ $placelistUniq[$j - 1]['zoom'] = $place['zoom'];
+ $placelistUniq[$j - 1]['icon'] = $place['icon'];
+ } elseif (($place['lati'] != '0') || ($place['long'] != '0')) {
+ echo 'Difference: previous value = ', $prevPlace, ', ', $prevLati, ', ', $prevLong, ' current = ', $place['place'], ', ', $place['lati'], ', ', $place['long'], '<br>';
+ }
+ }
+ $prevPlace = $place['place'];
+ $prevLati = $place['lati'];
+ $prevLong = $place['long'];
+ }
- if (event == 'flag_drag') {
- if (longitude < 0.0 ) {
- longitude = longitude * -1;
- document.editplaces.NEW_PLACE_LONG.value = longitude;
- document.editplaces.LONG_CONTROL.value = 'W';
+ $default_zoom_level = [];
+ $default_zoom_level[0] = 4;
+ $default_zoom_level[1] = 7;
+ $default_zoom_level[2] = 10;
+ $default_zoom_level[3] = 12;
+ foreach ($placelistUniq as $k => $place) {
+ $parent = explode(',', $place['place']);
+ $parent = array_reverse($parent);
+ $parent_id = 0;
+ $num_parent = count($parent);
+ for ($i = 0; $i < $num_parent; $i++) {
+ $escparent = $parent[$i];
+ if ($escparent == '') {
+ $escparent = 'Unknown';
+ }
+ $row =
+ Database::prepare("SELECT pl_id, pl_long, pl_lati, pl_zoom, pl_icon FROM `##placelocation` WHERE pl_level=? AND pl_parent_id=? AND pl_place LIKE ? ORDER BY pl_place")
+ ->execute([$i, $parent_id, $escparent])
+ ->fetchOneRow();
+ if (empty($row)) {
+ // this name does not yet exist: create entry
+ if (!Filter::postBool('updateonly')) {
+ $highestIndex = $highestIndex + 1;
+ if (($i + 1) == $num_parent) {
+ $zoomlevel = $place['zoom'];
+ } elseif (isset($default_zoom_level[$i])) {
+ $zoomlevel = $default_zoom_level[$i];
} else {
- document.editplaces.NEW_PLACE_LONG.value = longitude;
- document.editplaces.LONG_CONTROL.value = 'E';
+ $zoomlevel = $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT);
}
- if (latitude < 0.0 ) {
- latitude = latitude * -1;
- document.editplaces.NEW_PLACE_LATI.value = latitude;
- document.editplaces.LATI_CONTROL.value = 'S';
+ if (($place['lati'] == '0') || ($place['long'] == '0') || (($i + 1) < $num_parent)) {
+ Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?)")
+ ->execute([$highestIndex, $parent_id, $i, $escparent, $zoomlevel, $place['icon']]);
} else {
- document.editplaces.NEW_PLACE_LATI.value = latitude;
- document.editplaces.LATI_CONTROL.value = 'N';
- }
-
- if (document.editplaces.LATI_CONTROL.value == 'S') {
- latitude = latitude * -1;
- }
- if (document.editplaces.LONG_CONTROL.value == 'W') {
- longitude = longitude * -1;
+ //delete leading zero
+ $pl_lati = str_replace(['N', 'S', ','], ['', '-', '.'], $place['lati']);
+ $pl_long = str_replace(['E', 'W', ','], ['', '-', '.'], $place['long']);
+ if ($pl_lati >= 0) {
+ $place['lati'] = 'N' . abs($pl_lati);
+ } elseif ($pl_lati < 0) {
+ $place['lati'] = 'S' . abs($pl_lati);
+ }
+ if ($pl_long >= 0) {
+ $place['long'] = 'E' . abs($pl_long);
+ } elseif ($pl_long < 0) {
+ $place['long'] = 'W' . abs($pl_long);
+ }
+ Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
+ ->execute([$highestIndex, $parent_id, $i, $escparent, $place['long'], $place['lati'], $zoomlevel, $place['icon']]);
}
- point = new google.maps.LatLng(latitude, longitude);
+ $parent_id = $highestIndex;
+ }
+ } else {
+ $parent_id = $row->pl_id;
+ if (Filter::postBool('overwritedata') && ($i + 1 == count($parent))) {
+ Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ?, pl_zoom = ?, pl_icon = ? WHERE pl_id = ?")
+ ->execute([$place['lati'], $place['long'], $place['zoom'], $place['icon'], $parent_id]);
} else {
- if (latitude < 0.0) {
- latitude = latitude * -1;
- document.editplaces.NEW_PLACE_LATI.value = latitude;
- }
- if (longitude < 0.0) {
- longitude = longitude * -1;
- document.editplaces.NEW_PLACE_LONG.value = longitude;
+ // Update only if existing data is missing
+ if (!$row->pl_long && !$row->pl_lati) {
+ Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ? WHERE pl_id = ?")
+ ->execute([$place['lati'], $place['long'], $parent_id]);
}
- if (document.editplaces.LATI_CONTROL.value == 'S') {
- latitude = latitude * -1;
+ if (!$row->pl_icon && $place['icon']) {
+ Database::prepare("UPDATE `##placelocation` SET pl_icon = ? WHERE pl_id = ?")
+ ->execute([$place['icon'], $parent_id]);
}
- if (document.editplaces.LONG_CONTROL.value == 'W') {
- longitude = longitude * -1;
- }
- point = new google.maps.LatLng(latitude, longitude);
}
}
-
- map.setCenter(point);
- map.setZoom(zoom);
- marker.setPosition(point);
}
+ }
- // === Create Borders for the UK Countries =========================================================
- function overlays() {
- // Define place LatLng arrays
+ $parent_id = (int) Filter::post('parent_id');
+ $inactive = (int) Filter::post('inactive');
- <?php
- $coordsAsStr = [];
- switch (strtoupper($place_name)) {
- case 'ENGLAND':
- $coordsAsStr[] = '-4.74361,50.66750|-4.78361,50.59361|-4.91584,50.57722|-5.01750,50.54264|-5.02569,50.47271|-5.04729,50.42750|-5.15208,50.34374|-5.26805,50.27389|-5.43194,50.19326|-5.49584,50.21695|-5.54639,50.20527|-5.71000,50.12916|-5.71681,50.06083|-5.66174,50.03631|-5.58278,50.04777|-5.54166,50.07055|-5.53416,50.11569|-5.47055,50.12499|-5.33361,50.09138|-5.27666,50.05972|-5.25674,50.00514|-5.19306,49.95527|-5.16070,50.00319|-5.06555,50.03750|-5.07090,50.08166|-5.04806,50.17111|-4.95278,50.19333|-4.85750,50.23166|-4.76250,50.31138|-4.67861,50.32583|-4.54334,50.32222|-4.48278,50.32583|-4.42972,50.35139|-4.38000,50.36388|-4.16555,50.37028|-4.11139,50.33027|-4.05708,50.29791|-3.94389,50.31346|-3.87764,50.28139|-3.83653,50.22972|-3.78944,50.21222|-3.70666,50.20972|-3.65195,50.23111|-3.55139,50.43833|-3.49416,50.54639|-3.46181,50.58792|-3.41139,50.61610|-3.24416,50.67444|-3.17347,50.68833|-3.09445,50.69222|-2.97806,50.70638|-2.92750,50.73125|-2.88278,50.73111|-2.82305,50.72027|-2.77139,50.70861|-2.66195,50.67334|-2.56305,50.63222|-2.45861,50.57500|-2.44666,50.62639|-2.39097,50.64166|-2.19722,50.62611|-2.12195,50.60722|-2.05445,50.58569|-1.96437,50.59674|-1.95441,50.66536|-2.06681,50.71430|-1.93416,50.71277|-1.81639,50.72306|-1.68445,50.73888|-1.59278,50.72416|-1.33139,50.79138|-1.11695,50.80694|-1.15889,50.84083|-1.09445,50.84584|-0.92842,50.83966|-0.86584,50.79965|-0.90826,50.77396|-0.78187,50.72722|-0.74611,50.76583|-0.67528,50.78111|-0.57722,50.79527|-0.25500,50.82638|-0.19084,50.82583|-0.13805,50.81833|0.05695,50.78083|0.12334,50.75944|0.22778,50.73944|0.28695,50.76500|0.37195,50.81638|0.43084,50.83111|0.56722,50.84777|0.67889,50.87681|0.71639,50.90500|0.79334,50.93610|0.85666,50.92556|0.97125,50.98111|0.99778,51.01903|1.04555,51.04944|1.10028,51.07361|1.26250,51.10166|1.36889,51.13583|1.41111,51.20111|1.42750,51.33111|1.38556,51.38777|1.19195,51.37861|1.05278,51.36722|0.99916,51.34777|0.90806,51.34069|0.70416,51.37749|0.61972,51.38304|0.55945,51.40596|0.64236,51.44042|0.69750,51.47084|0.59195,51.48777|0.53611,51.48806|0.48916,51.48445|0.45215,51.45562|0.38894,51.44822|0.46500,51.50306|0.65195,51.53680|0.76695,51.52138|0.82084,51.53556|0.87528,51.56110|0.95250,51.60923|0.94695,51.72556|0.90257,51.73465|0.86306,51.71166|0.76140,51.69164|0.70111,51.71847|0.86211,51.77361|0.93236,51.80583|0.98278,51.82527|1.03569,51.77416|1.08834,51.77056|1.13222,51.77694|1.18139,51.78972|1.22361,51.80888|1.26611,51.83916|1.28097,51.88096|1.20834,51.95083|1.16347,52.02361|1.27750,51.98555|1.33125,51.92875|1.39028,51.96999|1.58736,52.08388|1.63000,52.19527|1.68576,52.32630|1.73028,52.41138|1.74945,52.45583|1.74590,52.62021|1.70250,52.71583|1.64528,52.77111|1.50361,52.83749|1.43222,52.87472|1.35250,52.90972|1.28222,52.92750|1.18389,52.93889|0.99472,52.95111|0.94222,52.95083|0.88472,52.96638|0.66722,52.97611|0.54778,52.96618|0.49139,52.93430|0.44431,52.86569|0.42903,52.82403|0.36334,52.78027|0.21778,52.80694|0.16125,52.86250|0.05778,52.88916|0.00211,52.87985|0.03222,52.91722|0.20389,53.02805|0.27666,53.06694|0.33916,53.09236|0.35389,53.18722|0.33958,53.23472|0.23555,53.39944|0.14347,53.47527|0.08528,53.48638|0.02694,53.50972|-0.10084,53.57306|-0.20722,53.63083|-0.26445,53.69083|-0.30166,53.71319|-0.39022,53.70794|-0.51972,53.68527|-0.71653,53.69638|-0.65445,53.72527|-0.60584,53.72972|-0.54916,53.70611|-0.42261,53.71755|-0.35728,53.73056|-0.29389,53.73666|-0.23139,53.72166|-0.10584,53.63166|-0.03472,53.62555|0.04416,53.63916|0.08916,53.62666|0.14945,53.58847|0.12639,53.64527|0.06264,53.70389|-0.12750,53.86388|-0.16916,53.91847|-0.21222,54.00833|-0.20569,54.05153|-0.16111,54.08806|-0.11694,54.13222|-0.20053,54.15171|-0.26250,54.17444|-0.39334,54.27277|-0.42166,54.33222|-0.45750,54.37694|-0.51847,54.44749|-0.56472,54.48000|-0.87584,54.57027|-1.06139,54.61722|-1.16528,54.64972|-1.30445,54.77138|-1.34556,54.87138|-1.41278,54.99944|-1.48292,55.08625|-1.51500,55.14972|-1.56584,55.28722|-1.58097,55.48361|-1.63597,55.58194|-1.69000,55.60556|-1.74695,55.62499|-1.81764,55.63306|-1.97681,55.75416|-2.02166,55.80611|-2.08361,55.78054|-2.22000,55.66499|-2.27916,55.64472|-2.27416,55.57527|-2.21528,55.50583|-2.18278,55.45985|-2.21236,55.42777|-2.46305,55.36111|-2.63055,55.25500|-2.69945,55.17722|-2.96278,55.03889|-3.01500,55.05222|-3.05103,54.97986|-3.13292,54.93139|-3.20861,54.94944|-3.28931,54.93792|-3.39166,54.87639|-3.42916,54.81555|-3.56916,54.64249|-3.61306,54.48861|-3.49305,54.40333|-3.43389,54.34806|-3.41056,54.28014|-3.38055,54.24444|-3.21472,54.09555|-3.15222,54.08194|-2.93097,54.15333|-2.81361,54.22277|-2.81750,54.14277|-2.83361,54.08500|-2.93250,53.95055|-3.05264,53.90764|-3.03708,53.74944|-2.99278,53.73277|-2.89979,53.72499|-2.97729,53.69382|-3.07306,53.59805|-3.10563,53.55993|-3.00678,53.41738|-2.95389,53.36027|-2.85736,53.32083|-2.70493,53.35062|-2.77639,53.29250|-2.89972,53.28916|-2.94250,53.31056|-3.02889,53.38191|-3.07248,53.40936|-3.16695,53.35708|-3.12611,53.32500|-3.08860,53.26001|-3.02000,53.24722|-2.95528,53.21555|-2.91069,53.17014|-2.89389,53.10416|-2.85695,53.03249|-2.77792,52.98514|-2.73109,52.96873|-2.71945,52.91902|-2.79278,52.90207|-2.85069,52.93875|-2.99389,52.95361|-3.08639,52.91611|-3.13014,52.88486|-3.13708,52.79312|-3.06806,52.77027|-3.01111,52.71166|-3.06666,52.63527|-3.11750,52.58666|-3.07089,52.55702|-3.00792,52.56902|-2.98028,52.53083|-3.02736,52.49792|-3.11916,52.49194|-3.19514,52.46722|-3.19611,52.41027|-3.02195,52.34027|-2.95486,52.33117|-2.99750,52.28139|-3.05125,52.23347|-3.07555,52.14804|-3.12222,52.11805|-3.11250,52.06945|-3.08500,52.01930|-3.04528,51.97639|-2.98889,51.92555|-2.91757,51.91569|-2.86639,51.92889|-2.77861,51.88583|-2.65944,51.81806|-2.68334,51.76957|-2.68666,51.71889|-2.66500,51.61500|-2.62916,51.64416|-2.57889,51.67777|-2.46056,51.74666|-2.40389,51.74041|-2.47166,51.72445|-2.55305,51.65722|-2.65334,51.56389|-2.77055,51.48916|-2.85278,51.44472|-2.96000,51.37499|-3.00695,51.30722|-3.01278,51.25632|-3.02834,51.20611|-3.30139,51.18111|-3.39361,51.18138|-3.43729,51.20638|-3.50722,51.22333|-3.57014,51.23027|-3.63222,51.21805|-3.70028,51.23000|-3.79250,51.23916|-3.88389,51.22416|-3.98472,51.21695|-4.11666,51.21222|-4.22805,51.18777|-4.22028,51.11054|-4.23702,51.04659|-4.30361,51.00416|-4.37639,50.99110|-4.42736,51.00958|-4.47445,51.01416|-4.52132,51.01424|-4.54334,50.92694|-4.56139,50.77625|-4.65139,50.71527|-4.74361,50.66750';
- break;
- case 'SCOTLAND':
- $coordsAsStr[] = '-2.02166,55.80611|-2.07972,55.86722|-2.13028,55.88583|-2.26028,55.91861|-2.37528,55.95694|-2.65722,56.05972|-2.82028,56.05694|-2.86618,56.02840|-2.89555,55.98861|-2.93500,55.96944|-3.01805,55.94944|-3.06750,55.94444|-3.25472,55.97166|-3.45472,55.99194|-3.66416,56.00652|-3.73722,56.05555|-3.57139,56.05360|-3.44111,56.01916|-3.39584,56.01083|-3.34403,56.02333|-3.13903,56.11084|-2.97611,56.19472|-2.91666,56.20499|-2.84695,56.18638|-2.78805,56.18749|-2.67937,56.21465|-2.58403,56.28264|-2.67208,56.32277|-2.76861,56.33180|-2.81528,56.37360|-2.81208,56.43958|-2.91653,56.45014|-2.99555,56.41416|-3.19042,56.35958|-3.27805,56.35750|-3.04055,56.45472|-2.95861,56.45611|-2.72084,56.48888|-2.64084,56.52250|-2.53126,56.57611|-2.48861,56.61416|-2.47805,56.71527|-2.39000,56.77166|-2.31986,56.79638|-2.21972,56.86777|-2.19708,56.94388|-2.16695,57.00055|-2.09334,57.07027|-2.05416,57.21861|-1.95889,57.33250|-1.85584,57.39889|-1.77334,57.45805|-1.78139,57.50555|-1.82195,57.57861|-1.86000,57.62138|-1.92972,57.67777|-2.02222,57.69388|-2.07555,57.69944|-2.14028,57.69056|-2.18611,57.66861|-2.39626,57.66638|-2.51000,57.67166|-2.78639,57.70222|-2.89806,57.70694|-2.96750,57.68027|-3.03847,57.66249|-3.12334,57.67166|-3.22334,57.69166|-3.28625,57.72499|-3.33972,57.72333|-3.48805,57.70945|-3.52222,57.66333|-3.59542,57.63666|-3.64063,57.63881|-3.75414,57.62504|-4.03986,57.55569|-4.19666,57.48584|-4.22889,57.51554|-4.17945,57.56249|-4.11139,57.59833|-4.08078,57.66533|-4.19139,57.67139|-4.25945,57.65527|-4.34361,57.60777|-4.41639,57.60166|-4.29666,57.67444|-4.08528,57.72611|-4.01908,57.70226|-3.96861,57.70250|-3.86556,57.76861|-3.81945,57.80458|-3.80681,57.85819|-3.85055,57.82000|-3.92639,57.80749|-4.04322,57.81438|-4.14973,57.82527|-4.29750,57.84638|-4.36250,57.89777|-4.24306,57.87028|-4.10666,57.85195|-4.01500,57.86777|-3.99166,57.90611|-3.99695,57.95056|-3.84500,58.02000|-3.56611,58.13916|-3.51319,58.16374|-3.45916,58.20305|-3.42028,58.24361|-3.33750,58.27694|-3.20555,58.30625|-3.10972,58.38166|-3.05792,58.45083|-3.02264,58.64653|-3.17639,58.64944|-3.35389,58.66055|-3.36931,58.59555|-3.57611,58.62194|-3.66028,58.61972|-3.71166,58.60374|-3.78264,58.56750|-3.84834,58.56000|-4.08056,58.55527|-4.27722,58.53361|-4.43653,58.54902|-4.50666,58.56777|-4.56055,58.57584|-4.59910,58.53027|-4.66805,58.48833|-4.76146,58.44604|-4.70195,58.50999|-4.70166,58.55861|-4.77014,58.60264|-5.00153,58.62416|-5.10945,58.50833|-5.16472,58.32527|-5.12639,58.28750|-5.07166,58.26472|-5.20361,58.25083|-5.39764,58.25055|-5.27389,58.11722|-5.31514,58.06416|-5.38416,58.08361|-5.45285,58.07416|-5.39805,58.03111|-5.26278,57.97111|-5.19334,57.95069|-5.12750,57.86944|-5.21750,57.90084|-5.33861,57.92083|-5.42876,57.90104|-5.45750,57.85889|-5.64445,57.89972|-5.62555,57.85222|-5.58153,57.81945|-5.60674,57.76618|-5.66305,57.78889|-5.71695,57.86944|-5.76695,57.86472|-5.81708,57.81944|-5.81084,57.63958|-5.69555,57.55944|-5.64361,57.55222|-5.53084,57.52833|-5.65305,57.50875|-5.75000,57.54834|-5.81569,57.57923|-5.85042,57.54972|-5.86695,57.46777|-5.81806,57.36250|-5.75111,57.34333|-5.50334,57.40111|-5.45126,57.41805|-5.49250,57.37083|-5.59884,57.33049|-5.57116,57.28411|-5.51266,57.27745|-5.40514,57.23097|-5.44972,57.22138|-5.49472,57.23888|-5.56066,57.25477|-5.64611,57.23499|-5.64751,57.16161|-5.55028,57.11639|-5.48166,57.11222|-5.40305,57.11062|-5.55945,57.09250|-5.65111,57.11611|-5.72472,57.11306|-5.77361,57.04556|-5.63139,56.98499|-5.56916,56.98972|-5.52403,56.99735|-5.57916,56.98000|-5.64611,56.97222|-5.73374,57.00909|-5.82584,57.00346|-5.91958,56.88708|-5.86528,56.87944|-5.74278,56.89374|-5.66292,56.86924|-5.73306,56.83916|-5.78584,56.83955|-5.85590,56.81430|-5.80208,56.79180|-5.84958,56.74444|-5.90500,56.75666|-5.96694,56.78027|-6.14000,56.75777|-6.19208,56.74888|-6.23452,56.71673|-6.19139,56.67972|-5.91916,56.67388|-5.82622,56.69156|-5.73945,56.71166|-5.55240,56.68886|-5.64861,56.68027|-5.69916,56.68278|-5.88261,56.65666|-5.97472,56.65138|-5.99584,56.61138|-5.93056,56.56972|-5.88416,56.55333|-5.79056,56.53805|-5.67695,56.49389|-5.56389,56.54056|-5.36334,56.66195|-5.23416,56.74333|-5.13236,56.79403|-5.31473,56.65666|-5.37405,56.55925|-5.31826,56.55633|-5.25080,56.55753|-5.37718,56.52112|-5.39866,56.47866|-5.19111,56.46194|-5.11556,56.51277|-5.07014,56.56069|-5.13555,56.48499|-5.22084,56.43583|-5.32764,56.43574|-5.42439,56.43091|-5.52611,56.37360|-5.57139,56.32833|-5.59653,56.25695|-5.57389,56.16000|-5.52000,56.16485|-5.56334,56.11333|-5.60139,56.07638|-5.64222,56.04305|-5.66039,55.98263|-5.62555,56.02055|-5.58014,56.01319|-5.63361,55.96611|-5.67697,55.88844|-5.64750,55.78139|-5.60986,55.75930|-5.66916,55.66166|-5.70166,55.58861|-5.71805,55.51500|-5.75916,55.41750|-5.79528,55.36027|-5.78166,55.29902|-5.73778,55.29222|-5.56694,55.31666|-5.51528,55.36347|-5.55520,55.41440|-5.48639,55.64306|-5.44597,55.70680|-5.38000,55.75027|-5.41889,55.90666|-5.39924,55.99972|-5.33895,56.03456|-5.30594,56.06922|-5.23889,56.11889|-5.03222,56.23250|-4.92229,56.27111|-4.97416,56.23333|-5.07222,56.18695|-5.20069,56.11861|-5.30906,56.00570|-5.34000,55.90201|-5.29250,55.84750|-5.20805,55.84444|-5.22458,55.90175|-5.17334,55.92916|-5.11000,55.90306|-5.01222,55.86694|-4.96195,55.88000|-4.89824,55.98145|-4.84623,56.08632|-4.86636,56.03178|-4.85461,55.98648|-4.77659,55.97977|-4.62723,55.94555|-4.52305,55.91861|-4.70972,55.93403|-4.75166,55.94611|-4.82406,55.94950|-4.87826,55.93653|-4.91639,55.70083|-4.87584,55.68194|-4.81361,55.64555|-4.68722,55.59750|-4.61361,55.49069|-4.63958,55.44264|-4.68250,55.43388|-4.74847,55.41055|-4.83715,55.31882|-4.84778,55.26944|-4.86542,55.22340|-4.93500,55.17860|-5.01250,55.13347|-5.05361,55.04902|-5.17834,54.98888|-5.18563,54.93622|-5.17000,54.89111|-5.11666,54.83180|-5.00500,54.76333|-4.96229,54.68125|-4.92250,54.64055|-4.85723,54.62958|-4.96076,54.79687|-4.92431,54.83708|-4.85222,54.86861|-4.80125,54.85556|-4.74055,54.82166|-4.68084,54.79972|-4.59861,54.78027|-4.55792,54.73903|-4.49639,54.69888|-4.37584,54.67666|-4.34569,54.70916|-4.35973,54.77111|-4.41111,54.82583|-4.42445,54.88152|-4.38479,54.90555|-4.35056,54.85903|-4.09555,54.76777|-3.95361,54.76749|-3.86972,54.80527|-3.81222,54.84888|-3.69250,54.88110|-3.61584,54.87527|-3.57111,54.99083|-3.44528,54.98638|-3.36056,54.97138|-3.14695,54.96500|-3.05103,54.97986|-3.01500,55.05222|-2.96278,55.03889|-2.69945,55.17722|-2.63055,55.25500|-2.46305,55.36111|-2.21236,55.42777|-2.18278,55.45985|-2.21528,55.50583|-2.27416,55.57527|-2.27916,55.64472|-2.22000,55.66499|-2.08361,55.78054|-2.02166,55.80611';
- break;
- case 'IRELAND':
- $coordsAsStr[] = '-8.17166,54.46388|-8.06555,54.37277|-7.94139,54.29944|-7.87576,54.28499|-7.86834,54.22764|-7.81805,54.19916|-7.69972,54.20250|-7.55945,54.12694|-7.31334,54.11250|-7.14584,54.22527|-7.17555,54.28916|-7.16084,54.33666|-7.05834,54.41000|-6.97445,54.40166|-6.92695,54.37916|-6.87305,54.34208|-6.85111,54.28972|-6.73473,54.18361|-6.65556,54.06527|-6.60584,54.04444|-6.44750,54.05833|-6.33889,54.11555|-6.26697,54.09983|-6.17403,54.07222|-6.10834,54.03638|-6.04389,54.03139|-5.96834,54.06389|-5.88500,54.11639|-5.87347,54.20916|-5.82500,54.23958|-5.74611,54.24806|-5.65556,54.22701|-5.60834,54.24972|-5.55916,54.29084|-5.57334,54.37704|-5.64502,54.49267|-5.70472,54.53361|-5.68055,54.57306|-5.59972,54.54194|-5.55097,54.50083|-5.54216,54.44903|-5.54643,54.40527|-5.50672,54.36444|-5.46111,54.38555|-5.43132,54.48596|-5.47945,54.53638|-5.53521,54.65090|-5.57431,54.67722|-5.62916,54.67945|-5.73674,54.67383|-5.80305,54.66138|-5.88257,54.60652|-5.92445,54.63180|-5.86681,54.68972|-5.81903,54.70972|-5.74672,54.72452|-5.68775,54.76335|-5.70931,54.83166|-5.74694,54.85361|-5.79139,54.85139|-6.03611,55.05778|-6.04250,55.10277|-6.03444,55.15458|-6.10125,55.20945|-6.14584,55.22069|-6.25500,55.21194|-6.37639,55.23916|-6.51556,55.23305|-6.61334,55.20722|-6.73028,55.18027|-6.82472,55.16806|-6.88972,55.16777|-6.96695,55.15611|-6.99416,55.11027|-7.05139,55.04680|-7.09500,55.03694|-7.25251,55.07059|-7.32639,55.04527|-7.40639,54.95333|-7.45805,54.85777|-7.55334,54.76277|-7.73916,54.71054|-7.82576,54.73416|-7.92639,54.70054|-7.85236,54.63388|-7.77750,54.62694|-7.83361,54.55389|-7.95084,54.53222|-8.04695,54.50722|-8.17166,54.46388';
- break;
- case 'WALES':
- $coordsAsStr[] = '-3.08860,53.26001|-3.33639,53.34722|-3.38806,53.34361|-3.60986,53.27944|-3.73014,53.28944|-3.85445,53.28444|-4.01861,53.23750|-4.06639,53.22639|-4.15334,53.22556|-4.19639,53.20611|-4.33028,53.11222|-4.36097,53.02888|-4.55278,52.92889|-4.61889,52.90916|-4.72195,52.83611|-4.72778,52.78139|-4.53945,52.79306|-4.47722,52.85500|-4.41416,52.88472|-4.31292,52.90499|-4.23334,52.91499|-4.13569,52.87888|-4.13056,52.77777|-4.05334,52.71666|-4.10639,52.65084|-4.12597,52.60375|-4.08056,52.55333|-4.05972,52.48584|-4.09666,52.38583|-4.14305,52.32027|-4.19361,52.27638|-4.23166,52.24888|-4.52722,52.13083|-4.66945,52.13027|-4.73695,52.10361|-4.76778,52.06444|-4.84445,52.01388|-5.09945,51.96056|-5.23916,51.91638|-5.25889,51.87056|-5.18500,51.86958|-5.11528,51.83333|-5.10257,51.77895|-5.16111,51.76222|-5.24694,51.73027|-5.19111,51.70888|-5.00739,51.70349|-4.90875,51.71249|-4.86111,51.71334|-4.97061,51.67577|-5.02128,51.66861|-5.05139,51.62028|-5.00528,51.60638|-4.94139,51.59416|-4.89028,51.62694|-4.83569,51.64534|-4.79063,51.63340|-4.69028,51.66666|-4.64584,51.72666|-4.57445,51.73416|-4.43611,51.73722|-4.26222,51.67694|-4.19750,51.67916|-4.06614,51.66804|-4.11639,51.63416|-4.17750,51.62235|-4.25055,51.62861|-4.29208,51.60743|-4.27778,51.55666|-4.20486,51.53527|-3.94972,51.61278|-3.83792,51.61999|-3.78166,51.56750|-3.75160,51.52931|-3.67194,51.47388|-3.54250,51.39777|-3.40334,51.37972|-3.27097,51.38014|-3.16458,51.40909|-3.15166,51.45305|-3.11875,51.48750|-3.02111,51.52527|-2.95472,51.53972|-2.89278,51.53861|-2.84778,51.54500|-2.71472,51.58083|-2.66500,51.61500|-2.68666,51.71889|-2.68334,51.76957|-2.65944,51.81806|-2.77861,51.88583|-2.86639,51.92889|-2.91757,51.91569|-2.98889,51.92555|-3.04528,51.97639|-3.08500,52.01930|-3.11250,52.06945|-3.12222,52.11805|-3.07555,52.14804|-3.05125,52.23347|-2.99750,52.28139|-2.95486,52.33117|-3.02195,52.34027|-3.19611,52.41027|-3.19514,52.46722|-3.11916,52.49194|-3.02736,52.49792|-2.98028,52.53083|-3.00792,52.56902|-3.07089,52.55702|-3.11750,52.58666|-3.06666,52.63527|-3.01111,52.71166|-3.06806,52.77027|-3.13708,52.79312|-3.13014,52.88486|-3.08639,52.91611|-2.99389,52.95361|-2.85069,52.93875|-2.79278,52.90207|-2.71945,52.91902|-2.73109,52.96873|-2.77792,52.98514|-2.85695,53.03249|-2.89389,53.10416|-2.91069,53.17014|-2.95528,53.21555|-3.02000,53.24722|-3.08860,53.26001';
- break;
- case 'NC':
- $coordsAsStr[] = '-81.65876,36.60938|-81.70390,36.55513|-81.70639,36.50804|-81.74665,36.39777|-81.90723,36.30804|-82.03195,36.12694|-82.08416,36.10146|-82.12826,36.11020|-82.21500,36.15833|-82.36375,36.11347|-82.43472,36.06013|-82.46236,36.01708|-82.56006,35.96263|-82.60042,35.99638|-82.62308,36.06121|-82.73500,36.01833|-82.84612,35.94944|-82.90451,35.88819|-82.93555,35.83846|-83.16000,35.76236|-83.24222,35.71944|-83.49222,35.57111|-83.56847,35.55861|-83.64416,35.56471|-83.73499,35.56638|-83.88222,35.51791|-83.98361,35.44944|-84.03639,35.35444|-84.04964,35.29117|-84.09042,35.25986|-84.15084,35.25388|-84.20521,35.25722|-84.29284,35.22596|-84.32471,34.98701|-83.09778,35.00027|-82.77722,35.09138|-82.59639,35.14972|-82.37999,35.21500|-82.27362,35.20583|-81.41306,35.17416|-81.05915,35.15333|-80.92666,35.10695|-80.78751,34.95610|-80.79334,34.82555|-79.66777,34.80694|-79.11555,34.34527|-78.57222,33.88166|-78.51806,33.87999|-78.43721,33.89804|-78.23735,33.91986|-78.15389,33.91471|-78.06974,33.89500|-78.02597,33.88936|-77.97611,33.94276|-77.95299,33.99243|-77.94499,34.06499|-77.92728,34.11756|-77.92250,33.99194|-77.92264,33.93715|-77.88215,34.06166|-77.86222,34.15083|-77.83501,34.19194|-77.75724,34.28527|-77.68222,34.36555|-77.63667,34.39805|-77.57363,34.43694|-77.45527,34.50403|-77.38173,34.51646|-77.37905,34.56294|-77.38572,34.61260|-77.40944,34.68916|-77.38847,34.73304|-77.33097,34.63992|-77.35024,34.60099|-77.30958,34.55972|-77.09424,34.67742|-76.75994,34.76659|-76.68325,34.79749|-76.66097,34.75781|-76.62611,34.71014|-76.50063,34.73617|-76.48138,34.77638|-76.38305,34.86423|-76.34326,34.88194|-76.27181,34.96263|-76.35125,35.02221|-76.32354,34.97429|-76.45319,34.93524|-76.43395,34.98782|-76.45356,35.06676|-76.52917,35.00444|-76.63382,34.98242|-76.69722,34.94887|-76.75306,34.90526|-76.81636,34.93944|-76.89000,34.95388|-76.93180,34.96957|-76.96501,34.99777|-77.06816,35.14978|-76.97639,35.06806|-76.86722,35.00000|-76.80531,34.98559|-76.72708,35.00152|-76.60402,35.07416|-76.56555,35.11486|-76.57305,35.16013|-76.66489,35.16694|-76.56361,35.23361|-76.48750,35.22582|-76.46889,35.27166|-76.50298,35.30791|-76.83251,35.39222|-77.02305,35.48694|-77.04958,35.52694|-76.91292,35.46166|-76.65250,35.41499|-76.61611,35.45888|-76.63195,35.52249|-76.58820,35.55104|-76.51556,35.53194|-76.56711,35.48494|-76.52251,35.40416|-76.46195,35.37221|-76.13319,35.35986|-76.04111,35.42416|-76.00223,35.46610|-75.97958,35.51666|-75.89362,35.57555|-75.83834,35.56694|-75.78944,35.57138|-75.74076,35.61846|-75.72084,35.69263|-75.72084,35.81451|-75.74917,35.87791|-75.78333,35.91972|-75.85083,35.97527|-75.94333,35.91777|-75.98944,35.88054|-75.98854,35.79110|-75.99388,35.71027|-76.02875,35.65409|-76.10320,35.66041|-76.13563,35.69239|-76.04475,35.68436|-76.04167,35.74916|-76.05305,35.79361|-76.05305,35.87375|-76.02653,35.96222|-76.07751,35.99319|-76.17472,35.99596|-76.27917,35.91915|-76.37986,35.95763|-76.42014,35.97874|-76.55375,35.93971|-76.66222,35.93305|-76.72952,35.93984|-76.73392,36.04760|-76.75384,36.09477|-76.76028,36.14513|-76.74610,36.22818|-76.70458,36.24673|-76.72764,36.16736|-76.71021,36.11752|-76.69117,36.07165|-76.65979,36.03312|-76.49527,36.00958|-76.37138,36.07694|-76.37084,36.14999|-76.21417,36.09471|-76.07591,36.17910|-76.18361,36.26915|-76.19965,36.31739|-76.13986,36.28805|-76.04274,36.21974|-76.00465,36.18110|-75.95287,36.19241|-75.97604,36.31138|-75.93895,36.28381|-75.85271,36.11069|-75.79315,36.07385|-75.79639,36.11804|-75.88333,36.29554|-75.94665,36.37194|-75.98694,36.41166|-76.03473,36.49666|-76.02899,36.55000|-78.44234,36.54986|-78.56594,36.55799|-80.27556,36.55110|-81.15361,36.56499|-81.38722,36.57695|-81.65876,36.60938';
- break;
- default:
- }
- ?>
- var coordStr = <?php echo json_encode($coordsAsStr) ?>;
- jQuery.each(coordStr, function(index, value) {
- var coordXY = value.split('|');
- var coords = [];
- var points = [];
- jQuery.each(coordXY, function(i, v) {
- coords = v.split(',');
- points.push(new google.maps.LatLng(parseFloat(coords[1]), parseFloat(coords[0])));
- });
- // Construct the polygon
- new google.maps.Polygon({
- paths: points,
- strokeColor: "#888888",
- strokeOpacity: 0.8,
- strokeWeight: 1,
- fillColor: "#ff0000",
- fillOpacity: 0.15
- }).setMap(map);
- });
- }
+ header('Location: ' . WT_BASE_URL . 'module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $parent_id . '&inactive=' . $inactive);
+ }
- function loadMap(zoom, mapType) {
- var mapTyp;
+ /**
+ * Export/download the place hierarchy, or a prt of it.
+ */
+ private function adminDownload() {
+ $parent_id = (int) Filter::get('parent_id');
+ $hierarchy = $this->placeIdToHierarchy($parent_id);
+ $maxLevel = min(8, $this->getHighestLevel());
- if (mapType) {
- mapTyp = mapType;
- } else {
- mapTyp = google.maps.MapTypeId.ROADMAP;
- }
- geocoder = new google.maps.Geocoder();
- if (!zoom) {
- zoom = pl_zoom;
- }
- // Define map
- var myOptions = {
- zoom: zoom,
- center: latlng,
- mapTypeId: mapTyp,// ROADMAP, SATELLITE, HYBRID, TERRAIN
- // mapTypeId: google.maps.MapTypeId.ROADMAP, // ROADMAP, SATELLITE, HYBRID, TERRAIN
- mapTypeControlOptions: {
- style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
- },
- navigationControlOptions: {
- position: google.maps.ControlPosition.TOP_RIGHT, // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
- style: google.maps.NavigationControlStyle.SMALL // ANDROID, DEFAULT, SMALL, ZOOM_PAN
- },
- scrollwheel: true
- };
+ if (empty($hierarchy)) {
+ $filename = 'places.csv';
+ } else {
+ $filename = 'places-' . preg_replace('/[:;\/\\\(\)\{\}\[\] $]/', '_', implode('-', $hierarchy)) . '.csv';
+ }
- map = new google.maps.Map(document.querySelector('.gm-map'), myOptions);
+ header('Content-Type: text/csv; charset=utf-8');
+ header('Content-Disposition: inline; filename="' . $filename . '"');
- overlays();
+ echo '"', I18N::translate('Level'), '";';
+ echo '"', I18N::translate('Country'), '";';
+ if ($maxLevel > 0) {
+ echo '"', I18N::translate('State'), '";';
+ }
+ if ($maxLevel > 1) {
+ echo '"', I18N::translate('County'), '";';
+ }
+ if ($maxLevel > 2) {
+ echo '"', I18N::translate('City'), '";';
+ }
+ if ($maxLevel > 3) {
+ echo '"', I18N::translate('Place'), '";';
+ }
+ if ($maxLevel > 4) {
+ echo '"', I18N::translate('Place'), '";';
+ }
+ if ($maxLevel > 5) {
+ echo '"', I18N::translate('Place'), '";';
+ }
+ if ($maxLevel > 6) {
+ echo '"', I18N::translate('Place'), '";';
+ }
+ if ($maxLevel > 7) {
+ echo '"', I18N::translate('Place'), '";';
+ }
+ echo '"', I18N::translate('Longitude'), '";';
+ echo '"', I18N::translate('Latitude'), '";';
+ echo '"', I18N::translate('Zoom level'), '";';
+ echo '"', I18N::translate('Icon'), '";', WT_EOL;
+ $this->outputLevel($parent_id);
+ }
- // Close any infowindow when map is clicked
- google.maps.event.addListener(map, 'click', function() {
- infowindow.close();
- });
+ /**
+ * Save a new/updated geographic place.
+ */
+ private function adminPlaceSave() {
+ $parent_id = (int) Filter::post('parent_id');
+ $place_id = (int) Filter::post('place_id');
+ $inactive = (int) Filter::post('inactive');
+ $level = count($this->placeIdToHierarchy($parent_id));
- // Check for zoom changes
- google.maps.event.addListener(map, 'zoom_changed', function() {
- document.editplaces.NEW_ZOOM_FACTOR.value = map.zoom;
- });
+ if ($place_id === 0) {
+ Database::prepare(
+ "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
+ )->execute([
+ $this->getHighestIndex() + 1,
+ $parent_id,
+ $level,
+ Filter::post('NEW_PLACE_NAME'),
+ Filter::post('LONG_CONTROL') . Filter::post('NEW_PLACE_LONG'),
+ Filter::post('LATI_CONTROL') . Filter::post('NEW_PLACE_LATI'),
+ Filter::post('NEW_ZOOM_FACTOR'),
+ Filter::post('icon'),
+ ]);
+ } else {
+ Database::prepare(
+ "UPDATE `##placelocation` SET pl_place = ?, pl_lati = ?, pl_long = ?, pl_zoom = ?, pl_icon = ? WHERE pl_id = ?"
+ )->execute([
+ Filter::post('NEW_PLACE_NAME'),
+ Filter::post('LATI_CONTROL') . Filter::post('NEW_PLACE_LATI'),
+ Filter::post('LONG_CONTROL') . Filter::post('NEW_PLACE_LONG'),
+ Filter::post('NEW_ZOOM_FACTOR'),
+ Filter::post('icon'),
+ $place_id,
+ ]);
+ }
- // Create the Main Location Marker
- <?php
- if ($level < 3 && $place_icon != '') {
- echo 'var image = {
- "url" : WT_STATIC_URL + WT_MODULES_DIR + "googlemap/" + "' . $place_icon . '",
- "size" : new google.maps.Size(25, 15), // Image size
- "origin" : new google.maps.Point(0, 0), // Image origin
- "anchor" : new google.maps.Point(12, 15) // Image anchor
- };';
- echo 'marker = new google.maps.Marker({';
- echo 'icon: image,';
- echo 'position: latlng,';
- echo 'map: map,';
- echo 'title: pl_name,';
- echo 'draggable: true,';
- echo 'zIndex:1';
- echo '});';
- } else {
- echo 'marker = new google.maps.Marker({';
- echo 'position: latlng,';
- echo 'map: map,';
- echo 'title: pl_name,';
- echo 'draggable: true,';
- echo 'zIndex: 1';
- echo '});';
- }
- ?>
+ header('Location: ' . WT_BASE_URL . 'module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $parent_id . '&inactive=' . $inactive);
+ }
- // Set marker by clicking on map ---
- google.maps.event.addListener(map, 'click', function(event) {
- clearMarks();
- latlng = event.latLng;
- marker = new google.maps.Marker({
- position: latlng,
- map: map,
- title: pl_name,
- draggable: true,
- zIndex: 1
- });
- document.getElementById('NEW_PLACE_LATI').value = marker.getPosition().lat().toFixed(5);
- document.getElementById('NEW_PLACE_LONG').value = marker.getPosition().lng().toFixed(5);
- updateMap('flag_drag');
- var currzoom = parseInt(document.editplaces.NEW_ZOOM_FACTOR.value);
- mapType = map.getMapTypeId();
- loadMap(currzoom, mapType);
- });
+ /**
+ * Create or edit a geographic place.
+ */
+ private function adminPlaceEdit() {
+ $parent_id = (int) Filter::post('parent_id', null, Filter::get('parent_id'));
+ $place_id = (int) Filter::post('place_id', null, Filter::get('place_id'));
+ $inactive = (int) Filter::post('inactive', null, Filter::get('inactive'));
+ $where_am_i = $this->placeIdToHierarchy($place_id);
+ $level = count($where_am_i);
- // If the marker is moved, update the location fields
- google.maps.event.addListener(marker, 'drag', function() {
- document.getElementById('NEW_PLACE_LATI').value = marker.getPosition().lat().toFixed(5);
- document.getElementById('NEW_PLACE_LONG').value = marker.getPosition().lng().toFixed(5);
- });
- google.maps.event.addListener(marker, 'dragend', function() {
- updateMap('flag_drag');
- });
- }
+ $controller = new PageController;
+ $controller
+ ->setPageTitle(I18N::translate('Geographic data'))
+ ->addInlineJavascript('$("<link>", {rel: "stylesheet", type: "text/css", href: "' . WT_STATIC_URL . WT_MODULES_DIR . 'googlemap/css/wt_v3_googlemap.css"}).appendTo("head");')
+ ->pageHeader();
- function clearMarks() {
- marker.setMap(null);
- }
+ // Find (or create) the record we are editing.
+ $record =
+ Database::prepare("SELECT * FROM `##placelocation` WHERE pl_id=?")
+ ->execute([$place_id])
+ ->fetchOneRow();
- /**
- * Called when we select one of the search results.
- *
- * @param lat
- * @param lng
- */
- function setLoc(lat, lng) {
- if (lat < 0.0) {
- document.editplaces.NEW_PLACE_LATI.value = (lat.toFixed(5) * -1);
- document.editplaces.LATI_CONTROL.value = 'S';
+ $parent_record =
+ Database::prepare("SELECT * FROM `##placelocation` WHERE pl_id=?")
+ ->execute([$parent_id])
+ ->fetchOneRow();
+
+ if ($parent_record === null) {
+ $parent_record = (object) [
+ 'pl_id' => 0,
+ 'pl_parent_id' => 0,
+ 'pl_place' => '',
+ 'pl_lati' => 'N0',
+ 'pl_long' => 'E0',
+ 'pl_level' => $level - 1,
+ 'pl_icon' => '',
+ 'pl_zoom' => self::GM_MIN_ZOOM_DEFAULT,
+ ];
+ }
+
+ if ($record === null || $place_id === 0) {
+ $record = (object) [
+ 'pl_id' => 0,
+ 'pl_parent_id' => $parent_id,
+ 'pl_place' => '',
+ 'pl_lati' => 'N0',
+ 'pl_long' => 'E0',
+ 'pl_level' => $level,
+ 'pl_icon' => '',
+ 'pl_zoom' => $parent_record === null ? self::GM_MIN_ZOOM_DEFAULT : $parent_record->pl_zoom,
+ ];
+ }
+
+ // Convert to floating point for the map.
+ $latitude = (float) (str_replace(['N', 'S'], ['', '-'], $record->pl_lati));
+ $longitude = (float) (str_replace(['E', 'W'], ['', '-'], $record->pl_long));
+ if ($latitude === 0 && $longitude === 0) {
+ $latitude = (float) (str_replace(['N', 'S'], ['', '-'], $record->pl_lati));
+ $longitude = (float) (str_replace(['E', 'W'], ['', '-'], $record->pl_long));
+ }
+
+ $parent_url = 'module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $parent_id . '&inactive=' . $inactive;
+
+ $breadcrumbs = [
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ $this->getConfigLink() => $this->getTitle(),
+ ];
+ $hierarchy =
+ [0 => I18N::translate('Geographic data')] +
+ $this->placeIdToHierarchy($place_id === 0 ? $parent_id : $place_id);
+ foreach ($hierarchy as $id => $name) {
+ $breadcrumbs += ['module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $id .'&inactive=' . $inactive => Filter::escapeHtml($name)];
+ }
+ echo Bootstrap4::breadcrumbs($breadcrumbs, $place_id === 0 ? I18N::translate('Add') : I18N::translate('Edit'));
+
+ ?>
+ <script src="<?= $this->googleMapsScript() ?>"></script>
+ <script>
+ var map;
+ var marker;
+ var zoom;
+ var pl_name = '<?= Filter::escapeJs($record->pl_place) ?>';
+ var latlng = new google.maps.LatLng(<?= $latitude ?>, <?= $longitude ?>);
+ var pl_zoom = <?= $record->pl_zoom ?>;
+ var polygon1;
+ var polygon2;
+ var geocoder;
+ var mapType;
+
+ var infowindow = new google.maps.InfoWindow({});
+
+ function geocodePosition(pos) {
+ geocoder.geocode({
+ latLng: pos
+ }, function(responses) {
+ if (responses && responses.length > 0) {
+ updateMarkerAddress(responses[0].formatted_address);
} else {
- document.editplaces.NEW_PLACE_LATI.value = lat.toFixed(5);
- document.editplaces.LATI_CONTROL.value = 'N';
+ updateMarkerAddress('Cannot determine address at this location.');
}
- if (lng < 0.0) {
- document.editplaces.NEW_PLACE_LONG.value = (lng.toFixed(5) * -1);
- document.editplaces.LONG_CONTROL.value = 'W';
+ });
+ }
+
+ /**
+ * Redraw the map, centered and zoomed on the selected point.
+ *
+ * @param event
+ */
+ function updateMap(event) {
+ var point;
+ var zoom = parseInt(document.editplaces.NEW_ZOOM_FACTOR.value);
+ var latitude;
+ var longitude;
+
+ if ((document.editplaces.NEW_PLACE_LATI.value === '') ||
+ (document.editplaces.NEW_PLACE_LONG.value === '')) {
+ latitude = parseFloat(document.editplaces.parent_lati.value).toFixed(5);
+ longitude = parseFloat(document.editplaces.parent_long.value).toFixed(5);
+ point = new google.maps.LatLng(latitude, longitude);
+ } else {
+ latitude = parseFloat(document.editplaces.NEW_PLACE_LATI.value).toFixed(5);
+ longitude = parseFloat(document.editplaces.NEW_PLACE_LONG.value).toFixed(5);
+ document.editplaces.NEW_PLACE_LATI.value = latitude;
+ document.editplaces.NEW_PLACE_LONG.value = longitude;
+
+ if (event === 'flag_drag') {
+ if (longitude < 0.0 ) {
+ longitude = longitude * -1;
+ document.editplaces.NEW_PLACE_LONG.value = longitude;
+ document.editplaces.LONG_CONTROL.value = 'W';
+ } else {
+ document.editplaces.NEW_PLACE_LONG.value = longitude;
+ document.editplaces.LONG_CONTROL.value = 'E';
+ }
+ if (latitude < 0.0 ) {
+ latitude = latitude * -1;
+ document.editplaces.NEW_PLACE_LATI.value = latitude;
+ document.editplaces.LATI_CONTROL.value = 'S';
+ } else {
+ document.editplaces.NEW_PLACE_LATI.value = latitude;
+ document.editplaces.LATI_CONTROL.value = 'N';
+ }
+
+ if (document.editplaces.LATI_CONTROL.value === 'S') {
+ latitude = latitude * -1;
+ }
+ if (document.editplaces.LONG_CONTROL.value === 'W') {
+ longitude = longitude * -1;
+ }
+ point = new google.maps.LatLng(latitude, longitude);
} else {
- document.editplaces.NEW_PLACE_LONG.value = lng.toFixed(5);
- document.editplaces.LONG_CONTROL.value = 'E';
+ if (latitude < 0.0) {
+ latitude = latitude * -1;
+ document.editplaces.NEW_PLACE_LATI.value = latitude;
+ }
+ if (longitude < 0.0) {
+ longitude = longitude * -1;
+ document.editplaces.NEW_PLACE_LONG.value = longitude;
+ }
+ if (document.editplaces.LATI_CONTROL.value === 'S') {
+ latitude = latitude * -1;
+ }
+ if (document.editplaces.LONG_CONTROL.value === 'W') {
+ longitude = longitude * -1;
+ }
+ point = new google.maps.LatLng(latitude, longitude);
}
- new google.maps.LatLng (lat.toFixed(5), lng.toFixed(5));
- infowindow.close();
- updateMap();
}
- function createMarker(i, point, name) {
-
- var image = {
- url: WT_STATIC_URL + WT_MODULES_DIR + 'googlemap/images/marker_yellow.png',
- size: new google.maps.Size(20, 34), // Image size
- origin: new google.maps.Point(0, 0), // Image origin
- anchor: new google.maps.Point(10, 34) // Image anchor
- };
+ map.setCenter(point);
+ map.setZoom(zoom);
+ marker.setPosition(point);
+ }
- var marker = new google.maps.Marker({
- icon: image,
- map: map,
- position: point,
- zIndex: 0
- });
+ // === Create Borders for the UK Countries =========================================================
+ function overlays() {
+ // Define place LatLng arrays
- google.maps.event.addListener(marker, 'click', function() {
- infowindow.close();
- infowindow.setContent(name);
- infowindow.open(map, marker);
+ <?php
+ $coordsAsStr = [];
+ switch ($record->pl_place) {
+ case 'England':
+ $coordsAsStr[] = '-4.74361,50.66750|-4.78361,50.59361|-4.91584,50.57722|-5.01750,50.54264|-5.02569,50.47271|-5.04729,50.42750|-5.15208,50.34374|-5.26805,50.27389|-5.43194,50.19326|-5.49584,50.21695|-5.54639,50.20527|-5.71000,50.12916|-5.71681,50.06083|-5.66174,50.03631|-5.58278,50.04777|-5.54166,50.07055|-5.53416,50.11569|-5.47055,50.12499|-5.33361,50.09138|-5.27666,50.05972|-5.25674,50.00514|-5.19306,49.95527|-5.16070,50.00319|-5.06555,50.03750|-5.07090,50.08166|-5.04806,50.17111|-4.95278,50.19333|-4.85750,50.23166|-4.76250,50.31138|-4.67861,50.32583|-4.54334,50.32222|-4.48278,50.32583|-4.42972,50.35139|-4.38000,50.36388|-4.16555,50.37028|-4.11139,50.33027|-4.05708,50.29791|-3.94389,50.31346|-3.87764,50.28139|-3.83653,50.22972|-3.78944,50.21222|-3.70666,50.20972|-3.65195,50.23111|-3.55139,50.43833|-3.49416,50.54639|-3.46181,50.58792|-3.41139,50.61610|-3.24416,50.67444|-3.17347,50.68833|-3.09445,50.69222|-2.97806,50.70638|-2.92750,50.73125|-2.88278,50.73111|-2.82305,50.72027|-2.77139,50.70861|-2.66195,50.67334|-2.56305,50.63222|-2.45861,50.57500|-2.44666,50.62639|-2.39097,50.64166|-2.19722,50.62611|-2.12195,50.60722|-2.05445,50.58569|-1.96437,50.59674|-1.95441,50.66536|-2.06681,50.71430|-1.93416,50.71277|-1.81639,50.72306|-1.68445,50.73888|-1.59278,50.72416|-1.33139,50.79138|-1.11695,50.80694|-1.15889,50.84083|-1.09445,50.84584|-0.92842,50.83966|-0.86584,50.79965|-0.90826,50.77396|-0.78187,50.72722|-0.74611,50.76583|-0.67528,50.78111|-0.57722,50.79527|-0.25500,50.82638|-0.19084,50.82583|-0.13805,50.81833|0.05695,50.78083|0.12334,50.75944|0.22778,50.73944|0.28695,50.76500|0.37195,50.81638|0.43084,50.83111|0.56722,50.84777|0.67889,50.87681|0.71639,50.90500|0.79334,50.93610|0.85666,50.92556|0.97125,50.98111|0.99778,51.01903|1.04555,51.04944|1.10028,51.07361|1.26250,51.10166|1.36889,51.13583|1.41111,51.20111|1.42750,51.33111|1.38556,51.38777|1.19195,51.37861|1.05278,51.36722|0.99916,51.34777|0.90806,51.34069|0.70416,51.37749|0.61972,51.38304|0.55945,51.40596|0.64236,51.44042|0.69750,51.47084|0.59195,51.48777|0.53611,51.48806|0.48916,51.48445|0.45215,51.45562|0.38894,51.44822|0.46500,51.50306|0.65195,51.53680|0.76695,51.52138|0.82084,51.53556|0.87528,51.56110|0.95250,51.60923|0.94695,51.72556|0.90257,51.73465|0.86306,51.71166|0.76140,51.69164|0.70111,51.71847|0.86211,51.77361|0.93236,51.80583|0.98278,51.82527|1.03569,51.77416|1.08834,51.77056|1.13222,51.77694|1.18139,51.78972|1.22361,51.80888|1.26611,51.83916|1.28097,51.88096|1.20834,51.95083|1.16347,52.02361|1.27750,51.98555|1.33125,51.92875|1.39028,51.96999|1.58736,52.08388|1.63000,52.19527|1.68576,52.32630|1.73028,52.41138|1.74945,52.45583|1.74590,52.62021|1.70250,52.71583|1.64528,52.77111|1.50361,52.83749|1.43222,52.87472|1.35250,52.90972|1.28222,52.92750|1.18389,52.93889|0.99472,52.95111|0.94222,52.95083|0.88472,52.96638|0.66722,52.97611|0.54778,52.96618|0.49139,52.93430|0.44431,52.86569|0.42903,52.82403|0.36334,52.78027|0.21778,52.80694|0.16125,52.86250|0.05778,52.88916|0.00211,52.87985|0.03222,52.91722|0.20389,53.02805|0.27666,53.06694|0.33916,53.09236|0.35389,53.18722|0.33958,53.23472|0.23555,53.39944|0.14347,53.47527|0.08528,53.48638|0.02694,53.50972|-0.10084,53.57306|-0.20722,53.63083|-0.26445,53.69083|-0.30166,53.71319|-0.39022,53.70794|-0.51972,53.68527|-0.71653,53.69638|-0.65445,53.72527|-0.60584,53.72972|-0.54916,53.70611|-0.42261,53.71755|-0.35728,53.73056|-0.29389,53.73666|-0.23139,53.72166|-0.10584,53.63166|-0.03472,53.62555|0.04416,53.63916|0.08916,53.62666|0.14945,53.58847|0.12639,53.64527|0.06264,53.70389|-0.12750,53.86388|-0.16916,53.91847|-0.21222,54.00833|-0.20569,54.05153|-0.16111,54.08806|-0.11694,54.13222|-0.20053,54.15171|-0.26250,54.17444|-0.39334,54.27277|-0.42166,54.33222|-0.45750,54.37694|-0.51847,54.44749|-0.56472,54.48000|-0.87584,54.57027|-1.06139,54.61722|-1.16528,54.64972|-1.30445,54.77138|-1.34556,54.87138|-1.41278,54.99944|-1.48292,55.08625|-1.51500,55.14972|-1.56584,55.28722|-1.58097,55.48361|-1.63597,55.58194|-1.69000,55.60556|-1.74695,55.62499|-1.81764,55.63306|-1.97681,55.75416|-2.02166,55.80611|-2.08361,55.78054|-2.22000,55.66499|-2.27916,55.64472|-2.27416,55.57527|-2.21528,55.50583|-2.18278,55.45985|-2.21236,55.42777|-2.46305,55.36111|-2.63055,55.25500|-2.69945,55.17722|-2.96278,55.03889|-3.01500,55.05222|-3.05103,54.97986|-3.13292,54.93139|-3.20861,54.94944|-3.28931,54.93792|-3.39166,54.87639|-3.42916,54.81555|-3.56916,54.64249|-3.61306,54.48861|-3.49305,54.40333|-3.43389,54.34806|-3.41056,54.28014|-3.38055,54.24444|-3.21472,54.09555|-3.15222,54.08194|-2.93097,54.15333|-2.81361,54.22277|-2.81750,54.14277|-2.83361,54.08500|-2.93250,53.95055|-3.05264,53.90764|-3.03708,53.74944|-2.99278,53.73277|-2.89979,53.72499|-2.97729,53.69382|-3.07306,53.59805|-3.10563,53.55993|-3.00678,53.41738|-2.95389,53.36027|-2.85736,53.32083|-2.70493,53.35062|-2.77639,53.29250|-2.89972,53.28916|-2.94250,53.31056|-3.02889,53.38191|-3.07248,53.40936|-3.16695,53.35708|-3.12611,53.32500|-3.08860,53.26001|-3.02000,53.24722|-2.95528,53.21555|-2.91069,53.17014|-2.89389,53.10416|-2.85695,53.03249|-2.77792,52.98514|-2.73109,52.96873|-2.71945,52.91902|-2.79278,52.90207|-2.85069,52.93875|-2.99389,52.95361|-3.08639,52.91611|-3.13014,52.88486|-3.13708,52.79312|-3.06806,52.77027|-3.01111,52.71166|-3.06666,52.63527|-3.11750,52.58666|-3.07089,52.55702|-3.00792,52.56902|-2.98028,52.53083|-3.02736,52.49792|-3.11916,52.49194|-3.19514,52.46722|-3.19611,52.41027|-3.02195,52.34027|-2.95486,52.33117|-2.99750,52.28139|-3.05125,52.23347|-3.07555,52.14804|-3.12222,52.11805|-3.11250,52.06945|-3.08500,52.01930|-3.04528,51.97639|-2.98889,51.92555|-2.91757,51.91569|-2.86639,51.92889|-2.77861,51.88583|-2.65944,51.81806|-2.68334,51.76957|-2.68666,51.71889|-2.66500,51.61500|-2.62916,51.64416|-2.57889,51.67777|-2.46056,51.74666|-2.40389,51.74041|-2.47166,51.72445|-2.55305,51.65722|-2.65334,51.56389|-2.77055,51.48916|-2.85278,51.44472|-2.96000,51.37499|-3.00695,51.30722|-3.01278,51.25632|-3.02834,51.20611|-3.30139,51.18111|-3.39361,51.18138|-3.43729,51.20638|-3.50722,51.22333|-3.57014,51.23027|-3.63222,51.21805|-3.70028,51.23000|-3.79250,51.23916|-3.88389,51.22416|-3.98472,51.21695|-4.11666,51.21222|-4.22805,51.18777|-4.22028,51.11054|-4.23702,51.04659|-4.30361,51.00416|-4.37639,50.99110|-4.42736,51.00958|-4.47445,51.01416|-4.52132,51.01424|-4.54334,50.92694|-4.56139,50.77625|-4.65139,50.71527|-4.74361,50.66750';
+ break;
+ case 'Scotland':
+ $coordsAsStr[] = '-2.02166,55.80611|-2.07972,55.86722|-2.13028,55.88583|-2.26028,55.91861|-2.37528,55.95694|-2.65722,56.05972|-2.82028,56.05694|-2.86618,56.02840|-2.89555,55.98861|-2.93500,55.96944|-3.01805,55.94944|-3.06750,55.94444|-3.25472,55.97166|-3.45472,55.99194|-3.66416,56.00652|-3.73722,56.05555|-3.57139,56.05360|-3.44111,56.01916|-3.39584,56.01083|-3.34403,56.02333|-3.13903,56.11084|-2.97611,56.19472|-2.91666,56.20499|-2.84695,56.18638|-2.78805,56.18749|-2.67937,56.21465|-2.58403,56.28264|-2.67208,56.32277|-2.76861,56.33180|-2.81528,56.37360|-2.81208,56.43958|-2.91653,56.45014|-2.99555,56.41416|-3.19042,56.35958|-3.27805,56.35750|-3.04055,56.45472|-2.95861,56.45611|-2.72084,56.48888|-2.64084,56.52250|-2.53126,56.57611|-2.48861,56.61416|-2.47805,56.71527|-2.39000,56.77166|-2.31986,56.79638|-2.21972,56.86777|-2.19708,56.94388|-2.16695,57.00055|-2.09334,57.07027|-2.05416,57.21861|-1.95889,57.33250|-1.85584,57.39889|-1.77334,57.45805|-1.78139,57.50555|-1.82195,57.57861|-1.86000,57.62138|-1.92972,57.67777|-2.02222,57.69388|-2.07555,57.69944|-2.14028,57.69056|-2.18611,57.66861|-2.39626,57.66638|-2.51000,57.67166|-2.78639,57.70222|-2.89806,57.70694|-2.96750,57.68027|-3.03847,57.66249|-3.12334,57.67166|-3.22334,57.69166|-3.28625,57.72499|-3.33972,57.72333|-3.48805,57.70945|-3.52222,57.66333|-3.59542,57.63666|-3.64063,57.63881|-3.75414,57.62504|-4.03986,57.55569|-4.19666,57.48584|-4.22889,57.51554|-4.17945,57.56249|-4.11139,57.59833|-4.08078,57.66533|-4.19139,57.67139|-4.25945,57.65527|-4.34361,57.60777|-4.41639,57.60166|-4.29666,57.67444|-4.08528,57.72611|-4.01908,57.70226|-3.96861,57.70250|-3.86556,57.76861|-3.81945,57.80458|-3.80681,57.85819|-3.85055,57.82000|-3.92639,57.80749|-4.04322,57.81438|-4.14973,57.82527|-4.29750,57.84638|-4.36250,57.89777|-4.24306,57.87028|-4.10666,57.85195|-4.01500,57.86777|-3.99166,57.90611|-3.99695,57.95056|-3.84500,58.02000|-3.56611,58.13916|-3.51319,58.16374|-3.45916,58.20305|-3.42028,58.24361|-3.33750,58.27694|-3.20555,58.30625|-3.10972,58.38166|-3.05792,58.45083|-3.02264,58.64653|-3.17639,58.64944|-3.35389,58.66055|-3.36931,58.59555|-3.57611,58.62194|-3.66028,58.61972|-3.71166,58.60374|-3.78264,58.56750|-3.84834,58.56000|-4.08056,58.55527|-4.27722,58.53361|-4.43653,58.54902|-4.50666,58.56777|-4.56055,58.57584|-4.59910,58.53027|-4.66805,58.48833|-4.76146,58.44604|-4.70195,58.50999|-4.70166,58.55861|-4.77014,58.60264|-5.00153,58.62416|-5.10945,58.50833|-5.16472,58.32527|-5.12639,58.28750|-5.07166,58.26472|-5.20361,58.25083|-5.39764,58.25055|-5.27389,58.11722|-5.31514,58.06416|-5.38416,58.08361|-5.45285,58.07416|-5.39805,58.03111|-5.26278,57.97111|-5.19334,57.95069|-5.12750,57.86944|-5.21750,57.90084|-5.33861,57.92083|-5.42876,57.90104|-5.45750,57.85889|-5.64445,57.89972|-5.62555,57.85222|-5.58153,57.81945|-5.60674,57.76618|-5.66305,57.78889|-5.71695,57.86944|-5.76695,57.86472|-5.81708,57.81944|-5.81084,57.63958|-5.69555,57.55944|-5.64361,57.55222|-5.53084,57.52833|-5.65305,57.50875|-5.75000,57.54834|-5.81569,57.57923|-5.85042,57.54972|-5.86695,57.46777|-5.81806,57.36250|-5.75111,57.34333|-5.50334,57.40111|-5.45126,57.41805|-5.49250,57.37083|-5.59884,57.33049|-5.57116,57.28411|-5.51266,57.27745|-5.40514,57.23097|-5.44972,57.22138|-5.49472,57.23888|-5.56066,57.25477|-5.64611,57.23499|-5.64751,57.16161|-5.55028,57.11639|-5.48166,57.11222|-5.40305,57.11062|-5.55945,57.09250|-5.65111,57.11611|-5.72472,57.11306|-5.77361,57.04556|-5.63139,56.98499|-5.56916,56.98972|-5.52403,56.99735|-5.57916,56.98000|-5.64611,56.97222|-5.73374,57.00909|-5.82584,57.00346|-5.91958,56.88708|-5.86528,56.87944|-5.74278,56.89374|-5.66292,56.86924|-5.73306,56.83916|-5.78584,56.83955|-5.85590,56.81430|-5.80208,56.79180|-5.84958,56.74444|-5.90500,56.75666|-5.96694,56.78027|-6.14000,56.75777|-6.19208,56.74888|-6.23452,56.71673|-6.19139,56.67972|-5.91916,56.67388|-5.82622,56.69156|-5.73945,56.71166|-5.55240,56.68886|-5.64861,56.68027|-5.69916,56.68278|-5.88261,56.65666|-5.97472,56.65138|-5.99584,56.61138|-5.93056,56.56972|-5.88416,56.55333|-5.79056,56.53805|-5.67695,56.49389|-5.56389,56.54056|-5.36334,56.66195|-5.23416,56.74333|-5.13236,56.79403|-5.31473,56.65666|-5.37405,56.55925|-5.31826,56.55633|-5.25080,56.55753|-5.37718,56.52112|-5.39866,56.47866|-5.19111,56.46194|-5.11556,56.51277|-5.07014,56.56069|-5.13555,56.48499|-5.22084,56.43583|-5.32764,56.43574|-5.42439,56.43091|-5.52611,56.37360|-5.57139,56.32833|-5.59653,56.25695|-5.57389,56.16000|-5.52000,56.16485|-5.56334,56.11333|-5.60139,56.07638|-5.64222,56.04305|-5.66039,55.98263|-5.62555,56.02055|-5.58014,56.01319|-5.63361,55.96611|-5.67697,55.88844|-5.64750,55.78139|-5.60986,55.75930|-5.66916,55.66166|-5.70166,55.58861|-5.71805,55.51500|-5.75916,55.41750|-5.79528,55.36027|-5.78166,55.29902|-5.73778,55.29222|-5.56694,55.31666|-5.51528,55.36347|-5.55520,55.41440|-5.48639,55.64306|-5.44597,55.70680|-5.38000,55.75027|-5.41889,55.90666|-5.39924,55.99972|-5.33895,56.03456|-5.30594,56.06922|-5.23889,56.11889|-5.03222,56.23250|-4.92229,56.27111|-4.97416,56.23333|-5.07222,56.18695|-5.20069,56.11861|-5.30906,56.00570|-5.34000,55.90201|-5.29250,55.84750|-5.20805,55.84444|-5.22458,55.90175|-5.17334,55.92916|-5.11000,55.90306|-5.01222,55.86694|-4.96195,55.88000|-4.89824,55.98145|-4.84623,56.08632|-4.86636,56.03178|-4.85461,55.98648|-4.77659,55.97977|-4.62723,55.94555|-4.52305,55.91861|-4.70972,55.93403|-4.75166,55.94611|-4.82406,55.94950|-4.87826,55.93653|-4.91639,55.70083|-4.87584,55.68194|-4.81361,55.64555|-4.68722,55.59750|-4.61361,55.49069|-4.63958,55.44264|-4.68250,55.43388|-4.74847,55.41055|-4.83715,55.31882|-4.84778,55.26944|-4.86542,55.22340|-4.93500,55.17860|-5.01250,55.13347|-5.05361,55.04902|-5.17834,54.98888|-5.18563,54.93622|-5.17000,54.89111|-5.11666,54.83180|-5.00500,54.76333|-4.96229,54.68125|-4.92250,54.64055|-4.85723,54.62958|-4.96076,54.79687|-4.92431,54.83708|-4.85222,54.86861|-4.80125,54.85556|-4.74055,54.82166|-4.68084,54.79972|-4.59861,54.78027|-4.55792,54.73903|-4.49639,54.69888|-4.37584,54.67666|-4.34569,54.70916|-4.35973,54.77111|-4.41111,54.82583|-4.42445,54.88152|-4.38479,54.90555|-4.35056,54.85903|-4.09555,54.76777|-3.95361,54.76749|-3.86972,54.80527|-3.81222,54.84888|-3.69250,54.88110|-3.61584,54.87527|-3.57111,54.99083|-3.44528,54.98638|-3.36056,54.97138|-3.14695,54.96500|-3.05103,54.97986|-3.01500,55.05222|-2.96278,55.03889|-2.69945,55.17722|-2.63055,55.25500|-2.46305,55.36111|-2.21236,55.42777|-2.18278,55.45985|-2.21528,55.50583|-2.27416,55.57527|-2.27916,55.64472|-2.22000,55.66499|-2.08361,55.78054|-2.02166,55.80611';
+ break;
+ case 'Ireland':
+ $coordsAsStr[] = '-8.17166,54.46388|-8.06555,54.37277|-7.94139,54.29944|-7.87576,54.28499|-7.86834,54.22764|-7.81805,54.19916|-7.69972,54.20250|-7.55945,54.12694|-7.31334,54.11250|-7.14584,54.22527|-7.17555,54.28916|-7.16084,54.33666|-7.05834,54.41000|-6.97445,54.40166|-6.92695,54.37916|-6.87305,54.34208|-6.85111,54.28972|-6.73473,54.18361|-6.65556,54.06527|-6.60584,54.04444|-6.44750,54.05833|-6.33889,54.11555|-6.26697,54.09983|-6.17403,54.07222|-6.10834,54.03638|-6.04389,54.03139|-5.96834,54.06389|-5.88500,54.11639|-5.87347,54.20916|-5.82500,54.23958|-5.74611,54.24806|-5.65556,54.22701|-5.60834,54.24972|-5.55916,54.29084|-5.57334,54.37704|-5.64502,54.49267|-5.70472,54.53361|-5.68055,54.57306|-5.59972,54.54194|-5.55097,54.50083|-5.54216,54.44903|-5.54643,54.40527|-5.50672,54.36444|-5.46111,54.38555|-5.43132,54.48596|-5.47945,54.53638|-5.53521,54.65090|-5.57431,54.67722|-5.62916,54.67945|-5.73674,54.67383|-5.80305,54.66138|-5.88257,54.60652|-5.92445,54.63180|-5.86681,54.68972|-5.81903,54.70972|-5.74672,54.72452|-5.68775,54.76335|-5.70931,54.83166|-5.74694,54.85361|-5.79139,54.85139|-6.03611,55.05778|-6.04250,55.10277|-6.03444,55.15458|-6.10125,55.20945|-6.14584,55.22069|-6.25500,55.21194|-6.37639,55.23916|-6.51556,55.23305|-6.61334,55.20722|-6.73028,55.18027|-6.82472,55.16806|-6.88972,55.16777|-6.96695,55.15611|-6.99416,55.11027|-7.05139,55.04680|-7.09500,55.03694|-7.25251,55.07059|-7.32639,55.04527|-7.40639,54.95333|-7.45805,54.85777|-7.55334,54.76277|-7.73916,54.71054|-7.82576,54.73416|-7.92639,54.70054|-7.85236,54.63388|-7.77750,54.62694|-7.83361,54.55389|-7.95084,54.53222|-8.04695,54.50722|-8.17166,54.46388';
+ break;
+ case 'Wales':
+ $coordsAsStr[] = '-3.08860,53.26001|-3.33639,53.34722|-3.38806,53.34361|-3.60986,53.27944|-3.73014,53.28944|-3.85445,53.28444|-4.01861,53.23750|-4.06639,53.22639|-4.15334,53.22556|-4.19639,53.20611|-4.33028,53.11222|-4.36097,53.02888|-4.55278,52.92889|-4.61889,52.90916|-4.72195,52.83611|-4.72778,52.78139|-4.53945,52.79306|-4.47722,52.85500|-4.41416,52.88472|-4.31292,52.90499|-4.23334,52.91499|-4.13569,52.87888|-4.13056,52.77777|-4.05334,52.71666|-4.10639,52.65084|-4.12597,52.60375|-4.08056,52.55333|-4.05972,52.48584|-4.09666,52.38583|-4.14305,52.32027|-4.19361,52.27638|-4.23166,52.24888|-4.52722,52.13083|-4.66945,52.13027|-4.73695,52.10361|-4.76778,52.06444|-4.84445,52.01388|-5.09945,51.96056|-5.23916,51.91638|-5.25889,51.87056|-5.18500,51.86958|-5.11528,51.83333|-5.10257,51.77895|-5.16111,51.76222|-5.24694,51.73027|-5.19111,51.70888|-5.00739,51.70349|-4.90875,51.71249|-4.86111,51.71334|-4.97061,51.67577|-5.02128,51.66861|-5.05139,51.62028|-5.00528,51.60638|-4.94139,51.59416|-4.89028,51.62694|-4.83569,51.64534|-4.79063,51.63340|-4.69028,51.66666|-4.64584,51.72666|-4.57445,51.73416|-4.43611,51.73722|-4.26222,51.67694|-4.19750,51.67916|-4.06614,51.66804|-4.11639,51.63416|-4.17750,51.62235|-4.25055,51.62861|-4.29208,51.60743|-4.27778,51.55666|-4.20486,51.53527|-3.94972,51.61278|-3.83792,51.61999|-3.78166,51.56750|-3.75160,51.52931|-3.67194,51.47388|-3.54250,51.39777|-3.40334,51.37972|-3.27097,51.38014|-3.16458,51.40909|-3.15166,51.45305|-3.11875,51.48750|-3.02111,51.52527|-2.95472,51.53972|-2.89278,51.53861|-2.84778,51.54500|-2.71472,51.58083|-2.66500,51.61500|-2.68666,51.71889|-2.68334,51.76957|-2.65944,51.81806|-2.77861,51.88583|-2.86639,51.92889|-2.91757,51.91569|-2.98889,51.92555|-3.04528,51.97639|-3.08500,52.01930|-3.11250,52.06945|-3.12222,52.11805|-3.07555,52.14804|-3.05125,52.23347|-2.99750,52.28139|-2.95486,52.33117|-3.02195,52.34027|-3.19611,52.41027|-3.19514,52.46722|-3.11916,52.49194|-3.02736,52.49792|-2.98028,52.53083|-3.00792,52.56902|-3.07089,52.55702|-3.11750,52.58666|-3.06666,52.63527|-3.01111,52.71166|-3.06806,52.77027|-3.13708,52.79312|-3.13014,52.88486|-3.08639,52.91611|-2.99389,52.95361|-2.85069,52.93875|-2.79278,52.90207|-2.71945,52.91902|-2.73109,52.96873|-2.77792,52.98514|-2.85695,53.03249|-2.89389,53.10416|-2.91069,53.17014|-2.95528,53.21555|-3.02000,53.24722|-3.08860,53.26001';
+ break;
+ case 'NC':
+ $coordsAsStr[] = '-81.65876,36.60938|-81.70390,36.55513|-81.70639,36.50804|-81.74665,36.39777|-81.90723,36.30804|-82.03195,36.12694|-82.08416,36.10146|-82.12826,36.11020|-82.21500,36.15833|-82.36375,36.11347|-82.43472,36.06013|-82.46236,36.01708|-82.56006,35.96263|-82.60042,35.99638|-82.62308,36.06121|-82.73500,36.01833|-82.84612,35.94944|-82.90451,35.88819|-82.93555,35.83846|-83.16000,35.76236|-83.24222,35.71944|-83.49222,35.57111|-83.56847,35.55861|-83.64416,35.56471|-83.73499,35.56638|-83.88222,35.51791|-83.98361,35.44944|-84.03639,35.35444|-84.04964,35.29117|-84.09042,35.25986|-84.15084,35.25388|-84.20521,35.25722|-84.29284,35.22596|-84.32471,34.98701|-83.09778,35.00027|-82.77722,35.09138|-82.59639,35.14972|-82.37999,35.21500|-82.27362,35.20583|-81.41306,35.17416|-81.05915,35.15333|-80.92666,35.10695|-80.78751,34.95610|-80.79334,34.82555|-79.66777,34.80694|-79.11555,34.34527|-78.57222,33.88166|-78.51806,33.87999|-78.43721,33.89804|-78.23735,33.91986|-78.15389,33.91471|-78.06974,33.89500|-78.02597,33.88936|-77.97611,33.94276|-77.95299,33.99243|-77.94499,34.06499|-77.92728,34.11756|-77.92250,33.99194|-77.92264,33.93715|-77.88215,34.06166|-77.86222,34.15083|-77.83501,34.19194|-77.75724,34.28527|-77.68222,34.36555|-77.63667,34.39805|-77.57363,34.43694|-77.45527,34.50403|-77.38173,34.51646|-77.37905,34.56294|-77.38572,34.61260|-77.40944,34.68916|-77.38847,34.73304|-77.33097,34.63992|-77.35024,34.60099|-77.30958,34.55972|-77.09424,34.67742|-76.75994,34.76659|-76.68325,34.79749|-76.66097,34.75781|-76.62611,34.71014|-76.50063,34.73617|-76.48138,34.77638|-76.38305,34.86423|-76.34326,34.88194|-76.27181,34.96263|-76.35125,35.02221|-76.32354,34.97429|-76.45319,34.93524|-76.43395,34.98782|-76.45356,35.06676|-76.52917,35.00444|-76.63382,34.98242|-76.69722,34.94887|-76.75306,34.90526|-76.81636,34.93944|-76.89000,34.95388|-76.93180,34.96957|-76.96501,34.99777|-77.06816,35.14978|-76.97639,35.06806|-76.86722,35.00000|-76.80531,34.98559|-76.72708,35.00152|-76.60402,35.07416|-76.56555,35.11486|-76.57305,35.16013|-76.66489,35.16694|-76.56361,35.23361|-76.48750,35.22582|-76.46889,35.27166|-76.50298,35.30791|-76.83251,35.39222|-77.02305,35.48694|-77.04958,35.52694|-76.91292,35.46166|-76.65250,35.41499|-76.61611,35.45888|-76.63195,35.52249|-76.58820,35.55104|-76.51556,35.53194|-76.56711,35.48494|-76.52251,35.40416|-76.46195,35.37221|-76.13319,35.35986|-76.04111,35.42416|-76.00223,35.46610|-75.97958,35.51666|-75.89362,35.57555|-75.83834,35.56694|-75.78944,35.57138|-75.74076,35.61846|-75.72084,35.69263|-75.72084,35.81451|-75.74917,35.87791|-75.78333,35.91972|-75.85083,35.97527|-75.94333,35.91777|-75.98944,35.88054|-75.98854,35.79110|-75.99388,35.71027|-76.02875,35.65409|-76.10320,35.66041|-76.13563,35.69239|-76.04475,35.68436|-76.04167,35.74916|-76.05305,35.79361|-76.05305,35.87375|-76.02653,35.96222|-76.07751,35.99319|-76.17472,35.99596|-76.27917,35.91915|-76.37986,35.95763|-76.42014,35.97874|-76.55375,35.93971|-76.66222,35.93305|-76.72952,35.93984|-76.73392,36.04760|-76.75384,36.09477|-76.76028,36.14513|-76.74610,36.22818|-76.70458,36.24673|-76.72764,36.16736|-76.71021,36.11752|-76.69117,36.07165|-76.65979,36.03312|-76.49527,36.00958|-76.37138,36.07694|-76.37084,36.14999|-76.21417,36.09471|-76.07591,36.17910|-76.18361,36.26915|-76.19965,36.31739|-76.13986,36.28805|-76.04274,36.21974|-76.00465,36.18110|-75.95287,36.19241|-75.97604,36.31138|-75.93895,36.28381|-75.85271,36.11069|-75.79315,36.07385|-75.79639,36.11804|-75.88333,36.29554|-75.94665,36.37194|-75.98694,36.41166|-76.03473,36.49666|-76.02899,36.55000|-78.44234,36.54986|-78.56594,36.55799|-80.27556,36.55110|-81.15361,36.56499|-81.38722,36.57695|-81.65876,36.60938';
+ break;
+ default:
+ }
+ ?>
+ var coordStr = <?= json_encode($coordsAsStr) ?>;
+ jQuery.each(coordStr, function(index, value) {
+ var coordXY = value.split('|');
+ var coords = [];
+ var points = [];
+ jQuery.each(coordXY, function(i, v) {
+ coords = v.split(',');
+ points.push(new google.maps.LatLng(parseFloat(coords[1]), parseFloat(coords[0])));
});
+ // Construct the polygon
+ new google.maps.Polygon({
+ paths: points,
+ strokeColor: "#888888",
+ strokeOpacity: 0.8,
+ strokeWeight: 1,
+ fillColor: "#ff0000",
+ fillOpacity: 0.15
+ }).setMap(map);
+ });
+ }
- google.maps.event.addListener(map, 'click', function() {
- infowindow.close();
- });
+ function loadMap(zoom, mapType) {
+ var mapTyp;
- return marker;
+ if (mapType) {
+ mapTyp = mapType;
+ } else {
+ mapTyp = google.maps.MapTypeId.ROADMAP;
+ }
+ geocoder = new google.maps.Geocoder();
+ if (!zoom) {
+ zoom = pl_zoom;
}
+ // Define map
+ var myOptions = {
+ zoom: zoom,
+ center: latlng,
+ mapTypeId: mapTyp,// ROADMAP, SATELLITE, HYBRID, TERRAIN
+ // mapTypeId: google.maps.MapTypeId.ROADMAP, // ROADMAP, SATELLITE, HYBRID, TERRAIN
+ mapTypeControlOptions: {
+ style: google.maps.MapTypeControlStyle.DROPDOWN_MENU // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
+ },
+ navigationControlOptions: {
+ position: google.maps.ControlPosition.TOP_RIGHT, // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
+ style: google.maps.NavigationControlStyle.SMALL // ANDROID, DEFAULT, SMALL, ZOOM_PAN
+ },
+ scrollwheel: true
+ };
+
+ map = new google.maps.Map(document.querySelector('.gm-map'), myOptions);
+
+ overlays();
- function change_icon() {
- window.open('module.php?mod=googlemap&mod_action=flags&countrySelected=<?php echo $selected_country ?>', '_blank', indx_window_specs);
- return false;
+ // Close any infowindow when map is clicked
+ google.maps.event.addListener(map, 'click', function() {
+ infowindow.close();
+ });
+
+ // Check for zoom changes
+ google.maps.event.addListener(map, 'zoom_changed', function() {
+ document.editplaces.NEW_ZOOM_FACTOR.value = map.zoom;
+ });
+
+ // Create the Main Location Marker
+ <?php
+ if ($level < 3 && $record->pl_icon != '') {
+ echo 'var image = {
+ "url" : WT_STATIC_URL + WT_MODULES_DIR + "googlemap/" + "' . $record->pl_icon . '",
+ "size" : new google.maps.Size(25, 15),
+ "origin" : new google.maps.Point(0, 0),
+ "anchor" : new google.maps.Point(12, 15)
+ };';
+ echo 'marker = new google.maps.Marker({';
+ echo 'icon: image,';
+ echo 'position: latlng,';
+ echo 'map: map,';
+ echo 'title: pl_name,';
+ echo 'draggable: true,';
+ echo 'zIndex:1';
+ echo '});';
+ } else {
+ echo 'marker = new google.maps.Marker({';
+ echo 'position: latlng,';
+ echo 'map: map,';
+ echo 'title: pl_name,';
+ echo 'draggable: true,';
+ echo 'zIndex: 1';
+ echo '});';
}
+ ?>
+
+ // Set marker by clicking on map ---
+ google.maps.event.addListener(map, 'click', function(event) {
+ clearMarks();
+ latlng = event.latLng;
+ marker = new google.maps.Marker({
+ position: latlng,
+ map: map,
+ title: pl_name,
+ draggable: true,
+ zIndex: 1
+ });
+ document.getElementById('NEW_PLACE_LATI').value = marker.getPosition().lat().toFixed(5);
+ document.getElementById('NEW_PLACE_LONG').value = marker.getPosition().lng().toFixed(5);
+ updateMap('flag_drag');
+ var currzoom = parseInt(document.editplaces.NEW_ZOOM_FACTOR.value);
+ mapType = map.getMapTypeId();
+ loadMap(currzoom, mapType);
+ });
- function remove_icon() {
- document.editplaces.icon.value = '';
- document.getElementById('flagsDiv').innerHTML = '<a href="#" onclick="change_icon();return false;"><?php echo I18N::translate('Change flag') ?></a>';
+ // If the marker is moved, update the location fields
+ google.maps.event.addListener(marker, 'drag', function() {
+ document.getElementById('NEW_PLACE_LATI').value = marker.getPosition().lat().toFixed(5);
+ document.getElementById('NEW_PLACE_LONG').value = marker.getPosition().lng().toFixed(5);
+ });
+ google.maps.event.addListener(marker, 'dragend', function() {
+ updateMap('flag_drag');
+ });
+ }
+
+ function clearMarks() {
+ marker.setMap(null);
+ }
+
+ /**
+ * Called when we select one of the search results.
+ *
+ * @param lat
+ * @param lng
+ */
+ function setLoc(lat, lng) {
+ if (lat < 0.0) {
+ document.editplaces.NEW_PLACE_LATI.value = (lat.toFixed(5) * -1);
+ document.editplaces.LATI_CONTROL.value = 'S';
+ } else {
+ document.editplaces.NEW_PLACE_LATI.value = lat.toFixed(5);
+ document.editplaces.LATI_CONTROL.value = 'N';
}
+ if (lng < 0.0) {
+ document.editplaces.NEW_PLACE_LONG.value = (lng.toFixed(5) * -1);
+ document.editplaces.LONG_CONTROL.value = 'W';
+ } else {
+ document.editplaces.NEW_PLACE_LONG.value = lng.toFixed(5);
+ document.editplaces.LONG_CONTROL.value = 'E';
+ }
+ new google.maps.LatLng (lat.toFixed(5), lng.toFixed(5));
+ infowindow.close();
+ updateMap();
+ }
- function addAddressToMap(response) {
- var bounds = new google.maps.LatLngBounds();
- if (!response) {
- alert('<?php echo I18N::translate('No places found') ?>');
- } else {
- if (response.length > 0) {
- for (var i=0; i<response.length; i++) {
- // 5 decimal places is approx 1 metre accuracy.
- var name =
- '<div>' + response[i].address_components[0].short_name +
- '<br><a href="#" onclick="setLoc(' + response[i].geometry.location.lat() + ', ' + response[i].geometry.location.lng() + ');">' +
- '<?php echo I18N::translate('Use this value') ?></a>' +
- '</div>';
- var point = response[i].geometry.location;
- var marker = createMarker(i, point, name);
- bounds.extend(response[i].geometry.location);
- }
+ function createMarker(i, point, name) {
+ var image = {
+ url: WT_STATIC_URL + WT_MODULES_DIR + 'googlemap/images/marker_yellow.png',
+ size: new google.maps.Size(20, 34),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(10, 34)
+ };
- <?php if ($level > 0) { ?>
- map.fitBounds(bounds);
- <?php } ?>
- var zoomlevel = map.getZoom();
+ var marker = new google.maps.Marker({
+ icon: image,
+ map: map,
+ position: point,
+ zIndex: 0
+ });
- if (zoomlevel < <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>) {
- zoomlevel = <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
- }
- if (zoomlevel > <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>) {
- zoomlevel = <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
+ google.maps.event.addListener(marker, 'click', function() {
+ infowindow.close();
+ infowindow.setContent(name);
+ infowindow.open(map, marker);
+ });
+
+ google.maps.event.addListener(map, 'click', function() {
+ infowindow.close();
+ });
+
+ return marker;
+ }
+
+ function change_icon() {
+ window.open('module.php?mod=googlemap&mod_action=admin_flags&countrySelected=', '_blank', indx_window_specs);
+ return false;
+ }
+
+ function remove_icon() {
+ document.editplaces.icon.value = '';
+ document.getElementById('flagsDiv').innerHTML = '<a href="#" onclick="change_icon();return false;"><?= I18N::translate('Change flag') ?></a>';
+ }
+
+ function addAddressToMap(response) {
+ var bounds = new google.maps.LatLngBounds();
+ if (!response) {
+ alert('<?= I18N::translate('No places found') ?>');
+ } else {
+ if (response.length > 0) {
+ for (var i=0; i<response.length; i++) {
+ // 5 decimal places is approx 1 metre accuracy.
+ var name =
+ '<div>' + response[i].address_components[0].short_name +
+ '<br><a href="#" onclick="setLoc(' + response[i].geometry.location.lat() + ', ' + response[i].geometry.location.lng() + ');">' +
+ '<?= I18N::translate('Use this value') ?></a>' +
+ '</div>';
+ var point = response[i].geometry.location;
+ var marker = createMarker(i, point, name);
+ bounds.extend(response[i].geometry.location);
+ }
+
+ <?php if ($level > 0) { ?>
+ map.fitBounds(bounds);
+ <?php } ?>
+ var zoomlevel = map.getZoom();
+
+ if (zoomlevel < <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>) {
+ zoomlevel = <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
+ }
+ if (zoomlevel > <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>) {
+ zoomlevel = <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
+ }
+ if (document.editplaces.NEW_ZOOM_FACTOR.value < zoomlevel) {
+ zoomlevel = document.editplaces.NEW_ZOOM_FACTOR.value;
+ if (zoomlevel < <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>) {
+ zoomlevel = <?= $this->getPreference('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
}
- if (document.editplaces.NEW_ZOOM_FACTOR.value < zoomlevel) {
- zoomlevel = document.editplaces.NEW_ZOOM_FACTOR.value;
- if (zoomlevel < <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>) {
- zoomlevel = <?php echo $this->getSetting('GM_MIN_ZOOM', self::GM_MIN_ZOOM_DEFAULT) ?>;
- }
- if (zoomlevel > <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>) {
- zoomlevel = <?php echo $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
- }
+ if (zoomlevel > <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>) {
+ zoomlevel = <?= $this->getPreference('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT) ?>;
}
- map.setCenter(bounds.getCenter());
- map.setZoom(zoomlevel);
}
+ map.setCenter(bounds.getCenter());
+ map.setZoom(zoomlevel);
}
}
+ }
- function showLocation_level(address) {
- <?php if ($level > 0) {?>
- address += '<?php echo ', ', addslashes(implode(', ', array_reverse($where_am_i, true))); ?>';
- <?php } ?>
- geocoder.geocode({'address': address}, addAddressToMap);
- }
-
- function showLocation_all(address) {
+ function showLocation_level(address) {
+ <?php if ($level > 0) { ?>
+ address += '<?= ', ' . addslashes(implode(', ', array_reverse($where_am_i, true))) ?>';
+ <?php } ?>
geocoder.geocode({'address': address}, addAddressToMap);
- }
+ }
- function paste_char(value) {
- document.editplaces.NEW_PLACE_NAME.value += value;
- }
- window.onload = function() {
- loadMap();
- };
- </script>
+ function showLocation_all(address) {
+ geocoder.geocode({'address': address}, addAddressToMap);
+ }
- <form method="post" id="editplaces" name="editplaces" action="module.php?mod=googlemap&amp;mod_action=places_edit">
- <input type="hidden" name="action" value="<?php echo $action ?>record">
- <input type="hidden" name="placeid" value="<?php echo $placeid ?>">
- <input type="hidden" name="level" value="<?php echo $level ?>">
- <input type="hidden" name="icon" value="<?php echo $place_icon ?>">
- <input type="hidden" name="parent_id" value="<?php echo $parent_id ?>">
- <input type="hidden" name="place_long" value="<?php echo $place_long ?>">
- <input type="hidden" name="place_lati" value="<?php echo $place_lati ?>">
- <input type="hidden" name="parent_long" value="<?php echo $parent_long ?>">
- <input type="hidden" name="parent_lati" value="<?php echo $parent_lati ?>">
+ function paste_char(value) {
+ document.editplaces.NEW_PLACE_NAME.value += value;
+ }
+ window.onload = function() {
+ loadMap();
+ };
+ </script>
- <table class="facts_table">
- <tr>
- <td class="optionbox" colspan="3">
- <div class="gm-map" style="width: 100%; height: 300px;"></div>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox"><?php echo GedcomTag::getLabel('PLAC') ?></td>
- <td class="optionbox"><input type="text" id="new_pl_name" name="NEW_PLACE_NAME" value="<?php echo Filter::escapeHtml($place_name) ?>" size="25" class="address_input">
- <div id="INDI_PLAC_pop" style="display: inline;">
- <?php echo FunctionsPrint::printSpecialCharacterLink('new_pl_name') ?></div></td><td class="optionbox">
- <label for="new_pl_name"><a href="#" onclick="showLocation_all(document.getElementById('new_pl_name').value); return false"><?php echo I18N::translate('Search globally') ?></a></label>
- |
- <label for="new_pl_name"><a href="#" onclick="showLocation_level(document.getElementById('new_pl_name').value); return false"><?php echo I18N::translate('Search locally') ?></a></label>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox"><?php echo GedcomTag::getLabel('LATI') ?></td>
- <td class="optionbox" colspan="2">
- <input type="text" id="NEW_PLACE_LATI" name="NEW_PLACE_LATI" placeholder="<?php echo /* I18N: Measure of latitude/longitude */ I18N::translate('degrees') ?>" value="<?php echo abs($place_lati) ?>" size="20" onchange="updateMap();">
- <select name="LATI_CONTROL" id="LATI_CONTROL" onchange="updateMap();">
- <option value="N"<?php echo $place_lati >= 0 ? ' selected' : '' ?>><?php echo I18N::translate('north') ?></option>
- <option value="S"<?php echo $place_lati < 0 ? ' selected' : '' ?>><?php echo I18N::translate('south') ?></option>
+ <form method="post" id="editplaces" name="editplaces" action="module.php?mod=googlemap&amp;mod_action=admin_place_save">
+ <input type="hidden" name="place_id" value="<?= $place_id ?>">
+ <input type="hidden" name="level" value="<?= $level ?>">
+ <input type="hidden" name="parent_id" value="<?= $parent_id ?>">
+ <input type="hidden" name="place_long" value="<?= $longitude ?>">
+ <input type="hidden" name="place_lati" value="<?= $latitude ?>">
+
+ <div class="form-group row">
+ <div class="col-sm-10 offset-sm-1">
+ <div class="gm-map" style="width: 100%; height: 350px;"></div>
+ </div>
+ </div>
- </select>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox"><?php echo GedcomTag::getLabel('LONG') ?></td>
- <td class="optionbox" colspan="2">
- <input type="text" id="NEW_PLACE_LONG" name="NEW_PLACE_LONG" placeholder="<?php echo I18N::translate('degrees') ?>" value="<?php echo abs($place_long) ?>" size="20" onchange="updateMap();">
- <select name="LONG_CONTROL" id="LONG_CONTROL" onchange="updateMap();">
- <option value="E"<?php echo $place_long >= 0 ? ' selected' : '' ?>><?php echo I18N::translate('east') ?></option>
- <option value="W"<?php echo $place_long < 0 ? ' selected' : '' ?>><?php echo I18N::translate('west') ?></option>
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2">
+ <?= I18N::translate('Place') ?>
+ </label>
+ <div class="col-sm-6">
+ <input type="text" id="new_pl_name" name="NEW_PLACE_NAME" value="<?= Filter::escapeHtml($record->pl_place) ?>" class="form-control" required>
- </select>
- </td>
- </tr>
- <tr>
- <td class="descriptionbox">
- <label for="NEW_ZOOM_FACTOR">
- <?php echo I18N::translate('Zoom level') ?>
+ <label for="new_pl_name">
+ <a href="#" onclick="showLocation_all(document.getElementById('new_pl_name').value); return false">
+ <?= I18N::translate('Search globally') ?>
+ </a>
+ </label>
+ |
+ <label for="new_pl_name">
+ <a href="#" onclick="showLocation_level(document.getElementById('new_pl_name').value); return false">
+ <?= I18N::translate('Search locally') ?>
+ </a>
</label>
- </td>
- <td class="optionbox" colspan="2">
- <input type="text" id="NEW_ZOOM_FACTOR" name="NEW_ZOOM_FACTOR" value="<?php echo $zoomfactor ?>" size="20" onchange="updateMap();">
- </td>
- </tr>
- <tr>
- <td class="descriptionbox">
- <?php echo I18N::translate('Flag') ?>
- </td>
- <td class="optionbox" colspan="2">
- <div id="flagsDiv">
- <?php if ($place_icon) { ?>
- <img alt="<?php echo /* I18N: The emblem of a country or region */ I18N::translate('Flag') ?>" src="<?php echo WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place_icon ?>">
- <a href="#" onclick="change_icon();return false;"><?php echo I18N::translate('Change flag') ?></a>
- <a href="#" onclick="remove_icon();return false;"><?php echo I18N::translate('Remove flag') ?></a>
- <?php } else { ?>
- <a href="#" onclick="change_icon();return false;"><?php echo I18N::translate('Change flag') ?></a>
- <?php } ?>
+ </div>
+
+ <label class="col-form-label col-sm-2" for="NEW_ZOOM_FACTOR">
+ <?= I18N::translate('Zoom level') ?>
+ </label>
+ <div class="col-sm-2">
+ <input type="text" id="NEW_ZOOM_FACTOR" name="NEW_ZOOM_FACTOR" value="<?= $record->pl_zoom ?>" class="form-control" onchange="updateMap();" required readonly>
+ </div>
+ </div class="form-group row">
+
+ <div class="form-group row">
+ <label class="col-form-label col-sm-2">
+ <?= I18N::translate('Latitude') ?>
+ </label>
+ <div class="col-sm-4">
+ <div class="input-group">
+ <input type="text" id="NEW_PLACE_LATI" name="NEW_PLACE_LATI" placeholder="<?= /* I18N: Measure of latitude/longitude */ I18N::translate('degrees') ?>" value="<?= abs($latitude) ?>" class="form-control" onchange="updateMap();" required>
+ <select name="LATI_CONTROL" id="LATI_CONTROL" onchange="updateMap();" class="form-control">
+ <option value="N"<?= $latitude >= 0 ? ' selected' : '' ?>>
+ <?= I18N::translate('north') ?>
+ </option>
+ <option value="S"<?= $latitude < 0 ? ' selected' : '' ?>>
+ <?= I18N::translate('south') ?>
+ </option>
+ </select>
</div>
- </td>
- </tr>
- </table>
- <p id="save-cancel">
- <input type="submit" class="save" value="<?php echo I18N::translate('save') ?>">
- <input type="button" class="cancel" value="<?php echo I18N::translate('close') ?>" onclick="window.close();">
- </p>
+ </div>
+
+ <label class="col-form-label col-sm-2">
+ <?= I18N::translate('Longitude') ?>
+ </label>
+ <div class="col-sm-4">
+ <div class="input-group">
+ <input type="text" id="NEW_PLACE_LONG" name="NEW_PLACE_LONG" placeholder="<?= I18N::translate('degrees') ?>" value="<?= abs($longitude) ?>" class="form-control" onchange="updateMap();" required>
+ <select name="LONG_CONTROL" id="LONG_CONTROL" onchange="updateMap();" class="form-control">
+ <option value="E"<?= $longitude >= 0 ? ' selected' : '' ?>>
+ <?= I18N::translate('east') ?>
+ </option>
+ <option value="W"<?= $longitude < 0 ? ' selected' : '' ?>>
+ <?= I18N::translate('west') ?>
+ </option>
+ </select>
+ </div>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="col-form-label col-sm-2" for="icon">
+ <?= I18N::translate('Flag') ?>
+ </label>
+ <div class="col-sm-10">
+ <div class="input-group" dir="ltr">
+ <span class="input-group-addon"><?= WT_MODULES_DIR ?>googlemap/places/flags/</span>
+ <?= FunctionsEdit::formControlFlag($record->pl_icon, ['name' => 'icon', 'id' => 'icon', 'class' => 'form-control']) ?>
+ </div>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <div class="col-sm-10 offset-sm-2">
+ <button class="btn btn-primary" type="submit">
+ <?= /* I18N: A button label. */ I18N::translate('save') ?>
+ </button>
+ <a class="btn btn-secondary" href="<?= $parent_url ?>">
+ <?= /* I18N: A button label. */ I18N::translate('cancel') ?>
+ </a>
+ </div>
+ </div>
</form>
- <br>
- <br>
- <br>
<?php
}
@@ -3228,89 +3070,27 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
private function adminPlaces() {
global $WT_TREE;
- $action = Filter::get('action');
- $parent = Filter::get('parent');
- $inactive = Filter::getBool('inactive');
- $deleteRecord = Filter::get('deleteRecord');
-
- if (!isset($parent)) {
- $parent = 0;
- }
+ $action = Filter::get('action');
+ $parent_id = (int) Filter::get('parent_id');
+ $inactive = Filter::getBool('inactive');
$controller = new PageController;
- $controller->restrictAccess(Auth::isAdmin());
-
- if ($action == 'ExportFile' && Auth::isAdmin()) {
- $tmp = $this->placeIdToHierarchy($parent);
- $maxLevel = $this->getHighestLevel();
- if ($maxLevel > 8) {
- $maxLevel = 8;
- }
- $tmp[0] = 'places';
- $outputFileName = preg_replace('/[:;\/\\\(\)\{\}\[\] $]/', '_', implode('-', $tmp)) . '.csv';
- header('Content-Type: application/octet-stream');
- header('Content-Disposition: attachment; filename="' . $outputFileName . '"');
- echo '"', I18N::translate('Level'), '";"', I18N::translate('Country'), '";';
- if ($maxLevel > 0) {
- echo '"', I18N::translate('State'), '";';
- }
- if ($maxLevel > 1) {
- echo '"', I18N::translate('County'), '";';
- }
- if ($maxLevel > 2) {
- echo '"', I18N::translate('City'), '";';
- }
- if ($maxLevel > 3) {
- echo '"', I18N::translate('Place'), '";';
- }
- if ($maxLevel > 4) {
- echo '"', I18N::translate('Place'), '";';
- }
- if ($maxLevel > 5) {
- echo '"', I18N::translate('Place'), '";';
- }
- if ($maxLevel > 6) {
- echo '"', I18N::translate('Place'), '";';
- }
- if ($maxLevel > 7) {
- echo '"', I18N::translate('Place'), '";';
- }
- echo '"', I18N::translate('Longitude'), '";"', I18N::translate('Latitude'), '";';
- echo '"', I18N::translate('Zoom level'), '";"', I18N::translate('Icon'), '";', WT_EOL;
- $this->outputLevel($parent);
-
- return;
- }
-
$controller
- ->setPageTitle(I18N::translate('Google Maps™'))
+ ->setPageTitle(I18N::translate('Geographic data'))
->pageHeader();
- ?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel') ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration') ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle() ?></li>
- </ol>
-
- <ul class="nav nav-tabs nav-justified" role="tablist">
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_config" role="tab">
- <?php echo I18N::translate('Google Maps™ preferences') ?>
- </a>
- </li>
- <li role="presentation" class="active">
- <a href="#">
- <?php echo I18N::translate('Geographic data') ?>
- </a>
- </li>
- <li role="presentation">
- <a href="?mod=googlemap&amp;mod_action=admin_placecheck">
- <?php echo I18N::translate('Place check') ?>
- </a>
- </li>
- </ul>
- <?php
+ $breadcrumbs = [
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ $this->getConfigLink() => $this->getTitle(),
+ ];
+ $hierarchy =
+ [0 => I18N::translate('Geographic data')] +
+ $this->placeIdToHierarchy($parent_id);
+ foreach (array_slice($hierarchy, 0, -1, true) as $id => $name) {
+ $breadcrumbs += ['module.php?mod=googlemap&mod_action=admin_places&parent_id=' . $id .'&inactive=' . $inactive => Filter::escapeHtml($name)];
+ }
+ echo Bootstrap4::breadcrumbs($breadcrumbs, end($hierarchy));
if ($action == 'ImportGedcom') {
echo '<h2>' . I18N::translate('Geographic data') . '</h2>';
@@ -3432,464 +3212,135 @@ class GoogleMapsModule extends AbstractModule implements ModuleConfigInterface,
}
}
}
- $parent = 0;
}
- if ($action === 'ImportFile') {
- echo '<h2>' . I18N::translate('Upload geographic data') . '</h2>';
- $placefiles = $this->findFiles(WT_MODULES_DIR . 'googlemap/extra');
- sort($placefiles);
+ $placelist = $this->getPlaceListLocation($parent_id, $inactive);
?>
- <form class="form-horizontal" method="post" enctype="multipart/form-data" id="importfile" name="importfile" action="module.php?mod=googlemap&amp;mod_action=admin_places&amp;action=ImportFile2">
-
- <!-- PLACES FILE -->
- <div class="form-group">
- <label class="control-label col-sm-4" for="placesfile">
- <?php echo I18N::translate('A file on your computer') ?>
- </label>
- <div class="col-sm-8">
- <div class="btn btn-default">
- <input id="placesfile" type="file" name="placesfile">
- </div>
- </div>
- </div>
-
- <!-- LOCAL FILE -->
- <div class="form-group">
- <label class="control-label col-sm-4" for="localfile">
- <?php echo I18N::translate('A file on the server') ?>
- </label>
- <div class="col-sm-8">
- <div class="input-group">
- <span class="input-group-addon">
- <?php echo WT_MODULES_DIR . 'googlemap/extra/' ?>
- </span>
- <?php
- foreach ($placefiles as $p => $placefile) {
- unset($placefiles[$p]);
- $p = Filter::escapeHtml($placefile);
- if (substr($placefile, 0, 1) == '/') {
- $placefiles[$p] = substr($placefile, 1);
- } else {
- $placefiles[$p] = $placefile;
- }
- }
- echo FunctionsEdit::selectEditControl('localfile', $placefiles, '', '', 'class="form-control"');
- ?>
- </div>
- </div>
- </div>
-
- <!-- CLEAR DATABASE -->
- <fieldset class="form-group">
- <legend class="control-label col-sm-4">
- <?php echo I18N::translate('Delete all existing geographic data before importing the file.') ?>
- </legend>
- <div class="col-sm-8">
- <?php echo FunctionsEdit::editFieldYesNo('cleardatabase', 0, 'class="radio-inline"') ?>
- </div>
- </fieldset>
-
- <!-- UPDATE ONLY -->
- <fieldset class="form-group">
- <legend class="control-label col-sm-4">
- <?php echo I18N::translate('Do not create new locations, just import coordinates for existing locations.') ?>
- </legend>
- <div class="col-sm-8">
- <?php echo FunctionsEdit::editFieldYesNo('updateonly', 0, 'class="radio-inline"') ?>
- </div>
- </fieldset>
-
- <!-- OVERWRITE DATA -->
- <fieldset class="form-group">
- <legend class="control-label col-sm-4">
- <?php echo I18N::translate('Overwrite existing coordinates.') ?>
- </legend>
- <div class="col-sm-8">
- <?php echo FunctionsEdit::editFieldYesNo('overwritedata', 0, 'class="radio-inline"') ?>
- </div>
- </fieldset>
-
- <!-- SAVE BUTTON -->
- <div class="form-group">
- <div class="col-sm-offset-4 col-sm-8">
- <button type="submit" class="btn btn-primary">
- <i class="fa fa-check"></i>
- <?php echo I18N::translate('continue') ?>
- </button>
- </div>
- </div>
+ <form class="form-inline">
+ <input type="hidden" name="mod" value="googlemap">
+ <input type="hidden" name="mod_action" value="admin_places">
+ <input type="hidden" name="parent_id" value="<?= $parent_id ?>">
+ <?= Bootstrap4::checkbox(I18N::translate('Show inactive places'), false, ['name' => 'inactive', 'checked' => $inactive, 'onclick' => 'this.form.submit()']) ?>
+ <p class="small text-muted">
+ <?= I18N::translate('By default, the list shows only those places which can be found in your family trees. You may have details for other places, such as those imported in bulk from an external file. Selecting this option will show all places, including ones that are not currently used.') ?>
+ <?= I18N::translate('If you have a large number of inactive places, it can be slow to generate the list.') ?>
+ </p>
</form>
- <?php
- return;
- }
- if ($action === 'ImportFile2') {
- echo '<h2>' . I18N::translate('Geographic data') . '</h2>';
- $country_names = [];
- $stats = new Stats($WT_TREE);
- foreach ($stats->iso3166() as $key => $value) {
- $country_names[$key] = I18N::translate($key);
- }
- if (Filter::postBool('cleardatabase')) {
- Database::exec("DELETE FROM `##placelocation` WHERE 1=1");
- }
- if (!empty($_FILES['placesfile']['tmp_name'])) {
- $lines = file($_FILES['placesfile']['tmp_name']);
- } elseif (!empty($_REQUEST['localfile'])) {
- $lines = file(WT_MODULES_DIR . 'googlemap/extra' . $_REQUEST['localfile']);
- }
- // Strip BYTE-ORDER-MARK, if present
- if (!empty($lines[0]) && substr($lines[0], 0, 3) === WT_UTF8_BOM) {
- $lines[0] = substr($lines[0], 3);
- }
- asort($lines);
- $highestIndex = $this->getHighestIndex();
- $placelist = [];
- $j = 0;
- $maxLevel = 0;
- foreach ($lines as $p => $placerec) {
- $fieldrec = explode(';', $placerec);
- if ($fieldrec[0] > $maxLevel) {
- $maxLevel = $fieldrec[0];
- }
- }
- $fields = count($fieldrec);
- $set_icon = true;
- if (!is_dir(WT_MODULES_DIR . 'googlemap/places/flags/')) {
- $set_icon = false;
- }
- foreach ($lines as $p => $placerec) {
- $fieldrec = explode(';', $placerec);
- if (is_numeric($fieldrec[0]) && $fieldrec[0] <= $maxLevel) {
- $placelist[$j] = [];
- $placelist[$j]['place'] = '';
- for ($ii = $fields - 4; $ii > 1; $ii--) {
- if ($fieldrec[0] > $ii - 2) {
- $placelist[$j]['place'] .= $fieldrec[$ii] . ',';
- }
- }
- foreach ($country_names as $countrycode => $countryname) {
- if ($countrycode == strtoupper($fieldrec[1])) {
- $fieldrec[1] = $countryname;
- break;
- }
- }
- $placelist[$j]['place'] .= $fieldrec[1];
- $placelist[$j]['long'] = $fieldrec[$fields - 4];
- $placelist[$j]['lati'] = $fieldrec[$fields - 3];
- $placelist[$j]['zoom'] = $fieldrec[$fields - 2];
- if ($set_icon) {
- $placelist[$j]['icon'] = trim($fieldrec[$fields - 1]);
- } else {
- $placelist[$j]['icon'] = '';
- }
- $j = $j + 1;
- }
- }
+ <div class="gm_plac_edit">
+ <table class="table table-bordered table-condensed table-hover">
+ <thead>
+ <tr>
+ <th><?= I18N::translate('Place') ?></th>
+ <th><?= I18N::translate('Latitude') ?></th>
+ <th><?= I18N::translate('Longitude') ?></th>
+ <th><?= I18N::translate('Zoom level') ?></th>
+ <th><?= I18N::translate('Icon') ?> / <?= I18N::translate('Flag') ?></th>
+ <th><?= I18N::translate('Edit') ?></th>
+ <th><?= I18N::translate('Delete') ?></th>
+ </tr>
+ </thead>
+ <tbody>
- $prevPlace = '';
- $prevLati = '';
- $prevLong = '';
- $placelistUniq = [];
- $j = 0;
- foreach ($placelist as $k => $place) {
- if ($place['place'] != $prevPlace) {
- $placelistUniq[$j] = [];
- $placelistUniq[$j]['place'] = $place['place'];
- $placelistUniq[$j]['lati'] = $place['lati'];
- $placelistUniq[$j]['long'] = $place['long'];
- $placelistUniq[$j]['zoom'] = $place['zoom'];
- $placelistUniq[$j]['icon'] = $place['icon'];
- $j = $j + 1;
- } elseif (($place['place'] == $prevPlace) && (($place['lati'] != $prevLati) || ($place['long'] != $prevLong))) {
- if (($placelistUniq[$j - 1]['lati'] == 0) || ($placelistUniq[$j - 1]['long'] == 0)) {
- $placelistUniq[$j - 1]['lati'] = $place['lati'];
- $placelistUniq[$j - 1]['long'] = $place['long'];
- $placelistUniq[$j - 1]['zoom'] = $place['zoom'];
- $placelistUniq[$j - 1]['icon'] = $place['icon'];
- } elseif (($place['lati'] != '0') || ($place['long'] != '0')) {
- echo 'Difference: previous value = ', $prevPlace, ', ', $prevLati, ', ', $prevLong, ' current = ', $place['place'], ', ', $place['lati'], ', ', $place['long'], '<br>';
- }
- }
- $prevPlace = $place['place'];
- $prevLati = $place['lati'];
- $prevLong = $place['long'];
- }
-
- $default_zoom_level = [];
- $default_zoom_level[0] = 4;
- $default_zoom_level[1] = 7;
- $default_zoom_level[2] = 10;
- $default_zoom_level[3] = 12;
- foreach ($placelistUniq as $k => $place) {
- $parent = explode(',', $place['place']);
- $parent = array_reverse($parent);
- $parent_id = 0;
- $num_parent = count($parent);
- for ($i = 0; $i < $num_parent; $i++) {
- $escparent = $parent[$i];
- if ($escparent == '') {
- $escparent = 'Unknown';
- }
- $row =
- Database::prepare("SELECT pl_id, pl_long, pl_lati, pl_zoom, pl_icon FROM `##placelocation` WHERE pl_level=? AND pl_parent_id=? AND pl_place LIKE ? ORDER BY pl_place")
- ->execute([$i, $parent_id, $escparent])
- ->fetchOneRow();
- if (empty($row)) {
- // this name does not yet exist: create entry
- if (!Filter::postBool('updateonly')) {
- $highestIndex = $highestIndex + 1;
- if (($i + 1) == $num_parent) {
- $zoomlevel = $place['zoom'];
- } elseif (isset($default_zoom_level[$i])) {
- $zoomlevel = $default_zoom_level[$i];
- } else {
- $zoomlevel = $this->getSetting('GM_MAX_ZOOM', self::GM_MAX_ZOOM_DEFAULT);
- }
- if (($place['lati'] == '0') || ($place['long'] == '0') || (($i + 1) < $num_parent)) {
- Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?)")
- ->execute([$highestIndex, $parent_id, $i, $escparent, $zoomlevel, $place['icon']]);
- } else {
- //delete leading zero
- $pl_lati = str_replace(['N', 'S', ','], ['', '-', '.'], $place['lati']);
- $pl_long = str_replace(['E', 'W', ','], ['', '-', '.'], $place['long']);
- if ($pl_lati >= 0) {
- $place['lati'] = 'N' . abs($pl_lati);
- } elseif ($pl_lati < 0) {
- $place['lati'] = 'S' . abs($pl_lati);
- }
- if ($pl_long >= 0) {
- $place['long'] = 'E' . abs($pl_long);
- } elseif ($pl_long < 0) {
- $place['long'] = 'W' . abs($pl_long);
- }
- Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
- ->execute([$highestIndex, $parent_id, $i, $escparent, $place['long'], $place['lati'], $zoomlevel, $place['icon']]);
- }
- $parent_id = $highestIndex;
- }
- } else {
- $parent_id = $row->pl_id;
- if (Filter::postBool('overwritedata') && ($i + 1 == count($parent))) {
- Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ?, pl_zoom = ?, pl_icon = ? WHERE pl_id = ?")
- ->execute([$place['lati'], $place['long'], $place['zoom'], $place['icon'], $parent_id]);
- } else {
- // Update only if existing data is missing
- if (!$row->pl_long && !$row->pl_lati) {
- Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ? WHERE pl_id = ?")
- ->execute([$place['lati'], $place['long'], $parent_id]);
- }
- if (!$row->pl_icon && $place['icon']) {
- Database::prepare("UPDATE `##placelocation` SET pl_icon = ? WHERE pl_id = ?")
- ->execute([$place['icon'], $parent_id]);
- }
- }
- }
- }
- }
- $parent = 0;
- }
-
- if ($action == 'DeleteRecord') {
- echo '<h2>' . I18N::translate('Geographic data') . '</h2>';
- $exists =
- Database::prepare("SELECT 1 FROM `##placelocation` WHERE pl_parent_id=?")
- ->execute([$deleteRecord])
- ->fetchOne();
-
- if (!$exists) {
- Database::prepare("DELETE FROM `##placelocation` WHERE pl_id=?")
- ->execute([$deleteRecord]);
- } else {
- echo '<table class="facts_table"><tr><td>', I18N::translate('Location not removed: this location contains sub-locations'), '</td></tr></table>';
- }
- }
-
- ?>
- <script>
- function updateList(inactive) {
- window.location.href='<?php if (strstr(Filter::server('REQUEST_URI'), '&inactive', true)) { $uri = strstr(Filter::server('REQUEST_URI'), '&inactive', true); } else { $uri = Filter::server('REQUEST_URI'); } echo $uri, '&inactive=' ?>'+inactive;
- }
-
- function edit_place_location(placeid) {
- window.open('module.php?mod=googlemap&mod_action=places_edit&action=update&placeid='+placeid, '_blank', gmap_window_specs);
- return false;
- }
+ <?php foreach ($placelist as $place): ?>
+ <?php $noRows = Database::prepare("SELECT COUNT(pl_id) FROM `##placelocation` WHERE pl_parent_id=?")->execute([$place['place_id']])->fetchOne(); ?>
+ <tr>
+ <td>
+ <a href="module.php?mod=googlemap&mod_action=admin_places&amp;parent_id=<?= $place['place_id'] ?>&inactive=<?= $inactive ?>">
+ <?php if ($place['place'] === 'Unknown'): ?>
+ <?= I18N::translate('unknown') ?>
+ <?php else: ?>
+ <?= Filter::escapeHtml($place['place']) ?>
+ <?php endif ?>
+ <?php if ($place['missing'] > 0): ?>
+ <span class="badge badge-pill badge-warning">
+ <?= I18N::number($place['children']) ?>
+ </span>
+ <?php elseif ($place['children'] > 0): ?>
+ <span class="badge badge-pill badge-default">
+ <?= I18N::number($place['children']) ?>
+ </span>
+ <?php endif ?>
+ </a>
+ </td>
+ <td>
+ <?= $place['is_empty'] ? FontAwesome::decorativeIcon('warning') : $place['lati'] ?>
+ </td>
+ <td>
+ <?= $place['is_empty'] ? FontAwesome::decorativeIcon('warning') : $place['long'] ?>
+ </td>
+ <td>
+ <?= $place['zoom'] ?>
+ </td>
+ <td>
+ <?php if ($place['icon']): ?>
+ <img src="<?= WT_STATIC_URL ?><?= WT_MODULES_DIR ?>googlemap/places/flags/<?= Filter::escapeHtml($place['icon']) ?>" width="25" height="15" title="<?= Filter::escapeHtml($place['icon']) ?>" alt="<?= I18N::translate('Flag') ?>">
+ <?php else: ?>
+ <img src="<?= WT_STATIC_URL ?><?= WT_MODULES_DIR ?>googlemap/images/mm_20_red.png">
+ <?php endif ?>
+ </td>
+ <td>
+ <?= FontAwesome::linkIcon('edit', I18N::translate('Edit'), ['href' => 'module.php?mod=googlemap&mod_action=admin_place_edit&action=update&place_id=' . $place['place_id'] . '&parent_id=' . $place['parent_id'], 'class' => 'btn btn-primary']) ?>
+ </td>
+ <td>
+ <?php if ($noRows == 0): ?>
+ <form method="POST" action="module.php?mod=googlemap&amp;mod_action=admin_delete_action" onsubmit="return confirm('<?= I18N::translate('Remove this location?') ?>')">
+ <input type="hidden" name="parent_id" value="<?= $parent_id ?>">
+ <input type="hidden" name="place_id" value="<?= $place['place_id'] ?>">
+ <input type="hidden" name="inactive" value="<?= $inactive ?>">
+ <button type="submit" class="btn btn-danger">
+ <?= FontAwesome::semanticIcon('delete', I18N::translate('Delete')) ?>
+ </button>
+ </form>
+ <?php else: ?>
+ <button type="button" class="btn btn-danger" disabled>
+ <?= FontAwesome::decorativeIcon('delete') ?>
+ </button>
+ <?php endif ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="7">
+ <a href="module.php?mod=googlemap&mod_action=admin_place_edit&parent_id=<?= $parent_id ?>" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('add') ?>
+ <?= /* I18N: A button label. */ I18N::translate('add') ?>
+ </a>
- function add_place_location(placeid) {
- window.open('module.php?mod=googlemap&mod_action=places_edit&action=add&placeid='+placeid, '_blank', gmap_window_specs);
- return false;
- }
-
- function delete_place(placeid) {
- var answer=confirm('<?php echo I18N::translate('Remove this location?') ?>');
- if (answer == true) {
- window.location = '<?php echo Functions::getQueryUrl(['action' => 'DeleteRecord']) ?>&action=DeleteRecord&deleteRecord=' + placeid;
- }
- }
- </script>
- <p id="gm_breadcrumb">
- <?php
- $where_am_i = $this->placeIdToHierarchy($parent);
- foreach (array_reverse($where_am_i, true) as $id => $place) {
- if ($id == $parent) {
- if ($place != 'Unknown') {
- echo Filter::escapeHtml($place);
- } else {
- echo I18N::translate('unknown');
- }
- } else {
- echo '<a href="module.php?mod=googlemap&mod_action=admin_places&parent=', $id, '&inactive=', $inactive, '">';
- if ($place != 'Unknown') {
- echo Filter::escapeHtml($place), '</a>';
- } else {
- echo I18N::translate('unknown'), '</a>';
- }
- }
- echo ' - ';
- }
- ?>
- <a href="module.php?mod=googlemap&mod_action=admin_places&parent=0&inactive=', $inactive, '"><?php echo I18N::translate('Top level') ?></a>
- </p>
+ <a href="module.php?mod=googlemap&mod_action=admin_download&parent_id=<?= $parent_id ?>" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('download') ?>
+ <?= /* I18N: A button label. */ I18N::translate('download') ?>
+ </a>
- <form class="form-inline" name="active" method="post" action="module.php?mod=googlemap&mod_action=admin_places&parent=', $parent, '&inactive=', $inactive, '">
- <div class="checkbox">
- <label for="inactive">
- <?php echo FunctionsEdit::checkbox('inactive', $inactive, 'onclick="updateList(this.checked)"') ?>
- <?php echo I18N::translate('Show inactive places') ?>
- </label>
- </div>
- <p class="small text-muted">
- <?php echo I18N::translate('By default, the list shows only those places which can be found in your family trees. You may have details for other places, such as those imported in bulk from an external file. Selecting this option will show all places, including ones that are not currently used.') ?>
- <?php echo I18N::translate('If you have a large number of inactive places, it can be slow to generate the list.') ?>
- </p>
- </form>
-
- <?php
- $placelist = $this->getPlaceListLocation($parent, $inactive);
- echo '<div class="gm_plac_edit">';
- echo '<table class="table table-bordered table-condensed table-hover"><tr>';
- echo '<th>', GedcomTag::getLabel('PLAC'), '</th>';
- echo '<th>', GedcomTag::getLabel('LATI'), '</th>';
- echo '<th>', GedcomTag::getLabel('LONG'), '</th>';
- echo '<th>', I18N::translate('Zoom level'), '</th>';
- echo '<th>', I18N::translate('Icon'), '</th>';
- echo '<th>';
- echo I18N::translate('Edit'), '</th><th>', I18N::translate('Delete'), '</th></tr>';
- if (count($placelist) == 0) {
- echo '<tr><td colspan="7">', I18N::translate('No places found'), '</td></tr>';
- }
- foreach ($placelist as $place) {
- echo '<tr><td><a href="module.php?mod=googlemap&mod_action=admin_places&parent=', $place['place_id'], '&inactive=', $inactive, '">';
- if ($place['place'] != 'Unknown') {
- echo Filter::escapeHtml($place['place']), '</a></td>';
- } else {
- echo I18N::translate('unknown'), '</a></td>';
- }
- echo '<td>', $place['lati'], '</td>';
- echo '<td>', $place['long'], '</td>';
- echo '<td>', $place['zoom'], '</td>';
- echo '<td>';
- if ($place['icon']) {
- echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place['icon'], '" width="25" height="15">';
- } else {
- if ($place['lati'] || $place['long']) {
- echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/images/mm_20_red.png">';
- } else {
- echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/images/mm_20_yellow.png">';
- }
- }
- echo '</td>';
- echo '<td class="narrow"><a href="#" onclick="edit_place_location(', $place['place_id'], ');return false;" class="icon-edit" title="', I18N::translate('Edit'), '"></a></td>';
- $noRows =
- Database::prepare("SELECT COUNT(pl_id) FROM `##placelocation` WHERE pl_parent_id=?")
- ->execute([$place['place_id']])
- ->fetchOne();
- if ($noRows == 0) { ?>
- <td><a href="#" onclick="delete_place(<?php echo $place['place_id'] ?>);return false;" class="icon-delete" title="<?php echo I18N::translate('Delete') ?>"></a></td>
- <?php } else { ?>
- <td><i class="icon-delete-grey"></i></td>
- <?php } ?>
- </tr>
- <?php
- }
- ?>
- </table>
+ <a href="module.php?mod=googlemap&amp;mod_action=admin_upload&amp;parent_id=<?= $parent_id ?>&amp;inactive=<?= $inactive ?>" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('upload') ?>
+ <?= /* I18N: A button label. */ I18N::translate('upload') ?>
+ </a>
+ </td>
+ </tr>
+ </tfoot>
+ </table>
</div>
<hr>
- <form class="form-horizontal" action="?" onsubmit="add_place_location(this.parent_id.options[this.parent_id.selectedIndex].value); return false;">
- <div class="form-group">
- <label class="form-control-static col-sm-4" for="parent_id">
- <?php echo I18N::translate('Add a geographic location') ?>
- </label>
- <div class="col-sm-8">
- <div class="col-sm-6">
- <?php echo FunctionsEdit::selectEditControl('parent_id', $where_am_i, I18N::translate('Top level'), $parent, 'class="form-control"') ?>
- </div>
- <button type="submit" class="btn btn-default">
- <i class="fa fa-plus"></i>
- <?php echo /* I18N: A button label. */ I18N::translate('add') ?>
- </button>
- </div>
- </div>
- </form>
- <form class="form-horizontal" action="module.php" method="get">
+ <form class="form-horizontal" action="module.php">
<input type="hidden" name="mod" value="googlemap">
<input type="hidden" name="mod_action" value="admin_places">
<input type="hidden" name="action" value="ImportGedcom">
- <div class="form-group">
+ <div class="row form-group">
<label class="form-control-static col-sm-4" for="ged">
- <?php echo I18N::translate('Import all places from a family tree') ?>
- </label>
- <div class="col-sm-8">
- <div class="col-sm-6">
- <?php echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), null, $WT_TREE->getName(), 'class="form-control"') ?>
- </div>
- <button type="submit" class="btn btn-default">
- <i class="fa fa-upload"></i>
- <?php echo /* I18N: A button label. */ I18N::translate('import') ?>
- </button>
- </div>
- </div>
- </form>
-
- <form class="form-horizontal" action="module.php" method="get">
- <input type="hidden" name="mod" value="googlemap">
- <input type="hidden" name="mod_action" value="admin_places">
- <input type="hidden" name="action" value="ImportFile">
- <div class="form-group">
- <label class="form-control-static col-sm-4">
- <?php echo I18N::translate('Upload geographic data') ?>
+ <?= I18N::translate('Import all places from a family tree') ?>
</label>
- <div class="col-sm-8">
- <div class="col-sm-6">
- <button type="submit" class="btn btn-default">
- <i class="fa fa-upload"></i>
- <?php echo /* I18N: A button label. */ I18N::translate('upload') ?>
- </button>
- </div>
+ <div class="col-sm-6">
+ <?= Bootstrap4::select(Tree::getNameList(), $WT_TREE->getName(), ['id' => 'ged', 'name' => 'ged']) ?>
</div>
- </div>
- </form>
-
- <form class="form-horizontal" action="module.php" method="get">
- <input type="hidden" name="mod" value="googlemap">
- <input type="hidden" name="mod_action" value="admin_places">
- <input type="hidden" name="action" value="ExportFile">
- <div class="form-group">
- <label class="form-control-static col-sm-4">
- <?php echo I18N::translate('Download geographic data') ?>
- </label>
- <div class="col-sm-8">
- <div class="col-sm-6">
- <?php echo FunctionsEdit::selectEditControl('parent', $where_am_i, I18N::translate('All'), $WT_TREE->getTreeId(), 'class="form-control"') ?>
- </div>
- <button type="submit" class="btn btn-default">
- <i class="fa fa-download"></i>
- <?php echo /* I18N: A button label. */ I18N::translate('download') ?>
+ <div class="col-sm-2">
+ <button type="submit" class="btn btn-primary">
+ <?= FontAwesome::decorativeIcon('add') ?>
+ <?= /* I18N: A button label. */ I18N::translate('import') ?>
</button>
</div>
</div>
diff --git a/app/Module/HtmlBlockModule.php b/app/Module/HtmlBlockModule.php
index 079d29fe3d..052ac7b6b4 100644
--- a/app/Module/HtmlBlockModule.php
+++ b/app/Module/HtmlBlockModule.php
@@ -16,10 +16,11 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsDate;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Site;
@@ -103,7 +104,7 @@ class HtmlBlockModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>' . $title;
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
}
$content = $html;
@@ -263,75 +264,78 @@ class HtmlBlockModule extends AbstractModule implements ModuleBlockInterface {
$title = $this->getBlockSetting($block_id, 'title');
$html = $this->getBlockSetting($block_id, 'html');
- $gedcom = $this->getBlockSetting($block_id, 'gedcom');
+ $gedcom = $this->getBlockSetting($block_id, 'gedcom', '__current__');
$show_timestamp = $this->getBlockSetting($block_id, 'show_timestamp', '0');
$languages = explode(',', $this->getBlockSetting($block_id, 'languages'));
- echo '<tr><td class="descriptionbox wrap">',
- GedcomTag::getLabel('TITL'),
- '</td><td class="optionbox"><input type="text" name="title" size="30" value="', Filter::escapeHtml($title), '"></td></tr>';
+ ?>
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="title">
+ <?= I18N::translate('Title') ?>
+ </label>
+ <div class="col-sm-9">
+ <input class="form-control" type="text" id="title" name="title" value="<?= Filter::escapeHtml($title) ?>">
+ </div>
+ </div>
- // templates
- echo '<tr><td class="descriptionbox wrap">',
- I18N::translate('Templates'),
- '</td><td class="optionbox wrap">';
- // The CK editor needs lots of help to load/save data :-(
- if (Module::getModuleByName('ckeditor')) {
- $ckeditor_onchange = 'CKEDITOR.instances.html.setData(document.block.html.value);';
- } else {
- $ckeditor_onchange = '';
- }
- echo '<select name="template" onchange="document.block.html.value=document.block.template.options[document.block.template.selectedIndex].value;', $ckeditor_onchange, '">';
- echo '<option value="', Filter::escapeHtml($html), '">', I18N::translate('Custom'), '</option>';
- foreach ($templates as $title => $template) {
- echo '<option value="', Filter::escapeHtml($template), '">', $title, '</option>';
- }
- echo '</select>';
- if (!$html) {
- echo '<p>', I18N::translate('To assist you in getting started with this block, we have created several standard templates. When you select one of these templates, the text area will contain a copy that you can then alter to suit your site’s requirements.'), '</p>';
- }
- echo '</td></tr>';
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="template">
+ <?= I18N::translate('Templates') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select('template', [$html => I18N::translate('Custom')] + array_flip($templates), '', ['onchange' => 'this.form.html.value=this.options[this.selectedIndex].value; CKEDITOR.instances.html.setData(document.block.html.value);']) ?>
+ <p class="small text-muted">
+ <?= I18N::translate('To assist you in getting started with this block, we have created several standard templates. When you select one of these templates, the text area will contain a copy that you can then alter to suit your site’s requirements.') ?>
+ </p>
+ </div>
+ </div>
- if (count(Tree::getAll()) > 1) {
- if ($gedcom == '__current__') {$sel_current = 'selected'; } else {$sel_current = ''; }
- if ($gedcom == '__default__') {$sel_default = 'selected'; } else {$sel_default = ''; }
- echo '<tr><td class="descriptionbox wrap">',
- I18N::translate('Family tree'),
- '</td><td class="optionbox">',
- '<select name="gedcom">',
- '<option value="__current__" ', $sel_current, '>', I18N::translate('Current'), '</option>',
- '<option value="__default__" ', $sel_default, '>', I18N::translate('Default'), '</option>';
- foreach (Tree::getAll() as $tree) {
- if ($tree->getName() === $gedcom) {$sel = 'selected'; } else {$sel = ''; }
- echo '<option value="', $tree->getNameHtml(), '" ', $sel, '>', $tree->getTitleHtml(), '</option>';
- }
- echo '</select>';
- echo '</td></tr>';
- }
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="gedcom">
+ <?= I18N::translate('Family tree') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['__current__' => I18N::translate('Current'), '__default__' => I18N::translate('Default')] + Tree::getNameList(), $gedcom, ['id' => 'gedcom', 'name' => 'gedcom']) ?>
+ </div>
+ </div>
- // html
- echo '<tr><td colspan="2" class="descriptionbox">',
- I18N::translate('Content');
- if (!$html) {
- echo '<p>', I18N::translate('As well as using the toolbar to apply HTML formatting, you can insert database fields which are updated automatically. These special fields are marked with <b>#</b> characters. For example <b>#totalFamilies#</b> will be replaced with the actual number of families in the database. Advanced users may wish to apply CSS classes to their text, so that the formatting matches the currently selected theme.'), '</p>';
- }
- echo
- '</td></tr><tr>',
- '<td colspan="2" class="optionbox">';
- echo '<textarea name="html" class="html-edit" rows="10" style="width:98%;">', Filter::escapeHtml($html), '</textarea>';
- echo '</td></tr>';
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="html">
+ <?= I18N::translate('Content') ?>
+ </label>
+ <div class="col-sm-9">
+ <p>
+ <?= I18N::translate('As well as using the toolbar to apply HTML formatting, you can insert database fields which are updated automatically. These special fields are marked with <b>#</b> characters. For example <b>#totalFamilies#</b> will be replaced with the actual number of families in the database. Advanced users may wish to apply CSS classes to their text, so that the formatting matches the currently selected theme.') ?>
+ </p>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <textarea name="html" id="html" class="html-edit" rows="10"><?= Filter::escapeHtml($html) ?></textarea>
+ </div>
+
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="form-control-legend col-sm-3">
+ <?= I18N::translate('Show the date and time of update') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('timestamp', FunctionsEdit::optionsNoYes(), $show_timestamp, true) ?>
+ </div>
+ </div>
+ </fieldset>
- echo '<tr><td class="descriptionbox wrap">';
- echo I18N::translate('Show the date and time of update');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('show_timestamp', $show_timestamp);
- echo '<input type="hidden" name="timestamp" value="', WT_TIMESTAMP, '">';
- echo '</td></tr>';
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="form-control-legend col-sm-3">
+ <?= I18N::translate('Show this block for which languages') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= FunctionsEdit::editLanguageCheckboxes('lang', $languages) ?>
+ </div>
+ </div>
+ </fieldset>
- echo '<tr><td class="descriptionbox wrap">';
- echo I18N::translate('Show this block for which languages');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editLanguageCheckboxes('lang', $languages);
- echo '</td></tr>';
+ <?php
}
}
diff --git a/app/Module/IndividualFactsTabModule.php b/app/Module/IndividualFactsTabModule.php
index 022699000f..891efff694 100644
--- a/app/Module/IndividualFactsTabModule.php
+++ b/app/Module/IndividualFactsTabModule.php
@@ -15,7 +15,6 @@
*/
namespace Fisharebest\Webtrees\Module;
-use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
@@ -127,19 +126,19 @@ class IndividualFactsTabModule extends AbstractModule implements ModuleTabInterf
</colgroup>
<tbody>
<tr>
- <td colspan="2" class="descriptionbox noprint">
+ <td colspan="2" class="descriptionbox">
<?php if ($controller->record->getTree()->getPreference('SHOW_RELATIVES_EVENTS')) : ?>
<label>
<input id="show-relatives-facts" type="checkbox">
- <?php echo I18N::translate('Events of close relatives'); ?>
+ <?= I18N::translate('Events of close relatives') ?>
</label>
- <?php endif; ?>
+ <?php endif ?>
<?php if (file_exists(Site::getPreference('INDEX_DIRECTORY') . 'histo.' . WT_LOCALE . '.php')) : ?>
<label>
<input id="show-historical-facts" type="checkbox">
- <?php echo I18N::translate('Historical facts'); ?>
+ <?= I18N::translate('Historical facts') ?>
</label>
- <?php endif; ?>
+ <?php endif ?>
</td>
</tr>
<?php
@@ -161,8 +160,8 @@ class IndividualFactsTabModule extends AbstractModule implements ModuleTabInterf
</tbody>
</table>
<script>
- persistent_toggle("show-relatives-facts", "tr.rela");
- persistent_toggle("show-historical-facts", "tr.histo");
+ //persistent_toggle("show-relatives-facts", "tr.rela");
+ //persistent_toggle("show-historical-facts", "tr.histo");
</script>
<?php
@@ -176,7 +175,7 @@ class IndividualFactsTabModule extends AbstractModule implements ModuleTabInterf
/** {@inheritdoc} */
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/** {@inheritdoc} */
diff --git a/app/Module/IndividualSidebarModule.php b/app/Module/IndividualSidebarModule.php
index b6dbaa3428..a74e145176 100644
--- a/app/Module/IndividualSidebarModule.php
+++ b/app/Module/IndividualSidebarModule.php
@@ -15,7 +15,6 @@
*/
namespace Fisharebest\Webtrees\Module;
-use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\I18N;
@@ -63,7 +62,7 @@ class IndividualSidebarModule extends AbstractModule implements ModuleSidebarInt
/** {@inheritdoc} */
public function hasSidebarContent() {
- return !Auth::isSearchEngine();
+ return true;
}
/** {@inheritdoc} */
@@ -100,23 +99,23 @@ class IndividualSidebarModule extends AbstractModule implements ModuleSidebarInt
var loadedNames = new Array();
function isearchQ() {
- var query = jQuery("#sb_indi_name").val();
+ var query = $("#sb_indi_name").val();
if (query.length>1) {
- jQuery("#sb_indi_content").load("module.php?mod=' . $this->getName() . '&mod_action=ajax&search="+query);
+ $("#sb_indi_content").load("module.php?mod=' . $this->getName() . '&mod_action=ajax&search="+query);
}
}
var timerid = null;
- jQuery("#sb_indi_name").keyup(function(e) {
+ $("#sb_indi_name").keyup(function(e) {
if (timerid) window.clearTimeout(timerid);
timerid = window.setTimeout("isearchQ()", 500);
});
- jQuery("#sb_content_individuals").on("click", ".sb_indi_letter", function() {
- jQuery("#sb_indi_content").load(this.href);
+ $("#sb_content_individuals").on("click", ".sb_indi_letter", function() {
+ $("#sb_indi_content").load(this.href);
return false;
});
- jQuery("#sb_content_individuals").on("click", ".sb_indi_surname", function() {
- var element = jQuery(this);
+ $("#sb_content_individuals").on("click", ".sb_indi_surname", function() {
+ var element = $(this);
var surname = element.data("surname");
var alpha = element.data("alpha");
@@ -125,7 +124,7 @@ class IndividualSidebarModule extends AbstractModule implements ModuleSidebarInt
url: "module.php?mod=' . $this->getName() . '&mod_action=ajax&alpha=" + encodeURIComponent(alpha) + "&surname=" + encodeURIComponent(surname),
cache: false,
success: function(html) {
- jQuery("div.name_tree_div", element.closest("li"))
+ $("div.name_tree_div", element.closest("li"))
.html(html)
.show("fast")
.css("list-style-image", "url(' . Theme::theme()->parameter('image-minus') . ')");
@@ -134,12 +133,12 @@ class IndividualSidebarModule extends AbstractModule implements ModuleSidebarInt
});
} else if (loadedNames[surname]==1) {
loadedNames[surname]=2;
- jQuery("div.name_tree_div", jQuery(this).closest("li"))
+ $("div.name_tree_div", $(this).closest("li"))
.show()
.css("list-style-image", "url(' . Theme::theme()->parameter('image-minus') . ')");
} else {
loadedNames[surname]=1;
- jQuery("div.name_tree_div", jQuery(this).closest("li"))
+ $("div.name_tree_div", $(this).closest("li"))
.hide("fast")
.css("list-style-image", "url(' . Theme::theme()->parameter('image-plus') . ')");
}
diff --git a/app/Module/InteractiveTree/TreeView.php b/app/Module/InteractiveTree/TreeView.php
index 8c8478d871..74b66bcc39 100644
--- a/app/Module/InteractiveTree/TreeView.php
+++ b/app/Module/InteractiveTree/TreeView.php
@@ -53,7 +53,7 @@ class TreeView {
$html = '
<a name="tv_content"></a>
<div id="' . $this->name . '_out" class="tv_out">
- <div id="tv_tools" class="noprint">
+ <div id="tv_tools">
<ul>
<li id="tvbCompact" class="tv_button">
<img src="' . WT_STATIC_URL . WT_MODULES_DIR . 'tree/images/compact.png" alt="' . I18N::translate('Use compact layout') . '" title="' . I18N::translate('Use compact layout') . '">
diff --git a/app/Module/InteractiveTreeModule.php b/app/Module/InteractiveTreeModule.php
index afec0fcbd8..67a9e68a76 100644
--- a/app/Module/InteractiveTreeModule.php
+++ b/app/Module/InteractiveTreeModule.php
@@ -15,7 +15,6 @@
*/
namespace Fisharebest\Webtrees\Module;
-use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Controller\ChartController;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\I18N;
@@ -52,14 +51,13 @@ class InteractiveTreeModule extends AbstractModule implements ModuleTabInterface
return
'<script src="' . $this->js() . '"></script>' .
- '<script src="' . WT_JQUERYUI_TOUCH_PUNCH_URL . '"></script>' .
'<script>' . $js . '</script>' .
$html;
}
/** {@inheritdoc} */
public function hasTabContent() {
- return !Auth::isSearchEngine();
+ return true;
}
/** {@inheritdoc} */
@@ -97,7 +95,7 @@ class InteractiveTreeModule extends AbstractModule implements ModuleTabInterface
/** {@inheritdoc} */
public function getPreLoadContent() {
- // We cannot use jQuery("head").append(<link rel="stylesheet" ...as jQuery is not loaded at this time
+ // We cannot use $("head").append(<link rel="stylesheet" ...as jQuery is not loaded at this time
return
'<script>
if (document.createStyleSheet) {
@@ -135,13 +133,12 @@ class InteractiveTreeModule extends AbstractModule implements ModuleTabInterface
->setPageTitle(I18N::translate('Interactive tree of %s', $person->getFullName()))
->pageHeader()
->addExternalJavascript($this->js())
- ->addExternalJavascript(WT_JQUERYUI_TOUCH_PUNCH_URL)
->addInlineJavascript($js)
->addInlineJavascript('
if (document.createStyleSheet) {
document.createStyleSheet("' . $this->css() . '"); // For Internet Explorer
} else {
- jQuery("head").append(\'<link rel="stylesheet" type="text/css" href="' . $this->css() . '">\');
+ $("head").append(\'<link rel="stylesheet" type="text/css" href="' . $this->css() . '">\');
}
');
echo $html;
diff --git a/app/Module/LifespansChartModule.php b/app/Module/LifespansChartModule.php
index f5a5aab6ea..f54c3a7573 100644
--- a/app/Module/LifespansChartModule.php
+++ b/app/Module/LifespansChartModule.php
@@ -61,7 +61,7 @@ class LifespansChartModule extends AbstractModule implements ModuleChartInterfac
public function getChartMenu(Individual $individual) {
return new Menu(
$this->getTitle(),
- 'lifespan.php',
+ 'lifespan.php?',
'menu-chart-lifespan',
['rel' => 'nofollow']
);
diff --git a/app/Module/LoggedInUsersModule.php b/app/Module/LoggedInUsersModule.php
index 23efe5aaaa..24e9c10580 100644
--- a/app/Module/LoggedInUsersModule.php
+++ b/app/Module/LoggedInUsersModule.php
@@ -17,7 +17,7 @@ namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\Functions;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Theme;
@@ -87,7 +87,7 @@ class LoggedInUsersModule extends AbstractModule implements ModuleBlockInterface
}
$content .= ' - ' . Filter::escapeHtml($user->getUserName());
if (Auth::id() != $user->getUserId() && $user->getPreference('contactmethod') != 'none') {
- $content .= ' <a class="icon-email" href="#" onclick="return message(\'' . Filter::escapeHtml($user->getUserName()) . '\', \'\', \'' . Filter::escapeHtml(Functions::getQueryUrl()) . '\');" title="' . I18N::translate('Send a message') . '"></a>';
+ $content .= FontAwesome::linkIcon('email', I18N::translate('Send a message'), ['class' => 'btn btn-link', 'href' => 'message.php?to=' . Filter::escapeUrl($user->getUserName()) . '&ged=' . $WT_TREE->getNameUrl()]);
}
$content .= '</div>';
}
diff --git a/app/Module/LoginBlockModule.php b/app/Module/LoginBlockModule.php
index 17ccb48284..009e1452e6 100644
--- a/app/Module/LoginBlockModule.php
+++ b/app/Module/LoginBlockModule.php
@@ -48,11 +48,11 @@ class LoginBlockModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
$controller->addInlineJavascript('
- jQuery("#new_passwd").hide();
- jQuery("#passwd_click").click(function() {
- jQuery("#new_passwd").slideToggle(200);
- jQuery("#register-link").slideToggle(200);
- jQuery("#new_passwd_username").focus();
+ $("#new_passwd").hide();
+ $("#passwd_click").click(function() {
+ $("#new_passwd").slideToggle(200);
+ $("#register-link").slideToggle(200);
+ $("#new_passwd_username").focus();
return false;
});
@@ -86,7 +86,7 @@ class LoginBlockModule extends AbstractModule implements ModuleBlockInterface {
<div>
<a href="#" id="passwd_click">' . I18N::translate('Forgot password?') . '</a>
</div>';
- if (Site::getPreference('USE_REGISTRATION_MODULE')) {
+ if (Site::getPreference('USE_REGISTRATION_MODULE') === '1') {
$content .= '<div id="register-link"><a href="' . WT_LOGIN_URL . '?action=register">' . I18N::translate('Request a new user account') . '</a></div>';
}
$content .= '</form>'; // close "login-form"
diff --git a/app/Module/MediaTabModule.php b/app/Module/MediaTabModule.php
index c5aed61deb..692a3fa2f8 100644
--- a/app/Module/MediaTabModule.php
+++ b/app/Module/MediaTabModule.php
@@ -20,7 +20,6 @@ use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Functions\Functions;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
/**
@@ -80,16 +79,16 @@ class MediaTabModule extends AbstractModule implements ModuleTabInterface {
?>
<tr>
<td class="facts_label">
- <?php echo GedcomTag::getLabel('OBJE'); ?>
+ <?= I18N::translate('Media object') ?>
</td>
<td class="facts_value">
- <a href="#" onclick="window.open('addmedia.php?action=showmediaform&amp;linktoid=<?php echo $controller->record->getXref(); ?>&amp;ged=<?php echo $controller->record->getTree()->getNameUrl(); ?>', '_blank', edit_window_specs); return false;">
- <?php echo I18N::translate('Add a media object'); ?>
+ <a href="#" onclick="window.open('addmedia.php?action=showmediaform&amp;linktoid=<?= $controller->record->getXref() ?>&amp;ged=<?= $controller->record->getTree()->getNameUrl() ?>', '_blank', edit_window_specs); return false;">
+ <?= I18N::translate('Add a media object') ?>
</a>
- <?php echo FunctionsPrint::helpLink('OBJE'); ?>
+ <?= FunctionsPrint::helpLink('OBJE') ?>
<br>
- <a href="#" onclick="window.open('inverselink.php?linktoid=<?php echo $controller->record->getXref(); ?>&amp;ged=<?php echo $WT_TREE->getNameUrl(); ?>&amp;linkto=person', '_blank', find_window_specs); return false;">
- <?php echo I18N::translate('Link to an existing media object'); ?>
+ <a href="#" onclick="window.open('inverselink.php?linktoid=<?= $controller->record->getXref() ?>&amp;ged=<?= $WT_TREE->getNameUrl() ?>&amp;linkto=person', '_blank', find_window_specs); return false;">
+ <?= I18N::translate('Link to an existing media object') ?>
</a>
</td>
</tr>
@@ -132,7 +131,7 @@ class MediaTabModule extends AbstractModule implements ModuleTabInterface {
/** {@inheritdoc} */
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/** {@inheritdoc} */
diff --git a/app/Module/NotesTabModule.php b/app/Module/NotesTabModule.php
index 075ccb8826..a3ed5e6682 100644
--- a/app/Module/NotesTabModule.php
+++ b/app/Module/NotesTabModule.php
@@ -67,11 +67,11 @@ class NotesTabModule extends AbstractModule implements ModuleTabInterface {
<col class="width20">
<col class="width80">
</colgroup>
- <tr class="noprint">
+ <tr>
<td colspan="2" class="descriptionbox rela">
<label>
<input id="show-level-2-notes" type="checkbox">
- <?php echo I18N::translate('Show all notes'); ?>
+ <?= I18N::translate('Show all notes') ?>
</label>
</td>
</tr>
@@ -93,23 +93,23 @@ class NotesTabModule extends AbstractModule implements ModuleTabInterface {
// New note link
if ($controller->record->canEdit()) {
?>
- <tr class="noprint">
+ <tr>
<td class="facts_label">
- <?php echo GedcomTag::getLabel('NOTE'); ?>
+ <?= GedcomTag::getLabel('NOTE') ?>
</td>
<td class="facts_value">
- <a href="#" onclick="add_new_record('<?php echo $controller->record->getXref(); ?>','NOTE'); return false;">
- <?php echo I18N::translate('Add a note'); ?>
+ <a href="edit_interface.php?action=add&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;fact=NOTE">
+ <?= I18N::translate('Add a note') ?>
</a>
</td>
</tr>
- <tr class="noprint">
+ <tr>
<td class="facts_label">
- <?php echo GedcomTag::getLabel('SHARED_NOTE'); ?>
+ <?= GedcomTag::getLabel('SHARED_NOTE') ?>
</td>
<td class="facts_value">
- <a href="#" onclick="add_new_record('<?php echo $controller->record->getXref(); ?>','SHARED_NOTE'); return false;">
- <?php echo I18N::translate('Add a shared note'); ?>
+ <a href="edit_interface.php?action=add&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;fact=SHARED_NOTE">
+ <?= I18N::translate('Add a shared note') ?>
</a>
</td>
</tr>
@@ -118,7 +118,7 @@ class NotesTabModule extends AbstractModule implements ModuleTabInterface {
?>
</table>
<script>
- persistent_toggle("show-level-2-notes", ".row_note2");
+ //persistent_toggle("show-level-2-notes", ".row_note2");
</script>
<?php
@@ -156,7 +156,7 @@ class NotesTabModule extends AbstractModule implements ModuleTabInterface {
/** {@inheritdoc} */
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/** {@inheritdoc} */
diff --git a/app/Module/OnThisDayModule.php b/app/Module/OnThisDayModule.php
index 7b3f5df809..fe829bf094 100644
--- a/app/Module/OnThisDayModule.php
+++ b/app/Module/OnThisDayModule.php
@@ -16,7 +16,9 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
use Fisharebest\Webtrees\I18N;
@@ -51,9 +53,8 @@ class OnThisDayModule extends AbstractModule implements ModuleBlockInterface {
$filter = $this->getBlockSetting($block_id, 'filter', '1');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha');
- $block = $this->getBlockSetting($block_id, 'block', '1');
- foreach (['filter', 'infoStyle', 'sortStyle', 'block'] as $name) {
+ foreach (['filter', 'infoStyle', 'sortStyle'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -64,7 +65,7 @@ class OnThisDayModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -89,10 +90,6 @@ class OnThisDayModule extends AbstractModule implements ModuleBlockInterface {
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -124,39 +121,39 @@ class OnThisDayModule extends AbstractModule implements ModuleBlockInterface {
$this->setBlockSetting($block_id, 'filter', Filter::postBool('filter'));
$this->setBlockSetting($block_id, 'infoStyle', Filter::post('infoStyle', 'list|table', 'table'));
$this->setBlockSetting($block_id, 'sortStyle', Filter::post('sortStyle', 'alpha|anniv', 'alpha'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$filter = $this->getBlockSetting($block_id, 'filter', '1');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha');
- $block = $this->getBlockSetting($block_id, 'block', '1');
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Show only events of living individuals');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('filter', $filter);
- echo '</td></tr>';
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('list'), 'table' => I18N::translate('table')], null, $infoStyle, '');
- echo '</td></tr>';
+ ?>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="filter">
+ <?= /* I18N: Label for a configuration option */ I18N::translate('Show only events of living individuals') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('filter', FunctionsEdit::optionsNoYes(), $filter, true) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Sort order');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('sortStyle', [
- /* I18N: An option in a list-box */ 'alpha' => I18N::translate('sort by name'),
- /* I18N: An option in a list-box */ 'anniv' => I18N::translate('sort by date'),
- ], null, $sortStyle, '');
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="infoStyle">
+ <?= /* I18N: Label for a configuration option */ I18N::translate('Presentation style') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['list' => I18N::translate('list'), 'table' => I18N::translate('table')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="sortStyle">
+ <?= /* I18N: Label for a configuration option */ I18N::translate('Sort order') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['alpha' => /* I18N: An option in a list-box */ I18N::translate('sort by name'), 'anniv' => /* I18N: An option in a list-box */ I18N::translate('sort by date')], $sortStyle, ['id' => 'sortStyle', 'name' => 'sortStyle']) ?>
+ </div>
+ </div>
+ <?php
}
}
diff --git a/app/Module/RecentChangesModule.php b/app/Module/RecentChangesModule.php
index d05089074d..fa2305f98e 100644
--- a/app/Module/RecentChangesModule.php
+++ b/app/Module/RecentChangesModule.php
@@ -16,8 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\GedcomTag;
@@ -57,10 +59,8 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', self::DEFAULT_INFO_STYLE);
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', self::DEFAULT_SORT_STYLE);
$show_user = $this->getBlockSetting($block_id, 'show_user', self::DEFAULT_SHOW_USER);
- $block = $this->getBlockSetting($block_id, 'block', self::DEFAULT_BLOCK);
- $hide_empty = $this->getBlockSetting($block_id, 'hide_empty', self::DEFAULT_HIDE_EMPTY);
- foreach (['days', 'infoStyle', 'sortStyle', 'hide_empty', 'show_user', 'block'] as $name) {
+ foreach (['days', 'infoStyle', 'sortStyle', 'show_user'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -68,16 +68,12 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$records = $this->getRecentChanges($WT_TREE, $days);
- if (empty($records) && $hide_empty) {
- return '';
- }
-
// Print block header
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -99,10 +95,6 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -131,60 +123,41 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$this->setBlockSetting($block_id, 'infoStyle', Filter::post('infoStyle', 'list|table'));
$this->setBlockSetting($block_id, 'sortStyle', Filter::post('sortStyle', 'name|date_asc|date_desc'));
$this->setBlockSetting($block_id, 'show_user', Filter::postBool('show_user'));
- $this->setBlockSetting($block_id, 'hide_empty', Filter::postBool('hide_empty'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$days = $this->getBlockSetting($block_id, 'days', self::DEFAULT_DAYS);
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', self::DEFAULT_INFO_STYLE);
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', self::DEFAULT_SORT_STYLE);
$show_user = $this->getBlockSetting($block_id, 'show_user', self::DEFAULT_SHOW_USER);
- $block = $this->getBlockSetting($block_id, 'block', self::DEFAULT_BLOCK);
- $hide_empty = $this->getBlockSetting($block_id, 'hide_empty', self::DEFAULT_HIDE_EMPTY);
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="days">';
echo I18N::translate('Number of days to show');
- echo '</td><td class="optionbox">';
+ echo '</div><div class="col-sm-9">';
echo '<input type="text" name="days" size="2" value="', $days, '">';
- echo ' <em>', I18N::plural('maximum %s day', 'maximum %s days', I18N::number(self::MAX_DAYS), I18N::number(self::MAX_DAYS)), '</em>';
- echo '</td></tr>';
+ echo ' ' . I18N::plural('maximum %s day', 'maximum %s days', I18N::number(self::MAX_DAYS), I18N::number(self::MAX_DAYS));
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="infoStyle">';
echo I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('list'), 'table' => I18N::translate('table')], null, $infoStyle, '');
- echo '</td></tr>';
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::select(['list' => I18N::translate('list'), 'table' => I18N::translate('table')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']);
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="sortStyle">';
echo I18N::translate('Sort order');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('sortStyle', [
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::select([
'name' => /* I18N: An option in a list-box */ I18N::translate('sort by name'),
'date_asc' => /* I18N: An option in a list-box */ I18N::translate('sort by date, oldest first'),
'date_desc' => /* I18N: An option in a list-box */ I18N::translate('sort by date, newest first'),
- ], null, $sortStyle, '');
- echo '</td></tr>';
+ ], $sortStyle, ['id' => 'sortStyle', 'name' => 'sortStyle']);
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="show_usere">';
echo /* I18N: label for a yes/no option */ I18N::translate('Show the user who made the change');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('show_user', $show_user);
- echo '</td></tr>';
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Should this block be hidden when it is empty');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('hide_empty', $hide_empty);
- echo '</td></tr>';
- echo '<tr><td colspan="2" class="optionbox wrap">';
- echo '<span class="error">', I18N::translate('If you hide an empty block, you will not be able to change its configuration until it becomes visible by no longer being empty.'), '</span>';
- echo '</td></tr>';
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::radioButtons('show_user', FunctionsEdit::optionsNoYes(), $show_user, true);
+ echo '</div></div>';
}
/**
@@ -298,16 +271,14 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$html = '';
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery("#' . $table_id . '").dataTable({
+ $("#' . $table_id . '").dataTable({
dom: \'t\',
paging: false,
autoWidth:false,
lengthChange: false,
filter: false,
' . I18N::datatablesI18N() . ',
- jQueryUI: true,
sorting: [' . $aaSorting . '],
columns: [
{ sortable: false, class: "center" },
@@ -322,7 +293,7 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$html .= '<thead><tr>';
$html .= '<th></th>';
$html .= '<th>' . I18N::translate('Record') . '</th>';
- $html .= '<th>' . GedcomTag::getLabel('CHAN') . '</th>';
+ $html .= '<th>' . I18N::translate('Last change') . '</th>';
$html .= '<th>' . GedcomTag::getLabel('_WT_USER') . '</th>';
$html .= '</tr></thead><tbody>';
@@ -330,22 +301,25 @@ class RecentChangesModule extends AbstractModule implements ModuleBlockInterface
$html .= '<tr><td>';
switch ($record::RECORD_TYPE) {
case 'INDI':
- $html .= $record->getSexImage('small');
+ $html .= FontAwesome::semanticIcon('individual', I18N::translate('Individual'));
break;
case 'FAM':
- $html .= '<i class="icon-button_family"></i>';
+ $html .= FontAwesome::semanticicon('family', I18N::translate('Family'));
break;
case 'OBJE':
- $html .= '<i class="icon-button_media"></i>';
+ $html .= FontAwesome::semanticIcon('media', I18N::translate('Media'));
break;
case 'NOTE':
- $html .= '<i class="icon-button_note"></i>';
+ $html .= FontAwesome::semanticIcon('note', I18N::translate('Note'));
break;
case 'SOUR':
- $html .= '<i class="icon-button_source"></i>';
+ $html .= FontAwesome::semanticIcon('source', I18N::translate('Source'));
+ break;
+ case 'SUBM':
+ $html .= FontAwesome::semanticIcon('submitter', I18N::translate('Submitter'));
break;
case 'REPO':
- $html .= '<i class="icon-button_repository"></i>';
+ $html .= FontAwesome::semanticIcon('repository', I18N::translate('Repository'));
break;
}
$html .= '</td>';
diff --git a/app/Module/RelationshipsChartModule.php b/app/Module/RelationshipsChartModule.php
index 6de6943faf..37bba9e144 100644
--- a/app/Module/RelationshipsChartModule.php
+++ b/app/Module/RelationshipsChartModule.php
@@ -16,10 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\FlashMessages;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
@@ -159,45 +159,47 @@ class RelationshipsChartModule extends AbstractModule implements ModuleConfigInt
->setPageTitle(I18N::translate('Chart preferences') . ' — ' . $this->getTitle())
->pageHeader();
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h1><?php echo $controller->getPageTitle(); ?></h1>
+
+ <h1><?= $controller->getPageTitle() ?></h1>
<p>
- <?php echo I18N::translate('Searching for all possible relationships can take a lot of time in complex trees.') ?>
+ <?= I18N::translate('Searching for all possible relationships can take a lot of time in complex trees.') ?>
</p>
<form method="post">
<?php foreach (Tree::getAll() as $tree): ?>
- <h2><?php echo $tree->getTitleHtml() ?></h2>
- <div class="form-group">
- <label class="control-label col-sm-3" for="relationship-ancestors-<?php echo $tree->getTreeId() ?>">
- <?php echo /* I18N: Configuration option */I18N::translate('Relationships'); ?>
+ <h2><?= $tree->getTitleHtml() ?></h2>
+ <div class="row form-group">
+ <label class="col-sm-3 col-form-label" for="relationship-ancestors-<?= $tree->getTreeId() ?>">
+ <?= /* I18N: Configuration option */I18N::translate('Relationships') ?>
</label>
<div class="col-sm-9">
- <?php echo FunctionsEdit::selectEditControl('relationship-ancestors-' . $tree->getTreeId(), $this->ancestorsOptions(), null, $tree->getPreference('RELATIONSHIP_ANCESTORS', self::DEFAULT_ANCESTORS), 'class="form-control"'); ?>
+ <?= Bootstrap4::select($this->ancestorsOptions(), $tree->getPreference('RELATIONSHIP_ANCESTORS', self::DEFAULT_ANCESTORS), ['id' => 'relationship-ancestors-' . $tree->getTreeId(), 'name' => 'relationship-ancestors-' . $tree->getTreeId()]) ?>
</div>
</div>
<fieldset class="form-group">
- <legend class="control-label col-sm-3">
- <?php echo /* I18N: Configuration option */I18N::translate('How much recursion to use when searching for relationships'); ?>
- </legend>
- <div class="col-sm-9">
- <?php echo FunctionsEdit::radioButtons('relationship-recursion-' . $tree->getTreeId(), $this->recursionOptions(), $tree->getPreference('RELATIONSHIP_RECURSION', self::DEFAULT_RECURSION), 'class="radio-inline"'); ?>
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= /* I18N: Configuration option */I18N::translate('How much recursion to use when searching for relationships') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('relationship-recursion-' . $tree->getTreeId(), $this->recursionOptions(), $tree->getPreference('RELATIONSHIP_RECURSION', self::DEFAULT_RECURSION), true) ?>
+ </div>
</div>
</fieldset>
- <?php endforeach; ?>
+ <?php endforeach ?>
- <div class="form-group">
- <div class="col-sm-offset-3 col-sm-9">
+ <div class="row form-group">
+ <div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-primary">
<i class="fa fa-check"></i>
- <?php echo I18N::translate('save'); ?>
+ <?= I18N::translate('save') ?>
</button>
</div>
</div>
diff --git a/app/Module/RelativesTabModule.php b/app/Module/RelativesTabModule.php
index f95dc30a67..2817c5f5ae 100644
--- a/app/Module/RelativesTabModule.php
+++ b/app/Module/RelativesTabModule.php
@@ -114,8 +114,8 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
<i class="icon-cfamily"></i>
</td>
<td>
- <span class="subheaders"> <?php echo $label; ?></span>
- <a class="noprint" href="<?php echo $family->getHtmlUrl(); ?>"> - <?php echo I18N::translate('View this family'); ?></a>
+ <span class="subheaders"> <?= $label ?></span>
+ <a href="<?= $family->getHtmlUrl() ?>"> - <?= I18N::translate('View this family') ?></a>
</td>
</tr>
</table>
@@ -137,11 +137,11 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
}
?>
<tr>
- <td class="<?php echo $class; ?>">
- <?php echo Functions::getCloseRelationshipName($controller->record, $person); ?>
+ <td class="<?= $class ?>">
+ <?= Functions::getCloseRelationshipName($controller->record, $person) ?>
</td>
- <td class="<?php echo $controller->getPersonStyle($person); ?>">
- <?php echo Theme::theme()->individualBoxLarge($person); ?>
+ <td class="<?= $controller->getPersonStyle($person) ?>">
+ <?= Theme::theme()->individualBoxLarge($person) ?>
</td>
</tr>
<?php
@@ -151,7 +151,11 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
?>
<tr>
<td class="facts_label"></td>
- <td class="facts_value"><a href="#" onclick="return add_spouse_to_family('<?php echo $family->getXref(); ?>', 'HUSB');"><?php echo I18N::translate('Add a husband to this family'); ?></a></td>
+ <td class="facts_value">
+ <a href="edit_interface.php?action=add_spouse_to_family&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;famtag=HUSB">
+ <?= I18N::translate('Add a husband to this family') ?>
+ </a>
+ </td>
</tr>
<?php
}
@@ -171,11 +175,11 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
}
?>
<tr>
- <td class="<?php echo $class; ?>">
- <?php echo Functions::getCloseRelationshipName($controller->record, $person); ?>
+ <td class="<?= $class ?>">
+ <?= Functions::getCloseRelationshipName($controller->record, $person) ?>
</td>
- <td class="<?php echo $controller->getPersonStyle($person); ?>">
- <?php echo Theme::theme()->individualBoxLarge($person); ?>
+ <td class="<?= $controller->getPersonStyle($person) ?>">
+ <?= Theme::theme()->individualBoxLarge($person) ?>
</td>
</tr>
<?php
@@ -185,7 +189,11 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
?>
<tr>
<td class="facts_label"></td>
- <td class="facts_value"><a href="#" onclick="return add_spouse_to_family('<?php echo $family->getXref(); ?>', 'WIFE');"><?php echo I18N::translate('Add a wife to this family'); ?></a></td>
+ <td class="facts_value">
+ <a href="edit_interface.php?action=add_spouse_to_family&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;famtag=WIFE">
+ <?= I18N::translate('Add a wife to this family') ?>
+ </a>
+ </td>
</tr>
<?php
}
@@ -206,8 +214,8 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
<tr>
<td class="facts_label">
</td>
- <td class="facts_value<?php echo $class; ?>">
- <?php echo GedcomTag::getLabelValue($fact->getTag(), $fact->getDate()->display() . ' — ' . $fact->getPlace()->getFullName()); ?>
+ <td class="facts_value<?= $class ?>">
+ <?= GedcomTag::getLabelValue($fact->getTag(), $fact->getDate()->display() . ' — ' . $fact->getPlace()->getFullName()) ?>
</td>
</tr>
<?php
@@ -222,8 +230,8 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
<td class="facts_label">
</td>
<td class="facts_value">
- <a href="#" onclick="return add_new_record('<?php echo $family->getXref(); ?>', 'MARR');">
- <?php echo I18N::translate('Add marriage details'); ?>
+ <a href="edit_interface.php?action=add&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;fact=MARR">
+ <?= I18N::translate('Add marriage details') ?>
</a>
</td>
</tr>
@@ -253,12 +261,12 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
}
?>
<tr>
- <td class="<?php echo $class; ?>">
- <?php echo self::ageDifference($prev, $next, $child_number); ?>
- <?php echo Functions::getCloseRelationshipName($controller->record, $person); ?>
+ <td class="<?= $class ?>">
+ <?= self::ageDifference($prev, $next, $child_number) ?>
+ <?= Functions::getCloseRelationshipName($controller->record, $person) ?>
</td>
- <td class="<?php echo $controller->getPersonStyle($person); ?>">
- <?php echo Theme::theme()->individualBoxLarge($person); ?>
+ <td class="<?= $controller->getPersonStyle($person) ?>">
+ <?= Theme::theme()->individualBoxLarge($person) ?>
</td>
</tr>
<?php
@@ -273,17 +281,21 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
$add_child_text = I18N::translate('Add a brother or sister');
}
?>
- <tr class="noprint">
+ <tr>
<td class="facts_label">
- <?php if (count($family->getChildren()) > 1) { ?>
- <a href="#" onclick="reorder_children('<?php echo $family->getXref(); ?>');tabswitch(5);"><i class="icon-media-shuffle"></i> <?php echo I18N::translate('Re-order children'); ?></a>
- <?php } ?>
+ <?php if (count($family->getChildren()) > 1): ?>
+ <a href="edit_interface.php?action=reorder_children&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>">
+ <i class="icon-media-shuffle"></i> <?= I18N::translate('Re-order children') ?>
+ </a>
+ <?php endif; ?>
</td>
<td class="facts_value">
- <a href="#" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>');"><?php echo $add_child_text; ?></a>
+ <a href="edit_interface.php?action=add_child_to_family&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;gender=U">
+ <?= $add_child_text ?>
+ </a>
<span style='white-space:nowrap;'>
- <a href="#" class="icon-sex_m_15x15" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>','M');"></a>
- <a href="#" class="icon-sex_f_15x15" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>','F');"></a>
+ <a href="edit_interface.php?action=add_child_to_family&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;gender=M" class="icon-sex_m_15x15"></a>
+ <a href="edit_interface.php?action=add_child_to_family&amp;ged=<?= $family->getTree()->getNameHtml() ?>&amp;xref=<?= $family->getXref() ?>&amp;gender=F" class="icon-sex_f_15x15"></a>
</span>
</td>
</tr>
@@ -295,22 +307,16 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
/** {@inheritdoc} */
public function getTabContent() {
- global $show_full, $controller;
-
- if (isset($show_full)) {
- $saved_show_full = $show_full;
- }
- // We always want to see full details here
- $show_full = true;
+ global $controller;
ob_start();
?>
<table class="facts_table">
- <tr class="noprint">
+ <tr>
<td class="descriptionbox rela">
<label>
<input id="show-date-differences" type="checkbox" checked>
- <?php echo I18N::translate('Date differences'); ?>
+ <?= I18N::translate('Date differences') ?>
</label>
</td>
</tr>
@@ -321,10 +327,18 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
?>
<table class="facts_table">
<tr>
- <td class="facts_value"><a href="#" onclick="return add_parent_to_individual('<?php echo $controller->record->getXref(); ?>', 'M');"><?php echo I18N::translate('Add a father'); ?></td>
+ <td class="facts_value">
+ <a href="edit_interface.php?action=add_parent_to_individual&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;gender=M">
+ <?= I18N::translate('Add a father') ?>
+ </a>
+ </td>
</tr>
<tr>
- <td class="facts_value"><a href="#" onclick="return add_parent_to_individual('<?php echo $controller->record->getXref(); ?>', 'F');"><?php echo I18N::translate('Add a mother'); ?></a></td>
+ <td class="facts_value">
+ <a href="edit_interface.php?action=add_parent_to_individual&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;gender=F">
+ <?= I18N::translate('Add a mother') ?>
+ </a>
+ </td>
</tr>
</table>
<?php
@@ -353,62 +367,61 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
if ($controller->record->canEdit()) {
?>
- <br><table class="facts_table noprint">
+ <br><table class="facts_table">
<?php
if (count($families) > 1) { ?>
<tr>
<td class="facts_value">
- <a href="#" onclick="return reorder_families('<?php echo $controller->record->getXref(); ?>');"><?php echo I18N::translate('Re-order families'); ?></a>
+ <a href="edit_interface.php?action=reorder_fams&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>">
+ <?= I18N::translate('Re-order families') ?>
+ </a>
</td>
</tr>
<?php } ?>
<tr>
<td class="facts_value">
- <a href="#" onclick="return add_famc('<?php echo $controller->record->getXref(); ?>');"><?php echo I18N::translate('Link this individual to an existing family as a child'); ?></a>
+ <a href="edit_interface.php?action=addfamlink&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>"><?= I18N::translate('Link this individual to an existing family as a child') ?></a>
</td>
</tr>
- <?php if ($controller->record->getSex() != 'F') { ?>
+ <?php if ($controller->record->getSex() !== 'F') { ?>
<tr>
<td class="facts_value">
- <a href="#" onclick="return add_spouse_to_individual('<?php echo $controller->record->getXref(); ?>','WIFE');"><?php echo I18N::translate('Add a wife'); ?></a>
+ <a href="edit_interface.php?action=add_spouse_to_individual&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;sex=F"><?= I18N::translate('Add a wife') ?></a>
</td>
</tr>
<tr>
<td class="facts_value">
- <a href="#" onclick="return linkspouse('<?php echo $controller->record->getXref(); ?>','WIFE');"><?php echo I18N::translate('Add a wife using an existing individual'); ?></a>
+ <a href="edit_interface.php?action=linkspouse&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;famtag=WIFE"><?= I18N::translate('Add a wife using an existing individual') ?></a>
</td>
</tr>
<?php }
- if ($controller->record->getSex() != 'M') { ?>
+ if ($controller->record->getSex() !== 'M') { ?>
<tr>
<td class="facts_value">
- <a href="#" onclick="return add_spouse_to_individual('<?php echo $controller->record->getXref(); ?>','HUSB');"><?php echo I18N::translate('Add a husband'); ?></a>
+ <a href="edit_interface.php?action=add_spouse_to_individual&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;sex=M"><?= I18N::translate('Add a husband') ?></a>
</td>
</tr>
<tr>
<td class="facts_value">
- <a href="#" onclick="return linkspouse('<?php echo $controller->record->getXref(); ?>','HUSB');"><?php echo I18N::translate('Add a husband using an existing individual'); ?></a>
+ <a href="edit_interface.php?action=linkspouse&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;famtag=HUSB"><?= I18N::translate('Add a husband using an existing individual') ?></a>
</td>
</tr>
<?php } ?>
<tr>
<td class="facts_value">
- <a href="#" onclick="return add_child_to_individual('<?php echo $controller->record->getXref(); ?>','U');"><?php echo I18N::translate('Add a child to create a one-parent family'); ?></a>
+ <a href="edit_interface.php?action=add_child_to_individual&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;gender=U">
+ <?= I18N::translate('Add a child to create a one-parent family') ?>
+ </a>
</td>
</tr>
</table>
<?php } ?>
<br>
<script>
- persistent_toggle("show-date-differences", ".elderdate");
+ //persistent_toggle("show-date-differences", ".elderdate");
</script>
<?php
- unset($show_full);
- if (isset($saved_show_full)) {
- $show_full = $saved_show_full;
- }
-
return '<div id="' . $this->getName() . '_content">' . ob_get_clean() . '</div>';
}
@@ -422,7 +435,7 @@ class RelativesTabModule extends AbstractModule implements ModuleTabInterface {
}
/** {@inheritdoc} */
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/** {@inheritdoc} */
diff --git a/app/Module/ResearchTaskModule.php b/app/Module/ResearchTaskModule.php
index ebf2597425..44254a721c 100644
--- a/app/Module/ResearchTaskModule.php
+++ b/app/Module/ResearchTaskModule.php
@@ -16,14 +16,15 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Database;
+use Fisharebest\Webtrees\Datatables;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Theme;
-use Rhumsaa\Uuid\Uuid;
/**
* Class ResearchTaskModule
@@ -54,14 +55,13 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
* @return string
*/
public function getBlock($block_id, $template = true, $cfg = []) {
- global $ctype, $controller, $WT_TREE;
+ global $ctype, $WT_TREE;
$show_other = $this->getBlockSetting($block_id, 'show_other', self::DEFAULT_SHOW_OTHER);
$show_unassigned = $this->getBlockSetting($block_id, 'show_unassigned', self::DEFAULT_SHOW_UNASSIGNED);
$show_future = $this->getBlockSetting($block_id, 'show_future', self::DEFAULT_SHOW_FUTURE);
- $block = $this->getBlockSetting($block_id, 'block', self::DEFAULT_BLOCK);
- foreach (['show_unassigned', 'show_other', 'show_future', 'block'] as $name) {
+ foreach (['show_unassigned', 'show_other', 'show_future'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -70,48 +70,12 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
$title .= $this->getTitle();
- $table_id = Uuid::uuid4(); // create a unique ID
-
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery("#' . $table_id . '").dataTable({
- dom: \'t\',
- ' . I18N::datatablesI18N() . ',
- autoWidth: false,
- paginate: false,
- lengthChange: false,
- filter: false,
- info: true,
- jQueryUI: true,
- columns: [
- null,
- null,
- null,
- null
- ]
- });
- jQuery("#' . $table_id . '").css("visibility", "visible");
- jQuery(".loading-image").css("display", "none");
- ');
-
- $content = '';
- $content .= '<div class="loading-image">&nbsp;</div>';
- $content .= '<table id="' . $table_id . '" style="visibility:hidden;">';
- $content .= '<thead><tr>';
- $content .= '<th>' . GedcomTag::getLabel('DATE') . '</th>';
- $content .= '<th>' . I18N::translate('Record') . '</th>';
- $content .= '<th>' . I18N::translate('Username') . '</th>';
- $content .= '<th>' . GedcomTag::getLabel('TEXT') . '</th>';
- $content .= '</tr></thead><tbody>';
-
- $found = false;
$end_jd = $show_future ? 99999999 : WT_CLIENT_JD;
$xrefs = Database::prepare(
@@ -122,40 +86,38 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
'jd' => $end_jd,
])->fetchOneColumn();
- $facts = [];
+ $content = '';
+ $content .= '<table ' . Datatables::researchTaskTableAttributes() . '>';
+ $content .= '<thead><tr>';
+ $content .= '<th>' . I18N::translate('Date') . '</th>';
+ $content .= '<th>' . I18N::translate('Record') . '</th>';
+ $content .= '<th>' . I18N::translate('Username') . '</th>';
+ $content .= '<th>' . I18N::translate('Research task') . '</th>';
+ $content .= '</tr></thead><tbody>';
+
foreach ($xrefs as $xref) {
$record = GedcomRecord::getInstance($xref, $WT_TREE);
if ($record->canShow()) {
foreach ($record->getFacts('_TODO') as $fact) {
- $facts[] = $fact;
+ $user_name = $fact->getAttribute('_WT_USER');
+ if ($user_name === Auth::user()->getUserName() || !$user_name && $show_unassigned || $user_name && $show_other) {
+ $content .= '<tr>';
+ $content .= '<td data-sort="' . $fact->getDate()->julianDay() . '">' . $fact->getDate()->display() . '</td>';
+ $content .= '<td data-sort="' . Filter::escapeHtml($record->getSortName()) . '"><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>';
+ $content .= '<td>' . $user_name . '</td>';
+ $content .= '<td dir="auto">' . $fact->getValue() . '</td>';
+ $content .= '</tr>';
+ }
}
}
}
- foreach ($facts as $fact) {
- $record = $fact->getParent();
- $user_name = $fact->getAttribute('_WT_USER');
- if ($user_name === Auth::user()->getUserName() || !$user_name && $show_unassigned || $user_name && $show_other) {
- $content .= '<tr>';
- $content .= '<td data-sort="' . $fact->getDate()->julianDay() . '">' . $fact->getDate()->display() . '</td>';
- $content .= '<td data-sort="' . Filter::escapeHtml($record->getSortName()) . '"><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>';
- $content .= '<td>' . $user_name . '</td>';
- $content .= '<td dir="auto">' . $fact->getValue() . '</td>';
- $content .= '</tr>';
- $found = true;
- }
- }
-
$content .= '</tbody></table>';
- if (!$found) {
+ if (empty($xrefs)) {
$content .= '<p>' . I18N::translate('There are no research tasks in this family tree.') . '</p>';
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -187,46 +149,36 @@ class ResearchTaskModule extends AbstractModule implements ModuleBlockInterface
$this->setBlockSetting($block_id, 'show_other', Filter::postBool('show_other'));
$this->setBlockSetting($block_id, 'show_unassigned', Filter::postBool('show_unassigned'));
$this->setBlockSetting($block_id, 'show_future', Filter::postBool('show_future'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$show_other = $this->getBlockSetting($block_id, 'show_other', self::DEFAULT_SHOW_OTHER);
$show_unassigned = $this->getBlockSetting($block_id, 'show_unassigned', self::DEFAULT_SHOW_UNASSIGNED);
$show_future = $this->getBlockSetting($block_id, 'show_future', self::DEFAULT_SHOW_FUTURE);
- $block = $this->getBlockSetting($block_id, 'block', self::DEFAULT_BLOCK);
?>
- <tr>
- <td colspan="2">
- <?php echo I18N::translate('Research tasks are special events, added to individuals in your family tree, which identify the need for further research. You can use them as a reminder to check facts against more reliable sources, to obtain documents or photographs, to resolve conflicting information, etc.'); ?>
- <?php echo I18N::translate('To create new research tasks, you must first add “research task” to the list of facts and events in the family tree’s preferences.'); ?>
- <?php echo I18N::translate('Research tasks are stored using the custom GEDCOM tag “_TODO”. Other genealogy applications may not recognize this tag.'); ?>
- </td>
- </tr>
+ <p>
+ <?= I18N::translate('Research tasks are special events, added to individuals in your family tree, which identify the need for further research. You can use them as a reminder to check facts against more reliable sources, to obtain documents or photographs, to resolve conflicting information, etc.') ?>
+ <?= I18N::translate('To create new research tasks, you must first add “research task” to the list of facts and events in the family tree’s preferences.') ?>
+ <?= I18N::translate('Research tasks are stored using the custom GEDCOM tag “_TODO”. Other genealogy applications may not recognize this tag.') ?>
+ </p>
<?php
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="show_other">';
echo I18N::translate('Show research tasks that are assigned to other users');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('show_other', $show_other);
- echo '</td></tr>';
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::radioButtons('show_other', FunctionsEdit::optionsNoYes(), $show_other, true);
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="show_unassigned">';
echo I18N::translate('Show research tasks that are not assigned to any user');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('show_unassigned', $show_unassigned);
- echo '</td></tr>';
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::radioButtons('show_unassigned', FunctionsEdit::optionsNoYes(), $show_unassigned, true);
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="show_future">';
echo I18N::translate('Show research tasks that have a date in the future');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('show_future', $show_future);
- echo '</td></tr>';
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
+ echo '</div><div class="col-sm-9">';
+ echo Bootstrap4::radioButtons('show_future', FunctionsEdit::optionsNoYes(), $show_future, true);
+ echo '</div></div>';
}
}
diff --git a/app/Module/ReviewChangesModule.php b/app/Module/ReviewChangesModule.php
index e4ae7360fe..6243007b73 100644
--- a/app/Module/ReviewChangesModule.php
+++ b/app/Module/ReviewChangesModule.php
@@ -16,8 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsDate;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomRecord;
@@ -56,9 +58,8 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
$sendmail = $this->getBlockSetting($block_id, 'sendmail', '1');
$days = $this->getBlockSetting($block_id, 'days', '1');
- $block = $this->getBlockSetting($block_id, 'block', '1');
- foreach (['days', 'sendmail', 'block'] as $name) {
+ foreach (['days', 'sendmail'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -73,7 +74,7 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
if ($changes === '1' && $sendmail === '1') {
// There are pending changes - tell moderators/managers/administrators about them.
- if (WT_TIMESTAMP - Site::getPreference('LAST_CHANGE_EMAIL') > (60 * 60 * 24 * $days)) {
+ if (WT_TIMESTAMP - (int) Site::getPreference('LAST_CHANGE_EMAIL') > (60 * 60 * 24 * $days)) {
// Which users have pending changes?
foreach (User::all() as $user) {
if ($user->getPreference('contactmethod') !== 'none') {
@@ -100,7 +101,7 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'user' || Auth::isManager($WT_TREE)) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -108,7 +109,7 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
$content = '';
if (Auth::isModerator($WT_TREE)) {
- $content .= "<a href=\"#\" onclick=\"window.open('edit_changes.php','_blank', chan_window_specs); return false;\">" . I18N::translate('There are pending changes for you to moderate.') . '</a><br>';
+ $content .= '<a href="edit_changes.php">' . I18N::translate('There are pending changes for you to moderate.') . '</a><br>';
}
if ($sendmail === '1') {
$content .= I18N::translate('Last email reminder was sent ') . FunctionsDate::formatTimestamp(Site::getPreference('LAST_CHANGE_EMAIL')) . '<br>';
@@ -131,15 +132,13 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
$content .= '</ul>';
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
}
}
+
+ return '';
}
/** {@inheritdoc} */
@@ -166,33 +165,35 @@ class ReviewChangesModule extends AbstractModule implements ModuleBlockInterface
if (Filter::postBool('save') && Filter::checkCsrf()) {
$this->setBlockSetting($block_id, 'days', Filter::postInteger('num', 1, 180, 1));
$this->setBlockSetting($block_id, 'sendmail', Filter::postBool('sendmail'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$sendmail = $this->getBlockSetting($block_id, 'sendmail', '1');
$days = $this->getBlockSetting($block_id, 'days', '1');
- $block = $this->getBlockSetting($block_id, 'block', '1');
?>
- <tr>
- <td colspan="2">
- <?php echo I18N::translate('This block will show editors a list of records with pending changes that need to be reviewed by a moderator. It also generates daily emails to moderators whenever pending changes exist.'); ?>
- </td>
- </tr>
+ <p>
+ <?= I18N::translate('This block will show editors a list of records with pending changes that need to be reviewed by a moderator. It also generates daily emails to moderators whenever pending changes exist.') ?>
+ </p>
- <?php
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Send out reminder emails');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('sendmail', $sendmail);
- echo '<br>';
- echo I18N::translate('Reminder email frequency (days)') . "&nbsp;<input type='text' name='days' value='" . $days . "' size='2'>";
- echo '</td></tr>';
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= /* I18N: Label for a configuration option */ I18N::translate('Send out reminder emails') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('sendmail', FunctionsEdit::optionsNoYes(), $sendmail, true) ?>
+ </div>
+ </div>
+ </fieldset>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="days">
+ <?= I18N::translate('Reminder email frequency (days)') ?>
+ </label>
+ <div class="col-sm-9">
+ <input class="form-control" type="text" name="days" id="days" value="<?= $days ?>">
+ </div>
+ </div>
+ <?php
}
}
diff --git a/app/Module/SiteMapModule.php b/app/Module/SiteMapModule.php
index 7e33d19fbc..a587f61718 100644
--- a/app/Module/SiteMapModule.php
+++ b/app/Module/SiteMapModule.php
@@ -16,6 +16,7 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
@@ -84,9 +85,9 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface {
*/
private function generateIndex() {
// Check the cache
- $timestamp = $this->getSetting('sitemap.timestamp');
+ $timestamp = (int) $this->getPreference('sitemap.timestamp');
if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE) {
- $data = $this->getSetting('sitemap.xml');
+ $data = $this->getPreference('sitemap.xml');
} else {
$data = '';
$lastmod = '<lastmod>' . date('Y-m-d') . '</lastmod>';
@@ -134,8 +135,8 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface {
}
$data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . PHP_EOL . $data . '</sitemapindex>' . PHP_EOL;
// Cache this data.
- $this->setSetting('sitemap.xml', $data);
- $this->setSetting('sitemap.timestamp', WT_TIMESTAMP);
+ $this->setPreference('sitemap.xml', $data);
+ $this->setPreference('sitemap.timestamp', WT_TIMESTAMP);
}
header('Content-Type: application/xml');
header('Content-Length: ' . strlen($data));
@@ -153,9 +154,9 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface {
private function generateFile($ged_id, $rec_type, $volume) {
$tree = Tree::findById($ged_id);
// Check the cache
- $timestamp = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp');
+ $timestamp = (int) $this->getPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp');
if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE && !Auth::check()) {
- $data = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml');
+ $data = $this->getPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml');
} else {
$data = '<url><loc>' . WT_BASE_URL . 'index.php?ctype=gedcom&amp;ged=' . $tree->getNameUrl() . '</loc></url>' . PHP_EOL;
$records = [];
@@ -259,8 +260,8 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface {
// Cache this data - but only for visitors, as we don’t want
// visitors to see data created by signed-in users.
if (!Auth::check()) {
- $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml', $data);
- $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp', WT_TIMESTAMP);
+ $this->setPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml', $data);
+ $this->setPreference('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp', WT_TIMESTAMP);
}
}
header('Content-Type: application/xml');
@@ -291,13 +292,13 @@ class SiteMapModule extends AbstractModule implements ModuleConfigInterface {
$include_any = false;
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h1><?php echo $controller->getPageTitle(); ?></h1>
+
+ <h1><?= $controller->getPageTitle() ?></h1>
<?php
echo
diff --git a/app/Module/SlideShowModule.php b/app/Module/SlideShowModule.php
index 8741eb01f3..b8d69c8429 100644
--- a/app/Module/SlideShowModule.php
+++ b/app/Module/SlideShowModule.php
@@ -16,8 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\GedcomTag;
@@ -60,22 +62,10 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
$all_media = Database::prepare(
"SELECT m_id FROM `##media`" .
" WHERE m_file = ?" .
- " AND m_ext IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')" .
+ " AND m_ext IN ('jpg', 'jpeg', 'png', 'gif', 'tiff', 'bmp')" .
" AND m_type IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')"
)->execute([
$WT_TREE->getTreeId(),
- $this->getBlockSetting($block_id, 'filter_avi', '0') ? 'avi' : null,
- $this->getBlockSetting($block_id, 'filter_bmp', '1') ? 'bmp' : null,
- $this->getBlockSetting($block_id, 'filter_gif', '1') ? 'gif' : null,
- $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpg' : null,
- $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpeg' : null,
- $this->getBlockSetting($block_id, 'filter_mp3', '0') ? 'mp3' : null,
- $this->getBlockSetting($block_id, 'filter_ole', '1') ? 'ole' : null,
- $this->getBlockSetting($block_id, 'filter_pcx', '1') ? 'pcx' : null,
- $this->getBlockSetting($block_id, 'filter_pdf', '0') ? 'pdf' : null,
- $this->getBlockSetting($block_id, 'filter_png', '1') ? 'png' : null,
- $this->getBlockSetting($block_id, 'filter_tiff', '1') ? 'tiff' : null,
- $this->getBlockSetting($block_id, 'filter_wav', '0') ? 'wav' : null,
$this->getBlockSetting($block_id, 'filter_audio', '0') ? 'audio' : null,
$this->getBlockSetting($block_id, 'filter_book', '1') ? 'book' : null,
$this->getBlockSetting($block_id, 'filter_card', '1') ? 'card' : null,
@@ -121,14 +111,14 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
$title .= $this->getTitle();
if ($random_media) {
- $content = "<div id=\"random_picture_container$block_id\">";
+ $content = '<div id="random_picture_container' . $block_id . '">';
if ($controls) {
if ($start) {
$icon_class = 'icon-media-stop';
@@ -137,18 +127,18 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
}
$content .= '<div dir="ltr" class="center" id="random_picture_controls' . $block_id . '"><br>';
$content .= '<a href="#" onclick="togglePlay(); return false;" id="play_stop" class="' . $icon_class . '" title="' . I18N::translate('Play') . '/' . I18N::translate('Stop') . '"></a>';
- $content .= '<a href="#" onclick="jQuery(\'#block_' . $block_id . '\').load(\'index.php?ctype=' . $ctype . '&amp;action=ajax&amp;block_id=' . $block_id . '\');return false;" title="' . I18N::translate('Next image') . '" class="icon-media-next"></a>';
+ $content .= '<a href="#" onclick="$(\'#block_' . $block_id . '\').load(\'index.php?ctype=' . $ctype . '&amp;action=ajax&amp;block_id=' . $block_id . '\');return false;" title="' . I18N::translate('Next image') . '" class="icon-media-next"></a>';
$content .= '</div><script>
var play = false;
function togglePlay() {
if (play) {
play = false;
- jQuery("#play_stop").removeClass("icon-media-stop").addClass("icon-media-play");
+ $("#play_stop").removeClass("icon-media-stop").addClass("icon-media-play");
}
else {
play = true;
playSlideShow();
- jQuery("#play_stop").removeClass("icon-media-play").addClass("icon-media-stop");
+ $("#play_stop").removeClass("icon-media-play").addClass("icon-media-stop");
}
}
@@ -159,7 +149,7 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
}
function reload_image() {
if (play) {
- jQuery("#block_' . $block_id . '").load("index.php?ctype=' . $ctype . '&action=ajax&block_id=' . $block_id . '&start=1");
+ $("#block_' . $block_id . '").load("index.php?ctype=' . $ctype . '&action=ajax&block_id=' . $block_id . '&start=1");
}
}
</script>';
@@ -223,17 +213,6 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
$this->setBlockSetting($block_id, 'filter', Filter::post('filter', 'indi|event|all', 'all'));
$this->setBlockSetting($block_id, 'controls', Filter::postBool('controls'));
$this->setBlockSetting($block_id, 'start', Filter::postBool('start'));
- $this->setBlockSetting($block_id, 'filter_avi', Filter::postBool('filter_avi'));
- $this->setBlockSetting($block_id, 'filter_bmp', Filter::postBool('filter_bmp'));
- $this->setBlockSetting($block_id, 'filter_gif', Filter::postBool('filter_gif'));
- $this->setBlockSetting($block_id, 'filter_jpeg', Filter::postBool('filter_jpeg'));
- $this->setBlockSetting($block_id, 'filter_mp3', Filter::postBool('filter_mp3'));
- $this->setBlockSetting($block_id, 'filter_ole', Filter::postBool('filter_ole'));
- $this->setBlockSetting($block_id, 'filter_pcx', Filter::postBool('filter_pcx'));
- $this->setBlockSetting($block_id, 'filter_pdf', Filter::postBool('filter_pdf'));
- $this->setBlockSetting($block_id, 'filter_png', Filter::postBool('filter_png'));
- $this->setBlockSetting($block_id, 'filter_tiff', Filter::postBool('filter_tiff'));
- $this->setBlockSetting($block_id, 'filter_wav', Filter::postBool('filter_wav'));
$this->setBlockSetting($block_id, 'filter_audio', Filter::postBool('filter_audio'));
$this->setBlockSetting($block_id, 'filter_book', Filter::postBool('filter_book'));
$this->setBlockSetting($block_id, 'filter_card', Filter::postBool('filter_card'));
@@ -256,26 +235,9 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
$filter = $this->getBlockSetting($block_id, 'filter', 'all');
$controls = $this->getBlockSetting($block_id, 'controls', '1');
- $start = $this->getBlockSetting($block_id, 'start', '0') || Filter::getBool('start');
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Show only individuals, events, or all');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('filter', ['indi' => I18N::translate('Individuals'), 'event' => I18N::translate('Facts and events'), 'all' => I18N::translate('All')], null, $filter, '');
- echo '</td></tr>';
+ $start = $this->getBlockSetting($block_id, 'start', '0');
$filters = [
- 'avi' => $this->getBlockSetting($block_id, 'filter_avi', '0'),
- 'bmp' => $this->getBlockSetting($block_id, 'filter_bmp', '1'),
- 'gif' => $this->getBlockSetting($block_id, 'filter_gif', '1'),
- 'jpeg' => $this->getBlockSetting($block_id, 'filter_jpeg', '1'),
- 'mp3' => $this->getBlockSetting($block_id, 'filter_mp3', '0'),
- 'ole' => $this->getBlockSetting($block_id, 'filter_ole', '1'),
- 'pcx' => $this->getBlockSetting($block_id, 'filter_pcx', '1'),
- 'pdf' => $this->getBlockSetting($block_id, 'filter_pdf', '0'),
- 'png' => $this->getBlockSetting($block_id, 'filter_png', '1'),
- 'tiff' => $this->getBlockSetting($block_id, 'filter_tiff', '1'),
- 'wav' => $this->getBlockSetting($block_id, 'filter_wav', '0'),
'audio' => $this->getBlockSetting($block_id, 'filter_audio', '0'),
'book' => $this->getBlockSetting($block_id, 'filter_book', '1'),
'card' => $this->getBlockSetting($block_id, 'filter_card', '1'),
@@ -297,124 +259,45 @@ class SlideShowModule extends AbstractModule implements ModuleBlockInterface {
];
?>
- <tr>
- <td class="descriptionbox wrap width33">
- <?php echo I18N::translate('Filter'); ?>
- </td>
- <td class="optionbox">
- <center><b><?php echo GedcomTag::getLabel('FORM'); ?></b></center>
- <table class="width100">
- <tr>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_avi" <?php echo $filters['avi'] ? 'checked' : ''; ?>>
- avi
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_bmp" <?php echo $filters['bmp'] ? 'checked' : ''; ?>>
- bmp
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_gif" <?php echo $filters['gif'] ? 'checked' : ''; ?>>
- gif
- </label>
- </td>
- </tr>
- <tr>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_jpeg" <?php echo $filters['jpeg'] ? 'checked' : ''; ?>>
- jpeg
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_mp3" <?php echo $filters['mp3'] ? 'checked' : ''; ?>>
- mp3
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_ole" <?php echo $filters['ole'] ? 'checked' : ''; ?>>
- ole
- </label>
- </td>
- </tr>
- <tr>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_pcx" <?php echo $filters['pcx'] ? 'checked' : ''; ?>>
- pcx
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_pdf" <?php echo $filters['pdf'] ? 'checked' : ''; ?>>
- pdf
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_png" <?php echo $filters['png'] ? 'checked' : ''; ?>>
- png
- </label>
- </td>
- </tr>
- <tr>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_tiff" <?php echo $filters['tiff'] ? 'checked' : ''; ?>>
- tiff
- </label>
- </td>
- <td class="width33">
- <label>
- <input type="checkbox" value="yes" name="filter_wav" <?php echo $filters['wav'] ? 'checked' : ''; ?>>
- wav
- </label>
- </td>
- <td class="width33"></td>
- <td class="width33"></td>
- </tr>
- </table>
- <br>
- <center><b><?php echo GedcomTag::getLabel('TYPE'); ?></b></center>
- <table class="width100">
- <tr>
- <?php
- //-- Build the list of checkboxes
- $i = 0;
- foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue) {
- $i++;
- if ($i > 3) {
- $i = 1;
- echo '</tr><tr>';
- }
- echo '<td class="width33"><label><input type="checkbox" value="yes" name="filter_' . $typeName . '" ';
- echo $filters[$typeName] ? 'checked' : '';
- echo '> ' . $typeValue . '</label></td>';
- }
- ?>
- </tr>
- </table>
- </td>
- </tr>
+ <div class="form-control row">
+ <label class="col-sm-3 col-form-label" for="filter">
+ <?= I18N::translate('Show only individuals, events, or all') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['indi' => I18N::translate('Individuals'), 'event' => I18N::translate('Facts and events'), 'all' => I18N::translate('All')], $filter, ['id' => 'filter', 'name' => 'filter']) ?>
+ </div>
+ </div>
- <?php
+ <fieldset class="form-group">
+ <div class="row">
+ <legend class="col-form-legend col-sm-3">
+ <?= GedcomTag::getLabel('TYPE') ?>
+ </legend>
+ <div class="col-sm-9">
+ <?php foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue): ?>
+ <?= Bootstrap4::checkbox($typeValue, false, ['name' => 'filter_' . $typeName, 'checked' => (bool) $filters[$typeName]]) ?>
+ <?php endforeach ?>
+ </div>
+ </div>
+ </fieldset>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Show slide show controls');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('controls', $controls);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="controls">
+ <?= I18N::translate('Show slide show controls') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('controls', FunctionsEdit::optionsNoYes(), $controls, true) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: Label for a configuration option */ I18N::translate('Start slide show on page load');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('start', $start);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="start">
+ <?= I18N::translate('Start slide show on page load') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('start', FunctionsEdit::optionsNoYes(), $start, true) ?>
+ </div>
+ </div>
+ <?php
}
}
diff --git a/app/Module/SourcesTabModule.php b/app/Module/SourcesTabModule.php
index 842b0ff247..348f47b62c 100644
--- a/app/Module/SourcesTabModule.php
+++ b/app/Module/SourcesTabModule.php
@@ -19,7 +19,6 @@ use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Functions\Functions;
use Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
-use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
/**
@@ -63,11 +62,11 @@ class SourcesTabModule extends AbstractModule implements ModuleTabInterface {
ob_start();
?>
<table class="facts_table">
- <tr class="noprint">
+ <tr>
<td colspan="2" class="descriptionbox rela">
<label>
<input id="show-level-2-sources" type="checkbox">
- <?php echo I18N::translate('Show all sources'); ?>
+ <?= I18N::translate('Show all sources') ?>
</label>
</td>
</tr>
@@ -86,13 +85,13 @@ class SourcesTabModule extends AbstractModule implements ModuleTabInterface {
// New Source Link
if ($controller->record->canEdit()) {
?>
- <tr class="noprint">
+ <tr>
<td class="facts_label">
- <?php echo GedcomTag::getLabel('SOUR'); ?>
+ <?= I18N::translate('Source') ?>
</td>
<td class="facts_value">
- <a href="#" onclick="add_new_record('<?php echo $controller->record->getXref(); ?>','SOUR'); return false;">
- <?php echo I18N::translate('Add a source citation'); ?>
+ <a href="edit_interface.php?action=add&amp;ged=<?= $controller->record->getTree()->getNameHtml() ?>&amp;xref=<?= $controller->record->getXref() ?>&amp;fact=SOUR">
+ <?= I18N::translate('Add a source citation') ?>
</a>
</td>
</tr>
@@ -101,7 +100,7 @@ class SourcesTabModule extends AbstractModule implements ModuleTabInterface {
?>
</table>
<script>
- persistent_toggle("show-level-2-sources", ".row_sour2");
+ //persistent_toggle("show-level-2-sources", ".row_sour2");
</script>
<?php
@@ -139,7 +138,7 @@ class SourcesTabModule extends AbstractModule implements ModuleTabInterface {
/** {@inheritdoc} */
public function canLoadAjax() {
- return !Auth::isSearchEngine(); // Search engines cannot use AJAX
+ return false;
}
/** {@inheritdoc} */
diff --git a/app/Module/StoriesModule.php b/app/Module/StoriesModule.php
index 1c13897b60..a83d936650 100644
--- a/app/Module/StoriesModule.php
+++ b/app/Module/StoriesModule.php
@@ -16,11 +16,11 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
-use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
@@ -197,77 +197,72 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
$story_body = '';
$xref = Filter::get('xref', WT_REGEX_XREF);
}
- $controller
- ->pageHeader()
- ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)
- ->addInlineJavascript('autocomplete();');
+ $controller->pageHeader();
if (Module::getModuleByName('ckeditor')) {
CkeditorModule::enableEditor($controller);
}
$individual = Individual::getInstance($xref, $WT_TREE);
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ 'module.php?mod=' . $this->getName() . '&mod_action=admin_config' => $this->getTitle(),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li><a href="module.php?mod=<?php echo $this->getName(); ?>&mod_action=admin_config"><?php echo $this->getTitle(); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h1><?php echo $controller->getPageTitle(); ?></h1>
+ <h1><?= $controller->getPageTitle() ?></h1>
- <form class="form-horizontal" method="post" action="module.php?mod=<?php echo $this->getName(); ?>&amp;mod_action=admin_edit">
- <?php echo Filter::getCsrf(); ?>
+ <form class="form-horizontal" method="post" action="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit">
+ <?= Filter::getCsrf() ?>
<input type="hidden" name="save" value="1">
- <input type="hidden" name="block_id" value="<?php echo $block_id; ?>">
- <input type="hidden" name="gedcom_id" value="<?php echo $WT_TREE->getTreeId(); ?>">
+ <input type="hidden" name="block_id" value="<?= $block_id ?>">
+ <input type="hidden" name="gedcom_id" value="<?= $WT_TREE->getTreeId() ?>">
- <div class="form-group">
- <label for="title" class="col-sm-3 control-label">
- <?php echo I18N::translate('Story title'); ?>
+ <div class="row form-group">
+ <label for="title" class="col-sm-3 col-form-label">
+ <?= I18N::translate('Story title') ?>
</label>
<div class="col-sm-9">
- <input type="text" class="form-control" name="title" id="title" value="<?php echo Filter::escapeHtml($title); ?>">
+ <input type="text" class="form-control" name="title" id="title" value="<?= Filter::escapeHtml($title) ?>">
</div>
</div>
- <div class="form-group">
- <label for="story_body" class="col-sm-3 control-label">
- <?php echo I18N::translate('Story'); ?>
+ <div class="row form-group">
+ <label for="story_body" class="col-sm-3 col-form-label">
+ <?= I18N::translate('Story') ?>
</label>
<div class="col-sm-9">
- <textarea name="story_body" id="story_body" class="html-edit form-control" rows="10"><?php echo Filter::escapeHtml($story_body); ?></textarea>
+ <textarea name="story_body" id="story_body" class="html-edit form-control" rows="10"><?= Filter::escapeHtml($story_body) ?></textarea>
</div>
</div>
- <div class="form-group">
- <label for="xref" class="col-sm-3 control-label">
- <?php echo I18N::translate('Individual'); ?>
+ <div class="row form-group">
+ <label for="xref" class="col-sm-3 col-form-label">
+ <?= I18N::translate('Individual') ?>
</label>
<div class="col-sm-9">
- <input data-autocomplete-type="INDI" type="text" name="xref" id="xref" size="4" value="<?php echo $xref; ?>">
- <?php echo FunctionsPrint::printFindIndividualLink('xref'); ?>
+ <input data-autocomplete-type="INDI" type="text" name="xref" id="xref" size="4" value="<?= $xref ?>">
<?php if ($individual): ?>
- <?php echo $individual->formatList('span'); ?>
- <?php endif; ?>
+ <?= $individual->formatList('span') ?>
+ <?php endif ?>
</div>
</div>
- <div class="form-group">
- <label for="xref" class="col-sm-3 control-label">
- <?php echo I18N::translate('Show this block for which languages'); ?>
+ <div class="row form-group">
+ <label for="xref" class="col-sm-3 col-form-label">
+ <?= I18N::translate('Show this block for which languages') ?>
</label>
<div class="col-sm-9">
- <?php echo FunctionsEdit::editLanguageCheckboxes('lang', explode(',', $this->getBlockSetting($block_id, 'languages'))); ?>
+ <?= FunctionsEdit::editLanguageCheckboxes('lang', explode(',', $this->getBlockSetting($block_id, 'languages'))) ?>
</div>
</div>
- <div class="form-group">
- <div class="col-sm-offset-3 col-sm-9">
+ <div class="row form-group">
+ <div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-primary">
<i class="fa fa-check"></i>
- <?php echo I18N::translate('save'); ?>
+ <?= I18N::translate('save') ?>
</button>
</div>
</div>
@@ -313,10 +308,8 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
->restrictAccess(Auth::isAdmin())
->setPageTitle($this->getTitle())
->pageHeader()
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)
->addInlineJavascript('
- jQuery("#story_table").dataTable({
+ $("#story_table").dataTable({
' . I18N::datatablesI18N() . ',
autoWidth: false,
paging: true,
@@ -342,72 +335,71 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
" ORDER BY xref"
)->execute([$this->getName(), $WT_TREE->getTreeId()])->fetchAll();
+ echo Bootstrap4::breadcrumbs([
+ 'admin.php' => I18N::translate('Control panel'),
+ 'admin_modules.php' => I18N::translate('Module administration'),
+ ], $controller->getPageTitle());
?>
- <ol class="breadcrumb small">
- <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
- <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
- <li class="active"><?php echo $controller->getPageTitle(); ?></li>
- </ol>
- <h1><?php echo $controller->getPageTitle(); ?></h1>
+ <h1><?= $controller->getPageTitle() ?></h1>
<form class="form form-inline">
<label for="ged" class="sr-only">
- <?php echo I18N::translate('Family tree'); ?>
+ <?= I18N::translate('Family tree') ?>
</label>
- <input type="hidden" name="mod" value="<?php echo $this->getName(); ?>">
+ <input type="hidden" name="mod" value="<?= $this->getName() ?>">
<input type="hidden" name="mod_action" value="admin_config">
- <?php echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), null, $WT_TREE->getName(), 'class="form-control"'); ?>
- <input type="submit" class="btn btn-primary" value="<?php echo I18N::translate('show'); ?>">
+ <?= Bootstrap4::select(Tree::getNameList(), $WT_TREE->getName(), ['id' => 'ged', 'name' => 'ged']) ?>
+ <input type="submit" class="btn btn-primary" value="<?= I18N::translate('show') ?>">
</form>
<p>
- <a href="module.php?mod=<?php echo $this->getName(); ?>&amp;mod_action=admin_edit" class="btn btn-default">
+ <a href="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit" class="btn btn-default">
<i class="fa fa-plus"></i>
- <?php echo I18N::translate('Add a story'); ?>
+ <?= I18N::translate('Add a story') ?>
</a>
</p>
<table class="table table-bordered table-condensed">
<thead>
<tr>
- <th><?php echo I18N::translate('Story title'); ?></th>
- <th><?php echo I18N::translate('Individual'); ?></th>
- <th><?php echo I18N::translate('Edit'); ?></th>
- <th><?php echo I18N::translate('Delete'); ?></th>
+ <th><?= I18N::translate('Story title') ?></th>
+ <th><?= I18N::translate('Individual') ?></th>
+ <th><?= I18N::translate('Edit') ?></th>
+ <th><?= I18N::translate('Delete') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($stories as $story): ?>
<tr>
<td>
- <?php echo Filter::escapeHtml($this->getBlockSetting($story->block_id, 'title')); ?>
+ <?= Filter::escapeHtml($this->getBlockSetting($story->block_id, 'title')) ?>
</td>
<td>
- <?php $individual = Individual::getInstance($story->xref, $WT_TREE); ?>
+ <?php $individual = Individual::getInstance($story->xref, $WT_TREE) ?>
<?php if ($individual): ?>
- <a href="<?php echo $individual->getHtmlUrl(); ?>#stories">
- <?php echo $individual->getFullName(); ?>
+ <a href="<?= $individual->getHtmlUrl() ?>#tab-stories">
+ <?= $individual->getFullName() ?>
</a>
<?php else: ?>
- <?php echo $story->xref; ?>
- <?php endif; ?>
+ <?= $story->xref ?>
+ <?php endif ?>
</td>
<td>
- <a href="module.php?mod=<?php echo $this->getName(); ?>&amp;mod_action=admin_edit&amp;block_id=<?php echo $story->block_id; ?>">
- <i class="fa fa-pencil"></i> <?php echo I18N::translate('Edit'); ?>
+ <a href="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit&amp;block_id=<?= $story->block_id ?>">
+ <i class="fa fa-pencil"></i> <?= I18N::translate('Edit') ?>
</a>
</td>
<td>
<a
- href="module.php?mod=<?php echo $this->getName(); ?>&amp;mod_action=admin_delete&amp;block_id=<?php echo $story->block_id; ?>"
- onclick="return confirm('<?php echo I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($this->getBlockSetting($story->block_id, 'title'))); ?>');"
+ href="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_delete&amp;block_id=<?= $story->block_id ?>"
+ onclick="return confirm('<?= I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($this->getBlockSetting($story->block_id, 'title'))) ?>');"
>
- <i class="fa fa-trash"></i> <?php echo I18N::translate('Delete'); ?>
+ <i class="fa fa-trash"></i> <?= I18N::translate('Delete') ?>
</a>
</td>
</tr>
- <?php endforeach; ?>
+ <?php endforeach ?>
</tbody>
</table>
<?php
@@ -423,9 +415,8 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
$controller
->setPageTitle($this->getTitle())
->pageHeader()
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery("#story_table").dataTable({
+ $("#story_table").dataTable({
dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
' . I18N::datatablesI18N() . ',
autoWidth: false,
@@ -434,7 +425,6 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
lengthChange: true,
filter: true,
info: true,
- jQueryUI: true,
sorting: [[0,"asc"]],
columns: [
/* 0-name */ null,
@@ -451,7 +441,7 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
" ORDER BY xref"
)->execute([$this->getName(), $WT_TREE->getTreeId()])->fetchAll();
- echo '<h2 class="center">', I18N::translate('Stories'), '</h2>';
+ echo '<h2 class="wt-page-title">', I18N::translate('Stories'), '</h2>';
if (count($stories) > 0) {
echo '<table id="story_table" class="width100">';
echo '<thead><tr>
@@ -466,7 +456,7 @@ class StoriesModule extends AbstractModule implements ModuleTabInterface, Module
if (!$languages || in_array(WT_LOCALE, explode(',', $languages))) {
if ($indi) {
if ($indi->canShow()) {
- echo '<tr><td><a href="' . $indi->getHtmlUrl() . '#stories">' . $story_title . '</a></td><td><a href="' . $indi->getHtmlUrl() . '#stories">' . $indi->getFullName() . '</a></td></tr>';
+ echo '<tr><td><a href="' . $indi->getHtmlUrl() . '#tab-stories">' . $story_title . '</a></td><td><a href="' . $indi->getHtmlUrl() . '#tab-stories">' . $indi->getFullName() . '</a></td></tr>';
}
} else {
echo '<tr><td>', $story_title, '</td><td class="error">', $story->xref, '</td></tr>';
diff --git a/app/Module/ThemeSelectModule.php b/app/Module/ThemeSelectModule.php
index a8c12bb197..51a46f7f43 100644
--- a/app/Module/ThemeSelectModule.php
+++ b/app/Module/ThemeSelectModule.php
@@ -48,7 +48,7 @@ class ThemeSelectModule extends AbstractModule implements ModuleBlockInterface {
$menu = Theme::theme()->menuThemes();
if ($menu) {
- $content = '<div class="center theme_form">' . $menu . '</div><br>';
+ $content = '<ul class="nav text-justify">' . $menu->bootstrap4() . '</ul>';
if ($template) {
return Theme::theme()->formatBlock($id, $title, $class, $content);
diff --git a/app/Module/TopGivenNamesModule.php b/app/Module/TopGivenNamesModule.php
index a205e6af9e..84d7ce569a 100644
--- a/app/Module/TopGivenNamesModule.php
+++ b/app/Module/TopGivenNamesModule.php
@@ -16,8 +16,9 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Stats;
use Fisharebest\Webtrees\Theme;
@@ -62,7 +63,7 @@ class TopGivenNamesModule extends AbstractModule implements ModuleBlockInterface
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -142,16 +143,24 @@ class TopGivenNamesModule extends AbstractModule implements ModuleBlockInterface
$num = $this->getBlockSetting($block_id, 'num', '10');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: ... to show in a list */ I18N::translate('Number of given names');
- echo '</td><td class="optionbox">';
- echo '<input type="text" name="num" size="2" value="', $num, '">';
- echo '</td></tr>';
+ ?>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="num">
+ <?= /* I18N: ... to show in a list */ I18N::translate('Number of given names') ?>
+ </label>
+ <div class="col-sm-9">
+ <input type="text" id="num" name="num" size="2" value="<?= $num ?>">
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('list'), 'table' => I18N::translate('table')], null, $infoStyle, '');
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="infoStyle">
+ <?= I18N::translate('Presentation style') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['list' => I18N::translate('list'), 'table' => I18N::translate('table')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']) ?>
+ </div>
+ </div>
+ <?php
}
}
diff --git a/app/Module/TopPageViewsModule.php b/app/Module/TopPageViewsModule.php
index fa863d0cc2..7937fadfe5 100644
--- a/app/Module/TopPageViewsModule.php
+++ b/app/Module/TopPageViewsModule.php
@@ -16,9 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Theme;
@@ -69,7 +70,7 @@ class TopPageViewsModule extends AbstractModule implements ModuleBlockInterface
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -155,16 +156,16 @@ class TopPageViewsModule extends AbstractModule implements ModuleBlockInterface
$num = $this->getBlockSetting($block_id, 'num', '10');
$count_placement = $this->getBlockSetting($block_id, 'count_placement', 'before');
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="num">';
echo /* I18N: ... to show in a list */ I18N::translate('Number of pages');
- echo '</td><td class="optionbox">';
+ echo '</label><div class="col-sm-9">';
echo '<input type="text" name="num" size="2" value="', $num, '">';
- echo '</td></tr>';
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="count_placement">';
echo /* I18N: Label for a configuration option */ I18N::translate('Show counts before or after name');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('count_placement', ['before' => I18N::translate('before'), 'after' => I18N::translate('after')], null, $count_placement, '');
- echo '</td></tr>';
+ echo '</label><div class="col-sm-9">';
+ echo Bootstrap4::select(['before' => I18N::translate('before'), 'after' => I18N::translate('after')], $count_placement, ['id' => 'count_placement', 'name' => 'count_placement']);
+ echo '</div></div>';
}
}
diff --git a/app/Module/TopSurnamesModule.php b/app/Module/TopSurnamesModule.php
index b35371cdc3..97ed881942 100644
--- a/app/Module/TopSurnamesModule.php
+++ b/app/Module/TopSurnamesModule.php
@@ -16,9 +16,10 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsDb;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Query\QueryName;
@@ -84,7 +85,7 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -153,17 +154,25 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface {
$num = $this->getBlockSetting($block_id, 'num', '10');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: ... to show in a list */ I18N::translate('Number of surnames');
- echo '</td><td class="optionbox">';
- echo '<input type="text" name="num" size="2" value="', $num, '">';
- echo '</td></tr>';
+ ?>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="num">
+ <?= /* I18N: ... to show in a list */ I18N::translate('Number of surnames') ?>
+ </label>
+ <div class="col-sm-9">
+ <input type="text" name="num" size="2" value="<?= $num ?>">
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('bullet list'), 'array' => I18N::translate('compact list'), 'table' => I18N::translate('table'), 'tagcloud' => I18N::translate('tag cloud')], null, $infoStyle, '');
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="infoStyle">
+ <?= I18N::translate('Presentation style') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['list' => I18N::translate('bullet list'), 'array' => I18N::translate('compact list'), 'table' => I18N::translate('table'), 'tagcloud' => I18N::translate('tag cloud')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']) ?>
+ </div>
+ </div>
+ <?php
}
/**
diff --git a/app/Module/UpcomingAnniversariesModule.php b/app/Module/UpcomingAnniversariesModule.php
index 59b03291bb..fa79666177 100644
--- a/app/Module/UpcomingAnniversariesModule.php
+++ b/app/Module/UpcomingAnniversariesModule.php
@@ -16,7 +16,9 @@
namespace Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrintLists;
use Fisharebest\Webtrees\I18N;
@@ -61,9 +63,8 @@ class UpcomingAnniversariesModule extends AbstractModule implements ModuleBlockI
$onlyBDM = $this->getBlockSetting($block_id, 'onlyBDM', '0');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha');
- $block = $this->getBlockSetting($block_id, 'block', '1');
- foreach (['days', 'filter', 'onlyBDM', 'infoStyle', 'sortStyle', 'block'] as $name) {
+ foreach (['days', 'filter', 'onlyBDM', 'infoStyle', 'sortStyle'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -75,7 +76,7 @@ class UpcomingAnniversariesModule extends AbstractModule implements ModuleBlockI
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = FontAwesome::linkIcon('preferences', I18N::translate('Preferences'), ['class' => 'btn btn-link', 'href' => 'block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype]) . ' ';
} else {
$title = '';
}
@@ -96,10 +97,6 @@ class UpcomingAnniversariesModule extends AbstractModule implements ModuleBlockI
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -133,7 +130,6 @@ class UpcomingAnniversariesModule extends AbstractModule implements ModuleBlockI
$this->setBlockSetting($block_id, 'onlyBDM', Filter::postBool('onlyBDM'));
$this->setBlockSetting($block_id, 'infoStyle', Filter::post('infoStyle', 'list|table', 'table'));
$this->setBlockSetting($block_id, 'sortStyle', Filter::post('sortStyle', 'alpha|anniv', 'alpha'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$days = $this->getBlockSetting($block_id, 'days', '7');
@@ -141,46 +137,53 @@ class UpcomingAnniversariesModule extends AbstractModule implements ModuleBlockI
$onlyBDM = $this->getBlockSetting($block_id, 'onlyBDM', '0');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$sortStyle = $this->getBlockSetting($block_id, 'sortStyle', 'alpha');
- $block = $this->getBlockSetting($block_id, 'block', '1');
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Number of days to show');
- echo '</td><td class="optionbox">';
- echo '<input type="text" name="days" size="2" value="', $days, '">';
- echo ' <em>', I18N::plural('maximum %s day', 'maximum %s days', 30, I18N::number(30)), '</em>';
- echo '</td></tr>';
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Show only events of living individuals');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('filter', $filter);
- echo '</td></tr>';
+ ?>
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="days">
+ <?= I18N::translate('Number of days to show') ?>
+ </label>
+ <div class="col-sm-9">
+ <input type="text" name="days" id="days" size="2" value="<?= $days ?>">
+ <?= I18N::plural('maximum %s day', 'maximum %s days', 30, I18N::number(30)) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Show only births, deaths, and marriages');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('onlyBDM', $onlyBDM);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="filter">
+ <?= I18N::translate('Show only events of living individuals') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('filter', FunctionsEdit::optionsNoYes(), $filter, true) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('list'), 'table' => I18N::translate('table')], null, $infoStyle, '');
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="onlyBDM">
+ <?= I18N::translate('Show only births, deaths, and marriages') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::radioButtons('onlyBDM', FunctionsEdit::optionsNoYes(), $onlyBDM, true) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo I18N::translate('Sort order');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('sortStyle', [
- /* I18N: An option in a list-box */ 'alpha' => I18N::translate('sort by name'),
- /* I18N: An option in a list-box */ 'anniv' => I18N::translate('sort by date'),
- ], null, $sortStyle, '');
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="infoStyle">
+ <?= I18N::translate('Presentation style') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select(['list' => I18N::translate('list'), 'table' => I18N::translate('table')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']) ?>
+ </div>
+ </div>
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
+ <div class="form-group row">
+ <label class="col-sm-3 col-form-label" for="sortStyle">
+ <?= I18N::translate('Sort order') ?>
+ </label>
+ <div class="col-sm-9">
+ <?= Bootstrap4::select([/* I18N: An option in a list-box */ 'alpha' => I18N::translate('sort by name'), /* I18N: An option in a list-box */ 'anniv' => I18N::translate('sort by date')], $sortStyle, ['id' => 'sortStyle', 'name' => 'sortStyle']) ?>
+ </div>
+ </div>
+ <?php
}
}
diff --git a/app/Module/UserJournalModule.php b/app/Module/UserJournalModule.php
index 05936ac322..178d27a22b 100644
--- a/app/Module/UserJournalModule.php
+++ b/app/Module/UserJournalModule.php
@@ -68,15 +68,6 @@ class UserJournalModule extends AbstractModule implements ModuleBlockInterface {
public function getBlock($block_id, $template = true, $cfg = []) {
global $ctype, $WT_TREE;
- switch (Filter::get('action')) {
- case 'deletenews':
- $news_id = Filter::getInteger('news_id');
- if ($news_id) {
- Database::prepare("DELETE FROM `##news` WHERE news_id = ?")->execute([$news_id]);
- }
- break;
- }
-
$articles = Database::prepare(
"SELECT SQL_CACHE news_id, user_id, gedcom_id, UNIX_TIMESTAMP(updated) + :offset AS updated, subject, body FROM `##news` WHERE user_id = :user_id ORDER BY updated DESC"
)->execute([
@@ -101,13 +92,13 @@ class UserJournalModule extends AbstractModule implements ModuleBlockInterface {
$article->body = nl2br($article->body, false);
}
$content .= $article->body;
- $content .= '<a href="#" onclick="window.open(\'editnews.php?news_id=\'+' . $article->news_id . ', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Edit') . '</a>';
+ $content .= '<a href="editnews.php?news_id=' . $article->news_id . '&amp;ctype=user&amp;ged=' . $WT_TREE->getNameHtml() . '">' . I18N::translate('Edit') . '</a>';
$content .= ' | ';
- $content .= '<a href="index.php?action=deletenews&amp;news_id=' . $article->news_id . '&amp;ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
+ $content .= '<a href="editnews.php?action=delete&amp;news_id=' . $article->news_id . '&amp;ctype=user&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
$content .= '</div><br>';
}
- $content .= '<p><a href="#" onclick="window.open(\'editnews.php?user_id=' . Auth::id() . '\', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Add a journal entry') . '</a></p>';
+ $content .= '<p><a href="editnews.php?ctype=user&amp;ged=' . $WT_TREE->getNameUrl() . '">' . I18N::translate('Add a journal entry') . '</a></p>';
if ($template) {
return Theme::theme()->formatBlock($id, $title, $class, $content);
diff --git a/app/Module/UserMessagesModule.php b/app/Module/UserMessagesModule.php
index 3e534a8941..50206bd960 100644
--- a/app/Module/UserMessagesModule.php
+++ b/app/Module/UserMessagesModule.php
@@ -19,7 +19,6 @@ use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\Functions\FunctionsDate;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Theme;
use Fisharebest\Webtrees\User;
@@ -75,12 +74,6 @@ class UserMessagesModule extends AbstractModule implements ModuleBlockInterface
public function getBlock($block_id, $template = true, $cfg = []) {
global $ctype, $WT_TREE;
- $block = $this->getBlockSetting($block_id, 'block', '1');
- foreach (['block'] as $name) {
- if (array_key_exists($name, $cfg)) {
- $$name = $cfg[$name];
- }
- }
$messages = Database::prepare("SELECT message_id, sender, subject, body, UNIX_TIMESTAMP(created) AS created FROM `##message` WHERE user_id=? ORDER BY message_id DESC")
->execute([Auth::id()])
->fetchAll();
@@ -108,7 +101,7 @@ class UserMessagesModule extends AbstractModule implements ModuleBlockInterface
}
if ($messages) {
$content .= '<table class="list_table"><tr>';
- $content .= '<th class="list_label">' . I18N::translate('Delete') . '<br><a href="#" onclick="jQuery(\'#' . $this->getName() . $block_id . ' :checkbox\').prop(\'checked\', true); return false;">' . I18N::translate('All') . '</a></th>';
+ $content .= '<th class="list_label">' . I18N::translate('Delete') . '<br><a href="#" onclick="$(\'#' . $this->getName() . $block_id . ' :checkbox\').prop(\'checked\', true); return false;">' . I18N::translate('All') . '</a></th>';
$content .= '<th class="list_label">' . I18N::translate('Subject') . '</th>';
$content .= '<th class="list_label">' . I18N::translate('Date sent') . '</th>';
$content .= '<th class="list_label">' . I18N::translate('Email address') . '</th>';
@@ -134,9 +127,9 @@ class UserMessagesModule extends AbstractModule implements ModuleBlockInterface
$message->subject = I18N::translate('RE: ') . $message->subject;
}
if ($user) {
- $content .= '<button type="button" onclick="reply(\'' . Filter::escapeJs($message->sender) . '\', \'' . Filter::escapeJs($message->subject) . '\'); return false;">' . I18N::translate('Reply') . '</button> ';
+ $content .= '<a class="btn btn-secondary" href="message.php?to=' . Filter::escapeUrl($message->sender) . '&amp;subject=' . Filter::escapeUrl($message->subject) . '&amp;ged=' . $WT_TREE->getNameUrl() .'" title="' . I18N::translate('Reply') .'">' . I18N::translate('Reply') . '</a> ';
}
- $content .= '<button type="button" onclick="if (confirm(\'' . I18N::translate('Are you sure you want to delete this message? It cannot be retrieved later.') . '\')) {jQuery(\'#messageform :checkbox\').prop(\'checked\', false); jQuery(\'#cb_message' . $message->message_id . '\').prop(\'checked\', true); document.messageform.submit();}">' . I18N::translate('Delete') . '</button></div></td></tr>';
+ $content .= '<button type="button" onclick="if (confirm(\'' . I18N::translate('Are you sure you want to delete this message? It cannot be retrieved later.') . '\')) {$(\'#messageform :checkbox\').prop(\'checked\', false); $(\'#cb_message' . $message->message_id . '\').prop(\'checked\', true); document.messageform.submit();}">' . I18N::translate('Delete') . '</button></div></td></tr>';
}
$content .= '</table>';
$content .= '<p><button type="submit">' . I18N::translate('Delete selected messages') . '</button></p>';
@@ -144,10 +137,6 @@ class UserMessagesModule extends AbstractModule implements ModuleBlockInterface
$content .= '</form>';
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -175,15 +164,5 @@ class UserMessagesModule extends AbstractModule implements ModuleBlockInterface
* @param int $block_id
*/
public function configureBlock($block_id) {
- if (Filter::postBool('save') && Filter::checkCsrf()) {
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
- }
-
- $block = $this->getBlockSetting($block_id, 'block', '1');
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
}
}
diff --git a/app/Module/UserWelcomeModule.php b/app/Module/UserWelcomeModule.php
index b2b54b28b8..17d927100a 100644
--- a/app/Module/UserWelcomeModule.php
+++ b/app/Module/UserWelcomeModule.php
@@ -48,19 +48,19 @@ class UserWelcomeModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
- $title = '<span dir="auto">' . /* I18N: A greeting; %s is the user’s name */ I18N::translate('Welcome %s', Auth::user()->getRealNameHtml()) . '</span>';
- $content = '<table><tr>';
- $content .= '<td><a href="edituser.php"><i class="icon-mypage"></i><br>' . I18N::translate('My account') . '</a></td>';
+ $title = /* I18N: A greeting; %s is the user’s name */ I18N::translate('Welcome %s', '<span dir="auto">' . Auth::user()->getRealNameHtml() . '</span>');
+ $content = '<div class="row">';
+ $content .= '<div class="col"><a href="edituser.php"><i class="icon-mypage"></i><br>' . I18N::translate('My account') . '</a></div>';
$gedcomid = $WT_TREE->getUserPreference(Auth::user(), 'gedcomid');
if ($gedcomid) {
if (Module::isActiveChart($WT_TREE, 'pedigree_chart')) {
- $content .= '<td><a href="pedigree.php?rootid=' . $gedcomid . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-pedigree"></i><br>' . I18N::translate('My pedigree') . '</a></td>';
+ $content .= '<div class="col"><a href="pedigree.php?rootid=' . $gedcomid . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-pedigree"></i><br>' . I18N::translate('My pedigree') . '</a></div>';
}
- $content .= '<td><a href="individual.php?pid=' . $gedcomid . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-indis"></i><br>' . I18N::translate('My individual record') . '</a></td>';
+ $content .= '<div class="col"><a href="individual.php?pid=' . $gedcomid . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-indis"></i><br>' . I18N::translate('My individual record') . '</a></div>';
}
- $content .= '</tr></table>';
+ $content .= '</div>';
if ($template) {
return Theme::theme()->formatBlock($id, $title, $class, $content);
diff --git a/app/Module/WelcomeBlockModule.php b/app/Module/WelcomeBlockModule.php
index 81cac60b7e..d4690486b8 100644
--- a/app/Module/WelcomeBlockModule.php
+++ b/app/Module/WelcomeBlockModule.php
@@ -51,16 +51,15 @@ class WelcomeBlockModule extends AbstractModule implements ModuleBlockInterface
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
$title = $WT_TREE->getTitleHtml();
- $content = '<table><tr>';
+ $content = '<div class="row">';
if (Module::isActiveChart($WT_TREE, 'pedigree_chart')) {
- $content .= '<td><a href="pedigree.php?rootid=' . $indi_xref . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-pedigree"></i><br>' . I18N::translate('Default chart') . '</a></td>';
+ $content .= '<div class="col"><a href="pedigree.php?rootid=' . $indi_xref . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-pedigree"></i><br>' . I18N::translate('Default chart') . '</a></div>';
}
- $content .= '<td><a href="individual.php?pid=' . $indi_xref . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-indis"></i><br>' . I18N::translate('Default individual') . '</a></td>';
- if (Site::getPreference('USE_REGISTRATION_MODULE') && !Auth::check()) {
- $content .= '<td><a href="' . WT_LOGIN_URL . '?action=register"><i class="icon-user_add"></i><br>' . I18N::translate('Request a new user account') . '</a></td>';
+ $content .= '<div class="col"><a href="individual.php?pid=' . $indi_xref . '&amp;ged=' . $WT_TREE->getNameUrl() . '"><i class="icon-indis"></i><br>' . I18N::translate('Default individual') . '</a></div>';
+ if (Site::getPreference('USE_REGISTRATION_MODULE') === '1' && !Auth::check()) {
+ $content .= '<div class="col"><a href="' . WT_LOGIN_URL . '?action=register"><i class="icon-user_add"></i><br>' . I18N::translate('Request a new user account') . '</a></div>';
}
- $content .= '</tr>';
- $content .= '</table>';
+ $content .= '</div>';
if ($template) {
return Theme::theme()->formatBlock($id, $title, $class, $content);
diff --git a/app/Module/YahrzeitModule.php b/app/Module/YahrzeitModule.php
index aab6c69dff..cec61e6268 100644
--- a/app/Module/YahrzeitModule.php
+++ b/app/Module/YahrzeitModule.php
@@ -17,12 +17,12 @@ namespace Fisharebest\Webtrees\Module;
use Fisharebest\ExtCalendar\JewishCalendar;
use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Bootstrap4;
use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Date\GregorianDate;
use Fisharebest\Webtrees\Date\JewishDate;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\Functions\FunctionsDb;
-use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Theme;
@@ -57,9 +57,8 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
$days = $this->getBlockSetting($block_id, 'days', '7');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$calendar = $this->getBlockSetting($block_id, 'calendar', 'jewish');
- $block = $this->getBlockSetting($block_id, 'block', '1');
- foreach (['days', 'infoStyle', 'block'] as $name) {
+ foreach (['days', 'infoStyle', 'calendar'] as $name) {
if (array_key_exists($name, $cfg)) {
$$name = $cfg[$name];
}
@@ -71,7 +70,7 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
$id = $this->getName() . $block_id;
$class = $this->getName() . '_block';
if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) {
- $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
+ $title = '<a class="fa fa-cog" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '">' . I18N::translate('Preferences') . '</a> ';
} else {
$title = '';
}
@@ -135,9 +134,8 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
default:
$table_id = Uuid::uuid4(); // table requires a unique ID
$controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
->addInlineJavascript('
- jQuery("#' . $table_id . '").dataTable({
+ $("#' . $table_id . '").dataTable({
dom: \'t\',
' . I18N::datatablesI18N() . ',
autoWidth: false,
@@ -145,7 +143,6 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
lengthChange: false,
filter: false,
info: true,
- jQueryUI: true,
sorting: [[5,"asc"]],
columns: [
/* 0-name */ { dataSort: 1 },
@@ -157,8 +154,8 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
/* 6-YART */ { visible: false }
]
});
- jQuery("#' . $table_id . '").css("visibility", "visible");
- jQuery(".loading-image").css("display", "none");
+ $("#' . $table_id . '").css("visibility", "visible");
+ $(".loading-image").css("display", "none");
');
$content = '';
$content .= '<div class="loading-image">&nbsp;</div>';
@@ -166,7 +163,7 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
$content .= '<thead><tr>';
$content .= '<th>' . GedcomTag::getLabel('NAME') . '</th>';
$content .= '<th>' . GedcomTag::getLabel('NAME') . '</th>';
- $content .= '<th>' . GedcomTag::getLabel('DEAT') . '</th>';
+ $content .= '<th>' . I18N::translate('Death') . '</th>';
$content .= '<th>DEAT</th>';
$content .= '<th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th>';
$content .= '<th>' . GedcomTag::getLabel('_YART') . '</th>';
@@ -220,10 +217,6 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
}
if ($template) {
- if ($block === '1') {
- $class .= ' small_inner_block';
- }
-
return Theme::theme()->formatBlock($id, $title, $class, $content);
} else {
return $content;
@@ -255,40 +248,29 @@ class YahrzeitModule extends AbstractModule implements ModuleBlockInterface {
$this->setBlockSetting($block_id, 'days', Filter::postInteger('days', 1, 30, 7));
$this->setBlockSetting($block_id, 'infoStyle', Filter::post('infoStyle', 'list|table', 'table'));
$this->setBlockSetting($block_id, 'calendar', Filter::post('calendar', 'jewish|gregorian', 'jewish'));
- $this->setBlockSetting($block_id, 'block', Filter::postBool('block'));
}
$days = $this->getBlockSetting($block_id, 'days', '7');
$infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
$calendar = $this->getBlockSetting($block_id, 'calendar', 'jewish');
- $block = $this->getBlockSetting($block_id, 'block', '1');
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="days">';
echo I18N::translate('Number of days to show');
- echo '</td><td class="optionbox">';
+ echo '</label><div class="col-sm-9">';
echo '<input type="text" name="days" size="2" value="' . $days . '">';
echo ' <em>', I18N::plural('maximum %s day', 'maximum %s days', 30, I18N::number(30)), '</em>';
- echo '</td></tr>';
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="infoStyle">';
echo I18N::translate('Presentation style');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('infoStyle', ['list' => I18N::translate('list'), 'table' => I18N::translate('table')], null, $infoStyle, '');
- echo '</td></tr>';
+ echo '</label><div class="col-sm-9">';
+ echo Bootstrap4::select(['list' => I18N::translate('list'), 'table' => I18N::translate('table')], $infoStyle, ['id' => 'infoStyle', 'name' => 'infoStyle']);
+ echo '</div></div>';
- echo '<tr><td class="descriptionbox wrap width33">';
+ echo '<div class="form-group row"><label class="col-sm-3 col-form-label" for="calendar">';
echo I18N::translate('Calendar');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::selectEditControl('calendar', [
- 'jewish' => /* I18N: The Hebrew/Jewish calendar */ I18N::translate('Jewish'),
- 'gregorian' => /* I18N: The gregorian calendar */ I18N::translate('Gregorian'),
- ], null, $calendar, '');
- echo '</td></tr>';
-
- echo '<tr><td class="descriptionbox wrap width33">';
- echo /* I18N: label for a yes/no option */ I18N::translate('Add a scrollbar when block contents grow');
- echo '</td><td class="optionbox">';
- echo FunctionsEdit::editFieldYesNo('block', $block);
- echo '</td></tr>';
+ echo '</label><div class="col-sm-9">';
+ echo Bootstrap4::select(['jewish' => I18N::translate('Jewish'), 'gregorian' => I18N::translate('Gregorian')], $calendar, ['id' => 'calendar', 'name' => 'calendar']);
+ echo '</div></div>';
}
}
diff --git a/app/Place.php b/app/Place.php
index 924d756ab3..4d65c09aff 100644
--- a/app/Place.php
+++ b/app/Place.php
@@ -107,18 +107,14 @@ class Place {
* @return string
*/
public function getURL() {
- if (Auth::isSearchEngine()) {
- return '#';
- } else {
- $url = 'placelist.php';
- foreach (array_reverse($this->gedcom_place) as $n => $place) {
- $url .= $n ? '&amp;' : '?';
- $url .= 'parent%5B%5D=' . rawurlencode($place);
- }
- $url .= '&amp;ged=' . $this->tree->getNameUrl();
-
- return $url;
+ $url = 'placelist.php';
+ foreach (array_reverse($this->gedcom_place) as $n => $place) {
+ $url .= $n ? '&amp;' : '?';
+ $url .= 'parent%5B%5D=' . rawurlencode($place);
}
+ $url .= '&amp;ged=' . $this->tree->getNameUrl();
+
+ return $url;
}
/**
@@ -196,7 +192,7 @@ class Place {
}
/**
- * For the "view all" option of placelist.php and find.php
+ * For the "view all" option of placelist.phpp
*
* @return string
*/
diff --git a/app/Report/ReportHtml.php b/app/Report/ReportHtml.php
index ffc10eb865..78174a2396 100644
--- a/app/Report/ReportHtml.php
+++ b/app/Report/ReportHtml.php
@@ -15,7 +15,7 @@
*/
namespace Fisharebest\Webtrees\Report;
-use Fisharebest\Webtrees\Controller\SimpleController;
+use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Functions\FunctionsRtl;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Media;
@@ -208,7 +208,7 @@ class ReportHtml extends ReportBase {
* Run the report.
*/
public function run() {
- $controller = new SimpleController;
+ $controller = new PageController;
$controller
->setPageTitle($this->title)
->pageHeader();
diff --git a/app/Schema/Migration0.php b/app/Schema/Migration0.php
index e6758d103e..ecf075e5f8 100644
--- a/app/Schema/Migration0.php
+++ b/app/Schema/Migration0.php
@@ -370,8 +370,6 @@ class Migration0 implements MigrationInterface {
Site::setPreference('SMTP_HOST', 'localhost');
Site::setPreference('SMTP_PORT', '25');
Site::setPreference('SMTP_AUTH', '1');
- Site::setPreference('SMTP_AUTH_USER', '');
- Site::setPreference('SMTP_AUTH_PASS', '');
Site::setPreference('SMTP_SSL', 'none');
Site::setPreference('SMTP_HELO', $_SERVER['SERVER_NAME']);
Site::setPreference('SMTP_FROM_NAME', $_SERVER['SERVER_NAME']);
diff --git a/app/Schema/Migration18.php b/app/Schema/Migration18.php
index 952fff395e..3d4ab4cf51 100644
--- a/app/Schema/Migration18.php
+++ b/app/Schema/Migration18.php
@@ -35,7 +35,7 @@ class Migration18 implements MigrationInterface {
" DROP KEY ix3," .
" DROP KEY ix4," .
" DROP p_level," . // Not needed - implicit from p_parent
- " ADD KEY ix1 (p_file, p_place)," . // autocomplete.php, find.php
+ " ADD KEY ix1 (p_file, p_place)," . // autocomplete.php
" ADD UNIQUE KEY ux1 (p_parent_id, p_file, p_place)" // placelist.php
);
} catch (PDOException $ex) {
diff --git a/app/Schema/Migration30.php b/app/Schema/Migration30.php
index b17269db92..6b18ea6ede 100644
--- a/app/Schema/Migration30.php
+++ b/app/Schema/Migration30.php
@@ -76,7 +76,6 @@ class Migration30 implements MigrationInterface {
"(-1, 'NOTE_FACTS_UNIQUE', '')," .
"(-1, 'NOTE_ID_PREFIX', 'N')," .
"(-1, 'NO_UPDATE_CHAN', '0')," .
- "(-1, 'PEDIGREE_FULL_DETAILS', '1')," .
"(-1, 'PEDIGREE_LAYOUT', '1')," .
"(-1, 'PEDIGREE_ROOT_ID', '')," .
"(-1, 'PEDIGREE_SHOW_GENDER', '0')," .
diff --git a/app/Select2.php b/app/Select2.php
new file mode 100644
index 0000000000..30a32a2c1a
--- /dev/null
+++ b/app/Select2.php
@@ -0,0 +1,725 @@
+<?php
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2017 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Fisharebest\Webtrees;
+
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+
+/**
+ * Generate markup and AJAX responses for SELECT2 queries.
+ *
+ * @link https://select2.github.io/
+ */
+class Select2 extends Html {
+ // Send this many results with each request.
+ const RESULTS_PER_PAGE = 20;
+
+ // Don't send queries with fewer than this many characters
+ const MINIMUM_INPUT_LENGTH = '1';
+
+ // Don't send queries until this many milliseconds.
+ const DELAY = '350';
+
+ // API endpoints
+ const URL_FAM = 'action.php?action=select2-family';
+ const URL_INDI = 'action.php?action=select2-individual';
+ const URL_NOTE = 'action.php?action=select2-note';
+ const URL_OBJE = 'action.php?action=select2-media';
+ const URL_PLAC = 'action.php?action=select2-place';
+ const URL_REPO = 'action.php?action=select2-repository';
+ const URL_SOUR = 'action.php?action=select2-source';
+ const URL_SUBM = 'action.php?action=select2-submitter';
+ const URL_FLAG = 'action.php?action=select2-flag';
+
+ /**
+ * Select2 configuration that is common to all searches.
+ *
+ * @return string[]
+ */
+ private static function commonConfig() {
+ return [
+ 'autocomplete' => 'off',
+ 'class' => 'form-control select2',
+ 'data-ajax--delay' => self::DELAY,
+ 'data-ajax--minimum-input-length' => self::MINIMUM_INPUT_LENGTH,
+ 'data-ajax--type' => 'POST',
+ 'data-allow-clear' => 'true',
+ 'data-placeholder' => '',
+ ];
+ }
+
+ /**
+ * Select2 configuration for a family lookup.
+ *
+ * @return string[]
+ */
+ public static function familyConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_FAM];
+ }
+
+ /**
+ * Format a family name for display in a Select2 control.
+ *
+ * @param Family $family
+ *
+ * @return string
+ */
+ public static function familyValue(Family $family) {
+ return $family->getFullName();
+ }
+
+ /**
+ * Look up a family.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function familySearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+
+ $cursor = Database::prepare("SELECT DISTINCT 'FAM' AS type, f_id AS xref, f_gedcom AS gedcom, husb_name.n_sort, wife_name.n_sort" .
+ " FROM `##families`" .
+ " JOIN `##name` AS husb_name ON f_husb = husb_name.n_id AND f_file = husb_name.n_file" .
+ " JOIN `##name` AS wife_name ON f_wife = wife_name.n_id AND f_file = wife_name.n_file" .
+ " WHERE CONCAT(husb_name.n_full, ' ', wife_name.n_full) LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND f_file = :tree_id" .
+ " AND husb_name.n_type <> '_MARNM' AND wife_name.n_type <> '_MARNM'" .
+ " ORDER BY husb_name.n_sort, wife_name.n_sort COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $family = Family::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($family !== null && $family->canShowName()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::familyValue($family),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a flag icon lookup.
+ *
+ * @return string[]
+ */
+ public static function flagConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_FLAG];
+ }
+
+ /**
+ * Format a flag icon for display in a Select2 control.
+ *
+ * @param string $flag
+ *
+ * @return string
+ */
+ public static function flagValue($flag) {
+ return '<img src="' . WT_MODULES_DIR . 'googlemap/places/flags/' . $flag . '"> ' . $flag;
+ }
+
+ /**
+ * Look up a flag icon.
+ *
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function flagSearch($page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $directory = WT_ROOT . WT_MODULES_DIR . 'googlemap/places/flags/';
+ $di = new RecursiveDirectoryIterator($directory);
+ $it = new RecursiveIteratorIterator($di);
+
+ $flag_files = [];
+ foreach ($it as $file) {
+ $file_path = substr($file->getPathname() , strlen($directory));
+ if ($file->getExtension() === 'png' && stripos($file_path, $query) !== false) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($flag_files) >= self::RESULTS_PER_PAGE) {
+ $more = true;
+ break;
+ } else {
+ $flag_files[] = $file_path;
+ }
+ }
+ }
+
+ foreach ($flag_files as $flag_file) {
+ $results[] = [
+ 'id' => $flag_file,
+ 'text' => self::flagValue($flag_file),
+ ];
+ }
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for an individual lookup.
+ *
+ * @return string[]
+ */
+ public static function individualConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_INDI];
+ }
+
+ /**
+ * Format an individual name for display in a Select2 control.
+ *
+ * @param Individual $individual
+ *
+ * @return string
+ */
+ public static function individualValue(Individual $individual) {
+ return $individual->getFullName() . ', ' . $individual->getLifeSpan();
+ }
+
+ /**
+ * Look up an individual.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function individualSearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom, n_full" . " FROM `##individuals`" . " JOIN `##name` ON i_id = n_id AND i_file = n_file" . " WHERE n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND i_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $individual = Individual::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($individual !== null && $individual->canShowName()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => str_replace(['@N.N.', '@P.N.'], [I18N::translateContext('Unknown surname', '…'), I18N::translateContext('Unknown given name', '…')], $row->n_full) . ', ' . $individual->getLifeSpan(),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a media object lookup.
+ *
+ * @return string[]
+ */
+ public static function mediaObjectConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_OBJE];
+ }
+
+ /**
+ * Format a media object name for display in a Select2 control.
+ *
+ * @param Media $media
+ *
+ * @return string
+ */
+ public static function mediaObjectValue(Media $media) {
+ return $media->getFullName() . ', ' . basename($media->getFilename());
+ }
+
+ /**
+ * Look up a media object.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function mediaObjectSearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom, n_full" . " FROM `##media`" . " JOIN `##name` ON m_id = n_id AND m_file = n_file" . " WHERE n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND m_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $media = Media::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($media !== null && $media->canShow()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::mediaObjectValue($media),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a note.
+ *
+ * @return string[]
+ */
+ public static function noteConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_NOTE];
+ }
+
+ /**
+ * Format a note name for display in a Select2 control.
+ *
+ * @param Note $note
+ *
+ * @return string
+ */
+ public static function noteValue(Note $note) {
+ return $note->getFullName();
+ }
+
+ /**
+ * Look up a note.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function noteSearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom, n_full" . " FROM `##other`" . " JOIN `##name` ON o_id = n_id AND o_file = n_file" . " WHERE n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND o_file = :tree_id AND o_type='NOTE'" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $note = Note::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($note !== null && $note->canShowName()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::noteValue($note),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a note.
+ *
+ * @return string[]
+ */
+ public static function placeConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_PLAC];
+ }
+
+ /**
+ * Format a note name for display in a Select2 control.
+ *
+ * @param Note $note
+ *
+ * @return string
+ */
+ public static function placeValue(Note $note) {
+ return $note->getFullName();
+ }
+
+ /**
+ * Look up a note.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ * @param bool $create if true, include the query in the results so it can be created.
+ *
+ * @return mixed[]
+ */
+ public static function placeSearch(Tree $tree, $page, $query, $create) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $results = [];
+ $found = false;
+
+ // Do not filter by privacy. Place names on their own do not identify individuals.
+ foreach (Place::findPlaces($query, $tree) as $place) {
+ $place_name = $place->getGedcomName();
+ if ($place_name === $query) {
+ $found = true;
+ }
+ $results[] = [
+ 'id' => $place_name,
+ 'text' => $place_name,
+ ];
+ }
+
+ // No place found? Use an external gazetteer
+ if (empty($results) && $tree->getPreference('GEONAMES_ACCOUNT')) {
+ $url =
+ "http://api.geonames.org/searchJSON" .
+ "?name_startsWith=" . urlencode($query) .
+ "&lang=" . WT_LOCALE .
+ "&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC" .
+ "&style=full" .
+ "&username=" . $tree->getPreference('GEONAMES_ACCOUNT');
+ // try to use curl when file_get_contents not allowed
+ if (ini_get('allow_url_fopen')) {
+ $json = file_get_contents($url);
+ $places = json_decode($json, true);
+ } elseif (function_exists('curl_init')) {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ $json = curl_exec($ch);
+ $places = json_decode($json, true);
+ curl_close($ch);
+ } else {
+ $places = [];
+ }
+ if (isset($places['geonames']) && is_array($places['geonames'])) {
+ foreach ($places['geonames'] as $k => $place) {
+ $place_name = $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName'];
+ if ($place_name === $query) {
+ $found = true;
+ }
+ $results[] = [
+ 'id' => $place_name,
+ 'text' => $place_name,
+ ];
+ }
+ }
+ }
+
+ // Include the query term in the results. This allows the user to select a
+ // place that doesn't already exist in the database.
+ if (!$found && $create) {
+ array_unshift($results, [
+ 'id' => $query,
+ 'text' => $query,
+ ]);
+ }
+
+ $more = count($results) > $offset + self::RESULTS_PER_PAGE;
+ $results = array_slice($results, $offset, self::RESULTS_PER_PAGE);
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a repository lookup.
+ *
+ * @return string[]
+ */
+ public static function repositoryConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_REPO];
+ }
+
+ /**
+ * Format a repository name for display in a Select2 control.
+ *
+ * @param Repository $repository
+ *
+ * @return string
+ */
+ public static function repositoryValue(Repository $repository) {
+ return $repository->getFullName();
+ }
+
+ /**
+ * Look up a repository.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function repositorySearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom, n_full" . " FROM `##other`" . " JOIN `##name` ON o_id = n_id AND o_file = n_file" . " WHERE o_type = 'REPO' AND n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND o_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $repository = Repository::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($repository !== null && $repository->canShow()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::repositoryValue($repository),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a source lookup.
+ *
+ * @return string[]
+ */
+ public static function sourceConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_SOUR];
+ }
+
+ /**
+ * Format a source name for display in a Select2 control.
+ *
+ * @param Source $source
+ *
+ * @return string
+ */
+ public static function sourceValue(Source $source) {
+ return $source->getFullName();
+ }
+
+ /**
+ * Look up a source.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function sourceSearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT s_id AS xref, s_gedcom AS gedcom, n_full" . " FROM `##sources`" . " JOIN `##name` ON s_id = n_id AND s_file = n_file" . " WHERE n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND s_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $source = Source::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($source !== null && $source->canShow()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::sourceValue($source),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+
+ /**
+ * Select2 configuration for a submitter lookup.
+ *
+ * @return string[]
+ */
+ public static function submitterConfig() {
+ return self::commonConfig() + ['data-ajax--url' => self::URL_SUBM];
+ }
+
+ /**
+ * Format a family name for display in a Select2 control.
+ *
+ * @param GedcomRecord $submitter
+ *
+ * @return string
+ */
+ public static function submitterValue(GedcomRecord $submitter) {
+ return $submitter->getFullName();
+ }
+
+ /**
+ * Look up a submitter.
+ *
+ * @param Tree $tree Search this tree.
+ * @param int $page Skip this number of pages. Starts with zero.
+ * @param string $query Search terms.
+ *
+ * @return mixed[]
+ */
+ public static function submitterSearch(Tree $tree, $page, $query) {
+ $offset = $page * self::RESULTS_PER_PAGE;
+ $more = false;
+ $results = [];
+ $cursor = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom, n_full" . " FROM `##individuals`" . " JOIN `##name` ON i_id = n_id AND i_file = n_file" . " WHERE n_full LIKE CONCAT('%', REPLACE(:query, ' ', '%'), '%') AND i_file = :tree_id" . " ORDER BY n_full COLLATE :collation")->execute([
+ 'query' => $query,
+ 'tree_id' => $tree->getTreeId(),
+ 'collation' => I18N::collation(),
+ ]);
+
+ while (is_object($row = $cursor->fetch())) {
+ $submitter = GedcomRecord::getInstance($row->xref, $tree, $row->gedcom);
+ // Filter for privacy
+ if ($submitter !== null && $submitter->canShow()) {
+ if ($offset > 0) {
+ // Skip results
+ $offset--;
+ } elseif (count($results) === self::RESULTS_PER_PAGE) {
+ // Stop when we have found a page of results
+ $more = true;
+ break;
+ } else {
+ // Add to the results
+ $results[] = [
+ 'id' => $row->xref,
+ 'text' => self::submitterValue($submitter),
+ ];
+ }
+ }
+ }
+ $cursor->closeCursor();
+
+ return [
+ 'results' => $results,
+ 'pagination' => [
+ 'more' => $more,
+ ],
+ ];
+ }
+}
diff --git a/app/Site.php b/app/Site.php
index 21b43c60c9..b1d742c7dc 100644
--- a/app/Site.php
+++ b/app/Site.php
@@ -24,58 +24,49 @@ class Site {
*
* @var array
*/
- private static $settings = null;
+ private static $preferences = [];
/**
* Get the site’s configuration settings
*
* @param string $setting_name
+ * @param string $default
*
- * @return string|null
+ * @return string
*/
- public static function getPreference($setting_name) {
+ public static function getPreference($setting_name, $default = '') {
// There are lots of settings, and we need to fetch lots of them on every page
// so it is quicker to fetch them all in one go.
- if (self::$settings === null) {
- self::$settings = Database::prepare(
+ if (empty(self::$preferences)) {
+ self::$preferences = Database::prepare(
"SELECT SQL_CACHE setting_name, setting_value FROM `##site_setting`"
)->fetchAssoc();
}
- // A setting that hasn't yet been set?
- if (!array_key_exists($setting_name, self::$settings)) {
- self::$settings[$setting_name] = null;
+ if (!array_key_exists($setting_name, self::$preferences)) {
+ self::$preferences[$setting_name] = $default;
}
- return self::$settings[$setting_name];
+ return self::$preferences[$setting_name];
}
/**
* Set the site’s configuration settings.
*
- * @param string $setting_name
- * @param string|int|bool $setting_value
+ * @param string $setting_name
+ * @param string $setting_value
*/
public static function setPreference($setting_name, $setting_value) {
- // Only need to update the database if the setting has actually changed.
- if (self::getPreference($setting_name) != $setting_value) {
- if ($setting_value === null) {
- Database::prepare(
- "DELETE FROM `##site_setting` WHERE setting_name = :setting_name"
- )->execute([
- 'setting_name' => $setting_name,
- ]);
- } else {
- Database::prepare(
- "REPLACE INTO `##site_setting` (setting_name, setting_value)" .
- " VALUES (:setting_name, LEFT(:setting_value, 2000))"
- )->execute([
- 'setting_name' => $setting_name,
- 'setting_value' => $setting_value,
- ]);
- }
+ if (self::getPreference($setting_name) !== $setting_value) {
+ Database::prepare(
+ "REPLACE INTO `##site_setting` (setting_name, setting_value)" .
+ " VALUES (:setting_name, LEFT(:setting_value, 2000))"
+ )->execute([
+ 'setting_name' => $setting_name,
+ 'setting_value' => $setting_value,
+ ]);
- self::$settings[$setting_name] = $setting_value;
+ self::$preferences[$setting_name] = $setting_value;
Log::addConfigurationLog('Site preference "' . $setting_name . '" set to "' . $setting_value . '"');
}
diff --git a/app/SpecialChars/AbstractSpecialChars.php b/app/SpecialChars/AbstractSpecialChars.php
deleted file mode 100644
index 1b08a5a1f2..0000000000
--- a/app/SpecialChars/AbstractSpecialChars.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for a language
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-abstract class AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [];
- }
-
- /**
- * A list of puncutation and other symbols
- *
- * @return string[]
- */
- public function other() {
- return [
- '¡', '¿', '„', '“', '”', '‚', '‛', '‘', '’', '«', '»', '‹', '›',
- '–', 'ª', 'º', '€', '¢', '£', '¥', '©', '°', '†', '‡', '§', '¶',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsAf.php b/app/SpecialChars/SpecialCharsAf.php
deleted file mode 100644
index a3bfa4d8d6..0000000000
--- a/app/SpecialChars/SpecialCharsAf.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Afrikaans
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsAf extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'È', 'É', 'Ê', 'Ë', 'Î', 'Ï', 'Ô', 'Û',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'è', 'é', 'ê', 'ë', 'î', 'ï', 'ô', 'û', 'ʼn',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsAr.php b/app/SpecialChars/SpecialCharsAr.php
deleted file mode 100644
index d1b1694bc8..0000000000
--- a/app/SpecialChars/SpecialCharsAr.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Arabic
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsAr extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط',
- 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsCs.php b/app/SpecialChars/SpecialCharsCs.php
deleted file mode 100644
index ddc48ae778..0000000000
--- a/app/SpecialChars/SpecialCharsCs.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Czech
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsCs extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'Ą', 'Ä', 'É', 'Ę', 'Ě', 'Í', 'Ó', 'Ô', 'Ú', 'Ů', 'Ý', 'Č', 'Ĺ', 'Ň', 'Ŕ', 'Ř', 'Š', 'Ž',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'ą', 'ä', 'é', 'ę', 'ě', 'í', 'ó', 'ô', 'ú', 'ů', 'ý', 'č', 'ď', 'ť', 'ĺ', 'ň', 'ŕ', 'ř', 'š', 'ž',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsDa.php b/app/SpecialChars/SpecialCharsDa.php
deleted file mode 100644
index 9226b36a24..0000000000
--- a/app/SpecialChars/SpecialCharsDa.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Danish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsDa extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Å', 'Æ', 'É', 'Ø', 'Á', 'Í', 'Ó', 'Ú', 'Ý',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'å', 'æ', 'é', 'ø', 'á', 'í', 'ó', 'ú', 'ý',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsDe.php b/app/SpecialChars/SpecialCharsDe.php
deleted file mode 100644
index 171ddbb4ac..0000000000
--- a/app/SpecialChars/SpecialCharsDe.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for German
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsDe extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ä', 'Ö', 'Ü', 'À', 'É',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ä', 'ö', 'ü', 'à', 'é', 'ß',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsEl.php b/app/SpecialChars/SpecialCharsEl.php
deleted file mode 100644
index 090774e66e..0000000000
--- a/app/SpecialChars/SpecialCharsEl.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Greek
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsEl extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ά', 'Α', 'Β', 'Γ', 'Δ', 'Έ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ί', 'Ϊ', 'Ι', 'Κ', 'Λ', 'Μ',
- 'Ν', 'Ξ', 'Ό', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Ύ', 'Ϋ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ώ', 'Ω',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ά', 'α', 'β', 'γ', 'δ', 'έ', 'ε', 'ζ', 'η', 'θ', 'ί', 'ϊ', 'ΐ', 'ι', 'κ', 'λ', 'μ', 'ν',
- 'ξ', 'ό', 'ο', 'π', 'ρ', 'σ', 'ς', 'τ', 'ύ', 'ϋ', 'ΰ', 'υ', 'φ', 'χ', 'ψ', 'ώ', 'ω',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsEn.php b/app/SpecialChars/SpecialCharsEn.php
deleted file mode 100644
index 8a268ddfe0..0000000000
--- a/app/SpecialChars/SpecialCharsEn.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for English
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsEn extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'Ð', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
- 'IJ', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Œ', 'Ø', 'Þ', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Ÿ',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'ð', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï',
- 'ij', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'œ', 'ø', 'þ', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'ß',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsEs.php b/app/SpecialChars/SpecialCharsEs.php
deleted file mode 100644
index 0a300439cd..0000000000
--- a/app/SpecialChars/SpecialCharsEs.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Spanish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsEs extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'É', 'Í', 'Ñ', 'Ó', 'Ú', 'Ü', 'Ç',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'é', 'í', 'ñ', 'ó', 'ú', 'ü', 'ç',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsEu.php b/app/SpecialChars/SpecialCharsEu.php
deleted file mode 100644
index 603655e730..0000000000
--- a/app/SpecialChars/SpecialCharsEu.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Basque
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsEu extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ç',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ç',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsFi.php b/app/SpecialChars/SpecialCharsFi.php
deleted file mode 100644
index bcb77a81dc..0000000000
--- a/app/SpecialChars/SpecialCharsFi.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Finnish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsFi extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ä', 'Ö', 'Å', 'Š', 'Ž',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ä', 'ö', 'å', 'š', 'ž',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsFr.php b/app/SpecialChars/SpecialCharsFr.php
deleted file mode 100644
index c5c620556f..0000000000
--- a/app/SpecialChars/SpecialCharsFr.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for French
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsFr extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'À', 'Â', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Î', 'Ï', 'Ô', 'Œ', 'Ù', 'Û', 'Ü', 'Ÿ',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'à', 'â', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'î', 'ï', 'ô', 'œ', 'ù', 'û', 'ü', 'ÿ',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsGd.php b/app/SpecialChars/SpecialCharsGd.php
deleted file mode 100644
index b20966362c..0000000000
--- a/app/SpecialChars/SpecialCharsGd.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Scottish Gaelic
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsGd extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'É', 'Í', 'Ó', 'Ú',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'é', 'í', 'ó', 'ú',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsHaw.php b/app/SpecialChars/SpecialCharsHaw.php
deleted file mode 100644
index 8fc5d6fd4d..0000000000
--- a/app/SpecialChars/SpecialCharsHaw.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Hawaiian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsHaw extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ā', 'Ē', 'Ī', 'Ō', 'Ū', '‘',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ā', 'ē', 'ī', 'ō', 'ū', '‘',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsHe.php b/app/SpecialChars/SpecialCharsHe.php
deleted file mode 100644
index 6cb4917b6e..0000000000
--- a/app/SpecialChars/SpecialCharsHe.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Hebrew
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsHe extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ך', 'ל', 'מ',
- 'ם', 'נ', 'ן', 'ס', 'ע', 'פ', 'ף', 'צ', 'ץ', 'ק', 'ר', 'ש', 'ת',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsHu.php b/app/SpecialChars/SpecialCharsHu.php
deleted file mode 100644
index 9084a94966..0000000000
--- a/app/SpecialChars/SpecialCharsHu.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Hungarian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsHu extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'É', 'Í', 'Ó', 'Ö', 'Ő', 'Ú', 'Ü', 'Ű',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'é', 'í', 'ó', 'ö', 'ő', 'ú', 'ü', 'ű',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsInterface.php b/app/SpecialChars/SpecialCharsInterface.php
deleted file mode 100644
index 238532f0a5..0000000000
--- a/app/SpecialChars/SpecialCharsInterface.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for a language
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-interface SpecialCharsInterface {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper();
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower();
-
- /**
- * A list of puncutation and other symbols
- *
- * @return string[]
- */
- public function other();
-}
diff --git a/app/SpecialChars/SpecialCharsIs.php b/app/SpecialChars/SpecialCharsIs.php
deleted file mode 100644
index b59d9f886d..0000000000
--- a/app/SpecialChars/SpecialCharsIs.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Icelandic
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsIs extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'Æ', 'Ð', 'É', 'Í', 'Ó', 'Ö', 'Þ', 'Ú', 'Ý',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'æ', 'ð', 'é', 'í', 'ó', 'ö', 'þ', 'ú', 'ý',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsIt.php b/app/SpecialChars/SpecialCharsIt.php
deleted file mode 100644
index 703a46827f..0000000000
--- a/app/SpecialChars/SpecialCharsIt.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Italian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsIt extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'À', 'È', 'É', 'Ì', 'Í', 'Ò', 'Ó', 'Ù', 'Ú', 'Ï',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'à', 'è', 'é', 'ì', 'í', 'ò', 'ó', 'ù', 'ú', 'ï',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsLt.php b/app/SpecialChars/SpecialCharsLt.php
deleted file mode 100644
index d2126618b3..0000000000
--- a/app/SpecialChars/SpecialCharsLt.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Lithuanian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsLt extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ą', 'Č', 'Ę', 'Ė', 'Į', 'Š', 'Ų', 'Ū', 'Ž',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ą', 'č', 'ę', 'ė', 'į', 'š', 'ų', 'ū', 'ž',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsNl.php b/app/SpecialChars/SpecialCharsNl.php
deleted file mode 100644
index cc09fe6f4c..0000000000
--- a/app/SpecialChars/SpecialCharsNl.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Dutch
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsNl extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'Â', 'È', 'É', 'Ê', 'Ë', 'Í', 'Ï', 'IJ', 'Ó', 'Ô', 'Ö', 'Ú', 'Ù', 'Ä', 'Û', 'Ü',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'â', 'è', 'é', 'ê', 'ë', 'í', 'ï', 'ij', 'ó', 'ô', 'ö', 'ú', 'ù', 'ä', 'û', 'ü',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsNn.php b/app/SpecialChars/SpecialCharsNn.php
deleted file mode 100644
index 30432f1e8e..0000000000
--- a/app/SpecialChars/SpecialCharsNn.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Norwegian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsNn extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Æ', 'Ø', 'Å', 'À', 'É', 'Ê', 'Ó', 'Ò', 'Ô',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'æ', 'ø', 'å', 'à', 'é', 'ê', 'ó', 'ò', 'ô',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsPl.php b/app/SpecialChars/SpecialCharsPl.php
deleted file mode 100644
index eba65bd421..0000000000
--- a/app/SpecialChars/SpecialCharsPl.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Polish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsPl extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ą', 'Ć', 'Ę', 'Ł', 'Ń', 'Ó', 'Ś', 'Ź', 'Ż',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ą', 'ć', 'ę', 'ł', 'ń', 'ó', 'ś', 'ź', 'ż',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsPt.php b/app/SpecialChars/SpecialCharsPt.php
deleted file mode 100644
index 582dfbfb20..0000000000
--- a/app/SpecialChars/SpecialCharsPt.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Portuguese
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsPt extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'À', 'Á', 'Â', 'Ã', 'Ç', 'É', 'Ê', 'Í', 'Ó', 'Ô', 'Õ', 'Ú', 'Ü', 'È', 'Ò',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'à', 'á', 'â', 'ã', 'ç', 'é', 'ê', 'í', 'ó', 'ô', 'õ', 'ú', 'ü', 'è', 'ò',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsRu.php b/app/SpecialChars/SpecialCharsRu.php
deleted file mode 100644
index b3c737f76b..0000000000
--- a/app/SpecialChars/SpecialCharsRu.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Russian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsRu extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П',
- 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п',
- 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsSk.php b/app/SpecialChars/SpecialCharsSk.php
deleted file mode 100644
index 91727dbc63..0000000000
--- a/app/SpecialChars/SpecialCharsSk.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Slovakian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsSk extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Á', 'Ä', 'Č', 'Ď', 'É', 'Ě', 'Í', 'Ĺ', 'Ľ', 'Ň', 'Ó', 'Ô', 'Ŕ', 'Ř', 'Š', 'Ť', 'Ú', 'Ů', 'Ý', 'Ž',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'á', 'ä', 'č', 'ď', 'é', 'ě', 'í', 'ĺ', 'ľ', 'ň', 'ó', 'ô', 'ŕ', 'ř', 'š', 'ť', 'ú', 'ů', 'ý', 'ž',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsSl.php b/app/SpecialChars/SpecialCharsSl.php
deleted file mode 100644
index 5f008b1755..0000000000
--- a/app/SpecialChars/SpecialCharsSl.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Slovenian
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsSl extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Č', 'Š', 'Ž', 'Ć', 'Ð', 'Ä', 'Ö', 'Ü',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'č', 'š', 'ž', 'ć', 'đ', 'ä', 'ö', 'ü',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsSv.php b/app/SpecialChars/SpecialCharsSv.php
deleted file mode 100644
index 155c24470d..0000000000
--- a/app/SpecialChars/SpecialCharsSv.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Swedish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsSv extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Ä', 'Å', 'É', 'Ö', 'Á', 'Ë', 'Ü',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'ä', 'å', 'é', 'ö', 'á', 'ë', 'ü',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsTr.php b/app/SpecialChars/SpecialCharsTr.php
deleted file mode 100644
index 74145a181e..0000000000
--- a/app/SpecialChars/SpecialCharsTr.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Turkish
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsTr extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'Â', 'Ç', 'Ğ', 'Î', 'İ', 'Ö', 'Ş', 'Û', 'Ü',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'â', 'ç', 'ğ', 'î', 'ı', 'ö', 'ş', 'û', 'ü',
- ];
- }
-}
diff --git a/app/SpecialChars/SpecialCharsVi.php b/app/SpecialChars/SpecialCharsVi.php
deleted file mode 100644
index 6dc902f8df..0000000000
--- a/app/SpecialChars/SpecialCharsVi.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * webtrees: online genealogy
- * Copyright (C) 2017 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Fisharebest\Webtrees\SpecialChars;
-
-/**
- * Exemplar characters for Vietnamese
- *
- * For each language, list the symbols, puncutation and letters with diacritics
- * that may be difficult to type.
- */
-class SpecialCharsVi extends AbstractSpecialChars {
- /**
- * A list of magiscule letters.
- *
- * @return string[]
- */
- public function upper() {
- return [
- 'À', 'Á', 'Â', 'Ã', 'Ạ', 'Ả', 'Ă', 'Ấ', 'Ầ', 'Ẫ', 'Ậ', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ',
- 'Đ', 'È', 'É', 'Ê', 'Ẹ', 'Ẻ', 'Ẽ', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ì', 'Í', 'Ĩ', 'Ỉ', 'Ị',
- 'Ò', 'Ó', 'Ô', 'Õ', 'Ơ', 'Ọ', 'Ỏ', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ',
- 'Ù', 'Ú', 'Ũ', 'Ư', 'Ụ', 'Ủ', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Ý', 'Ỳ', 'Ỵ', 'Ỷ', 'Ỹ',
- ];
- }
-
- /**
- * A list of miniscule letters.
- *
- * @return string[]
- */
- public function lower() {
- return [
- 'à', 'á', 'â', 'ã', 'ạ', 'ả', 'ă', 'ấ', 'ầ', 'ẫ', 'ậ', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ',
- 'đ', 'è', 'é', 'ê', 'ẹ', 'ẻ', 'ẽ', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ì', 'í', 'ĩ', 'ỉ', 'ị',
- 'ò', 'ó', 'ô', 'õ', 'ơ', 'ọ', 'ỏ', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ',
- 'ù', 'ú', 'ũ', 'ư', 'ụ', 'ủ', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'ý', 'ỳ', 'ỵ', 'ỷ', 'ỹ',
- ];
- }
-}
diff --git a/app/Stats.php b/app/Stats.php
index 03d85f20a0..372b6c3a0a 100644
--- a/app/Stats.php
+++ b/app/Stats.php
@@ -25,7 +25,6 @@ use Fisharebest\Webtrees\Module\UserFavoritesModule;
use Fisharebest\Webtrees\Query\QueryName;
use PDO;
use PDOException;
-use Rhumsaa\Uuid\Uuid;
/**
* A selection of pre-formatted statistical queries.
@@ -5539,7 +5538,7 @@ class Stats {
}
switch ($type) {
case 'table':
- $common[] = '<tr><td>' . $given . '</td><td>' . I18N::number($total) . '</td><td>' . $total . '</td></tr>';
+ $common[] = '<tr><td>' . $given . '</td><td data-sort="' . $total . '">' . I18N::number($total) . '</td></tr>';
break;
case 'list':
$common[] = '<li><span dir="auto">' . $given . '</span>' . $tot . '</li>';
@@ -5552,31 +5551,9 @@ class Stats {
if ($common) {
switch ($type) {
case 'table':
- global $controller;
- $table_id = Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page
- $controller
- ->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)
- ->addInlineJavascript('
- jQuery("#' . $table_id . '").dataTable({
- dom: \'t\',
- autoWidth: false,
- paging: false,
- lengthChange: false,
- filter: false,
- info: false,
- jQueryUI: true,
- sorting: [[1,"desc"]],
- columns: [
- /* 0-name */ {},
- /* 1-count */ { class: "center", dataSort: 2},
- /* 2-COUNT */ { visible: false}
- ]
- });
- jQuery("#' . $table_id . '").css("visibility", "visible");
- ');
$lookup = ['M' => I18N::translate('Male'), 'F' => I18N::translate('Female'), 'U' => I18N::translateContext('unknown gender', 'Unknown'), 'B' => I18N::translate('All')];
- return '<table id="' . $table_id . '" class="givn-list"><thead><tr><th class="ui-state-default" colspan="3">' . $lookup[$sex] . '</th></tr><tr><th>' . I18N::translate('Name') . '</th><th>' . I18N::translate('Count') . '</th><th>COUNT</th></tr></thead><tbody>' . implode('', $common) . '</tbody></table>';
+ return '<table ' . Datatables::givenNameTableAttributes() . '><thead><tr><th class="ui-state-default" colspan="3">' . $lookup[$sex] . '</th></tr><tr><th>' . I18N::translate('Name') . '</th><th>' . I18N::translate('Individuals') . '</th></tr></thead><tbody>' . implode('', $common) . '</tbody></table>';
case 'list':
return '<ul>' . implode('', $common) . '</ul>';
case 'nolist':
@@ -5927,10 +5904,9 @@ class Stats {
}
if (Auth::id() != $user->getUserId() && $user->getPreference('contactmethod') != 'none') {
if ($type == 'list') {
- $content .= '<br><a class="icon-email" href="#" onclick="return message(\'' . $user->getUserId() . '\', \'\', \'' . Filter::escapeJs(Functions::getQueryUrl()) . '\');" title="' . I18N::translate('Send a message') . '"></a>';
- } else {
- $content .= ' <a class="icon-email" href="#" onclick="return message(\'' . $user->getUserId() . '\', \'\', \'' . Filter::escapeJs(Functions::getQueryUrl()) . '\');" title="' . I18N::translate('Send a message') . '"></a>';
+ $content .= '<br>';
}
+ $content .= FontAwesome::linkIcon('email', I18N::translate('Send a message'), ['class' => 'btn btn-link', 'href' => 'message.php?to=' . Filter::escapeUrl($user->getUserName())]);
}
if ($type == 'list') {
$content .= '</li>';
diff --git a/app/Theme/AbstractTheme.php b/app/Theme/AbstractTheme.php
index dd02ebe229..4a53377c98 100644
--- a/app/Theme/AbstractTheme.php
+++ b/app/Theme/AbstractTheme.php
@@ -53,7 +53,62 @@ use Fisharebest\Webtrees\User;
* Common functions for all themes.
*/
abstract class AbstractTheme {
- /** @var Tree The current tree */
+ /**
+ * Where are our CSS, JS and other assets?
+ */
+ const THEME_DIR = '_common';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
+
+ // Icons are created using <i class="..."></i>
+ const ICONS = [
+ // Icons for GEDCOM records
+ 'family' => 'fa fa-users',
+ 'individual' => 'fa fa-user',
+ 'media' => 'fa fa-file-image-o',
+ 'note' => 'fa fa-sticky-note-o',
+ 'repository' => 'fa fa-institution',
+ 'source' => 'fa fa-file-text-o',
+ 'submission' => 'fa fa-upload',
+ 'submitter' => 'fa fa-user-plus',
+
+ // Icons for sexes
+ 'F' => 'fa fa-venus',
+ 'M' => 'fa fa-mars',
+ 'U' => 'fa fa-genderless',
+
+ // Icons for editing
+ 'add' => 'fa fa-plus',
+ 'config' => 'fa fa-cogs',
+ 'copy' => 'fa fa-copy',
+ 'create' => 'fa fa-plus',
+ 'delete' => 'fa fa-trash',
+ 'edit' => 'fa fa-pencil',
+ 'link' => 'fa fa-link',
+ 'unlink' => 'fa fa-unlink',
+
+ // Icons for arrows
+ 'arrow-down' => 'fa fa-arrow-down',
+ 'arrow-left' => 'fa fa-arrow-left',
+ 'arrow-right' => 'fa fa-arrow-right',
+ 'arrow-up' => 'fa fa-arrow-up',
+
+ // Status icons
+ 'error' => 'fa fa-exclamation-triangle',
+ 'info' => 'fa fa-info-circle',
+ 'warning' => 'fa fa-exclamation-circle',
+
+ // Icons for file types
+ 'mime-application-pdf' => '',
+ 'mime-text-html' => '',
+
+ // Other icons
+ 'mail' => 'fa fa-envelope-o',
+ 'help' => 'fa fa-info-circle',
+ 'search' => 'fa fa-search',
+ ];
+
+ /** @var Tree */
protected $tree;
/** @var string An escaped version of the "ged=XXX" URL parameter */
@@ -79,7 +134,7 @@ abstract class AbstractTheme {
*/
protected function accessibilityLinks() {
return
- '<div class="accessibility-links">' .
+ '<div class="wt-accessibility-links">' .
'<a class="sr-only sr-only-focusable btn btn-info btn-sm" href="#content">' .
/* I18N: Skip over the headers and menus, to the main content of the page */ I18N::translate('Skip to content') .
'</a>' .
@@ -227,30 +282,33 @@ abstract class AbstractTheme {
}
/**
- * Create the top of the <body>.
+ * Where are our CSS, JS and other assets?
*
- * @return string
+ * @deprecated - use the constant directly
+ *
+ * @return string A relative path, such as "themes/foo/"
*/
- public function bodyHeader() {
- return
- '<body class="container">' .
- '<header>' .
- $this->headerContent() .
- $this->primaryMenuContainer($this->primaryMenu()) .
- '</header>' .
- '<main id="content">' .
- $this->flashMessagesContainer(FlashMessages::getMessages());
+ public function assetUrl() {
+ return self::ASSET_DIR;
}
/**
- * Create the top of the <body> (for popup windows).
+ * Create the top of the <body>.
*
* @return string
*/
- public function bodyHeaderPopupWindow() {
+ public function bodyHeader() {
return
- '<body class="container container-popup">' .
- '<main id="content">' .
+ '<body class="wt-global">' .
+ '<header class="wt-header-wrapper">' .
+ '<div class="container wt-header-container">' .
+ '<div class="row wt-header-content">' .
+ $this->headerContent() .
+ '</div>' .
+ '</div>' .
+ '</header>' .
+ '<main id="content" class="wt-main-wrapper">' .
+ '<div class="container wt-main-container">' .
$this->flashMessagesContainer(FlashMessages::getMessages());
}
@@ -270,7 +328,7 @@ abstract class AbstractTheme {
case 'mailto':
return '<a href="mailto:' . Filter::escapeHtml($user->getEmail()) . '">' . $user->getRealNameHtml() . '</a>';
default:
- return "<a href='#' onclick='message(\"" . Filter::escapeHtml($user->getUserName()) . '", "' . $method . '", "' . WT_BASE_URL . Filter::escapeHtml(Functions::getQueryUrl()) . "\", \"\");return false;'>" . $user->getRealNameHtml() . '</a>';
+ return '<a href="message.php?to=' . Filter::escapeUrl($user->getUserName()) . '&amp;ged=' . $this->tree->getNameUrl() . '&amp;url=' . Filter::escapeHtml(Functions::getQueryUrl()) . '">' . $user->getRealNameHtml() . '</a>';
}
}
@@ -338,10 +396,10 @@ abstract class AbstractTheme {
if (
empty($_SERVER['HTTP_DNT']) &&
empty($_COOKIE['cookie']) &&
- (Site::getPreference('GOOGLE_ANALYTICS_ID') || Site::getPreference('PIWIK_SITE_ID') || Site::getPreference('STATCOUNTER_PROJECT_ID'))
+ (Site::getPreference('GOOGLE_ANALYTICS_ID') === '1' || Site::getPreference('PIWIK_SITE_ID') === '1' || Site::getPreference('STATCOUNTER_PROJECT_ID') === '1')
) {
return
- '<div class="cookie-warning">' .
+ '<div class="wt-cookie-warning">' .
I18N::translate('Cookies') . ' - ' .
I18N::translate('This website uses cookies to learn about visitor behaviour.') . ' ' .
'<button onclick="document.cookie=\'cookie=1\'; this.parentNode.classList.add(\'hidden\');">' . I18N::translate('continue') . '</button>' .
@@ -367,9 +425,9 @@ abstract class AbstractTheme {
*/
protected function favicon() {
return
- '<link rel="icon" href="' . $this->assetUrl() . 'favicon.png" type="image/png">' .
- '<link rel="icon" type="image/png" href="' . $this->assetUrl() . 'favicon192.png" sizes="192x192">' .
- '<link rel="apple-touch-icon" sizes="180x180" href="' . $this->assetUrl() . 'favicon180.png">';
+ '<link rel="icon" href="' . self::ASSET_DIR . 'favicon.png" type="image/png">' .
+ '<link rel="icon" type="image/png" href="' . self::ASSET_DIR . 'favicon192.png" sizes="192x192">' .
+ '<link rel="apple-touch-icon" sizes="180x180" href="' . self::ASSET_DIR . 'favicon180.png">';
}
/**
@@ -411,17 +469,12 @@ abstract class AbstractTheme {
* @return string
*/
public function footerContainer() {
- return '</main><footer>' . $this->footerContent() . '</footer>';
- }
-
- /**
- * Close the main content.
- * Note that popup windows are deprecated
- *
- * @return string
- */
- public function footerContainerPopupWindow() {
- return '</main>';
+ return
+ '</div>' .
+ '</main>' .
+ '<footer class="wt-footer-container">' .
+ '<div class="wt-footer-content container">' . $this->footerContent() . '</div>' .
+ '</footer>';
}
/**
@@ -448,10 +501,13 @@ abstract class AbstractTheme {
* @return string
*/
public function formatBlock($id, $title, $class, $content) {
+ // Prefer underscores in CSS classes
+ $class = str_replace('_', '-', $class);
+
return
- '<div id="' . $id . '" class="block" >' .
- '<div class="blockheader">' . $title . '</div>' .
- '<div class="blockcontent ' . $class . '">' . $content . '</div>' .
+ '<div class="card mb-4 wt-block wt-block-' . $class . '" id="' . $id . '">' .
+ '<div class="card-header wt-block-header wt-block-header-' . $class . '">' . $title . '</div>' .
+ '<div class="card-block wt-block-content wt-block-content-' . $class . '">' . $content . '</div>' .
'</div>';
}
@@ -462,7 +518,7 @@ abstract class AbstractTheme {
*/
protected function formatContactLinks() {
if ($this->tree) {
- return '<div class="contact-links">' . $this->contactLinks() . '</div>';
+ return '<div class="wt-contact-links">' . $this->contactLinks() . '</div>';
} else {
return '';
}
@@ -478,7 +534,7 @@ abstract class AbstractTheme {
protected function formatPageViews($count) {
if ($count > 0) {
return
- '<div class="page-views">' .
+ '<div class="wt-page-views">' .
I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $count,
'<span class="odometer">' . I18N::digits($count) . '</span>') .
'</div>';
@@ -508,11 +564,13 @@ abstract class AbstractTheme {
protected function formQuickSearch() {
if ($this->tree) {
return
- '<form action="search.php" class="header-search" role="search">' .
+ '<div class="col wt-header-search">' .
+ '<form class="wt-header-search-form" role="search" action="search.php">' .
'<input type="hidden" name="action" value="header">' .
'<input type="hidden" name="ged" value="' . $this->tree->getNameHtml() . '">' .
$this->formQuickSearchFields() .
- '</form>';
+ '</form>' .
+ '</div>';
} else {
return '';
}
@@ -525,8 +583,13 @@ abstract class AbstractTheme {
*/
protected function formQuickSearchFields() {
return
- '<input type="search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
- '<input type="image" src="' . $this->assetUrl() . 'images/go.png" alt="' . I18N::translate('Search') . '">';
+ '<div class="input-group">' .
+ '<label class="sr-only" for="quick-search">' . I18N::translate('Search') . '</label>' .
+ '<input type="search" class="form-control form-control-sm wt-header-search-field" id="quick-search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
+ '<span class="input-group-btn">' .
+ '<button type="submit" class="btn btn-primary wt-header-search-button"><i class="fa fa-search"></i></button>' .
+ '</span>' .
+ '</div>';
}
/**
@@ -536,7 +599,7 @@ abstract class AbstractTheme {
*/
protected function formatTreeTitle() {
if ($this->tree) {
- return '<h1 class="header-title">' . $this->tree->getTitleHtml() . '</h1>';
+ return '<h1 class="col wt-site-title">' . $this->tree->getTitleHtml() . '</h1>';
} else {
return '';
}
@@ -549,8 +612,8 @@ abstract class AbstractTheme {
*/
protected function formatSecondaryMenu() {
return
- '<ul class="secondary-menu">' .
- implode('', $this->secondaryMenu()) .
+ '<ul class="nav wt-secondary-menu">' .
+ implode('', array_map(function (Menu $menu) { return $this->formatSecondaryMenuItem($menu); }, $this->secondaryMenu())) .
'</ul>';
}
@@ -562,7 +625,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function formatSecondaryMenuItem(Menu $menu) {
- return $menu->getMenuAsList();
+ return $menu->bootstrap4();
}
/**
@@ -601,16 +664,12 @@ abstract class AbstractTheme {
}
$html =
- // modernizr.js and respond.js need to be loaded before the <body> to avoid FOUC
- '<!--[if IE 8]><script src="' . WT_MODERNIZR_JS_URL . '"></script><![endif]-->' .
- '<!--[if IE 8]><script src="' . WT_RESPOND_JS_URL . '"></script><![endif]-->' .
$this->metaCharset() .
$this->metaCsrf() .
$this->title($title) .
$this->favicon() .
$this->metaViewport() .
$this->metaRobots($controller->getMetaRobots()) .
- $this->metaUaCompatible() .
$this->metaGenerator(WT_WEBTREES . ' ' . WT_VERSION . ' - ' . WT_WEBTREES_URL);
if ($this->tree) {
@@ -632,22 +691,12 @@ abstract class AbstractTheme {
*/
protected function headerContent() {
return
- //$this->accessibilityLinks() .
+ $this->accessibilityLinks() .
$this->logoHeader() .
- $this->secondaryMenuContainer($this->secondaryMenu()) .
$this->formatTreeTitle() .
- $this->formQuickSearch();
- }
-
- /**
- * Create the <header> tag for a popup window.
- *
- * @return string
- */
- protected function headerSimple() {
- return
- $this->flashMessagesContainer(FlashMessages::getMessages()) .
- '<div id="content">';
+ $this->formQuickSearch() .
+ $this->secondaryMenuContainer($this->secondaryMenu()) .
+ $this->primaryMenuContainer($this->primaryMenu());
}
/**
@@ -720,9 +769,9 @@ abstract class AbstractTheme {
*/
public function icon(Fact $fact) {
$icon = 'images/facts/' . $fact->getTag() . '.png';
- $dir = substr($this->assetUrl(), strlen(WT_STATIC_URL));
+ $dir = substr(self::ASSET_DIR, strlen(WT_STATIC_URL));
if (file_exists($dir . $icon)) {
- return '<img src="' . $this->assetUrl() . $icon . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">';
+ return '<img src="' . self::ASSET_DIR . $icon . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">';
} elseif (file_exists($dir . 'images/facts/NULL.png')) {
// Spacer image - for alignment - until we move to a sprite.
return '<img src="' . Theme::theme()->assetUrl() . 'images/facts/NULL.png">';
@@ -732,6 +781,37 @@ abstract class AbstractTheme {
}
/**
+ * Decorative icons are used in addition to text.
+ * They need additional markup to hide them from assistive technologies.
+ *
+ * Semantic icons are used in place of text.
+ * They need additional markup to convey their meaning to assistive technologies.
+ *
+ * @link http://fontawesome.io/accessibility
+ *
+ * @param string $icon
+ * @param string $text
+ *
+ * @return string
+ */
+ public function replacementIconFunction($icon, $text = '') {
+ if (array_key_exists($icon, self::ICONS)) {
+ if ($text === '') {
+ // Decorative icon. Hiden from assistive technology.
+ return '<i class="' . self::ICONS[$icon] . '" aria-hidden="true"></i>';
+ } else {
+ // Semantic icon. Label for assistive technology.
+ return
+ '<i class="' . self::ICONS[$icon] . '" title="' . $text . '"></i>' .
+ '<span class="sr-only">' . $text . '</span>';
+ }
+ } else {
+ return $text;
+ }
+ }
+
+
+ /**
* Display an individual in a box - for charts, etc.
*
* @param Individual $individual
@@ -753,10 +833,10 @@ abstract class AbstractTheme {
'<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
'<div class="namedef name1">' . $individual->getAddName() . '</div>';
$icons =
- '<div class="noprint icons">' .
+ '<div class="icons">' .
'<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
'<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
- '<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
+ '<ul class="' . $personBoxClass . '">' . implode('', array_map(function(Menu $menu) { return $menu->bootstrap4(); }, $this->individualBoxMenu($individual))) . '</ul>' .
'</div>' .
'</div>' .
'</div>';
@@ -805,10 +885,10 @@ abstract class AbstractTheme {
'<a href="' . $individual->getHtmlUrl() . '">' . $content . '</a>' .
'<div class="namedef name2">' . $individual->getAddName() . '</div>';
$icons =
- '<div class="noprint icons">' .
+ '<div class="icons">' .
'<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' .
'<div class="itr"><i class="icon-pedigree"></i><div class="popup">' .
- '<ul class="' . $personBoxClass . '">' . implode('', $this->individualBoxMenu($individual)) . '</ul>' .
+ '<ul class="' . $personBoxClass . '">' . implode('', array_map(function(Menu $menu) { return $menu->bootstrap4(); }, $this->individualBoxMenu($individual))) . '</ul>' .
'</div>' .
'</div>' .
'</div>';
@@ -1041,7 +1121,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function logoHeader() {
- return '<div class="header-logo"></div>';
+ return '<div class="col wt-site-logo"></div>';
}
/**
@@ -1050,7 +1130,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function logoPoweredBy() {
- return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '"></a>';
+ return '<a href="' . WT_WEBTREES_URL . '" class="wt-powered-by-webtrees" title="' . WT_WEBTREES_URL . '" dir="ltr">' . WT_WEBTREES_URL . '</a>';
}
/**
@@ -1100,14 +1180,14 @@ abstract class AbstractTheme {
}
}
- if ($submenus) {
+ if (empty($submenus)) {
+ return null;
+ } else {
usort($submenus, function (Menu $x, Menu $y) {
return I18N::strcasecmp($x->getLabel(), $y->getLabel());
});
return new Menu(I18N::translate('Charts'), '#', 'menu-chart', ['rel' => 'nofollow'], $submenus);
- } else {
- return null;
}
}
@@ -1383,7 +1463,7 @@ abstract class AbstractTheme {
* @return Menu
*/
protected function menuHomePage() {
- if (count(Tree::getAll()) === 1 || Site::getPreference('ALLOW_CHANGE_GEDCOM') === '0') {
+ if (count(Tree::getAll()) === 1 || Site::getPreference('ALLOW_CHANGE_GEDCOM') !== '1') {
return new Menu(I18N::translate('Family tree'), 'index.php?ctype=gedcom&amp;' . $this->tree_url, 'menu-tree');
} else {
$submenus = [];
@@ -1656,12 +1736,11 @@ abstract class AbstractTheme {
$gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid');
if ($gedcomid && Module::isActiveChart($this->tree, 'pedigree_chart')) {
- $showFull = $this->tree->getPreference('PEDIGREE_FULL_DETAILS') ? 1 : 0;
$showLayout = $this->tree->getPreference('PEDIGREE_LAYOUT') ? 1 : 0;
return new Menu(
I18N::translate('My pedigree'),
- 'pedigree.php?' . $this->tree_url . '&amp;rootid=' . $gedcomid . '&amp;show_full=' . $showFull . '&amp;talloffset=' . $showLayout,
+ 'pedigree.php?' . $this->tree_url . '&amp;rootid=' . $gedcomid . '&amp;talloffset=' . $showLayout,
'menu-mypedigree'
);
} else {
@@ -1676,7 +1755,7 @@ abstract class AbstractTheme {
*/
protected function menuPendingChanges() {
if ($this->pendingChangesExist()) {
- $menu = new Menu(I18N::translate('Pending changes'), '#', 'menu-pending', ['onclick' => 'window.open("edit_changes.php", "_blank", chan_window_specs); return false;']);
+ $menu = new Menu(I18N::translate('Pending changes'), 'edit_changes.php', 'menu-pending');
return $menu;
} else {
@@ -1695,10 +1774,10 @@ abstract class AbstractTheme {
$submenus[] = $report->getReportMenu();
}
- if ($submenus) {
- return new Menu(I18N::translate('Reports'), '#', 'menu-report', ['rel' => 'nofollow'], $submenus);
- } else {
+ if (empty($submenus)) {
return null;
+ } else {
+ return new Menu(I18N::translate('Reports'), '#', 'menu-report', ['rel' => 'nofollow'], $submenus);
}
}
@@ -1762,7 +1841,7 @@ abstract class AbstractTheme {
* @return Menu|null
*/
public function menuThemes() {
- if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
+ if ($this->tree !== null && Site::getPreference('ALLOW_USER_THEMES') === '1' && $this->tree->getPreference('ALLOW_THEME_DROPDOWN') === '1') {
$submenus = [];
foreach (Theme::installedThemes() as $theme) {
$class = 'menu-theme-' . $theme->themeId() . ($theme === $this ? ' active' : '');
@@ -1848,15 +1927,6 @@ abstract class AbstractTheme {
}
/**
- * Create the <meta http-equiv="X-UA-Compatible"> tag.
- *
- * @return string
- */
- protected function metaUaCompatible() {
- return '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
- }
-
- /**
* Create the <meta name="viewport" content="width=device-width, initial-scale=1"> tag.
*
* @return string
@@ -1904,7 +1974,6 @@ abstract class AbstractTheme {
'chart-background-u' => 'eeeeee',
'chart-box-x' => 250,
'chart-box-y' => 80,
- 'chart-descendancy-indent' => 15,
'chart-font-color' => '000000',
'chart-font-name' => WT_ROOT . 'packages/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf',
'chart-font-size' => 7,
@@ -1925,13 +1994,13 @@ abstract class AbstractTheme {
'stats-small-chart-x' => 440,
'stats-small-chart-y' => 125,
'stats-large-chart-x' => 900,
- 'image-dline' => $this->assetUrl() . 'images/dline.png',
- 'image-dline2' => $this->assetUrl() . 'images/dline2.png',
- 'image-hline' => $this->assetUrl() . 'images/hline.png',
- 'image-spacer' => $this->assetUrl() . 'images/spacer.png',
- 'image-vline' => $this->assetUrl() . 'images/vline.png',
- 'image-minus' => $this->assetUrl() . 'images/minus.png',
- 'image-plus' => $this->assetUrl() . 'images/plus.png',
+ 'image-dline' => static::ASSET_DIR . 'images/dline.png',
+ 'image-dline2' => static::ASSET_DIR . 'images/dline2.png',
+ 'image-hline' => static::ASSET_DIR . 'images/hline.png',
+ 'image-spacer' => static::ASSET_DIR . 'images/spacer.png',
+ 'image-vline' => static::ASSET_DIR . 'images/vline.png',
+ 'image-minus' => static::ASSET_DIR . 'images/minus.png',
+ 'image-plus' => static::ASSET_DIR . 'images/plus.png',
];
if (array_key_exists($parameter_name, $parameters)) {
@@ -1956,10 +2025,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function pendingChangesLink() {
- return
- '<a href="#" onclick="window.open(\'edit_changes.php\', \'_blank\', chan_window_specs); return false;">' .
- $this->pendingChangesLinkText() .
- '</a>';
+ return '<a href="edit_changes.php">' . $this->pendingChangesLinkText() . '</a>';
}
/**
@@ -2004,7 +2070,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function primaryMenuContainer(array $menus) {
- return '<nav><ul class="primary-menu">' . $this->primaryMenuContent($menus) . '</ul></nav>';
+ return '<nav class="col wt-primary-navigation"><ul class="nav wt-primary-menu">' . $this->primaryMenuContent($menus) . '</ul></nav>';
}
/**
@@ -2016,7 +2082,7 @@ abstract class AbstractTheme {
*/
protected function primaryMenuContent(array $menus) {
return implode('', array_map(function (Menu $menu) {
- return $menu->getMenuAsList();
+ return $menu->bootstrap4();
}, $menus));
}
@@ -2045,7 +2111,7 @@ abstract class AbstractTheme {
* @return string
*/
protected function secondaryMenuContainer(array $menus) {
- return '<ul class="nav nav-pills secondary-menu">' . $this->secondaryMenuContent($menus) . '</ul>';
+ return '<div class="col wt-secondary-navigation"><ul class="nav wt-secondary-menu">' . $this->secondaryMenuContent($menus) . '</ul></div>';
}
/**
@@ -2057,7 +2123,7 @@ abstract class AbstractTheme {
*/
protected function secondaryMenuContent(array $menus) {
return implode('', array_map(function (Menu $menu) {
- return $menu->getMenuAsList();
+ return $menu->bootstrap4();
}, $menus));
}
@@ -2078,6 +2144,9 @@ abstract class AbstractTheme {
WT_BOOTSTRAP_CSS_URL,
WT_FONT_AWESOME_CSS_URL,
WT_FONT_AWESOME_RTL_CSS_URL,
+ WT_DATATABLES_BOOTSTRAP_CSS_URL,
+ WT_SELECT2_CSS_URL,
+ self::STYLESHEET,
];
if (I18N::direction() === 'rtl') {
@@ -2088,6 +2157,22 @@ abstract class AbstractTheme {
}
/**
+ * A fixed string to identify this theme, in settings, etc.
+ *
+ * @return string
+ */
+ public function themeId() {
+ return static::THEME_DIR;
+ }
+
+ /**
+ * What is this theme called?
+ *
+ * @return string
+ */
+ abstract public function themeName();
+
+ /**
* Create the <title> tag.
*
* @param string $title
diff --git a/app/Theme/AdministrationTheme.php b/app/Theme/AdministrationTheme.php
index c547c911ee..1e3027b72c 100644
--- a/app/Theme/AdministrationTheme.php
+++ b/app/Theme/AdministrationTheme.php
@@ -25,26 +25,23 @@ use Fisharebest\Webtrees\Tree;
*/
class AdministrationTheme extends AbstractTheme implements ThemeInterface {
/**
- * A list of CSS files to include for this page.
- *
- * @return string[]
+ * Where are our CSS, JS and other assets?
*/
- protected function stylesheets() {
- $stylesheets = parent::stylesheets();
- $stylesheets[] = WT_DATATABLES_BOOTSTRAP_CSS_URL;
- $stylesheets[] = WT_BOOTSTRAP_DATETIMEPICKER_CSS_URL;
- $stylesheets[] = $this->assetUrl() . 'style.css';
-
- return $stylesheets;
- }
+ const THEME_DIR = '_administration';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
- * Where are our CSS, JS and other assets?
+ * A list of CSS files to include for this page.
*
- * @return string A relative path, such as "themes/foo/"
+ * @return string[]
*/
- public function assetUrl() {
- return 'themes/_administration/css-1.7.5/';
+ protected function stylesheets() {
+ return array_merge(parent::stylesheets(), [
+ WT_DATATABLES_BOOTSTRAP_CSS_URL,
+ WT_BOOTSTRAP_DATETIMEPICKER_CSS_URL,
+ self::STYLESHEET,
+ ]);
}
/**
@@ -65,27 +62,6 @@ class AdministrationTheme extends AbstractTheme implements ThemeInterface {
}
/**
- * Create the contents of the <header> tag.
- *
- * @return string
- */
- protected function headerContent() {
- return
- $this->accessibilityLinks() .
- $this->secondaryMenuContainer($this->secondaryMenu());
- }
-
- /**
- * Allow themes to add extra scripts to the page footer.
- *
- * @return string
- */
- public function hookFooterExtraJavascript() {
- return
- '<script src="' . WT_BOOTSTRAP_JS_URL . '"></script>';
- }
-
- /**
* Site administration functions.
*
* @return Menu
@@ -98,10 +74,8 @@ class AdministrationTheme extends AbstractTheme implements ThemeInterface {
new Menu(/* I18N: Menu entry */ I18N::translate('Languages'), 'admin_site_config.php?action=languages'),
new Menu(/* I18N: Menu entry */ I18N::translate('Tracking and analytics'), 'admin_site_config.php?action=tracking'),
new Menu(/* I18N: Menu entry */ I18N::translate('Website logs'), 'admin_site_logs.php'),
- new Menu(/* I18N: Menu entry */ I18N::translate('Website access rules'), 'admin_site_access.php'),
new Menu(/* I18N: Menu entry */ I18N::translate('Clean up data folder'), 'admin_site_clean.php'),
new Menu(/* I18N: Menu entry */ I18N::translate('Server information'), 'admin_site_info.php'),
- new Menu(/* I18N: Menu entry */ I18N::translate('README documentation'), 'admin_site_readme.php'),
]);
}
@@ -226,25 +200,15 @@ class AdministrationTheme extends AbstractTheme implements ThemeInterface {
* @return string
*/
protected function primaryMenuContainer(array $menus) {
- $html = '';
- foreach ($menus as $menu) {
- $html .= $menu->bootstrap();
- }
-
return
- '<nav class="navbar navbar-default">' .
- '<div class="navbar-header">' .
- '<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#primary-navbar-collapse">' .
- '<span class="sr-only">Toggle navigation</span>' .
- '<span class="icon-bar"></span>' .
- '<span class="icon-bar"></span>' .
- '<span class="icon-bar"></span>' .
- '</button>' .
+ '<nav class="navbar navbar-toggleable-md navbar-light bg-faded" role="navigation">' .
+ '<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">' .
+ '<span class="navbar-toggler-icon"></span>' .
+ '</button> ' .
'<a class="navbar-brand" href="admin.php">' . I18N::translate('Control panel') . '</a>' .
- '</div>' .
'<div class="collapse navbar-collapse" id="primary-navbar-collapse">' .
- '<ul class="nav navbar-nav">' .
- $html .
+ '<ul class="navbar-nav">' .
+ $this->primaryMenuContent($menus) .
'</ul>' .
'</div>' .
'</nav>';
@@ -265,37 +229,6 @@ class AdministrationTheme extends AbstractTheme implements ThemeInterface {
}
/**
- * Add markup to the secondary menu.
- *
- * @param Menu[] $menus
- *
- * @return string
- */
- protected function secondaryMenuContainer(array $menus) {
- return '<div class="clearfix"><ul class="nav nav-pills small pull-right flip" role="menu">' . $this->secondaryMenuContent($menus) . '</ul></div>';
- }
-
- /**
- * Format the secondary menu.
- *
- * @param Menu[] $menus
- *
- * @return string
- */
- protected function secondaryMenuContent(array $menus) {
- return implode('', array_map(function (Menu $menu) { return $menu->bootstrap(); }, $menus));
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return '_administration';
- }
-
- /**
* What is this theme called?
*
* @return string
diff --git a/app/Theme/CloudsTheme.php b/app/Theme/CloudsTheme.php
index e4dd42500f..24b25e74cb 100644
--- a/app/Theme/CloudsTheme.php
+++ b/app/Theme/CloudsTheme.php
@@ -17,7 +17,6 @@ namespace Fisharebest\Webtrees\Theme;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Menu;
-use Fisharebest\Webtrees\Theme;
/**
* The clouds theme.
@@ -25,60 +24,10 @@ use Fisharebest\Webtrees\Theme;
class CloudsTheme extends AbstractTheme implements ThemeInterface {
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl() {
- return 'themes/clouds/css-1.7.8/';
- }
-
- /**
- * Add markup to a flash message.
- *
- * @param \stdClass $message
- *
- * @return string
- */
- protected function flashMessageContainer(\stdClass $message) {
- // This theme uses jQueryUI markup.
- switch ($message->status) {
- case 'danger':
- return '<p class="ui-state-error">' . $message->text . '</p>';
- default:
- return '<p class="ui-state-highlight">' . $message->text . '</p>';
- }
- }
-
- /**
- * Format the contents of a variable-height home-page block.
- *
- * @param string $id
- * @param string $title
- * @param string $class
- * @param string $content
- *
- * @return string
- */
- public function formatBlock($id, $title, $class, $content) {
- return
- '<div id="' . $id . '" class="block" >' .
- '<table class="blockheader"><tr><td class="blockh1"></td><td class="blockh2">' .
- '<div class="blockhc"><b>' . $title . '</b></div>' .
- '</td><td class="blockh3"></td></tr></table>' .
- '<div class="blockcontent normal_inner_block ' . $class . '">' . $content . '</div>' .
- '</div>';
- }
-
- /**
- * Create a search field and submit button for the quick search form in the header.
- *
- * @return string
*/
- protected function formQuickSearchFields() {
- return
- '<input type="search" name="query" size="15" placeholder="' . I18N::translate('Search') . '">' .
- '<input class="search-icon" type="image" src="' . $this->assetUrl() . 'images/go.png" alt="' . I18N::translate('Search') . '" title="' . I18N::translate('Search') . '">';
- }
+ const THEME_DIR = 'clouds';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
* Allow themes to add extra scripts to the page footer.
@@ -97,7 +46,7 @@ class CloudsTheme extends AbstractTheme implements ThemeInterface {
' transition: "none",' .
' slideshowStart: "' . I18N::translate('Play') . '",' .
' slideshowStop: "' . I18N::translate('Stop') . '",' .
- ' title: function() { return jQuery(this).data("title"); }' .
+ ' title: function() { return $(this).data("title"); }' .
'});' .
'</script>';
}
@@ -133,21 +82,16 @@ class CloudsTheme extends AbstractTheme implements ThemeInterface {
* @return string
*/
protected function primaryMenuContent(array $menus) {
- $html = '';
-
- foreach ($menus as $menu) {
- // Create an inert menu - to use as a label
- $tmp = new Menu($menu->getLabel(), '');
-
- // Insert the label into the submenu
- $submenus = $menu->getSubmenus();
- array_unshift($submenus, $tmp);
- $menu->setSubmenus($submenus);
+ return implode('', array_map(function (Menu $menu) {
+ if (!empty($menu->getSubmenus())) {
+ // Insert a dummy menu / label into the submenu
+ $submenus = $menu->getSubmenus();
+ array_unshift($submenus, new Menu($menu->getLabel(), null, null, [ 'onclick' => 'return false;']));
+ $menu->setSubmenus($submenus);
+ }
- $html .= $menu->getMenuAsList();
- }
-
- return $html;
+ return $menu->bootstrap4();
+ }, $menus));
}
/**
@@ -156,19 +100,9 @@ class CloudsTheme extends AbstractTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/clouds/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'clouds';
+ return array_merge(parent::stylesheets(), [
+ self::STYLESHEET,
+ ]);
}
/**
diff --git a/app/Theme/ColorsTheme.php b/app/Theme/ColorsTheme.php
index 7149805f30..0d21ddae49 100644
--- a/app/Theme/ColorsTheme.php
+++ b/app/Theme/ColorsTheme.php
@@ -26,47 +26,18 @@ use Fisharebest\Webtrees\Site;
* The colors theme.
*/
class ColorsTheme extends CloudsTheme implements ThemeInterface {
- /** @var string[] A list of color palettes */
- protected $palettes;
-
- /** @var string Which of the color palettes to use on this page */
- protected $palette;
-
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
*/
- public function assetUrl() {
- return 'themes/colors/css-1.7.8/';
- }
+ const THEME_DIR = 'colors';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
- /**
- * Add markup to the secondary menu.
- *
- * @return string
- */
- protected function formatSecondaryMenu() {
- return
- '<ul class="secondary-menu">' .
- implode('', $this->secondaryMenu()) .
- '<li>' .
- $this->formQuickSearch() .
- '</li>' .
- '</ul>';
- }
+ /** @var string[] A list of color palettes */
+ protected $palettes;
- /**
- * Create the contents of the <header> tag.
- *
- * @return string
- */
- protected function headerContent() {
- return
- //$this->accessibilityLinks() .
- $this->formatTreeTitle() .
- $this->formatSecondaryMenu();
- }
+ /** @var string Which of the color palettes to use on this page */
+ protected $palette;
/**
* Create resources for the colors theme.
@@ -144,7 +115,7 @@ class ColorsTheme extends CloudsTheme implements ThemeInterface {
* @return Menu
*/
protected function menuPalette() {
- if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
+ if ($this->tree !== null && Site::getPreference('ALLOW_USER_THEMES') === '1' && $this->tree->getPreference('ALLOW_THEME_DROPDOWN') === '1') {
$menu = new Menu(/* I18N: A colour scheme */
I18N::translate('Palette'), '#', 'menu-color');
@@ -171,20 +142,10 @@ class ColorsTheme extends CloudsTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/colors/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- $this->assetUrl() . 'palette/' . $this->palette . '.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'colors';
+ return array_merge(parent::stylesheets(), [
+ 'themes/colors/css-1.7.8/style.css',
+ 'themes/colors/css-1.7.8/palette/' . $this->palette . '.css',
+ ]);
}
/**
diff --git a/app/Theme/FabTheme.php b/app/Theme/FabTheme.php
index 4981e55077..e71acbf459 100644
--- a/app/Theme/FabTheme.php
+++ b/app/Theme/FabTheme.php
@@ -24,29 +24,10 @@ use Fisharebest\Webtrees\Menu;
class FabTheme extends AbstractTheme implements ThemeInterface {
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl() {
- return 'themes/fab/css-1.7.8/';
- }
-
- /**
- * Add markup to a flash message.
- *
- * @param \stdClass $message
- *
- * @return string
*/
- protected function flashMessageContainer(\stdClass $message) {
- // This theme uses jQueryUI markup.
- switch ($message->status) {
- case 'danger':
- return '<p class="ui-state-error">' . $message->text . '</p>';
- default:
- return '<p class="ui-state-highlight">' . $message->text . '</p>';
- }
- }
+ const THEME_DIR = 'fab';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
* Add markup to the secondary menu.
@@ -55,8 +36,8 @@ class FabTheme extends AbstractTheme implements ThemeInterface {
*/
protected function formatSecondaryMenu() {
return
- '<ul class="secondary-menu">' .
- implode('', $this->secondaryMenu()) .
+ '<ul class="nav wt-secondary-menu justify-content-end">' .
+ implode('', array_map(function (Menu $menu) { return $menu->bootstrap4(); }, $this->secondaryMenu())) .
'<li>' .
$this->formQuickSearch() .
'</li>' .
@@ -64,29 +45,6 @@ class FabTheme extends AbstractTheme implements ThemeInterface {
}
/**
- * Create the contents of the <header> tag.
- *
- * @return string
- */
- protected function headerContent() {
- return
- //$this->accessibilityLinks() .
- $this->formatTreeTitle() .
- $this->formatSecondaryMenu();
- }
-
- /**
- * Add markup to an item in the secondary menu.
- *
- * @param Menu $menu
- *
- * @return string
- */
- protected function formatSecondaryMenuItem(Menu $menu) {
- return $menu->getMenuAsList();
- }
-
- /**
* Create a search field and submit button for the quick search form in the header.
*
* @return string
@@ -113,7 +71,7 @@ class FabTheme extends AbstractTheme implements ThemeInterface {
' transition: "none",' .
' slideshowStart: "' . I18N::translate('Play') . '",' .
' slideshowStop: "' . I18N::translate('Stop') . '",' .
- ' title: function() { return jQuery(this).data("title"); }' .
+ ' title: function() { return $(this).data("title"); }' .
'});' .
'</script>';
}
@@ -148,19 +106,9 @@ class FabTheme extends AbstractTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/fab/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'fab';
+ return array_merge(parent::stylesheets(), [
+ self::STYLESHEET,
+ ]);
}
/**
diff --git a/app/Theme/MinimalTheme.php b/app/Theme/MinimalTheme.php
index 307cfdaa91..4ac7e50663 100644
--- a/app/Theme/MinimalTheme.php
+++ b/app/Theme/MinimalTheme.php
@@ -23,75 +23,10 @@ use Fisharebest\Webtrees\I18N;
class MinimalTheme extends AbstractTheme implements ThemeInterface {
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl() {
- return 'themes/minimal/css-1.7.8/';
- }
-
- /**
- * Add markup to a flash message.
- *
- * @param \stdClass $message
- *
- * @return string
- */
- protected function flashMessageContainer(\stdClass $message) {
- // This theme uses jQueryUI markup.
- switch ($message->status) {
- case 'danger':
- return '<p class="ui-state-error">' . $message->text . '</p>';
- default:
- return '<p class="ui-state-highlight">' . $message->text . '</p>';
- }
- }
-
- /**
- * Create a search field and submit button for the quick search form in the header.
- *
- * @return string
- */
- protected function formQuickSearchFields() {
- return
- '<input type="search" name="query" size="20" placeholder="' . I18N::translate('Search') . '">';
- }
-
- /**
- * Add markup to the secondary menu.
- *
- * @return string
*/
- protected function formatSecondaryMenu() {
- return
- '<ul class="secondary-menu">' .
- implode('', $this->secondaryMenu()) .
- '<li>' .
- $this->formQuickSearch() .
- '</li>' .
- '</ul>';
- }
-
- /**
- * Create the contents of the <header> tag.
- *
- * @return string
- */
- protected function headerContent() {
- return
- //$this->accessibilityLinks() .
- $this->formatTreeTitle() .
- $this->formatSecondaryMenu();
- }
-
- /**
- * A small "powered by webtrees" logo for the footer.
- *
- * @return string
- */
- protected function logoPoweredBy() {
- return '<a href="' . WT_WEBTREES_URL . '" class="powered-by-webtrees" title="' . WT_WEBTREES_URL . '">' . WT_WEBTREES . '</a>';
- }
+ const THEME_DIR = 'minimal';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
* Allow themes to add extra scripts to the page footer.
@@ -110,7 +45,7 @@ class MinimalTheme extends AbstractTheme implements ThemeInterface {
' transition: "none",' .
' slideshowStart: "' . I18N::translate('Play') . '",' .
' slideshowStop: "' . I18N::translate('Stop') . '",' .
- ' title: function() { return jQuery(this).data("title"); }' .
+ ' title: function() { return $(this).data("title"); }' .
'});' .
'</script>';
}
@@ -143,19 +78,9 @@ class MinimalTheme extends AbstractTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/minimal/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'minimal';
+ return array_merge(parent::stylesheets(), [
+ self::STYLESHEET,
+ ]);
}
/**
diff --git a/app/Theme/ThemeInterface.php b/app/Theme/ThemeInterface.php
index ebbf773432..cdbc853ec2 100644
--- a/app/Theme/ThemeInterface.php
+++ b/app/Theme/ThemeInterface.php
@@ -27,25 +27,12 @@ use Fisharebest\Webtrees\User;
*/
interface ThemeInterface {
/**
- * Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl();
-
- /**
* Create the top of the <body>.
*
* @return string
*/
public function bodyHeader();
- /**
- * Create the top of the <body> (for popup windows).
- *
- * @return string
- */
- public function bodyHeaderPopupWindow();
/**
* Create a contact link for a user.
@@ -71,14 +58,6 @@ interface ThemeInterface {
public function footerContainer();
/**
- * Close the main content.
- * Note that popup windows are deprecated
- *
- * @return string
- */
- public function footerContainerPopupWindow();
-
- /**
* Format the contents of a variable-height home-page block.
*
* @param string $id
diff --git a/app/Theme/WebtreesTheme.php b/app/Theme/WebtreesTheme.php
index 251b003a56..05706ad387 100644
--- a/app/Theme/WebtreesTheme.php
+++ b/app/Theme/WebtreesTheme.php
@@ -16,7 +16,6 @@
namespace Fisharebest\Webtrees\Theme;
use Fisharebest\Webtrees\I18N;
-use Fisharebest\Webtrees\Theme;
/**
* The webtrees (default) theme.
@@ -24,40 +23,10 @@ use Fisharebest\Webtrees\Theme;
class WebtreesTheme extends AbstractTheme implements ThemeInterface {
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl() {
- return 'themes/webtrees/css-1.7.8/';
- }
-
- /**
- * Add markup to a flash message.
- *
- * @param \stdClass $message
- *
- * @return string
- */
- protected function flashMessageContainer(\stdClass $message) {
- // This theme uses jQueryUI markup.
- switch ($message->status) {
- case 'danger':
- return '<p class="ui-state-error">' . $message->text . '</p>';
- default:
- return '<p class="ui-state-highlight">' . $message->text . '</p>';
- }
- }
-
- /**
- * Create a search field and submit button for the quick search form in the header.
- *
- * @return string
*/
- protected function formQuickSearchFields() {
- return
- '<input type="search" name="query" size="25" placeholder="' . I18N::translate('Search') . '">' .
- '<input type="image" class="image" src="' . $this->assetUrl() . 'images/search.png" alt="' . I18N::translate('Search') . '" title="' . I18N::translate('Search') . '">';
- }
+ const THEME_DIR = 'webtrees';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
* Allow themes to add extra scripts to the page footer.
@@ -76,7 +45,7 @@ class WebtreesTheme extends AbstractTheme implements ThemeInterface {
' transition:"none",' .
' slideshowStart:"' . I18N::translate('Play') . '",' .
' slideshowStop:"' . I18N::translate('Stop') . '",' .
- ' title: function() { return jQuery(this).data("title"); }' .
+ ' title: function() { return $(this).data("title"); }' .
'});' .
'</script>';
}
@@ -109,19 +78,9 @@ class WebtreesTheme extends AbstractTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/webtrees/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'webtrees';
+ return array_merge(parent::stylesheets(), [
+ self::STYLESHEET,
+ ]);
}
/**
diff --git a/app/Theme/XeneaTheme.php b/app/Theme/XeneaTheme.php
index 8a379093c1..503e8c25d1 100644
--- a/app/Theme/XeneaTheme.php
+++ b/app/Theme/XeneaTheme.php
@@ -23,57 +23,10 @@ use Fisharebest\Webtrees\I18N;
class XeneaTheme extends AbstractTheme implements ThemeInterface {
/**
* Where are our CSS, JS and other assets?
- *
- * @return string A relative path, such as "themes/foo/"
- */
- public function assetUrl() {
- return 'themes/xenea/css-1.7.8/';
- }
-
- /**
- * Add markup to a flash message.
- *
- * @param \stdClass $message
- *
- * @return string
*/
- protected function flashMessageContainer(\stdClass $message) {
- // This theme uses jQueryUI markup.
- switch ($message->status) {
- case 'danger':
- return '<p class="ui-state-error">' . $message->text . '</p>';
- default:
- return '<p class="ui-state-highlight">' . $message->text . '</p>';
- }
- }
-
- /**
- * Create a search field and submit button for the quick search form in the header.
- *
- * @return string
- */
- protected function formQuickSearchFields() {
- return
- '<input type="search" name="query" size="12" placeholder="' . I18N::translate('Search') . '">' .
- '<input type="submit" name="search" value="&gt;">';
- }
-
- /**
- * Create the contents of the <header> tag.
- *
- * @return string
- */
- protected function headerContent() {
- return
- //$this->accessibilityLinks() .
- '<div class="header-upper">' .
- $this->formatTreeTitle() .
- $this->formQuickSearch() .
- '</div>' .
- '<div class="header-lower">' .
- $this->formatSecondaryMenu() .
- '</div>';
- }
+ const THEME_DIR = 'xenea';
+ const ASSET_DIR = 'themes/' . self::THEME_DIR . '/css-1.7.8/';
+ const STYLESHEET = self::ASSET_DIR . 'style.css';
/**
* Allow themes to add extra scripts to the page footer.
@@ -92,7 +45,7 @@ class XeneaTheme extends AbstractTheme implements ThemeInterface {
' transition: "none",' .
' slideshowStart: "' . I18N::translate('Play') . '",' .
' slideshowStop: "' . I18N::translate('Stop') . '",' .
- ' title: function() { return jQuery(this).data("title"); }' .
+ ' title: function() { return $(this).data("title"); }' .
'});' .
'</script>';
}
@@ -125,19 +78,9 @@ class XeneaTheme extends AbstractTheme implements ThemeInterface {
* @return string[]
*/
protected function stylesheets() {
- return [
- 'themes/xenea/jquery-ui-1.11.2/jquery-ui.css',
- $this->assetUrl() . 'style.css',
- ];
- }
-
- /**
- * A fixed string to identify this theme, in settings, etc.
- *
- * @return string
- */
- public function themeId() {
- return 'xenea';
+ return array_merge(parent::stylesheets(), [
+ self::STYLESHEET,
+ ]);
}
/**
diff --git a/app/Tree.php b/app/Tree.php
index 72192881f6..353141addc 100644
--- a/app/Tree.php
+++ b/app/Tree.php
@@ -45,7 +45,7 @@ class Tree {
private static $trees;
/** @var string[] Cached copy of the wt_gedcom_setting table. */
- private $preferences;
+ private $preferences = [];
/** @var string[][] Cached copy of the wt_user_gedcom_setting table. */
private $user_preferences = [];
@@ -176,13 +176,13 @@ class Tree {
/**
* Get the tree’s configuration settings.
*
- * @param string $setting_name
- * @param string|null $default
+ * @param string $setting_name
+ * @param string $default
*
- * @return string|null
+ * @return string
*/
- public function getPreference($setting_name, $default = null) {
- if ($this->preferences === null) {
+ public function getPreference($setting_name, $default = '') {
+ if (empty($this->preferences)) {
$this->preferences = Database::prepare(
"SELECT SQL_CACHE setting_name, setting_value FROM `##gedcom_setting` WHERE gedcom_id = ?"
)->execute([$this->tree_id])->fetchAssoc();
@@ -205,27 +205,17 @@ class Tree {
*/
public function setPreference($setting_name, $setting_value) {
if ($setting_value !== $this->getPreference($setting_name)) {
- // Update the database
- if ($setting_value === null) {
- Database::prepare(
- "DELETE FROM `##gedcom_setting` WHERE gedcom_id = :tree_id AND setting_name = :setting_name"
- )->execute([
- 'tree_id' => $this->tree_id,
- 'setting_name' => $setting_name,
- ]);
- } else {
- Database::prepare(
- "REPLACE INTO `##gedcom_setting` (gedcom_id, setting_name, setting_value)" .
- " VALUES (:tree_id, :setting_name, LEFT(:setting_value, 255))"
- )->execute([
- 'tree_id' => $this->tree_id,
- 'setting_name' => $setting_name,
- 'setting_value' => $setting_value,
- ]);
- }
- // Update our cache
+ Database::prepare(
+ "REPLACE INTO `##gedcom_setting` (gedcom_id, setting_name, setting_value)" .
+ " VALUES (:tree_id, :setting_name, LEFT(:setting_value, 255))"
+ )->execute([
+ 'tree_id' => $this->tree_id,
+ 'setting_name' => $setting_name,
+ 'setting_value' => $setting_value,
+ ]);
+
$this->preferences[$setting_name] = $setting_value;
- // Audit log of changes
+
Log::addConfigurationLog('Tree preference "' . $setting_name . '" set to "' . $setting_value . '"', $this);
}
@@ -745,7 +735,7 @@ class Tree {
*
* @throws \Exception
*
- * @return GedcomRecord
+ * @return GedcomRecord|Individual|Family|Note|Source|Repository|Media
*/
public function createRecord($gedcom) {
if (preg_match('/^0 @(' . WT_REGEX_XREF . ')@ (' . WT_REGEX_TAG . ')/', $gedcom, $match)) {
diff --git a/app/User.php b/app/User.php
index 0f440938ae..e54b2868f6 100644
--- a/app/User.php
+++ b/app/User.php
@@ -31,8 +31,8 @@ class User {
/** @var string The email address of this user. */
private $email;
- /** @var array Cached copy of the wt_user_setting table. */
- private $preferences;
+ /** @var string[] Cached copy of the wt_user_setting table. */
+ private $preferences = [];
/** @var User[] Only fetch users from the database once. */
private static $cache = [];
@@ -452,28 +452,27 @@ class User {
* Since we'll fetch several settings for each user, and since there aren’t
* that many of them, fetch them all in one database query
*
- * @param string $setting_name
- * @param string|null $default
+ * @param string $setting_name
+ * @param string $default
*
- * @return string|null
+ * @return string
*/
- public function getPreference($setting_name, $default = null) {
- if ($this->preferences === null) {
- if ($this->user_id) {
- $this->preferences = Database::prepare(
- "SELECT SQL_CACHE setting_name, setting_value FROM `##user_setting` WHERE user_id = ?"
- )->execute([$this->user_id])->fetchAssoc();
- } else {
- // Not logged in? We have no preferences.
- $this->preferences = [];
- }
+ public function getPreference($setting_name, $default = '') {
+ if (empty($this->preferences) && $this->user_id !== null) {
+ $this->preferences = Database::prepare(
+ "SELECT SQL_CACHE setting_name, setting_value" .
+ " FROM `##user_setting`" .
+ " WHERE user_id = :user_id"
+ )->execute([
+ 'user_id' => $this->user_id,
+ ])->fetchAssoc();
}
- if (array_key_exists($setting_name, $this->preferences)) {
- return $this->preferences[$setting_name];
- } else {
- return $default;
+ if (!array_key_exists($setting_name, $this->preferences)) {
+ $this->preferences[$setting_name] = $default;
}
+
+ return $this->preferences[$setting_name];
}
/**
@@ -488,24 +487,8 @@ class User {
if ($this->user_id && $this->getPreference($setting_name) !== $setting_value) {
Database::prepare("REPLACE INTO `##user_setting` (user_id, setting_name, setting_value) VALUES (?, ?, LEFT(?, 255))")
->execute([$this->user_id, $setting_name, $setting_value]);
- $this->preferences[$setting_name] = $setting_value;
- }
-
- return $this;
- }
- /**
- * Delete a setting for the user.
- *
- * @param string $setting_name
- *
- * @return User
- */
- public function deletePreference($setting_name) {
- if ($this->user_id && $this->getPreference($setting_name) !== null) {
- Database::prepare("DELETE FROM `##user_setting` WHERE user_id = ? AND setting_name = ?")
- ->execute([$this->user_id, $setting_name]);
- unset($this->preferences[$setting_name]);
+ $this->preferences[$setting_name] = $setting_value;
}
return $this;