Skip to content

Commit

Permalink
CONCD-599 Implement UI/Design change for OCR language selection (#2339)
Browse files Browse the repository at this point in the history
* CONCD-599 language selection (WiP)

* css change that goes with the previous commit

* CONCD-599 splitting the modal in to two steps

* CONCD-599 trying to get the dialog to match the design

* CONCD-599 breaking this up in to two separate modals

* Center modal

* CONCD-599 the modal should be hidden, if the captcha is displayed

* rule-empty-line-before

Expected empty line before rule

* added stylelint-value-no-unknown-custom-properties to package.json

* CONCD-599 added Spanish, etc to list of allowed languages

* CONCD-599 the language input should actually be part of the form

* CONCD-599 The dialog looks a little narrower in the design

* CONCD-599 trying to make the modal dialogs match the designs

* CONCD-599 I think the transcription modal needs some padding

* CONCD-599 ran 'pipenv update'
  • Loading branch information
rasarkar authored Apr 16, 2024
1 parent 16b2c88 commit 4452f64
Show file tree
Hide file tree
Showing 8 changed files with 1,610 additions and 278 deletions.
465 changes: 242 additions & 223 deletions Pipfile.lock

Large diffs are not rendered by default.

106 changes: 105 additions & 1 deletion concordia/settings_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,111 @@
}
TINYMCE_JS_URL = "https://cdn.tiny.cloud/1/rf486i5f1ww9m8191oolczn7f0ry61mzdtfwbu7maiiiv2kv/tinymce/6/tinymce.min.js"

PYTESSERACT_ALLOWED_LANGUAGES = ["eng"]
LANGUAGE_CODES = {
"eng": "English (default)",
"afr": "Afrikaans",
"amh": "Amharic",
"ara": "Arabic",
"asm": "Assamese",
"aze": "Azerbaijani",
"aze_cyrl": "Azerbaijani - Cyrillic",
"bel": "Belarusian",
"ben": "Bengali",
"bod": "Tibetan",
"bos": "Bosnian",
"bul": "Bulgarian",
"cat": "Catalan; Valencian",
"ceb": "Cebuano",
"ces": "Czech",
"chi_sim": "Chinese - Simplified",
"chi_tra": "Chinese - Traditional",
"chr": "Cherokee",
"cym": "Welsh",
"dan": "Danish",
"deu": "German",
"dzo": "Dzongkha",
"ell": "Greek, Modern (1453-)",
"enm": "English, Middle (1100-1500)",
"epo": "Esperanto",
"est": "Estonian",
"eus": "Basque",
"fas": "Persian",
"fin": "Finnish",
"fra": "French",
"frk": "German Fraktur",
"frm": "French, Middle (ca. 1400-1600)",
"gle": "Irish",
"glg": "Galician",
"grc": "Greek, Ancient (-1453)",
"guj": "Gujarati",
"hat": "Haitian; Haitian Creole",
"heb": "Hebrew",
"hin": "Hindi",
"hrv": "Croatian",
"hun": "Hungarian",
"iku": "Inuktitut",
"ind": "Indonesian",
"isl": "Icelandic",
"ita": "Italian",
"ita_old": "Italian - Old",
"jav": "Javanese",
"jpn": "Japanese",
"kan": "Kannada",
"kat": "Georgian",
"kat_old": "Georgian - Old",
"kaz": "Kazakh",
"khm": "Central Khmer",
"kir": "Kirghiz; Kyrgyz",
"kor": "Korean",
"kur": "Kurdish",
"lao": "Lao",
"lat": "Latin",
"lav": "Latvian",
"lit": "Lithuanian",
"mal": "Malayalam",
"mar": "Marathi",
"mkd": "Macedonian",
"mlt": "Maltese",
"msa": "Malay",
"mya": "Burmese",
"nep": "Nepali",
"nld": "Dutch; Flemish",
"nor": "Norwegian",
"ori": "Oriya",
"pan": "Panjabi; Punjabi",
"pol": "Polish",
"por": "Portuguese",
"pus": "Pushto; Pashto",
"ron": "Romanian; Moldavian; Moldovan",
"rus": "Russian",
"san": "Sanskrit",
"sin": "Sinhala; Sinhalese",
"slk": "Slovak",
"slv": "Slovenian",
"spa": "Spanish; Castilian",
"spa_old": "Spanish; Castilian - Old",
"sqi": "Albanian",
"srp": "Serbian",
"srp_latn": "Serbian - Latin",
"swa": "Swahili",
"swe": "Swedish",
"syr": "Syriac",
"tam": "Tamil",
"tel": "Telugu",
"tgk": "Tajik",
"tgl": "Tagalog",
"tha": "Thai",
"tir": "Tigrinya",
"tur": "Turkish",
"uig": "Uighur; Uyghur",
"ukr": "Ukrainian",
"urd": "Urdu",
"uzb": "Uzbek",
"uzb_cyrl": "Uzbek - Cyrillic",
"vie": "Vietnamese",
"yid": "Yiddish",
}
PYTESSERACT_ALLOWED_LANGUAGES = LANGUAGE_CODES.keys()

PYLENIUM_CONFIG = os.path.join(SITE_ROOT_DIR, "pylenium.json")

Expand Down
5 changes: 3 additions & 2 deletions concordia/static/js/src/contribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function setupPage() {
var $ocrSection = $('#ocr-section');
var $ocrForm = $('#ocr-transcription-form');
var $ocrModal = $('#ocr-transcription-modal');
var $languageModal = $('#language-selection-modal');
var $ocrLoading = $('#ocr-loading');

let firstEditorUpdate = true;
Expand Down Expand Up @@ -424,7 +425,7 @@ function setupPage() {
$('#help-container').html(
$(data).find('#help-container').html(),
);
$('#ocr-transcription-modal').html(
$ocrModal.html(
$(data).find('#ocr-transcription-modal').html(),
);
reserveAssetForEditing();
Expand Down Expand Up @@ -596,7 +597,7 @@ function setupPage() {
if ($ocrForm) {
$ocrForm
.on('submit', function () {
$ocrModal.modal('hide');
$languageModal.modal('hide');
$ocrLoading.removeAttr('hidden');
})
.on('form-submit-success', function (event, extra) {
Expand Down
19 changes: 19 additions & 0 deletions concordia/static/scss/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ $card-progress-height: 12px;
#{$card-img-height} - #{$card-btn-height - $card-progress-height}
);
z-index: 3;

.view-transcriptions--item-detail & {
top: 0;
}
Expand Down Expand Up @@ -988,6 +989,23 @@ $card-progress-height: 12px;
}
}

#ocr-transcription-modal .modal-dialog {
max-width: 419px;
}

#language-selection-modal {
display: none;
margin-left: 40px;
}

#language-selection-modal .modal-dialog {
max-width: 428px;
}

#language-selection-modal .modal-footer {
justify-content: center;
}

/*
* Tag input on the asset detail page
*/
Expand Down Expand Up @@ -1108,6 +1126,7 @@ $card-progress-height: 12px;
transition: 0.3s;
background-color: $white;
}

.sidebar.offscreen {
transform: translateX(100%);
}
Expand Down
118 changes: 82 additions & 36 deletions concordia/templates/transcriptions/asset_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -681,26 +681,63 @@ <h5 id="captcha-modal-title" class="modal-title">Please confirm you are not a ro
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Are you sure?</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
<span aria-hidden="true" class="text-primary">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Clicking "Transcribe with OCR" will remove all existing transcription text and replace it with automatically generated text. We recommend saving existing text in a separate document if you may want to revisit it.</p>
<div class="bg-light px-3">
<h5 class="modal-title">Are you sure?</h5>
<p>Clicking "Transcribe with OCR" will remove all existing transcription text and replace it with automatically generated text. We recommend saving existing text in a separate document if you may want to revisit it.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button>
{% if transcription_status == "not_started" or transcription_status == "in_progress" %}
<form id="ocr-transcription-form" class="ajax-submission" method="post" action="{% url 'generate-ocr-transcription' asset_pk=asset.pk %}" data-lock-element="#transcription-editor">
<input type="hidden" name="supersedes" value="{{ transcription.pk|default:'' }}" />
<button id="ocr-transcription-button" class="btn btn-link underline-link font-weight-bold" disabled>Yes, replace the text</button>
</form>
<input type="hidden" name="supersedes" value="{{ transcription.pk|default:'' }}" />
<a tabindex="0" class="btn btn-link d-inline p-0" role="button" data-placement="top" id="select-language-button" onclick="selectLanguage()">
<span class="underline-link font-weight-bold">Yes, Select Language</span>
</a>
{% endif %}
</div>
</div>
</div>
</div>
<div id="language-selection-modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true" class="text-primary">&times;</span>
</button>
</div>
<form id="ocr-transcription-form" class="ajax-submission" method="post" action="{% url 'generate-ocr-transcription' asset_pk=asset.pk %}" data-lock-element="#transcription-editor">
<div class="modal-body">
<div class="bg-light pb-4">
<h5 class="modal-title">Select language</h5>
<p>Select the language the transcription is in from the list below.</p>
<div class="text-center">
<select id="language" name="language" size="7">
{% for language in languages %}
<option value="{{ language.0 }}"{% if language.0 == "eng" %} selected="selected"{% endif %}>
{{ language.1 }}
</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button>
{% if transcription_status == "not_started" or transcription_status == "in_progress" %}
<input type="hidden" name="supersedes" value="{{ transcription.pk|default:'' }}" />
<button id="ocr-transcription-button" class="btn btn-link underline-link font-weight-bold" disabled>Replace Text</button>
{% endif %}
</div>
</form>
</div>
</div>
</div>
</div>
<div class="print-transcription-image d-none d-print-block"><img class="img-fluid" alt="Scanned image of the current content page" src="{% asset_media_url asset %}"></div>
{% if cards %}
Expand Down Expand Up @@ -803,9 +840,9 @@ <h5>{{ card.display_heading }}</h5>
crossOriginPolicy: "Anonymous"
});

// We need to define our own fullscreen function rather than using OpenSeadragon's
// because the built-in fullscreen function overwrites the DOM with the viewer,
// breaking our extra controls, such as the image filters.
// We need to define our own fullscreen function rather than using OpenSeadragon's
// because the built-in fullscreen function overwrites the DOM with the viewer,
// breaking our extra controls, such as the image filters.
if (screenfull.isEnabled) {
let fullscreenButton = document.querySelector("#viewer-fullscreen");
fullscreenButton.addEventListener('click', function(event) {
Expand All @@ -819,14 +856,14 @@ <h5>{{ card.display_heading }}</h5>
});
}

// The buttons configured as controls for the viewer don't properly get focus
// when clicked. This mostly isn't a problem, but causes odd-looking behavior
// when one of the extra buttons in the control bar is clicked (and therefore
// focused) first--clicking the control button leaves the focus on the extra
// button.
// TODO: Attempting to add focus to the clicked button here doesn't consistently
// work for unknown reasons, so it just removes focus from the extra buttons
// for now
// The buttons configured as controls for the viewer don't properly get focus
// when clicked. This mostly isn't a problem, but causes odd-looking behavior
// when one of the extra buttons in the control bar is clicked (and therefore
// focused) first--clicking the control button leaves the focus on the extra
// button.
// TODO: Attempting to add focus to the clicked button here doesn't consistently
// work for unknown reasons, so it just removes focus from the extra buttons
// for now
let viewerControlButtons = document.querySelectorAll('.viewer-control-button');
viewerControlButtons.forEach(function(node){
node.addEventListener('click', function(event){
Expand All @@ -838,9 +875,9 @@ <h5>{{ card.display_heading }}</h5>
})
});

/*
* Image filter handling
*/
/*
* Image filter handling
*/

let availableFilters = [
{
Expand Down Expand Up @@ -895,18 +932,18 @@ <h5>{{ card.display_heading }}</h5>
if(form){
form.addEventListener('change', updateFilters);
form.addEventListener('reset', function(){
// We use setTimeout to push the updateFilters
// call to the next event cycle in order to
// call it after the form is reset, instead
// of before, which is when this listener
// triggers
// We use setTimeout to push the updateFilters
// call to the next event cycle in order to
// call it after the form is reset, instead
// of before, which is when this listener
// triggers
setTimeout(updateFilters);
});
}
input = document.getElementById(filterData.inputId)
if(input){
// We use debounce here so that updateFilters is only called once,
// after the user stops typing or scrolling with their mousewheel
// We use debounce here so that updateFilters is only called once,
// after the user stops typing or scrolling with their mousewheel
input.addEventListener('keyup', debounce(() => updateFilters()));
input.addEventListener('wheel', debounce(() => updateFilters()));
}
Expand Down Expand Up @@ -1025,10 +1062,10 @@ <h5>{{ card.display_heading }}</h5>
}
pageSplit = horizontalSplit();
setTimeout(function(){
// Some quirk in the viewer makes this
// sometimes not work depending on
// the rotation, unless it's delayed.
// Less than 10ms didn't reliable work.
// Some quirk in the viewer makes this
// sometimes not work depending on
// the rotation, unless it's delayed.
// Less than 10ms didn't reliable work.
seadragonViewer.viewport.zoomTo(1);
}, 10);
}
Expand Down Expand Up @@ -1083,16 +1120,16 @@ <h5>{{ card.display_heading }}</h5>
}
window.addEventListener('beforeunload', function(event){
if(formChanged){
// Some browsers ignore this value and always display a built-in message instead
// Some browsers ignore this value and always display a built-in message instead
return event.returnValue = "The transcription you've started has not been saved.";
}
});
</script>

<script>
/*
* Image filter form handling
*/
/*
* Image filter form handling
*/
function stepUp(id){
let input = document.getElementById(id);
input.stepUp();
Expand Down Expand Up @@ -1185,5 +1222,14 @@ <h5>{{ card.display_heading }}</h5>
$("#tutorial-popup").on("shown.bs.modal", function() {
setTutorialHeight();
});
function selectLanguage() {
$("#ocr-transcription-modal").modal("hide");
$("#language-selection-modal").modal("show");
}
const dialog = document.querySelector(".example-dialog");
dialog.addEventListener("close", (event) => {
$("#language-selection-modal").modal("hide");
$("#ocr-confirmation-modal").modal("show");
});
</script>
{% endblock body_scripts %}
4 changes: 3 additions & 1 deletion concordia/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,8 @@ def get_context_data(self, **kwargs):
if guides.count() > 0:
ctx["guides"] = guides

ctx["languages"] = list(settings.LANGUAGE_CODES.items())

return ctx


Expand Down Expand Up @@ -1478,7 +1480,7 @@ def generate_ocr_transcription(request, *, asset_pk):
user = request.user

supersedes_pk = request.POST.get("supersedes")
language = request.POST.get("language")
language = request.POST.get("language", None)
superseded = get_transcription_superseded(asset, supersedes_pk)
if superseded and isinstance(superseded, HttpResponse):
return superseded
Expand Down
Loading

0 comments on commit 4452f64

Please sign in to comment.