OCR review UX: person cards, apply preview, Advanced
OCR: person cards clarify scan vs wiki page vs team update
Line 1,358: Line 1,358:
var val = (fact.value || '').trim();
var val = (fact.value || '').trim();
var label = (fact.label || '').toLowerCase();
var label = (fact.label || '').toLowerCase();
if (fact.already_on_page && (field === 'ipw_ge' || field === 'teams')) {
return 'Team already on their profile (' + (val || fact.existing_value || 'same') + ') — no change';
}
if (fact.already_on_page) {
if (fact.already_on_page) {
return (fact.label || 'Already on page') + ' — skipped';
return (fact.label || 'Already on page') + ' — skipped';
}
}
if (field === 'ipw_ge') {
if (field === 'ipw_ge') {
return 'Team: set IPW ' + val;
return 'Set their Team (IPW) to ' + val;
}
}
if (field === 'teams') {
if (field === 'teams') {
return 'Team: add ' + val + ' to teams';
return 'Add ' + val + ' to their Teams list';
}
}
if (field === 'asn') {
if (field === 'asn') {
return 'ASN: ' + val;
return 'Set ASN to ' + val;
}
}
if (field === 'rank_final') {
if (field === 'rank_final') {
return 'Rank: ' + val;
return 'Set rank to ' + val;
}
}
if (field === 'specialty') {
if (field === 'specialty') {
return 'Role: ' + val;
return 'Set specialty/role to ' + val;
}
}
if (field === 'class_number') {
if (field === 'class_number') {
return 'Class: ' + val;
return 'Set class to ' + val;
}
}
if (fact.kind === 'bio') {
if (fact.kind === 'bio') {
return 'Biography: ' + (val.length > 80 ? val.slice(0, 80) + '…' : val);
return 'Add to biography: ' + (val.length > 80 ? val.slice(0, 80) + '…' : val);
}
}
if (fact.kind === 'note') {
if (fact.kind === 'note') {
Line 1,396: Line 1,399:
}
}


function personMetaBits(items) {
function personMetaFromItems(items) {
var bits = [];
var rank = '';
var role = '';
var asn = '';
var team = '';
items.forEach(function (f) {
items.forEach(function (f) {
if (f.field === 'asn' && f.value && bits.indexOf('ASN ' + f.value) < 0) {
if (f.field === 'rank_final' && f.value && !rank) {
bits.push('ASN ' + f.value);
rank = f.value;
}
}
if (f.field === 'rank_final' && f.value && bits.indexOf(f.value) < 0) {
if (f.field === 'specialty' && f.value && !role) {
bits.push(f.value);
role = f.value;
}
}
if (f.field === 'specialty' && f.value && bits.indexOf(f.value) < 0) {
if (f.field === 'asn' && f.value && !asn) {
bits.push(f.value);
asn = f.value;
}
}
if ((f.field === 'ipw_ge' || f.field === 'teams') && f.value) {
if ((f.field === 'ipw_ge' || f.field === 'teams') && f.value && !team) {
var t = f.value.indexOf('IPW') === 0 ? f.value : ('IPW ' + f.value);
team = f.value.indexOf('IPW') === 0 ? f.value : ('IPW ' + f.value);
if (bits.indexOf(t) < 0) {
bits.push(t);
}
}
}
});
});
return bits;
return { rank: rank, role: role, asn: asn, team: team };
}
}


Line 1,434: Line 1,437:
function isWritableFact(fact) {
function isWritableFact(fact) {
return fact.kind === 'field' || fact.kind === 'bio';
return fact.kind === 'field' || fact.kind === 'bio';
}
/** Team membership is the main action on multi-person roster docs. */
function isPrimaryTeamFact(fact) {
return fact.field === 'ipw_ge' || fact.field === 'teams';
}
function profileUpdateSentence(fact) {
if (!fact || !isPrimaryTeamFact(fact)) {
return changeLineForFact(fact);
}
var val = (fact.value || '').trim();
if (fact.already_on_page) {
return 'Their profile already lists this team — nothing to write.';
}
if (fact.field === 'teams') {
return 'On their soldier page, add ' + val + ' under Teams (they already have a different primary team).';
}
return 'On their soldier page, set Team to IPW ' + val + '.';
}
}


Line 1,476: Line 1,498:
opts = opts || {};
opts = opts || {};
var writable = isWritableFact(fact) && !fact.already_on_page;
var writable = isWritableFact(fact) && !fact.already_on_page;
var forceSelected = opts.forceSelected;
var selected = writable && (forceSelected === undefined ? !!fact.selected : !!forceSelected);
var $row = $('<div>', {
var $row = $('<div>', {
'class': 'ocr-fact-row' +
'class': 'ocr-fact-row' +
(fact.already_on_page ? ' ocr-fact-already' : '') +
(fact.already_on_page ? ' ocr-fact-already' : '') +
(writable ? ' ocr-fact-writable' : ' ocr-fact-note') +
(writable ? ' ocr-fact-writable' : ' ocr-fact-note') +
(isPrimaryTeamFact(fact) ? ' ocr-fact-primary' : ' ocr-fact-secondary') +
(fact.kind === 'note' ? ' ocr-fact-is-note' : ''),
(fact.kind === 'note' ? ' ocr-fact-is-note' : ''),
'data-id': fact.id,
'data-id': fact.id,
Line 1,488: Line 1,513:
var $check = $('<input>', {
var $check = $('<input>', {
type: 'checkbox',
type: 'checkbox',
checked: !!fact.selected && writable,
checked: selected,
disabled: !writable
disabled: !writable
});
});
var $line = $('<span>', { 'class': 'ocr-change-line' }).text(changeLineForFact(fact));
var $line = $('<span>', { 'class': 'ocr-change-line' }).text(
opts.plainSentence ? profileUpdateSentence(fact) : changeLineForFact(fact)
);
var $val = $('<input>', {
var $val = $('<input>', {
type: 'text',
type: 'text',
Line 1,503: Line 1,530:
});
});
var $details = $('<details>', { 'class': 'ocr-fact-details' });
var $details = $('<details>', { 'class': 'ocr-fact-details' });
$details.append($('<summary>').text('Edit'));
$details.append($('<summary>').text('Edit value'));
$details.append($('<label>').text('Value ').append($val));
$details.append($('<label>').text('Value ').append($val));
if (!opts.hideTargetVisible) {
var $tgtVis = $('<input>', {
type: 'text',
'class': 'ocr-fact-target-vis',
value: fact.target_title || job.bound_title || '',
placeholder: 'Soldier page title'
});
if (job.bound_title && !isInbox) {
$tgtVis.prop('readonly', true);
}
$tgtVis.on('input change', function () {
$tgt.val($.trim($tgtVis.val() || ''));
});
$details.append($('<label>').text('Page ').append($tgtVis));
}
$details.append($('<span>', { 'class': 'ocr-fact-meta' }).text(
$details.append($('<span>', { 'class': 'ocr-fact-meta' }).text(
(fact.kind || '') + ' · conf ' + (fact.confidence || 0) + '%'
'field ' + (fact.field || fact.kind || '') + ' · conf ' + (fact.confidence || 0) + '%'
));
));
if (writable || fact.already_on_page) {
if (writable || fact.already_on_page) {
Line 1,527: Line 1,539:
} else {
} else {
$row.append($line, $tgt, $details);
$row.append($line, $tgt, $details);
$check.prop('checked', false);
}
}
/* Keep a hidden checkbox state for notes (never apply) */
if (!writable) {
if (!writable) {
$row.append($('<input>', { type: 'checkbox', checked: false, 'class': 'ocr-fact-check-hidden' }).hide());
$row.append($('<input>', { type: 'checkbox', checked: false, 'class': 'ocr-fact-check-hidden' }).hide());
Line 1,540: Line 1,550:
function renderPersonCards($list, proposed, job, onChange) {
function renderPersonCards($list, proposed, job, onChange) {
var grouped = groupFactsByPerson(proposed);
var grouped = groupFactsByPerson(proposed);
var lastGroup = null;
var personIndex = 0;
grouped.order.forEach(function (key) {
grouped.order.forEach(function (key) {
var items = grouped.byPerson[key];
var items = grouped.byPerson[key];
var first = items[0] || {};
var first = items[0] || {};
var title = first.target_title || '';
var title = first.target_title || '';
var writable = items.filter(function (f) {
var meta = personMetaFromItems(items);
return isWritableFact(f) && !f.already_on_page;
var groupId = first.group_id || '';
var teamFacts = items.filter(isPrimaryTeamFact);
var secondary = items.filter(function (f) {
return isWritableFact(f) && !isPrimaryTeamFact(f) && !f.already_on_page;
});
});
var notes = items.filter(function (f) {
var notes = items.filter(function (f) {
return f.kind === 'note' || f.already_on_page;
return f.kind === 'note';
});
});
var included = writable.some(function (f) { return f.selected; });
var teamFact = teamFacts[0];
var teamDone = teamFact && teamFact.already_on_page;
var teamReady = teamFact && !teamFact.already_on_page && !!(teamFact.value || '').trim();
var included = !!(title && teamReady && teamFact.selected !== false);
 
if (groupId && groupId !== lastGroup) {
lastGroup = groupId;
var groupLabel = meta.team
? ('Team ' + meta.team)
: ('Group ' + groupId.replace(/^g/i, ''));
var inGroup = grouped.order.filter(function (k) {
return (grouped.byPerson[k][0] || {}).group_id === groupId;
}).length;
$list.append($('<h3>', { 'class': 'ocr-group-heading' }).text(
groupLabel + ' — ' + inGroup + ' people on this document'
));
}
 
personIndex += 1;
var $card = $('<div>', {
var $card = $('<div>', {
'class': 'ocr-person-card' + (title ? ' ocr-person-matched' : ' ocr-person-unresolved'),
'class': 'ocr-person-card' +
(title ? ' ocr-person-matched' : ' ocr-person-unresolved') +
(teamDone ? ' ocr-person-done' : ''),
'data-person': key
'data-person': key
});
});
var $head = $('<div>', { 'class': 'ocr-card-head' });
 
$card.append($('<div>', { 'class': 'ocr-card-step' }).text(
'Person ' + personIndex + ' of ' + grouped.order.length + ' on the scan'
));
 
/* 1. Who is on the document (read-only identity) */
var $who = $('<div>', { 'class': 'ocr-card-who' });
$who.append($('<div>', { 'class': 'ocr-card-who-label' }).text('On the document'));
$who.append($('<div>', { 'class': 'ocr-card-name' }).text(personDisplayName(first)));
var whoBits = [];
if (meta.rank) {
whoBits.push(meta.rank);
}
if (meta.role) {
whoBits.push(meta.role);
}
if (meta.asn) {
whoBits.push('ASN ' + meta.asn);
}
if (meta.team) {
whoBits.push(meta.team);
}
if (whoBits.length) {
$who.append($('<div>', { 'class': 'ocr-card-meta' }).text(whoBits.join(' · ')));
}
$who.append($('<p>', { 'class': 'ocr-card-hint' }).text(
'Rank, role, and ASN here are from the scan (for matching). They are not written to the wiki unless you open “Also update other fields.”'
));
$card.append($who);
 
/* 2. Which wiki profile */
var $match = $('<div>', { 'class': 'ocr-card-match' });
$match.append($('<div>', { 'class': 'ocr-card-who-label' }).text('Wiki soldier page'));
var $include = $('<input>', {
var $include = $('<input>', {
type: 'checkbox',
type: 'checkbox',
'class': 'ocr-include',
'class': 'ocr-include',
checked: included && !!title
checked: included
});
});
$head.append($('<label>', { 'class': 'ocr-include-label' }).append($include, ' Include'));
$head.append($('<div>', { 'class': 'ocr-card-name' }).text(personDisplayName(first)));
var meta = personMetaBits(items);
if (meta.length) {
$head.append($('<div>', { 'class': 'ocr-card-meta' }).text(meta.join(' · ')));
}
$card.append($head);
var $match = $('<div>', { 'class': 'ocr-card-match' });
var $tgtShared = $('<input>', {
var $tgtShared = $('<input>', {
type: 'text',
type: 'text',
'class': 'ocr-person-title',
'class': 'ocr-person-title',
value: title,
value: title,
placeholder: 'Find soldier (name or ASN)…'
placeholder: 'Type surname or ASN to find their page…'
});
});
var $suggest = $('<div>', { 'class': 'ocr-suggest' }).hide();
var $suggest = $('<div>', { 'class': 'ocr-suggest' }).hide();
Line 1,585: Line 1,644:
$card.removeClass('ocr-person-unresolved').addClass('ocr-person-matched');
$card.removeClass('ocr-person-unresolved').addClass('ocr-person-matched');
$matchStatus.empty().append(
$matchStatus.empty().append(
$('<span>').text('Matched: '),
$('<span>').text('Will update: '),
$('<a>', { href: mw.util.getUrl(title), text: title, target: '_blank' })
$('<a>', { href: mw.util.getUrl(title), text: title, target: '_blank' })
);
);
} else {
} else {
$card.removeClass('ocr-person-matched').addClass('ocr-person-unresolved');
$card.removeClass('ocr-person-matched').addClass('ocr-person-unresolved');
$matchStatus.text('Needs a soldier match before Apply');
$matchStatus.text('Pick the matching soldier page before applying.');
$include.prop('checked', false);
$include.prop('checked', false);
syncPrimaryChecks();
}
}
if (onChange) {
if (onChange) {
Line 1,597: Line 1,657:
}
}
}
}
function syncPrimaryChecks() {
var on = $include.prop('checked') && !!$.trim($tgtShared.val() || '');
$card.find('.ocr-fact-primary.ocr-fact-writable input[type="checkbox"]').prop('checked', on);
if (!on) {
$card.find('.ocr-fact-secondary.ocr-fact-writable input[type="checkbox"]').prop('checked', false);
}
}
$match.append($matchStatus);
if (title) {
if (title) {
setMatch(title);
setMatch(title);
} else {
} else {
$matchStatus.text('Needs a soldier match before Apply');
$matchStatus.text('Not matched yet — search below or pick a suggestion.');
}
}
$match.append($matchStatus);
$match.append($tgtShared);
$match.append($('<label>').text('Wiki page ').append($tgtShared));
$match.append($suggest);
$match.append($suggest);
bindSoldierTypeahead($tgtShared, $suggest, setMatch);
bindSoldierTypeahead($tgtShared, $suggest, setMatch);
Line 1,617: Line 1,684:
if (candidates && candidates.length) {
if (candidates && candidates.length) {
var $pick = $('<select>', { 'class': 'ocr-match-pick' });
var $pick = $('<select>', { 'class': 'ocr-match-pick' });
$pick.append($('<option>', { value: '', text: 'Suggested matches…' }));
$pick.append($('<option>', { value: '', text: 'Suggested wiki pages…' }));
candidates.forEach(function (t) {
candidates.forEach(function (t) {
$pick.append($('<option>', { value: t, text: t, selected: t === title }));
$pick.append($('<option>', { value: t, text: t, selected: t === title }));
Line 1,629: Line 1,696:
}
}
$card.append($match);
$card.append($match);
/* 3. What changes on that profile (team is the only primary action) */
var $update = $('<div>', { 'class': 'ocr-card-update' });
$update.append($('<div>', { 'class': 'ocr-card-who-label' }).text('Change on their profile'));
var $includeRow = $('<label>', { 'class': 'ocr-include-row' });
$includeRow.append($include);


var $changes = $('<div>', { 'class': 'ocr-card-changes' });
var $changes = $('<div>', { 'class': 'ocr-card-changes' });
writable.forEach(function (fact) {
if (teamFact) {
var $row = renderChangeRow(fact, job, { hideTargetVisible: true });
var $teamRow = renderChangeRow(teamFact, job, {
$row.find('.ocr-fact-target').val(title);
hideTargetVisible: true,
$changes.append($row);
plainSentence: true,
forceSelected: included && !teamDone
});
$teamRow.find('.ocr-fact-target').val(title);
$teamRow.find('input[type="checkbox"]').first().addClass('ocr-primary-check').hide();
$changes.append($teamRow);
var sentence = profileUpdateSentence(teamFact);
$includeRow.append(document.createTextNode(' ' + (teamDone ? sentence : ('Apply this: ' + sentence))));
} else {
$includeRow.append(document.createTextNode(' No team number found for this person yet.'));
$include.prop('disabled', true);
}
$update.append($includeRow);
$update.append($changes);
 
$include.on('change', function () {
if ($include.prop('checked') && !$.trim($tgtShared.val() || '')) {
$include.prop('checked', false);
$matchStatus.text('Match a soldier page first, then check Apply.');
return;
}
if ($include.prop('checked') && teamDone) {
$include.prop('checked', false);
return;
}
syncPrimaryChecks();
if (onChange) {
onChange();
}
});
});
if (!writable.length && notes.some(function (n) { return n.already_on_page; })) {
 
notes.filter(function (n) { return n.already_on_page; }).forEach(function (fact) {
if (secondary.length) {
$changes.append(renderChangeRow(fact, job, { hideTargetVisible: true }));
var $moreFields = $('<details>', { 'class': 'ocr-card-more' });
$moreFields.append($('<summary>').text(
'Also update other fields on their page (' + secondary.length + ') — off by default'
));
secondary.forEach(function (fact) {
var $row = renderChangeRow(fact, job, {
hideTargetVisible: true,
forceSelected: false
});
$row.find('.ocr-fact-target').val(title);
$moreFields.append($row);
});
});
$update.append($moreFields);
}
}
$card.append($changes);


var detailNotes = notes.filter(function (n) { return n.kind === 'note'; });
if (notes.length) {
if (detailNotes.length) {
var $moreNotes = $('<details>', { 'class': 'ocr-card-more' });
var $more = $('<details>', { 'class': 'ocr-card-more' });
$moreNotes.append($('<summary>').text('OCR line / teammates (not written)'));
$more.append($('<summary>').text('Document details'));
notes.forEach(function (fact) {
detailNotes.forEach(function (fact) {
var $row = renderChangeRow(fact, job, { hideTargetVisible: true });
var $row = renderChangeRow(fact, job, { hideTargetVisible: true });
$row.find('.ocr-fact-target').val(title);
$row.find('.ocr-fact-target').val(title);
$more.append($row);
$moreNotes.append($row);
});
});
$card.append($more);
$update.append($moreNotes);
}
}


$include.on('change', function () {
$card.append($update);
var on = $include.prop('checked');
$card.on('change', 'input[type="checkbox"], input.ocr-fact-value', function (ev) {
if (on && !$.trim($tgtShared.val() || '')) {
if ($(ev.target).hasClass('ocr-include')) {
$include.prop('checked', false);
$matchStatus.text('Match a soldier page first, then Include.');
return;
return;
}
}
$card.find('.ocr-fact-writable input[type="checkbox"]').prop('checked', on);
if (onChange) {
onChange();
}
});
$card.on('change', 'input[type="checkbox"], input.ocr-fact-value', function () {
if (onChange) {
if (onChange) {
onChange();
onChange();
Line 1,679: Line 1,781:
var $card = $('<div>', { 'class': 'ocr-person-card ocr-person-matched ocr-single-card' });
var $card = $('<div>', { 'class': 'ocr-person-card ocr-person-matched ocr-single-card' });
var title = job.bound_title || '';
var title = job.bound_title || '';
$card.append($('<div>', { 'class': 'ocr-card-who-label' }).text('Changes for this soldier page'));
$card.append($('<div>', { 'class': 'ocr-card-name' }).text(title || 'This soldier'));
$card.append($('<div>', { 'class': 'ocr-card-name' }).text(title || 'This soldier'));
if (title) {
if (title) {
Line 1,699: Line 1,802:
}
}
primary.forEach(function (fact) {
primary.forEach(function (fact) {
var $row = renderChangeRow(fact, job, { hideTargetVisible: true });
var $row = renderChangeRow(fact, job, { hideTargetVisible: true, plainSentence: true });
$row.find('.ocr-fact-target').val(title);
$row.find('.ocr-fact-target').val(title);
$changes.append($row);
$changes.append($row);
});
});
skipped.forEach(function (fact) {
if (skipped.length) {
$changes.append(renderChangeRow(fact, job, { hideTargetVisible: true }));
var $skip = $('<details>', { 'class': 'ocr-card-more' });
});
$skip.append($('<summary>').text('Already on page (' + skipped.length + ')'));
skipped.forEach(function (fact) {
$skip.append(renderChangeRow(fact, job, { hideTargetVisible: true }));
});
$changes.append($skip);
}
$card.append($changes);
$card.append($changes);


Line 1,767: Line 1,875:
var $panel = $('<div>', { 'class': 'ocr-review-panel ocr-review-v2' });
var $panel = $('<div>', { 'class': 'ocr-review-panel ocr-review-v2' });
$panel.append($('<p>').append(
$panel.append($('<p>').append(
$('<strong>').text(job.multi_person ? 'Confirm people, then Apply' : 'Confirm changes, then Apply'),
$('<strong>').text(job.multi_person ? 'One card per person on the scan' : 'Confirm changes, then Apply'),
document.createTextNode(' — nothing is saved until you click Apply.')
document.createTextNode(
job.multi_person
? ' — for each person: confirm the wiki page, then check what to write on their profile (usually just Team). Nothing is saved until Apply.'
: ' — nothing is saved until you click Apply.'
)
));
));


Line 1,774: Line 1,886:
var ps = job.people_summary;
var ps = job.people_summary;
$panel.append($('<p>', { 'class': 'ocr-people-summary' }).text(
$panel.append($('<p>', { 'class': 'ocr-people-summary' }).text(
(ps.detected || 0) + ' people · ' +
(ps.detected || 0) + ' people on this document · ' +
(ps.matched || 0) + ' matched · ' +
(ps.matched || 0) + ' matched to wiki pages · ' +
(ps.unresolved || 0) + ' need review · ' +
(ps.unresolved || 0) + ' still need a match · ' +
(ps.already_on_page || 0) + ' already have team' +
(ps.already_on_page || 0) + ' already have this team' +
(ps.teams && ps.teams.length ? (' · teams ' + ps.teams.join(', ')) : '') +
(ps.teams && ps.teams.length ? (' · teams ' + ps.teams.join(', ')) : '') +
(ps.inferred_teams && ps.inferred_teams.length ? (' · inferred ' + ps.inferred_teams.join(', ')) : '')
(ps.inferred_teams && ps.inferred_teams.length ? (' · inferred ' + ps.inferred_teams.join(', ')) : '')
Line 1,830: Line 1,942:


var $previewBox = $('<div>', { 'class': 'ocr-apply-preview' });
var $previewBox = $('<div>', { 'class': 'ocr-apply-preview' });
$previewBox.append($('<strong>').text('What will change'));
$previewBox.append($('<strong>').text('What will change on soldier pages'));
$previewBox.append($('<p>', { 'class': 'ocr-fact-meta' }).text(
job.multi_person
? 'Only checked “Apply this” team updates (and any extra fields you opened) are listed here.'
: 'Checked items below will be written on Apply.'
));
var $previewUl = $('<ul>', { 'class': 'ocr-apply-preview-list' });
var $previewUl = $('<ul>', { 'class': 'ocr-apply-preview-list' });
$previewBox.append($previewUl);
$previewBox.append($previewUl);
Line 1,841: Line 1,958:
return;
return;
}
}
if (!(p.target_title || '').trim()) {
var page = (p.target_title || '').trim();
if (!page) {
return;
return;
}
}
var who = personDisplayName(p);
var who = personDisplayName(p);
lines.push(who + ' → ' + changeLineForFact(p));
lines.push(who + ' → page “' + page + '”: ' + changeLineForFact(p));
});
});
$previewUl.empty();
$previewUl.empty();
if (!lines.length) {
if (!lines.length) {
$previewUl.append($('<li>', { 'class': 'ocr-fact-meta' }).text('Nothing selected yet.'));
$previewUl.append($('<li>', { 'class': 'ocr-fact-meta' }).text(
job.multi_person
? 'Nothing selected yet. Match a person and check “Apply this” on their card.'
: 'Nothing selected yet.'
));
} else {
} else {
lines.forEach(function (ln) {
lines.forEach(function (ln) {
Line 1,859: Line 1,981:
if (job.multi_person) {
if (job.multi_person) {
var $toolbar = $('<div>', { 'class': 'ocr-multi-toolbar' });
var $toolbar = $('<div>', { 'class': 'ocr-multi-toolbar' });
var $selMatched = $('<button>', { type: 'button', text: 'Include all matched' });
var $selMatched = $('<button>', { type: 'button', text: 'Apply team for all matched' });
var $deselUnres = $('<button>', { type: 'button', text: 'Exclude unmatched' });
var $deselUnres = $('<button>', { type: 'button', text: 'Clear unmatched' });
$toolbar.append($selMatched, $deselUnres);
$toolbar.append($selMatched, $deselUnres);
$facts.append($toolbar);
$facts.append($toolbar);
renderPersonCards($list, proposed, job, refreshPreview);
renderPersonCards($list, proposed, job, refreshPreview);
$selMatched.on('click', function () {
$selMatched.on('click', function () {
$list.find('.ocr-person-matched').each(function () {
$list.find('.ocr-person-matched:not(.ocr-person-done)').each(function () {
var $card = $(this);
var $card = $(this);
$card.find('.ocr-include').prop('checked', true).trigger('change');
$card.find('.ocr-include').prop('checked', true).trigger('change');
$card.find('.ocr-fact-writable input[type="checkbox"]').prop('checked', true);
});
});
refreshPreview();
refreshPreview();
});
});
$deselUnres.on('click', function () {
$deselUnres.on('click', function () {
$list.find('.ocr-person-unresolved .ocr-include').prop('checked', false);
$list.find('.ocr-person-unresolved .ocr-include').prop('checked', false).trigger('change');
$list.find('.ocr-person-unresolved input[type="checkbox"]').prop('checked', false);
refreshPreview();
refreshPreview();
});
});