\n" +
@@ -1277,7 +1279,7 @@ class MergeNode {
this.isLater = false;
let survivorGx = survivorMergeNode ? survivorMergeNode.gedcomx : null;
// GedcomX within 24 hours of the person's creation, or at the initial time of merge.
- this.gedcomx = survivorGx ? copySurvivorGx(survivorGx) : getInitialGedcomx(personId);
+ this.gedcomx = survivorGx ? copySurvivorGedcomx(survivorGx) : getInitialGedcomx(personId);
// Flag for whether only changes in 2012 or within 24 hours of creation have been made to this person's GedcomX so far
this.isInitialIdentity = true;
@@ -1337,6 +1339,20 @@ class MergeNode {
// ===============
class PersonDisplay {
constructor(person, nameClass, status, coupleRelationship, shouldIncludeId) {
+ // To show all names for each person and relative, do this.name = combineNames();
+ // function combineNames() {
+ // let names = [];
+ // for (let name of getList(person, "names")) {
+ // let nameForm = getFirst(getList(name, "nameForms"));
+ // let fullText = getProperty(nameForm, "fullText");
+ // let nameHtml = "" + encode(fullText ? fullText : "") + "";
+ // if (!names.includes(nameHtml)) {
+ // names.push(nameHtml);
+ // }
+ // }
+ // return names.join(" ");
+ // }
+
this.person = person;
this.name = "" + encode(getPersonName(person)) + "";
this.coupleRelationship = coupleRelationship;
@@ -2345,6 +2361,7 @@ function updateTabsHtml() {
updateMergeHierarchyHtml();
updateFlatViewHtml(flatGrouper);
updateFlatViewHtml(sourceGrouper);
+ updateSplitViewHtml();
}
function updateFlatViewHtml(grouper) {
@@ -2379,10 +2396,10 @@ function buildPersonaRows() {
let personaRows = [];
for (let sourceInfo of Object.values(sourceMap)) {
- if (sourceInfo.personaArk && sourceInfo.gx) {
- let personaId = findPersonInGx(sourceInfo.gx, shortenPersonArk(sourceInfo.personaArk)).id;
+ if (sourceInfo.personaArk && sourceInfo.gedcomx) {
+ let personaId = findPersonInGx(sourceInfo.gedcomx, shortenPersonArk(sourceInfo.personaArk)).id;
if (!personaIds.has(personaId)) {
- personaRows.push(new PersonRow(null, personaId, sourceInfo.gx, 0, 0, false, null, sourceInfo));
+ personaRows.push(new PersonRow(null, personaId, sourceInfo.gedcomx, 0, 0, false, null, sourceInfo));
personaIds.add(personaId);
}
}
@@ -2417,12 +2434,28 @@ const TYPE_SOURCE = "Sources"; // attached source
// One element of information from the original GedcomX that is either kept on the old person, or copied or moved out to the new person.
class Element {
constructor(id, item, type, direction, famId) {
- this.id = id;
+ this.id = id; // index in split.elements[]
this.item = item; // name, gender, fact, field, relationship or source [or eventually ordinance] being decided upon.
this.type = type; // Type of item (see TYPE_* above)
this.direction = direction; // Direction for this piece of information: DIR_KEEP/COPY/MOVE
- this.famId = famId; // optional value identifying which family (i.e., spouseId) this relationship element is part of.
- // (to help group children by spouse).
+ this.famId = famId; // optional value identifying which family (i.e., spouseId) this relationship element is part of, to group children by spouse.
+ this.canExpand = false;
+ // Flag for whether following elements of the same type AND with an 'elementSource' should be displayed.
+ this.isExpanded = false;
+ // Where this came from, if it isn't the main current person.
+ this.elementSource = null;
+ // Flag for whether this element is 'selected', so that it will show even when collapsed.
+ // This also means it will be kept on the resulting person(s), even though 'elementSource' would otherwise cause it to be ignored.
+ this.isSelected = false;
+ }
+
+ isVisible() {
+ return !this.elementSource || this.isSelected;
+ }
+
+ // Tell whether this element is an "extra" value that can be hidden.
+ isExtra() {
+ return !!this.elementSource;
}
}
@@ -2441,12 +2474,23 @@ class Split {
initElements(gedcomx, personId) {
function addElement(item, type, famId) {
- elements.push(new Element(elementIndex++, item, type, DIR_KEEP, famId))
+ let element = new Element(elementIndex++, item, type, DIR_KEEP, famId);
+ if (item.elementSource) {
+ element.elementSource = item.elementSource;
+ delete item["elementSource"];
+ }
+ elements.push(element);
+ return element;
}
- function addElements(list, type) {
+ function addElements(list, type, shouldSetCanExpand) {
if (list) {
+ let isFirst = true;
for (let item of list) {
- addElement(item, type);
+ let element = addElement(item, type);
+ if (isFirst && shouldSetCanExpand) {
+ element.canExpand = true;
+ }
+ isFirst = false;
}
}
}
@@ -2489,7 +2533,6 @@ class Split {
}
}
}
-
for (let parentRel of parentRelationships) {
addElement(parentRel, TYPE_PARENTS);
}
@@ -2503,21 +2546,123 @@ class Split {
}
}
}
-
+ function populateExtraNamesAndFacts() {
+ // Tell whether the given newName already exists in names[] (i.e., if they have the same full text on the first name form)
+ function alreadyHasName(names, newName) {
+ function getFullText(name) {
+ let nameForm = getFirst(getList(name, "nameForms"));
+ let fullText = getProperty(nameForm, "fullText");
+ return fullText ? fullText : "";
+ }
+ if (names) {
+ let targetText = getFullText(newName);
+ if (!isEmpty(targetText)) {
+ for (let name of names) {
+ let fullText = getFullText(name);
+ if (targetText === fullText) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ function alreadyHasFact(facts, newFact) {
+ function getFactString(fact) {
+ return (fact.type ? extractType(fact.type).replaceAll(/ /g, "") : "") + ": " +
+ (fact.date && fact.date.original ? fact.date.original.trim().replaceAll(/^0/g, "") : "") + "; " +
+ (fact.place && fact.place.original ? fact.place.original.trim().replaceAll(/, United States$/g, "") : "") + "; " +
+ (fact.value && fact.value.text ? fact.value.text : "");
+ }
+ if (facts) {
+ let newFactString = getFactString(newFact);
+ for (let fact of facts) {
+ let factString = getFactString(fact);
+ if (factString === newFactString) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // -- addExtraNamesAndFacts()
+ for (let i = allEntries.length - 1; i >= 0; i--) {
+ let entry = allEntries[i];
+ let changeInfo = entry.changeInfo[0];
+ let operation = extractType(getProperty(changeInfo, "operation"));
+ let objectType = extractType(getProperty(changeInfo, "objectType"));
+ let objectModifier = extractType(getProperty(changeInfo, "objectModifier"));
+ if (objectModifier === "Person" && objectType !== "NotAMatch" && operation !== "Delete") {
+ let resultingId = getProperty(changeInfo, "resulting.resourceId");
+ let entryPerson = findPersonByLocalId(entry, resultingId);
+ let combo = operation + "-" + ((entryPerson.hasOwnProperty("facts") && entryPerson.facts.length === 1) ? "(Fact)" : objectType);
+ if (combo === "Create-BirthName" || combo === "Update-BirthName") {
+ if (!alreadyHasName(person.names, entryPerson.names[0])) {
+ let nameCopy = copyObject(entryPerson.names[0]);
+ nameCopy.elementSource = "From person: " + getPersonId(entryPerson);
+ extraNames.push(nameCopy);
+ }
+ }
+ else if (combo === "Create-(Fact)") {
+ if (!alreadyHasFact(allFacts, entryPerson.facts[0])) {
+ let factCopy = copyObject(entryPerson.facts[0]);
+ factCopy.elementSource = "From person: " + getPersonId(entryPerson);
+ allFacts.push(factCopy);
+ }
+ }
+ }
+ }
+ let personaIds = [];
+ for (let sourceInfo of Object.values(sourceMap)) {
+ if (sourceInfo.personaArk && sourceInfo.gedcomx) {
+ let persona = findPersonInGx(sourceInfo.gedcomx, shortenPersonArk(sourceInfo.personaArk));
+ if (persona && !personaIds.includes(persona.id) && persona.facts) {
+ for (let fact of persona.facts) {
+ if (!alreadyHasFact(allFacts, fact)) {
+ let factCopy = copyObject(fact);
+ factCopy.elementSource = "From source: " + sourceInfo.collectionName;
+ allFacts.push(factCopy);
+ }
+ }
+ personaIds.push(persona.id);
+ }
+ }
+ }
+ }
+ // initElements()...
let elementIndex = 0;
let elements = [];
let person = gedcomx.persons[0];
- addElements(person.names, TYPE_NAME);
+ let extraNames = [];
+ let allFacts = copyObject(person.facts);
+ populateExtraNamesAndFacts();
+ fixEventOrder({"facts" : allFacts});
+ addElements(person.names, TYPE_NAME, extraNames.length > 0);
+ addElements(extraNames, TYPE_NAME);
addElement(person.gender, TYPE_GENDER);
- addElements(person.facts, TYPE_FACT);
- addRelationshipElements(gedcomx);
+ addElements(allFacts, TYPE_FACT, allFacts.length > (person.facts ? person.facts.length : 0));
+ addRelationshipElements(gedcomx); // future: find other relationships that were removed along the way.
addElements(person.sources, TYPE_SOURCE);
return elements;
}
}
function moveElement(direction, elementId) {
- split.elements[elementId].direction = direction;
+ let element = split.elements[elementId];
+ element.direction = direction;
+ if (element.direction !== DIR_KEEP && element.isExtra() && !element.isSelected) {
+ element.isSelected = true;
+ }
+ updateSplitViewHtml();
+}
+
+function toggleSplitExpanded(elementIndex) {
+ split.elements[elementIndex].isExpanded = !split.elements[elementIndex].isExpanded;
+ updateSplitViewHtml();
+}
+
+function toggleElement(elementId) {
+ split.elements[elementId].isSelected = !split.elements[elementId].isSelected;
updateSplitViewHtml();
}
@@ -2532,47 +2677,57 @@ function getSplitViewHtml() {
(isActive ? "onclick='moveElement(\"" + direction + "\", " + element.id + ")'" : "disabled")
+ ">" + encode(label) + "";
}
-
+ function getHeadingHtml(element) {
+ let headingClass = (element.type === TYPE_CHILD && prevElement.type === TYPE_SPOUSE) ? "split-children" : "split-heading";
+ let tdHeading = "
";
+ let buttonHtml = "";
+ if (element.canExpand) {
+ if (!prevElement || element.type !== prevElement.type) {
+ // For "Names" and "Facts", add an expand/collapse button after the label
+ isExpanded = element.isExpanded;
+ buttonHtml = "";
+ }
+ } else {
+ isExpanded = false;
+ }
+ return "
\n";
html += "";
let prevElement = null;
- let infoClass = "identity-gx";
+ let isExpanded = false;
+
for (let element of split.elements) {
if (element.status === DELETED_STATUS || element.status === MERGE_DELETED_STATUS) {
continue; // skip elements that have been deleted. (Perhaps we eventually make these available to "reclaim" when splitting out a person)
}
- if (!prevElement || element.type !== prevElement.type) {
- let headingClass = (element.type === TYPE_CHILD && prevElement.type === TYPE_SPOUSE) ? "split-children" : "split-heading";
- let tdHeading = "