Skip to content

Commit

Permalink
Fixes #56: Fix name mismatch
Browse files Browse the repository at this point in the history
  • Loading branch information
magicsunday committed Apr 2, 2024
1 parent d8c2390 commit 4f59846
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 29 deletions.
2 changes: 1 addition & 1 deletion resources/js/descendants-chart.min.js

Large diffs are not rendered by default.

23 changes: 13 additions & 10 deletions resources/js/modules/lib/tree/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,14 @@ export default class Name
this.addNameElements(
text,
(datum) => {
const nameGroups = this.createNamesData(datum);
const [first, ...last] = this.createNamesData(datum);

// Merge the firstname and lastname groups, as we display the whole name in one line
const combined = [].concat(first, typeof last[0] !== "undefined" ? last[0] : []);

return this.truncateNamesData(
text,
// Merge the firstname and lastname groups together,
// as we display the whole name in one line
[
...nameGroups[0],
...nameGroups[1],
],
combined,
this.getAvailableWidth(datum)
)
}
Expand Down Expand Up @@ -276,13 +274,16 @@ export default class Name
let lastnames = {};
let minPosFirstnames = Number.MAX_SAFE_INTEGER;
let minPosLastnames = Number.MAX_SAFE_INTEGER;
let offset = 0;

// Iterate over the individual name components and determine their position in the overall
// name and insert the component at the corresponding position in the result object.
for (let i in datum.data.data.firstNames) {
const pos = datum.data.data.name.indexOf(datum.data.data.firstNames[i]);
const pos = datum.data.data.name.indexOf(datum.data.data.firstNames[i], offset);

if (pos !== -1) {
offset = pos;

if (pos < minPosFirstnames) {
minPosFirstnames = pos;
}
Expand All @@ -299,9 +300,11 @@ export default class Name
names[minPosFirstnames] = Object.values(firstnames);

for (let i in datum.data.data.lastNames) {
const pos = datum.data.data.name.indexOf(datum.data.data.lastNames[i]);
const pos = datum.data.data.name.indexOf(datum.data.data.lastNames[i], offset);

if (pos !== -1) {
offset = pos;

if (pos < minPosLastnames) {
minPosLastnames = pos;
}
Expand All @@ -317,7 +320,7 @@ export default class Name

names[minPosLastnames] = Object.values(lastnames);

// Extract the values (keys doesn't matter anymore)
// Extract the values (keys don't matter anymore)
return Object.values(names);
}

Expand Down
77 changes: 59 additions & 18 deletions src/Processor/NameProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace MagicSunday\Webtrees\DescendantsChart\Processor;

use DOMDocument;
use DOMNode;
use DOMXPath;
use Fisharebest\Webtrees\Individual;

Expand All @@ -20,7 +21,7 @@
*
* @author Rico Sonntag <[email protected]>
* @license https://opensource.org/licenses/GPL-3.0 GNU General Public License v3.0
* @link https://github.com/magicsunday/webtrees-module-base/
* @link https://github.com/magicsunday/webtrees-descendants-chart/
*/
class NameProcessor
{
Expand All @@ -34,6 +35,17 @@ class NameProcessor
*/
private const FULL_NAME = 'full';

/**
* The XPath identifier to extract the first name parts (including the prefix).
*/
private const XPATH_FIRST_NAMES
= './/text()[count(.|(//span[@class="SURN"]/text() | //span[@class="SURN"]/following::text()))!=count((//span[@class="SURN"]/text() | //span[@class="SURN"]/following::text()))]';

/**
* The XPath identifier to extract the last name parts (surname + surname suffix).
*/
private const XPATH_LAST_NAMES = '//span[@class="NAME"]//span[@class="SURN"]/text()|//span[@class="SURN"]/following::text()';

/**
* The XPath identifier to extract the starred name part.
*/
Expand Down Expand Up @@ -97,7 +109,7 @@ private function getDomXPathInstance(string $input): DOMXPath
/**
* Extracts the primary name from the individual.
*
* @param Individual|null $spouse
* @param null|Individual $spouse
* @param bool $useMarriedName TRUE to return the married name instead of the primary one
*
* @return array<string, string>
Expand Down Expand Up @@ -164,36 +176,65 @@ private function replacePlaceholders(string $value): string
);
}

/**
* Returns the full name of the individual without formatting of the individual parts of the name.
* All placeholders were removed as we do not need them in this module.
*
* @return string
*/
public function getFullName(): string
{
// The name of the person without formatting of the individual parts of the name.
// Remove placeholders as we do not need them in this module
return $this->replacePlaceholders($this->primaryName[self::FULL_NAME_WITH_PLACEHOLDERS]);
}

/**
* Splits a name into an array, removing all name placeholders.
*
* @param string $name
* @param string[] $names
*
* @return string[]
*/
private function splitAndCleanName(string $name): array
private function splitAndCleanName(array $names): array
{
$values = [[]];

foreach ($names as $name) {
$values[] = explode(' ', $name);
}

// Remove empty values and reindex array
return array_values(
array_filter(
explode(
' ',
$this->replacePlaceholders($name)
)
array_merge(...$values)
)
);
}

/**
* Returns the full name of the individual without formatting of the individual parts of the name.
* All placeholders were removed as we do not need them in this module.
* Returns all name parts by given identifier.
*
* @return string
* @param string $expression The XPath expression to execute
*
* @return string[]
*/
public function getFullName(): string
private function getNamesByIdentifier(string $expression): array
{
// The name of the person without formatting of the individual parts of the name.
// Remove placeholders as we do not need them in this module
return $this->replacePlaceholders($this->primaryName[self::FULL_NAME_WITH_PLACEHOLDERS]);
$nodeList = $this->xPath->query($expression);
$names = [];

if ($nodeList !== false) {
/** @var DOMNode $node */
foreach ($nodeList as $node) {
$names[] = $node->nodeValue ?? '';
}
}

// Remove all leading/trailing whitespace characters
$names = array_map('trim', $names);

return $this->splitAndCleanName($names);
}

/**
Expand All @@ -203,7 +244,7 @@ public function getFullName(): string
*/
public function getFirstNames(): array
{
return $this->splitAndCleanName($this->primaryName['givn']);
return $this->getNamesByIdentifier(self::XPATH_FIRST_NAMES);
}

/**
Expand All @@ -213,7 +254,7 @@ public function getFirstNames(): array
*/
public function getLastNames(): array
{
return $this->splitAndCleanName($this->primaryName['surn']);
return $this->getNamesByIdentifier(self::XPATH_LAST_NAMES);
}

/**
Expand Down Expand Up @@ -247,7 +288,7 @@ public function getAlternateName(Individual $individual): string
$individual->canShowName()
&& ($individual->getPrimaryName() !== $individual->getSecondaryName())
) {
$allNames = $individual->getAllNames();
$allNames = $individual->getAllNames();
$alternativeName = $allNames[$individual->getSecondaryName()][self::FULL_NAME_WITH_PLACEHOLDERS];

return $this->replacePlaceholders($alternativeName);
Expand Down

0 comments on commit 4f59846

Please sign in to comment.