From 7c4bb9f8580b084a0f7dc605bc3a98cd2a81fc56 Mon Sep 17 00:00:00 2001 From: Erik Brommers Date: Thu, 29 Feb 2024 13:46:55 -0800 Subject: [PATCH] Work on #558 Add some helper code to suggest / auto-add the language name. Looks like we're okay with RFC5646 compliance. --- www/js/views/ProjectViews.js | 142 ++++++++++++++++++++++++----------- www/tpl/LanguagesList.html | 13 ---- 2 files changed, 99 insertions(+), 56 deletions(-) delete mode 100755 www/tpl/LanguagesList.html diff --git a/www/js/views/ProjectViews.js b/www/js/views/ProjectViews.js index f803fda5..6f5a4b36 100644 --- a/www/js/views/ProjectViews.js +++ b/www/js/views/ProjectViews.js @@ -41,6 +41,7 @@ define(function (require) { USFMMarkers = null, theFont = null, template = null, + firstLang = null, projid = "", //// @@ -48,6 +49,7 @@ define(function (require) { //// // Helper method that returns the RFC5646 code based on the ISO639 code and variant + // See https://www.rfc-editor.org/rfc/rfc5646 buildFullLanguageCode = function (langCode, langVariant) { var fullCode = ""; // only build if there's a language code defined @@ -688,12 +690,14 @@ define(function (require) { var theQuery = query.toLowerCase(); $.when(coll.fetch({reset: true, data: {name: theQuery}})).done(function () { // convert to Array for the typeahead to consume + firstLang = (coll.length > 0) ? coll.at(0) : null; // set our static "first language suggestion" callback(coll.toArray()); }); }; }, template: Handlebars.compile(tplSourceLanguage), onShow: function () { + firstLang = null; // clear out static language suggestion this.theLangs = new langs.LanguageCollection(); this.theLangs.fetch({reset: true, data: {name: ""}}); @@ -753,12 +757,14 @@ define(function (require) { var theQuery = query.toLowerCase(); $.when(coll.fetch({reset: true, data: {name: theQuery}})).done(function () { // convert to Array for the typeahead to consume + firstLang = (coll.length > 0) ? coll.at(0) : null; // set our static "first language suggestion" callback(coll.toArray()); }); }; }, template: Handlebars.compile(tplTargetLanguage), onShow: function () { + firstLang = null; // clear out static language suggestion this.theLangs = new langs.LanguageCollection(); this.theLangs.fetch({reset: true, data: {name: ""}}); @@ -1105,11 +1111,13 @@ define(function (require) { "click #Cases": "OnEditCases", "click #Filtering": "OnEditFiltering", "focus #LanguageName": "onFocusLanguageName", + "keydown #LanguageName": "onKeydownLanguageName", "focus #LanguageVariant": "onFocusLanguageVariant", "keyup #LanguageVariant": "onkeyupLanguageVariant", "focus #LanguageCode": "onFocusLanguageCode", "typeahead:select .typeahead": "selectLanguage", "typeahead:cursorchange .typeahead": "selectLanguage", + "typeahead:autocomplete .typeahead": "selectLanguage", "click .delete-row": "onClickDeleteRow", "keyup .new-row": "addNewRow", "click #CopyPunctuation": "OnClickCopyPunctuation", @@ -1158,6 +1166,30 @@ define(function (require) { onkeypressTargetName: function (event) { currentView.onkeypress(event); }, + onKeydownLanguageName: function (event) { + if ((event.keyCode === 9) || (event.keyCode === 13)) { + // if there was a suggestion in the typeahead, assume the user wanted it + if (firstLang) { + var newLangCode = ""; + // try autonym, fall back on language name in English + if (firstLang.attributes.localname) { + currentView.langName = firstLang.attributes.localname; + } else if (firstLang.attributes.localnames) { + currentView.langName = firstLang.attributes.localnames[0]; + } else if (firstLang.attributes.names) { + currentView.langName = firstLang.attributes.names[0]; + } else { + currentView.langName = firstLang.attributes.name; + } + newLangCode = firstLang.attributes.tag; + currentView.langCode = buildFullLanguageCode(newLangCode, $('#LanguageVariant').val().trim().replace(/\s+/g, '')); + $('#LanguageCode').val(currentView.langCode); + + } + // blur the edit field + $("#LanguageName").trigger("blur"); + } + }, selectLanguage: function (event, suggestion) { if (suggestion) { var newLangCode = ""; @@ -1550,8 +1582,10 @@ define(function (require) { "click #navFont": "OnEditNavFont", "focus #LanguageName": "onFocusLanguageName", "blur #LanguageName": "onBlurLanguageName", + "keydown #LanguageName": "onKeydownLanguageName", "typeahead:select .typeahead": "selectLanguage", "typeahead:cursorchange .typeahead": "selectLanguage", + "typeahead:autocomplete .typeahead": "selectLanguage", "focus #LanguageVariant": "onFocusLanguageVariant", "keyup #LanguageVariant": "onkeyupLanguageVariant", "focus #LanguageCode": "onFocusLanguageCode", @@ -1631,6 +1665,30 @@ define(function (require) { onkeypressTargetName: function (event) { currentView.onkeypress(event); }, + onKeydownLanguageName: function (event) { + if ((event.keyCode === 9) || (event.keyCode === 13)) { + // if there was a suggestion in the typeahead, assume the user wanted it + if (firstLang) { + var newLangCode = ""; + // try autonym, fall back on language name in English + if (firstLang.attributes.localname) { + currentView.langName = firstLang.attributes.localname; + } else if (firstLang.attributes.localnames) { + currentView.langName = firstLang.attributes.localnames[0]; + } else if (firstLang.attributes.names) { + currentView.langName = firstLang.attributes.names[0]; + } else { + currentView.langName = firstLang.attributes.name; + } + newLangCode = firstLang.attributes.tag; + currentView.langCode = buildFullLanguageCode(newLangCode, $('#LanguageVariant').val().trim().replace(/\s+/g, '')); + $('#LanguageCode').val(currentView.langCode); + + } + // blur the edit field + $("#LanguageName").trigger("blur"); + } + }, selectLanguage: function (event, suggestion) { if (suggestion) { var newLangCode = ""; @@ -1830,55 +1888,52 @@ define(function (require) { var value = null; if (currentView.langName.trim().length === 0) { // fail - no language set - // Is there something in the language edit field? - if ($("#LanguageName").val().length > 0) { - // something in the language field -- attempt to get the nearest match in the languages list - value = languages.at(0); - if (languages.length > 0) { - // found something that matches the search text -- suggest it - if (navigator.notification) { - // on mobile device -- use notification plugin API - navigator.notification.confirm( - i18n.t('view.lblUseLanguage', {language: value.get("Ref_Name")}), - function (btnIndex) { - if (btnIndex === 1) { - // set the language and ID - currentView.langName = value.get("Ref_Name"); - currentView.langCode = buildFullLanguageCode(value.get("Id"), $('#LanguageVariant').val().trim()); - } else { - // user rejected this suggestion -- tell them to enter - // a language name and finish up - navigator.notification.alert(i18n.t('view.errEnterLanguageName')); - } - }, - i18n.t('view.ttlMain'), - [i18n.t('view.lblYes'), i18n.t('view.lblNo')] - ); - } else { - // in browser -- use window.confirm / window.alert - if (window.confirm(i18n.t('view.lblUseLanguage', {language: value.get("Ref_Name")}))) { - // use the suggested language - currentView.langName = value.get("Ref_Name"); - currentView.langCode = buildFullLanguageCode(value.get("Id"), $('#LanguageVariant').val().trim()); - } else { - // user rejected this suggestion -- tell them to enter - // a language name and finish up - alert(i18n.t('view.errEnterLanguageName')); - } - } + // is there a suggested language? + if (firstLang) { + var strLangName = ""; + // try autonym, fall back on language name in English + if (firstLang.attributes.localname) { + strLangName = firstLang.attributes.localname; + } else if (firstLang.attributes.localnames) { + strLangName = firstLang.attributes.localnames[0]; + } else if (firstLang.attributes.names) { + strLangName = firstLang.attributes.names[0]; + } else { + strLangName = firstLang.attributes.name; + } + // found something that matches the search text -- suggest it + if (navigator.notification) { + // on mobile device -- use notification plugin API + navigator.notification.confirm( + i18n.t('view.lblUseLanguage', {language: strLangName}), + function (btnIndex) { + if (btnIndex === 1) { + // set the language and ID + currentView.langName = strLangName; + currentView.langCode = buildFullLanguageCode(firstLang.attributes.tag, $('#LanguageVariant').val().trim()); + } else { + // user rejected this suggestion -- tell them to enter + // a language name and finish up + navigator.notification.alert(i18n.t('view.errEnterLanguageName')); + } + }, + i18n.t('view.ttlMain'), + [i18n.t('view.lblYes'), i18n.t('view.lblNo')] + ); } else { - // no suggestion found (user fell on his keyboard?) - // just tell them to enter something - if (navigator.notification) { - // on mobile device -- use notification plugin API - navigator.notification.alert(i18n.t('view.errEnterLanguageName')); + // in browser -- use window.confirm / window.alert + if (window.confirm(i18n.t('view.lblUseLanguage', {language: strLangName}))) { + // use the suggested language + currentView.langName = strLangName; + currentView.langCode = buildFullLanguageCode(firstLang.attributes.tag, $('#LanguageVariant').val().trim()); } else { - // in browser -- use window.confirm / window.alert + // user rejected this suggestion -- tell them to enter + // a language name and finish up alert(i18n.t('view.errEnterLanguageName')); } } } else { - // user didn't type anything in + // no suggestion found (user fell on their keyboard?) // just tell them to enter something if (navigator.notification) { // on mobile device -- use notification plugin API @@ -1892,6 +1947,7 @@ define(function (require) { // return whatever we got (could be empty) return currentView.langName; }; + switch (step) { case 1: // source language // get / validate the language string diff --git a/www/tpl/LanguagesList.html b/www/tpl/LanguagesList.html deleted file mode 100755 index 6f3863cc..00000000 --- a/www/tpl/LanguagesList.html +++ /dev/null @@ -1,13 +0,0 @@ -{{! LanguagesList.html - Template for rendering the languages that match the search list on the project source and target language pages. - This template is compiled by LanguagesView and called from ProjectSourceLanguageView.js and ProjectTargetLanguageView.js. -}} -{{#if this.Part1}} -
- {{this.Ref_Name}} ({{this.Part1}}) -
-{{else}} -
- {{this.Ref_Name}} ({{this.Id}}) -
-{{/if}}