MediaWiki:Common.js: Difference between revisions
OCR roster table: who / wiki page / what changes on that profile |
OCR roster: treat MW API true as empty string; table when 24 people detected |
||
| Line 1,353: | Line 1,353: | ||
{ id: 'other', label: 'Other document' } | { id: 'other', label: 'Other document' } | ||
]; | ]; | ||
/** MediaWiki JSON encodes PHP true as "" and false as null/omitted. */ | |||
function mwApiBool(v) { | |||
if (v === true || v === 1 || v === '1' || v === 'true') { | |||
return true; | |||
} | |||
if (v === false || v === 0 || v === '0' || v === 'false' || v == null) { | |||
return false; | |||
} | |||
if (v === '') { | |||
return true; | |||
} | |||
return !!v; | |||
} | |||
function isMultiPersonJob(job) { | |||
if (!job) { | |||
return false; | |||
} | |||
if (mwApiBool(job.multi_person)) { | |||
return true; | |||
} | |||
var detected = job.people_summary && job.people_summary.detected; | |||
if (Number(detected) > 1) { | |||
return true; | |||
} | |||
var keys = {}; | |||
(job.proposed || []).forEach(function (p) { | |||
if (p.person_key) { | |||
keys[p.person_key] = 1; | |||
} | |||
}); | |||
return Object.keys(keys).length > 1; | |||
} | |||
function factAlreadyOnPage(fact) { | |||
return !!(fact && mwApiBool(fact.already_on_page)); | |||
} | |||
function factSelected(fact) { | |||
return !!(fact && mwApiBool(fact.selected)); | |||
} | |||
function changeLineForFact(fact) { | function changeLineForFact(fact) { | ||
| Line 1,358: | Line 1,400: | ||
var val = (fact.value || '').trim(); | var val = (fact.value || '').trim(); | ||
var label = (fact.label || '').toLowerCase(); | var label = (fact.label || '').toLowerCase(); | ||
if (fact | if (factAlreadyOnPage(fact) && (field === 'ipw_ge' || field === 'teams')) { | ||
return 'Team already on their profile (' + (val || fact.existing_value || 'same') + ') — no change'; | return 'Team already on their profile (' + (val || fact.existing_value || 'same') + ') — no change'; | ||
} | } | ||
if (fact | if (factAlreadyOnPage(fact)) { | ||
return (fact.label || 'Already on page') + ' — skipped'; | return (fact.label || 'Already on page') + ' — skipped'; | ||
} | } | ||
| Line 1,449: | Line 1,491: | ||
} | } | ||
var val = (fact.value || '').trim(); | var val = (fact.value || '').trim(); | ||
if (fact | if (factAlreadyOnPage(fact)) { | ||
return 'Their profile already lists this team — nothing to write.'; | return 'Their profile already lists this team — nothing to write.'; | ||
} | } | ||
| Line 1,497: | Line 1,539: | ||
function renderChangeRow(fact, job, opts) { | function renderChangeRow(fact, job, opts) { | ||
opts = opts || {}; | opts = opts || {}; | ||
var writable = isWritableFact(fact) && !fact | var writable = isWritableFact(fact) && !factAlreadyOnPage(fact); | ||
var forceSelected = opts.forceSelected; | var forceSelected = opts.forceSelected; | ||
var selected = writable && (forceSelected === undefined ? | var selected = writable && (forceSelected === undefined ? factSelected(fact) : !!forceSelected); | ||
var $row = $('<div>', { | var $row = $('<div>', { | ||
'class': 'ocr-fact-row' + | 'class': 'ocr-fact-row' + | ||
(fact | (factAlreadyOnPage(fact) ? ' 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') + | (isPrimaryTeamFact(fact) ? ' ocr-fact-primary' : ' ocr-fact-secondary') + | ||
| Line 1,535: | Line 1,577: | ||
'field ' + (fact.field || fact.kind || '') + ' · conf ' + (fact.confidence || 0) + '%' | 'field ' + (fact.field || fact.kind || '') + ' · conf ' + (fact.confidence || 0) + '%' | ||
)); | )); | ||
if (writable || fact | if (writable || factAlreadyOnPage(fact)) { | ||
$row.append($check, $line, $tgt, $details); | $row.append($check, $line, $tgt, $details); | ||
} else { | } else { | ||
| Line 1,569: | Line 1,611: | ||
var teamFacts = items.filter(isPrimaryTeamFact); | var teamFacts = items.filter(isPrimaryTeamFact); | ||
var secondary = items.filter(function (f) { | var secondary = items.filter(function (f) { | ||
return isWritableFact(f) && !isPrimaryTeamFact(f) && !f | return isWritableFact(f) && !isPrimaryTeamFact(f) && !factAlreadyOnPage(f); | ||
}); | }); | ||
var notes = items.filter(function (f) { | var notes = items.filter(function (f) { | ||
| Line 1,575: | Line 1,617: | ||
}); | }); | ||
var teamFact = teamFacts[0]; | var teamFact = teamFacts[0]; | ||
var teamDone = !!(teamFact && teamFact | var teamDone = !!(teamFact && factAlreadyOnPage(teamFact)); | ||
var teamReady = !!(teamFact && !teamFact | var teamReady = !!(teamFact && !factAlreadyOnPage(teamFact) && (teamFact.value || '').trim()); | ||
var included = !!(title && teamReady && teamFact | var included = !!(title && teamReady && factSelected(teamFact)); | ||
var teamLabel = (teamFact && (teamFact.value || '').trim()) | var teamLabel = (teamFact && (teamFact.value || '').trim()) | ||
? ('IPW ' + String(teamFact.value).replace(/^IPW\s+/i, '')) | ? ('IPW ' + String(teamFact.value).replace(/^IPW\s+/i, '')) | ||
| Line 1,838: | Line 1,880: | ||
var primary = proposed.filter(function (f) { | var primary = proposed.filter(function (f) { | ||
return isWritableFact(f) && !f | return isWritableFact(f) && !factAlreadyOnPage(f); | ||
}); | }); | ||
var skipped = proposed.filter(function (f) { return f | var skipped = proposed.filter(function (f) { return factAlreadyOnPage(f); }); | ||
var notes = proposed.filter(function (f) { return f.kind === 'note'; }); | var notes = proposed.filter(function (f) { return f.kind === 'note'; }); | ||
| Line 1,919: | Line 1,961: | ||
function renderReview($host, job, cfg) { | function renderReview($host, job, cfg) { | ||
$host.empty(); | $host.empty(); | ||
var $panel = $('<div>', { 'class': 'ocr-review-panel ocr-review-v2' + (job | var $panel = $('<div>', { 'class': 'ocr-review-panel ocr-review-v2' + (isMultiPersonJob(job) ? ' ocr-review-roster' : '') }); | ||
if (job | if (isMultiPersonJob(job)) { | ||
$panel.append($('<p>').append( | $panel.append($('<p>').append( | ||
$('<strong>').text('Each row is one person'), | $('<strong>').text('Each row is one person'), | ||
| Line 1,934: | Line 1,976: | ||
} | } | ||
if (job | if (isMultiPersonJob(job) && job.people_summary) { | ||
var ps = job.people_summary; | var ps = job.people_summary; | ||
var $banner = $('<div>', { 'class': 'ocr-outcome-banner' }); | var $banner = $('<div>', { 'class': 'ocr-outcome-banner' }); | ||
| Line 1,963: | Line 2,005: | ||
if (job.identity_warning) { | if (job.identity_warning) { | ||
var $id = $('<div>', { | var $id = $('<div>', { | ||
'class': 'ocr-identity-banner' + (job.identity_ok ? ' ocr-identity-ok' : ' ocr-identity-warn') | 'class': 'ocr-identity-banner' + (mwApiBool(job.identity_ok) ? ' ocr-identity-ok' : ' ocr-identity-warn') | ||
}); | }); | ||
$id.append($('<strong>').text(job.identity_ok ? 'Identity check: ' : 'Identity warning: ')); | $id.append($('<strong>').text(mwApiBool(job.identity_ok) ? 'Identity check: ' : 'Identity warning: ')); | ||
$id.append(document.createTextNode(job.identity_warning)); | $id.append(document.createTextNode(job.identity_warning)); | ||
$panel.append($id); | $panel.append($id); | ||
| Line 2,004: | Line 2,046: | ||
$previewBox.append($('<strong>').text('Soldier pages that will be edited')); | $previewBox.append($('<strong>').text('Soldier pages that will be edited')); | ||
$previewBox.append($('<p>', { 'class': 'ocr-fact-meta ocr-preview-hint' }).text( | $previewBox.append($('<p>', { 'class': 'ocr-fact-meta ocr-preview-hint' }).text( | ||
job | isMultiPersonJob(job) | ||
? 'Grouped by wiki page. Rank/role/ASN from the scan are not listed here unless you check them under a row.' | ? 'Grouped by wiki page. Rank/role/ASN from the scan are not listed here unless you check them under a row.' | ||
: 'Checked items below will be written on Apply.' | : 'Checked items below will be written on Apply.' | ||
| Line 2,016: | Line 2,058: | ||
var byPage = {}; | var byPage = {}; | ||
props.forEach(function (p) { | props.forEach(function (p) { | ||
if (!p.selected || !isWritableFact(p) || p | if (!p.selected || !isWritableFact(p) || factAlreadyOnPage(p)) { | ||
return; | return; | ||
} | } | ||
| Line 2,033: | Line 2,075: | ||
$previewCount.text(''); | $previewCount.text(''); | ||
$previewUl.append($('<li>', { 'class': 'ocr-fact-meta' }).text( | $previewUl.append($('<li>', { 'class': 'ocr-fact-meta' }).text( | ||
job | isMultiPersonJob(job) | ||
? 'Nothing will be written on Apply. Check Write? on a row (after matching a wiki page) to add that person.' | ? 'Nothing will be written on Apply. Check Write? on a row (after matching a wiki page) to add that person.' | ||
: 'Nothing selected yet.' | : 'Nothing selected yet.' | ||
| Line 2,055: | Line 2,097: | ||
$facts.append($previewBox); | $facts.append($previewBox); | ||
if (job | if (isMultiPersonJob(job)) { | ||
var $toolbar = $('<div>', { 'class': 'ocr-multi-toolbar' }); | var $toolbar = $('<div>', { 'class': 'ocr-multi-toolbar' }); | ||
var $selMatched = $('<button>', { type: 'button', text: 'Write team for every matched person who still needs it' }); | var $selMatched = $('<button>', { type: 'button', text: 'Write team for every matched person who still needs it' }); | ||
| Line 2,108: | Line 2,150: | ||
var $overwrite = $('<label>').append( | var $overwrite = $('<label>').append( | ||
$('<input>', { type: 'checkbox', checked: | $('<input>', { type: 'checkbox', checked: mwApiBool(job.overwrite) }), | ||
' Overwrite existing infobox fields (default: fill empty only)' | ' Overwrite existing infobox fields (default: fill empty only)' | ||
); | ); | ||
var $gallery = $('<label>').append( | var $gallery = $('<label>').append( | ||
$('<input>', { type: 'checkbox', checked: job.add_to_gallery | $('<input>', { type: 'checkbox', checked: mwApiBool(job.add_to_gallery) }), | ||
' Add document to Gallery on Apply' + (job | ' Add document to Gallery on Apply' + (isMultiPersonJob(job) ? ' (off by default for multi-person)' : '') | ||
); | ); | ||
var $forceId = $('<label>', { 'class': 'ocr-force-identity' }).append( | var $forceId = $('<label>', { 'class': 'ocr-force-identity' }).append( | ||
| Line 2,119: | Line 2,161: | ||
' I confirmed this document matches this soldier (override identity guard)' | ' I confirmed this document matches this soldier (override identity guard)' | ||
); | ); | ||
if (job.identity_ok || job | if (mwApiBool(job.identity_ok) || isMultiPersonJob(job)) { | ||
$forceId.hide(); | $forceId.hide(); | ||
} | } | ||
| Line 2,141: | Line 2,183: | ||
type: 'button', | type: 'button', | ||
'class': 'ocr-apply-btn', | 'class': 'ocr-apply-btn', | ||
text: job | text: isMultiPersonJob(job) ? 'Apply selected' : 'Apply selected' | ||
}); | }); | ||
var $status = $('<p>', { 'class': 'ocr-review-status' }); | var $status = $('<p>', { 'class': 'ocr-review-status' }); | ||
| Line 2,169: | Line 2,211: | ||
var $cb = $row.find('input[type="checkbox"]').first(); | var $cb = $row.find('input[type="checkbox"]').first(); | ||
base.selected = $cb.length ? !!$cb.prop('checked') : false; | base.selected = $cb.length ? !!$cb.prop('checked') : false; | ||
if ($row.hasClass('ocr-fact-is-note') || ($row.hasClass('ocr-fact-note') && !base | if ($row.hasClass('ocr-fact-is-note') || ($row.hasClass('ocr-fact-note') && !factAlreadyOnPage(base) && base.kind === 'note')) { | ||
base.selected = false; | base.selected = false; | ||
} | } | ||
| Line 2,262: | Line 2,304: | ||
$apply.on('click', function () { | $apply.on('click', function () { | ||
if (!job | if (!isMultiPersonJob(job) && !mwApiBool(job.identity_ok) && !$forceId.find('input').prop('checked')) { | ||
$status.text('Confirm identity (Advanced → checkbox) before Apply, or fix the wrong document.'); | $status.text('Confirm identity (Advanced → checkbox) before Apply, or fix the wrong document.'); | ||
$adv.prop('open', true); | $adv.prop('open', true); | ||
| Line 2,489: | Line 2,531: | ||
var $meta = $('<div>', { 'class': 'ocr-queue-meta' }); | var $meta = $('<div>', { 'class': 'ocr-queue-meta' }); | ||
var ps = job.people_summary || {}; | var ps = job.people_summary || {}; | ||
var peopleBit = job | var peopleBit = isMultiPersonJob(job) | ||
? ((ps.detected || 0) + ' people · ' + (ps.matched || 0) + ' matched · ' + (ps.unresolved || 0) + ' unmatched') | ? ((ps.detected || 0) + ' people · ' + (ps.matched || 0) + ' matched · ' + (ps.unresolved || 0) + ' unmatched') | ||
: (job.bound_title ? job.bound_title : 'single document'); | : (job.bound_title ? job.bound_title : 'single document'); | ||