PageSourceSearch

https://pops.int/Resources/Shared/scripts/appContacts/contacts-v2.js

js pops.int collected 2026-09-24 08:57:33 UTC 34,016 bytes, 690 lines download raw bytes

1// arrConfig sample DisplayContactsList({ id: "OfficialContacts", template: "default", conv: "basel", showSearch: true, showSearchByConvention: false, showSearchByCountry: true, showSearchByName: true, showSearchByRole: true, showNames: true, showMap: true, lang: "en"  });
2//js file with arrLabels must be placed before this
3
4//set global variables to be accessed from template
5var arrRoles = [];
6//to handle exception when a country has contact but not a party (to avoid heavy processing)
7var arrExcep = [{ conv: "rotterdam", iso: "HT", msg: " <span class=\"attentionNote\">(Haiti has not signed or ratified the Rotterdam Connvetion)</span>", msgMap: " (Not a signatory or party to the Rotterdam Convention)" }];
8var root;
9var modal;
10var oMap;
11
12function DisplayContactsList(arrConfig) {
13    //init variables
14    var dsNames = [];
15    var dsCountries = [];
16    var dsRoles = [];
17    var dsConv = [];
18    var contactsDS;
19    var arrFeedFilter = { logic: "or", filters: [] };
20    var arrCountriesBase = [];
21    var arrMapData;
22    var localDataLoaded = false;
23
24    //set default language
25    var curLang = "en";
26    //check if arrConfig exists to get the desired language
27    if ((typeof arrConfig == "object") && (arrConfig !== null)) {
28        curLang = arrConfig.lang;
29    }
30    else {
31        //check if a lang param exist in query string
32        var UrlParams = extractUrlParams();
33        var lLang = UrlParams['lang'];
34        if (lLang !== null && lLang !== "" && lLang !== undefined) { curLang = lLang; }
35    }
36    switch (curLang) {
37        case "fr":
38            arrLabels = langLablelsFr;
39            kendo.culture("fr-FR"); //only for calendar...
40            break;
41        case "es":
42            arrLabels = langLablelsSp;
43            kendo.culture("es-ES");
44            break;
45        default:
46            arrLabels = langLablelsEn;
47    }
48    //set roles array for templates
49    arrRoles.push({ value: "BC CA", label: arrLabels.lblContactRoleCA });
50    arrRoles.push({ value: "BC FP", label: arrLabels.lblContactRoleFP });
51    arrRoles.push({ value: "RC OCP", label: arrLabels.lblContactRoleRcOCP });
52    arrRoles.push({ value: "RC DNA CP", label: arrLabels.lblContactRoleDNACP });
53    arrRoles.push({ value: "RC DNA C", label: arrLabels.lblContactRoleDNAC });
54    arrRoles.push({ value: "RC DNA P", label: arrLabels.lblContactRoleDNAP });
55    arrRoles.push({ value: "SC OCP", label: arrLabels.lblContactRoleScOCP });
56    arrRoles.push({ value: "SC NFP", label: arrLabels.lblContactRoleNFP });
57
58    //Load the template definition from an external file
59    templateLoader.loadExtTemplate("/Resources/Shared/scripts/appContacts/contacts.tmpl.htm", arrConfig.id);
60
61    //Subscribe to event triggered when templates loaded (Don't load use templates before they are available)
62    $(document).bind("TEMPLATE_LOADED_" + arrConfig.id, function (e, path) {
63        $(document).ready(function () {
64
65            //1. inject html elements in HTML module based on the id given as a parameter and add warper class for controling display in CSS
66            $("#" + arrConfig.id).addClass("contactsListWrap");
67            //add map divs
68            if (arrConfig.showMap) {
69                $("#" + arrConfig.id).append("<div id=\"mapRefresh_" + arrConfig.id + "\" style=\"display:none;\">0</div><div class=\"contactMapHeader\"id=\"mapHeader_" + arrConfig.id + "\"><p class=\"TextHeader showMap\"><img src=\"/portals/5/images/rcStatusOfRatificationsMap.gif\" alt=\"" + arrLabels.imgContactMapTitle + "\" title=\"" + arrLabels.imgContactMapTitle + "\" />" + arrLabels.contactMapHeader + "</p><p class=\"TextHeader hideMap\"><img src=\"/Resources/Shared/scripts/appCountryProfiles/img/ratif_list.jpg\" alt=\"" + arrLabels.imgContactListTitle + "\" title=\"" + arrLabels.imgContactListTitle + "\" />" + arrLabels.contactListHeader + "</p></div><div class=\"clear\"></div><div class=\"contactsMapWrap\"><div class=\"contactsMap\" id=\"map_" + arrConfig.id + "\"></div><div class=\"contactsMapDisclamerBtn\" id=\"mapDisclamerBtn_" + arrConfig.id + "\">" + arrLabels.mapDisclaimerTitle + "</div><div class=\"contactsMapDisclamerText\" id=\"mapDisclamerText_" + arrConfig.id + "\">" + arrLabels.mapDisclaimer + "</div></div>");
70            }
71            //add search divs
72            if (arrConfig.showSearch) {
73                $("#" + arrConfig.id).append("<div class=\"brsOfficialContacts_SearchBox\" id=\"searchBox_" + arrConfig.id + "\"><h3>" + arrLabels.searchBoxTitle + "</h3></div>");
74                if (arrConfig.showSearchByConvention) {
75                    $("#" + arrConfig.id).find(".brsOfficialContacts_SearchBox").append("<div><select id=\"msConv_" + arrConfig.id + "\" class=\"contactsSearchConv\"></select></div>");
76                }
77                if (arrConfig.showSearchByCountry) {
78                    $("#" + arrConfig.id).find(".brsOfficialContacts_SearchBox").append("<div><select id=\"ddlCountry_" + arrConfig.id + "\" class=\"contactsSearchCountry\"></select></div>");
79                }
80                if (arrConfig.showSearchByRole) {
81                    $("#" + arrConfig.id).find(".brsOfficialContacts_SearchBox").append("<div><select id=\"msRoles_" + arrConfig.id + "\" class=\"contactsSearchRole\"></select></div>");
82                }
83                if (arrConfig.showSearchByName) {
84                    $("#" + arrConfig.id).find(".brsOfficialContacts_SearchBox").append("<div><input id=\"txtName_" + arrConfig.id + "\" class=\"contactsSearchName\" type=\"text\" /></div>");
85                }
86            }
87            //add contact list div
88            $("#" + arrConfig.id).append("<div id=\"contactsList_" + arrConfig.id + "\" class=\"contactsList\"></div>");
89
90            //add other divs
91            $("#" + arrConfig.id).append("<div id=\"contactsProgress_" + arrConfig.id + "\" class=\"contactsListProgress\"></div><div id=\"contactsLog_" + arrConfig.id + "\" class=\"contactsListLog\"></div>");
92
93            //2. set data sources
94            var oContactsFeedURL = "//informea.pops.int/Contacts2/brsContacts.svc/Contacts";
95            switch (arrConfig.conv) {
96                case "basel":
97                    arrFeedFilter.filters.push({ field: "brsTreatyName", operator: "contains", value: "Basel" });
98                    dsRoles.push({ value: "BC CA", label: arrLabels.lblContactRoleCA });
99                    dsRoles.push({ value: "BC FP", label: arrLabels.lblContactRoleFP });                    
100                    break;
101                case "rotterdam":
102                    arrFeedFilter.filters.push({ field: "brsTreatyName", operator: "contains", value: "Rotterdam" });
103                    dsRoles.push({ value: "RC OCP", label: arrLabels.lblContactRoleRcOCP });
104                    dsRoles.push({ value: "RC DNA CP", label: arrLabels.lblContactRoleDNACP });
105                    dsRoles.push({ value: "RC DNA C", label: arrLabels.lblContactRoleDNAC });
106                    dsRoles.push({ value: "RC DNA P", label: arrLabels.lblContactRoleDNAP });
107                    break;
108                case "stockholm":
109                    arrFeedFilter.filters.push({ field: "brsTreatyName", operator: "contains", value: "Stockholm" });
110                    dsRoles.push({ value: "SC OCP", label: arrLabels.lblContactRoleScOCP });
111                    dsRoles.push({ value: "SC NFP", label: arrLabels.lblContactRoleNFP });
112                    break;
113                default:
114                    dsRoles = arrRoles;
115            }
116
117            contactsDS = new kendo.data.DataSource({
118                serverFiltering: true, 
119                serverSorting: true,
120                serverPaging: true,
121                pageSize: 1500,
122                type: "odata",
123                transport: {
124                    read: {
125                        url: oContactsFeedURL,
126                        dataType: "jsonp"
127                    }
128                },
129                filter: arrFeedFilter,
130                sort: [
131                    { field: "brsPartyNameEn", dir: "asc" },
132                    { field: "brsTreatyName", dir: "asc" },
133                    { field: "primary", dir: "desc" },
134                    { field: "lastName", dir: "asc" }
135                ],
136                schema: {
137                    parse: function (response) {
138                        //parse response to capture names, countries needed for the search and map (roles are static to avoid downgrading performance)
139                        var prevCountry = "";
140                        for (var i = 0; i < response.d.results.length; i++) {
141                            //store countries
142                            if (prevCountry !== response.d.results[i].country) {
143                                dsCountries.push({ value: response.d.results[i].country, label: response.d.results[i].brsPartyNameEn });
144                                prevCountry = response.d.results[i].country;
145                            }
146                            //store contact names
147                            if (response.d.results[i].brsFullName !== null) {
148                                dsNames.push(response.d.results[i].brsFullName);
149                            }
150                            dsNames.sort();
151                        }
152                        return response;
153                    }
154                },
155                requestStart: function (e) {
156                    kendo.ui.progress($("#" + arrConfig.id).find(".contactsListProgress"), true);
157                },
158                requestEnd: function (e) {
159                    kendo.ui.progress($("#" + arrConfig.id).find(".contactsListProgress"), false);
160                },
161                error: function (e) {
162                    $("#" + arrConfig.id).find(".contactsListLog").append("<p>Error: " + e.status + "</p>");
163                }
164            });
165
166            //3. display 
167            var tmplId = "#contactTemplateDefault";
168            if (arrConfig.template !== undefined && arrConfig.template !== "" && arrConfig.template !== "default") {
169                tmplId = "#" + arrConfig.template;
170            }
171            $("#contactsList_" + arrConfig.id).kendoListView({
172                dataSource: contactsDS,
173                template: kendo.template($(tmplId).html()),
174				bordered: false,
175                dataBound: function () {
176                    //adjust left column height
177                    AdjustLeftColumnHeight();
178                    //hide names, if needed
179                    if (!arrConfig.showNames) {
180                        $("#" + arrConfig.id).find(".brsOfficialContacts_ContactName").hide();
181                    }
182                    //hide country labels
183                    HideDuplicatesCountryLabels("#contactsList_" + arrConfig.id);
184                    //show search by countries
185                    if (arrConfig.showSearchByCountry && !localDataLoaded) {
186                        $("#ddlCountry_" + arrConfig.id).width(390).kendoDropDownList({
187                            dataSource: dsCountries,
188                            dataValueField: "value",
189                            dataTextField: "label",
190                            change: filterByParties,
191                            optionLabel: {
192                                label: arrLabels.ddlCountriesDefault,
193                                value: ""
194                            }
195                        });
196                    }
197                    //show search by names
198                    if (arrConfig.showSearchByName && !localDataLoaded) {
199                        $("#txtName_" + arrConfig.id).width(390).kendoAutoComplete({
200                            dataSource: dsNames,
201                            filter: "contains",
202                            minLength: 2,
203                            placeholder: arrLabels.ddlNamesDefault,
204                            change: filterByName
205                        });
206                    }
207                    //show search by role 
208                    if (arrConfig.showSearchByRole && !localDataLoaded) {
209                        $("#msRoles_" + arrConfig.id).width(390).kendoMultiSelect({
210                            dataSource: dsRoles,
211                            dataValueField: "value",
212                            dataTextField: "label",
213                            placeholder: arrLabels.ddlRolesDefault,
214                            change: filterByRoles
215                        });
216                    }
217                    //show search by convention 
218                    if (arrConfig.showSearchByConvention && !localDataLoaded) {
219                        $("#msConv_" + arrConfig.id).width(390).kendoMultiSelect({
220                            dataSource: [
221                                { value: "basel", label: arrLabels.ddlConvBc },
222                                { value: "rotterdam", label: arrLabels.ddlConvRc },
223                                { value: "stockholm", label: arrLabels.ddlConvSc }
224                            ],
225                            dataValueField: "value",
226                            dataTextField: "label",
227                            placeholder: arrLabels.ddlConvDefault,
228                            value: [arrConfig.conv],
229                            change: filterByConv
230                        });
231                    }
232                    //check exceptions for countries not parties - if only one conv is selected
233                    //if (arrConfig.conv == "rotterdam") {
234                    //    $("#contactsList_" + arrConfig.id).find("h3.HT").append(arrExcep[0].msg);
235                    //}
236                    //Build map data (show it after click, else it brings issues with legend)
237                    if (arrConfig.showMap) {
238                        if (!localDataLoaded) {
239                            //get all official countries to set map
240                            var dataSourceCountries = new kendo.data.DataSource({
241                                serverFiltering: true,
242                                serverSorting: true,
243                                serverPaging: true,
244                                //pageSize: 25,
245                                type: "odata",
246                                transport: {
247                                    read: {
248                                        url: "//informea.pops.int/CountryProfiles/brsTreatyProfile.svc/countryNames?$select=IsoCode2d,NameEn",
249                                        dataType: "jsonp"
250                                    }
251                                },
252                                sort: { field: "NameEn", dir: "asc" }
253                            });
254                            dataSourceCountries.fetch(function () {
255                                var view = dataSourceCountries.view();
256                                for (var i = 0; i < view.length; i++) {
257                                    arrCountriesBase.push({ id: view[i].IsoCode2d, label: view[i].NameEn, title: view[i].NameEn, description: "", groupId: view[i].IsoCode2d, color: "#AAAAAA" });
258                                }
259                                //Get map data
260                                arrMapData = getMapData(arrConfig, arrCountriesBase);
261                            });
262                        }
263                        else if ($("#mapRefresh_" + arrConfig.id).text() == "1") {
264                            //refresh map data after changing the Convention filter but not the others (map build its data based on the list displayed)
265                            arrMapData = getMapData(arrConfig, arrCountriesBase);
266                            $("#mapRefresh_" + arrConfig.id).text("0"); //reset refresh flag
267                        }
268                    }
269                    //set flag to indicate if local data has been loaded an bound to controls
270                    localDataLoaded = true;
271                }
272            });
273
274            //4. handles filtering
275            function filterByConv(e) {
276                //listen to conventions filter
277                $("#mapRefresh_" + arrConfig.id).text("1"); //reset refresh flag for the map
278                //refresh roles datasource (unselect previously selected roles)
279                var msConv = $("#msConv_" + arrConfig.id).data("kendoMultiSelect");
280                var oDsRoles = [];
281                if (msConv !== undefined && msConv.value().length > 0) {
282                    //split multiple values
283                    for (var i = 0; i < msConv.value().length; i++) {
284                        switch (msConv.value()[i]) {
285                            case "basel":
286                                oDsRoles.push({ value: "BC CA", label: arrLabels.lblContactRoleCA });
287                                oDsRoles.push({ value: "BC FP", label: arrLabels.lblContactRoleFP });
288                                break;
289                            case "rotterdam":
290                                oDsRoles.push({ value: "RC OCP", label: arrLabels.lblContactRoleRcOCP });
291                                oDsRoles.push({ value: "RC DNA CP", label: arrLabels.lblContactRoleDNACP });
292                                oDsRoles.push({ value: "RC DNA C", label: arrLabels.lblContactRoleDNAC });
293                                oDsRoles.push({ value: "RC DNA P", label: arrLabels.lblContactRoleDNAP });
294                                break;
295                            case "stockholm":
296                                oDsRoles.push({ value: "SC OCP", label: arrLabels.lblContactRoleScOCP });
297                                oDsRoles.push({ value: "SC NFP", label: arrLabels.lblContactRoleNFP });
298                                break;
299                        }
300                    }
301                    //check exceptions for countries not parties - if only one conv is selected
302                    if (msConv.value().length == 0 && msConv.value()[i] == "rotterdam") {
303                        $("#contactsList_" + arrConfig.id).find("h3.HT").html("Haiti" + arrExcep[0].msg);
304                    }
305                    else {
306                        $("#contactsList_" + arrConfig.id).find("h3.HT").html("Haiti");
307                    }
308                }
309                else {
310                    //show all roles
311                    oDsRoles = arrRoles;
312                }
313                //refresh roles list
314                var msRoles = $("#msRoles_" + arrConfig.id).data("kendoMultiSelect");
315                msRoles.setDataSource(oDsRoles);
316                msRoles.refresh();
317                //apply filters against contacts ds
318                applyFilters(arrConfig, contactsDS);
319            }
320            function filterByParties(e) {
321                //listen to Parties drop down list event
322                applyFilters(arrConfig, contactsDS);
323            }
324            function filterByName(e) {
325                //listen to names filter
326                applyFilters(arrConfig, contactsDS);
327            }
328            function filterByRoles(e) {
329                //listen to roles filter
330                applyFilters(arrConfig, contactsDS);
331            }
332
333            //5. handles show / hide map
334            $(".showMap").on("click", function () {
335                $(this).hide();
336                $("#searchBox_" + arrConfig.id).hide();
337                $("#contactsList_" + arrConfig.id).hide();
338                $("#mapHeader_" + arrConfig.id).find(".hideMap").show();
339                $("#" + arrConfig.id).find(".contactsMapWrap").show(); //animates bring positioning issues on map
340                showMap(arrConfig, arrCountriesBase, arrMapData); //build the map on demand (if built while hidden it brings issues with legend)
341            });
342            $(".hideMap").on("click", function () {
343				if(modal){modal.close();}
344                $(this).hide();
345                $("#" + arrConfig.id).find(".contactsMapWrap").hide();
346                $("#mapHeader_" + arrConfig.id).find(".showMap").show();
347                $("#searchBox_" + arrConfig.id).show();
348                $("#contactsList_" + arrConfig.id).show();
349            });
350
351            //6. handles map disclaimer event (to do: multiple instances firendly)
352            $(".contactsMapDisclamerBtn").on("click", function () {
353                $(".contactsMapDisclamerText").show().animate({
354                    width: "280px",
355                    height: "160px",
356                    opacity: 0.9
357                }, 600);
358            });
359            $(".contactsMapDisclamerText").on("mouseleave", function () {
360                $(this).animate({
361                    width: "0px",
362                    height: "0px",
363                    opacity: 1
364                }, 600, function () {
365                    $(this).hide();
366                });
367            });
368        });
369    });
370
371}
372
373function GetRolesLabels(rVal) {
374    //get roles labels based on its value (no more than 2 roles per user)
375    var oLabel = "";
376    var strTemp = "";
377    //split if multiple roles in rVal
378    var oVal = rVal.split(", ");
379    for (var j = 0; j < arrRoles.length; j++) {
380        for (var i = 0; i < arrRoles.length; i++) {
381            if (arrRoles[i].value === oVal[j]) {
382                oLabel += strTemp + arrRoles[i].label;
383                strTemp = ", ";
384            }
385        }
386    }
387    return oLabel;
388    
389}
390
391function HideDuplicatesCountryLabels(contId) {
392    //remove country labels that are not needed
393    var prevCountry = '';
394    $(contId).find("h3").each(function () {
395        if ($(this).hasClass(prevCountry)) {
396            $(this).hide();
397        }
398        else {
399            $(this).show();
400            $(this).before("<div class='brsOfficialContacts_countrySeparator'></div>");
401        }
402        prevCountry = $(this).attr("class");
403    });
404}
405
406function AdjustLeftColumnHeight() {
407    //adjust left column height to match the height of content pane loaded after initial display
408    if ($("#dnn_LeftColumn").height() !== null) {
409        //inner page
410        if ($("#dnn_LeftColumn").height() < $("#dnn_ContentPane").height()) { $("#content_leftColumn").height($("#dnn_ContentPane").height() + 100); }
411    }
412}
413
414
415function applyFilters(conf, oDS) {
416    //handles filtering after user's selction
417    var arrAllFilters = [];
418    var arrConvFilters = { logic: "or", filters: [] };
419    var arrPartyFilter = { logic: "and", filters: [] };
420    var arrRoleFilters = { logic: "or", filters: [] };
421    var arrNamesFilter = { logic: "and", filters: [] };
422
423    //set convention filter
424    if (conf.showSearchByConvention) {
425        var msConv = $("#msConv_" + conf.id).data("kendoMultiSelect");
426        if (msConv !== undefined && msConv.value().length > 0) {
427            //split multiple values
428            for (var i = 0; i < msConv.value().length; i++) {
429                var convSearch = "";
430                switch(msConv.value()[i]) {
431                    case "basel":
432                        convSearch = "Basel Convention";
433                        break;
434                    case "rotterdam":
435                        convSearch = "Rotterdam Convention";
436                        break;
437                    case "stockholm":
438                        convSearch = "Stockholm Convention";
439                        break;
440                }
441                arrConvFilters.filters.push({ field: "brsTreatyName", operator: "contains", value: convSearch });
442            }
443            arrAllFilters.push(arrConvFilters);
444        }
445    }
446    //set country filter
447    if (conf.showSearchByCountry) {
448        var ddlCountries = $("#ddlCountry_" + conf.id).data("kendoDropDownList");
449        if (ddlCountries !== undefined && ddlCountries.value() !== "") {
450            arrPartyFilter.filters.push({ field: "country", operator: "equals", value: ddlCountries.value() });
451            arrAllFilters.push(arrPartyFilter);
452        }
453    }
454    //set names filter
455    if (conf.showSearchByName) {
456        var txtName = $("#txtName_" + conf.id).data("kendoAutoComplete");
457        if (txtName !== undefined && txtName.value() !== "") {
458            arrNamesFilter.filters.push({ field: "brsFullName", operator: "equals", value: txtName.value() });
459            arrAllFilters.push(arrNamesFilter);
460        }
461    }
462    //set roles filter
463    if (conf.showSearchByRole) {
464        var msRoles = $("#msRoles_" + conf.id).data("kendoMultiSelect");
465        if (msRoles !== undefined && msRoles.value().length > 0) {
466            //split multiple values
467            for (var i = 0; i < msRoles.value().length; i++) {
468                arrRoleFilters.filters.push({ field: "brsContactRoleName", operator: "contains", value: msRoles.value()[i] });    
469            }
470            arrAllFilters.push(arrRoleFilters);
471        }
472    }
473    //refresh contacts datasource
474    oDS.filter(arrAllFilters);
475}
476
477function getMapData(config, allCountries) {
478    //build array for the map with all contacts and countries
479    var arrMapData = [];
480    //1. retrieve data from rendered template and package it for map
481    var prevCountryIso = "";
482    var prevCountryName = "";
483    var prevDesc = "";
484    //set first contact before entring the loop 
485    prevCountryIso = $("#contactsList_" + config.id).find(".brsOfficialContacts_contactWrap").first().attr("data-countryiso");
486    prevCountryName = $("#contactsList_" + config.id).find(".brsOfficialContacts_contactWrap").first().attr("data-countryname");
487    $("#contactsList_" + config.id).find(".brsOfficialContacts_contactWrap").each(function (index) {
488        var curCountryIso = $(this).attr("data-countryiso");
489        if (prevCountryIso !== curCountryIso) {
490            //check exceptions for countries not parties - if only one conv is selected
491            if (config.conv == "rotterdam" && prevCountryIso == "HT") {
492                arrMapData.push({ id: prevCountryIso, label: prevCountryName, title: prevCountryName + arrExcep[0].msgMap, description: prevDesc, groupId: prevCountryIso, color: "#4F98F7" });
493            }
494            else {
495                //push previous country data to array
496                arrMapData.push({ id: prevCountryIso, label: prevCountryName, title: prevCountryName, description: prevDesc, groupId: prevCountryIso, color: "#4F98F7" });
497            }
498            
499            //get current contact data
500            prevCountryIso = curCountryIso;
501            prevCountryName = $(this).attr("data-countryname");
502            prevDesc = $(this).html();
503        }
504        else {
505            //same country, append new contact to description (no separation line for first list item)
506            if (index > 0) {
507                prevDesc = prevDesc + "<hr class=\"contactMapBalloonSep\"/>"
508            }
509            prevDesc = prevDesc + $(this).html();
510        }
511        //push last country
512        if (index == $("#contactsList_" + config.id).find(".brsOfficialContacts_contactWrap").length -1) {
513            arrMapData.push({ id: prevCountryIso, label: prevCountryName, title: prevCountryName, description: prevDesc, groupId: prevCountryIso, color: "#4F98F7" });
514        }
515    });
516    //add countries without contacts to display borders properly (compare with allCountries where all countries are listed)
517    for (var i = 0; i < allCountries.length; i++) {
518        var result = $.grep(arrMapData, function (e) { return e.id == allCountries[i].id; });
519        if (result.length == 0) {
520            arrMapData.push({ id: allCountries[i].id, label: allCountries[i].label, title: allCountries[i].title, description: allCountries[i].description, groupId: allCountries[i].groupId, color: "#FFFFFF" });
521            //if Serbia is not a party, attach Kosovo
522            if (allCountries[i].id == "RS") {
523                arrMapData.push({ id: "XK", label: allCountries[i].label, title: allCountries[i].title, description: allCountries[i].description, groupId: allCountries[i].groupId, color: "#FFFFFF" });
524            }
525        }
526    }
527    return arrMapData;
528}
529
530function showMap(config, allCountries, arrMapData) {
531	
532	// Create root and map
533	if (!root){ root = am5.Root.new("map_" + config.id); }
534	if (!modal){ modal = am5.Modal.new(root, {content: "texte"});}
535
536	if (!oMap){
537		oMap = root.container.children.push(
538		am5map.MapChart.new(root, {projection: am5map.geoEqualEarth()})
539		);
540	}
541	//Zoom & home buttons
542	var zoomControl = oMap.set("zoomControl", am5map.ZoomControl.new(root, {
543	  x: am5.p0,
544	  centerX: am5.p0,
545	  y: am5.p0,
546	  centerY: am5.p0
547	}));
548	zoomControl.homeButton.set("visible", true);
549	
550	// Create map polygon series from  the UN GeoJSON
551	var polygonSeries = oMap.series.push(
552	  am5map.MapPolygonSeries.new(root, {})
553	);
554	
555	am5.net.load("/Resources/Shared/scripts/appContacts/BNDA_simplified.js").then(function(result) {
556		var geodata =JSON.parse(result.response);
557		polygonSeries.setAll({
558			geoJSON: geodata,
559			exclude: [12], // Remove Antarctica (id 12 in UN geoJSON)
560			reverseGeodata: true // important! when loading geojson from external source, must indicate coordinates are "reversed"
561		});
562				
563		// Configure polygon display
564		var polygonTemplate = polygonSeries.mapPolygons.template;
565		polygonTemplate.states.create("pointeroverState", {
566		  fill: am5.color("#CC0000")
567		});
568		polygonTemplate.setAll({
569		  tooltipText: "{lbl_en}",
570		  templateField: "polygonSettings",
571		  interactive: true
572		});
573		
574		//set hover function to:
575		// - highlight the selected country
576		// - highlight "related" countries" having the same "admiso" property (e.g., putting mouse on Taiwan should also highlight China and vice-versa)
577		// - display the name relayed to the "admiso" property (e.g., "China" instead of Taiwan)
578		var selectedISO = "";
579		var selectedName_en = "";
580		polygonTemplate.events.on("pointerover", function (event) {
581			selectedISO = event.target.dataItem.dataContext.admiso;
582			selectedName_en = event.target.dataItem.dataContext.lbl_en;
583			polygonSeries.mapPolygons.each(function (polygon) {
584				if (selectedISO == polygon.dataItem.dataContext.admiso){
585					polygon.states.apply("pointeroverState");
586				} else {
587					polygon.states.apply("default");
588				}
589			});
590			event.target.set("tooltipText", selectedName_en); //needed to hide tooltip when name is empty
591		});
592		
593		//set out function to remove highlight for all "related" countries
594		polygonTemplate.events.on("pointerout", function (event) {
595			selectedISO = event.target.dataItem.dataContext.admiso;
596			polygonSeries.mapPolygons.each(function (polygon) {
597				if (selectedISO == polygon.dataItem.dataContext.admiso){
598					polygon.states.apply("default");
599				}
600			});
601		});
602		
603		
604		polygonTemplate.events.on("click", function (event) {
605			if (event.target.dataItem.dataContext.description != "") {
606				MapOpenPopup(event.target.dataItem.dataContext.lbl_en, event.target.dataItem.dataContext.description);
607			}
608		});
609		
610		
611		// Set up data for countries
612		var data = [];
613		for (i=0; i<=geodata.features.length-1; i++){
614			var admiso3 = geodata.features[i].properties["admiso"];
615			var admiso2 = "";
616			var name_en = geodata.features[i].properties["lbl_en"];
617			var color="#3f79c4";
618			var description="";
619			//get corresponding 2-letter isoCode
620			for (var j=0 ; j < geodata.features.length ; j++){
621				if (geodata.features[j].properties["iso3cd"] == admiso3) {
622					admiso2 = geodata.features[j].properties["iso2cd"];					
623					break;
624				}
625			}
626			//get data from arrMapData table
627			for (var j=0 ; j < arrMapData.length ; j++){
628				if (arrMapData[j].id == admiso2) {
629					color = arrMapData[j].color;
630					description = arrMapData[j].description;
631					name_en = arrMapData[j].label;
632					break;
633				}
634			}
635			//specific text/title for western sahara, Jammu and Kashmir and South Sudan
636			if (admiso3 == "xjk" || admiso3 == "ESH") {name_en = geodata.features[i].properties["nam_en"] + "*";}
637			if (admiso3 == "xjk"){description = "* Lines on this map represents approximately the Line of Control in Jammu and Kashmir agreed upon by India and Pakistan. The final status of Jammu and Kashmir has not yet been agreed upon by the parties."}
638			if (admiso3 == "SSD"){color="#3f79c4"; description = "Final boundary between the Republic of Sudan and the Republic of South Sudan has not yet been determined."}
639			data.push({
640				id: geodata.features[i].id,
641				lbl_en: name_en,
642				description: description,
643				polygonSettings: {
644					fill: am5.color(color),
645				}
646			});
647		}
648		polygonSeries.data.setAll(data);
649	});
650	
651	//insert legend
652	var legend = oMap.children.push(am5.Legend.new(root, {
653		nameField: "name",
654		fillField: "color",
655		strokeField: "color",
656		y: am5.percent(80),
657		layout: root.verticalLayout
658	}));
659
660	legend.data.setAll([{
661		name: arrLabels.mapLegendContact,
662		color: am5.color("#4F98F7")
663	}, {
664		name: arrLabels.mapLegendNoContact,
665		color: am5.color("#FFFFFF")
666	}]);
667	
668}
669// Modal
670function MapOpenPopup(title,htmlText){
671	var content = "<img src=\"/Resources/Shared/scripts/appContacts/xIcon.svg\" style=\"float: right; cursor: pointer;\" onclick=\"modal.close();\" />";
672	content += "<div style=\"font-weight:bold;\">" + title + "</div>";
673	content += "<div style=\"max-width:520px;max-height:370px;overflow-y:scroll\">";
674	content += htmlText;
675	content += "</div>";
676	modal.set("content",content);	
677	modal.open();
678}
679
680
681// get all querystring parameters and store in array
682function extractUrlParams() {
683    var t = location.search.substring(1).split('&');
684    var f = [];
685    for (var i = 0; i < t.length; i++) {
686        var x = t[i].split('=');
687        f[x[0]] = x[1];
688    }
689    return f;
690}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.