diff options
| -rw-r--r-- | app/Controller/RelationshipController.php | 305 | ||||
| -rw-r--r-- | composer.json | 1 | ||||
| -rw-r--r-- | composer.lock | 48 | ||||
| -rw-r--r-- | includes/functions/functions.php | 143 | ||||
| -rw-r--r-- | relationship.php | 479 | ||||
| -rw-r--r-- | themes/clouds/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | themes/colors/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | themes/fab/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | themes/minimal/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | themes/webtrees/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | themes/xenea/css-1.7.0/style.css | 9 | ||||
| -rw-r--r-- | vendor/autoload.php | 2 | ||||
| -rw-r--r-- | vendor/composer/autoload_classmap.php | 2 | ||||
| -rw-r--r-- | vendor/composer/autoload_psr4.php | 1 | ||||
| -rw-r--r-- | vendor/composer/autoload_real.php | 10 | ||||
| -rw-r--r-- | vendor/composer/installed.json | 48 |
16 files changed, 350 insertions, 743 deletions
diff --git a/app/Controller/RelationshipController.php b/app/Controller/RelationshipController.php index 9eeb4b0296..9b300d7ca6 100644 --- a/app/Controller/RelationshipController.php +++ b/app/Controller/RelationshipController.php @@ -16,264 +16,107 @@ namespace Fisharebest\Webtrees; * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +use Fisharebest\Algorithm\Dijkstra; + /** - * Class BranchesController - Controller for the branches list + * Class RelationshipController - Controller for the relationships calculations */ -class BranchesController extends PageController { - /** @var string Generate the branches for this surname */ - private $surname; - - /** @var bool Whether to use Standard phonetic matching */ - private $soundex_std; - - /** @var bool Whether to use Daitch-Mokotov phonetic matching */ - private $soundex_dm; - - /** @var Individual[] Everyone with the selected surname */ - private $individuals = array(); - - /** @var Individual[] Ancestors of the root person - for SOSA numbers */ - private $ancestors = array(); - - /** - * Create a branches list controller - */ - public function __construct() { - parent::__construct(); - - $this->surname = Filter::get('surname'); - $this->soundex_std = Filter::getBool('soundex_std'); - $this->soundex_dm = Filter::getBool('soundex_dm'); - - if ($this->surname) { - $this->setPageTitle(/* I18N: %s is a surname */ - I18N::translate('Branches of the %s family', Filter::escapeHtml($this->surname))); - $this->loadIndividuals(); - $self = Individual::getInstance(WT_USER_GEDCOM_ID); - if ($self) { - $this->loadAncestors($self, 1); - } - } else { - $this->setPageTitle(/* I18N: Branches of a family tree */ I18N::translate('Branches')); - } - } - - /** - * The surname to be used on this page. - * - * @return null|string - */ - public function getSurname() { - return $this->surname; - } - +class RelationshipController extends PageController { /** - * Should we use Standard phonetic matching + * Calculate the shortest paths - or all paths - between two individuals. * - * @return boolean - */ - public function getSoundexStd() { - return $this->soundex_std; - } - - /** - * Should we use Daitch-Mokotov phonetic matching + * @param Individual $indi1 + * @param Individual $indi2 + * @param boolean $all; * - * @return boolean + * @return string[][]; */ - public function getSoundexDm() { - return $this->soundex_dm; - } + public function calculateRelationships(Individual $individual1, Individual $individual2, $all) { + $rows = Database::prepare( + "SELECT l_from, l_to FROM `##link` WHERE l_file = :tree_id AND l_type IN ('FAMS', 'FAMC', 'CHIL', 'HUSB', 'WIFE')" + )->execute(array( + 'tree_id' => $individual1->getTree()->getTreeId() + ))->fetchAll(); - /** - * Fetch all individuals with a matching surname - */ - private function loadIndividuals() { - $sql = - "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom" . - " FROM `##individuals`" . - " JOIN `##name` ON (i_id=n_id AND i_file=n_file)" . - " WHERE n_file = ?" . - " AND n_type != ?" . - " AND (n_surn = ? OR n_surname = ?"; - $args = array(WT_GED_ID, '_MARNM', $this->surname, $this->surname); - if ($this->soundex_std) { - $sdx = Soundex::russell($this->surname); - if ($sdx) { - foreach (explode(':', $sdx) as $value) { - $sql .= " OR n_soundex_surn_std LIKE CONCAT('%', ?, '%')"; - $args[] = $value; - } - } - } - if ($this->soundex_dm) { - $sdx = Soundex::daitchMokotoff($this->surname); - if ($sdx) { - foreach (explode(':', $sdx) as $value) { - $sql .= " OR n_soundex_surn_dm LIKE CONCAT('%', ?, '%')"; - $args[] = $value; - } - } - } - $sql .= ')'; - $rows = Database::prepare($sql)->execute($args)->fetchAll(); - $this->individuals = array(); + $graph = array(); foreach ($rows as $row) { - $this->individuals[] = Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); + $graph[$row->l_from][$row->l_to] = 1; } - // Sort by birth date, oldest first - usort($this->individuals, __NAMESPACE__ . '\Individual::compareBirthDate'); - } - /** - * Load the ancestors of an individual, so we can highlight them in the list - * - * @param Individual $ancestor - * @param integer $sosa - */ - private function loadAncestors(Individual $ancestor, $sosa) { - if ($ancestor) { - $this->ancestors[$sosa] = $ancestor; - foreach ($ancestor->getChildFamilies() as $family) { - foreach ($family->getSpouses() as $parent) { - $this->loadAncestors($parent, $sosa * 2 + ($parent->getSex() == 'F' ? 1 : 0)); - } - } - } - } + $xref1 = $individual1->getXref(); + $xref2 = $individual2->getXref(); + $dijkstra = new Dijkstra($graph); + $paths = $dijkstra->shortestPaths($xref1, $xref2); - /** - * For each individual with no ancestors, list their descendants. - * - * @return string - */ - public function getPatriarchsHtml() { - $html = ''; - foreach ($this->individuals as $individual) { - foreach ($individual->getChildFamilies() as $family) { - foreach ($family->getSpouses() as $parent) { - if (in_array($parent, $this->individuals, true)) { - continue 3; + if ($all) { + $queue = array(); + foreach ($paths as $path) { + // Insert the paths into the queue, with an exclusion list. + $queue[] = array('path' => $path, 'exclude' => array()); + // While there are un-extended paths + while (list(, $next) = each($queue)) { + // For each family on the path + for ($n = count($next['path']) - 2; $n >= 1; $n-=2) { + $exclude = $next['exclude']; + $exclude[] = $next['path'][$n]; + // Add any new path to the queue + foreach ($dijkstra->shortestPaths($xref1, $xref2, $exclude) as $new_path) { + $queue[] = array('path' => $new_path, 'exclude' => $exclude); + } } } } - $html .= $this->getDescendantsHtml($individual); + // Extract the paths from the queue, removing duplicates. + $paths = array(); + foreach ($queue as $next) { + $paths[implode('-', $next['path'])] = $next['path']; + } } - return $html; + return $paths; } /** - * Generate a recursive list of descendants of an individual. - * If parents are specified, we can also show the pedigree (adopted, etc.). + * Convert a path (list of XREFs) to an "old-style" string of relationships. + * + * Return an empty array, if privacy rules prevent us viewing any node. * - * @param Individual $individual - * @param Family|null $parents + * @param string $path * - * @return string + * @return array(); */ - private function getDescendantsHtml(Individual $individual, Family $parents = null) { - // A person has many names. Select the one that matches the searched surname - $person_name = ''; - foreach ($individual->getAllNames() as $name) { - list($surn1) = explode(",", $name['sort']); - if (// one name is a substring of the other - stripos($surn1, $this->surname) !== false || - stripos($this->surname, $surn1) !== false || - // one name sounds like the other - $this->soundex_std && Soundex::compare(Soundex::russell($surn1), Soundex::russell($this->surname)) || - $this->soundex_dm && Soundex::compare(Soundex::daitchMokotoff($surn1), Soundex::daitchMokotoff($this->surname)) - ) { - $person_name = $name['full']; - break; - } - } - - // No matching name? Typically children with a different surname. The branch stops here. - if (!$person_name) { - return '<li title="' . strip_tags($individual->getFullName()) . '">' . $individual->getSexImage() . '…</li>'; - } - - // Is this individual one of our ancestors? - $sosa = array_search($individual, $this->ancestors, true); - if ($sosa) { - $sosa_class = 'search_hit'; - $sosa_html = ' <a class="details1 ' . $individual->getBoxStyle() . '" title="' . I18N::translate('Sosa') . '" href="relationship.php?pid2=' . WT_USER_ROOT_ID . '&pid1=' . $individual->getXref() . '">' . $sosa . '</a>' . self::sosaGeneration($sosa); - } else { - $sosa_class = ''; - $sosa_html = ''; - } + public function oldStyleRelationshipPath(array $path) { + $spouse_codes = array('M' => 'hus', 'F' => 'wif', 'U' => 'spo'); + $parent_codes = array('M' => 'fat', 'F' => 'mot', 'U' => 'par'); + $child_codes = array('M' => 'son', 'F' => 'dau', 'U' => 'chi'); + $sibling_codes = array('M' => 'bro', 'F' => 'sis', 'U' => 'sib'); + $relationships = array(); - // Generate HTML for this individual, and all their descendants - $indi_html = $individual->getSexImage() . '<a class="' . $sosa_class . '" href="' . $individual->getHtmlUrl() . '">' . $person_name . '</a> ' . $individual->getLifeSpan() . $sosa_html; - - // If this is not a birth pedigree (e.g. an adoption), highlight it - if ($parents) { - $pedi = ''; - foreach ($individual->getFacts('FAMC') as $fact) { - if ($fact->getTarget() === $parents) { - $pedi = $fact->getAttribute('PEDI'); - break; - } + for ($i = 1; $i < count($path); $i += 2) { + $family = Family::getInstance($path[$i]); + $prev = Individual::getInstance($path[$i - 1]); + $next = Individual::getInstance($path[$i + 1]); + if (preg_match('/\n\d (HUSB|WIFE|CHIL) @' . $prev->getXref() . '@/', $family->getGedcom(), $match)) { + $rel1 = $match[1]; + } else { + return array(); } - if ($pedi && $pedi != 'birth') { - $indi_html = '<span class="red">' . WT_Gedcom_Code_Pedi::getValue($pedi, $individual) . '</span> ' . $indi_html; + if (preg_match('/\n\d (HUSB|WIFE|CHIL) @' . $next->getXref() . '@/', $family->getGedcom(), $match)) { + $rel2 = $match[1]; + } else { + return array(); } - } - - // spouses and children - $spouse_families = $individual->getSpouseFamilies(); - if ($spouse_families) { - usort($spouse_families, __NAMESPACE__ . '\Family::compareMarrDate'); - $fam_html = ''; - foreach ($spouse_families as $family) { - $fam_html .= $indi_html; // Repeat the individual details for each spouse. - - $spouse = $family->getSpouse($individual); - if ($spouse) { - $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=' . WT_USER_ROOT_ID . '&pid1=' . $spouse->getXref() . '"> ' . $sosa . ' </a>' . self::sosaGeneration($sosa); - } else { - $sosa_class = ''; - $sosa_html = ''; - } - $marriage_year = $family->getMarriageYear(); - if ($marriage_year) { - $fam_html .= ' <a href="' . $family->getHtmlUrl() . '" title="' . strip_tags($family->getMarriageDate()->display()) . '"><i class="icon-rings"></i>' . $marriage_year . '</a>'; - } elseif ($family->getFirstFact('MARR')) { - $fam_html .= ' <a href="' . $family->getHtmlUrl() . '" title="' . WT_Gedcom_Tag::getLabel('MARR') . '"><i class="icon-rings"></i></a>'; - } elseif ($family->getFirstFact('_NMR')) { - $fam_html .= ' <a href="' . $family->getHtmlUrl() . '" title="' . WT_Gedcom_Tag::getLabel('_NMR') . '"><i class="icon-rings"></i></a>'; - } - $fam_html .= ' ' . $spouse->getSexImage() . '<a class="' . $sosa_class . '" href="' . $spouse->getHtmlUrl() . '">' . $spouse->getFullName() . '</a> ' . $spouse->getLifeSpan() . ' ' . $sosa_html; - } - - $fam_html .= '<ol>'; - foreach ($family->getChildren() as $child) { - $fam_html .= $this->getDescendantsHtml($child, $family); - } - $fam_html .= '</ol>'; + if (($rel1 === 'HUSB' || $rel1 === 'WIFE') && ($rel2 === 'HUSB' || $rel2 === 'WIFE')) { + $relationships[$i] = $spouse_codes[$next->getSex()]; + } elseif (($rel1 === 'HUSB' || $rel1 === 'WIFE') && $rel2 === 'CHIL') { + $relationships[$i] = $child_codes[$next->getSex()]; + } elseif ($rel1 === 'CHIL' && ($rel2 === 'HUSB' || $rel2 === 'WIFE')) { + $relationships[$i] = $parent_codes[$next->getSex()]; + } elseif ($rel1 === 'CHIL' && $rel2 === 'CHIL') { + $relationships[$i] = $sibling_codes[$next->getSex()]; } - - return '<li>' . $fam_html . '</li>'; - } else { - // No spouses - just show the individual - return '<li>' . $indi_html . '</li>'; } - } - - /** - * Convert a SOSA number into a generation number. e.g. 8 = great-grandfather = 3 generations - * - * @param integer $sosa - * - * @return string - */ - private static function sosaGeneration($sosa) { - $generation = (int) log($sosa, 2) + 1; - return '<sup title="' . I18N::translate('Generation') . '">' . $generation . '</sup>'; + return $relationships; } } diff --git a/composer.json b/composer.json index c94e501bb9..6eb9e2d2c5 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "require": { "bombayworks/zendframework1": "*", "ezyang/htmlpurifier": "*", + "fisharebest/algorithm": "*", "fisharebest/ext-calendar": "*", "ircmaxell/password-compat": "*", "michelf/php-markdown": "*", diff --git a/composer.lock b/composer.lock index 0e0b8cf3bb..587ca64c9e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "542685d0ebe4107f510791dcc2f67542", + "hash": "32d402bd09151198895b11be00e60610", "packages": [ { "name": "bombayworks/zendframework1", @@ -103,6 +103,52 @@ "time": "2013-11-30 08:25:19" }, { + "name": "fisharebest/algorithm", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/fisharebest/algorithm.git", + "reference": "ddfbf31e7b1ef49f227409a41261770ed3fb467b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fisharebest/algorithm/zipball/ddfbf31e7b1ef49f227409a41261770ed3fb467b", + "reference": "ddfbf31e7b1ef49f227409a41261770ed3fb467b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "*", + "satooshi/php-coveralls": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fisharebest\\Algorithm\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0+" + ], + "authors": [ + { + "name": "Greg Roach", + "email": "greg@subaqua.co.uk", + "role": "Developer" + } + ], + "description": "Implementation of standard algorithms in PHP.", + "homepage": "https://github.com/fisharebest/algorithm", + "keywords": [ + "Algorithm", + "dijkstra" + ], + "time": "2015-02-15 21:38:53" + }, + { "name": "fisharebest/ext-calendar", "version": "1.3.0", "source": { diff --git a/includes/functions/functions.php b/includes/functions/functions.php index 58c9b46bdc..0df71a0785 100644 --- a/includes/functions/functions.php +++ b/includes/functions/functions.php @@ -255,8 +255,6 @@ function sort_facts(&$arr) { /** * For close family relationships, such as the families tab and the family navigator * Display a tick if both individuals are the same. - * Stop after 3 steps, because pending edits may mean that there is no longer a - * relationship to find. * * @param Individual $person1 * @param Individual $person2 @@ -267,7 +265,7 @@ function get_close_relationship_name(Individual $person1, Individual $person2) { if ($person1 === $person2) { $label = '<i class="icon-selected" title="' . I18N::translate('self') . '"></i>'; } else { - $label = get_relationship_name(get_relationship($person1, $person2, true, 3)); + $label = get_relationship_name(get_relationship($person1, $person2)); } return $label; @@ -275,8 +273,6 @@ function get_close_relationship_name(Individual $person1, Individual $person2) { /** * For facts on the individual/family pages. - * Stop after 4 steps, as distant relationships may take a long time to find. - * Review the limit of 4 if/when the performance of the function is improved. * * @param Individual $person1 * @param Individual $person2 @@ -287,7 +283,7 @@ function get_associate_relationship_name(Individual $person1, Individual $person if ($person1 === $person2) { $label = I18N::translate('self'); } else { - $label = get_relationship_name(get_relationship($person1, $person2, true, 4)); + $label = get_relationship_name(get_relationship($person1, $person2)); } return $label; @@ -296,19 +292,22 @@ function get_associate_relationship_name(Individual $person1, Individual $person /** * Get relationship between two individuals in the gedcom * - * @param Individual $person1 the person to compute the relationship from - * @param Individual $person2 the person to compute the relatiohip to - * @param boolean $followspouse whether to add spouses to the path - * @param integer $maxlength the maximum length of path - * @param integer $path_to_find which path in the relationship to find, 0 is the shortest path, 1 is the next shortest path, etc + * @param Individual $person1 The person to compute the relationship from + * @param Individual $person2 The person to compute the relatiohip to + * @param integer $maxlength The maximum length of path * * @return array|bool An array of nodes on the relationship path, or false if no path found */ -function get_relationship(Individual $person1, Individual $person2, $followspouse = true, $maxlength = 0, $path_to_find = 0) { +function get_relationship(Individual $person1, Individual $person2, $maxlength = 4) { if ($person1 === $person2) { return false; } + $spouse_codes = array('M' => 'hus', 'F' => 'wif', 'U' => 'spo'); + $parent_codes = array('M' => 'fat', 'F' => 'mot', 'U' => 'par'); + $child_codes = array('M' => 'son', 'F' => 'dau', 'U' => 'chi'); + $sibling_codes = array('M' => 'bro', 'F' => 'sis', 'U' => 'sib'); + //-- current path nodes $p1nodes = array(); //-- ids visited @@ -354,15 +353,11 @@ function get_relationship(Individual $person1, Individual $person2, $followspous $node1['length']++; $node1['path'][] = $spouse; $node1['indi'] = $spouse; - $node1['relations'][] = 'parent'; + $node1['relations'][] = $parent_codes[$spouse->getSex()]; $p1nodes[] = $node1; if ($spouse === $person2) { - if ($path_to_find > 0) { - $path_to_find--; - } else { - $found = true; - $resnode = $node1; - } + $found = true; + $resnode = $node1; } else { $visited[$spouse->getXref()] = true; } @@ -374,15 +369,11 @@ function get_relationship(Individual $person1, Individual $person2, $followspous $node1['length']++; $node1['path'][] = $child; $node1['indi'] = $child; - $node1['relations'][] = 'sibling'; + $node1['relations'][] = $sibling_codes[$child->getSex()]; $p1nodes[] = $node1; if ($child === $person2) { - if ($path_to_find > 0) { - $path_to_find--; - } else { - $found = true; - $resnode = $node1; - } + $found = true; + $resnode = $node1; } else { $visited[$child->getXref()] = true; } @@ -392,25 +383,19 @@ function get_relationship(Individual $person1, Individual $person2, $followspous //-- check all spouses and children of this node foreach ($indi->getSpouseFamilies(WT_PRIV_HIDE) as $family) { $visited[$family->getXref()] = true; - if ($followspouse) { - foreach ($family->getSpouses(WT_PRIV_HIDE) as $spouse) { - if (!in_array($spouse->getXref(), $node1) || !isset($visited[$spouse->getXref()])) { - $node1 = $node; - $node1['length']++; - $node1['path'][] = $spouse; - $node1['indi'] = $spouse; - $node1['relations'][] = 'spouse'; - $p1nodes[] = $node1; - if ($spouse === $person2) { - if ($path_to_find > 0) { - $path_to_find--; - } else { - $found = true; - $resnode = $node1; - } - } else { - $visited[$spouse->getXref()] = true; - } + foreach ($family->getSpouses(WT_PRIV_HIDE) as $spouse) { + if (!in_array($spouse->getXref(), $node1) || !isset($visited[$spouse->getXref()])) { + $node1 = $node; + $node1['length']++; + $node1['path'][] = $spouse; + $node1['indi'] = $spouse; + $node1['relations'][] = $spouse_codes[$spouse->getSex()]; + $p1nodes[] = $node1; + if ($spouse === $person2) { + $found = true; + $resnode = $node1; + } else { + $visited[$spouse->getXref()] = true; } } } @@ -420,15 +405,11 @@ function get_relationship(Individual $person1, Individual $person2, $followspous $node1['length']++; $node1['path'][] = $child; $node1['indi'] = $child; - $node1['relations'][] = 'child'; + $node1['relations'][] = $child_codes[$child->getSex()]; $p1nodes[] = $node1; if ($child === $person2) { - if ($path_to_find > 0) { - $path_to_find--; - } else { - $found = true; - $resnode = $node1; - } + $found = true; + $resnode = $node1; } else { $visited[$child->getXref()] = true; } @@ -439,52 +420,6 @@ function get_relationship(Individual $person1, Individual $person2, $followspous unset($p1nodes[$shortest]); } - // Convert generic relationships into sex-specific ones. - foreach ($resnode['path'] as $n => $indi) { - switch ($resnode['relations'][$n]) { - case 'parent': - switch ($indi->getSex()) { - case 'M': - $resnode['relations'][$n] = 'father'; - break; - case 'F': - $resnode['relations'][$n] = 'mother'; - break; - } - break; - case 'child': - switch ($indi->getSex()) { - case 'M': - $resnode['relations'][$n] = 'son'; - break; - case 'F': - $resnode['relations'][$n] = 'daughter'; - break; - } - break; - case 'spouse': - switch ($indi->getSex()) { - case 'M': - $resnode['relations'][$n] = 'husband'; - break; - case 'F': - $resnode['relations'][$n] = 'wife'; - break; - } - break; - case 'sibling': - switch ($indi->getSex()) { - case 'M': - $resnode['relations'][$n] = 'brother'; - break; - case 'F': - $resnode['relations'][$n] = 'sister'; - break; - } - break; - } - } - return $resnode; } @@ -518,13 +453,11 @@ function get_relationship_name($nodes) { // This is very repetitive in English, but necessary in order to handle the // complexities of other languages. - // Make each relationship parts the same length, for simpler matching. - $combined_path = ''; - foreach ($path as $rel) { - $combined_path .= substr($rel, 0, 3); - } - - return get_relationship_name_from_path($combined_path, $person1, $person2); + return get_relationship_name_from_path( + implode('', array_slice($nodes['relations'], 1)), + $nodes['path'][0], + $nodes['path'][count($nodes['path']) - 1] + ); } /** diff --git a/relationship.php b/relationship.php index 4955770f90..8aed0f4445 100644 --- a/relationship.php +++ b/relationship.php @@ -20,35 +20,17 @@ namespace Fisharebest\Webtrees; * Defined in session.php * * @global Tree $WT_TREE - * @global integer $bwidth */ -global $WT_TREE, $bwidth; +global $WT_TREE; define('WT_SCRIPT_NAME', 'relationship.php'); require './includes/session.php'; -$controller = new PageController; - -$pid1 = Filter::get('pid1', WT_REGEX_XREF); -$pid2 = Filter::get('pid2', WT_REGEX_XREF); -$show_full = Filter::getInteger('show_full', 0, 1, $WT_TREE->getPreference('PEDIGREE_FULL_DETAILS')); -$path_to_find = Filter::getInteger('path_to_find'); -$followspouse = Filter::getBool('followspouse'); -$asc = Filter::getBool('asc'); - -$asc = $asc ? -1 : 1; -$Dbwidth = $bwidth; -if (!$show_full) { - $bwidth = Theme::theme()->parameter('compact-chart-box-x'); - $bheight = Theme::theme()->parameter('compact-chart-box-y'); - $Dbwidth = Theme::theme()->parameter('compact-chart-box-x'); -} - -$Dbheight = $bheight; -$Dbxspacing = 0; -$Dbyspacing = 0; -$Dbasexoffset = 0; -$Dbaseyoffset = 0; +$controller = new RelationshipController; +$pid1 = Filter::get('pid1', WT_REGEX_XREF); +$pid2 = Filter::get('pid2', WT_REGEX_XREF); +$show_full = Filter::getInteger('show_full', 0, 1, $WT_TREE->getPreference('PEDIGREE_FULL_DETAILS')); +$find_all = Filter::getInteger('find_all', 0, 1); $person1 = Individual::getInstance($pid1); $person2 = Individual::getInstance($pid2); @@ -57,355 +39,160 @@ $controller ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) ->addInlineJavascript('autocomplete();'); -if ($person1 && $person1->canShowName() && $person2 && $person2->canShowName()) { +if ($person1 && $person2) { $controller ->setPageTitle(I18N::translate(/* I18N: %s are individual’s names */ 'Relationships between %1$s and %2$s', $person1->getFullName(), $person2->getFullName())) ->PageHeader(); - $node = get_relationship($person1, $person2, $followspouse, 0, $path_to_find); - // If no blood relationship exists, look for relationship via marriage - if ($path_to_find == 0 && $node == false && $followspouse == false) { - $followspouse = true; - $node = get_relationship($person1, $person2, $followspouse, 0, $path_to_find); - } - $disp = true; + $paths = $controller->calculateRelationships($person1, $person2, $find_all); } else { $controller ->setPageTitle(I18N::translate('Relationships')) ->PageHeader(); - $node = false; - $disp = false; + $paths = array(); } ?> -<div id="relationship-page"> - <h2><?php echo $controller->getPageTitle(); ?></h2> - <form name="people" method="get" action="?"> - <input type="hidden" name="ged" value="<?php echo Filter::escapeHtml(WT_GEDCOM); ?>"> - <input type="hidden" name="path_to_find" value="0"> - <table class="list_table"> - <tr> - <td colspan="2" class="topbottombar center"> - <?php echo I18N::translate('Relationships'); ?> - </td> - <td colspan="2" class="topbottombar center"> - <?php echo I18N::translate('Options:'); ?> - </td> - </tr> - <tr> - <td class="descriptionbox"> - <?php echo I18N::translate('Individual 1'); ?> - </td> - <td class="optionbox vmiddle"> - <input tabindex="1" class="pedigree_form" data-autocomplete-type="INDI" type="text" name="pid1" id="pid1" size="3" value="<?php echo $pid1; ?>"> - <?php echo print_findindi_link('pid1'); ?> - </td> - <td class="descriptionbox"> - <?php echo I18N::translate('Show details'); ?> - </td> - <td class="optionbox vmiddle"> +<h2><?php echo $controller->getPageTitle(); ?></h2> +<form name="people" method="get" action="?"> + <input type="hidden" name="ged" value="<?php echo Filter::escapeHtml(WT_GEDCOM); ?>"> + <table class="list_table"> + <tr> + <td class="descriptionbox"> + <?php echo I18N::translate('Individual 1'); ?> + </td> + <td class="optionbox"> + <input class="pedigree_form" data-autocomplete-type="INDI" type="text" name="pid1" id="pid1" size="3" value="<?php echo $pid1; ?>"> + <?php echo print_findindi_link('pid1'); ?> + </td> + <td class="optionbox"> + <label> <?php echo two_state_checkbox('show_full', $show_full); ?> - </td> - </tr> - <tr> - <td class="descriptionbox"> - <?php echo I18N::translate('Individual 2'); ?> - </td> - <td class="optionbox vmiddle"> - <input tabindex="2" class="pedigree_form" data-autocomplete-type="INDI" type="text" name="pid2" id="pid2" size="3" value="<?php echo $pid2; ?>"> - <?php echo print_findindi_link('pid2'); ?> - </td> - <td class="descriptionbox"> - <?php echo I18N::translate('Show oldest top'); ?> - </td> - <td class="optionbox"> - <input tabindex="4" type="checkbox" name="asc" value="1" <?php echo $asc === -1 ? 'checked' : ''; ?>> - </td> - </tr> - <tr> - <td class="descriptionbox"> - <?php - if ($path_to_find > 0) { - echo I18N::translate('Show path'); - } - ?> - </td> - <td class="optionbox"> - <?php - for ($i = 0; $i < $path_to_find; ++$i) { - echo ' <a href="relationship.php?pid1=', $pid1, '&pid2=', $pid2, '&path_to_find=', $i, '&followspouse=', $followspouse, '&show_full=', $show_full, '&asc=', -$asc, '">', $i + 1, '</a>'; - } - ?> - </td> - <td class="descriptionbox"> - <?php echo I18N::translate('Check relationships by marriage'), help_link('CHECK_MARRIAGE_RELATIONS'); ?> - </td> - <td class="optionbox" id="followspousebox"> - <input tabindex="6" type="checkbox" name="followspouse" value="1" <?php echo $followspouse ? 'checked' : ''; ?> onclick="document.people.path_to_find.value='-1';" > - </td> - </tr> - <td class="topbottombar vmiddle center" colspan="2"> - <?php - if ($node) { - echo '<input type="submit" value="', I18N::translate('Find next path'), '" onclick="document.people.path_to_find.value=', $path_to_find + 1, ';">'; - echo help_link('next_path'); - } - ?> - </td> - <td class="topbottombar vmiddle center" colspan="2"> - <input tabindex="7" type="submit" value="<?php echo I18N::translate('View'); ?>"> - </td> - </tr> - </table> - </form> - + <?php echo I18N::translate('Show details'); ?> + </label> + </td> + <td class="optionbox vmiddle" rowspan="2"> + <input type="submit" value="<?php echo I18N::translate('View'); ?>"> + </td> + </tr> + <tr> + <td class="descriptionbox"> + <?php echo I18N::translate('Individual 2'); ?> + </td> + <td class="optionbox"> + <input class="pedigree_form" data-autocomplete-type="INDI" type="text" name="pid2" id="pid2" size="3" value="<?php echo $pid2; ?>"> + <?php echo print_findindi_link('pid2'); ?> + <br> + <a href="#" onclick="var x = jQuery('#pid1').val(); jQuery('#pid1').val(jQuery('#pid2').val()); jQuery('#pid2').val(x); return false;"><?php /* I18N: Reverse the order of two individuals */ echo I18N::translate('Swap individuals'); ?></a> + </td> + <td class="optionbox"> + <label> + <input type="radio" name="find_all" value="0" <?php echo $find_all ? '' : 'checked'; ?>> + <?php echo I18N::translate('Find the shortest relationships'); ?> + </label> + <br> + <label> + <input type="radio" name="find_all" value="1"<?php echo $find_all ? 'checked' : ''; ?>> + <?php echo I18N::translate('Find all possible relationships'); ?> + </label> + </td> + </tr> + </table> +</form> <?php -$maxyoffset = $Dbaseyoffset; if ($person1 && $person2) { - if (!$disp) { - echo '<div class="error">', I18N::translate('This information is private and cannot be shown.'), '</div>'; - } elseif (!$node) { - if ($path_to_find == 0) { - echo '<p class="error">', I18N::translate('No link between the two individuals could be found.'), '</p>'; - } else { - echo '<p class="error">', I18N::translate('No other link between the two individuals could be found.'), '</p>'; - } + if (I18N::direction() === 'ltr') { + $horizontal_arrow = '<br><i class="icon-rarrow"></i>'; } else { - if ($node) { - echo '<h3>', I18N::translate('Relationship: %s', get_relationship_name($node)), '</h3>'; + $horizontal_arrow = '<br><i class="icon-larrow"></i>'; + } + $up_arrow = ' <i class="icon-uarrow"></i>'; + $down_arrow = ' <i class="icon-darrow"></i>'; - // Use relative layout to position the person boxes. - echo '<div id="relationship_chart" style="position:relative;">'; + $num_paths = 0; + foreach ($paths as $path) { + // Extract the relationship names between pairs of individuals + $relationships = $controller->oldStyleRelationshipPath($path); + if (!$relationships) { + echo "<h3>private or error</h3>"; + continue; + } + echo '<h3>', I18N::translate('Relationship: %s', get_relationship_name_from_path(implode('', $relationships), $person1, $person2)), '</h3>'; + $num_paths++; - $yoffset = $Dbaseyoffset + 20; - $xoffset = $Dbasexoffset; - $colNum = 0; - $rowNum = 0; - $previous = ''; - $change_count = ''; // shift right on alternate change of direction - $xs = $Dbxspacing + 70; - $ys = $Dbyspacing + 50; - // step1 = tree depth calculation - $dmin = 0; - $dmax = 0; - $depth = 0; - foreach ($node['path'] as $index=>$person) { - if ($node['relations'][$index] === 'father' || $node['relations'][$index] === 'mother' || $node['relations'][$index] === 'parent') { - $depth++; - if ($depth > $dmax) { - $dmax = $depth; - } - if ($asc == 0) { - $asc = 1; // the first link is a parent link - } - } - if ($node['relations'][$index] === 'son' || $node['relations'][$index] === 'daughter' || $node['relations'][$index] === 'child') { - $depth--; - if ($depth < $dmin) { - $dmin = $depth; - } - if ($asc === 0) { - $asc = -1; // the first link is a child link - } - } - } - $depth = $dmax + $dmin; - // need more yoffset before the first box ? - if ($asc == 1) { - $yoffset -= $dmin * ($Dbheight + $ys); - } - if ($asc == -1) { - $yoffset += $dmax * ($Dbheight + $ys); - } - $rowNum = ($asc == -1) ? $depth : 0; - $maxxoffset = -1 * $Dbwidth - 20; - $maxyoffset = $yoffset; - // Left and right get reversed on RTL pages - if (I18N::direction() === 'ltr') { - $right_arrow = 'icon-rarrow'; - } else { - $right_arrow = 'icon-larrow'; - } - // Up and down get reversed, for the “oldest at top” option - if ($asc == 1) { - $up_arrow = 'icon-uarrow'; - $down_arrow = 'icon-darrow'; - } else { - $up_arrow = 'icon-darrow'; - $down_arrow = 'icon-uarrow'; - } - foreach ($node['path'] as $index=>$person) { - $linex = $xoffset; - $liney = $yoffset; - switch ($person->getSex()) { - case 'M': - $mfstyle = ''; - break; - case 'F': - $mfstyle = 'F'; - break; - default: - $mfstyle = 'NN'; - break; - } - switch ($node['relations'][$index]) { - case 'father': - case 'mother': - case 'parent': - $arrow_img = $down_arrow; - $line = Theme::theme()->parameter('image-vline'); - $liney += $Dbheight; - $linex += $Dbwidth / 2; - $lh = 54; - $lw = 3; - $lh = $ys; - $linex = $xoffset + $Dbwidth / 2; - // put the box up or down ? - $yoffset += $asc * ($Dbheight + $lh); - $rowNum += $asc; - if ($asc == 1) { - $liney = $yoffset - $lh; - } else { - $liney = $yoffset + $Dbheight; - } - // need to draw a joining line ? - if ($previous === 'child' && ($change_count++ % 2) === 0) { - $joinh = 3; - $joinw = $xs / 2 + 2; - $xoffset += $Dbwidth + $xs; - $colNum++; - //$rowNum is inherited from the box immediately to the left - $linex = $xoffset - $xs / 2; - if ($asc == -1) { - $liney = $yoffset + $Dbheight; - } else { - $liney = $yoffset - $lh; - } - $joinx = $xoffset - $xs; - $joiny = $liney - 2 - ($asc - 1) / 2 * $lh; - echo "<div id=\"joina", $index, "\" style=\"position:absolute; ", I18N::direction() === 'ltr' ? 'left' : 'right', ':', $joinx + $Dbxspacing, 'px; top:', $joiny + $Dbyspacing, "px;\" align=\"center\"><img src=\"", Theme::theme()->parameter('image-hline'), "\" align=\"left\" width=\"", $joinw, "\" height=\"", $joinh, "\" alt=\"\"></div>"; - $joinw = $xs / 2 + 2; - $joinx = $joinx + $xs / 2; - $joiny = $joiny + $asc * $lh; - echo "<div id=\"joinb", $index, "\" style=\"position:absolute; ", I18N::direction() === 'ltr' ? 'left' : 'right', ':', $joinx + $Dbxspacing, 'px; top:', $joiny + $Dbyspacing, "px;\" align=\"center\"><img src=\"", Theme::theme()->parameter('image-hline'), "\" align=\"left\" width=\"", $joinw, "\" height=\"", $joinh, "\" alt=\"\"></div>"; - } else { - $change_count = ''; - } - $previous = 'parent'; - break; - case 'brother': - case 'sister': - case 'sibling': - case 'husband': - case 'wife': - case 'spouse': - $arrow_img = $right_arrow; - $xoffset += $Dbwidth + $Dbxspacing + 70; - $colNum++; - //$rowNum is inherited from the box immediately to the left - $line = Theme::theme()->parameter('image-hline'); - $linex += $Dbwidth; - $liney += $Dbheight / 2; - $lh = 3; - $lw = 70; - $lw = $xs; - $linex = $xoffset - $lw; - $liney = $yoffset + $Dbheight / 4; - $previous = ''; + // Use a table/grid for layout. + $table = array(); + // Current position in the grid. + $x = 0; + $y = 0; + // Extent of the grid. + $min_y = 0; + $max_y = 0; + $max_x = 0; + // For each node in the path. + foreach ($path as $n => $xref) { + if ($n % 2 === 1) { + switch ($relationships[$n]) { + case 'hus': + case 'wif': + case 'spo': + case 'bro': + case 'sis': + case 'sib': + $table[$x+1][$y] = '<div style="background:url(' . Theme::theme()->parameter('image-hline') . ') repeat-x center; width: 65px; text-align: center"><span style="background: #fff;">' . get_relationship_name_from_path($relationships[$n], Individual::getInstance($path[$n - 1]), Individual::getInstance($path[$n + 1])) . $horizontal_arrow . '</span></div>'; + $x += 2; break; case 'son': - case 'daughter': - case 'child': - $arrow_img = $up_arrow; - $line = Theme::theme()->parameter('image-vline'); - $liney += $Dbheight; - $linex += $Dbwidth / 2; - $lh = 54; - $lw = 3; - $lh = $ys; - $linex = $xoffset + $Dbwidth / 2; - // put the box up or down ? - $yoffset -= $asc * ($Dbheight + $lh); - $rowNum -= $asc; - if ($asc == -1) { - $liney = $yoffset - $lh; + case 'dau': + case 'chi': + if ($n > 2 && preg_match('/fat|mot|par/', $relationships[$n-2])) { + $table[$x + 1][$y - 1] = '<div style="background:url(' . Theme::theme()->parameter('image-dline2') . '); width: 65px; height: 50px; padding-top: 15px;"><div style="text-align: center; background: #fff;">' . get_relationship_name_from_path($relationships[$n], Individual::getInstance($path[$n - 1]), Individual::getInstance($path[$n + 1])) . $down_arrow . '</div></div>'; + $x += 2; } else { - $liney = $yoffset + $Dbheight; + $table[$x][$y - 1] = '<div style="background:url(' . Theme::theme() + ->parameter('image-vline') . ') repeat-y center; height: 50px; padding-top: 15px;"><div style="text-align: center; background: #fff;">' . get_relationship_name_from_path($relationships[$n], Individual::getInstance($path[$n - 1]), Individual::getInstance($path[$n + 1])) . $down_arrow . '</div></div>'; } - // need to draw a joining line ? - if ($previous == 'parent' && ($change_count++ % 2) == 0) { - $joinh = 3; - $joinw = $xs / 2 + 2; - $xoffset += $Dbwidth + $xs; - $colNum++; - //$rowNum is inherited from the box immediately to the left - $linex = $xoffset - $xs / 2; - if ($asc == 1) { - $liney = $yoffset + $Dbheight; - } else { - $liney = $yoffset - ($lh + $Dbyspacing); - } - $joinx = $xoffset - $xs; - $joiny = $liney - 2 + ($asc + 1) / 2 * $lh; - echo '<div id="joina', $index, '" style="position:absolute; ', I18N::direction() === 'ltr' ? 'left' : 'right', ':', $joinx + $Dbxspacing, 'px; top:', $joiny + $Dbyspacing, 'px;" align="center"><img src="', Theme::theme()->parameter('image-hline'), '" align="left" width="', $joinw, '" height="', $joinh, '" alt=""></div>'; - $joinw = $xs / 2 + 2; - $joinx = $joinx + $xs / 2; - $joiny = $joiny - $asc * $lh; - echo '<div id="joinb', $index, '" style="position:absolute; ', I18N::direction() === 'ltr' ? 'left' : 'right', ':', $joinx + $Dbxspacing, 'px; top:', $joiny + $Dbyspacing, 'px;" align="center"><img src="', Theme::theme()->parameter('image-hline'), '" align="left" width="', $joinw, '" height="', $joinh, '" alt=""></div>'; + $y -= 2; + break; + case 'fat': + case 'mot': + case 'par': + if ($n > 2 && preg_match('/son|dau|chi/', $relationships[$n-2])) { + $table[$x + 1][$y + 1] = '<div style="background:url(' . Theme::theme()->parameter('image-dline') . '); width: 65px; height: 65px; padding-top: 15px;"><div style="text-align: center; background: #fff;">' . get_relationship_name_from_path($relationships[$n], Individual::getInstance($path[$n - 1]), Individual::getInstance($path[$n + 1])) . $up_arrow . '</div></div>'; + $x += 2; } else { - $change_count = ''; + $table[$x][$y + 1] = '<div style="background:url(' . Theme::theme() + ->parameter('image-vline') . ') repeat-y center; height: 50px; padding-top: 15px;"><div style="text-align: center; background: #fff;">' . get_relationship_name_from_path($relationships[$n], Individual::getInstance($path[$n - 1]), Individual::getInstance($path[$n + 1])) . $up_arrow . '</div></div>'; } - $previous = 'child'; + $y += 2; break; } - if ($yoffset > $maxyoffset) { - $maxyoffset = $yoffset; - } - $plinex = $linex; - $pxoffset = $xoffset; - - // Adjust all box positions for proper placement with respect to other page elements - $pyoffset = $yoffset - 2; - - if ($index > 0) { - if (I18N::direction() === 'rtl' && $line !== Theme::theme()->parameter('image-hline')) { - echo '<div id="line', $index, '" style="background:none; position:absolute; right:', $plinex + $Dbxspacing, 'px; top:', $liney + $Dbyspacing, 'px; width:', $lw + $lh * 2, 'px;" align="right">'; - echo '<img src="', $line, '" align="right" width="', $lw, '" height="', $lh, '" alt="">'; - echo '<br>'; - echo I18N::translate($node['relations'][$index]); - echo '<i class="', $arrow_img, '"></i>'; - } else { - echo '<div id="line', $index, '" style="background:none; position:absolute; ', I18N::direction() === 'ltr' ? 'left' : 'right', ':', $plinex + $Dbxspacing, 'px; top:', $liney + $Dbyspacing, 'px; width:', $lw + $lh * 2, 'px;" align="', $lh == 3 ? 'center' : 'left', '"><img src="', $line, '" align="left" width="', $lw, '" height="', $lh, '" alt="">'; - echo '<br>'; - echo '<i class="', $arrow_img, '"></i>'; - if ($lh == 3) { - echo '<br>'; // note: $lh==3 means horiz arrow - } - echo I18N::translate($node['relations'][$index]); - } - echo '</div>'; + $max_x = max($max_x, $x); + $min_y = min($min_y, $y); + $max_y = max($max_y, $y); + } else { + $individual = Individual::getInstance($xref); + ob_start(); + print_pedigree_person($individual); + $table[$x][$y] = ob_get_clean(); + } + } + echo '<table style="border-collapse: collapse; margin: 20px 50px;">'; + for ($y = $max_y; $y >= $min_y; --$y) { + echo '<tr>'; + for ($x = 0; $x <= $max_x; ++$x) { + echo '<td style="padding: 0;">'; + if (isset($table[$x][$y])) { + echo $table[$x][$y]; } - - // Determine the z-index for this box - $zIndex = 200 - ($colNum * $depth + $rowNum); - - echo '<div style="position:absolute; ', I18N::direction() === 'ltr' ? 'left' : 'right', ':', $pxoffset, 'px; top:', $pyoffset, 'px; width:', $Dbwidth, 'px; height:', $Dbheight, 'px; z-index:', $zIndex, ';">'; - print_pedigree_person($person); - echo '</div>'; + echo '</td>'; } + echo '</tr>'; } - echo '</div>'; // close#relationship_chart + echo '</table>'; } -} -echo '</div>'; // close #relationshippage -// The contents of <div id="relationship_chart"> use relative positions. -// Need to expand the div to include the children, or we'll overlap the footer. -// $maxyoffset is the top edge of the lowest box. -$controller->addInlineJavascript(' - relationship_chart_div = document.getElementById("relationship_chart"); - if (relationship_chart_div) { - relationship_chart_div.style.height = "'.($maxyoffset + $Dbheight + 20) . 'px"; - relationship_chart_div.style.width = "100%"; - }' -); + if (!$num_paths) { + echo '<p>', I18N::translate('No link between the two individuals could be found.'), '</p>'; + } +}
\ No newline at end of file diff --git a/themes/clouds/css-1.7.0/style.css b/themes/clouds/css-1.7.0/style.css index ce32745a0e..2e1c9e840a 100644 --- a/themes/clouds/css-1.7.0/style.css +++ b/themes/clouds/css-1.7.0/style.css @@ -3502,15 +3502,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 6px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/themes/colors/css-1.7.0/style.css b/themes/colors/css-1.7.0/style.css index 3971774919..55409446fa 100644 --- a/themes/colors/css-1.7.0/style.css +++ b/themes/colors/css-1.7.0/style.css @@ -3498,15 +3498,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 6px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/themes/fab/css-1.7.0/style.css b/themes/fab/css-1.7.0/style.css index 05da61b6d4..45a042d997 100644 --- a/themes/fab/css-1.7.0/style.css +++ b/themes/fab/css-1.7.0/style.css @@ -3426,15 +3426,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 6px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/themes/minimal/css-1.7.0/style.css b/themes/minimal/css-1.7.0/style.css index 7674231a5c..36596e5d47 100644 --- a/themes/minimal/css-1.7.0/style.css +++ b/themes/minimal/css-1.7.0/style.css @@ -3431,15 +3431,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 6px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/themes/webtrees/css-1.7.0/style.css b/themes/webtrees/css-1.7.0/style.css index bfa3469869..5718d6f465 100644 --- a/themes/webtrees/css-1.7.0/style.css +++ b/themes/webtrees/css-1.7.0/style.css @@ -3385,15 +3385,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 6px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/themes/xenea/css-1.7.0/style.css b/themes/xenea/css-1.7.0/style.css index 1eb5d99335..83e7aef15e 100644 --- a/themes/xenea/css-1.7.0/style.css +++ b/themes/xenea/css-1.7.0/style.css @@ -3396,15 +3396,6 @@ table.table-census-assistant th { position: absolute; } -/*-- Relationship ---- */ -#relationship-page h3 { - margin: 20px 0 0 20px; -} - -#relationship_chart { - margin: 0 20px; -} - /*-- timeline --*/ #timeline_chart { position: relative; diff --git a/vendor/autoload.php b/vendor/autoload.php index 48f332e5fe..8910960f3c 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12::getLoader(); +return ComposerAutoloaderInitbc7ef3c4f9a7f3ece04ccd8101dc6f40::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index e8a8fb4bd3..2024efdb3c 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir); return array( 'Datamatrix' => $vendorDir . '/tecnick.com/tcpdf/include/barcodes/datamatrix.php', + 'Fisharebest\\Algorithm\\Dijkstra' => $vendorDir . '/fisharebest/algorithm/src/Dijkstra.php', 'Fisharebest\\ExtCalendar\\AbstractCalendar' => $vendorDir . '/fisharebest/ext-calendar/src/AbstractCalendar.php', 'Fisharebest\\ExtCalendar\\ArabicCalendar' => $vendorDir . '/fisharebest/ext-calendar/src/ArabicCalendar.php', 'Fisharebest\\ExtCalendar\\CalendarInterface' => $vendorDir . '/fisharebest/ext-calendar/src/CalendarInterface.php', @@ -83,6 +84,7 @@ return array( 'Fisharebest\\Webtrees\\PageController' => $baseDir . '/app/Controller/PageController.php', 'Fisharebest\\Webtrees\\PedigreeController' => $baseDir . '/app/Controller/PedigreeController.php', 'Fisharebest\\Webtrees\\Place' => $baseDir . '/app/Place.php', + 'Fisharebest\\Webtrees\\RelationshipController' => $baseDir . '/app/Controller/RelationshipController.php', 'Fisharebest\\Webtrees\\ReportBase' => $baseDir . '/app/Report/ReportBase.php', 'Fisharebest\\Webtrees\\ReportBaseCell' => $baseDir . '/app/Report/ReportBaseCell.php', 'Fisharebest\\Webtrees\\ReportBaseElement' => $baseDir . '/app/Report/ReportBaseElement.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 1280ac6abc..991a431092 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -9,4 +9,5 @@ return array( 'Rhumsaa\\Uuid\\' => array($vendorDir . '/rhumsaa/uuid/src'), 'Fisharebest\\Webtrees\\' => array($baseDir . '/app', $baseDir . '/modules_v3'), 'Fisharebest\\ExtCalendar\\' => array($vendorDir . '/fisharebest/ext-calendar/src'), + 'Fisharebest\\Algorithm\\' => array($vendorDir . '/fisharebest/algorithm/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 42795084cc..6c352fe4b9 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12 +class ComposerAutoloaderInitbc7ef3c4f9a7f3ece04ccd8101dc6f40 { private static $loader; @@ -19,9 +19,9 @@ class ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitbc7ef3c4f9a7f3ece04ccd8101dc6f40', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitbc7ef3c4f9a7f3ece04ccd8101dc6f40', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; array_push($includePaths, get_include_path()); @@ -46,14 +46,14 @@ class ComposerAutoloaderInit207af526399948cc5e2e445108bc9b12 $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequire207af526399948cc5e2e445108bc9b12($file); + composerRequirebc7ef3c4f9a7f3ece04ccd8101dc6f40($file); } return $loader; } } -function composerRequire207af526399948cc5e2e445108bc9b12($file) +function composerRequirebc7ef3c4f9a7f3ece04ccd8101dc6f40($file) { require $file; } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 283c14fae2..91834c7d34 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -486,5 +486,53 @@ "ZF1", "framework" ] + }, + { + "name": "fisharebest/algorithm", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/fisharebest/algorithm.git", + "reference": "ddfbf31e7b1ef49f227409a41261770ed3fb467b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fisharebest/algorithm/zipball/ddfbf31e7b1ef49f227409a41261770ed3fb467b", + "reference": "ddfbf31e7b1ef49f227409a41261770ed3fb467b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "*", + "satooshi/php-coveralls": "*" + }, + "time": "2015-02-15 21:38:53", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Fisharebest\\Algorithm\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0+" + ], + "authors": [ + { + "name": "Greg Roach", + "email": "greg@subaqua.co.uk", + "role": "Developer" + } + ], + "description": "Implementation of standard algorithms in PHP.", + "homepage": "https://github.com/fisharebest/algorithm", + "keywords": [ + "Algorithm", + "dijkstra" + ] } ] |
