Document OCR review UI and docs
Constrain contribute box width; consistent Gallery placement
Line 598: Line 598:


/**
/**
  * Soldier page upload box (Gallery section) — profile photos and documents.
  * Soldier page contribute box (Gallery) — photo/document upload + OCR slot.
* Always mounts at the end of the Gallery section (creates Gallery if missing)
* so position is consistent across profiles.
  */
  */
$(function () {
$(function () {
Line 608: Line 610:
var DOC_EXT = /\.(pdf|docx?|txt|rtf|odt|tiff?)$/i;
var DOC_EXT = /\.(pdf|docx?|txt|rtf|odt|tiff?)$/i;
var ALLOWED = /\.(jpe?g|png|gif|webp|pdf|docx?|txt|rtf|odt|tiff?)$/i;
var ALLOWED = /\.(jpe?g|png|gif|webp|pdf|docx?|txt|rtf|odt|tiff?)$/i;
var $galleryHeading = $('#Gallery').closest('h2');
 
if (!$galleryHeading.length) {
function headingText($el) {
$galleryHeading = $('h2').filter(function () {
var $h = $el.is('h2') ? $el : $el.find('h2').first();
return $.trim($(this).text()).replace(/\[edit\]/i, '') === 'Gallery';
return $.trim(($h.text() || '').replace(/\s*\[edit.*$/i, '').replace(/\s*edit\s*(source)?\s*/ig, ''));
}).first();
}
 
function headingWrap($h2) {
var $wrap = $h2.closest('.mw-heading');
return $wrap.length ? $wrap : $h2;
}
 
function findSectionHeading(names) {
var re = new RegExp('^(' + names.join('|') + ')$', 'i');
var $found = $();
$('h2').each(function () {
if (re.test(headingText($(this)))) {
$found = $(this);
return false;
}
});
return $found;
}
 
function ensureGalleryAnchor() {
var $h2 = $('#Gallery');
if (!$h2.length || !$h2.is('h2')) {
$h2 = findSectionHeading(['Gallery']);
}
if ($h2.length) {
return headingWrap($h2);
}
/* No Gallery yet — insert a heading before Technical record / Sources. */
var $anchor = findSectionHeading(['Technical record', 'Sources']);
var $wrap = $('<div>', { 'class': 'mw-heading mw-heading2' });
$wrap.append($('<h2>', { id: 'Gallery' }).text('Gallery'));
if ($anchor.length) {
headingWrap($anchor).before($wrap);
} else {
$('.mw-parser-output').first().append($wrap);
}
return $wrap;
}
}
if (!$galleryHeading.length) {
 
return;
function placeContributeBox($box) {
if ($('.soldier-upload-box').length) {
return;
}
var $gal = $('.mw-parser-output .soldier-gallery').last();
if ($gal.length) {
$gal.after($box);
return;
}
var $start = ensureGalleryAnchor();
var $next = $();
$start.nextAll('.mw-heading, h2').each(function () {
var t = headingText($(this));
if (/^(Technical record|Sources|Awards|See also)$/i.test(t)) {
$next = $(this).is('h2') ? headingWrap($(this)) : $(this);
return false;
}
});
if ($next.length) {
$next.before($box);
} else {
$start.after($box);
}
}
}


Line 640: Line 700:
));
));
$box.append($photoSection);
$box.append($photoSection);
$galleryHeading.after($box);
$box.append($('<div>', { 'class': 'soldier-ocr-slot' }));
placeContributeBox($box);
return;
return;
}
}
Line 660: Line 721:
$photoSection.append($form);
$photoSection.append($form);
$box.append($photoSection);
$box.append($photoSection);
/* OCR tools mount into .soldier-ocr-slot (filled by the OCR init below). */
$box.append($('<div>', { 'class': 'soldier-ocr-slot' }));
$box.append($('<div>', { 'class': 'soldier-ocr-slot' }));
$galleryHeading.after($box);
placeContributeBox($box);


function setStatus(msg, isError) {
function setStatus(msg, isError) {
Line 1,302: Line 1,362:
});
});
var $slot = $('.soldier-ocr-slot').first();
var $slot = $('.soldier-ocr-slot').first();
if ($slot.length) {
if (!$slot.length) {
/* Contribute box not ready yet (rare); wait one tick. */
window.setTimeout(function () {
var $retry = $('.soldier-ocr-slot').first();
if ($retry.length) {
$retry.empty().append($section);
}
}, 0);
} else {
$slot.empty().append($section);
$slot.empty().append($section);
} else {
var $fallback = $('<div>', { 'class': 'soldier-upload-box' }).append($section);
$('.soldier-infobox').first().after($fallback);
}
}
}
}