@bmlt-enabled/croutonjs 4.1.12 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11186,7 +11186,9 @@ function CroutonLocalization(language) {
11186
11186
  'all': 'الجميع',
11187
11187
  'menu': 'القائمة',
11188
11188
  'search for meetings': 'البحث عن الاجتماعات',
11189
+ 'search by location': 'البحث حسب الموقع',
11189
11190
  'show meetings near...': 'أظهر الاجتماعات بالقرب من...',
11191
+ 'closest meetings': 'أقرب الاجتماعات',
11190
11192
  'filter meetings': 'سرد الاجتماعات',
11191
11193
  'visible meeting list': 'قائمة الاجتماعات المرئية',
11192
11194
  'enter a city or zip code': 'أدخل المدينة أو الرمز البريدي',
@@ -11207,6 +11209,10 @@ function CroutonLocalization(language) {
11207
11209
  "waze": "وايز",
11208
11210
  "waze_desc": "فتح في تطبيق وايز",
11209
11211
  'address_lookup_fail': 'تعذر العثور على العنوان. يرجى المحاولة مرة أخرى.',
11212
+ "favorites": "المفضلة",
11213
+ "choose one": "اختر واحدا",
11214
+ "widen search": "البحث الواسع",
11215
+ "cancel search": "إلغاء البحث"
11210
11216
  },
11211
11217
  "cs": {
11212
11218
  "days_of_the_week": ["", "Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"],
@@ -11246,7 +11252,9 @@ function CroutonLocalization(language) {
11246
11252
  "all": "Jakékoli",
11247
11253
  "menu": "Menu",
11248
11254
  "search for meetings": "Hledat setkání",
11255
+ 'search by location': 'Vyhledávání podle lokality',
11249
11256
  "show meetings near...": "Setkání v jiných městech",
11257
+ 'closest meetings': "Nejbližší setkání",
11250
11258
  "filter meetings": "Filtr pro jazyk, formát atd.",
11251
11259
  "visible meeting list": "Viditelný seznam setkání jako tabulka",
11252
11260
  "enter a city or zip code": "Město nebo PSČ",
@@ -11257,7 +11265,6 @@ function CroutonLocalization(language) {
11257
11265
  "meeting details": "Podrobnosti o setkání",
11258
11266
  "report update": "Nahlásit aktualizaci",
11259
11267
  "filter by visibility": "Zobrazit pouze setkání, která jsou aktuálně na mapě",
11260
- "go": "Jít!",
11261
11268
  "get_directions": "Získat pokyny",
11262
11269
  "select_map_app": "Vyberte aplikaci pro mapy",
11263
11270
  "apple_maps": "Apple Mapy",
@@ -11272,6 +11279,10 @@ function CroutonLocalization(language) {
11272
11279
  "sorted by distance": "Seřazeno podle vzdálenosti",
11273
11280
  "address_lookup_fail": "Adresu se nepodařilo najít. Zkuste to prosím znovu.",
11274
11281
  "contact": "Kontakt",
11282
+ "favorites": "Oblíbené",
11283
+ "choose one": "Vyberte si jedno:",
11284
+ "widen search": "Rozšířit vyhledávání",
11285
+ "cancel search": "Zrušit vyhledávání",
11275
11286
  },
11276
11287
  "da-DK": {
11277
11288
  "days_of_the_week": ["", "Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"],
@@ -11288,7 +11299,7 @@ function CroutonLocalization(language) {
11288
11299
  "formats": "Struktur",
11289
11300
  "map": "Kort",
11290
11301
  "neighborhood": "Neighborhood",
11291
- "near_me": "Find nearby meetings",
11302
+ "near_me": "Find closest meetings",
11292
11303
  "text_search": "Find meetings there",
11293
11304
  "click_search": "Find meetings near to a point on the map",
11294
11305
  "pan_and_zoom": "Pan + Zoom",
@@ -11318,7 +11329,9 @@ function CroutonLocalization(language) {
11318
11329
  'menu': 'Menu',
11319
11330
  "bmlt2ics": "Add to your calendar",
11320
11331
  'search for meetings': 'Search for meetings',
11332
+ 'search by location': 'Søg efter placering',
11321
11333
  'show meetings near...': 'Show meetings near...',
11334
+ 'closest meetings': 'Nærmeste møder',
11322
11335
  'filter meetings': 'Filter meetings',
11323
11336
  'visible meeting list': 'Visible meetings as list',
11324
11337
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11338,6 +11351,10 @@ function CroutonLocalization(language) {
11338
11351
  "sorted by distance": "Sorteret efter Afstand",
11339
11352
  "address_lookup_fail": "Adressen kunne ikke findes. Prøv venligst igen.",
11340
11353
  "contact": "Kontakt",
11354
+ "favorites": "Favoritter",
11355
+ "choose one": "Vælg én:",
11356
+ "widen search": "Udvid søgning",
11357
+ "cancel search": "Annuller søgning",
11341
11358
  },
11342
11359
  "de-DE": {
11343
11360
  "days_of_the_week": ["", "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
@@ -11383,7 +11400,9 @@ function CroutonLocalization(language) {
11383
11400
  'all': 'Alle',
11384
11401
  'menu': 'Menu',
11385
11402
  'search for meetings': 'Search for meetings',
11403
+ 'search by location': 'Suche nach Standort',
11386
11404
  'show meetings near...': 'Meetings in andere Städten',
11405
+ 'closest meetings': 'Nächstgelegene Meetings',
11387
11406
  'filter meetings': 'Filter für Sprache, Format usw.',
11388
11407
  'visible meeting list': 'Sichtbare Meetings als Tabelle',
11389
11408
  'enter a city or zip code': 'Stadt oder PLZ',
@@ -11394,7 +11413,6 @@ function CroutonLocalization(language) {
11394
11413
  'meeting details': "Genaueres zum Meeting",
11395
11414
  'report update': "Report an Update",
11396
11415
  'filter by visibility': "Zeige nur Meetings, die gerade auf dem Karte stehen",
11397
- 'go': "Los!",
11398
11416
  "get_directions": "Wegbeschreibung",
11399
11417
  "select_map_app": "Karten-App auswählen",
11400
11418
  "apple_maps": "Apple Maps",
@@ -11412,6 +11430,10 @@ function CroutonLocalization(language) {
11412
11430
  "distance": "Entfernung",
11413
11431
  "all meetings": "Alle Meetings",
11414
11432
  'upcoming meetings': "Nächste 24 Stunden",
11433
+ "favorites": "Favoriten",
11434
+ "choose one": "Auswählen:",
11435
+ "widen search": "Suche ausweiten",
11436
+ "cancel search": "Abbrechen",
11415
11437
  },
11416
11438
  'el-GR': {
11417
11439
  "days_of_the_week": ["", "Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"],
@@ -11457,7 +11479,9 @@ function CroutonLocalization(language) {
11457
11479
  "all": "",
11458
11480
  "menu": "Μενού",
11459
11481
  "search for meetings": "Αναζήτηση ομάδων",
11482
+ 'search by location': 'Αναζήτηση ανά τοποθεσία',
11460
11483
  "show meetings near...": "Εμφάνιση ομάδων κοντά σε..",
11484
+ "closest meetings": "Πλησιέστερες Συναντήσεις",
11461
11485
  "filter meetings": "Φίλτραρε τις ομάδες",
11462
11486
  "visible meeting list": "Λίστα ορατών ομάδων",
11463
11487
  "enter a city or zip code": "Εισαγάγετε μια πόλη ή ταχυδρομικό κώδικα",
@@ -11469,7 +11493,6 @@ function CroutonLocalization(language) {
11469
11493
  "report update": "Ανέφερε ενημέρωση",
11470
11494
  "filter by visibility": "Φίλτραρε ανα ορατές ομάδες",
11471
11495
  "open search dialog": "’νοιξε αναζήτηση",
11472
- "go": "Έναρξη",
11473
11496
  "get_directions": "Λάβετε οδηγίες",
11474
11497
  "select_map_app": "Διαλέξτε εφαρμογή χάρτη",
11475
11498
  "apple_maps": "Χάρτες Apple",
@@ -11504,6 +11527,10 @@ function CroutonLocalization(language) {
11504
11527
  "meets virtually and in person": "Διαδικτυακή και φυσική ομάδα",
11505
11528
  "all meetings": "Όλες οι ομάδες",
11506
11529
  "upcoming meetings": "Προσεχείς ομάδες",
11530
+ "favorites": "Αγαπημένα",
11531
+ "choose one": "Επιλέξτε ένα:",
11532
+ "widen search": "Διεύρυνση αναζήτησης",
11533
+ "cancel search": "Ακύρωση αναζήτησης",
11507
11534
  },
11508
11535
  "en-AU": {
11509
11536
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11520,7 +11547,7 @@ function CroutonLocalization(language) {
11520
11547
  "formats": "Formats",
11521
11548
  "map": "Map",
11522
11549
  "neighborhood": "Neighbourhood",
11523
- "near_me": "Find nearby meetings",
11550
+ "near_me": "Find closest meetings",
11524
11551
  "text_search": "Find meetings there",
11525
11552
  "click_search": "Find meetings near to a point on the map",
11526
11553
  "languages": "Languages",
@@ -11549,7 +11576,9 @@ function CroutonLocalization(language) {
11549
11576
  'all': 'All',
11550
11577
  'menu': 'Menu',
11551
11578
  'search for meetings': 'Search for meetings',
11579
+ 'search by location': 'Search by Location',
11552
11580
  'show meetings near...': 'Show meetings near...',
11581
+ 'closest meetings': "Closest Meetings",
11553
11582
  'filter meetings': 'Filter meetings',
11554
11583
  'visible meeting list': 'Visible meetings as list',
11555
11584
  'enter a city or zip code': 'Enter a city and state',
@@ -11572,6 +11601,10 @@ function CroutonLocalization(language) {
11572
11601
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11573
11602
  "sorted by distance": "Sorted by Distance",
11574
11603
  "address_lookup_fail": "The address could not be found. Please try again.",
11604
+ "favorites": "Favorites",
11605
+ "choose one": "Select one:",
11606
+ "widen search": "Widen Search",
11607
+ "cancel search": "Cancel Search",
11575
11608
  },
11576
11609
  "en-CA": {
11577
11610
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11588,7 +11621,7 @@ function CroutonLocalization(language) {
11588
11621
  "formats": "Formats",
11589
11622
  "map": "Map",
11590
11623
  "neighborhood": "Neighborhood",
11591
- "near_me": "Find nearby meetings",
11624
+ "near_me": "Find closest meetings",
11592
11625
  "text_search": "Find meetings there",
11593
11626
  "click_search": "Find meetings near to a point on the map",
11594
11627
  "pan_and_zoom": "Pan + Zoom",
@@ -11617,7 +11650,9 @@ function CroutonLocalization(language) {
11617
11650
  'all': 'All',
11618
11651
  'menu': 'Menu',
11619
11652
  'search for meetings': 'Search for meetings',
11653
+ 'search by location': 'Search by Location',
11620
11654
  'show meetings near...': 'Show meetings near...',
11655
+ 'closest meetings': "Closest Meetings",
11621
11656
  'filter meetings': 'Filter meetings',
11622
11657
  'visible meeting list': 'Visible meetings as list',
11623
11658
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11641,6 +11676,10 @@ function CroutonLocalization(language) {
11641
11676
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11642
11677
  "sorted by distance": "Sorted by Distance",
11643
11678
  "address_lookup_fail": "The address could not be found. Please try again.",
11679
+ "favorites": "Favorites",
11680
+ "choose one": "Select one:",
11681
+ "widen search": "Widen Search",
11682
+ "cancel search": "Cancel Search",
11644
11683
  },
11645
11684
  "en-NZ": {
11646
11685
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11657,7 +11696,7 @@ function CroutonLocalization(language) {
11657
11696
  "formats": "Formats",
11658
11697
  "map": "Map",
11659
11698
  "neighborhood": "Neighborhood",
11660
- "near_me": "Find nearby meetings",
11699
+ "near_me": "Find closest meetings",
11661
11700
  "text_search": "Find meetings there",
11662
11701
  "click_search": "Find meetings near to a point on the map",
11663
11702
  "pan_and_zoom": "Pan + Zoom",
@@ -11686,7 +11725,9 @@ function CroutonLocalization(language) {
11686
11725
  'all': 'All',
11687
11726
  'menu': 'Menu',
11688
11727
  'search for meetings': 'Search for meetings',
11728
+ 'search by location': 'Search by Location',
11689
11729
  'show meetings near...': 'Show meetings near...',
11730
+ 'closest meetings': "Closest Meetings",
11690
11731
  'filter meetings': 'Filter meetings',
11691
11732
  'visible meeting list': 'Visible meetings as list',
11692
11733
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11710,6 +11751,10 @@ function CroutonLocalization(language) {
11710
11751
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11711
11752
  "sorted by distance": "Sorted by Distance",
11712
11753
  "address_lookup_fail": "The address could not be found. Please try again.",
11754
+ "favorites": "Favorites",
11755
+ "choose one": "Select one:",
11756
+ "widen search": "Widen Search",
11757
+ "cancel search": "Cancel Search",
11713
11758
  },
11714
11759
  "en-UK": {
11715
11760
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11726,7 +11771,7 @@ function CroutonLocalization(language) {
11726
11771
  "formats": "Formats",
11727
11772
  "map": "Map",
11728
11773
  "neighborhood": "Neighborhood",
11729
- "near_me": "Find nearby meetings",
11774
+ "near_me": "Find closest meetings",
11730
11775
  "text_search": "Find meetings there",
11731
11776
  "click_search": "Find meetings near to a point on the map",
11732
11777
  "pan_and_zoom": "Pan + Zoom",
@@ -11756,7 +11801,9 @@ function CroutonLocalization(language) {
11756
11801
  'menu': "Menu",
11757
11802
  "bmlt2ics": "Add to your calendar",
11758
11803
  'search for meetings': 'Search for meetings',
11804
+ 'search by location': 'Search by Location',
11759
11805
  'show meetings near...': 'Show meetings near...',
11806
+ 'closest meetings': "Closest Meetings",
11760
11807
  'filter meetings': 'Filter meetings',
11761
11808
  'visible meeting list': 'Visible meetings as list',
11762
11809
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11779,6 +11826,10 @@ function CroutonLocalization(language) {
11779
11826
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11780
11827
  "sorted by distance": "Sorted by Distance",
11781
11828
  "address_lookup_fail": "The address could not be found. Please try again.",
11829
+ "favorites": "Favorites",
11830
+ "choose one": "Select one:",
11831
+ "widen search": "Widen Search",
11832
+ "cancel search": "Cancel Search",
11782
11833
  },
11783
11834
 
11784
11835
  "en-US": {
@@ -11796,7 +11847,7 @@ function CroutonLocalization(language) {
11796
11847
  "formats": "Formats",
11797
11848
  "map": "Map",
11798
11849
  "neighborhood": "Neighborhood",
11799
- "near_me": "Find nearby meetings",
11850
+ "near_me": "Find closest meetings",
11800
11851
  "text_search": "Find meetings there",
11801
11852
  "click_search": "Find meetings near to a point on the map",
11802
11853
  "pan_and_zoom": "Pan + Zoom",
@@ -11825,7 +11876,9 @@ function CroutonLocalization(language) {
11825
11876
  'all': 'All',
11826
11877
  'menu': "Menu",
11827
11878
  'search for meetings': 'Search for meetings',
11879
+ 'search by location': 'Search by Location',
11828
11880
  'show meetings near...': 'Show meetings near...',
11881
+ 'closest meetings': "Closest Meetings",
11829
11882
  'filter meetings': 'Filter meetings',
11830
11883
  'visible meeting list': 'Visible meetings as list',
11831
11884
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11872,6 +11925,10 @@ function CroutonLocalization(language) {
11872
11925
  "more info": "More Info",
11873
11926
  "all meetings": "All Meetings",
11874
11927
  'upcoming meetings': "Upcoming Meetings",
11928
+ "favorites": "Favorites",
11929
+ "choose one": "Select one:",
11930
+ "widen search": "Widen Search",
11931
+ "cancel search": "Cancel Search",
11875
11932
  },
11876
11933
  "es-US": {
11877
11934
  "days_of_the_week": ["", "Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
@@ -11918,7 +11975,9 @@ function CroutonLocalization(language) {
11918
11975
  'all': 'Todos',
11919
11976
  'menu': "Menú",
11920
11977
  'search for meetings': 'Buscar reuniones',
11978
+ 'search by location': 'Buscar por ubicación',
11921
11979
  'show meetings near...': 'Mostrar reuniones cercanas...',
11980
+ 'closest meetings': 'Reuniones más cercanas',
11922
11981
  'filter meetings': 'Filtrar reuniones',
11923
11982
  'visible meeting list': 'Listado visible de reuniones',
11924
11983
  'enter a city or zip code': 'Introduce una ciudad o un código postal',
@@ -11942,6 +12001,10 @@ function CroutonLocalization(language) {
11942
12001
  "zoomed-out-message": "No podemos buscar reuniones en toda la zona. Por favor, acérquese o haga una nueva búsqueda.",
11943
12002
  "sorted by distance": "Ordenado por distancia",
11944
12003
  "address_lookup_fail": "The address could not be found. Please try again.",
12004
+ "favorites": "Favoritos",
12005
+ "choose one": "Elige uno:",
12006
+ "widen search": "Búsqueda amplia",
12007
+ "cancel search": "Cancelar búsqueda",
11945
12008
  },
11946
12009
  "fa-IR": {
11947
12010
  "days_of_the_week": ["", 'یَکشَنب', 'دوشَنبه', 'سه‌شنبه', 'چهار شنبه', 'پَنج شَنبه', 'جُمعه', 'شَنبه'],
@@ -11994,7 +12057,9 @@ function CroutonLocalization(language) {
11994
12057
  "all": "همه",
11995
12058
  "menu": " منوی",
11996
12059
  "search for meetings": "جستجوی جلسه ها",
12060
+ 'search by location': 'جستجو بر اساس مکان',
11997
12061
  "show meetings near...": "نمایش جلسات نزدیک",
12062
+ "closest meetings": "نزدیک ترین ملاقات ها",
11998
12063
  "filter meetings": "فیلتر جلسات",
11999
12064
  "visible meeting list": "جلسات قابل مشاهده به عنوان لیست",
12000
12065
  "enter a city or zip code": "شهر یا کد پستی را وارد کنید",
@@ -12005,7 +12070,6 @@ function CroutonLocalization(language) {
12005
12070
  "meeting details": "جزئیات جلسه",
12006
12071
  "report update": "گزارش به‌روزرسانی",
12007
12072
  "filter by visibility": "فقط این جلسات را فهرست کنید",
12008
- "go": "برو",
12009
12073
  "distance": "فاصله",
12010
12074
  "get_directions": "دریافت مسیر",
12011
12075
  "select_map_app": "انتخاب برنامه نقشه",
@@ -12024,6 +12088,10 @@ function CroutonLocalization(language) {
12024
12088
  'comments': 'توضیحات',
12025
12089
  'group details': 'نمایش گروه',
12026
12090
  "address_lookup_fail": "آدرس پیدا نشد. لطفا دوباره تلاش کنید.",
12091
+ "favorites": "مورد علاقه",
12092
+ "choose one": "یکی را انتخاب کنید",
12093
+ "widen search": "جستجوی گسترده",
12094
+ "cancel search": "لغو جستجو",
12027
12095
  },
12028
12096
  "fr-CA": {
12029
12097
  "days_of_the_week": ["", "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
@@ -12069,7 +12137,9 @@ function CroutonLocalization(language) {
12069
12137
  "all": "Tout",
12070
12138
  "menu": "Menu",
12071
12139
  "search for meetings": "Rechercher des réunions",
12140
+ 'search by location': 'Recherche par localisation',
12072
12141
  "show meetings near...": "Afficher les réunions près de...",
12142
+ "closest meetings": "Réunions les plus proches",
12073
12143
  "filter meetings": "Filtrer les réunions",
12074
12144
  "visible meeting list": "Liste des réunions visibles",
12075
12145
  "enter a city or zip code": "Entrer une ville ou un code postal",
@@ -12092,6 +12162,10 @@ function CroutonLocalization(language) {
12092
12162
  "waze_desc": "Ouvrir dans l'application Waze",
12093
12163
  "sorted by distance": "Trié par distance",
12094
12164
  "address_lookup_fail": "L'adresse est introuvable. Veuillez réessayer.",
12165
+ "favorites": "Favoris",
12166
+ "choose one": "Choisis-en un",
12167
+ "widen search": "Recherche élargie",
12168
+ "cancel search": "Annuler la recherche",
12095
12169
  },
12096
12170
  "it-IT": {
12097
12171
  "days_of_the_week": ["", "Domenica", " Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"],
@@ -12137,7 +12211,9 @@ function CroutonLocalization(language) {
12137
12211
  'all': 'Tutti',
12138
12212
  'menu': "Menu",
12139
12213
  'search for meetings': 'Search for meetings',
12214
+ 'search by location': 'Cerca per posizione',
12140
12215
  'show meetings near...': 'Mostra incontri nelle vicinanze..',
12216
+ 'closest meetings': "Riunioni più ravvicinati",
12141
12217
  'filter meetings': 'Filtrare le riunioni',
12142
12218
  'visible meeting list': 'Elenco riunioni visibile',
12143
12219
  'enter a city or zip code': 'Inserire una città o un codice postale',
@@ -12160,6 +12236,10 @@ function CroutonLocalization(language) {
12160
12236
  "waze_desc": "Apri nell'app Waze",
12161
12237
  "sorted by distance": "Ordinati per distanza",
12162
12238
  "address_lookup_fail": "L'indirizzo non è stato trovato. Per favore riprova.",
12239
+ "favorites": "Preferiti",
12240
+ "choose one": "Scegline uno",
12241
+ "widen search": "Ricerca larga",
12242
+ "cancel search": "Annulla ricerca",
12163
12243
  },
12164
12244
  "nl-NL": {
12165
12245
  "days_of_the_week": ["", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
@@ -12205,6 +12285,7 @@ function CroutonLocalization(language) {
12205
12285
  'all': 'All',
12206
12286
  'menu': "Menu",
12207
12287
  'search for meetings': 'Search for meetings',
12288
+ 'search by location': 'Search by Location',
12208
12289
  'show meetings near...': 'Show meetings near...',
12209
12290
  'filter meetings': 'Filter meetings',
12210
12291
  'visible meeting list': 'Visible meetings as list',
@@ -12272,6 +12353,7 @@ function CroutonLocalization(language) {
12272
12353
  'all': 'All',
12273
12354
  'menu': "Menu",
12274
12355
  'search for meetings': 'Search for meetings',
12356
+ 'search by location': 'Search by Location',
12275
12357
  'show meetings near...': 'Show meetings near...',
12276
12358
  'filter meetings': 'Filter meetings',
12277
12359
  'visible meeting list': 'Visible meetings as list',
@@ -12295,6 +12377,10 @@ function CroutonLocalization(language) {
12295
12377
  "waze_desc": "Otwórz w aplikacji Waze",
12296
12378
  "sorted by distance": "Posortowane według odległości",
12297
12379
  "address_lookup_fail": "The address could not be found. Please try again.",
12380
+ "favorites": "Ulubione",
12381
+ "choose one": "Wybierz jedną",
12382
+ "widen search": "Widen Search",
12383
+ "cancel search": "Cancel Search",
12298
12384
  },
12299
12385
  "pt-BR": {
12300
12386
  "days_of_the_week": ["", "Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado"],
@@ -12341,6 +12427,7 @@ function CroutonLocalization(language) {
12341
12427
  'menu': "Menu",
12342
12428
  "bmlt2ics": "Add to your calendar",
12343
12429
  'search for meetings': 'Search for meetings',
12430
+ 'search by location': 'Search by Location',
12344
12431
  'show meetings near...': 'Show meetings near...',
12345
12432
  'filter meetings': 'Filter meetings',
12346
12433
  'visible meeting list': 'Visible meetings as list',
@@ -12363,6 +12450,9 @@ function CroutonLocalization(language) {
12363
12450
  "waze_desc": "Abrir no aplicativo Waze",
12364
12451
  "sorted by distance": "Classificado por distância",
12365
12452
  "address_lookup_fail": "The address could not be found. Please try again.",
12453
+ "favorites": "Favoritos",
12454
+ "widen search": "Widen Search",
12455
+ "cancel search": "Cancel Search",
12366
12456
  },
12367
12457
  "ru-RU": {
12368
12458
  "days_of_the_week": ["", "Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"],
@@ -12409,7 +12499,9 @@ function CroutonLocalization(language) {
12409
12499
  'menu': "Меню",
12410
12500
  "bmlt2ics": "Добавить в календарь",
12411
12501
  'search for meetings': 'Поиск собраний',
12502
+ 'search by location': 'Поиск по местонахождению',
12412
12503
  'show meetings near...': 'Показывать собрания рядом с...',
12504
+ 'closest meetings': 'Ближайшие встречи',
12413
12505
  'filter meetings': 'Фильтровать собрания',
12414
12506
  'visible meeting list': 'Собрания в виде списка',
12415
12507
  'enter a city or zip code': 'Введите город или почтовый индек',
@@ -12419,7 +12511,6 @@ function CroutonLocalization(language) {
12419
12511
  'meeting details': "Подробности собрания",
12420
12512
  'report update': "Report an Update",
12421
12513
  'filter by visibility': "List only these meetings",
12422
- 'go': "Go!",
12423
12514
  "distance": "Расстояние",
12424
12515
  "get_directions": "Проложить маршрут",
12425
12516
  "select_map_app": "Выбрать приложение карт",
@@ -12431,6 +12522,10 @@ function CroutonLocalization(language) {
12431
12522
  "waze_desc": "Открыть в приложении Waze",
12432
12523
  "sorted by distance": "Сортировка по расстоянию",
12433
12524
  "address_lookup_fail": "Адрес не найден. Пожалуйста, попробуйте еще раз.",
12525
+ "favorites": "Избранное",
12526
+ "choose one": "Выбери одну",
12527
+ "widen search": "Расширить поиск",
12528
+ "cancel search": "Отмена поиска",
12434
12529
  },
12435
12530
  "sk": {
12436
12531
  "days_of_the_week": ["", "Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"],
@@ -12470,7 +12565,9 @@ function CroutonLocalization(language) {
12470
12565
  "all": "Akékoľvek",
12471
12566
  "menu": "Menu",
12472
12567
  "search for meetings": "Hľadať stretnutia",
12568
+ 'search by location': 'Vyhľadávanie podľa lokality',
12473
12569
  "show meetings near...": "Stretnutia v iných mestách",
12570
+ "closest meetings": "Najbližšie stretnutia",
12474
12571
  "filter meetings": "Filter pre jazyk, formát atď.",
12475
12572
  "visible meeting list": "Viditeľné stretnutia ako tabuľka",
12476
12573
  "enter a city or zip code": "Mesto alebo PSČ",
@@ -12481,7 +12578,6 @@ function CroutonLocalization(language) {
12481
12578
  "meeting details": "Podrobnosti o stretnutí",
12482
12579
  "report update": "Nahlásiť aktualizáciu",
12483
12580
  "filter by visibility": "Zobraziť iba stretnutia, ktoré sú práve na mape",
12484
- "go": "Ísť!",
12485
12581
  "get_directions": "Získať trasu",
12486
12582
  "select_map_app": "Vyberte aplikáciu pre mapy",
12487
12583
  "apple_maps": "Apple Maps",
@@ -12495,6 +12591,10 @@ function CroutonLocalization(language) {
12495
12591
  "zoomed-out-message": "Nemôžeme prehľadať celú oblasť pre stretnutia. Prosím, priblížte alebo vykonajte nové vyhľadávanie.",
12496
12592
  "sorted by distance": "Zoradené podľa vzdialenosti",
12497
12593
  "address_lookup_fail": "Adresa sa nenašla. Skúste to znova prosím.",
12594
+ "favorites": "Obľúbené",
12595
+ "choose one": "Vyber si jeden",
12596
+ "widen search": "Rozšíriť vyhľadávanie",
12597
+ "cancel search": "Zrušiť vyhľadávanie",
12498
12598
  },
12499
12599
  "sv-SE": {
12500
12600
  "days_of_the_week": ["", "Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"],
@@ -12540,6 +12640,7 @@ function CroutonLocalization(language) {
12540
12640
  'all': 'All',
12541
12641
  'menu': "Menu",
12542
12642
  'search for meetings': 'Search for meetings',
12643
+ 'search by location': 'Search by Location',
12543
12644
  'show meetings near...': 'Show meetings near...',
12544
12645
  'filter meetings': 'Filter meetings',
12545
12646
  'visible meeting list': 'Visible meetings as list',
@@ -12668,6 +12769,9 @@ function CroutonHandlebarsExtensions() {
12668
12769
  ? options.fn(this)
12669
12770
  : options.inverse(this);
12670
12771
  });
12772
+ crouton_Handlebars.registerHelper('format_list_style', function(data, options) {
12773
+ return crouton.config.format_list_style === 'formatNames' ? 'formatNames' : 'formatKeys'
12774
+ });
12671
12775
  crouton_Handlebars.registerHelper('groupsConfigured', function(data, options) {
12672
12776
  if (crouton.config.groups) {
12673
12777
  return getTrueResult(options, this);
@@ -12679,8 +12783,8 @@ function CroutonHandlebarsExtensions() {
12679
12783
  * @deprecated Since version 3.12.2, will be removed in a future version.
12680
12784
  */
12681
12785
  crouton_Handlebars.registerHelper('isVirtual', function(data, options) {
12682
- return ((data['venue_type'] === venueType.HYBRID || data['venue_type'] === venueType.VIRTUAL) || ((inArray(getMasterFormatId('HY', data), getFormats(data)) && !inArray(getMasterFormatId('TC', data), getFormats(data)))
12683
- || inArray(getMasterFormatId('VM', data), getFormats(data))))
12786
+ return ((data['venue_type'] === venueType.HYBRID || data['venue_type'] === venueType.VIRTUAL) || ((getFormats(data).includes(getMasterFormatId('HY', data)) && !getFormats(data).includes(getMasterFormatId('TC', data)))
12787
+ || getFormats(data).includes(getMasterFormatId('VM', data))))
12684
12788
  && (data['virtual_meeting_link'] || data['phone_meeting_number'] || data['virtual_meeting_additional_info']) ? getTrueResult(options, this) : getFalseResult(options, this);
12685
12789
  });
12686
12790
 
@@ -12688,83 +12792,85 @@ function CroutonHandlebarsExtensions() {
12688
12792
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12689
12793
  */
12690
12794
  crouton_Handlebars.registerHelper('isVirtualOnly', function(data, options) {
12691
- return data['venue_type'] === venueType.VIRTUAL || inArray(getMasterFormatId('VM', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12795
+ return data['venue_type'] === venueType.VIRTUAL || getFormats(data).includes(getMasterFormatId('VM', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12692
12796
  });
12693
12797
 
12694
12798
  /**
12695
12799
  * @deprecated Since version 3.12.2 will be removed in a future version.
12696
12800
  */
12697
12801
  crouton_Handlebars.registerHelper('isHybrid', function(data, options) {
12698
- return data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12802
+ return data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12699
12803
  });
12700
12804
 
12701
12805
  /**
12702
12806
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12703
12807
  */
12704
12808
  crouton_Handlebars.registerHelper('isHybridOnly', function(data, options) {
12705
- return data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12809
+ return data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12706
12810
  });
12707
12811
 
12708
12812
  crouton_Handlebars.registerHelper('isTemporarilyClosed', function(data, options) {
12709
- return inArray(getMasterFormatId('TC', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12813
+ return getFormats(data).includes(getMasterFormatId('TC', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12710
12814
  });
12711
12815
 
12712
12816
  crouton_Handlebars.registerHelper('isNotTemporarilyClosed', function(data, options) {
12713
- return !inArray(getMasterFormatId('TC', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12817
+ return !getFormats(data).includes(getMasterFormatId('TC', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12714
12818
  });
12715
12819
 
12716
12820
  /**
12717
12821
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12718
12822
  */
12719
12823
  crouton_Handlebars.registerHelper('isInPersonOrHybrid', function(data, options) {
12720
- return data['venue_type'] !== venueType.VIRTUAL && !inArray(getMasterFormatId('VM', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12824
+ return data['venue_type'] !== venueType.VIRTUAL && !getFormats(data).includes(getMasterFormatId('VM', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12721
12825
  });
12722
12826
 
12723
12827
  /**
12724
12828
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12725
12829
  */
12726
12830
  crouton_Handlebars.registerHelper('isInPersonOnly', function(data, options) {
12727
- return data['venue_type'] === venueType.IN_PERSON || (!inArray(getMasterFormatId('VM', data), getFormats(data))
12728
- && !inArray(getMasterFormatId('HY', data), getFormats(data))) ? getTrueResult(options, this) : getFalseResult(options, this);
12831
+ return data['venue_type'] === venueType.IN_PERSON || (!getFormats(data).includes(getMasterFormatId('VM', data))
12832
+ && !getFormats(data).includes(getMasterFormatId('HY', data))) ? getTrueResult(options, this) : getFalseResult(options, this);
12729
12833
  });
12730
12834
 
12731
12835
  /**
12732
12836
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12733
12837
  */
12734
12838
  crouton_Handlebars.registerHelper('isVirtualOrHybrid', function(data, options) {
12735
- return (data['venue_type'] === venueType.VIRTUAL || data['venue_type'] === venueType.HYBRID) || inArray(getMasterFormatId('VM', data), getFormats(data))
12736
- || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12839
+ return (data['venue_type'] === venueType.VIRTUAL || data['venue_type'] === venueType.HYBRID) || getFormats(data).includes(getMasterFormatId('VM', data))
12840
+ || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12737
12841
  });
12738
12842
 
12739
12843
  crouton_Handlebars.registerHelper('hasFormats', function(formats, data, options) {
12740
- var allFound = false;
12741
- var formatsResponse = data['formats'].split(",")
12742
- var formatsParam = formats.split(",");
12844
+ const formatsResponse = data['formats'].split(",")
12845
+ const formatsParam = formats.split(",");
12743
12846
  for(var i = 0;i < formatsParam.length;i++) {
12744
- allFound = inArray(formatsParam[i], formatsResponse);
12847
+ if (!formatsResponse.includes(formatsParam[i]))
12848
+ return getFalseResult(options, this);
12745
12849
  }
12746
-
12747
- return allFound ? getTrueResult(options, this) : getFalseResult(options, this);
12850
+ return getTrueResult(options, this);
12748
12851
  });
12749
12852
  crouton_Handlebars.registerHelper('temporarilyClosed', function(data, options) {
12750
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('TC', data)) !== undefined) {
12751
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('TC', data))['description'];
12853
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('TC', data));
12854
+ if (found !== undefined) {
12855
+ return found['description'];
12752
12856
  } else {
12753
12857
  return crouton.localization.getWord("FACILITY IS TEMPORARILY CLOSED");
12754
12858
  }
12755
12859
  });
12756
12860
 
12757
12861
  crouton_Handlebars.registerHelper('meetsVirtually', function(data, options) {
12758
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('VM', data)) !== undefined) {
12759
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('VM', data))['description'];
12862
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('VM', data));
12863
+ if (found !== undefined) {
12864
+ return found['description'];
12760
12865
  } else {
12761
12866
  return crouton.localization.getWord("MEETS VIRTUALLY");
12762
12867
  }
12763
12868
  });
12764
12869
 
12765
12870
  crouton_Handlebars.registerHelper('meetsHybrid', function(data, options) {
12766
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('HY', data)) !== undefined) {
12767
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('HY', data))['description'];
12871
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('HY', data));
12872
+ if (found !== undefined) {
12873
+ return found['description'];
12768
12874
  } else {
12769
12875
  return crouton.localization.getWord("MEETS VIRTUALLY AND IN PERSON");
12770
12876
  }
@@ -12815,6 +12921,18 @@ function CroutonHandlebarsExtensions() {
12815
12921
  return new crouton_Handlebars.SafeString("<a href='tel:" + text + "' target='_blank'>" + text + "</a>");
12816
12922
  });
12817
12923
 
12924
+ function isFavorite(meeting) {
12925
+ const localStorageKey = "crouton-favorites";
12926
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
12927
+ return favorites.includes(meeting.root_server_uri + "_" + meeting.id_bigint);
12928
+ }
12929
+ crouton_Handlebars.registerHelper('favoriteIcon', function(meeting, options) {
12930
+ return new crouton_Handlebars.SafeString("<span id='crouton-favorite-" + meeting.id_bigint + "' class='crouton-favorite glyphicon glyphicon-heart" + (!isFavorite(meeting) ? "-empty" : "") + "'></span>");
12931
+ });
12932
+
12933
+ crouton_Handlebars.registerHelper('isFavorite', function(meeting, options) {
12934
+ return new crouton_Handlebars.SafeString(isFavorite(meeting) ? 1 : 0);
12935
+ });
12818
12936
  crouton_Handlebars.registerHelper('ifEquals', function(arg1, arg2, options) {
12819
12937
  return (arg1 === arg2) ? options.fn(this) : options.inverse(this);
12820
12938
  });
@@ -12890,8 +13008,31 @@ function CroutonHandlebarsExtensions() {
12890
13008
  <br/>
12891
13009
  {{/if}}
12892
13010
  `);
13011
+ crouton_Handlebars.registerPartial('formatNames', `
13012
+ {{#each formats_expanded}}
13013
+ <a
13014
+ class="bmlt-formats btn btn-primary btn-xs"
13015
+ title=""
13016
+ data-html="true"
13017
+ tabindex="0"
13018
+ data-trigger="focus"
13019
+ role="button"
13020
+ data-toggle="popover"
13021
+ data-original-title=""
13022
+ data-placement="{{{getWord 'bootstrap-popover-placement'}}}"
13023
+ data-content="{{description}}">
13024
+ <span class="glyphicon glyphicon-search"
13025
+ aria-hidden="true"
13026
+ data-toggle="popover"
13027
+ data-trigger="focus"
13028
+ data-html="true"
13029
+ role="button"></span>{{ name }}
13030
+ </a>
13031
+ {{/each}}
13032
+ `
13033
+ )
12893
13034
  crouton_Handlebars.registerPartial('formatKeys', `
12894
- {{#if this.formats}}
13035
+ {{#if this.formats}}
12895
13036
  <a
12896
13037
  class="bmlt-formats btn btn-primary btn-xs"
12897
13038
  title=""
@@ -12913,7 +13054,6 @@ function CroutonHandlebarsExtensions() {
12913
13054
  {{/if}}
12914
13055
  `
12915
13056
  )
12916
-
12917
13057
  crouton_Handlebars.registerPartial('observerLine', `
12918
13058
  {{#if (hasObserverLine name phone email) }}
12919
13059
  <div class='observerLine'>{{getWord "Contact"}}: {{name}} <a href='tel:{{phone}}'>{{phone}}</a> <a href='mailto:{{email}}'>{{email}}</a></div>
@@ -13344,8 +13484,10 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13344
13484
  + ((stack1 = lookupProperty(helpers,"each").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"grouping_buttons") : stack1),{"name":"each","hash":{},"fn":container.program(2, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":6,"column":4},"end":{"line":8,"column":13}}})) != null ? stack1 : "")
13345
13485
  + ((stack1 = lookupProperty(helpers,"each").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"formattype_grouping_buttons") : stack1),{"name":"each","hash":{},"fn":container.program(3, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":9,"column":4},"end":{"line":11,"column":13}}})) != null ? stack1 : "")
13346
13486
  + ((stack1 = lookupProperty(helpers,"if").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"map_page") : stack1),{"name":"if","hash":{},"fn":container.program(4, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":12,"column":4},"end":{"line":14,"column":11}}})) != null ? stack1 : "")
13347
- + "\n"
13348
- + ((stack1 = lookupProperty(helpers,"each").call(alias1,(depth0 != null ? lookupProperty(depth0,"dropdownData") : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":16,"column":4},"end":{"line":25,"column":13}}})) != null ? stack1 : "")
13487
+ + " <div class=\"bmlt-button-container\"><a id=\"crouton_favorites_button\" tabindex=0 class=\"croutonControlButton btn btn-primary btn-sm\">"
13488
+ + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(alias1,"Favorites",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":15,"column":135},"end":{"line":15,"column":158}}}))
13489
+ + "</a></div>\n\n"
13490
+ + ((stack1 = lookupProperty(helpers,"each").call(alias1,(depth0 != null ? lookupProperty(depth0,"dropdownData") : depth0),{"name":"each","hash":{},"fn":container.program(5, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":17,"column":4},"end":{"line":26,"column":13}}})) != null ? stack1 : "")
13349
13491
  + " </div>\n";
13350
13492
  },"1":function(container,depth0,helpers,partials,data) {
13351
13493
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13370,8 +13512,8 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13370
13512
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13371
13513
  + "\" tabindex=0 data-field=\""
13372
13514
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"title") : depth0), depth0))
13373
- + "\" class=\"groupingButton groupingButtonLogic btn btn-primary btn-sm\">"
13374
- + alias2((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"title") : depth0),{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":7,"column":186},"end":{"line":7,"column":208}}}))
13515
+ + "\" class=\"groupingButton croutonControlButton groupingButtonLogic btn btn-primary btn-sm\">"
13516
+ + alias2((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"title") : depth0),{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":7,"column":207},"end":{"line":7,"column":229}}}))
13375
13517
  + "</a></div>\n";
13376
13518
  },"3":function(container,depth0,helpers,partials,data) {
13377
13519
  var alias1=container.lambda, alias2=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13385,7 +13527,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13385
13527
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13386
13528
  + "\"tabindex=0 data-field=\""
13387
13529
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13388
- + "\" class=\"groupingButton groupingButtonLogic btn btn-primary btn-sm\">"
13530
+ + "\" class=\"groupingButton croutonControlButton groupingButtonLogic btn btn-primary btn-sm\">"
13389
13531
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"title") : depth0), depth0))
13390
13532
  + "</a></div>\n";
13391
13533
  },"4":function(container,depth0,helpers,partials,data) {
@@ -13396,8 +13538,8 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13396
13538
  return undefined
13397
13539
  };
13398
13540
 
13399
- return " <div class=\"bmlt-button-container\"><a id=\"groupingButton_embeddedMapPage\" tabindex=0 data-field=\"embeddedMapPage\" class=\"groupingButton btn btn-primary btn-sm\">"
13400
- + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"map",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":13,"column":168},"end":{"line":13,"column":185}}}))
13541
+ return " <div class=\"bmlt-button-container\"><a id=\"groupingButton_embeddedMapPage\" tabindex=0 data-field=\"embeddedMapPage\" class=\"groupingButton croutonControlButton btn btn-primary btn-sm\">"
13542
+ + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"map",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":13,"column":189},"end":{"line":13,"column":206}}}))
13401
13543
  + "</a></div>\n";
13402
13544
  },"5":function(container,depth0,helpers,partials,data,blockParams,depths) {
13403
13545
  var stack1, helper, alias1=container.escapeExpression, alias2=depth0 != null ? depth0 : (container.nullContext || {}), alias3=container.hooks.helperMissing, alias4="function", lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13410,17 +13552,17 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13410
13552
  return " <div class=\"bmlt-dropdown-container\">\n <select class=\"crouton-select filter-dropdown\" style=\"width:"
13411
13553
  + alias1(container.lambda(((stack1 = (depths[1] != null ? lookupProperty(depths[1],"config") : depths[1])) != null ? lookupProperty(stack1,"dropdown_width") : stack1), depth0))
13412
13554
  + ";\" data-placeholder=\""
13413
- + alias1(((helper = (helper = lookupProperty(helpers,"placeholder") || (depth0 != null ? lookupProperty(depth0,"placeholder") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"placeholder","hash":{},"data":data,"loc":{"start":{"line":18,"column":116},"end":{"line":18,"column":131}}}) : helper)))
13555
+ + alias1(((helper = (helper = lookupProperty(helpers,"placeholder") || (depth0 != null ? lookupProperty(depth0,"placeholder") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"placeholder","hash":{},"data":data,"loc":{"start":{"line":19,"column":116},"end":{"line":19,"column":131}}}) : helper)))
13414
13556
  + "\" data-pointer=\""
13415
- + alias1(((helper = (helper = lookupProperty(helpers,"pointer") || (depth0 != null ? lookupProperty(depth0,"pointer") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"pointer","hash":{},"data":data,"loc":{"start":{"line":18,"column":147},"end":{"line":18,"column":158}}}) : helper)))
13557
+ + alias1(((helper = (helper = lookupProperty(helpers,"pointer") || (depth0 != null ? lookupProperty(depth0,"pointer") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"pointer","hash":{},"data":data,"loc":{"start":{"line":19,"column":147},"end":{"line":19,"column":158}}}) : helper)))
13416
13558
  + "\" id="
13417
- + alias1(((helper = (helper = lookupProperty(helpers,"elementId") || (depth0 != null ? lookupProperty(depth0,"elementId") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"elementId","hash":{},"data":data,"loc":{"start":{"line":18,"column":163},"end":{"line":18,"column":176}}}) : helper)))
13559
+ + alias1(((helper = (helper = lookupProperty(helpers,"elementId") || (depth0 != null ? lookupProperty(depth0,"elementId") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"elementId","hash":{},"data":data,"loc":{"start":{"line":19,"column":163},"end":{"line":19,"column":176}}}) : helper)))
13418
13560
  + ">\n <option value=\"a-\">"
13419
- + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"all",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":19,"column":25},"end":{"line":19,"column":42}}}))
13561
+ + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"all",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":20,"column":25},"end":{"line":20,"column":42}}}))
13420
13562
  + " "
13421
- + alias1(((helper = (helper = lookupProperty(helpers,"placeholder") || (depth0 != null ? lookupProperty(depth0,"placeholder") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"placeholder","hash":{},"data":data,"loc":{"start":{"line":19,"column":43},"end":{"line":19,"column":58}}}) : helper)))
13563
+ + alias1(((helper = (helper = lookupProperty(helpers,"placeholder") || (depth0 != null ? lookupProperty(depth0,"placeholder") : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"placeholder","hash":{},"data":data,"loc":{"start":{"line":20,"column":43},"end":{"line":20,"column":58}}}) : helper)))
13422
13564
  + "</option>\n"
13423
- + ((stack1 = lookupProperty(helpers,"each").call(alias2,(lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias3).call(alias2,(depth0 != null ? lookupProperty(depth0,"uniqueData") : depth0),((stack1 = (depths[1] != null ? lookupProperty(depths[1],"meetings") : depths[1])) != null ? lookupProperty(stack1,"meetingData") : stack1),{"name":"call","hash":{},"data":data,"loc":{"start":{"line":20,"column":14},"end":{"line":20,"column":55}}}),{"name":"each","hash":{},"fn":container.program(6, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":20,"column":6},"end":{"line":22,"column":15}}})) != null ? stack1 : "")
13565
+ + ((stack1 = lookupProperty(helpers,"each").call(alias2,(lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias3).call(alias2,(depth0 != null ? lookupProperty(depth0,"uniqueData") : depth0),((stack1 = (depths[1] != null ? lookupProperty(depths[1],"meetings") : depths[1])) != null ? lookupProperty(stack1,"meetingData") : stack1),{"name":"call","hash":{},"data":data,"loc":{"start":{"line":21,"column":14},"end":{"line":21,"column":55}}}),{"name":"each","hash":{},"fn":container.program(6, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":21,"column":6},"end":{"line":23,"column":15}}})) != null ? stack1 : "")
13424
13566
  + " </select>\n </div>\n";
13425
13567
  },"6":function(container,depth0,helpers,partials,data,blockParams,depths) {
13426
13568
  var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13431,9 +13573,9 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13431
13573
  };
13432
13574
 
13433
13575
  return " <option value=\"a-"
13434
- + alias3((lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias2).call(alias1,(depths[1] != null ? lookupProperty(depths[1],"objectPointer") : depths[1]),depth0,{"name":"call","hash":{},"data":data,"loc":{"start":{"line":21,"column":24},"end":{"line":21,"column":54}}}))
13576
+ + alias3((lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias2).call(alias1,(depths[1] != null ? lookupProperty(depths[1],"objectPointer") : depths[1]),depth0,{"name":"call","hash":{},"data":data,"loc":{"start":{"line":22,"column":24},"end":{"line":22,"column":54}}}))
13435
13577
  + "\">"
13436
- + alias3((lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias2).call(alias1,(depths[1] != null ? lookupProperty(depths[1],"optionName") : depths[1]),depth0,{"name":"call","hash":{},"data":data,"loc":{"start":{"line":21,"column":56},"end":{"line":21,"column":83}}}))
13578
+ + alias3((lookupProperty(helpers,"call")||(depth0 && lookupProperty(depth0,"call"))||alias2).call(alias1,(depths[1] != null ? lookupProperty(depths[1],"optionName") : depths[1]),depth0,{"name":"call","hash":{},"data":data,"loc":{"start":{"line":22,"column":56},"end":{"line":22,"column":83}}}))
13437
13579
  + "</option>\n";
13438
13580
  },"7":function(container,depth0,helpers,partials,data) {
13439
13581
  var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13443,9 +13585,9 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13443
13585
  return undefined
13444
13586
  };
13445
13587
 
13446
- return ((stack1 = (lookupProperty(helpers,"ifEquals")||(depth0 && lookupProperty(depth0,"ifEquals"))||container.hooks.helperMissing).call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"view_by") : stack1),"weekdays",{"name":"ifEquals","hash":{},"fn":container.program(8, data, 0),"inverse":container.program(9, data, 0),"data":data,"loc":{"start":{"line":30,"column":4},"end":{"line":34,"column":17}}})) != null ? stack1 : "")
13588
+ return ((stack1 = (lookupProperty(helpers,"ifEquals")||(depth0 && lookupProperty(depth0,"ifEquals"))||container.hooks.helperMissing).call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"view_by") : stack1),"weekdays",{"name":"ifEquals","hash":{},"fn":container.program(8, data, 0),"inverse":container.program(9, data, 0),"data":data,"loc":{"start":{"line":31,"column":4},"end":{"line":35,"column":17}}})) != null ? stack1 : "")
13447
13589
  + " <ul class=\"nav nav-tabs\">\n"
13448
- + ((stack1 = lookupProperty(helpers,"each").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"day_sequence") : stack1),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":21}}})) != null ? stack1 : "")
13590
+ + ((stack1 = lookupProperty(helpers,"each").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"day_sequence") : stack1),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":37,"column":12},"end":{"line":39,"column":21}}})) != null ? stack1 : "")
13449
13591
  + " </ul>\n </div>\n";
13450
13592
  },"8":function(container,depth0,helpers,partials,data) {
13451
13593
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13456,7 +13598,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13456
13598
  };
13457
13599
 
13458
13600
  return " <div class=\"bmlt-page "
13459
- + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"css-direction",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":31,"column":30},"end":{"line":31,"column":57}}}))
13601
+ + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"css-direction",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":32,"column":30},"end":{"line":32,"column":57}}}))
13460
13602
  + " show\" id=\"nav-days\">\n";
13461
13603
  },"9":function(container,depth0,helpers,partials,data) {
13462
13604
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13467,7 +13609,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13467
13609
  };
13468
13610
 
13469
13611
  return " <div class=\"bmlt-page "
13470
- + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"css-direction",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":33,"column":30},"end":{"line":33,"column":57}}}))
13612
+ + container.escapeExpression((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"css-direction",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":34,"column":30},"end":{"line":34,"column":57}}}))
13471
13613
  + " hide\" id=\"nav-days\">\n";
13472
13614
  },"10":function(container,depth0,helpers,partials,data) {
13473
13615
  var alias1=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13480,7 +13622,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13480
13622
  return " <li><a href=\"#tab"
13481
13623
  + alias1(container.lambda(depth0, depth0))
13482
13624
  + "\" data-toggle=\"tab\">"
13483
- + alias1((lookupProperty(helpers,"getDayOfTheWeek")||(depth0 && lookupProperty(depth0,"getDayOfTheWeek"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"getDayOfTheWeek","hash":{},"data":data,"loc":{"start":{"line":37,"column":61},"end":{"line":37,"column":85}}}))
13625
+ + alias1((lookupProperty(helpers,"getDayOfTheWeek")||(depth0 && lookupProperty(depth0,"getDayOfTheWeek"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"getDayOfTheWeek","hash":{},"data":data,"loc":{"start":{"line":38,"column":61},"end":{"line":38,"column":85}}}))
13484
13626
  + "</a></li>\n";
13485
13627
  },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
13486
13628
  var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13492,10 +13634,38 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13492
13634
 
13493
13635
  return container.escapeExpression((lookupProperty(helpers,"startup")||(depth0 && lookupProperty(depth0,"startup"))||container.hooks.helperMissing).call(alias1,depth0,{"name":"startup","hash":{},"data":data,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":16}}}))
13494
13636
  + "\n"
13495
- + ((stack1 = lookupProperty(helpers,"if").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"header") : stack1),{"name":"if","hash":{},"fn":container.program(0, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":2,"column":0},"end":{"line":27,"column":7}}})) != null ? stack1 : "")
13637
+ + ((stack1 = lookupProperty(helpers,"if").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"header") : stack1),{"name":"if","hash":{},"fn":container.program(0, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":2,"column":0},"end":{"line":28,"column":7}}})) != null ? stack1 : "")
13496
13638
  + "\n"
13497
- + ((stack1 = lookupProperty(helpers,"if").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"has_tabs") : stack1),{"name":"if","hash":{},"fn":container.program(7, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":29,"column":0},"end":{"line":41,"column":7}}})) != null ? stack1 : "");
13639
+ + ((stack1 = lookupProperty(helpers,"if").call(alias1,((stack1 = (depth0 != null ? lookupProperty(depth0,"config") : depth0)) != null ? lookupProperty(stack1,"has_tabs") : stack1),{"name":"if","hash":{},"fn":container.program(7, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":30,"column":0},"end":{"line":42,"column":7}}})) != null ? stack1 : "");
13498
13640
  },"useData":true,"useDepths":true});
13641
+ this["hbs_Crouton"]["templates"]["locationSearch"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
13642
+ var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
13643
+ if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
13644
+ return parent[propertyName];
13645
+ }
13646
+ return undefined
13647
+ };
13648
+
13649
+ return "<button id=\"location-search-button\" style=\"width: auto\" class=\"location-search-button\" title=\""
13650
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Open Location Search Dialog",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":1,"column":94},"end":{"line":1,"column":135}}}))
13651
+ + "\">\n <span class=\"location-search-button-label\" style=\"position:initial;\">\n "
13652
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Search by location",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":3,"column":8},"end":{"line":3,"column":40}}}))
13653
+ + "\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-crosshair\" viewBox=\"0 0 16 16\" style=\"vertical-align: sub;\">\n <path d=\"M8.5.5a.5.5 0 0 0-1 0v.518A7 7 0 0 0 1.018 7.5H.5a.5.5 0 0 0 0 1h.518A7 7 0 0 0 7.5 14.982v.518a.5.5 0 0 0 1 0v-.518A7 7 0 0 0 14.982 8.5h.518a.5.5 0 0 0 0-1h-.518A7 7 0 0 0 8.5 1.018zm-6.48 7A6 6 0 0 1 7.5 2.02v.48a.5.5 0 0 0 1 0v-.48a6 6 0 0 1 5.48 5.48h-.48a.5.5 0 0 0 0 1h.48a6 6 0 0 1-5.48 5.48v-.48a.5.5 0 0 0-1 0v.48A6 6 0 0 1 2.02 8.5h.48a.5.5 0 0 0 0-1zM8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4\"/>\n </svg>\n </span>\n</button>\n<div id=\"bmlt_location_search_modal\" class=\"modal\" style=\"display: none;\">\n <div id=\"bmlt_location_search_content\" class=\"modal-content\" style=\"border-color:unset;\">\n <span id=\"close_location_search\" class=\"modal-close\">x</span>\n <div class=\"modal-title\">"
13654
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Search by location",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":12,"column":33},"end":{"line":12,"column":65}}}))
13655
+ + "</div>\n <div class=\"crouton-modal-search-page\">\n <div id=\"modal-location-search-box\" class=\"modal-search\">\n <div>\n <input id=\"bmlt-location-search-goto-text\" type=\"text\" class=\"crouton-goto-text\" autocomplete=\"off\"\n placeholder=\""
13656
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Enter a city or zip code",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":17,"column":33},"end":{"line":17,"column":71}}}))
13657
+ + "\">\n </div>\n <button id=\"bmlt-location-search-text-button\" class=\"filter-button\">"
13658
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"text_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":19,"column":84},"end":{"line":19,"column":109}}}))
13659
+ + "</button>\n </div>\n <div class=\"modal-search\">\n <button id=\"bmlt-location-search-nearbyMeetings\" class=\"filter-button\">"
13660
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"near_me",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":22,"column":87},"end":{"line":22,"column":108}}}))
13661
+ + "</button>\n </div>\n <div id=\"location-search-widen\" class=\"modal-search\">\n <button id=\"bmlt-location-search-widen\" class=\"filter-button\">"
13662
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Widen Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":25,"column":78},"end":{"line":25,"column":104}}}))
13663
+ + "</button>\n </div>\n <div>\n <!--<button id=\"location-search-close\" class=\"advanced-search-button\" style=\"float:left\">"
13664
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Close",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":28,"column":96},"end":{"line":28,"column":115}}}))
13665
+ + "</a>-->\n <button id=\"bmlt-location_search-cancel\" class=\"advanced-search-button\">"
13666
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Cancel Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":29,"column":88},"end":{"line":29,"column":115}}}))
13667
+ + "</button>\n </div>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n </div>\n</div>";
13668
+ },"useData":true});
13499
13669
  this["hbs_Crouton"]["templates"]["main"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
13500
13670
  var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
13501
13671
  if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
@@ -13692,11 +13862,11 @@ this["hbs_Crouton"]["templates"]["mapMenu"] = Handlebars.template({"0":function(
13692
13862
  + ((stack1 = lookupProperty(helpers,"each").call(alias2,((stack1 = (depth0 != null ? lookupProperty(depth0,"meetings") : depth0)) != null ? lookupProperty(stack1,"bydays") : stack1),{"name":"each","hash":{},"fn":container.program(4, data, 0, blockParams, depths),"inverse":container.noop,"data":data,"loc":{"start":{"line":36,"column":8},"end":{"line":38,"column":17}}})) != null ? stack1 : "")
13693
13863
  + " </table>\n </div>\n</div>\n<div id=\"geocoding_modal\" class=\"modal\" style=\"display: none;\">\n <div id=\"search_content\" class=\"modal-content\">\n <span class=\"modal-title\">"
13694
13864
  + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"Show meetings near...",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":44,"column":28},"end":{"line":44,"column":63}}}))
13695
- + "</span><span id=\"close_search\" class=\"modal-close\">x</span>\n <p></p>\n <div class=\"modal-search\">\n "
13696
- + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"Enter a city or zip code",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":47,"column":12},"end":{"line":47,"column":50}}}))
13697
- + "\n <input id=\"goto-text\" type=\"text\">\n <button id=\"goto-button\" class=\"filter-button\">"
13698
- + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"go",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":49,"column":59},"end":{"line":49,"column":75}}}))
13699
- + "</button>\n </div>\n </div>\n</div>\n\n";
13865
+ + "</span><span id=\"close_search\" class=\"modal-close\">x</span>\n <p></p>\n <div class=\"crouton-modal-search-page\">\n <div class=\"modal-search\">\n "
13866
+ + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"Enter a city or zip code",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":48,"column":16},"end":{"line":48,"column":54}}}))
13867
+ + "\n <div>\n <input id=\"goto-text\" class=\"crouton-goto-text\" type=\"text\" autocomplete=\"off\">\n </div>\n <button id=\"goto-button\" class=\"filter-button\">"
13868
+ + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"text_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":52,"column":63},"end":{"line":52,"column":88}}}))
13869
+ + "</button>\n </div>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n </div>\n</div>\n\n";
13700
13870
  },"usePartial":true,"useData":true,"useDepths":true});
13701
13871
  this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
13702
13872
  var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13710,13 +13880,13 @@ this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":
13710
13880
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Open Search Dialog",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":1,"column":58},"end":{"line":1,"column":90}}}))
13711
13881
  + "\">\n <span class=\"menu-button-label\" style=\"position:initial;\">"
13712
13882
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Search for meetings",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":2,"column":62},"end":{"line":2,"column":95}}}))
13713
- + "</span>\n</button>\n<div id=\"bmltsearch_modal\" class=\"modal\" style=\"display: none;\">\n <div id=\"bmltsearch_content\" class=\"modal-content\">\n <span id=\"close_search\" class=\"modal-close\">x</span>\n <div id=\"modal-search-page\">\n <div class=\"modal-title\">"
13883
+ + "</span>\n</button>\n<div id=\"bmltsearch_modal\" class=\"modal\" style=\"display: none;\">\n <div id=\"bmltsearch_content\" class=\"modal-content\">\n <span id=\"close_search\" class=\"modal-close\">x</span>\n <div class=\"crouton-modal-search-page\">\n <div class=\"modal-title\">"
13714
13884
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Search for meetings",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":8,"column":37},"end":{"line":8,"column":70}}}))
13715
13885
  + "</div>\n <div id=\"zoomed-out-message\" class=\"hide\">\n <p>"
13716
13886
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"zoomed-out-message",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":10,"column":19},"end":{"line":10,"column":51}}}))
13717
13887
  + "</p>\n </div>\n <div id=\"modal-search-box\" class=\"modal-search\">\n <input id=\"bmltsearch-goto-text\" type=\"text\"\n placeholder=\""
13718
13888
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Enter a city or zip code",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":14,"column":33},"end":{"line":14,"column":71}}}))
13719
- + "\" style=\"margin-bottom:5px;\">\n <button id=\"bmltsearch-text-button\" class=\"filter-button\">"
13889
+ + "\" class=\"crouton-goto-text\">\n <button id=\"bmltsearch-text-button\" class=\"filter-button\">"
13720
13890
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"text_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":15,"column":74},"end":{"line":15,"column":99}}}))
13721
13891
  + "</button>\n </div>\n <div class=\"modal-search\">\n <button id=\"bmltsearch-nearbyMeetings\" class=\"filter-button\">"
13722
13892
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"near_me",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":18,"column":77},"end":{"line":18,"column":98}}}))
@@ -13724,14 +13894,14 @@ this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":
13724
13894
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"click_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":21,"column":74},"end":{"line":21,"column":100}}}))
13725
13895
  + "</button>\n </div>\n <button id=\"show-search-parameters\" class=\"advanced-search-button\">"
13726
13896
  + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Adjust Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":23,"column":79},"end":{"line":23,"column":106}}}))
13727
- + "</button>\n </div>\n <div id=\"modal-seach-parameters\">\n <div class=\"modal-title\">"
13728
- + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Adjust Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":26,"column":37},"end":{"line":26,"column":64}}}))
13897
+ + "</button>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n <div id=\"modal-seach-parameters\">\n <div class=\"modal-title\">"
13898
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Adjust Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":27,"column":37},"end":{"line":27,"column":64}}}))
13729
13899
  + "</div>\n <input type=\"number\" id=\"search_parameter\" name=\"search_parameter\" maxlength=\"3\" size=\"3\">\n <p>"
13730
- + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"This number represents",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":28,"column":15},"end":{"line":28,"column":51}}}))
13900
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"This number represents",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":29,"column":15},"end":{"line":29,"column":51}}}))
13731
13901
  + ":</p>\n <input type=\"radio\" id=\"search_radius\" name=\"map_search_type\" value=\"radius\">\n <label id=\"search_radius_label\" for=\"search_radius\"></label><br>\n <input type=\"radio\" id=\"search_count\" name=\"map_search_type\" value=\"count\">\n <label for=\"search_count\">"
13732
- + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Approx. number of meetings in result",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":32,"column":38},"end":{"line":32,"column":88}}}))
13902
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Approx. number of meetings in result",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":33,"column":38},"end":{"line":33,"column":88}}}))
13733
13903
  + "</label><br>\n <button id=\"show-search-page\" class=\"advanced-search-button\">"
13734
- + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Back",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":33,"column":73},"end":{"line":33,"column":91}}}))
13904
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Back",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":34,"column":73},"end":{"line":34,"column":91}}}))
13735
13905
  + "</button>\n </div>\n </div>\n</div>";
13736
13906
  },"useData":true});
13737
13907
  this["hbs_Crouton"]["templates"]["meeting3ColumnRow"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
@@ -14038,7 +14208,9 @@ this["hbs_Crouton"]["templates"]["tableRows"] = Handlebars.template({"0":functio
14038
14208
  + alias3((lookupProperty(helpers,"formatDataFromArray")||(depth0 && lookupProperty(depth0,"formatDataFromArray"))||alias2).call(alias1,(depth0 != null ? lookupProperty(depth0,"venue_type_name") : depth0),{"name":"formatDataFromArray","hash":{},"data":data,"loc":{"start":{"line":15,"column":15},"end":{"line":15,"column":59}}}))
14039
14209
  + "\"\n data-weekdays=\""
14040
14210
  + alias3((lookupProperty(helpers,"formatDataPointer")||(depth0 && lookupProperty(depth0,"formatDataPointer"))||alias2).call(alias1,(depth0 != null ? lookupProperty(depth0,"formatted_day") : depth0),{"name":"formatDataPointer","hash":{},"data":data,"loc":{"start":{"line":16,"column":17},"end":{"line":16,"column":57}}}))
14041
- + "\">\n"
14211
+ + "\"\n data-favorite="
14212
+ + alias3((lookupProperty(helpers,"isFavorite")||(depth0 && lookupProperty(depth0,"isFavorite"))||alias2).call(alias1,depth0,{"name":"isFavorite","hash":{},"data":data,"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":35}}}))
14213
+ + ">\n"
14042
14214
  + ((stack1 = container.invokePartial(lookupProperty(partials,"tableDataRow"),depth0,{"name":"tableDataRow","data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
14043
14215
  + " </tr>\n";
14044
14216
  },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
@@ -14049,7 +14221,7 @@ this["hbs_Crouton"]["templates"]["tableRows"] = Handlebars.template({"0":functio
14049
14221
  return undefined
14050
14222
  };
14051
14223
 
14052
- return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"each","hash":{},"fn":container.program(0, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":1,"column":0},"end":{"line":19,"column":9}}})) != null ? stack1 : "");
14224
+ return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"each","hash":{},"fn":container.program(0, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":1,"column":0},"end":{"line":20,"column":9}}})) != null ? stack1 : "");
14053
14225
  },"usePartial":true,"useData":true});
14054
14226
  this["hbs_Crouton"]["templates"]["weekdays"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
14055
14227
  var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -14175,13 +14347,16 @@ var croutonDefaultTemplates = {
14175
14347
  </div>
14176
14348
  `,
14177
14349
  meeting_times_template: `
14178
- <div class="bmlt-day">{{this.formatted_day}}</div>
14350
+ <div class="bmlt-meeting-day-favorite">
14351
+ <div class="bmlt-day">{{this.formatted_day}}</div>
14352
+ <div class="favorite-icon">{{favoriteIcon this}}</div>
14353
+ </div>
14179
14354
  {{#ifEquals this.duration_time "24:00:00"}}
14180
14355
  <div class="bmlt-time-2">{{this.start_time_formatted}}</div>
14181
14356
  {{else}}
14182
14357
  <div class="bmlt-time-2">{{this.start_time_formatted}} - {{this.end_time_formatted}}</div>
14183
14358
  {{/ifEquals}}
14184
- {{> formatKeys }}
14359
+ {{> (format_list_style) }}
14185
14360
  <div class="bmlt-comments">{{formatLink this.formatted_comments}}</div>
14186
14361
  <div class="bmlt-observer">{{> (selectObserver) }}</div>
14187
14362
  `,
@@ -15277,16 +15452,20 @@ crouton_Handlebars.registerHelper("log", (x) => console.log(x));
15277
15452
  crouton_Handlebars.registerHelper('selectFormatPopup', () => "formatPopup");
15278
15453
  crouton_Handlebars.registerHelper('selectObserver', () => "observerTemplate");
15279
15454
 
15280
-
15455
+ /**
15456
+ * There must be exactly one crouton instance per page.
15457
+ * @param {*} config
15458
+ */
15281
15459
  function Crouton(config) {
15282
- var self = this;
15283
- self.mutex = false;
15460
+ const self = this;
15461
+ self.ready = false;
15284
15462
  self.filtering = false;
15285
15463
  self.masterFormatCodes = [];
15286
15464
  self.currentView = "weekday";
15287
15465
  self.distanceTabAllowed = false;
15466
+ self.favoritesOn = false;
15288
15467
  self.config = {
15289
- version: '4.1.12', // CroutonJS version for debugging
15468
+ version: '4.3.2', // CroutonJS version for debugging
15290
15469
  on_complete: null, // Javascript function to callback when data querying is completed.
15291
15470
  root_server: null, // The root server to use.
15292
15471
  placeholder_id: "bmlt-tabs", // The DOM id that will be used for rendering
@@ -15321,6 +15500,8 @@ function Crouton(config) {
15321
15500
  has_languages: false, // Shows the language dropdown
15322
15501
  has_common_needs: false, // Shows the Common Needs dropdown
15323
15502
  has_venues: true, // Shows the venue types dropdown
15503
+ has_favorites: false, // Shows the favorites button
15504
+ has_geolocation: false, // Shows the geolocation button in the table header
15324
15505
  has_meeting_count: false, // Shows the meeting count
15325
15506
  recurse_service_bodies: false,// Recurses service bodies when making service bodies request
15326
15507
  service_body: [], // Array of service bodies to return data for.
@@ -15363,7 +15544,6 @@ function Crouton(config) {
15363
15544
  tileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
15364
15545
  tileOptions: {
15365
15546
  attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
15366
- maxZoom: 18
15367
15547
  },
15368
15548
  minZoom: 6,
15369
15549
  maxZoom: 17,
@@ -15373,9 +15553,41 @@ function Crouton(config) {
15373
15553
  caption: false,
15374
15554
  groups: false,
15375
15555
  details_table: false,
15556
+ focusedMeetingPopupZoomLevel: 14,
15376
15557
  };
15377
15558
 
15378
15559
  self.setConfig(config);
15560
+ const body = jQuery("body");
15561
+ if (self.config['theme'] !== '') {
15562
+ body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
15563
+ }
15564
+ if (self.config['custom_css'] !== '') {
15565
+ body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
15566
+ }
15567
+ self.isIOSDevice = function() {
15568
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
15569
+ if (navigator.userAgentData.platform === 'iOS') {
15570
+ return true;
15571
+ }
15572
+ }
15573
+ const userAgent = navigator.userAgent || navigator.vendor || window.opera;
15574
+ const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
15575
+ const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && !window.MSStream;
15576
+ return isIOS || isIPadOS;
15577
+ }
15578
+
15579
+ self.isAndroidDevice = function() {
15580
+ return /Android/i.test(navigator.userAgent);
15581
+ }
15582
+ self.deviceType = self.isIOSDevice() ? 'ios' : (self.isAndroidDevice() ? 'android' : 'desktop');
15583
+
15584
+ /**
15585
+ * Do the lookups for the [crouton_map] shortcode
15586
+ * @param float latitude
15587
+ * @param float longitude
15588
+ * @param float width search width that will be sent to the server
15589
+ * @param boolean fitBounds
15590
+ */
15379
15591
  Crouton.prototype.searchByCoordinates = function(latitude, longitude, width, fitBounds=true) {
15380
15592
  const original_query = self.config['custom_query'];
15381
15593
  self.config['custom_query'] = (self.config['custom_query'] !== null ? self.config['custom_query'] : "")
@@ -15384,20 +15596,23 @@ function Crouton(config) {
15384
15596
  self.meetingSearch(function() {
15385
15597
  self.config.refresh_map=1;
15386
15598
  self.config.show_map = 1;
15387
- self.reset();
15599
+ jQuery("#" + self.config["placeholder_id"]).html("");
15388
15600
  self.render(false, fitBounds);
15389
15601
  });
15390
15602
  self.config['custom_query'] = original_query;
15391
15603
  };
15392
15604
 
15605
+ /**
15606
+ * Get the meeting list for the [bmlt_tab] shortcode.
15607
+ * @param string url
15608
+ * @param function cb
15609
+ * @returns Promise that returns when the server query finishes.
15610
+ */
15393
15611
  self.getMeetings = function(url,cb=null) {
15394
- var promises = [fetchJsonp(this.config['root_server'] + url).then(function(response) { return response.json(); })];
15612
+ const promises = [fetchJsonp(this.config['root_server'] + url).then(function(response) { return response.json(); })];
15395
15613
 
15396
15614
  if (self.config['extra_meetings'].length > 0) {
15397
- var extra_meetings_query = "";
15398
- for (var i = 0; i < self.config['extra_meetings'].length; i++) {
15399
- extra_meetings_query += "&meeting_ids[]=" + self.config["extra_meetings"][i];
15400
- }
15615
+ const extra_meetings_query = self.config['extra_meetings'].reduce((query,item) => query + "&meeting_ids[]=" + item, '');
15401
15616
  const regex = /&services\[\]=\d+/;
15402
15617
  url = url.replace(regex, '');
15403
15618
  promises.push(fetchJsonp(self.config['root_server'] + url + extra_meetings_query).then(function (response) { return response.json(); }));
@@ -15405,38 +15620,34 @@ function Crouton(config) {
15405
15620
 
15406
15621
  return Promise.all(promises)
15407
15622
  .then(function(data) {
15408
- var mainMeetings = data[0];
15409
- var extraMeetings;
15410
- var jsonMeetings = JSON.stringify(mainMeetings['meetings']);
15411
- if (data.length === 2) {
15412
- extraMeetings = data[1];
15413
- }
15414
- if (jsonMeetings === "{}" || jsonMeetings === "[]") {
15415
- var fullUrl = self.config['root_server'] + url
15623
+ const mainMeetings = data[0];
15624
+ if (mainMeetings['meetings'].length === 0) {
15625
+ const fullUrl = self.config['root_server'] + url
15416
15626
  console.log("Could not find any meetings for the criteria specified with the query <a href=\"" + fullUrl + "\" target=_blank>" + fullUrl + "</a>");
15417
15627
  jQuery('#' + self.config['placeholder_id']).html("No meetings found.");
15418
15628
  self.meetingData = [];
15419
15629
  self.formatsData = [];
15420
- self.mutex = false;
15421
15630
  cb && cb();
15631
+ self.fireReady();
15422
15632
  return;
15423
15633
  }
15634
+ // TODO: is this necessary? why not just add this to the query?
15424
15635
  if (self.config['exclude_zip_codes'].length > 0) {
15425
- mainMeetings['meetings'] = mainMeetings['meetings'].filter(function(m) { return !inArray(m['location_postal_code_1'], self.config['exclude_zip_codes']); } );
15636
+ mainMeetings['meetings'] = mainMeetings['meetings'].filter(function(m) { return !self.config['exclude_zip_codes'].includes(m['location_postal_code_1']); } );
15426
15637
  }
15427
15638
  self.meetingData = mainMeetings['meetings'];
15428
15639
  self.formatsData = mainMeetings['formats'];
15429
- if (extraMeetings) {
15430
- self.meetingData = self.meetingData.concat(extraMeetings['meetings']);
15640
+ // extra meetings
15641
+ if (data.length === 2) {
15642
+ self.meetingData = self.meetingData.concat(data[1]['meetings']);
15431
15643
  }
15432
15644
  cb && cb();
15433
- self.mutex = false;
15645
+ self.fireReady();
15434
15646
  });
15435
15647
  };
15436
- self.mutex = true;
15437
15648
 
15438
15649
  self.meetingSearch = function(cb=null) {
15439
- var url = '/client_interface/jsonp/?switcher=GetSearchResults&get_used_formats&lang_enum=' + self.config['short_language'];
15650
+ let url = '/client_interface/jsonp/?switcher=GetSearchResults&get_used_formats&lang_enum=' + self.config['short_language'];
15440
15651
 
15441
15652
  if (self.config['formats']) {
15442
15653
  url += self.config['formats'].reduce(function(prev,id) {
@@ -15465,9 +15676,7 @@ function Crouton(config) {
15465
15676
  url += self.config['custom_query'] + '&sort_keys=' + self.config['sort_keys'];
15466
15677
  return self.getMeetings(url,cb);
15467
15678
  } else if (self.config['service_body'].length > 0) {
15468
- for (var i = 0; i < self.config['service_body'].length; i++) {
15469
- url += '&services[]=' + self.config['service_body'][i];
15470
- }
15679
+ url = self.config['service_body'].reduce((curr,item)=>curr+'&services[]='+item, url);
15471
15680
 
15472
15681
  if (self.config['recurse_service_bodies']) {
15473
15682
  url += '&recursive=1';
@@ -15480,31 +15689,47 @@ function Crouton(config) {
15480
15689
  return new Promise(function(resolve, reject) {
15481
15690
  self.meetingData = [];
15482
15691
  self.formatsData = [];
15483
- self.mutex = false;
15484
15692
  resolve([]);
15693
+ self.fireReady();
15485
15694
  });
15486
15695
  }
15696
+ }
15697
+ self.readyListener = [];
15698
+ /**
15699
+ * Add a listener for the event that the crouton instance has loaded its data and we can now go ahead and execute the shortcodes.
15700
+ * Generally, each listener corresponds to different shortcode. The main ones go over the render method, but there are also listeners
15701
+ * for [meeting_count] etc.
15702
+ * @param function callback
15703
+ */
15704
+ self.listenForReady = function(callback) {
15705
+ if (self.ready) callback();
15706
+ else self.readyListener.push(callback);
15487
15707
  };
15488
-
15489
- self.lock = function(callback) {
15490
- var self = this;
15491
- var lock_id = setInterval(function() {
15492
- if (!self.mutex) {
15493
- clearInterval(lock_id);
15494
- callback();
15495
- }
15496
- }, 100);
15708
+ /**
15709
+ * FIres the event that crouton is loaded and ready.
15710
+ */
15711
+ self.fireReady = function() {
15712
+ self.ready = true;
15713
+ self.readyListener.forEach(function(callback) {
15714
+ callback();
15715
+ });
15716
+ self.readyListener = [];
15497
15717
  };
15498
-
15499
- self.dayTab = function(day_id) {
15718
+ /**
15719
+ * Bring up the appropriate tab based on the meeting id.
15720
+ * This is only used when a meeting is selected in the msp. I consider this bloat, it is superceded by the meeting details popup available in the marker text.
15721
+ * @param string id meeting id.
15722
+ */
15723
+ self.dayTabFromId = function(id) {
15724
+ const day_id = self.meetingData.find((m)=>m.id_bigint == id).weekday_tinyint;
15500
15725
  self.hideAllPages();
15501
15726
  jQuery('.nav-tabs a[href="#tab' + day_id + '"]').tab('show');
15502
15727
  jQuery("#" + day_id).removeClass("hide").addClass("show");
15503
15728
  };
15504
- self.dayTabFromId = function(id) {
15505
- day_id = self.meetingData.find((m)=>m.id_bigint == id).weekday_tinyint;
15506
- self.dayTab(day_id);
15507
- };
15729
+ /**
15730
+ * Show a page from the table (weekday, distance, city...)
15731
+ * @param string id selector, id attribute of the HtML
15732
+ */
15508
15733
  self.showPage = function (id) {
15509
15734
  jQuery(id+" .bmlt-data-row-placeholder").each(function() {
15510
15735
  const meetingId = this.dataset.meetingid;
@@ -15517,7 +15742,11 @@ function Crouton(config) {
15517
15742
  self.addStripes();
15518
15743
  jQuery(id).removeClass("hide").addClass("show");
15519
15744
  };
15520
-
15745
+ /**
15746
+ * Bring up a view.
15747
+ * @param string viewName abstract viewname (weekday, distance, city...)
15748
+ * @param int showingNow number of items currently being displayed on the page
15749
+ */
15521
15750
  self.showView = function (viewName, showingNow=0) {
15522
15751
  if (viewName === 'distance' && !self.distanceTabAllowed) {
15523
15752
  viewName = self.config.groups ? 'city' : 'day';
@@ -15578,6 +15807,7 @@ function Crouton(config) {
15578
15807
  self.dayView();
15579
15808
  return;
15580
15809
  }
15810
+ self.currentView = field;
15581
15811
  self.lowlightButton("#day");
15582
15812
  self.lowlightButton(".groupingButton");
15583
15813
  self.highlightButton("#groupingButton_" + field);
@@ -15620,8 +15850,12 @@ function Crouton(config) {
15620
15850
  jQuery(value).addClass((index % 2) ? 'oddRow' : 'evenRow');
15621
15851
  });
15622
15852
  }
15853
+ /**
15854
+ *
15855
+ * @returns a list of the IDs of meetings matching the current filters.
15856
+ */
15623
15857
  self.calcShowingNow = function() {
15624
- var showingNow = [];
15858
+ let showingNow = [];
15625
15859
  jQuery(".bmlt-data-row:not(.hide)").each(function (index, value) {
15626
15860
  const rowId = value.id.split("-");
15627
15861
  showingNow.push(rowId[rowId.length-1]);
@@ -15644,26 +15878,13 @@ function Crouton(config) {
15644
15878
  }
15645
15879
  });
15646
15880
  this.addStripes();
15647
- var showingNow = this.calcShowingNow();
15881
+ const showingNow = this.calcShowingNow();
15648
15882
  self.updateMeetingCount(showingNow);
15649
- self.updateFilters();
15650
- if (croutonMap) croutonMap.fillMap(showingNow);
15651
- self.showView(self.currentView, showingNow.length);
15883
+ self.updateFilters(showingNow);
15884
+ if (croutonMap) croutonMap.setFilteredIds(showingNow);
15885
+ if (self.currentView !== 'map') self.showView(self.currentView, showingNow.length);
15652
15886
  };
15653
- self.resetFilter = function () {
15654
- croutonMap.filterVisible(false);
15655
- if ((self.config.map_page && self.filtering) || self.config.show_map) croutonMap.fillMap();
15656
- self.filtering = false;
15657
- self.updateFilters();
15658
- self.updateMeetingCount();
15659
- jQuery(".filter-dropdown").val(null).trigger("change");
15660
- jQuery(".group-header").removeClass("hide");
15661
- jQuery(".meeting-group").removeClass("hide");
15662
- jQuery(".bmlt-data-row").removeClass("hide");
15663
- jQuery(".evenRow").removeClass("evenRow");
15664
- jQuery(".oddRow").removeClass("oddRow");
15665
- };
15666
- self.updateFilters = function() {
15887
+ self.updateFilters = function(showingNow) {
15667
15888
  if (!self.dropdownData) return;
15668
15889
  const getId = function (row) {return row.id.replace("meeting-data-row-", "")};
15669
15890
  // The options available for this filter have to take into account all other filters, but ignore the
@@ -15686,6 +15907,12 @@ function Crouton(config) {
15686
15907
  let showing = self.meetingData.filter((m) => !(hidden.includes(m.id_bigint)));
15687
15908
  dropdown.optionsShowing = dropdown.uniqueData(showing).map((o) => dropdown.optionName(o));
15688
15909
  });
15910
+ const favoritesDropdown = self.dropdownData.find((d) => d.elementId === "filter-dropdown-favorites");
15911
+ if (!favoritesDropdown || !self.shouldOfferFavorites(showingNow)) {
15912
+ jQuery("#crouton_favorites_button").addClass("hide");
15913
+ } else {
15914
+ jQuery("#crouton_favorites_button").removeClass("hide");
15915
+ }
15689
15916
  }
15690
15917
  self.renderStandaloneMap = function (selector, context, callback=null, fitBounds=true) {
15691
15918
  hbs_Crouton['localization'] = self.localization;
@@ -15693,40 +15920,14 @@ function Crouton(config) {
15693
15920
  self.setUpPartials();
15694
15921
  croutonMap.initialize(self.createBmltMapElement(),self.meetingData,context,null,fitBounds,callback,self.config['noMap']);
15695
15922
  }
15696
- self.retrieveGeolocation = function() {
15697
- return new Promise((resolve, reject) => {
15698
- if (window.storedGeolocation) {
15699
- resolve(window.storedGeolocation);
15700
- } else if (navigator.geolocation) {
15701
- navigator.geolocation.getCurrentPosition((position) => {
15702
- window.storedGeolocation = {
15703
- latitude: position.coords.latitude,
15704
- longitude: position.coords.longitude
15705
- };
15706
- resolve(window.storedGeolocation);
15707
- }, (error) => {
15708
- reject(new Error('Error getting geolocation: ' + error.message));
15709
- });
15710
- } else {
15711
- reject(new Error('Geolocation is not supported by this browser.'));
15712
- }
15713
- });
15714
- };
15715
- self.getCurrentLocation = function(callback) {
15716
- self.gretrieveGeolocation().then(position => {
15717
- callback(position);
15718
- }).catch(error => {
15719
- jQuery('.geo').removeClass("hide").addClass("show").html(`<p>${error.message}</p>`);
15720
- });
15721
- };
15722
15923
  self.renderView = function (selector, context, callback, fitBounds) {
15723
15924
  hbs_Crouton['localization'] = self.localization;
15724
- var template = hbs_Crouton.templates['main'];
15925
+ const template = hbs_Crouton.templates['main'];
15725
15926
  jQuery(selector).html(template(context));
15726
15927
  callback();
15727
15928
  };
15728
15929
  self.updateMeetingCount = function(showingNow=null) {
15729
- var self = this;
15930
+ const self = this;
15730
15931
  let meetingCount = self.meetingData.length;
15731
15932
  if (self.meetingCountCallback) self.meetingCountCallback(meetingCount);
15732
15933
  if (self.groupCountCallback) self.groupCountCallback(
@@ -15739,8 +15940,8 @@ function Crouton(config) {
15739
15940
  }
15740
15941
  self.showingNowCount = meetingCount;
15741
15942
  jQuery(".crouton_root_service_body").each(function() {
15742
- var text = "";
15743
- var field = 'name';
15943
+ let text = "";
15944
+ let field = 'name';
15744
15945
  if (this.dataset.field) field = this.dataset.field;
15745
15946
  if (self.config['service_body'].length > 0) {
15746
15947
  const sb = self.getServiceBodyDetails(self.config['service_body'][0]);
@@ -15750,19 +15951,17 @@ function Crouton(config) {
15750
15951
  });
15751
15952
  jQuery(addLive('#bmlt_tabs_meeting_count')).text(meetingCount);
15752
15953
  jQuery(addLive('#bmlt_tabs_group_count')).each(function(){
15753
- var filteredMeetings = self.meetingData;
15754
- if (showingNow!==null) filteredMeetings = self.meetingData.filter((m) => showingNow.includes(m.id_bigint));
15954
+ const filteredMeetings = (showingNow!==null) ? self.meetingData.filter((m) => showingNow.includes(m.id_bigint)) : self.meetingData;
15755
15955
  const groups = self.config.groups ? filteredMeetings : self.convertToGroups([...filteredMeetings]);
15756
- jQuery(this).text(arrayUnique(groups).length);
15956
+ jQuery(this).text([...new Set(groups)].length);
15757
15957
  });
15758
15958
  jQuery(addLive('#bmlt_tabs_service_body_names')).each(function() {
15759
- var filteredMeetings = self.meetingData;
15760
- if (showingNow!==null) filteredMeetings = self.meetingData.filter((m) => showingNow.includes(m.id_bigint));
15761
- var ids = getUniqueValuesOfKey(filteredMeetings, 'service_body_bigint');
15762
- var me = this;
15959
+ const filteredMeetings = (showingNow!==null) ? self.meetingData.filter((m) => showingNow.includes(m.id_bigint)) : self.meetingData;
15960
+ const ids = getUniqueValuesOfKey(filteredMeetings, 'service_body_bigint');
15961
+ const me = this;
15763
15962
  self.getServiceBodies(ids, false).then(function (service_bodies) {
15764
- var n = service_bodies.length;
15765
- var names = service_bodies.map((m)=>m['name']);
15963
+ const n = service_bodies.length;
15964
+ const names = service_bodies.map((m)=>m['name']);
15766
15965
  names.sort();
15767
15966
  var ret = "";
15768
15967
  if (n===1) {
@@ -15781,16 +15980,23 @@ function Crouton(config) {
15781
15980
  });
15782
15981
  }
15783
15982
  self.getServiceBodies = function(service_bodies_id, requires_parents=true) {
15784
- var url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetServiceBodies'
15785
- + (requires_parents ? '&parents=1' : '') + getServiceBodiesQueryString(service_bodies_id);
15983
+ const url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetServiceBodies'
15984
+ + (requires_parents ? '&parents=1' : '') + self.getServiceBodiesQueryString(service_bodies_id);
15786
15985
  return fetchJsonp(url)
15787
15986
  .then(function(response) {
15788
15987
  return response.json();
15789
15988
  });
15790
15989
  };
15791
15990
 
15991
+ self.getServiceBodiesQueryString = function(service_bodies_id) {
15992
+ let service_bodies_query = "";
15993
+ for (var x = 0; x < service_bodies_id.length; x++) {
15994
+ service_bodies_query += "&services[]=" + service_bodies_id[x];
15995
+ }
15996
+ return service_bodies_query;
15997
+ }
15792
15998
  self.getMasterFormats = function() {
15793
- var url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetFormats&lang_enum=en&key_strings[]=TC&key_strings[]=VM&key_strings[]=HY';
15999
+ const url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetFormats&lang_enum=en&key_strings[]=TC&key_strings[]=VM&key_strings[]=HY';
15794
16000
  return fetchJsonp(url)
15795
16001
  .then(function(response) {
15796
16002
  return response.json();
@@ -15812,16 +16018,16 @@ function Crouton(config) {
15812
16018
  self.handlebarMapOptions.lng = parseFloat(meetingDetailsData.longitude);
15813
16019
  return "<div id='bmlt-handlebars-map' class='bmlt-map'></div>"
15814
16020
  });
15815
- var parser = new DOMParser();
16021
+ const parser = new DOMParser();
15816
16022
 
15817
16023
  while (elements.length > 0) {
15818
- var element = elements.item(0);
16024
+ const element = elements.item(0);
15819
16025
  if (!element.firstChild) {
15820
16026
  console.log('<bmlt-handlebar> tag must have at least one child');
15821
16027
  element.remove();
15822
16028
  continue;
15823
16029
  }
15824
- var templateString = '';
16030
+ let templateString = '';
15825
16031
  if (element.firstChild.nodeType === 1) {
15826
16032
  if (!element.firstChild.firstChild || element.firstChild.firstChild.nodeType !== 3) {
15827
16033
  console.log('<bmlt-handlebar> tag: cannot find textnode');
@@ -15834,13 +16040,13 @@ function Crouton(config) {
15834
16040
  }
15835
16041
  var handlebarResult;
15836
16042
  try {
15837
- var template = crouton_Handlebars.compile(templateString);
16043
+ const template = crouton_Handlebars.compile(templateString);
15838
16044
  handlebarResult = template(meetingDetailsData);
15839
16045
  } catch (e) {
15840
16046
  console.log(e);
15841
16047
  handlebarResult = e.message;
15842
16048
  }
15843
- var htmlDecode = parser.parseFromString('<body>'+handlebarResult+'</body>', "text/html");
16049
+ const htmlDecode = parser.parseFromString('<body>'+handlebarResult+'</body>', "text/html");
15844
16050
  if (!htmlDecode.body || !htmlDecode.body.firstChild) {
15845
16051
  console.log('<bmlt-handlebar> tag: could not parse the Handlebars result');
15846
16052
  element.replaceWith('<bmlt-handlebar> tag: could not parse the Handlebars result');
@@ -15912,7 +16118,12 @@ function Crouton(config) {
15912
16118
  n = n.replace(/PM|pm/g, x => ampm['PM']);
15913
16119
  return n;
15914
16120
  }
15915
- self.enrichMeetings = function (meetingData) {
16121
+ /**
16122
+ * Take raw meeting data as returned from server adding values that should be conveniently displayed.
16123
+ * @param array meetingData
16124
+ * @returns the array with enriched data
16125
+ */
16126
+ self.enrichMeetings = function(meetingData) {
15916
16127
  var meetings = [];
15917
16128
 
15918
16129
  let queryStringChar = '?';
@@ -15943,8 +16154,8 @@ function Crouton(config) {
15943
16154
  meetingData[m]['day_of_the_week'] = meetingData[m]['start_time_raw'].isoWeekday() === 7 ? 1 : meetingData[m]['start_time_raw'].isoWeekday() + 1;
15944
16155
  meetingData[m]['formatted_day'] = self.localization.getDayOfTheWeekWord(meetingData[m]['day_of_the_week']);
15945
16156
 
15946
- var formats = meetingData[m]['formats'].split(",");
15947
- var formats_expanded = [];
16157
+ const formats = meetingData[m]['formats'].split(",");
16158
+ const formats_expanded = [];
15948
16159
  let formatRootServer = self.formatsData.filter((f)=>f['root_server_uri'] == meetingData[m]['root_server_uri']);
15949
16160
  meetingData[m]['wheelchair'] = false;
15950
16161
  for (var f = 0; f < formats.length; f++) {
@@ -15966,14 +16177,13 @@ function Crouton(config) {
15966
16177
 
15967
16178
  meetingData[m]['venue_type'] = parseInt(meetingData[m]['venue_type']);
15968
16179
  meetingData[m]['venue_type_name'] = getVenueTypeName(meetingData[m]);
15969
- meetingData[m]['formats_expanded'] = formats_expanded;
15970
- var addressParts = [
16180
+ meetingData[m]['formats_expanded'] = formats_expanded.sortByKey('name');
16181
+ const addressParts = [
15971
16182
  meetingData[m]['location_street'],
15972
16183
  meetingData[m]['location_municipality'].trim(),
15973
16184
  meetingData[m]['location_province'].trim(),
15974
16185
  meetingData[m]['location_postal_code_1'].trim()
15975
- ];
15976
- addressParts.clean();
16186
+ ].filter((value)=>value!=="");
15977
16187
  meetingData[m]['formatted_address'] = addressParts.join(", ");
15978
16188
  meetingData[m]['formatted_location_info'] =
15979
16189
  meetingData[m]['location_info'] != null
@@ -15992,7 +16202,7 @@ function Crouton(config) {
15992
16202
  }
15993
16203
  }
15994
16204
 
15995
- var serviceBodyInfo = self.getServiceBodyDetails(meetingData[m]['service_body_bigint'])
16205
+ const serviceBodyInfo = self.getServiceBodyDetails(meetingData[m]['service_body_bigint'])
15996
16206
  meetingData[m]['serviceBodyUrl'] = serviceBodyInfo["url"];
15997
16207
  meetingData[m]['serviceBodyPhone'] = serviceBodyInfo["helpline"];
15998
16208
  meetingData[m]['serviceBodyName'] = serviceBodyInfo["name"];
@@ -16000,7 +16210,7 @@ function Crouton(config) {
16000
16210
  meetingData[m]['serviceBodyContactEmail'] = serviceBodyInfo["contact_email"];
16001
16211
  meetingData[m]['serviceBodyType'] = self.localization.getServiceBodyType(serviceBodyInfo["type"]);
16002
16212
 
16003
- var parentBodyInfo = self.getServiceBodyDetails(serviceBodyInfo["parent_id"]);
16213
+ const parentBodyInfo = self.getServiceBodyDetails(serviceBodyInfo["parent_id"]);
16004
16214
  if (parentBodyInfo !== undefined) {
16005
16215
  meetingData[m]['parentServiceBodyId'] = serviceBodyInfo["parent_id"];
16006
16216
  meetingData[m]['parentServiceBodyUrl'] = parentBodyInfo["url"];
@@ -16029,7 +16239,27 @@ function Crouton(config) {
16029
16239
  return self.convertToGroups(meetings);
16030
16240
  }
16031
16241
  return meetings;
16032
- };
16242
+ }
16243
+ // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16244
+ const masterFormatVenueType = {
16245
+ IN_PERSON: "IN_PERSON",
16246
+ VIRTUAL: "VIRTUAL",
16247
+ }
16248
+
16249
+ function getVenueTypeName(data) {
16250
+ if (data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data))) {
16251
+ return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL), crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16252
+ } else if (data['venue_type'] === venueType.VIRTUAL || getFormats(data).includes(getMasterFormatId('VM', data))) {
16253
+ return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL)];
16254
+ } else {
16255
+ return [crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16256
+ }
16257
+ }
16258
+ /**
16259
+ * Convert from individual meetings to groups.
16260
+ * @param array meetings
16261
+ * @returns
16262
+ */
16033
16263
  self.convertToGroups = function(meetings) {
16034
16264
  if (!meetings || !meetings.length) return [];
16035
16265
  if (meetings[0].hasOwnProperty('membersOfGroup')) return meetings;
@@ -16076,6 +16306,11 @@ function Crouton(config) {
16076
16306
  });
16077
16307
  return groups;
16078
16308
  }
16309
+ /**
16310
+ * Update the distances displyed after geocoding or geolocation.
16311
+ * @param boolean initial
16312
+ * @returns
16313
+ */
16079
16314
  Crouton.prototype.updateDistances = function(initial=false) {
16080
16315
  const self = this;
16081
16316
  var knt = 0;
@@ -16110,8 +16345,8 @@ function Crouton(config) {
16110
16345
  });
16111
16346
  }
16112
16347
  const sorted = parent.children().sort(function (a, b) {
16113
- const idA =parseFloat( jQuery(a).data('meetingid').replace("meeting-data-row-", ""));
16114
- const idB =parseFloat( jQuery(b).data('meetingid').replace("meeting-data-row-", ""));
16348
+ const idA =parseFloat( (jQuery(a).data('meetingid') ?? jQuery(a).attr('id')).replace("meeting-data-row-", ""));
16349
+ const idB =parseFloat( (jQuery(b).data('meetingid') ?? jQuery(b).attr('id')).replace("meeting-data-row-", ""));
16115
16350
  const dataA = self.meetingData.find((m) => m.id_bigint==idA);
16116
16351
  const dataB = self.meetingData.find((m) => m.id_bigint==idB);
16117
16352
  const distanceA = dataA ? parseFloat(dataA['distance_in_km']) : Number.POSITIVE_INFINITY;
@@ -16143,8 +16378,6 @@ function Crouton(config) {
16143
16378
  ? "<td>{{> meetingStackedRow}}</td>"
16144
16379
  : hbs_Crouton.templates['meeting3ColumnRow'])
16145
16380
  );
16146
-
16147
-
16148
16381
  self.registerPartial("meetingDataTemplate", self.config['meeting_data_template']);
16149
16382
  self.registerPartial("meetingDataTemplate", self.config['meeting_data_template']);
16150
16383
  self.registerPartial("metaDataTemplate", self.config['metadata_template']);
@@ -16162,6 +16395,14 @@ function Crouton(config) {
16162
16395
  handlebarsExtensions.registerHelpers();
16163
16396
  handlebarsExtensions.registerPartials(self.config.groups);
16164
16397
  }
16398
+ self.getServiceBodyDetails = function(serviceBodyId) {
16399
+ return this.all_service_bodies.find((s)=>s['id'] === serviceBodyId)
16400
+ }
16401
+ /**
16402
+ * Calculate the distances sfter geocoding or geolocation, adding them to the meeting data.
16403
+ * @param boolean initial
16404
+ * @returns
16405
+ */
16165
16406
  self.calculateDistance = function(meetingData) {
16166
16407
  meetingData['distance'] = '';
16167
16408
  if (meetingData['venue_type'] != 2) {
@@ -16205,19 +16446,21 @@ function Crouton(config) {
16205
16446
  self.getUsedNext24 = function(meetings) {
16206
16447
  return [{name: 'Next24', value: 1}];
16207
16448
  }
16208
- self.isEmpty = function(obj) {
16209
- for (var key in obj) {
16210
- if(obj.hasOwnProperty(key))
16211
- return false;
16212
- }
16213
- return true;
16214
- };
16449
+ self.getUsedFavorites = function(meetings) {
16450
+ return [{name: 'Favorite', value: 1}]
16451
+ }
16215
16452
  self.createBmltMapElement = function() {
16216
16453
  if (!document.getElementById('bmlt-map')) {
16217
16454
  jQuery("#bmlt-tabs").before("<div id='bmlt-map' class='bootstrap-bmlt bmlt-map "+self.localization.getWord('css-direction')+" bmlt_map_container_div'></div>");
16218
16455
  }
16219
16456
  return 'bmlt-map';
16220
16457
  }
16458
+ self.createLocationSearchElement = function() {
16459
+ if (!document.getElementById('bmlt-location-search')) {
16460
+ jQuery("#bmlt-header").append("<div id='bmlt-location-search' class='bootstrap-bmlt bmlt-location-search "+self.localization.getWord('css-direction')+" bmlt_location_search_container_div'></div>");
16461
+ }
16462
+ return 'bmlt-location-search';
16463
+ }
16221
16464
  if (typeof window.croutonMap === 'undefined') {
16222
16465
  window.croutonMap = new MeetingMap(self.config);
16223
16466
  if (self.config['map_search']) self.searchMap();
@@ -16227,7 +16470,7 @@ function Crouton(config) {
16227
16470
  }
16228
16471
 
16229
16472
  Crouton.prototype.setConfig = function(config) {
16230
- var self = this;
16473
+ const self = this;
16231
16474
  const deprecatedNames = {
16232
16475
  button_filters: 'grouping_buttons',
16233
16476
  button_format_filters: 'formattype_grouping_buttons',
@@ -16288,43 +16531,27 @@ Crouton.prototype.setConfig = function(config) {
16288
16531
  console.log("Error parsing custom translations: " + e.message);
16289
16532
  }
16290
16533
  }
16291
- };
16292
-
16293
- Crouton.prototype.reset = function() {
16294
- var self = this;
16295
- jQuery("#custom-css").remove();
16296
- jQuery("#" + self.config["placeholder_id"]).html("");
16297
- };
16298
-
16299
- Crouton.prototype.doFilters = function() {
16300
- return this.filterMeetingsFromView();
16301
- }
16302
- Crouton.prototype.getServiceBodyDetails = function(serviceBodyId) {
16303
- var self = this;
16304
- for (var s = 0; s < self.all_service_bodies.length; s++) {
16305
- var service_body = self.all_service_bodies[s];
16306
- if (service_body['id'] === serviceBodyId) {
16307
- return service_body;
16308
- }
16309
- }
16534
+ if (self.config.format_list_style !== 'formatNames') self.config.format_list_style = 'formatKeys';
16310
16535
  }
16311
-
16536
+ /**
16537
+ * This supports the [bmlt_handlebars] shortcode, which allows a meeting's details to be inserted into a page.
16538
+ */
16312
16539
  Crouton.prototype.doHandlebars = function() {
16313
16540
  var elements = document.getElementsByTagName('bmlt-handlebar');
16314
16541
  if (elements.length === 0) {
16315
16542
  console.log('No <bmlt-handlebar> tags found');
16316
16543
  return;
16317
16544
  };
16318
- var self = this;
16319
- self.lock(function() {
16320
- if (self.isEmpty(self.meetingData)) {
16545
+ const self = this;
16546
+ self.listenForReady(function() {
16547
+ if (!self.meetingData || self.meetingData.length === 0) {
16321
16548
  for (let i = 0; i < elements.length; i++) {
16322
16549
  var element = elements.item(i);
16323
16550
  element.innerHTML = "Meeting not found!";
16324
16551
  }
16325
16552
  return;
16326
16553
  }
16327
- var promises = [self.getServiceBodies([self.meetingData[0]['service_body_bigint']])];
16554
+ const promises = [self.getServiceBodies([self.meetingData[0]['service_body_bigint']])];
16328
16555
  Promise.all(promises)
16329
16556
  .then(function(data) {
16330
16557
  hbs_Crouton['localization'] = self.localization;
@@ -16345,10 +16572,21 @@ Crouton.prototype.doHandlebars = function() {
16345
16572
  });
16346
16573
  });
16347
16574
  };
16348
-
16575
+ /**
16576
+ * Sometimes the logic in the map has to decide whether to let the map implementation (google or leaflet) do something, or just do the calculation
16577
+ * itself. So we have to ask crouton if the map is showing or not.
16578
+ * @returns boolean
16579
+ */
16580
+ Crouton.prototype.isEmbeddedMapShowing = function() {
16581
+ if (this.config['show_map']) return true;
16582
+ const embeddedMap = document.getElementById("byfield_embeddedMapPage");
16583
+ if (embeddedMap) {
16584
+ return !embeddedMap.classList.contains('hide');
16585
+ }
16586
+ return true;
16587
+ }
16349
16588
  Crouton.prototype.meetingModal = function(meetingId) {
16350
- let self = this;
16351
- this.openMeetingModal(self.meetingData.find((m) => m.id_bigint == meetingId));
16589
+ this.openMeetingModal(this.meetingData.find((m) => m.id_bigint == meetingId));
16352
16590
  return;
16353
16591
  }
16354
16592
  Crouton.prototype.openMeetingModal = function(meeting) {
@@ -16369,7 +16607,7 @@ Crouton.prototype.openMeetingModal = function(meeting) {
16369
16607
  croutonMap.loadPopupMap("bmlt-handlebars-map", meeting, {
16370
16608
  lat: parseFloat(meeting.latitude),
16371
16609
  lng: parseFloat(meeting.longitude),
16372
- zoom: 14
16610
+ zoom: self.config.focusedMeetingPopupZoomLevel ?? 14
16373
16611
  });
16374
16612
  let visibleMeetings = jQuery('.bmlt-data-row:visible');
16375
16613
  let index = -1;
@@ -16410,8 +16648,11 @@ Crouton.prototype.openMeetingModal = function(meeting) {
16410
16648
  mm.getElementsByClassName('modal-right').item(0).addEventListener("click", ev=>doSwipe("left"));
16411
16649
  }
16412
16650
  }
16651
+ /**
16652
+ * Execute the [crouton_map] shortcode.
16653
+ */
16413
16654
  Crouton.prototype.searchMap = function() {
16414
- var self = this;
16655
+ const self = this;
16415
16656
  self.distanceTabAllowed = true;
16416
16657
  if (!self.config.map_search || typeof self.config.map_search !== 'object') {
16417
16658
  self.config.map_search = {
@@ -16429,12 +16670,6 @@ Crouton.prototype.searchMap = function() {
16429
16670
  }
16430
16671
  self.config['map_page'] = false;
16431
16672
  self.config['show_map'] = false;
16432
- var body = jQuery("body");
16433
- if (self.config['theme'] !== '') {
16434
- body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
16435
- }
16436
-
16437
- body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
16438
16673
 
16439
16674
  self.meetingData = null;
16440
16675
  self.renderStandaloneMap("#" + self.config['placeholder_id'], {
@@ -16451,28 +16686,26 @@ Crouton.prototype.searchMap = function() {
16451
16686
  "location": {'latitude':0,'longitude':0,'zoom':10} // TODO: Where is this used?
16452
16687
  });
16453
16688
  }
16689
+ /**
16690
+ * This methods does the main work of creating the crouton table.
16691
+ * @param boolean doMeetingMap MeetingMap is the old name for the [bmlt_map] shortcode.
16692
+ * @param boolean fitBounds Expand the scaale and center of the map to contain all meetings.
16693
+ */
16454
16694
  Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16455
- var self = this;
16456
-
16457
- self.lock(function() {
16458
- var body = jQuery("body");
16459
- if (self.config['theme'] !== '') {
16460
- body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
16461
- }
16462
-
16463
- body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
16695
+ const self = this;
16464
16696
 
16465
- if (self.isEmpty(self.meetingData)) {
16697
+ self.listenForReady(function() {
16698
+ if (!self.meetingData || self.meetingData.length === 0) {
16466
16699
  jQuery('#please-wait').remove();
16467
16700
  self.showMessage("No meetings found for parameters specified.");
16468
16701
  if (self.config['refresh_map']) {
16469
- croutonMap.refreshMeetings(self.meetingData, fitBounds, true);
16702
+ croutonMap.refreshMeetings(self.meetingData, fitBounds);
16470
16703
  }
16471
16704
  return;
16472
16705
  }
16473
16706
 
16474
16707
  self.unique_service_bodies_ids = getUniqueValuesOfKey(self.meetingData, 'service_body_bigint').sort();
16475
- var promises = [self.getMasterFormats(), self.getServiceBodies(self.unique_service_bodies_ids)];
16708
+ const promises = [self.getMasterFormats(), self.getServiceBodies(self.unique_service_bodies_ids)];
16476
16709
  Promise.all(promises)
16477
16710
  .then(function(data) {
16478
16711
  self.all_service_bodies = [];
@@ -16509,7 +16742,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16509
16742
  var weekdaysData = [];
16510
16743
  while (day_counter < 7) {
16511
16744
  var day = self.config.day_sequence[day_counter];
16512
- var daysOfTheWeekMeetings = enrichedMeetingData.filterByObjectKeyValue('day_of_the_week', day);
16745
+ var daysOfTheWeekMeetings = enrichedMeetingData.filter((meeting)=>meeting['day_of_the_week'] == day);
16513
16746
  weekdaysData.push({
16514
16747
  "day": day,
16515
16748
  "meetings": daysOfTheWeekMeetings
@@ -16525,7 +16758,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16525
16758
  if (groupByName.startsWith('distance')) continue;
16526
16759
  var groupByData = getUniqueValuesOfKey(daysOfTheWeekMeetings, groupByName).sort();
16527
16760
  for (var i = 0; i < groupByData.length; i++) {
16528
- var groupByMeetings = daysOfTheWeekMeetings.filterByObjectKeyValue(groupByName, groupByData[i]);
16761
+ var groupByMeetings = daysOfTheWeekMeetings.filter((meeting)=>meeting[groupByName] == groupByData[i]);
16529
16762
  if (groupingButtonsData.hasOwnProperty(groupByName) && groupingButtonsData[groupByName].hasOwnProperty(groupByData[i])) {
16530
16763
  groupingButtonsData[groupByName][groupByData[i]] = groupingButtonsData[groupByName][groupByData[i]].concat(groupByMeetings);
16531
16764
  } else if (groupingButtonsData.hasOwnProperty(groupByName)) {
@@ -16600,7 +16833,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16600
16833
  self.dropdownData = [];
16601
16834
  if (self.config.has_days) self.dropdownData.push(
16602
16835
  {placeholder: self.localization.getWord('weekday'), pointer: 'weekdays', elementId: "filter-dropdown-weekdays",
16603
- uniqueData: (meetings) => sortListByList(getUniqueValuesOfKey(meetings, "formatted_day"), self.dayNamesSequenced),
16836
+ uniqueData: (meetings) => self.sortListByList(getUniqueValuesOfKey(meetings, "formatted_day"), self.dayNamesSequenced),
16604
16837
  objectPointer: convertToPunyCode, optionName: (s)=>s});
16605
16838
  if (self.config.has_states) self.dropdownData.push(
16606
16839
  {placeholder: self.localization.getWord('states'), pointer: 'States', elementId: "filter-dropdown-states",
@@ -16662,6 +16895,10 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16662
16895
  {placeholder: '', pointer: 'next24', elementId: "filter-dropdown-next24",
16663
16896
  uniqueData: (meetings) => self.getUsedNext24(meetings),
16664
16897
  objectPointer: (s)=>s.value, optionName: (s)=>s.name});
16898
+ if (self.config.has_favorites) self.dropdownData.push(
16899
+ {placeholder: '', pointer: 'favorite', elementId: "filter-dropdown-favorites",
16900
+ uniqueData: (meetings) => self.getUsedFavorites(meetings),
16901
+ objectPointer: (s)=>s.value, optionName: (s)=>s.name});
16665
16902
  let renderer = doMeetingMap ? self.renderStandaloneMap : self.renderView;
16666
16903
  renderer("#" + self.config['placeholder_id'], {
16667
16904
  "config": self.config,
@@ -16680,20 +16917,30 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16680
16917
  jQuery('#groupingButton_distance_in_km').addClass('hide');
16681
16918
  }
16682
16919
  self.addStripes();
16683
- self.calcShowingNow()
16920
+ const showingNow = self.calcShowingNow();
16684
16921
  self.updateMeetingCount();
16685
16922
  jQuery('#please-wait').remove();
16686
16923
  if (self.config['map_search'] != null || self.config['show_map']) {
16687
16924
  jQuery(".bmlt-data-row").css({cursor: "pointer"});
16688
16925
  jQuery(".bmlt-data-row").click(function (e) {
16689
- if (e.target.tagName !== 'A')
16926
+ if (e.target.tagName !== 'A' && !e.target.id.startsWith('crouton-favorite-')) {
16690
16927
  croutonMap.rowClick(parseInt(this.id.replace("meeting-data-row-", "")));
16928
+ }
16691
16929
  });
16692
16930
  }
16693
16931
 
16694
16932
  jQuery("#" + self.config['placeholder_id']).addClass("bootstrap-bmlt");
16695
16933
  jQuery("#filter-dropdown-visibile").removeClass("crouton-select").addClass("hide");
16934
+ jQuery("#filter-dropdown-visibile").parent().addClass("hide");
16696
16935
  jQuery("#filter-dropdown-next24").removeClass("crouton-select").addClass("hide");
16936
+ jQuery("#filter-dropdown-next24").parent().addClass("hide");
16937
+ jQuery("#filter-dropdown-favorites").removeClass("crouton-select").addClass("hide");
16938
+ jQuery("#filter-dropdown-favorites").parent().addClass("hide");
16939
+ if (self.shouldOfferFavorites(showingNow)) {
16940
+ jQuery("#crouton_favorites_button").removeClass("hide");
16941
+ } else {
16942
+ jQuery("#crouton_favorites_button").addClass("hide");
16943
+ }
16697
16944
  jQuery(".crouton-select").select2({
16698
16945
  dropdownAutoWidth: true,
16699
16946
  allowClear: false,
@@ -16730,6 +16977,57 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16730
16977
  jQuery('.filter-dropdown').on('select2:select', function (e) {
16731
16978
  self.filterMeetingsFromView();
16732
16979
  });
16980
+ jQuery('#crouton_favorites_button').on('click', function (e) {
16981
+ if (self.favoritesOn) {
16982
+ self.favoritesOn = false;
16983
+ jQuery("#filter-dropdown-favorites").val("a-");
16984
+ self.lowlightButton("#crouton_favorites_button");
16985
+ } else {
16986
+ self.favoritesOn = true;
16987
+ jQuery("#filter-dropdown-favorites").val("a-1");
16988
+ self.highlightButton("#crouton_favorites_button");
16989
+ }
16990
+ self.filterMeetingsFromView();
16991
+ return;
16992
+ });
16993
+ if (!self.config['has_favorites'] || !self.config['header']) {
16994
+ jQuery(".favorite-icon").addClass("hide");
16995
+ }
16996
+ jQuery(document).on('click', '.crouton-favorite', function(e) {
16997
+ e.preventDefault();
16998
+ e.stopPropagation();
16999
+ const meetingId = parseInt(this.id.replace("crouton-favorite-", ""));
17000
+ const localStorageKey = "crouton-favorites";
17001
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
17002
+ const index = favorites.indexOf(self.config.root_server + "_" + meetingId);
17003
+ const row = e.target.closest(".bmlt-data-row");
17004
+ let shouldFilterMeetings = self.favoritesOn;
17005
+ const showingNow = self.calcShowingNow();
17006
+ const favoritesButtonHidden = jQuery("#crouton_favorites_button").hasClass("hide");
17007
+ if (index !== -1) {
17008
+ favorites.splice(index, 1);
17009
+ e.target.classList.remove("glyphicon-heart");
17010
+ e.target.classList.add("glyphicon-heart-empty");
17011
+ row.setAttribute("data-favorite", 0);
17012
+ } else {
17013
+ shouldFilterMeetings = favoritesButtonHidden;
17014
+ favorites.push(self.config.root_server + "_" + meetingId);
17015
+ e.target.classList.remove("glyphicon-heart-empty");
17016
+ e.target.classList.add("glyphicon-heart");
17017
+ row.setAttribute("data-favorite", 1);
17018
+ }
17019
+ localStorage.setItem(localStorageKey, JSON.stringify(favorites));
17020
+ if (!self.shouldOfferFavorites(showingNow)) {
17021
+ shouldFilterMeetings = true;
17022
+ self.favoritesOn = false;
17023
+ jQuery("#filter-dropdown-favorites").val("a-");
17024
+ self.lowlightButton("#crouton_favorites_button");
17025
+ jQuery("#crouton_favorites_button").addClass("hide");
17026
+ }
17027
+ if (shouldFilterMeetings) {
17028
+ self.filterMeetingsFromView();
17029
+ }
17030
+ });
16733
17031
 
16734
17032
  jQuery("#day").on('click', function () {
16735
17033
  self.showView('day');
@@ -16755,8 +17053,8 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16755
17053
  jQuery(this).tab('show');
16756
17054
  });
16757
17055
 
16758
- var d = new Date();
16759
- var n = d.getDay();
17056
+ const d = new Date();
17057
+ let n = d.getDay();
16760
17058
  n++;
16761
17059
  jQuery('.nav-tabs a[href="#tab' + n + '"]').tab('show');
16762
17060
  jQuery('#tab' + n).show();
@@ -16778,27 +17076,46 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16778
17076
  if (self.meetingData.filter(m => m.venue_type != 2).length==0) {
16779
17077
  jQuery('#groupingButton_embeddedMapPage').addClass('hide');
16780
17078
  }
16781
- else croutonMap.initialize('byfield_embeddedMapPage', self.meetingData, null, null, fitBoundsInitial);
17079
+ else {
17080
+ croutonMap.initialize('byfield_embeddedMapPage', self.meetingData, null, null, fitBoundsInitial);
17081
+ if (self.config['has_geolocation'] && self.config['header']) jQuery('#'+self.createLocationSearchElement()).append(croutonMap.createLocationSearchButton());
17082
+ }
16782
17083
  }
16783
17084
  if (self.config['refresh_map']) {
16784
- croutonMap.refreshMeetings(self.meetingData, fitBounds, true);
17085
+ croutonMap.refreshMeetings(self.meetingData, fitBounds);
16785
17086
  }
16786
17087
  if (self.config['view_by'] == 'map' && !self.config['map_page'])
16787
17088
  self.config['view_by'] = 'day';
16788
17089
  self.showView(self.config['view_by'], self.meetingData.length);
16789
- if (self.config['on_complete'] != null && isFunction(self.config['on_complete'])) {
17090
+ if (self.config['on_complete'] != null && {}.toString.call(self.config['on_complete']) === '[object Function]') {
16790
17091
  self.config['on_complete']();
16791
17092
  }
16792
17093
  }, !doMeetingMap || (!self.config['lat'] && !self.config['lng']));
16793
17094
  });
16794
17095
  });
16795
- Crouton.prototype.forceShowMap = function() {
16796
- if (this.config.map_page && jQuery('#byfield_embeddedMapPage').hasClass('hide')) {
16797
- this.mapView();
17096
+ self.shouldOfferFavorites = function(showingNow) {
17097
+ if (!self.config['has_favorites']) return false;
17098
+ const localStorageKey = "crouton-favorites";
17099
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
17100
+ for (let i = 0; i < favorites.length; i++) {
17101
+ const split = favorites[i].split("_");
17102
+ const meetingId = split[split.length-1];
17103
+ if (showingNow.includes(meetingId)) return true;
17104
+ }
17105
+ return false;
17106
+ }
17107
+ self.sortListByList = function(source, truth) {
17108
+ var goal = [];
17109
+ for (var x = 0; x < truth.length; x++) {
17110
+ for (var y = 0; y < source.length; y++) {
17111
+ if (truth[x] === source[y]) {
17112
+ goal.push(source[y])
17113
+ }
17114
+ }
16798
17115
  }
17116
+ return goal;
16799
17117
  }
16800
17118
  };
16801
-
16802
17119
  // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16803
17120
  function getMasterFormatId(code, data) {
16804
17121
  for (var f = 0; f < crouton.masterFormatCodes.length; f++) {
@@ -16809,28 +17126,6 @@ function getMasterFormatId(code, data) {
16809
17126
  }
16810
17127
  }
16811
17128
 
16812
- // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16813
- var masterFormatVenueType = {
16814
- IN_PERSON: "IN_PERSON",
16815
- VIRTUAL: "VIRTUAL",
16816
- }
16817
-
16818
- var venueType = {
16819
- IN_PERSON: 1,
16820
- VIRTUAL: 2,
16821
- HYBRID: 3,
16822
- }
16823
-
16824
- function getVenueTypeName(data) {
16825
- if (data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data))) {
16826
- return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL), crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16827
- } else if (data['venue_type'] === venueType.VIRTUAL || inArray(getMasterFormatId('VM', data), getFormats(data))) {
16828
- return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL)];
16829
- } else {
16830
- return [crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16831
- }
16832
- }
16833
-
16834
17129
  // TODO: Change this logic when https://github.com/bmlt-enabled/bmlt-root-server/issues/353 is released and rolled out everywhere.
16835
17130
  function getFormats(data) {
16836
17131
  return data['formats'] !== "" ? data['format_shared_id_list'].split(",") : [];
@@ -16846,17 +17141,6 @@ function getUniqueValuesOfKey(array, key){
16846
17141
  return carry;
16847
17142
  }, []);
16848
17143
  }
16849
-
16850
- function getValuesFromObject(o) {
16851
- var arr = [];
16852
- for (key in o) {
16853
- if (o.hasOwnProperty(key)) {
16854
- arr.push(o[key]);
16855
- }
16856
- }
16857
-
16858
- return arr;
16859
- }
16860
17144
  function getUniqueFormats(array){
16861
17145
  return array.reduce(function(carry, val){
16862
17146
  if (!(val.formats_expanded)) return carry;
@@ -16874,13 +17158,13 @@ function getUniqueFormatsOfType(array, type){
16874
17158
  },[]).sortByKey('name');
16875
17159
  }
16876
17160
  Crouton.prototype.renderMeetingCount = function() {
16877
- var self = this;
16878
- self.lock(function() {
17161
+ const self = this;
17162
+ self.listenForReady(function() {
16879
17163
  self.updateMeetingCount()
16880
17164
  });
16881
17165
  }
16882
17166
  Crouton.prototype.simulateFilterDropdown = function() {
16883
- self = this;
17167
+ const self = this;
16884
17168
  jQuery('.bmlt-page:not(#byfield_embeddedMapPage)').each(function () {
16885
17169
  self.hidePage(this);
16886
17170
  });
@@ -16919,76 +17203,12 @@ Crouton.prototype.getAdjustedDateTime = function(meeting_day, meeting_time, meet
16919
17203
 
16920
17204
  return meeting_date_time_obj;
16921
17205
  };
16922
-
16923
- function arrayUnique(a, b, c) {
16924
- b = a.length;
16925
- while (c = --b)
16926
- while (c--) a[b] !== a[c] || a.splice(c, 1);
16927
- return a
16928
- }
16929
-
16930
- function sortListByList(source, truth) {
16931
- var goal = [];
16932
- for (var x = 0; x < truth.length; x++) {
16933
- for (var y = 0; y < source.length; y++) {
16934
- if (truth[x] === source[y]) {
16935
- goal.push(source[y])
16936
- }
16937
- }
16938
- }
16939
-
16940
- return goal;
16941
- }
16942
-
16943
- function inArray(needle, haystack) {
16944
- return haystack.indexOf(needle) !== -1;
16945
- }
16946
-
16947
- function isFunction(functionToCheck) {
16948
- return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
16949
- }
16950
-
16951
- function getServiceBodiesQueryString(service_bodies_id) {
16952
- var service_bodies_query = "";
16953
- for (var x = 0; x < service_bodies_id.length; x++) {
16954
- service_bodies_query += "&services[]=" + service_bodies_id[x];
16955
- }
16956
- return service_bodies_query;
16957
- }
16958
-
16959
- Array.prototype.clone = function() {
16960
- return this.slice();
17206
+ // TODO: why can't this be a const? If I set it to const, then I get an error from bootstrap???!!!!
17207
+ var venueType = {
17208
+ IN_PERSON: 1,
17209
+ VIRTUAL: 2,
17210
+ HYBRID: 3,
16961
17211
  }
16962
-
16963
- Array.prototype.filterByObjectKeyValue = function(key, value) {
16964
- var ret = [];
16965
- for (var i = 0; i < this.length; i++) {
16966
- if (this[i][key] === value) {
16967
- ret.push(this[i])
16968
- }
16969
- }
16970
-
16971
- return ret;
16972
- };
16973
-
16974
- Array.prototype.getArrayItemByObjectKeyValue = function(key, value) {
16975
- for (var i = 0; i < this.length; i++) {
16976
- if (this[i][key] === value) {
16977
- return this[i];
16978
- }
16979
- }
16980
- };
16981
-
16982
- Array.prototype.clean = function() {
16983
- for (var i = 0; i < this.length; i++) {
16984
- if (this[i] === "") {
16985
- this.splice(i, 1);
16986
- i--;
16987
- }
16988
- }
16989
- return this;
16990
- };
16991
-
16992
17212
  Array.prototype.sortByKey = function (key) {
16993
17213
  this.sort(function (a, b) {
16994
17214
  if (a[key] < b[key])
@@ -17032,21 +17252,14 @@ function swipedetect(el, callback){
17032
17252
  }, false)
17033
17253
  }
17034
17254
  function isIOSDevice() {
17035
- if (navigator.userAgentData && navigator.userAgentData.platform) {
17036
- if (navigator.userAgentData.platform === 'iOS') {
17037
- return true;
17038
- }
17039
- }
17040
- const userAgent = navigator.userAgent || navigator.vendor || window.opera;
17041
- const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
17042
- const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && !window.MSStream;
17043
- return isIOS || isIPadOS;
17255
+ return crouton.deviceType === "ios";
17044
17256
  }
17045
17257
 
17046
17258
  function isAndroidDevice() {
17047
- return /Android/i.test(navigator.userAgent);
17259
+ return crouton.deviceType === "android";
17048
17260
  }
17049
17261
 
17262
+
17050
17263
  function isMobileDevice() {
17051
17264
  return isIOSDevice() || isAndroidDevice() || /Mobi|Android/i.test(navigator.userAgent);
17052
17265
  }
@@ -17146,8 +17359,10 @@ function openDirectionsModal(e) {
17146
17359
 
17147
17360
  function closeDirectionsModal() {
17148
17361
  const modal = document.getElementById('directionsMapModal');
17149
- modal.style.display = 'none';
17150
- if (modal.className.includes('remove-after-use')) modal.remove();
17362
+ if (modal) {
17363
+ modal.style.display = 'none';
17364
+ if (modal.className.includes('remove-after-use')) modal.remove();
17365
+ }
17151
17366
  }
17152
17367
 
17153
17368
  function openDirections(url, latitude, longitude, fromModal = true) {
@@ -17170,33 +17385,32 @@ function MeetingMap(inConfig) {
17170
17385
  const config = inConfig;
17171
17386
  if (!config.maxZoom) config.maxZoom = 17;
17172
17387
  if (!config.minZoom) config.minZoom = 6;
17388
+ if (!config.locationSearchZoom) config.locationSearchZoom = 12; // TODO: for now, not in interface. Experience will show if it is worth adding to UI.
17173
17389
  if (!config.marker_contents_template) config.marker_contents_template = croutonDefaultTemplates.marker_contents_template;
17174
17390
  var gAllMeetings = [];
17175
17391
  var gMeetingIdsFromCrouton = null;
17176
17392
  var gSearchPoint = false;
17177
- var loadedCallbackFunction = null;
17178
- var loadedCallbackArgs = [];
17179
- var oldBounds = false;
17180
- var isMouseDown = false;
17393
+ var gLoadedCallbackFunction = null;
17394
+ var gLoadedCallbackArgs = [];
17395
+ var gOldBounds = false;
17396
+ var gCurrentlyDraggingMap = false;
17397
+ var gLocationSearchResult = null;
17398
+ var gAllCities = [];
17181
17399
  function preloadApiLoadedCallback(f,a) {
17182
- loadedCallbackFunction = f;
17183
- loadedCallbackArgs = a;
17400
+ gLoadedCallbackFunction = f;
17401
+ gLoadedCallbackArgs = a;
17184
17402
  }
17185
17403
  function apiLoadedCallback() {
17186
- loadedCallbackFunction(...loadedCallbackArgs);
17404
+ gLoadedCallbackFunction(...gLoadedCallbackArgs);
17187
17405
  }
17188
-
17189
17406
  function retrieveGeolocation() {
17190
17407
  return new Promise((resolve, reject) => {
17191
- if (window.storedGeolocation) {
17192
- resolve(window.storedGeolocation);
17193
- } else if (navigator.geolocation) {
17408
+ if (navigator.geolocation) {
17194
17409
  navigator.geolocation.getCurrentPosition((position) => {
17195
- window.storedGeolocation = {
17196
- latitude: position.coords.latitude,
17197
- longitude: position.coords.longitude
17198
- };
17199
- resolve(window.storedGeolocation);
17410
+ resolve({
17411
+ lat: position.coords.latitude,
17412
+ lng: position.coords.longitude
17413
+ });
17200
17414
  }, (error) => {
17201
17415
  reject(new Error('Error getting geolocation: ' + error.message));
17202
17416
  });
@@ -17208,10 +17422,14 @@ function MeetingMap(inConfig) {
17208
17422
  function isFilterVisible() {
17209
17423
  return config.filter_visible && config.filter_visible == 1;
17210
17424
  }
17211
- /************************************************************************************//**
17212
- * \brief Load the map and set it up. *
17213
- ****************************************************************************************/
17214
-
17425
+ /**
17426
+ * Creates the map and adds the various ornaments like search buttons and menus.
17427
+ * @param HTMLElement inDiv Element that contains the map.
17428
+ * @param Object menuContext Contains info for the map menu. For instance, for [bmlt_map], the dropdown filters.
17429
+ * @param {*} handlebarMapOptions
17430
+ * @param Function cb
17431
+ * @param boolean hide
17432
+ */
17215
17433
  function loadMap(inDiv, menuContext, handlebarMapOptions=null,cb=null,hide=false) {
17216
17434
  if (inDiv) {
17217
17435
  crouton_Handlebars.registerPartial("markerContentsTemplate", crouton_Handlebars.compile(config['marker_contents_template']));
@@ -17238,8 +17456,8 @@ function MeetingMap(inConfig) {
17238
17456
  gDelegate.addListener('idle', triggerCroutonMapNewQuery, false);
17239
17457
  } else {
17240
17458
  gDelegate.addListener('zoomend', function (ev) {
17241
- if (shouldRedrawMarkers() && gAllMeetings) {
17242
- if (listOnlyVisible) {
17459
+ if (shouldRedrawMarkers() && gAllMeetings && !gLocationSearchResult) {
17460
+ if (gListOnlyVisible) {
17243
17461
  const oldValue = filterVisible(false);
17244
17462
  searchResponseCallback();
17245
17463
  filterVisible(oldValue);
@@ -17285,9 +17503,7 @@ function MeetingMap(inConfig) {
17285
17503
  controlDiv.querySelector("#bmltsearch-text-button").addEventListener('click', function () {
17286
17504
  let text = document.getElementById("bmltsearch-goto-text").value.trim();
17287
17505
  if (text === "") return;
17288
- showThrobber();
17289
- gDelegate.callGeocoder(text, null, mapSearchGeocode);
17290
- clearMessageAndClose(gSearchModal);
17506
+ gDelegate.callGeocoder(text, mapSearchGeocode);
17291
17507
  });
17292
17508
  controlDiv.querySelector("#modal-seach-parameters").style.display = 'none';
17293
17509
  controlDiv.querySelector("#show-search-parameters").addEventListener('click', function (e) {
@@ -17317,12 +17533,169 @@ function MeetingMap(inConfig) {
17317
17533
  });
17318
17534
 
17319
17535
  controlDiv.querySelector("#bmltsearch-clicksearch").addEventListener('click', clickSearch);
17320
- [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>clearMessageAndClose(e.target)));
17536
+ [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>closeModalWindow(e.target)));
17321
17537
  gSearchModal = controlDiv.querySelector("#bmltsearch_modal");
17322
17538
  gSearchModal.parentElement.removeChild(gSearchModal);
17323
17539
 
17324
17540
  return controlDiv;
17325
17541
  }
17542
+ var gLocationSearchModal;
17543
+ var gDefaultLocationSearchButtonLabel = '';
17544
+ function doGeolocationThenClose() {
17545
+ doGeolocation().then(closeModalWindow(gLocationSearchModal));
17546
+ }
17547
+ function addAutocompleteEvents(inp, button) {
17548
+ var currentFocus;
17549
+ inp.addEventListener("input",function(e) {
17550
+ var a, b, i, val = this.value;
17551
+ const inp = this;
17552
+ /*close any already open lists of autocompleted values*/
17553
+ closeAllLists();
17554
+ if (!val) { return false;}
17555
+ currentFocus = -1;
17556
+ /*create a DIV element that will contain the items (values):*/
17557
+ a = document.createElement("DIV");
17558
+ a.setAttribute("id", this.id + "autocomplete-list");
17559
+ a.setAttribute("class", "autocomplete-items");
17560
+ /*append the DIV element as a child of the autocomplete container:*/
17561
+ this.parentNode.appendChild(a);
17562
+ /*for each item in the array...*/
17563
+ for (i = 0; i < gAllCities.length; i++) {
17564
+ /*check if the item starts with the same letters as the text field value:*/
17565
+ if (gAllCities[i].substr(0, val.length).toUpperCase() == val.toUpperCase()) {
17566
+ /*create a DIV element for each matching element:*/
17567
+ b = document.createElement("DIV");
17568
+ /*make the matching letters bold:*/
17569
+ b.innerHTML = "<strong>" + gAllCities[i].substr(0, val.length) + "</strong>";
17570
+ b.innerHTML += gAllCities[i].substr(val.length);
17571
+ /*insert a input field that will hold the current array item's value:*/
17572
+ b.innerHTML += "<input type='hidden' value='" + gAllCities[i] + "'>";
17573
+ /*execute a function when someone clicks on the item value (DIV element):*/
17574
+ b.addEventListener("click", function(event) {
17575
+ /*insert the value for the autocomplete text field:*/
17576
+ inp.value = this.getElementsByTagName("input")[0].value;
17577
+ /*close the list of autocompleted values,
17578
+ (or any other open lists of autocompleted values:*/
17579
+ closeAllLists();
17580
+ button.click();
17581
+ });
17582
+ a.appendChild(b);
17583
+ }
17584
+ }
17585
+ });
17586
+ inp.addEventListener("keydown", function(e) {
17587
+ var x = document.getElementById(this.id + "autocomplete-list");
17588
+ if (x) x = x.getElementsByTagName("div");
17589
+ if (e.keyCode == 40) {
17590
+ /*If the arrow DOWN key is pressed,
17591
+ increase the currentFocus variable:*/
17592
+ currentFocus++;
17593
+ /*and and make the current item more visible:*/
17594
+ addActive(x);
17595
+ } else if (e.keyCode == 38) { //up
17596
+ /*If the arrow UP key is pressed,
17597
+ decrease the currentFocus variable:*/
17598
+ currentFocus--;
17599
+ /*and and make the current item more visible:*/
17600
+ addActive(x);
17601
+ } else if (e.keyCode == 13) {
17602
+ /*If the ENTER key is pressed, prevent the form from being submitted,*/
17603
+ e.preventDefault();
17604
+ if (currentFocus > -1) {
17605
+ /*and simulate a click on the "active" item:*/
17606
+ if (x) x[currentFocus].click();
17607
+ }
17608
+ }
17609
+ });
17610
+ function addActive(x) {
17611
+ /*a function to classify an item as "active":*/
17612
+ if (!x) return false;
17613
+ /*start by removing the "active" class on all items:*/
17614
+ removeActive(x);
17615
+ if (currentFocus >= x.length) currentFocus = 0;
17616
+ if (currentFocus < 0) currentFocus = (x.length - 1);
17617
+ /*add class "autocomplete-active":*/
17618
+ x[currentFocus].classList.add("autocomplete-active");
17619
+ }
17620
+ function removeActive(x) {
17621
+ /*a function to remove the "active" class from all autocomplete items:*/
17622
+ for (var i = 0; i < x.length; i++) {
17623
+ x[i].classList.remove("autocomplete-active");
17624
+ }
17625
+ }
17626
+ function closeAllLists() {
17627
+ var x = document.getElementsByClassName("autocomplete-items");
17628
+ for (var i = 0; i < x.length; i++) {
17629
+ x[i].parentNode.removeChild(x[i]);
17630
+ }
17631
+ }
17632
+ /*execute a function when someone clicks in the document:*/
17633
+ document.addEventListener("click", function (e) {
17634
+ closeAllLists(e.target);
17635
+ });
17636
+ }
17637
+ function createLocationSearchButton() {
17638
+ const template = hbs_Crouton.templates['locationSearch'];
17639
+ const controlDiv = document.createElement('div');
17640
+ const params = {};
17641
+ controlDiv.innerHTML = template(params);
17642
+ controlDiv.querySelector("#location-search-button").addEventListener('click', showLocationSearchDialog);
17643
+ gDefaultLocationSearchButtonLabel = controlDiv.querySelector("#location-search-button :first-child").innerHTML;
17644
+ controlDiv.querySelector("#bmlt-location-search-nearbyMeetings").addEventListener('click', doGeolocationThenClose);
17645
+ addAutocompleteEvents(controlDiv.querySelector("#bmlt-location-search-goto-text"), controlDiv.querySelector("#bmlt-location-search-text-button"));
17646
+ controlDiv.querySelector("#bmlt-location-search-text-button").addEventListener('click', function () {
17647
+ let text = document.getElementById("bmlt-location-search-goto-text").value.trim();
17648
+ if (text === "") return;
17649
+ if (isMapVisible()) {
17650
+ gDelegate.callGeocoder(text, locationSearchOpenMapGeocode);
17651
+ } else {
17652
+ gDelegate.callGeocoder(text, locationSearchGeocode);
17653
+ }
17654
+ });
17655
+ controlDiv.querySelector("#bmlt-location-search-widen").addEventListener('click', function () {
17656
+ if (gLocationSearchResult === null) {
17657
+ if (gListOnlyVisible && gSearchPoint) {
17658
+ gLocationSearchResult = {center: gSearchPoint, bounds: gDelegate.getBounds(), zoom: gDelegate.getZoom()};
17659
+ } else return;
17660
+ }
17661
+ if (gLocationSearchResult.zoom == config.minZoom) return;
17662
+ filterVisible(false);
17663
+ let bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, gLocationSearchResult.zoom);
17664
+ let knt = filterMeetingsAndBounds(bounds).length;
17665
+ for (let zoom = gLocationSearchResult.zoom-1; zoom >= config.minZoom; zoom = zoom-1) {
17666
+ bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, zoom);
17667
+ if (filterMeetingsAndBounds(bounds).length > knt) {
17668
+ if (isMapVisible()) {
17669
+ gDelegate.flyToFixedZoom(gLocationSearchResult.center, zoom, filterVisible);
17670
+ gLocationSearchResult = null;
17671
+ } else {
17672
+ gLocationSearchResult.zoom = zoom;
17673
+ gLocationSearchResult.bounds = bounds;
17674
+ gListOnlyVisible = false; // force new calc.
17675
+ filterVisible(true, gLocationSearchResult.bounds);
17676
+ }
17677
+ closeModalWindow(gLocationSearchModal);
17678
+ return;
17679
+ }
17680
+ }
17681
+ bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, gLocationSearchResult.zoom);
17682
+ filterVisible(true, bounds);
17683
+ alert("No further matches");
17684
+ });
17685
+ controlDiv.querySelector("#bmlt-location_search-cancel").addEventListener('click', function () {
17686
+ filterVisible(false);
17687
+ setLocationSearchButtonLabel('');
17688
+ closeModalWindow(gLocationSearchModal);
17689
+ });
17690
+ [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>closeModalWindow(e.target)));
17691
+ gLocationSearchModal = controlDiv.querySelector("#bmlt_location_search_modal");
17692
+ gLocationSearchModal.parentElement.removeChild(gLocationSearchModal);
17693
+
17694
+ return controlDiv;
17695
+ }
17696
+ function isMapVisible() {
17697
+ return gDelegate.isMapVisible() && crouton.isEmbeddedMapShowing();
17698
+ }
17326
17699
  var next24status = false;
17327
17700
  function createNext24Toggle() {
17328
17701
  const toggleSrc = `
@@ -17348,14 +17721,14 @@ function MeetingMap(inConfig) {
17348
17721
  }`
17349
17722
  .replace("__text1__", crouton.localization.getWord("Upcoming Meetings"))
17350
17723
  .replace("__text2__", crouton.localization.getWord("All Meetings"));
17351
- var controlDiv = document.createElement('div');
17724
+ const controlDiv = document.createElement('div');
17352
17725
  controlDiv.innerHTML = toggleSrc;
17353
17726
  controlDiv.querySelector(".onoffswitch").addEventListener('click', function (event) {
17354
17727
  if (event.pointerId < 0) return;
17355
17728
  next24status = !next24status;
17356
- fitDuringFilter = false;
17729
+ gAllowExpandViewport = false;
17357
17730
  crouton.filterNext24(next24status);
17358
- fitDuringFilter = true;
17731
+ gAllowExpandViewport = true;
17359
17732
  });
17360
17733
  let style = document.createElement('style');
17361
17734
  style.innerHTML = rules;
@@ -17363,15 +17736,18 @@ function MeetingMap(inConfig) {
17363
17736
  return controlDiv;
17364
17737
  }
17365
17738
  function createMenuButton(menuContext) {
17366
- var template = hbs_Crouton.templates['mapMenu'];
17367
- var controlDiv = document.createElement('div');
17739
+ const template = hbs_Crouton.templates['mapMenu'];
17740
+ const controlDiv = document.createElement('div');
17368
17741
  controlDiv.innerHTML = template(menuContext);
17369
17742
  controlDiv.querySelector("#nearbyMeetings").addEventListener('click', function (e) {
17370
17743
  retrieveGeolocation().then(position => {
17371
17744
  filterVisible(false);
17372
- gDelegate.setViewToPosition(position, filterMeetingsAndBounds, filterVisible);
17373
- gSearchPoint = {"lat": position.latitude, "lng": position.longitude};
17745
+ gSearchPoint = {"lat": position.lat, "lng": position.lng};
17374
17746
  crouton.updateDistances();
17747
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(gSearchPoint, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
17748
+ gDelegate.flyToFixedZoom(position, locationSearchResult.zoom, filterVisible);
17749
+ filterVisible(true);
17750
+ setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
17375
17751
 
17376
17752
  }).catch(error => {
17377
17753
  console.log(error.message);
@@ -17393,21 +17769,15 @@ function MeetingMap(inConfig) {
17393
17769
  if (dropdownContent.style.display == "inline-block") {
17394
17770
  dropdownContent.style.display = "none";
17395
17771
  } else {
17396
- jQuery("#filteringByVisibility").html(listOnlyVisible?'&#10004;':'');
17772
+ jQuery("#filteringByVisibility").html(gListOnlyVisible?'&#10004;':'');
17397
17773
  dropdownContent.style.display = "inline-block";
17398
17774
  }
17399
17775
  });
17400
17776
  [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>closeModalWindow(e.target)));
17401
17777
  controlDiv.querySelector("#close_table").addEventListener('click', hideListView);
17402
- controlDiv.querySelector("#goto-text").addEventListener('keydown', function (event) {
17403
- if (event && event.key == "Enter") {
17404
- closeModalWindow(event.target);
17405
- lookupLocation(g_suspendedFullscreen);
17406
- }
17407
- });
17778
+ addAutocompleteEvents(controlDiv.querySelector("#goto-text"), controlDiv.querySelector("#goto-button"));
17408
17779
  controlDiv.querySelector("#goto-button").addEventListener('click', function (event) {
17409
- closeModalWindow(event.target);
17410
- lookupLocation(g_suspendedFullscreen);
17780
+ lookupLocation(document.getElementById('goto-text').value, g_suspendedFullscreen, mapMenuGeocode);
17411
17781
  });
17412
17782
 
17413
17783
  return controlDiv;
@@ -17415,6 +17785,17 @@ function MeetingMap(inConfig) {
17415
17785
  function hasMapSearch() {
17416
17786
  return 'map_search' in config;
17417
17787
  }
17788
+ /**
17789
+ * Load the meetings for [bmlt_tabs] and [bmlt_map]: all the meetings, during map initialization.
17790
+ * @param string inDiv_id selector for the div that will contain the map.
17791
+ * @param Array meetings_responseObject the meetings returned from the server and enhanced by the crouton core.
17792
+ * @param {*} menuContext information about the dropdown filters.
17793
+ * @param {*} handlebarMapOptions
17794
+ * @param boolean fitBounds should we expand our map so that all the meetings are visible?
17795
+ * @param function callback called after map has been initialized
17796
+ * @param boolean hide make the map invisisble
17797
+ * @returns
17798
+ */
17418
17799
  function loadFromCrouton(inDiv_id, meetings_responseObject, menuContext = null, handlebarMapOptions = null, fitBounds = true, callback, hide) {
17419
17800
  if (!gDelegate.isApiLoaded()) {
17420
17801
  preloadApiLoadedCallback(loadFromCrouton, [inDiv_id, meetings_responseObject, menuContext, handlebarMapOptions, fitBounds, callback, hide]);
@@ -17423,8 +17804,15 @@ function MeetingMap(inConfig) {
17423
17804
  }
17424
17805
  let inDiv = document.getElementById(inDiv_id);
17425
17806
  loadMap(inDiv, menuContext, handlebarMapOptions, callback, hide);
17426
- loadAllMeetings(meetings_responseObject, fitBounds, true);
17807
+ loadAllMeetings(meetings_responseObject, fitBounds);
17427
17808
  };
17809
+ /**
17810
+ * The map on the meeting details popup modal.
17811
+ * @param string inDiv_id selector for the div that will contain the map.
17812
+ * @param Object meeting
17813
+ * @param {*} handlebarMapOptions
17814
+ * @returns
17815
+ */
17428
17816
  function loadPopupMap(inDiv_id, meeting, handlebarMapOptions = null) {
17429
17817
  if (!gDelegate.isApiLoaded()) {
17430
17818
  preloadApiLoadedCallback(loadPopupMap, [inDiv_id, meeting, handlebarMapOptions]);
@@ -17442,25 +17830,21 @@ function MeetingMap(inConfig) {
17442
17830
  gModalDelegate = delegate;
17443
17831
  }
17444
17832
  };
17445
- var fitDuringFilter = true;
17446
- function filterFromCrouton(filter) {
17447
- gMeetingIdsFromCrouton = filter;
17833
+ var gAllowExpandViewport = true;
17834
+ function setFilteredIds(ids) {
17835
+ gMeetingIdsFromCrouton = ids;
17448
17836
  if (gAllMeetings)
17449
- searchResponseCallback(fitDuringFilter && !listOnlyVisible);
17837
+ searchResponseCallback(gAllowExpandViewport && !gListOnlyVisible);
17450
17838
  };
17451
- function clearMessageAndClose(modal) {
17452
- jQuery('#zoomed-out-message').not('.hide').addClass('hide');
17453
- closeModalWindow(modal);
17454
- }
17455
17839
  function nearMeSearch() {
17456
17840
  retrieveGeolocation().then(position => {
17457
17841
  showThrobber();
17458
- gSearchPoint = {"lat": position.latitude, "lng": position.longitude};
17459
- crouton.searchByCoordinates(position.latitude, position.longitude, config.map_search.width);
17460
- if (activeModal == gSearchModal) clearMessageAndClose(gSearchModal);
17842
+ gSearchPoint = {"lat": position.lat, "lng": position.lng};
17843
+ crouton.searchByCoordinates(position.lat, position.lng, config.map_search.width);
17844
+ if (gActiveModal == gSearchModal) closeModalWindow(gSearchModal);
17461
17845
  }).catch(error => {
17462
17846
  console.log(error.message);
17463
- if (activeModal != gSearchModal) showBmltSearchDialog();
17847
+ if (gActiveModal != gSearchModal) showBmltSearchDialog();
17464
17848
  });
17465
17849
  };
17466
17850
  function clickSearch(e) {
@@ -17470,7 +17854,7 @@ function MeetingMap(inConfig) {
17470
17854
  gSearchPoint = {"lat": lat, "lng": lng};
17471
17855
  crouton.searchByCoordinates(lat, lng, config.map_search.width);
17472
17856
  });
17473
- clearMessageAndClose(gSearchModal);
17857
+ closeModalWindow(gSearchModal);
17474
17858
  }
17475
17859
  function createThrobber(inDiv) {
17476
17860
  if (!inDiv.myThrobber) {
@@ -17480,7 +17864,7 @@ function MeetingMap(inConfig) {
17480
17864
  inDiv.myThrobber.className = 'bmlt_map_throbber_div';
17481
17865
  inDiv.myThrobber.style.display = 'none';
17482
17866
  inDiv.appendChild(inDiv.myThrobber);
17483
- var img = document.createElement("img");
17867
+ const img = document.createElement("img");
17484
17868
 
17485
17869
  if (img) {
17486
17870
  img.src = config.BMLTPlugin_images ? config.BMLTPlugin_images + "/Throbber.gif"
@@ -17505,19 +17889,104 @@ function MeetingMap(inConfig) {
17505
17889
  gInDiv.myThrobber.style.display = 'none';
17506
17890
  };
17507
17891
  };
17892
+ function setLocationSearchButtonLabel(label) {
17893
+ if (!label || label==='')
17894
+ jQuery("#location-search-button :first-child").html(gDefaultLocationSearchButtonLabel);
17895
+ else if (gDefaultLocationSearchButtonLabel && gDefaultLocationSearchButtonLabel !== '') {
17896
+ let html = gDefaultLocationSearchButtonLabel.replace(crouton.localization.getWord("Search by Location"), label);
17897
+ jQuery("#location-search-button :first-child").html(html);
17898
+ }
17899
+ }
17900
+ function openMapGeocode(resp, modalName, initial=false) {
17901
+ chooseResponse(modalName, resp, function(resp, i) {
17902
+ let center = gDelegate.getGeocodeCenterAndBounds(resp,i).center;
17903
+ gSearchPoint = {"lat": center.lat, "lng": center.lng};
17904
+ crouton.updateDistances(initial);
17905
+ const modal = document.getElementById(modalName);
17906
+ closeModalWindow(modal);
17907
+ filterVisible(false);
17908
+ const centerAndBounds = gDelegate.getGeocodeCenterAndBounds(resp, i);
17909
+ if (!centerAndBounds) return;
17910
+ const zoom = calcZoomThatContainsBoundingBox(centerAndBounds);
17911
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(gSearchPoint, filterMeetingsAndBounds, zoom);
17912
+ gDelegate.flyToFixedZoom(gSearchPoint, locationSearchResult.zoom, filterVisible);
17913
+ searchResponseCallback();
17914
+ })
17915
+ }
17916
+ function mapMenuGeocode(resp) {
17917
+ openMapGeocode(resp, "geocoding_modal");
17918
+ }
17919
+ function mapMenuGeocodeInitial(resp) {
17920
+ openMapGeocode(resp, "geocoding_modal", true);
17921
+ }
17508
17922
  function mapSearchGeocode(resp) {
17509
- showThrobber();
17510
- if (document.getElementById("bmltsearch-goto-text"))
17511
- document.getElementById("bmltsearch-goto-text").value = "";
17512
- let latlng = gDelegate.getGeocodeCenter(resp);
17513
- if (!latlng) {
17514
- hideThrobber();
17923
+ chooseResponse('bmltsearch_modal', resp, function(resp, i) {
17924
+ closeModalWindow(gSearchModal);
17925
+ if (document.getElementById("bmltsearch-goto-text"))
17926
+ document.getElementById("bmltsearch-goto-text").value = "";
17927
+ let latlng = gDelegate.getGeocodeCenterAndBounds(resp,i).center;
17928
+ if (!latlng) return;
17929
+ showThrobber();
17930
+ gSearchPoint = {"lat": latlng.lat, "lng": latlng.lng};
17931
+ crouton.searchByCoordinates(latlng.lat, latlng.lng, config.map_search.width);
17932
+ });
17933
+ }
17934
+ function chooseResponse(modalName, resp, callback) {
17935
+ if (jQuery('#'+modalName).is(":hidden")) {
17936
+ callback(resp, 0);
17515
17937
  return;
17516
17938
  }
17517
- gSearchPoint = {"lat": latlng.lat, "lng": latlng.lng};
17518
- crouton.searchByCoordinates(latlng.lat, latlng.lng, config.map_search.width);
17939
+ const choices = gDelegate.getGeocodingChoices(resp);
17940
+ if (choices.length < 2) {
17941
+ setLocationSearchButtonLabel(choices[0]);
17942
+ callback(resp, 0);
17943
+ return;
17944
+ }
17945
+ const html = choices.map((choice, index) =>
17946
+ '<button class="location-choice" data-choice="'+index+'">'+choice+'</button>'
17947
+ );
17948
+ jQuery('#'+modalName+' .crouton-modal-search-page').addClass('hide');
17949
+ jQuery('#'+modalName+' .crouton-modal-search-choice').removeClass('hide')
17950
+ .html('<div class="choose-location"><h4>'+crouton.localization.getWord('Select one')+'</h4>'+html.join('')+'</div>')
17951
+ jQuery('#'+modalName+' .location-choice').on('click', function() {
17952
+ const index = parseInt(jQuery(this).data("choice"))
17953
+ setLocationSearchButtonLabel(choices[index]);
17954
+ callback(resp, index);
17955
+ })
17956
+ }
17957
+ function locationSearchOpenMapGeocode(resp) {
17958
+ openMapGeocode(resp, 'bmlt_location_search_modal');
17959
+ }
17960
+ function calcZoomThatContainsBoundingBox(centerAndBounds) {
17961
+ const center = {lat: (centerAndBounds.southWest.lat + centerAndBounds.northEast.lat)/2,
17962
+ lng: (centerAndBounds.southWest.lng + centerAndBounds.northEast.lng)/2,};
17963
+ let zoom = config.locationSearchZoom + 1;
17964
+ do {
17965
+ if (zoom <= config.minZoom) break;
17966
+ zoom = zoom - 1;
17967
+ var bounds = gDelegate.calculateBoundsFromCenterAndZoom(center, zoom);
17968
+ } while (!gDelegate.contains(bounds, centerAndBounds.southWest.lat, centerAndBounds.southWest.lng)
17969
+ || !gDelegate.contains(bounds, centerAndBounds.northEast.lat, centerAndBounds.northEast.lng))
17970
+ return zoom;
17971
+ }
17972
+ function locationSearchGeocodeInitial(resp) {
17973
+ locationSearchGeocode(resp, true);
17974
+ }
17975
+ function locationSearchGeocode(resp, initial=false) {
17976
+ chooseResponse('bmlt_location_search_modal', resp, function(resp, i) {
17977
+ closeModalWindow(gLocationSearchModal);
17978
+ const centerAndBounds = gDelegate.getGeocodeCenterAndBounds(resp, i);
17979
+ if (!centerAndBounds) return;
17980
+ let center = centerAndBounds.center;
17981
+ filterVisible(false);
17982
+ let zoom = calcZoomThatContainsBoundingBox(centerAndBounds);
17983
+ gLocationSearchResult = gDelegate.getZoomAdjustedBounds(center, filterMeetingsAndBounds, zoom);
17984
+ gSearchPoint = {"lat": gLocationSearchResult.center.lat, "lng": gLocationSearchResult.center.lng};
17985
+ filterVisible(true, gLocationSearchResult.bounds);
17986
+ crouton.updateDistances(initial);
17987
+ });
17519
17988
  }
17520
- function loadAllMeetings(meetings_responseObject, fitBounds=true, fitAll=false) {
17989
+ function loadAllMeetings(meetings_responseObject, fitBounds=true) {
17521
17990
  if (meetings_responseObject === null && config.map_search) {
17522
17991
  if (config.map_search.auto) nearMeSearch();
17523
17992
  else if (config.map_search.coordinates_search) {
@@ -17526,12 +17995,19 @@ function MeetingMap(inConfig) {
17526
17995
  gSearchPoint = {"lat": config.map_search.latitude, "lng": config.map_search.longitude};
17527
17996
  crouton.searchByCoordinates(config.map_search.latitude, config.map_search.longitude, config.map_search.width);
17528
17997
  }
17529
- else if (config.map_search.location) gDelegate.callGeocoder(config.map_search.location, null, mapSearchGeocode);
17998
+ else if (config.map_search.location) gDelegate.callGeocoder(config.map_search.location, mapSearchGeocode);
17530
17999
  else showBmltSearchDialog();
17531
18000
  return;
17532
18001
  }
17533
18002
  gAllMeetings = meetings_responseObject.filter(m => m.venue_type != 2);
17534
- if (fitBounds) {
18003
+ gAllCities = meetings_responseObject.reduce(function (carry, m) {
18004
+ const fields = ['location_municipality', 'location_city_subsection', 'location_province', 'location_neighborhood'];
18005
+ fields.forEach(function (f) {
18006
+ if (m[f].length > 1 && !carry.includes(m[f])) carry.push(m[f]);
18007
+ });
18008
+ return carry;
18009
+ }, []);
18010
+ if (fitBounds && !config.centerMe && !config.goto) {
17535
18011
  let lat_lngs = gAllMeetings.reduce(function(a,m) {a.push([m.latitude, m.longitude]); return a;},[]);
17536
18012
  const maxRadius = config.maxTomatoWidth/2.0;
17537
18013
  if (gSearchPoint) lat_lngs.push([gSearchPoint.lat, gSearchPoint.lng]);
@@ -17547,31 +18023,45 @@ function MeetingMap(inConfig) {
17547
18023
  }
17548
18024
  searchResponseCallback();
17549
18025
  hideThrobber();
17550
- if (isFilterVisible() || config.centerMe || config.goto) crouton.forceShowMap();
17551
- if (config.centerMe) {
17552
- if (navigator.geolocation) {
17553
- navigator.geolocation.getCurrentPosition(
17554
- function (position) {
17555
- coords = {latitude: position.coords.latitude, longitude: position.coords.longitude};
17556
- filterVisible(false);
17557
- if (config.zoom) gDelegate.setZoom(false, config.zoom);
17558
- gDelegate.setViewToPosition(coords, filterMeetingsAndBounds, () => {
17559
- filterVisible(isFilterVisible());
17560
- });
17561
- gSearchPoint = {"lat": position.coords.latitude, "lng": position.coords.longitude};
17562
- crouton.updateDistances(true);
17563
- },
17564
- showGeocodingDialog
17565
- );
17566
- } else if (fitAll) {
17567
- showGeocodingDialog();
17568
- }
17569
- } else {
17570
- if ((!config.centerMe && !config.goto) && !(config.map_search && isFilterVisible())) {
17571
- gDelegate.afterInit(()=>filterVisible(isFilterVisible()));
18026
+ gDelegate.afterInit(!crouton.isEmbeddedMapShowing(), () => {
18027
+ if (config.centerMe) {
18028
+ doGeolocation(isFilterVisible(), true).catch(error => showGeocodingDialog());
18029
+ } else {
18030
+ if ((!config.centerMe && !config.goto) && !(config.map_search && isFilterVisible())) {
18031
+ filterVisible(isFilterVisible());
18032
+ }
18033
+ if (config.goto) {
18034
+ if (isMapVisible()) {
18035
+ gDelegate.callGeocoder(config.goto, mapMenuGeocodeInitial);
18036
+ } else {
18037
+ gDelegate.callGeocoder(config.goto, locationSearchGeocodeInitial);
18038
+ }
18039
+ }
17572
18040
  }
17573
- if (config.goto) gDelegate.callGeocoder(config.goto, isFilterVisible() ? resetVisibleThenFilterMeetingsAndBounds : setVisibleThenFilterMeetingsAndBounds);
17574
- }
18041
+ });
18042
+ }
18043
+ function doGeolocation(makeFilterVisible=true, initial=false) {
18044
+ return new Promise((resolve, reject) =>
18045
+ retrieveGeolocation().then(function(coords) {
18046
+ filterVisible(false);
18047
+ if (isMapVisible() || !makeFilterVisible) {
18048
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(coords, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
18049
+ gDelegate.flyToFixedZoom(coords, locationSearchResult.zoom, () => {
18050
+ filterVisible(makeFilterVisible);
18051
+ if (makeFilterVisible) setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
18052
+ });
18053
+ } else {
18054
+ gLocationSearchResult = gDelegate.getZoomAdjustedBounds(coords, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
18055
+ filterVisible(true, gLocationSearchResult.bounds);
18056
+ setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
18057
+ }
18058
+ gSearchPoint = coords;
18059
+ crouton.updateDistances(initial);
18060
+ resolve(coords);
18061
+ }).catch(error => {
18062
+ reject(error);
18063
+ })
18064
+ );
17575
18065
  }
17576
18066
  function createCityHash(allMeetings) {
17577
18067
  return allMeetings.reduce(function(prev, meeting) {
@@ -17584,11 +18074,12 @@ function MeetingMap(inConfig) {
17584
18074
  }
17585
18075
  var g_suspendedFullscreen = false;
17586
18076
  var g_overflowX;
17587
- var activeModal = null;
18077
+ var gActiveModal = null;
17588
18078
  var swipableModal = false;
17589
18079
  function closeModalWindow(modal) {
17590
18080
  gDelegate.modalOff();
17591
- activeModal = null;
18081
+ gActiveModal = null;
18082
+ if (!modal) return;
17592
18083
  if (!modal.classList.contains("modal"))
17593
18084
  return closeModalWindow(modal.parentNode);
17594
18085
  modal.style.display = "none";
@@ -17608,8 +18099,8 @@ function MeetingMap(inConfig) {
17608
18099
  }
17609
18100
  }
17610
18101
  document.addEventListener("keydown", function(event) {
17611
- if (activeModal && event.key == "Escape") {
17612
- closeModalWindow(activeModal);
18102
+ if (gActiveModal && event.key == "Escape") {
18103
+ closeModalWindow(gActiveModal);
17613
18104
  }
17614
18105
  }, true);
17615
18106
  function openModalWindow(modal,swipe=false) {
@@ -17619,9 +18110,10 @@ function MeetingMap(inConfig) {
17619
18110
  }
17620
18111
  if (!modal) return;
17621
18112
  modal.style.display = "block";
18113
+ document.body.appendChild(modal);
17622
18114
  swipableModal = swipe;
17623
18115
  modal.focus();
17624
- activeModal = modal;
18116
+ gActiveModal = modal;
17625
18117
  dd = document.getElementById("map-menu-dropdown");
17626
18118
  if (dd) dd.style.display = "none";
17627
18119
  gDelegate.modalOn();
@@ -17639,15 +18131,33 @@ function MeetingMap(inConfig) {
17639
18131
  openModalWindow(document.getElementById('filter_modal'));
17640
18132
  }
17641
18133
  function showBmltSearchDialog(e) {
17642
- if (!document.getElementById('bmltsearch_modal')) gInDiv.appendChild(gSearchModal);
18134
+ openModalWindow(gSearchModal);
17643
18135
  if (gDelegate.isMapDefined())
17644
18136
  jQuery('#bmltsearch-clicksearch').parent().show();
17645
18137
  else
17646
18138
  jQuery('#bmltsearch-clicksearch').parent().hide();
17647
- openModalWindow(gSearchModal);
18139
+ jQuery('#zoomed-out-message').addClass('hide');
18140
+ jQuery('#bmltsearch_modal .crouton-modal-search-page').removeClass('hide');
18141
+ jQuery('#bmltsearch_modal .crouton-modal-search-choice').addClass('hide');
18142
+ }
18143
+ function showLocationSearchDialog(e) {
18144
+ openModalWindow(gLocationSearchModal);
18145
+ if ((gSearchPoint !== null) && gListOnlyVisible) {
18146
+ jQuery("#location-search-widen").removeClass('hide');
18147
+ } else {
18148
+ jQuery("#location-search-widen").addClass('hide');
18149
+ }
18150
+ jQuery('#bmlt_location_search_modal .crouton-modal-search-page').removeClass('hide');
18151
+ jQuery('#bmlt_location_search_modal .crouton-modal-search-choice').addClass('hide');
18152
+ jQuery('#bmlt-location-search-goto-text').val('');
18153
+ jQuery('#bmlt-location-search-goto-textautocomplete-list').remove();
17648
18154
  }
17649
18155
  function showGeocodingDialog(e=null) {
17650
18156
  openModalWindow(document.getElementById('geocoding_modal'));
18157
+ jQuery('#geocoding_modal .crouton-modal-search-page').removeClass('hide');
18158
+ jQuery('#geocoding_modal .crouton-modal-search-choice').addClass('hide');
18159
+ jQuery('#goto-text').val('');
18160
+ jQuery('#goto-textautocomplete-list').remove();
17651
18161
  }
17652
18162
  function showListView(e=null) {
17653
18163
  filterVisible();
@@ -17663,36 +18173,17 @@ function MeetingMap(inConfig) {
17663
18173
  jQuery("#table_page").addClass("hide");
17664
18174
  jQuery("#bmlt-map").css("display", "block");
17665
18175
  }
17666
- function resetVisibleThenFilterMeetingsAndBounds(bounds, center=null) {
17667
- filterVisible(false);
17668
- const ret = filterMeetingsAndBounds(bounds);
17669
- filterVisible(true);
17670
- if (gSearchPoint.lat != center.lat || gSearchPoint.lng != center.lng) {
17671
- gSearchPoint = center;
17672
- crouton.updateDistances();
17673
- }
17674
- return ret;
17675
- }
17676
- function setVisibleThenFilterMeetingsAndBounds(bounds, center=null) {
17677
- filterVisible(false);
17678
- const ret = filterMeetingsAndBounds(bounds);
17679
- if (gSearchPoint.lat != center.lat || gSearchPoint.lng != center.lng) {
17680
- gSearchPoint = center;
17681
- crouton.updateDistances();
17682
- }
17683
- return ret;
17684
- }
17685
- function lookupLocation(fullscreen) {
17686
- if (document.getElementById('goto-text').value != '') {
18176
+ function lookupLocation(location,fullscreen, callback) {
18177
+ if (location != '') {
17687
18178
  if (fullscreen) {
17688
18179
  gDelegate.addListener('idle', function () {
17689
- gDelegate.callGeocoder(document.getElementById('goto-text').value, resetVisibleThenFilterMeetingsAndBounds);
18180
+ gDelegate.callGeocoder(location, callback);
17690
18181
  }, true);
17691
18182
  } else {
17692
- gDelegate.callGeocoder(document.getElementById('goto-text').value, resetVisibleThenFilterMeetingsAndBounds);
18183
+ gDelegate.callGeocoder(location, callback);
17693
18184
  }
17694
18185
  } else {
17695
- alert("");
18186
+ alert("Location not found");
17696
18187
  };
17697
18188
  return true;
17698
18189
  };
@@ -17700,19 +18191,9 @@ function MeetingMap(inConfig) {
17700
18191
  if (!gAllMeetings || !gAllMeetings.length) {
17701
18192
  return;
17702
18193
  };
17703
- try {
17704
- drawMarkers(expand);
17705
- if (gSearchPoint) {
17706
- gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17707
- }
17708
- } catch (e) {
17709
- console.log(e);
17710
- gDelegate.addListener('projection_changed', function (ev) {
17711
- drawMarkers(expand);
17712
- if (gSearchPoint) {
17713
- gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17714
- }
17715
- }, true);
18194
+ drawMarkers(expand);
18195
+ if (gSearchPoint) {
18196
+ gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17716
18197
  }
17717
18198
  };
17718
18199
  /****************************************************************************************
@@ -17760,33 +18241,55 @@ function MeetingMap(inConfig) {
17760
18241
  gDelegate.fitBounds(lat_lngs);
17761
18242
  }
17762
18243
  };
18244
+ function latLngToWebMercator(latlng, zoom) {
18245
+ const lat = Math.max(-85.05112878, Math.min(85.05112878, latlng.lat));
18246
+ const phi = lat * Math.PI / 180;
18247
+ const scale = 256 * Math.pow(2, zoom);
18248
+
18249
+ const x = scale * ((latlng.lng/360.) + .5);
18250
+ const y =
18251
+ scale * (Math.PI - Math.log(Math.tan(Math.PI / 4 + phi / 2))) / (2 * Math.PI);
18252
+ return { x: x, y: y };
18253
+ }
18254
+ function webMercatorToLatLng(point, zoom) {
18255
+ const scale = 256 * Math.pow(2, zoom);
18256
+
18257
+ const lng = 360 * (point.x / scale - .5);
18258
+ const t = Math.exp(Math.PI - (2 * Math.PI) * (point.y / scale));
18259
+ const phi = 2 * Math.atan(t) - Math.PI / 2; // radians
18260
+
18261
+ return { lat: phi * 180 / Math.PI, lng: lng };
18262
+ }
17763
18263
  function mapOverlappingMarkersInCity(in_meeting_array) ///< Used to draw the markers when done.
17764
18264
  {
17765
- var tolerance = 8; /* This is how many pixels we allow. */
18265
+ const tolerance = 8; /* This is how many pixels we allow. */
17766
18266
 
17767
- var ret = new Array;
18267
+ const ret = new Array;
18268
+ const zoom = gDelegate.getZoom();
18269
+ const center = latLngToWebMercator(gDelegate.getCenter(), zoom)
17768
18270
  // We create this hash because we limit looking for "matches" to within one city.
17769
18271
  for (const [city, meetings] of Object.entries(createCityHash(in_meeting_array))) {
17770
18272
  // create a tmp object so we can mark which items haven't been matched yet.
17771
- var tmp = meetings.map((meeting) => {
18273
+ const tmp = meetings.map((meeting) => {
17772
18274
  item = new Object;
17773
18275
  item.matched = false;
17774
18276
  item.meeting = meeting;
17775
- item.coords = gDelegate.fromLatLngToPoint(meeting.latitude, meeting.longitude);
18277
+ const point = latLngToWebMercator({lat: meeting.latitude, lng: meeting.longitude}, zoom);
18278
+ item.coords = {x: point.x-center.x, y: point.y-center.y};
17776
18279
  return item;
17777
18280
  });
17778
18281
  tmp.reduce(function(prev, item, index) {
17779
18282
  if (item.matched) return prev;
17780
18283
  matches = [item.meeting];
17781
- var outer_coords = item.coords;
18284
+ const outer_coords = item.coords;
17782
18285
  for (c2 = index+1; c2<meetings.length; c2++) {
17783
18286
  if (tmp[c2].matched) continue;
17784
- var inner_coords = tmp[c2].coords;
18287
+ const inner_coords = tmp[c2].coords;
17785
18288
 
17786
- var xmin = outer_coords.x - tolerance;
17787
- var xmax = outer_coords.x + tolerance;
17788
- var ymin = outer_coords.y - tolerance;
17789
- var ymax = outer_coords.y + tolerance;
18289
+ const xmin = outer_coords.x - tolerance;
18290
+ const xmax = outer_coords.x + tolerance;
18291
+ const ymin = outer_coords.y - tolerance;
18292
+ const ymax = outer_coords.y + tolerance;
17790
18293
 
17791
18294
  /* We have an overlap. */
17792
18295
  if ((inner_coords.x >= xmin) && (inner_coords.x <= xmax) && (inner_coords.y >= ymin) && (inner_coords.y <= ymax)) {
@@ -17803,8 +18306,8 @@ function MeetingMap(inConfig) {
17803
18306
  return ret;
17804
18307
  };
17805
18308
  function sortMeetingSearchResponseCallback(mtg_a, mtg_b) {
17806
- var weekday_score_a = parseInt(mtg_a.weekday_tinyint, 10);
17807
- var weekday_score_b = parseInt(mtg_b.weekday_tinyint, 10);
18309
+ const weekday_score_a = parseInt(mtg_a.weekday_tinyint, 10);
18310
+ const weekday_score_b = parseInt(mtg_b.weekday_tinyint, 10);
17808
18311
 
17809
18312
  if (weekday_score_a < config.start_week) {
17810
18313
  weekday_score_a += 7;
@@ -17820,8 +18323,8 @@ function MeetingMap(inConfig) {
17820
18323
  else if (weekday_score_a > weekday_score_b) {
17821
18324
  return 1;
17822
18325
  };
17823
- var time_a = mtg_a.start_time.toString().split(':');
17824
- var time_b = mtg_b.start_time.toString().split(':');
18326
+ const time_a = mtg_a.start_time.toString().split(':');
18327
+ const time_b = mtg_b.start_time.toString().split(':');
17825
18328
  if (parseInt(time_a[0]) < parseInt(time_b[0])) {
17826
18329
  return -1;
17827
18330
  }
@@ -17853,77 +18356,77 @@ function MeetingMap(inConfig) {
17853
18356
  * \brief This creates a single meeting's marker on the map. *
17854
18357
  ****************************************************************************************/
17855
18358
  function createMapMarker(meetings, openMarker) {
17856
- var main_point = [meetings[0].latitude, meetings[0].longitude];
18359
+ const main_point = [meetings[0].latitude, meetings[0].longitude];
17857
18360
  const marker_html = markerTemplate(meetings);
17858
18361
  const marker = gDelegate.createMarker(main_point, (meetings.length > 1), null);
17859
18362
  gDelegate.bindPopup(marker, marker_html, meetings.map((m)=>parseInt(m.id_bigint)), openMarker);
17860
18363
  };
17861
18364
  function createGroupMarker(group, openMarker) {
17862
- var main_point = [group.latitude, group.longitude];
18365
+ const main_point = [group.latitude, group.longitude];
17863
18366
  const marker = gDelegate.createMarker(main_point, group['membersOfGroup'].length > 1, null);
17864
18367
  gDelegate.addMarkerCallback(marker, function() {
17865
18368
  crouton.openMeetingModal(group);
17866
18369
  });
17867
18370
  };
17868
- var listOnlyVisible = false;
17869
- var listener = null;
18371
+ var gListOnlyVisible = false;
18372
+ var gDragStartListener = null;
17870
18373
  function filterBounds(bounds) {
17871
18374
  return gAllMeetings.filter((meeting) => gDelegate.contains(bounds, meeting.latitude, meeting.longitude));
17872
18375
  }
17873
18376
  function onDragStart() {
17874
- isMouseDown = true;
18377
+ gCurrentlyDraggingMap = true;
17875
18378
  // if no [crouton_map], then show all meetings
17876
18379
  if (!config.map_search) filterVisible(false);
17877
18380
  gDelegate.addListener('dragend', onDragEnd, true);
17878
18381
  }
17879
18382
  function onDragEnd() {
17880
- isMouseDown = false;
18383
+ gCurrentlyDraggingMap = false;
17881
18384
  // if no [crouton_map], then turn filter visible back on.
17882
18385
  if (config.map_search && isFilterVisible()) triggerCroutonMapNewQuery(null);
17883
18386
  else filterVisible(true);
17884
18387
  }
17885
18388
  function triggerCroutonMapNewQuery(ev) {
17886
- if (isMouseDown) return;
18389
+ if (gCurrentlyDraggingMap) return;
17887
18390
  gMeetingIdsFromCrouton = null;
17888
18391
  corners = gDelegate.getCorners();
17889
- if (oldBounds && gDelegate.contains(oldBounds,corners.ne.lat,corners.ne.lng)
17890
- && gDelegate.contains(oldBounds,corners.sw.lat,corners.sw.lng)) {
18392
+ if (gOldBounds && gDelegate.contains(gOldBounds,corners.ne.lat,corners.ne.lng)
18393
+ && gDelegate.contains(gOldBounds,corners.sw.lat,corners.sw.lng)) {
17891
18394
  filterVisible();
17892
18395
  } else if (getScreenRadius('km') > config.maxTomatoWidth) {
17893
18396
  jQuery('#zoomed-out-message').removeClass('hide');
17894
18397
  showBmltSearchDialog(null);
17895
18398
  } else {
17896
- oldBounds = gDelegate.getBounds();
18399
+ gOldBounds = gDelegate.getBounds();
17897
18400
  showThrobber();
17898
18401
  crouton.searchByCoordinates(gDelegate.getCenter().lat, gDelegate.getCenter().lng, getScreenRadius(), false);
17899
18402
  }
17900
18403
  }
17901
- function filterVisible(on=true) {
17902
- if (on==listOnlyVisible && !config.map_search) return on;
17903
- let mtgs = on ? filterBounds(gDelegate.getBounds()) : gAllMeetings;
18404
+ function filterVisible(on=true, bounds = gDelegate.getBounds()) {
18405
+ if (on==gListOnlyVisible && !config.map_search) return on;
18406
+ let mtgs = on ? filterBounds(bounds) : gAllMeetings;
17904
18407
  let visible = mtgs.map((m)=>m.id_bigint);
17905
18408
  jQuery(".bmlt-data-row").each(function(index,row) {
17906
18409
  row.dataset.visible = (visible.includes(row.id.split('-').pop())) ? '1' : '0';
17907
18410
  });
17908
18411
  jQuery("#byday").removeClass('hide');
17909
18412
  jQuery("#filter-dropdown-visibile").val(on?'a-1':'');
17910
- fitDuringFilter = false;
17911
- crouton.simulateFilterDropdown();
17912
- fitDuringFilter = true;
18413
+ gAllowExpandViewport = false; // calling simulateFilterDropdown will callback croutonMap to set the filtered Ids.
18414
+ crouton.simulateFilterDropdown(); // but we don't want to expand the viewport.
18415
+ gAllowExpandViewport = true;
17913
18416
  jQuery("#filteringByVisibility").html(on?'&#10004;':'');
17914
- listOnlyVisible = on;
17915
- if (on) listener = gDelegate.addListener('dragstart', onDragStart, true);
17916
- else if (listener) {
17917
- gDelegate.removeListener(listener);
17918
- listener = null;
18417
+ gListOnlyVisible = on;
18418
+ if (on) gDragStartListener = gDelegate.addListener('dragstart', onDragStart, true);
18419
+ else if (gDragStartListener) {
18420
+ gDelegate.removeListener(gDragStartListener);
18421
+ gDragStartListener = null;
17919
18422
  }
17920
18423
  return !on;
17921
18424
  }
17922
18425
  function toggleVisible() {
17923
- filterVisible(!listOnlyVisible);
18426
+ filterVisible(!gListOnlyVisible);
17924
18427
  }
17925
18428
  function filterBounds(bounds) {
17926
- var ret = gAllMeetings.filter((meeting) =>
18429
+ const ret = gAllMeetings.filter((meeting) =>
17927
18430
  gDelegate.contains(bounds, meeting.latitude, meeting.longitude));
17928
18431
  return ret;
17929
18432
  }
@@ -17933,31 +18436,31 @@ function MeetingMap(inConfig) {
17933
18436
  if ((gDelegate.getZoom()>=14) && gDelegate.contains(gDelegate.getBounds(), meeting.latitude, meeting.longitude)) {
17934
18437
  gDelegate.openMarker(meetingId);
17935
18438
  } else {
17936
- gDelegate.setViewToPosition({latitude: meeting.latitude, longitude: meeting.longitude}, filterMeetingsAndBounds, function() {gDelegate.openMarker(meetingId);});
18439
+ gDelegate.flyToFixedZoom({lat: meeting.latitude, lng: meeting.longitude}, config.focusedMeetingPopupZoomLevel ?? 14, function() {gDelegate.openMarker(meetingId);});
17937
18440
  }
17938
18441
  }
17939
18442
  function filterMeetingsAndBounds(bounds) {
17940
18443
  return filterMeetings(filterBounds(bounds));
17941
18444
  }
17942
18445
  function filterMeetings(in_meetings_array) {
17943
- var ret = in_meetings_array.filter(m => m.venue_type != 2);
18446
+ const ret = in_meetings_array.filter(m => m.venue_type != 2);
17944
18447
  if (gMeetingIdsFromCrouton != null) {
17945
18448
  return ret.filter((m) => gMeetingIdsFromCrouton.includes(m.id_bigint));
17946
18449
  }
17947
18450
  return ret;
17948
18451
  }
17949
- var _isPseudoFullscreen = false;
18452
+ var gIsPseudoFullscreen = false;
17950
18453
  function isFullscreen() {
17951
- var fullscreenElement =
18454
+ const fullscreenElement =
17952
18455
  document.fullscreenElement ||
17953
18456
  document.mozFullScreenElement ||
17954
18457
  document.webkitFullscreenElement ||
17955
18458
  document.msFullscreenElement;
17956
18459
 
17957
- return (fullscreenElement === gInDiv) || _isPseudoFullscreen;
18460
+ return (fullscreenElement === gInDiv) || gIsPseudoFullscreen;
17958
18461
  }
17959
18462
  function toggleFullscreen(options) {
17960
- var container = gInDiv;
18463
+ const container = gInDiv;
17961
18464
  if (isFullscreen()) {
17962
18465
  if (options && options.pseudoFullscreen) {
17963
18466
  _setFullscreen(false);
@@ -17988,10 +18491,9 @@ function MeetingMap(inConfig) {
17988
18491
  }
17989
18492
  }
17990
18493
  }
17991
- var _isPseudoFullscreen = false;
17992
18494
  function _setFullscreen(fullscreen) {
17993
- _isPseudoFullscreen = fullscreen;
17994
- var container = gInDiv;
18495
+ gIsPseudoFullscreen = fullscreen;
18496
+ const container = gInDiv;
17995
18497
  if (fullscreen) {
17996
18498
  L.DomUtil.addClass(container, 'leaflet-pseudo-fullscreen');
17997
18499
  } else {
@@ -18006,6 +18508,12 @@ function MeetingMap(inConfig) {
18006
18508
  }
18007
18509
  gDelegate.invalidateSize();
18008
18510
  if (!gAllMeetings) return;
18511
+ if (gLocationSearchResult) {
18512
+ searchResponseCallback();
18513
+ filterVisible(false);
18514
+ gDelegate.flyToFixedZoom(gLocationSearchResult.center, gLocationSearchResult.zoom, filterVisible);
18515
+ gLocationSearchResult = null;
18516
+ }
18009
18517
  if (fitBounds) gDelegate.fitBounds(
18010
18518
  ((gMeetingIdsFromCrouton) ? gAllMeetings.filter((m) => gMeetingIdsFromCrouton.includes(m.id_bigint)) : gAllMeetings)
18011
18519
  .reduce(function(a,m) {a.push([m.latitude, m.longitude]); return a;},[])
@@ -18016,14 +18524,14 @@ function MeetingMap(inConfig) {
18016
18524
  }
18017
18525
 
18018
18526
  function getDistance(p1, p2) {
18019
- var R = 6378137; // Earth’s mean radius in meter
18020
- var dLat = rad(p2.lat - p1.lat);
18021
- var dLong = rad(p2.lng - p1.lng);
18022
- var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
18527
+ const R = 6378137; // Earth’s mean radius in meter
18528
+ const dLat = rad(p2.lat - p1.lat);
18529
+ const dLong = rad(p2.lng - p1.lng);
18530
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
18023
18531
  Math.cos(rad(p1.lat)) * Math.cos(rad(p2.lat)) *
18024
18532
  Math.sin(dLong / 2) * Math.sin(dLong / 2);
18025
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
18026
- var d = R * c;
18533
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
18534
+ const d = R * c;
18027
18535
  return d; // returns the distance in meter
18028
18536
  }
18029
18537
  function getDistanceFromSearch(p) {
@@ -18046,7 +18554,7 @@ function MeetingMap(inConfig) {
18046
18554
  ****************************************************************************************/
18047
18555
  this.initialize = loadFromCrouton;
18048
18556
  this.showMap = showMap;
18049
- this.fillMap = filterFromCrouton;
18557
+ this.setFilteredIds = setFilteredIds;
18050
18558
  this.rowClick = focusOnMeeting;
18051
18559
  this.apiLoadedCallback = apiLoadedCallback;
18052
18560
  this.refreshMeetings = loadAllMeetings;
@@ -18056,17 +18564,22 @@ function MeetingMap(inConfig) {
18056
18564
  this.loadPopupMap = loadPopupMap;
18057
18565
  this.filterVisible = filterVisible;
18058
18566
  this.hasMapSearch = hasMapSearch;
18567
+ this.createLocationSearchButton = createLocationSearchButton;
18568
+ this.latLngToWebMercator = latLngToWebMercator;
18569
+ this.webMercatorToLatLng = webMercatorToLatLng;
18059
18570
  };
18060
18571
  MeetingMap.prototype.initialize = null;
18061
18572
  MeetingMap.prototype.showMap = null;
18062
- MeetingMap.prototype.fillMap = null;
18573
+ MeetingMap.prototype.setFilteredIds = null;
18063
18574
  MeetingMap.prototype.rowClick = null;
18064
18575
  MeetingMap.prototype.apiLoadedCallback = null;
18065
18576
  MeetingMap.prototype.refreshMeetings = null;
18066
18577
  MeetingMap.prototype.getDistanceFromSearch = null;
18067
-
18578
+ MeetingMap.prototype.latLngToWebMercator = null; // called from delegates - yuck!
18579
+ MeetingMap.prototype.webMercatorToLatLng = null; // called from delegates - yuck!
18068
18580
  MeetingMap.prototype.openModalWindow = null;
18069
18581
  MeetingMap.prototype.closeModalWindow = null;
18070
18582
  MeetingMap.prototype.loadPopupMap = null;
18071
18583
  MeetingMap.prototype.filterVisible = null;
18072
18584
  MeetingMap.prototype.hasMapSearch = null;
18585
+ MeetingMap.prototype.createLocationSearchButton = null;