diff --git a/tools/cldr-apps/js/src/esm/cldrInfo.mjs b/tools/cldr-apps/js/src/esm/cldrInfo.mjs index 95b46645321..a66d09f0eb7 100644 --- a/tools/cldr-apps/js/src/esm/cldrInfo.mjs +++ b/tools/cldr-apps/js/src/esm/cldrInfo.mjs @@ -18,6 +18,7 @@ import * as cldrVue from "./cldrVue.mjs"; import InfoPanel from "../views/InfoPanel.vue"; import InfoSelectedItem from "../views/InfoSelectedItem.vue"; +import InfoRegionalVariants from "../views/InfoRegionalVariants.vue"; let containerId = null; let neighborId = null; @@ -30,6 +31,7 @@ let unShow = null; let lastShown = null; let selectedItemWrapper = null; +let regionalVariantsWrapper = null; const ITEM_INFO_ID = "itemInfo"; // must match redesign.css const ITEM_INFO_CLASS = "sidebyside-scrollable"; // must match redesign.css, cldrGui.mjs, DashboardWidget.vue @@ -38,7 +40,10 @@ const HELP_HTML_ID = "info-panel-help"; const PLACEHOLDER_HELP_ID = "info-panel-placeholder"; const INFO_MESSAGE_ID = "info-panel-message"; const SELECTED_ITEM_ID = "info-panel-selected"; -const INFO_REMAINDER_ID = "info-panel-remainder"; +const INFO_VOTE_TICKET_ID = "info-panel-vote-and-ticket"; +const INFO_REGIONAL_ID = "info-panel-regional"; +const INFO_FORUM_ID = "info-panel-forum"; +const INFO_XPATH_ID = "info-panel-xpath"; /** * Initialize the Info Panel @@ -63,6 +68,11 @@ function insertWidget() { insertLegacyElement(containerEl); const selectedItemEl = document.getElementById(SELECTED_ITEM_ID); selectedItemWrapper = cldrVue.mount(InfoSelectedItem, selectedItemEl); + const regionalVariantsEl = document.getElementById(INFO_REGIONAL_ID); + regionalVariantsWrapper = cldrVue.mount( + InfoRegionalVariants, + regionalVariantsEl + ); } catch (e) { console.error("Error loading InfoPanel vue " + e.message + " / " + e.name); cldrNotify.exception(e, "while loading InfoPanel"); @@ -93,7 +103,10 @@ function insertLegacyElement(containerEl) { appendDiv(el, PLACEHOLDER_HELP_ID); appendDiv(el, INFO_MESSAGE_ID); appendDiv(el, SELECTED_ITEM_ID); - appendDiv(el, INFO_REMAINDER_ID); + appendDiv(el, INFO_VOTE_TICKET_ID); + appendDiv(el, INFO_REGIONAL_ID); + appendDiv(el, INFO_FORUM_ID); + appendDiv(el, INFO_XPATH_ID); } function appendDiv(el, id) { @@ -240,19 +253,23 @@ function show(str, tr, hideIfLast, fn) { cldrLoad.updateCurrentId(tr.sethash); } setLastShown(hideIfLast); - if (tr?.theRow) { - addDeferredHelp(tr.theRow); - addPlaceholderHelp(tr.theRow); - } + addDeferredHelp(tr?.theRow); // if !tr.theRow, erase (as when click Next/Previous) + addPlaceholderHelp(tr?.theRow); // ditto addInfoMessage(str); - addRemainder(tr, fn); - addSelectedItem(tr?.theRow); // after addRemainder calls fn to set theRow.selectedItem + addVoteDivAndTicketLink(tr, fn); + addSelectedItem(tr?.theRow); // after addVoteDivAndTicketLink calls fn to set theRow.selectedItem + addRegionalSidewaysMenu(tr); + addForumPanel(tr); + addXpath(tr); addVoterInfoHover(); } function addDeferredHelp(theRow) { const el = document.getElementById(HELP_HTML_ID); - if (el) { + if (!el) { + return; + } + if (theRow) { const { helpHtml, rdf, translationHint } = theRow; if (helpHtml || rdf || translationHint) { const fragment = document.createDocumentFragment(); @@ -262,15 +279,18 @@ function addDeferredHelp(theRow) { } else { el.appendChild(fragment); } - } else { - cldrDom.removeAllChildNodes(el); + return; } } + cldrDom.removeAllChildNodes(el); } function addPlaceholderHelp(theRow) { const el = document.getElementById(PLACEHOLDER_HELP_ID); - if (el) { + if (!el) { + return; + } + if (theRow) { const { placeholderStatus, placeholderInfo } = theRow; if (placeholderStatus !== "DISALLOWED") { const fragment = document.createDocumentFragment(); @@ -284,10 +304,10 @@ function addPlaceholderHelp(theRow) { } else { el.appendChild(fragment); } - } else { - cldrDom.removeAllChildNodes(el); + return; } } + cldrDom.removeAllChildNodes(el); } function addInfoMessage(html) { @@ -399,10 +419,13 @@ function getLinkUrlAndText(theRow, item) { return { linkUrl, linkText }; } -function addRemainder(tr, fn) { +function addVoteDivAndTicketLink(tr, fn) { const fragment = document.createDocumentFragment(); // If a generator fn (common case), call it. + // Typically, fn is the function returned by showItemInfoFn. + // However, there is also "ourShowFn" in cldrVote.mjs... + // It's not clear why this is so indirect and complicated; tech debt; probably it could be more straightforward. if (fn) { unShow = fn(fragment); } @@ -412,18 +435,43 @@ function addRemainder(tr, fn) { if (tr?.ticketLink) { fragment.appendChild(tr.ticketLink.cloneNode(true)); } - if (tr) { - // TODO: Put a blank line around the sublocale menu, and give it a label. In context: - // Changes to this item require 20 votes. - // Regional Variants for German - // [ Germany (= German) ] - // Flag for Review (moved up) - // Reference: https://unicode-org.atlassian.net/browse/CLDR-7536 - cldrSideways.loadMenu(fragment, tr.xpstrid); // regional variants (sibling locales) + const el = document.getElementById(INFO_VOTE_TICKET_ID); + if (!el) { + return; } + cldrDom.removeAllChildNodes(el); + el.appendChild(fragment); +} + +// regional variants (sibling locales) +function addRegionalSidewaysMenu(tr) { + if (!regionalVariantsWrapper) { + return; + } + cldrSideways.loadMenu(regionalVariantsWrapper, tr?.xpstrid); +} + +function addForumPanel(tr) { + const el = document.getElementById(INFO_FORUM_ID); + if (!el) { + return; + } + const fragment = document.createDocumentFragment(); if (tr?.theRow && !cldrStatus.isVisitor()) { cldrForumPanel.loadInfo(fragment, tr, tr.theRow); } + cldrDom.removeAllChildNodes(el); + if (tr) { + el.appendChild(fragment); + } +} + +function addXpath(tr) { + const el = document.getElementById(INFO_XPATH_ID); + if (!el) { + return; + } + const fragment = document.createDocumentFragment(); if (tr?.theRow?.xpath) { fragment.appendChild( cldrDom.clickToSelect( @@ -431,22 +479,9 @@ function addRemainder(tr, fn) { ) ); } - const remainderElement = document.getElementById(INFO_REMAINDER_ID); - if (!remainderElement) { - console.log("remainderElement not found in show!"); - return; - } - - // Now, copy or append the 'fragment' to the - // appropriate spot. This depends on how we were called. + cldrDom.removeAllChildNodes(el); if (tr) { - cldrDom.removeAllChildNodes(remainderElement); - remainderElement.appendChild(fragment); - } else { - // show, for example, dataPageInitialGuidance in Info Panel - const clone = fragment.cloneNode(true); - cldrDom.removeAllChildNodes(remainderElement); - remainderElement.appendChild(clone); + el.appendChild(fragment); } } diff --git a/tools/cldr-apps/js/src/esm/cldrSideways.mjs b/tools/cldr-apps/js/src/esm/cldrSideways.mjs index 69d580cf5c3..35ddbaebb24 100644 --- a/tools/cldr-apps/js/src/esm/cldrSideways.mjs +++ b/tools/cldr-apps/js/src/esm/cldrSideways.mjs @@ -4,15 +4,17 @@ * such as: aa = Afar, aa_DJ = Afar (Djibouti), and aa_ER = Afar (Eritrea) */ import * as cldrCache from "./cldrCache.mjs"; -import * as cldrDom from "./cldrDom.mjs"; -import * as cldrEvent from "./cldrEvent.mjs"; import * as cldrLoad from "./cldrLoad.mjs"; import * as cldrStatus from "./cldrStatus.mjs"; import * as cldrSurvey from "./cldrSurvey.mjs"; -import * as cldrText from "./cldrText.mjs"; + +const SIDEWAYS_DEBUG = true; + +const escape = "\u00A0\u00A0\u00A0"; // non-breaking spaces +const unequalSign = "\u2260\u00A0"; // U+2260 = "≠" /** - * Array storing all only-1 sublocale + * Array storing all only-1 sublocales */ const oneLocales = []; @@ -23,47 +25,56 @@ let sidewaysShowTimeout = -1; const sidewaysCache = new cldrCache.LRU(); -const SIDEWAYS_AREA_CLASS = "sidewaysArea"; - -function loadMenu(frag, xpstrid) { +function loadMenu(regionalVariantsWrapper, xpstrid) { const curLocale = cldrStatus.getCurrentLocale(); - if (!curLocale || oneLocales[curLocale]) { + if (!curLocale || oneLocales[curLocale] || !xpstrid) { + regionalVariantsWrapper.setData(null); + if (SIDEWAYS_DEBUG) { + console.log("cldrSideways.loadMenu, nothing to display"); + } return; } - const cachedData = sidewaysCache.get(makeCacheKey(curLocale, xpstrid)); + const cacheKey = makeCacheKey(curLocale, xpstrid); + const cachedData = sidewaysCache.get(cacheKey); if (cachedData) { - const sidewaysControl = document.createElement("div"); - sidewaysControl.className = SIDEWAYS_AREA_CLASS; - frag.appendChild(sidewaysControl); - setMenuFromData(sidewaysControl, cachedData); + if (SIDEWAYS_DEBUG) { + console.log("cldrSideways.loadMenu, using cached data"); + } + regionalVariantsWrapper.setData(cachedData); } else { - fetchAndLoadMenu(frag, curLocale, xpstrid); + if (SIDEWAYS_DEBUG) { + console.log("cldrSideways.loadMenu, fetching new data"); + } + fetchAndLoadMenu(regionalVariantsWrapper, curLocale, xpstrid, cacheKey); } } -function fetchAndLoadMenu(frag, curLocale, xpstrid) { - const sidewaysControl = cldrDom.createChunk( - cldrText.get("sideways_loading0"), - "div", - SIDEWAYS_AREA_CLASS - ); - frag.appendChild(sidewaysControl); +function fetchAndLoadMenu( + regionalVariantsWrapper, + curLocale, + xpstrid, + cacheKey +) { clearMyTimeout(); + regionalVariantsWrapper.setLoading(); sidewaysShowTimeout = window.setTimeout(function () { clearMyTimeout(); if ( curLocale !== cldrStatus.getCurrentLocale() || xpstrid !== cldrStatus.getCurrentId() ) { + if (SIDEWAYS_DEBUG) { + console.log( + "cldrSideways.fetchAndLoadMenu, locale or path changed, skipping" + ); + } return; } - cldrDom.updateIf(sidewaysControl, cldrText.get("sideways_loading1")); cldrLoad.myLoad( getSidewaysUrl(curLocale, xpstrid), "sidewaysView", function (json) { - sidewaysCache.set(makeCacheKey(curLocale, xpstrid), json); - setMenuFromData(sidewaysControl, json); + setMenuFromData(regionalVariantsWrapper, json, cacheKey); } ); }, 2000); // wait 2 seconds before loading this. @@ -90,37 +101,43 @@ function getSidewaysUrl(curLocale, xpstrid) { ); } -function setMenuFromData(sidewaysControl, json) { +/** + * Construct the data needed for the menu, using the json data received from the server, + * and update the menu + * + * @param {Object} regionalVariantsWrapper the menu GUI component + * @param {Object} json the data received from the serer + * @param {String} cacheKey the key for caching the data + */ +function setMenuFromData(regionalVariantsWrapper, json, cacheKey) { /* * Count the number of unique locales in json.others and json.novalue. */ - var relatedLocales = json.novalue.slice(); - for (var s in json.others) { - for (var t in json.others[s]) { + const relatedLocales = json.novalue.slice(); + for (let s in json.others) { + for (let t in json.others[s]) { relatedLocales[json.others[s][t]] = true; } } - // if there is 1 sublocale (+ 1 default), we do nothing + // if there is 1 sublocale (+ 1 default), show nothing if (Object.keys(relatedLocales).length <= 2) { oneLocales[cldrStatus.getCurrentLocale()] = true; - cldrDom.updateIf(sidewaysControl, ""); + regionalVariantsWrapper.setData(null); } else { if (!json.others) { - cldrDom.updateIf(sidewaysControl, ""); // no sibling locales (or all null?) + regionalVariantsWrapper.setData(null); } else { - cldrDom.updateIf(sidewaysControl, ""); // remove string - - var topLocale = json.topLocale; + const topLocale = json.topLocale; const locmap = cldrLoad.getTheLocaleMap(); - var curLocale = locmap.getRegionAndOrVariantName(topLocale); - var readLocale = null; + const curLocaleName = locmap.getRegionAndOrVariantName(topLocale); + let readLocale = null; // merge the read-only sublocale to base locale var mergeReadBase = function mergeReadBase(list) { - var baseValue = null; + let baseValue = null; // find the base locale, remove it and store its value - for (var l = 0; l < list.length; l++) { - var loc = list[l][0]; + for (let l = 0; l < list.length; l++) { + const loc = list[l][0]; if (loc === topLocale) { baseValue = list[l][1]; list.splice(l, 1); @@ -129,9 +146,9 @@ function setMenuFromData(sidewaysControl, json) { } // replace the default locale(read-only) with base locale, store its name for label - for (var l = 0; l < list.length; l++) { - var loc = list[l][0]; - var bund = locmap.getLocaleInfo(loc); + for (let l = 0; l < list.length; l++) { + const loc = list[l][0]; + const bund = locmap.getLocaleInfo(loc); if (bund && bund.readonly) { readLocale = locmap.getRegionAndOrVariantName(loc); list[l][0] = topLocale; @@ -142,53 +159,38 @@ function setMenuFromData(sidewaysControl, json) { }; // compare all sublocale values - var appendLocaleList = function appendLocaleList(list, curValue) { - var group = document.createElement("optGroup"); - var br = document.createElement("optGroup"); - group.appendChild(br); - - group.setAttribute("label", "Regional Variants for " + curLocale); - group.setAttribute("title", "Regional Variants for " + curLocale); - - var escape = "\u00A0\u00A0\u00A0"; - var unequalSign = "\u2260\u00A0"; - - for (var l = 0; l < list.length; l++) { - var loc = list[l][0]; - var title = list[l][1]; - var item = document.createElement("option"); - item.setAttribute("value", loc); - if (title == null) { - item.setAttribute("title", "undefined"); - } else { - item.setAttribute("title", title); - } - - var str = locmap.getRegionAndOrVariantName(loc); + function appendLocaleList(list, curValue) { + popupSelect.label = "Regional Variants for " + curLocaleName; + + for (let l = 0; l < list.length; l++) { + const loc = list[l][0]; + const title = list[l][1]; + const item = { value: loc }; + let str = locmap.getRegionAndOrVariantName(loc); if (loc === topLocale) { - str = str + " (= " + readLocale + ")"; + str += " (= " + readLocale + ")"; } if (loc === cldrStatus.getCurrentLocale()) { str = escape + str; - item.setAttribute("selected", "selected"); - item.setAttribute("disabled", "disabled"); + item.disabled = true; } else if (title != curValue) { str = unequalSign + str; + item.disabled = false; } else { str = escape + str; + item.disabled = false; } - item.appendChild(document.createTextNode(str)); - group.appendChild(item); + item.str = str; + popupSelect.items.push(item); } - popupSelect.appendChild(group); - }; - - var dataList = []; + } - var popupSelect = document.createElement("select"); - for (var s in json.others) { - for (var t in json.others[s]) { + const dataList = []; + const popupSelect = {}; + popupSelect.items = []; + for (let s in json.others) { + for (let t in json.others[s]) { dataList.push([json.others[s][t], s]); } } @@ -196,9 +198,9 @@ function setMenuFromData(sidewaysControl, json) { /* * Set curValue = the value for cldrStatus.getCurrentLocale() */ - var curValue = null; + let curValue = null; for (let l = 0; l < dataList.length; l++) { - var loc = dataList[l][0]; + const loc = dataList[l][0]; if (loc === cldrStatus.getCurrentLocale()) { curValue = dataList[l][1]; break; @@ -210,34 +212,22 @@ function setMenuFromData(sidewaysControl, json) { */ if (json.novalue) { const differentValue = curValue === "A" ? "B" : "A"; // anything different from curValue - for (s in json.novalue) { + for (let s in json.novalue) { dataList.push([json.novalue[s], differentValue]); } } mergeReadBase(dataList); // then sort by sublocale name - dataList = dataList.sort(function (a, b) { + const sortedDataList = dataList.sort(function (a, b) { return ( locmap.getRegionAndOrVariantName(a[0]) > locmap.getRegionAndOrVariantName(b[0]) ); }); - appendLocaleList(dataList, curValue); - - var group = document.createElement("optGroup"); - popupSelect.appendChild(group); - - cldrDom.listenFor(popupSelect, "change", function (e) { - var newLoc = popupSelect.value; - if (newLoc !== cldrStatus.getCurrentLocale()) { - cldrStatus.setCurrentLocale(newLoc); - cldrLoad.reloadV(); - } - return cldrEvent.stopPropagation(e); - }); - - sidewaysControl.appendChild(popupSelect); + appendLocaleList(sortedDataList, curValue); + sidewaysCache.set(cacheKey, popupSelect); + regionalVariantsWrapper.setData(popupSelect); } } } diff --git a/tools/cldr-apps/js/src/esm/cldrText.mjs b/tools/cldr-apps/js/src/esm/cldrText.mjs index b564f11642a..e4de7986805 100644 --- a/tools/cldr-apps/js/src/esm/cldrText.mjs +++ b/tools/cldr-apps/js/src/esm/cldrText.mjs @@ -381,9 +381,6 @@ const strings = { sidewaysArea_desc: "view of what the votes are in other, sister locales", sideways_loading0: " ", sideways_loading1: "Comparing to other locales...", - sideways_same: "Other locales have the same value.", - sideways_diff: "Other locales have different values!", - sideways_noValue: "(no value)", ari_message: "Problem with the SurveyTool", ari_sessiondisconnect_message: "Your session has been disconnected.", diff --git a/tools/cldr-apps/js/src/views/InfoRegionalVariants.vue b/tools/cldr-apps/js/src/views/InfoRegionalVariants.vue new file mode 100644 index 00000000000..57ea725e21f --- /dev/null +++ b/tools/cldr-apps/js/src/views/InfoRegionalVariants.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/tools/cldr-apps/src/main/webapp/surveytool.css b/tools/cldr-apps/src/main/webapp/surveytool.css index 9c0695c1e74..db30fac4f0d 100644 --- a/tools/cldr-apps/src/main/webapp/surveytool.css +++ b/tools/cldr-apps/src/main/webapp/surveytool.css @@ -547,20 +547,6 @@ pre.adminExceptionMESSAGE { margin-bottom: 0; } -div.sidewaysArea { - font-size: smaller; - padding-left: 20px; -} - -div.sideways_same { - background: url(squo.png) no-repeat 0 top; -} - -div.sideways_diff { - background-color: #fbb; - background: url(zoom.png) no-repeat 0 top; -} - div.adminException { display: block; padding-top: 0.25em;