@bmlt-enabled/croutonjs 4.1.11 → 4.3.1

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.
package/crouton-gmaps.js CHANGED
@@ -11189,7 +11189,9 @@ function CroutonLocalization(language) {
11189
11189
  'all': 'الجميع',
11190
11190
  'menu': 'القائمة',
11191
11191
  'search for meetings': 'البحث عن الاجتماعات',
11192
+ 'search by location': 'البحث حسب الموقع',
11192
11193
  'show meetings near...': 'أظهر الاجتماعات بالقرب من...',
11194
+ 'closest meetings': 'أقرب الاجتماعات',
11193
11195
  'filter meetings': 'سرد الاجتماعات',
11194
11196
  'visible meeting list': 'قائمة الاجتماعات المرئية',
11195
11197
  'enter a city or zip code': 'أدخل المدينة أو الرمز البريدي',
@@ -11210,6 +11212,9 @@ function CroutonLocalization(language) {
11210
11212
  "waze": "وايز",
11211
11213
  "waze_desc": "فتح في تطبيق وايز",
11212
11214
  'address_lookup_fail': 'تعذر العثور على العنوان. يرجى المحاولة مرة أخرى.',
11215
+ "favorites": "المفضلة",
11216
+ "widen search": "البحث الواسع",
11217
+ "cancel search": "إلغاء البحث"
11213
11218
  },
11214
11219
  "cs": {
11215
11220
  "days_of_the_week": ["", "Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"],
@@ -11249,7 +11254,9 @@ function CroutonLocalization(language) {
11249
11254
  "all": "Jakékoli",
11250
11255
  "menu": "Menu",
11251
11256
  "search for meetings": "Hledat setkání",
11257
+ 'search by location': 'Vyhledávání podle lokality',
11252
11258
  "show meetings near...": "Setkání v jiných městech",
11259
+ 'closest meetings': "Nejbližší setkání",
11253
11260
  "filter meetings": "Filtr pro jazyk, formát atd.",
11254
11261
  "visible meeting list": "Viditelný seznam setkání jako tabulka",
11255
11262
  "enter a city or zip code": "Město nebo PSČ",
@@ -11260,7 +11267,6 @@ function CroutonLocalization(language) {
11260
11267
  "meeting details": "Podrobnosti o setkání",
11261
11268
  "report update": "Nahlásit aktualizaci",
11262
11269
  "filter by visibility": "Zobrazit pouze setkání, která jsou aktuálně na mapě",
11263
- "go": "Jít!",
11264
11270
  "get_directions": "Získat pokyny",
11265
11271
  "select_map_app": "Vyberte aplikaci pro mapy",
11266
11272
  "apple_maps": "Apple Mapy",
@@ -11275,6 +11281,9 @@ function CroutonLocalization(language) {
11275
11281
  "sorted by distance": "Seřazeno podle vzdálenosti",
11276
11282
  "address_lookup_fail": "Adresu se nepodařilo najít. Zkuste to prosím znovu.",
11277
11283
  "contact": "Kontakt",
11284
+ "favorites": "Oblíbené",
11285
+ "widen search": "Rozšířit vyhledávání",
11286
+ "cancel search": "Zrušit vyhledávání",
11278
11287
  },
11279
11288
  "da-DK": {
11280
11289
  "days_of_the_week": ["", "Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"],
@@ -11291,7 +11300,7 @@ function CroutonLocalization(language) {
11291
11300
  "formats": "Struktur",
11292
11301
  "map": "Kort",
11293
11302
  "neighborhood": "Neighborhood",
11294
- "near_me": "Find nearby meetings",
11303
+ "near_me": "Find closest meetings",
11295
11304
  "text_search": "Find meetings there",
11296
11305
  "click_search": "Find meetings near to a point on the map",
11297
11306
  "pan_and_zoom": "Pan + Zoom",
@@ -11321,7 +11330,9 @@ function CroutonLocalization(language) {
11321
11330
  'menu': 'Menu',
11322
11331
  "bmlt2ics": "Add to your calendar",
11323
11332
  'search for meetings': 'Search for meetings',
11333
+ 'search by location': 'Søg efter placering',
11324
11334
  'show meetings near...': 'Show meetings near...',
11335
+ 'closest meetings': 'Nærmeste møder',
11325
11336
  'filter meetings': 'Filter meetings',
11326
11337
  'visible meeting list': 'Visible meetings as list',
11327
11338
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11341,6 +11352,9 @@ function CroutonLocalization(language) {
11341
11352
  "sorted by distance": "Sorteret efter Afstand",
11342
11353
  "address_lookup_fail": "Adressen kunne ikke findes. Prøv venligst igen.",
11343
11354
  "contact": "Kontakt",
11355
+ "favorites": "Favoritter",
11356
+ "widen search": "Udvid søgning",
11357
+ "cancel search": "Annuller søgning",
11344
11358
  },
11345
11359
  "de-DE": {
11346
11360
  "days_of_the_week": ["", "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
@@ -11386,7 +11400,9 @@ function CroutonLocalization(language) {
11386
11400
  'all': 'Alle',
11387
11401
  'menu': 'Menu',
11388
11402
  'search for meetings': 'Search for meetings',
11403
+ 'search by location': 'Suche nach Standort',
11389
11404
  'show meetings near...': 'Meetings in andere Städten',
11405
+ 'closest meetings': 'Nächstgelegene Meetings',
11390
11406
  'filter meetings': 'Filter für Sprache, Format usw.',
11391
11407
  'visible meeting list': 'Sichtbare Meetings als Tabelle',
11392
11408
  'enter a city or zip code': 'Stadt oder PLZ',
@@ -11397,7 +11413,6 @@ function CroutonLocalization(language) {
11397
11413
  'meeting details': "Genaueres zum Meeting",
11398
11414
  'report update': "Report an Update",
11399
11415
  'filter by visibility': "Zeige nur Meetings, die gerade auf dem Karte stehen",
11400
- 'go': "Los!",
11401
11416
  "get_directions": "Wegbeschreibung",
11402
11417
  "select_map_app": "Karten-App auswählen",
11403
11418
  "apple_maps": "Apple Maps",
@@ -11415,6 +11430,9 @@ function CroutonLocalization(language) {
11415
11430
  "distance": "Entfernung",
11416
11431
  "all meetings": "Alle Meetings",
11417
11432
  'upcoming meetings': "Nächste 24 Stunden",
11433
+ "favorites": "Favoriten",
11434
+ "widen search": "Suche ausweiten",
11435
+ "cancel search": "Abbrechen",
11418
11436
  },
11419
11437
  'el-GR': {
11420
11438
  "days_of_the_week": ["", "Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"],
@@ -11460,7 +11478,9 @@ function CroutonLocalization(language) {
11460
11478
  "all": "",
11461
11479
  "menu": "Μενού",
11462
11480
  "search for meetings": "Αναζήτηση ομάδων",
11481
+ 'search by location': 'Αναζήτηση ανά τοποθεσία',
11463
11482
  "show meetings near...": "Εμφάνιση ομάδων κοντά σε..",
11483
+ "closest meetings": "Πλησιέστερες Συναντήσεις",
11464
11484
  "filter meetings": "Φίλτραρε τις ομάδες",
11465
11485
  "visible meeting list": "Λίστα ορατών ομάδων",
11466
11486
  "enter a city or zip code": "Εισαγάγετε μια πόλη ή ταχυδρομικό κώδικα",
@@ -11472,7 +11492,6 @@ function CroutonLocalization(language) {
11472
11492
  "report update": "Ανέφερε ενημέρωση",
11473
11493
  "filter by visibility": "Φίλτραρε ανα ορατές ομάδες",
11474
11494
  "open search dialog": "’νοιξε αναζήτηση",
11475
- "go": "Έναρξη",
11476
11495
  "get_directions": "Λάβετε οδηγίες",
11477
11496
  "select_map_app": "Διαλέξτε εφαρμογή χάρτη",
11478
11497
  "apple_maps": "Χάρτες Apple",
@@ -11507,6 +11526,9 @@ function CroutonLocalization(language) {
11507
11526
  "meets virtually and in person": "Διαδικτυακή και φυσική ομάδα",
11508
11527
  "all meetings": "Όλες οι ομάδες",
11509
11528
  "upcoming meetings": "Προσεχείς ομάδες",
11529
+ "favorites": "Αγαπημένα",
11530
+ "widen search": "Διεύρυνση αναζήτησης",
11531
+ "cancel search": "Ακύρωση αναζήτησης",
11510
11532
  },
11511
11533
  "en-AU": {
11512
11534
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11523,7 +11545,7 @@ function CroutonLocalization(language) {
11523
11545
  "formats": "Formats",
11524
11546
  "map": "Map",
11525
11547
  "neighborhood": "Neighbourhood",
11526
- "near_me": "Find nearby meetings",
11548
+ "near_me": "Find closest meetings",
11527
11549
  "text_search": "Find meetings there",
11528
11550
  "click_search": "Find meetings near to a point on the map",
11529
11551
  "languages": "Languages",
@@ -11552,7 +11574,9 @@ function CroutonLocalization(language) {
11552
11574
  'all': 'All',
11553
11575
  'menu': 'Menu',
11554
11576
  'search for meetings': 'Search for meetings',
11577
+ 'search by location': 'Search by Location',
11555
11578
  'show meetings near...': 'Show meetings near...',
11579
+ 'closest meetings': "Closest Meetings",
11556
11580
  'filter meetings': 'Filter meetings',
11557
11581
  'visible meeting list': 'Visible meetings as list',
11558
11582
  'enter a city or zip code': 'Enter a city and state',
@@ -11575,6 +11599,9 @@ function CroutonLocalization(language) {
11575
11599
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11576
11600
  "sorted by distance": "Sorted by Distance",
11577
11601
  "address_lookup_fail": "The address could not be found. Please try again.",
11602
+ "favorites": "Favorites",
11603
+ "widen search": "Widen Search",
11604
+ "cancel search": "Cancel Search",
11578
11605
  },
11579
11606
  "en-CA": {
11580
11607
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11591,7 +11618,7 @@ function CroutonLocalization(language) {
11591
11618
  "formats": "Formats",
11592
11619
  "map": "Map",
11593
11620
  "neighborhood": "Neighborhood",
11594
- "near_me": "Find nearby meetings",
11621
+ "near_me": "Find closest meetings",
11595
11622
  "text_search": "Find meetings there",
11596
11623
  "click_search": "Find meetings near to a point on the map",
11597
11624
  "pan_and_zoom": "Pan + Zoom",
@@ -11620,7 +11647,9 @@ function CroutonLocalization(language) {
11620
11647
  'all': 'All',
11621
11648
  'menu': 'Menu',
11622
11649
  'search for meetings': 'Search for meetings',
11650
+ 'search by location': 'Search by Location',
11623
11651
  'show meetings near...': 'Show meetings near...',
11652
+ 'closest meetings': "Closest Meetings",
11624
11653
  'filter meetings': 'Filter meetings',
11625
11654
  'visible meeting list': 'Visible meetings as list',
11626
11655
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11644,6 +11673,9 @@ function CroutonLocalization(language) {
11644
11673
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11645
11674
  "sorted by distance": "Sorted by Distance",
11646
11675
  "address_lookup_fail": "The address could not be found. Please try again.",
11676
+ "favorites": "Favorites",
11677
+ "widen search": "Widen Search",
11678
+ "cancel search": "Cancel Search",
11647
11679
  },
11648
11680
  "en-NZ": {
11649
11681
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11660,7 +11692,7 @@ function CroutonLocalization(language) {
11660
11692
  "formats": "Formats",
11661
11693
  "map": "Map",
11662
11694
  "neighborhood": "Neighborhood",
11663
- "near_me": "Find nearby meetings",
11695
+ "near_me": "Find closest meetings",
11664
11696
  "text_search": "Find meetings there",
11665
11697
  "click_search": "Find meetings near to a point on the map",
11666
11698
  "pan_and_zoom": "Pan + Zoom",
@@ -11689,7 +11721,9 @@ function CroutonLocalization(language) {
11689
11721
  'all': 'All',
11690
11722
  'menu': 'Menu',
11691
11723
  'search for meetings': 'Search for meetings',
11724
+ 'search by location': 'Search by Location',
11692
11725
  'show meetings near...': 'Show meetings near...',
11726
+ 'closest meetings': "Closest Meetings",
11693
11727
  'filter meetings': 'Filter meetings',
11694
11728
  'visible meeting list': 'Visible meetings as list',
11695
11729
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11713,6 +11747,9 @@ function CroutonLocalization(language) {
11713
11747
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11714
11748
  "sorted by distance": "Sorted by Distance",
11715
11749
  "address_lookup_fail": "The address could not be found. Please try again.",
11750
+ "favorites": "Favorites",
11751
+ "widen search": "Widen Search",
11752
+ "cancel search": "Cancel Search",
11716
11753
  },
11717
11754
  "en-UK": {
11718
11755
  "days_of_the_week": ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
@@ -11729,7 +11766,7 @@ function CroutonLocalization(language) {
11729
11766
  "formats": "Formats",
11730
11767
  "map": "Map",
11731
11768
  "neighborhood": "Neighborhood",
11732
- "near_me": "Find nearby meetings",
11769
+ "near_me": "Find closest meetings",
11733
11770
  "text_search": "Find meetings there",
11734
11771
  "click_search": "Find meetings near to a point on the map",
11735
11772
  "pan_and_zoom": "Pan + Zoom",
@@ -11759,7 +11796,9 @@ function CroutonLocalization(language) {
11759
11796
  'menu': "Menu",
11760
11797
  "bmlt2ics": "Add to your calendar",
11761
11798
  'search for meetings': 'Search for meetings',
11799
+ 'search by location': 'Search by Location',
11762
11800
  'show meetings near...': 'Show meetings near...',
11801
+ 'closest meetings': "Closest Meetings",
11763
11802
  'filter meetings': 'Filter meetings',
11764
11803
  'visible meeting list': 'Visible meetings as list',
11765
11804
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11782,6 +11821,9 @@ function CroutonLocalization(language) {
11782
11821
  "zoomed-out-message": "We can't search the entire area for meetings. Please zoom in or do a new search.",
11783
11822
  "sorted by distance": "Sorted by Distance",
11784
11823
  "address_lookup_fail": "The address could not be found. Please try again.",
11824
+ "favorites": "Favorites",
11825
+ "widen search": "Widen Search",
11826
+ "cancel search": "Cancel Search",
11785
11827
  },
11786
11828
 
11787
11829
  "en-US": {
@@ -11799,7 +11841,7 @@ function CroutonLocalization(language) {
11799
11841
  "formats": "Formats",
11800
11842
  "map": "Map",
11801
11843
  "neighborhood": "Neighborhood",
11802
- "near_me": "Find nearby meetings",
11844
+ "near_me": "Find closest meetings",
11803
11845
  "text_search": "Find meetings there",
11804
11846
  "click_search": "Find meetings near to a point on the map",
11805
11847
  "pan_and_zoom": "Pan + Zoom",
@@ -11828,7 +11870,9 @@ function CroutonLocalization(language) {
11828
11870
  'all': 'All',
11829
11871
  'menu': "Menu",
11830
11872
  'search for meetings': 'Search for meetings',
11873
+ 'search by location': 'Search by Location',
11831
11874
  'show meetings near...': 'Show meetings near...',
11875
+ 'closest meetings': "Closest Meetings",
11832
11876
  'filter meetings': 'Filter meetings',
11833
11877
  'visible meeting list': 'Visible meetings as list',
11834
11878
  'enter a city or zip code': 'Enter a city or zip code',
@@ -11875,6 +11919,10 @@ function CroutonLocalization(language) {
11875
11919
  "more info": "More Info",
11876
11920
  "all meetings": "All Meetings",
11877
11921
  'upcoming meetings': "Upcoming Meetings",
11922
+ "favorites": "Favorites",
11923
+ "choose one": "Choose one:",
11924
+ "widen search": "Widen Search",
11925
+ "cancel search": "Cancel Search",
11878
11926
  },
11879
11927
  "es-US": {
11880
11928
  "days_of_the_week": ["", "Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
@@ -11921,7 +11969,9 @@ function CroutonLocalization(language) {
11921
11969
  'all': 'Todos',
11922
11970
  'menu': "Menú",
11923
11971
  'search for meetings': 'Buscar reuniones',
11972
+ 'search by location': 'Buscar por ubicación',
11924
11973
  'show meetings near...': 'Mostrar reuniones cercanas...',
11974
+ 'closest meetings': 'Reuniones más cercanas',
11925
11975
  'filter meetings': 'Filtrar reuniones',
11926
11976
  'visible meeting list': 'Listado visible de reuniones',
11927
11977
  'enter a city or zip code': 'Introduce una ciudad o un código postal',
@@ -11945,6 +11995,9 @@ function CroutonLocalization(language) {
11945
11995
  "zoomed-out-message": "No podemos buscar reuniones en toda la zona. Por favor, acérquese o haga una nueva búsqueda.",
11946
11996
  "sorted by distance": "Ordenado por distancia",
11947
11997
  "address_lookup_fail": "The address could not be found. Please try again.",
11998
+ "favorites": "Favoritos",
11999
+ "widen search": "Búsqueda amplia",
12000
+ "cancel search": "Cancelar búsqueda",
11948
12001
  },
11949
12002
  "fa-IR": {
11950
12003
  "days_of_the_week": ["", 'یَکشَنب', 'دوشَنبه', 'سه‌شنبه', 'چهار شنبه', 'پَنج شَنبه', 'جُمعه', 'شَنبه'],
@@ -11997,7 +12050,9 @@ function CroutonLocalization(language) {
11997
12050
  "all": "همه",
11998
12051
  "menu": " منوی",
11999
12052
  "search for meetings": "جستجوی جلسه ها",
12053
+ 'search by location': 'جستجو بر اساس مکان',
12000
12054
  "show meetings near...": "نمایش جلسات نزدیک",
12055
+ "closest meetings": "نزدیک ترین ملاقات ها",
12001
12056
  "filter meetings": "فیلتر جلسات",
12002
12057
  "visible meeting list": "جلسات قابل مشاهده به عنوان لیست",
12003
12058
  "enter a city or zip code": "شهر یا کد پستی را وارد کنید",
@@ -12008,7 +12063,6 @@ function CroutonLocalization(language) {
12008
12063
  "meeting details": "جزئیات جلسه",
12009
12064
  "report update": "گزارش به‌روزرسانی",
12010
12065
  "filter by visibility": "فقط این جلسات را فهرست کنید",
12011
- "go": "برو",
12012
12066
  "distance": "فاصله",
12013
12067
  "get_directions": "دریافت مسیر",
12014
12068
  "select_map_app": "انتخاب برنامه نقشه",
@@ -12027,6 +12081,9 @@ function CroutonLocalization(language) {
12027
12081
  'comments': 'توضیحات',
12028
12082
  'group details': 'نمایش گروه',
12029
12083
  "address_lookup_fail": "آدرس پیدا نشد. لطفا دوباره تلاش کنید.",
12084
+ "favorites": "مورد علاقه",
12085
+ "widen search": "جستجوی گسترده",
12086
+ "cancel search": "لغو جستجو",
12030
12087
  },
12031
12088
  "fr-CA": {
12032
12089
  "days_of_the_week": ["", "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
@@ -12072,7 +12129,9 @@ function CroutonLocalization(language) {
12072
12129
  "all": "Tout",
12073
12130
  "menu": "Menu",
12074
12131
  "search for meetings": "Rechercher des réunions",
12132
+ 'search by location': 'Recherche par localisation',
12075
12133
  "show meetings near...": "Afficher les réunions près de...",
12134
+ "closest meetings": "Réunions les plus proches",
12076
12135
  "filter meetings": "Filtrer les réunions",
12077
12136
  "visible meeting list": "Liste des réunions visibles",
12078
12137
  "enter a city or zip code": "Entrer une ville ou un code postal",
@@ -12095,6 +12154,9 @@ function CroutonLocalization(language) {
12095
12154
  "waze_desc": "Ouvrir dans l'application Waze",
12096
12155
  "sorted by distance": "Trié par distance",
12097
12156
  "address_lookup_fail": "L'adresse est introuvable. Veuillez réessayer.",
12157
+ "favorites": "Favoris",
12158
+ "widen search": "Recherche élargie",
12159
+ "cancel search": "Annuler la recherche",
12098
12160
  },
12099
12161
  "it-IT": {
12100
12162
  "days_of_the_week": ["", "Domenica", " Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"],
@@ -12140,7 +12202,9 @@ function CroutonLocalization(language) {
12140
12202
  'all': 'Tutti',
12141
12203
  'menu': "Menu",
12142
12204
  'search for meetings': 'Search for meetings',
12205
+ 'search by location': 'Cerca per posizione',
12143
12206
  'show meetings near...': 'Mostra incontri nelle vicinanze..',
12207
+ 'closest meetings': "Riunioni più ravvicinati",
12144
12208
  'filter meetings': 'Filtrare le riunioni',
12145
12209
  'visible meeting list': 'Elenco riunioni visibile',
12146
12210
  'enter a city or zip code': 'Inserire una città o un codice postale',
@@ -12163,6 +12227,9 @@ function CroutonLocalization(language) {
12163
12227
  "waze_desc": "Apri nell'app Waze",
12164
12228
  "sorted by distance": "Ordinati per distanza",
12165
12229
  "address_lookup_fail": "L'indirizzo non è stato trovato. Per favore riprova.",
12230
+ "favorites": "Preferiti",
12231
+ "widen search": "Ricerca larga",
12232
+ "cancel search": "Annulla ricerca",
12166
12233
  },
12167
12234
  "nl-NL": {
12168
12235
  "days_of_the_week": ["", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
@@ -12208,6 +12275,7 @@ function CroutonLocalization(language) {
12208
12275
  'all': 'All',
12209
12276
  'menu': "Menu",
12210
12277
  'search for meetings': 'Search for meetings',
12278
+ 'search by location': 'Search by Location',
12211
12279
  'show meetings near...': 'Show meetings near...',
12212
12280
  'filter meetings': 'Filter meetings',
12213
12281
  'visible meeting list': 'Visible meetings as list',
@@ -12275,6 +12343,7 @@ function CroutonLocalization(language) {
12275
12343
  'all': 'All',
12276
12344
  'menu': "Menu",
12277
12345
  'search for meetings': 'Search for meetings',
12346
+ 'search by location': 'Search by Location',
12278
12347
  'show meetings near...': 'Show meetings near...',
12279
12348
  'filter meetings': 'Filter meetings',
12280
12349
  'visible meeting list': 'Visible meetings as list',
@@ -12298,6 +12367,9 @@ function CroutonLocalization(language) {
12298
12367
  "waze_desc": "Otwórz w aplikacji Waze",
12299
12368
  "sorted by distance": "Posortowane według odległości",
12300
12369
  "address_lookup_fail": "The address could not be found. Please try again.",
12370
+ "favorites": "Ulubione",
12371
+ "widen search": "Widen Search",
12372
+ "cancel search": "Cancel Search",
12301
12373
  },
12302
12374
  "pt-BR": {
12303
12375
  "days_of_the_week": ["", "Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado"],
@@ -12344,6 +12416,7 @@ function CroutonLocalization(language) {
12344
12416
  'menu': "Menu",
12345
12417
  "bmlt2ics": "Add to your calendar",
12346
12418
  'search for meetings': 'Search for meetings',
12419
+ 'search by location': 'Search by Location',
12347
12420
  'show meetings near...': 'Show meetings near...',
12348
12421
  'filter meetings': 'Filter meetings',
12349
12422
  'visible meeting list': 'Visible meetings as list',
@@ -12366,6 +12439,9 @@ function CroutonLocalization(language) {
12366
12439
  "waze_desc": "Abrir no aplicativo Waze",
12367
12440
  "sorted by distance": "Classificado por distância",
12368
12441
  "address_lookup_fail": "The address could not be found. Please try again.",
12442
+ "favorites": "Favoritos",
12443
+ "widen search": "Widen Search",
12444
+ "cancel search": "Cancel Search",
12369
12445
  },
12370
12446
  "ru-RU": {
12371
12447
  "days_of_the_week": ["", "Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"],
@@ -12412,7 +12488,9 @@ function CroutonLocalization(language) {
12412
12488
  'menu': "Меню",
12413
12489
  "bmlt2ics": "Добавить в календарь",
12414
12490
  'search for meetings': 'Поиск собраний',
12491
+ 'search by location': 'Поиск по местонахождению',
12415
12492
  'show meetings near...': 'Показывать собрания рядом с...',
12493
+ 'closest meetings': 'Ближайшие встречи',
12416
12494
  'filter meetings': 'Фильтровать собрания',
12417
12495
  'visible meeting list': 'Собрания в виде списка',
12418
12496
  'enter a city or zip code': 'Введите город или почтовый индек',
@@ -12422,7 +12500,6 @@ function CroutonLocalization(language) {
12422
12500
  'meeting details': "Подробности собрания",
12423
12501
  'report update': "Report an Update",
12424
12502
  'filter by visibility': "List only these meetings",
12425
- 'go': "Go!",
12426
12503
  "distance": "Расстояние",
12427
12504
  "get_directions": "Проложить маршрут",
12428
12505
  "select_map_app": "Выбрать приложение карт",
@@ -12434,6 +12511,9 @@ function CroutonLocalization(language) {
12434
12511
  "waze_desc": "Открыть в приложении Waze",
12435
12512
  "sorted by distance": "Сортировка по расстоянию",
12436
12513
  "address_lookup_fail": "Адрес не найден. Пожалуйста, попробуйте еще раз.",
12514
+ "favorites": "Избранное",
12515
+ "widen search": "Расширить поиск",
12516
+ "cancel search": "Отмена поиска",
12437
12517
  },
12438
12518
  "sk": {
12439
12519
  "days_of_the_week": ["", "Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"],
@@ -12473,7 +12553,9 @@ function CroutonLocalization(language) {
12473
12553
  "all": "Akékoľvek",
12474
12554
  "menu": "Menu",
12475
12555
  "search for meetings": "Hľadať stretnutia",
12556
+ 'search by location': 'Vyhľadávanie podľa lokality',
12476
12557
  "show meetings near...": "Stretnutia v iných mestách",
12558
+ "closest meetings": "Najbližšie stretnutia",
12477
12559
  "filter meetings": "Filter pre jazyk, formát atď.",
12478
12560
  "visible meeting list": "Viditeľné stretnutia ako tabuľka",
12479
12561
  "enter a city or zip code": "Mesto alebo PSČ",
@@ -12484,7 +12566,6 @@ function CroutonLocalization(language) {
12484
12566
  "meeting details": "Podrobnosti o stretnutí",
12485
12567
  "report update": "Nahlásiť aktualizáciu",
12486
12568
  "filter by visibility": "Zobraziť iba stretnutia, ktoré sú práve na mape",
12487
- "go": "Ísť!",
12488
12569
  "get_directions": "Získať trasu",
12489
12570
  "select_map_app": "Vyberte aplikáciu pre mapy",
12490
12571
  "apple_maps": "Apple Maps",
@@ -12498,6 +12579,9 @@ function CroutonLocalization(language) {
12498
12579
  "zoomed-out-message": "Nemôžeme prehľadať celú oblasť pre stretnutia. Prosím, priblížte alebo vykonajte nové vyhľadávanie.",
12499
12580
  "sorted by distance": "Zoradené podľa vzdialenosti",
12500
12581
  "address_lookup_fail": "Adresa sa nenašla. Skúste to znova prosím.",
12582
+ "favorites": "Obľúbené",
12583
+ "widen search": "Rozšíriť vyhľadávanie",
12584
+ "cancel search": "Zrušiť vyhľadávanie",
12501
12585
  },
12502
12586
  "sv-SE": {
12503
12587
  "days_of_the_week": ["", "Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"],
@@ -12543,6 +12627,7 @@ function CroutonLocalization(language) {
12543
12627
  'all': 'All',
12544
12628
  'menu': "Menu",
12545
12629
  'search for meetings': 'Search for meetings',
12630
+ 'search by location': 'Search by Location',
12546
12631
  'show meetings near...': 'Show meetings near...',
12547
12632
  'filter meetings': 'Filter meetings',
12548
12633
  'visible meeting list': 'Visible meetings as list',
@@ -12671,6 +12756,9 @@ function CroutonHandlebarsExtensions() {
12671
12756
  ? options.fn(this)
12672
12757
  : options.inverse(this);
12673
12758
  });
12759
+ crouton_Handlebars.registerHelper('format_list_style', function(data, options) {
12760
+ return crouton.config.format_list_style === 'formatNames' ? 'formatNames' : 'formatKeys'
12761
+ });
12674
12762
  crouton_Handlebars.registerHelper('groupsConfigured', function(data, options) {
12675
12763
  if (crouton.config.groups) {
12676
12764
  return getTrueResult(options, this);
@@ -12682,8 +12770,8 @@ function CroutonHandlebarsExtensions() {
12682
12770
  * @deprecated Since version 3.12.2, will be removed in a future version.
12683
12771
  */
12684
12772
  crouton_Handlebars.registerHelper('isVirtual', function(data, options) {
12685
- return ((data['venue_type'] === venueType.HYBRID || data['venue_type'] === venueType.VIRTUAL) || ((inArray(getMasterFormatId('HY', data), getFormats(data)) && !inArray(getMasterFormatId('TC', data), getFormats(data)))
12686
- || inArray(getMasterFormatId('VM', data), getFormats(data))))
12773
+ return ((data['venue_type'] === venueType.HYBRID || data['venue_type'] === venueType.VIRTUAL) || ((getFormats(data).includes(getMasterFormatId('HY', data)) && !getFormats(data).includes(getMasterFormatId('TC', data)))
12774
+ || getFormats(data).includes(getMasterFormatId('VM', data))))
12687
12775
  && (data['virtual_meeting_link'] || data['phone_meeting_number'] || data['virtual_meeting_additional_info']) ? getTrueResult(options, this) : getFalseResult(options, this);
12688
12776
  });
12689
12777
 
@@ -12691,83 +12779,85 @@ function CroutonHandlebarsExtensions() {
12691
12779
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12692
12780
  */
12693
12781
  crouton_Handlebars.registerHelper('isVirtualOnly', function(data, options) {
12694
- return data['venue_type'] === venueType.VIRTUAL || inArray(getMasterFormatId('VM', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12782
+ return data['venue_type'] === venueType.VIRTUAL || getFormats(data).includes(getMasterFormatId('VM', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12695
12783
  });
12696
12784
 
12697
12785
  /**
12698
12786
  * @deprecated Since version 3.12.2 will be removed in a future version.
12699
12787
  */
12700
12788
  crouton_Handlebars.registerHelper('isHybrid', function(data, options) {
12701
- return data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12789
+ return data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12702
12790
  });
12703
12791
 
12704
12792
  /**
12705
12793
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12706
12794
  */
12707
12795
  crouton_Handlebars.registerHelper('isHybridOnly', function(data, options) {
12708
- return data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12796
+ return data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12709
12797
  });
12710
12798
 
12711
12799
  crouton_Handlebars.registerHelper('isTemporarilyClosed', function(data, options) {
12712
- return inArray(getMasterFormatId('TC', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12800
+ return getFormats(data).includes(getMasterFormatId('TC', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12713
12801
  });
12714
12802
 
12715
12803
  crouton_Handlebars.registerHelper('isNotTemporarilyClosed', function(data, options) {
12716
- return !inArray(getMasterFormatId('TC', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12804
+ return !getFormats(data).includes(getMasterFormatId('TC', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12717
12805
  });
12718
12806
 
12719
12807
  /**
12720
12808
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12721
12809
  */
12722
12810
  crouton_Handlebars.registerHelper('isInPersonOrHybrid', function(data, options) {
12723
- return data['venue_type'] !== venueType.VIRTUAL && !inArray(getMasterFormatId('VM', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12811
+ return data['venue_type'] !== venueType.VIRTUAL && !getFormats(data).includes(getMasterFormatId('VM', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12724
12812
  });
12725
12813
 
12726
12814
  /**
12727
12815
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12728
12816
  */
12729
12817
  crouton_Handlebars.registerHelper('isInPersonOnly', function(data, options) {
12730
- return data['venue_type'] === venueType.IN_PERSON || (!inArray(getMasterFormatId('VM', data), getFormats(data))
12731
- && !inArray(getMasterFormatId('HY', data), getFormats(data))) ? getTrueResult(options, this) : getFalseResult(options, this);
12818
+ return data['venue_type'] === venueType.IN_PERSON || (!getFormats(data).includes(getMasterFormatId('VM', data))
12819
+ && !getFormats(data).includes(getMasterFormatId('HY', data))) ? getTrueResult(options, this) : getFalseResult(options, this);
12732
12820
  });
12733
12821
 
12734
12822
  /**
12735
12823
  * Assumes consistent set of venue type formats (enforced for newly edited meetings in root server 2.16.0 or greater)
12736
12824
  */
12737
12825
  crouton_Handlebars.registerHelper('isVirtualOrHybrid', function(data, options) {
12738
- return (data['venue_type'] === venueType.VIRTUAL || data['venue_type'] === venueType.HYBRID) || inArray(getMasterFormatId('VM', data), getFormats(data))
12739
- || inArray(getMasterFormatId('HY', data), getFormats(data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12826
+ return (data['venue_type'] === venueType.VIRTUAL || data['venue_type'] === venueType.HYBRID) || getFormats(data).includes(getMasterFormatId('VM', data))
12827
+ || getFormats(data).includes(getMasterFormatId('HY', data)) ? getTrueResult(options, this) : getFalseResult(options, this);
12740
12828
  });
12741
12829
 
12742
12830
  crouton_Handlebars.registerHelper('hasFormats', function(formats, data, options) {
12743
- var allFound = false;
12744
- var formatsResponse = data['formats'].split(",")
12745
- var formatsParam = formats.split(",");
12831
+ const formatsResponse = data['formats'].split(",")
12832
+ const formatsParam = formats.split(",");
12746
12833
  for(var i = 0;i < formatsParam.length;i++) {
12747
- allFound = inArray(formatsParam[i], formatsResponse);
12834
+ if (!formatsResponse.includes(formatsParam[i]))
12835
+ return getFalseResult(options, this);
12748
12836
  }
12749
-
12750
- return allFound ? getTrueResult(options, this) : getFalseResult(options, this);
12837
+ return getTrueResult(options, this);
12751
12838
  });
12752
12839
  crouton_Handlebars.registerHelper('temporarilyClosed', function(data, options) {
12753
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('TC', data)) !== undefined) {
12754
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('TC', data))['description'];
12840
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('TC', data));
12841
+ if (found !== undefined) {
12842
+ return found['description'];
12755
12843
  } else {
12756
12844
  return crouton.localization.getWord("FACILITY IS TEMPORARILY CLOSED");
12757
12845
  }
12758
12846
  });
12759
12847
 
12760
12848
  crouton_Handlebars.registerHelper('meetsVirtually', function(data, options) {
12761
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('VM', data)) !== undefined) {
12762
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('VM', data))['description'];
12849
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('VM', data));
12850
+ if (found !== undefined) {
12851
+ return found['description'];
12763
12852
  } else {
12764
12853
  return crouton.localization.getWord("MEETS VIRTUALLY");
12765
12854
  }
12766
12855
  });
12767
12856
 
12768
12857
  crouton_Handlebars.registerHelper('meetsHybrid', function(data, options) {
12769
- if(data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('HY', data)) !== undefined) {
12770
- return data['formats_expanded'].getArrayItemByObjectKeyValue('id', getMasterFormatId('HY', data))['description'];
12858
+ const found = data['formats_expanded'].find((format)=>format['id'] === getMasterFormatId('HY', data));
12859
+ if (found !== undefined) {
12860
+ return found['description'];
12771
12861
  } else {
12772
12862
  return crouton.localization.getWord("MEETS VIRTUALLY AND IN PERSON");
12773
12863
  }
@@ -12818,6 +12908,18 @@ function CroutonHandlebarsExtensions() {
12818
12908
  return new crouton_Handlebars.SafeString("<a href='tel:" + text + "' target='_blank'>" + text + "</a>");
12819
12909
  });
12820
12910
 
12911
+ function isFavorite(meeting) {
12912
+ const localStorageKey = "crouton-favorites";
12913
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
12914
+ return favorites.includes(meeting.root_server_uri + "_" + meeting.id_bigint);
12915
+ }
12916
+ crouton_Handlebars.registerHelper('favoriteIcon', function(meeting, options) {
12917
+ return new crouton_Handlebars.SafeString("<span id='crouton-favorite-" + meeting.id_bigint + "' class='crouton-favorite glyphicon glyphicon-heart" + (!isFavorite(meeting) ? "-empty" : "") + "'></span>");
12918
+ });
12919
+
12920
+ crouton_Handlebars.registerHelper('isFavorite', function(meeting, options) {
12921
+ return new crouton_Handlebars.SafeString(isFavorite(meeting) ? 1 : 0);
12922
+ });
12821
12923
  crouton_Handlebars.registerHelper('ifEquals', function(arg1, arg2, options) {
12822
12924
  return (arg1 === arg2) ? options.fn(this) : options.inverse(this);
12823
12925
  });
@@ -12893,8 +12995,31 @@ function CroutonHandlebarsExtensions() {
12893
12995
  <br/>
12894
12996
  {{/if}}
12895
12997
  `);
12998
+ crouton_Handlebars.registerPartial('formatNames', `
12999
+ {{#each formats_expanded}}
13000
+ <a
13001
+ class="bmlt-formats btn btn-primary btn-xs"
13002
+ title=""
13003
+ data-html="true"
13004
+ tabindex="0"
13005
+ data-trigger="focus"
13006
+ role="button"
13007
+ data-toggle="popover"
13008
+ data-original-title=""
13009
+ data-placement="{{{getWord 'bootstrap-popover-placement'}}}"
13010
+ data-content="{{description}}">
13011
+ <span class="glyphicon glyphicon-search"
13012
+ aria-hidden="true"
13013
+ data-toggle="popover"
13014
+ data-trigger="focus"
13015
+ data-html="true"
13016
+ role="button"></span>{{ name }}
13017
+ </a>
13018
+ {{/each}}
13019
+ `
13020
+ )
12896
13021
  crouton_Handlebars.registerPartial('formatKeys', `
12897
- {{#if this.formats}}
13022
+ {{#if this.formats}}
12898
13023
  <a
12899
13024
  class="bmlt-formats btn btn-primary btn-xs"
12900
13025
  title=""
@@ -12916,7 +13041,6 @@ function CroutonHandlebarsExtensions() {
12916
13041
  {{/if}}
12917
13042
  `
12918
13043
  )
12919
-
12920
13044
  crouton_Handlebars.registerPartial('observerLine', `
12921
13045
  {{#if (hasObserverLine name phone email) }}
12922
13046
  <div class='observerLine'>{{getWord "Contact"}}: {{name}} <a href='tel:{{phone}}'>{{phone}}</a> <a href='mailto:{{email}}'>{{email}}</a></div>
@@ -13347,8 +13471,10 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13347
13471
  + ((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 : "")
13348
13472
  + ((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 : "")
13349
13473
  + ((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 : "")
13350
- + "\n"
13351
- + ((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 : "")
13474
+ + " <div class=\"bmlt-button-container\"><a id=\"crouton_favorites_button\" tabindex=0 class=\"croutonControlButton btn btn-primary btn-sm\">"
13475
+ + 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}}}))
13476
+ + "</a></div>\n\n"
13477
+ + ((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 : "")
13352
13478
  + " </div>\n";
13353
13479
  },"1":function(container,depth0,helpers,partials,data) {
13354
13480
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13373,8 +13499,8 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13373
13499
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13374
13500
  + "\" tabindex=0 data-field=\""
13375
13501
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"title") : depth0), depth0))
13376
- + "\" class=\"groupingButton groupingButtonLogic btn btn-primary btn-sm\">"
13377
- + 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}}}))
13502
+ + "\" class=\"groupingButton croutonControlButton groupingButtonLogic btn btn-primary btn-sm\">"
13503
+ + 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}}}))
13378
13504
  + "</a></div>\n";
13379
13505
  },"3":function(container,depth0,helpers,partials,data) {
13380
13506
  var alias1=container.lambda, alias2=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13388,7 +13514,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13388
13514
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13389
13515
  + "\"tabindex=0 data-field=\""
13390
13516
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"field") : depth0), depth0))
13391
- + "\" class=\"groupingButton groupingButtonLogic btn btn-primary btn-sm\">"
13517
+ + "\" class=\"groupingButton croutonControlButton groupingButtonLogic btn btn-primary btn-sm\">"
13392
13518
  + alias2(alias1((depth0 != null ? lookupProperty(depth0,"title") : depth0), depth0))
13393
13519
  + "</a></div>\n";
13394
13520
  },"4":function(container,depth0,helpers,partials,data) {
@@ -13399,8 +13525,8 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13399
13525
  return undefined
13400
13526
  };
13401
13527
 
13402
- return " <div class=\"bmlt-button-container\"><a id=\"groupingButton_embeddedMapPage\" tabindex=0 data-field=\"embeddedMapPage\" class=\"groupingButton btn btn-primary btn-sm\">"
13403
- + 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}}}))
13528
+ return " <div class=\"bmlt-button-container\"><a id=\"groupingButton_embeddedMapPage\" tabindex=0 data-field=\"embeddedMapPage\" class=\"groupingButton croutonControlButton btn btn-primary btn-sm\">"
13529
+ + 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}}}))
13404
13530
  + "</a></div>\n";
13405
13531
  },"5":function(container,depth0,helpers,partials,data,blockParams,depths) {
13406
13532
  var stack1, helper, alias1=container.escapeExpression, alias2=depth0 != null ? depth0 : (container.nullContext || {}), alias3=container.hooks.helperMissing, alias4="function", lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13413,17 +13539,17 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13413
13539
  return " <div class=\"bmlt-dropdown-container\">\n <select class=\"crouton-select filter-dropdown\" style=\"width:"
13414
13540
  + alias1(container.lambda(((stack1 = (depths[1] != null ? lookupProperty(depths[1],"config") : depths[1])) != null ? lookupProperty(stack1,"dropdown_width") : stack1), depth0))
13415
13541
  + ";\" data-placeholder=\""
13416
- + 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)))
13542
+ + 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)))
13417
13543
  + "\" data-pointer=\""
13418
- + 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)))
13544
+ + 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)))
13419
13545
  + "\" id="
13420
- + 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)))
13546
+ + 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)))
13421
13547
  + ">\n <option value=\"a-\">"
13422
- + 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}}}))
13548
+ + 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}}}))
13423
13549
  + " "
13424
- + 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)))
13550
+ + 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)))
13425
13551
  + "</option>\n"
13426
- + ((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 : "")
13552
+ + ((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 : "")
13427
13553
  + " </select>\n </div>\n";
13428
13554
  },"6":function(container,depth0,helpers,partials,data,blockParams,depths) {
13429
13555
  var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13434,9 +13560,9 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13434
13560
  };
13435
13561
 
13436
13562
  return " <option value=\"a-"
13437
- + 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}}}))
13563
+ + 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}}}))
13438
13564
  + "\">"
13439
- + 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}}}))
13565
+ + 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}}}))
13440
13566
  + "</option>\n";
13441
13567
  },"7":function(container,depth0,helpers,partials,data) {
13442
13568
  var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13446,9 +13572,9 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13446
13572
  return undefined
13447
13573
  };
13448
13574
 
13449
- 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 : "")
13575
+ 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 : "")
13450
13576
  + " <ul class=\"nav nav-tabs\">\n"
13451
- + ((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 : "")
13577
+ + ((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 : "")
13452
13578
  + " </ul>\n </div>\n";
13453
13579
  },"8":function(container,depth0,helpers,partials,data) {
13454
13580
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13459,7 +13585,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13459
13585
  };
13460
13586
 
13461
13587
  return " <div class=\"bmlt-page "
13462
- + 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}}}))
13588
+ + 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}}}))
13463
13589
  + " show\" id=\"nav-days\">\n";
13464
13590
  },"9":function(container,depth0,helpers,partials,data) {
13465
13591
  var lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13470,7 +13596,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13470
13596
  };
13471
13597
 
13472
13598
  return " <div class=\"bmlt-page "
13473
- + 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}}}))
13599
+ + 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}}}))
13474
13600
  + " hide\" id=\"nav-days\">\n";
13475
13601
  },"10":function(container,depth0,helpers,partials,data) {
13476
13602
  var alias1=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13483,7 +13609,7 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13483
13609
  return " <li><a href=\"#tab"
13484
13610
  + alias1(container.lambda(depth0, depth0))
13485
13611
  + "\" data-toggle=\"tab\">"
13486
- + 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}}}))
13612
+ + 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}}}))
13487
13613
  + "</a></li>\n";
13488
13614
  },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
13489
13615
  var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}), lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13495,10 +13621,38 @@ this["hbs_Crouton"]["templates"]["header"] = Handlebars.template({"0":function(c
13495
13621
 
13496
13622
  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}}}))
13497
13623
  + "\n"
13498
- + ((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 : "")
13624
+ + ((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 : "")
13499
13625
  + "\n"
13500
- + ((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 : "");
13626
+ + ((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 : "");
13501
13627
  },"useData":true,"useDepths":true});
13628
+ this["hbs_Crouton"]["templates"]["locationSearch"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
13629
+ var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
13630
+ if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
13631
+ return parent[propertyName];
13632
+ }
13633
+ return undefined
13634
+ };
13635
+
13636
+ return "<button id=\"location-search-button\" style=\"width: auto\" class=\"location-search-button\" title=\""
13637
+ + 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}}}))
13638
+ + "\">\n <span class=\"location-search-button-label\" style=\"position:initial;\">\n "
13639
+ + 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}}}))
13640
+ + "\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\">"
13641
+ + 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}}}))
13642
+ + "</div>\n <div class=\"crouton-modal-search-page\">\n <div id=\"modal-location-search-box\" class=\"modal-search\">\n <input id=\"bmlt-location-search-goto-text\" type=\"text\" class=\"crouton-goto-text\"\n placeholder=\""
13643
+ + 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":16,"column":33},"end":{"line":16,"column":71}}}))
13644
+ + "\">\n <button id=\"bmlt-location-search-text-button\" class=\"filter-button\">"
13645
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"text_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":17,"column":84},"end":{"line":17,"column":109}}}))
13646
+ + "</button>\n </div>\n <div class=\"modal-search\">\n <button id=\"bmlt-location-search-nearbyMeetings\" class=\"filter-button\">"
13647
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"near_me",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":20,"column":87},"end":{"line":20,"column":108}}}))
13648
+ + "</button>\n </div>\n <div id=\"location-search-widen\" class=\"modal-search\">\n <button id=\"bmlt-location-search-widen\" class=\"filter-button\">"
13649
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Widen Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":23,"column":78},"end":{"line":23,"column":104}}}))
13650
+ + "</button>\n </div>\n <div>\n <!--<button id=\"location-search-close\" class=\"advanced-search-button\" style=\"float:left\">"
13651
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Close",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":26,"column":96},"end":{"line":26,"column":115}}}))
13652
+ + "</a>-->\n <button id=\"bmlt-location_search-cancel\" class=\"advanced-search-button\">"
13653
+ + alias3((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias2).call(alias1,"Cancel Search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":27,"column":88},"end":{"line":27,"column":115}}}))
13654
+ + "</button>\n </div>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n </div>\n</div>";
13655
+ },"useData":true});
13502
13656
  this["hbs_Crouton"]["templates"]["main"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
13503
13657
  var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
13504
13658
  if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
@@ -13695,11 +13849,11 @@ this["hbs_Crouton"]["templates"]["mapMenu"] = Handlebars.template({"0":function(
13695
13849
  + ((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 : "")
13696
13850
  + " </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\">"
13697
13851
  + 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}}}))
13698
- + "</span><span id=\"close_search\" class=\"modal-close\">x</span>\n <p></p>\n <div class=\"modal-search\">\n "
13699
- + 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}}}))
13700
- + "\n <input id=\"goto-text\" type=\"text\">\n <button id=\"goto-button\" class=\"filter-button\">"
13701
- + 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}}}))
13702
- + "</button>\n </div>\n </div>\n</div>\n\n";
13852
+ + "</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 "
13853
+ + 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}}}))
13854
+ + "\n <input id=\"goto-text\" class=\"crouton-goto-text\" type=\"text\">\n <button id=\"goto-button\" class=\"filter-button\">"
13855
+ + alias1((lookupProperty(helpers,"getWord")||(depth0 && lookupProperty(depth0,"getWord"))||alias3).call(alias2,"text_search",{"name":"getWord","hash":{},"data":data,"loc":{"start":{"line":50,"column":63},"end":{"line":50,"column":88}}}))
13856
+ + "</button>\n </div>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n </div>\n</div>\n\n";
13703
13857
  },"usePartial":true,"useData":true,"useDepths":true});
13704
13858
  this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
13705
13859
  var alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -13713,13 +13867,13 @@ this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":
13713
13867
  + 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}}}))
13714
13868
  + "\">\n <span class=\"menu-button-label\" style=\"position:initial;\">"
13715
13869
  + 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}}}))
13716
- + "</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\">"
13870
+ + "</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\">"
13717
13871
  + 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}}}))
13718
13872
  + "</div>\n <div id=\"zoomed-out-message\" class=\"hide\">\n <p>"
13719
13873
  + 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}}}))
13720
13874
  + "</p>\n </div>\n <div id=\"modal-search-box\" class=\"modal-search\">\n <input id=\"bmltsearch-goto-text\" type=\"text\"\n placeholder=\""
13721
13875
  + 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}}}))
13722
- + "\" style=\"margin-bottom:5px;\">\n <button id=\"bmltsearch-text-button\" class=\"filter-button\">"
13876
+ + "\" class=\"crouton-goto-text\">\n <button id=\"bmltsearch-text-button\" class=\"filter-button\">"
13723
13877
  + 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}}}))
13724
13878
  + "</button>\n </div>\n <div class=\"modal-search\">\n <button id=\"bmltsearch-nearbyMeetings\" class=\"filter-button\">"
13725
13879
  + 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}}}))
@@ -13727,14 +13881,14 @@ this["hbs_Crouton"]["templates"]["mapSearch"] = Handlebars.template({"compiler":
13727
13881
  + 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}}}))
13728
13882
  + "</button>\n </div>\n <button id=\"show-search-parameters\" class=\"advanced-search-button\">"
13729
13883
  + 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}}}))
13730
- + "</button>\n </div>\n <div id=\"modal-seach-parameters\">\n <div class=\"modal-title\">"
13731
- + 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}}}))
13884
+ + "</button>\n </div>\n <div class=\"crouton-modal-search-choice\"></div>\n <div id=\"modal-seach-parameters\">\n <div class=\"modal-title\">"
13885
+ + 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}}}))
13732
13886
  + "</div>\n <input type=\"number\" id=\"search_parameter\" name=\"search_parameter\" maxlength=\"3\" size=\"3\">\n <p>"
13733
- + 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}}}))
13887
+ + 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}}}))
13734
13888
  + ":</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\">"
13735
- + 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}}}))
13889
+ + 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}}}))
13736
13890
  + "</label><br>\n <button id=\"show-search-page\" class=\"advanced-search-button\">"
13737
- + 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}}}))
13891
+ + 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}}}))
13738
13892
  + "</button>\n </div>\n </div>\n</div>";
13739
13893
  },"useData":true});
13740
13894
  this["hbs_Crouton"]["templates"]["meeting3ColumnRow"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
@@ -14041,7 +14195,9 @@ this["hbs_Crouton"]["templates"]["tableRows"] = Handlebars.template({"0":functio
14041
14195
  + 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}}}))
14042
14196
  + "\"\n data-weekdays=\""
14043
14197
  + 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}}}))
14044
- + "\">\n"
14198
+ + "\"\n data-favorite="
14199
+ + 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}}}))
14200
+ + ">\n"
14045
14201
  + ((stack1 = container.invokePartial(lookupProperty(partials,"tableDataRow"),depth0,{"name":"tableDataRow","data":data,"indent":"\t\t","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
14046
14202
  + " </tr>\n";
14047
14203
  },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
@@ -14052,7 +14208,7 @@ this["hbs_Crouton"]["templates"]["tableRows"] = Handlebars.template({"0":functio
14052
14208
  return undefined
14053
14209
  };
14054
14210
 
14055
- 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 : "");
14211
+ 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 : "");
14056
14212
  },"usePartial":true,"useData":true});
14057
14213
  this["hbs_Crouton"]["templates"]["weekdays"] = Handlebars.template({"0":function(container,depth0,helpers,partials,data) {
14058
14214
  var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) {
@@ -14178,13 +14334,16 @@ var croutonDefaultTemplates = {
14178
14334
  </div>
14179
14335
  `,
14180
14336
  meeting_times_template: `
14181
- <div class="bmlt-day">{{this.formatted_day}}</div>
14337
+ <div class="bmlt-meeting-day-favorite">
14338
+ <div class="bmlt-day">{{this.formatted_day}}</div>
14339
+ <div class="favorite-icon">{{favoriteIcon this}}</div>
14340
+ </div>
14182
14341
  {{#ifEquals this.duration_time "24:00:00"}}
14183
14342
  <div class="bmlt-time-2">{{this.start_time_formatted}}</div>
14184
14343
  {{else}}
14185
14344
  <div class="bmlt-time-2">{{this.start_time_formatted}} - {{this.end_time_formatted}}</div>
14186
14345
  {{/ifEquals}}
14187
- {{> formatKeys }}
14346
+ {{> (format_list_style) }}
14188
14347
  <div class="bmlt-comments">{{formatLink this.formatted_comments}}</div>
14189
14348
  <div class="bmlt-observer">{{> (selectObserver) }}</div>
14190
14349
  `,
@@ -15280,16 +15439,20 @@ crouton_Handlebars.registerHelper("log", (x) => console.log(x));
15280
15439
  crouton_Handlebars.registerHelper('selectFormatPopup', () => "formatPopup");
15281
15440
  crouton_Handlebars.registerHelper('selectObserver', () => "observerTemplate");
15282
15441
 
15283
-
15442
+ /**
15443
+ * There must be exactly one crouton instance per page.
15444
+ * @param {*} config
15445
+ */
15284
15446
  function Crouton(config) {
15285
- var self = this;
15286
- self.mutex = false;
15447
+ const self = this;
15448
+ self.ready = false;
15287
15449
  self.filtering = false;
15288
15450
  self.masterFormatCodes = [];
15289
15451
  self.currentView = "weekday";
15290
15452
  self.distanceTabAllowed = false;
15453
+ self.favoritesOn = false;
15291
15454
  self.config = {
15292
- version: '4.1.11', // CroutonJS version for debugging
15455
+ version: '4.3.1', // CroutonJS version for debugging
15293
15456
  on_complete: null, // Javascript function to callback when data querying is completed.
15294
15457
  root_server: null, // The root server to use.
15295
15458
  placeholder_id: "bmlt-tabs", // The DOM id that will be used for rendering
@@ -15324,6 +15487,8 @@ function Crouton(config) {
15324
15487
  has_languages: false, // Shows the language dropdown
15325
15488
  has_common_needs: false, // Shows the Common Needs dropdown
15326
15489
  has_venues: true, // Shows the venue types dropdown
15490
+ has_favorites: false, // Shows the favorites button
15491
+ has_geolocation: false, // Shows the geolocation button in the table header
15327
15492
  has_meeting_count: false, // Shows the meeting count
15328
15493
  recurse_service_bodies: false,// Recurses service bodies when making service bodies request
15329
15494
  service_body: [], // Array of service bodies to return data for.
@@ -15366,7 +15531,6 @@ function Crouton(config) {
15366
15531
  tileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
15367
15532
  tileOptions: {
15368
15533
  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>',
15369
- maxZoom: 18
15370
15534
  },
15371
15535
  minZoom: 6,
15372
15536
  maxZoom: 17,
@@ -15376,9 +15540,41 @@ function Crouton(config) {
15376
15540
  caption: false,
15377
15541
  groups: false,
15378
15542
  details_table: false,
15543
+ focusedMeetingPopupZoomLevel: 14,
15379
15544
  };
15380
15545
 
15381
15546
  self.setConfig(config);
15547
+ const body = jQuery("body");
15548
+ if (self.config['theme'] !== '') {
15549
+ body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
15550
+ }
15551
+ if (self.config['custom_css'] !== '') {
15552
+ body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
15553
+ }
15554
+ self.isIOSDevice = function() {
15555
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
15556
+ if (navigator.userAgentData.platform === 'iOS') {
15557
+ return true;
15558
+ }
15559
+ }
15560
+ const userAgent = navigator.userAgent || navigator.vendor || window.opera;
15561
+ const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
15562
+ const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && !window.MSStream;
15563
+ return isIOS || isIPadOS;
15564
+ }
15565
+
15566
+ self.isAndroidDevice = function() {
15567
+ return /Android/i.test(navigator.userAgent);
15568
+ }
15569
+ self.deviceType = self.isIOSDevice() ? 'ios' : (self.isAndroidDevice() ? 'android' : 'desktop');
15570
+
15571
+ /**
15572
+ * Do the lookups for the [crouton_map] shortcode
15573
+ * @param float latitude
15574
+ * @param float longitude
15575
+ * @param float width search width that will be sent to the server
15576
+ * @param boolean fitBounds
15577
+ */
15382
15578
  Crouton.prototype.searchByCoordinates = function(latitude, longitude, width, fitBounds=true) {
15383
15579
  const original_query = self.config['custom_query'];
15384
15580
  self.config['custom_query'] = (self.config['custom_query'] !== null ? self.config['custom_query'] : "")
@@ -15387,20 +15583,23 @@ function Crouton(config) {
15387
15583
  self.meetingSearch(function() {
15388
15584
  self.config.refresh_map=1;
15389
15585
  self.config.show_map = 1;
15390
- self.reset();
15586
+ jQuery("#" + self.config["placeholder_id"]).html("");
15391
15587
  self.render(false, fitBounds);
15392
15588
  });
15393
15589
  self.config['custom_query'] = original_query;
15394
15590
  };
15395
15591
 
15592
+ /**
15593
+ * Get the meeting list for the [bmlt_tab] shortcode.
15594
+ * @param string url
15595
+ * @param function cb
15596
+ * @returns Promise that returns when the server query finishes.
15597
+ */
15396
15598
  self.getMeetings = function(url,cb=null) {
15397
- var promises = [fetchJsonp(this.config['root_server'] + url).then(function(response) { return response.json(); })];
15599
+ const promises = [fetchJsonp(this.config['root_server'] + url).then(function(response) { return response.json(); })];
15398
15600
 
15399
15601
  if (self.config['extra_meetings'].length > 0) {
15400
- var extra_meetings_query = "";
15401
- for (var i = 0; i < self.config['extra_meetings'].length; i++) {
15402
- extra_meetings_query += "&meeting_ids[]=" + self.config["extra_meetings"][i];
15403
- }
15602
+ const extra_meetings_query = self.config['extra_meetings'].reduce((query,item) => query + "&meeting_ids[]=" + item, '');
15404
15603
  const regex = /&services\[\]=\d+/;
15405
15604
  url = url.replace(regex, '');
15406
15605
  promises.push(fetchJsonp(self.config['root_server'] + url + extra_meetings_query).then(function (response) { return response.json(); }));
@@ -15408,38 +15607,34 @@ function Crouton(config) {
15408
15607
 
15409
15608
  return Promise.all(promises)
15410
15609
  .then(function(data) {
15411
- var mainMeetings = data[0];
15412
- var extraMeetings;
15413
- var jsonMeetings = JSON.stringify(mainMeetings['meetings']);
15414
- if (data.length === 2) {
15415
- extraMeetings = data[1];
15416
- }
15417
- if (jsonMeetings === "{}" || jsonMeetings === "[]") {
15418
- var fullUrl = self.config['root_server'] + url
15610
+ const mainMeetings = data[0];
15611
+ if (mainMeetings['meetings'].length === 0) {
15612
+ const fullUrl = self.config['root_server'] + url
15419
15613
  console.log("Could not find any meetings for the criteria specified with the query <a href=\"" + fullUrl + "\" target=_blank>" + fullUrl + "</a>");
15420
15614
  jQuery('#' + self.config['placeholder_id']).html("No meetings found.");
15421
15615
  self.meetingData = [];
15422
15616
  self.formatsData = [];
15423
- self.mutex = false;
15424
15617
  cb && cb();
15618
+ self.fireReady();
15425
15619
  return;
15426
15620
  }
15621
+ // TODO: is this necessary? why not just add this to the query?
15427
15622
  if (self.config['exclude_zip_codes'].length > 0) {
15428
- mainMeetings['meetings'] = mainMeetings['meetings'].filter(function(m) { return !inArray(m['location_postal_code_1'], self.config['exclude_zip_codes']); } );
15623
+ mainMeetings['meetings'] = mainMeetings['meetings'].filter(function(m) { return !self.config['exclude_zip_codes'].includes(m['location_postal_code_1']); } );
15429
15624
  }
15430
15625
  self.meetingData = mainMeetings['meetings'];
15431
15626
  self.formatsData = mainMeetings['formats'];
15432
- if (extraMeetings) {
15433
- self.meetingData = self.meetingData.concat(extraMeetings['meetings']);
15627
+ // extra meetings
15628
+ if (data.length === 2) {
15629
+ self.meetingData = self.meetingData.concat(data[1]['meetings']);
15434
15630
  }
15435
15631
  cb && cb();
15436
- self.mutex = false;
15632
+ self.fireReady();
15437
15633
  });
15438
15634
  };
15439
- self.mutex = true;
15440
15635
 
15441
15636
  self.meetingSearch = function(cb=null) {
15442
- var url = '/client_interface/jsonp/?switcher=GetSearchResults&get_used_formats&lang_enum=' + self.config['short_language'];
15637
+ let url = '/client_interface/jsonp/?switcher=GetSearchResults&get_used_formats&lang_enum=' + self.config['short_language'];
15443
15638
 
15444
15639
  if (self.config['formats']) {
15445
15640
  url += self.config['formats'].reduce(function(prev,id) {
@@ -15468,9 +15663,7 @@ function Crouton(config) {
15468
15663
  url += self.config['custom_query'] + '&sort_keys=' + self.config['sort_keys'];
15469
15664
  return self.getMeetings(url,cb);
15470
15665
  } else if (self.config['service_body'].length > 0) {
15471
- for (var i = 0; i < self.config['service_body'].length; i++) {
15472
- url += '&services[]=' + self.config['service_body'][i];
15473
- }
15666
+ url = self.config['service_body'].reduce((curr,item)=>curr+'&services[]='+item, url);
15474
15667
 
15475
15668
  if (self.config['recurse_service_bodies']) {
15476
15669
  url += '&recursive=1';
@@ -15483,31 +15676,47 @@ function Crouton(config) {
15483
15676
  return new Promise(function(resolve, reject) {
15484
15677
  self.meetingData = [];
15485
15678
  self.formatsData = [];
15486
- self.mutex = false;
15487
15679
  resolve([]);
15680
+ self.fireReady();
15488
15681
  });
15489
15682
  }
15683
+ }
15684
+ self.readyListener = [];
15685
+ /**
15686
+ * Add a listener for the event that the crouton instance has loaded its data and we can now go ahead and execute the shortcodes.
15687
+ * Generally, each listener corresponds to different shortcode. The main ones go over the render method, but there are also listeners
15688
+ * for [meeting_count] etc.
15689
+ * @param function callback
15690
+ */
15691
+ self.listenForReady = function(callback) {
15692
+ if (self.ready) callback();
15693
+ else self.readyListener.push(callback);
15490
15694
  };
15491
-
15492
- self.lock = function(callback) {
15493
- var self = this;
15494
- var lock_id = setInterval(function() {
15495
- if (!self.mutex) {
15496
- clearInterval(lock_id);
15497
- callback();
15498
- }
15499
- }, 100);
15695
+ /**
15696
+ * FIres the event that crouton is loaded and ready.
15697
+ */
15698
+ self.fireReady = function() {
15699
+ self.ready = true;
15700
+ self.readyListener.forEach(function(callback) {
15701
+ callback();
15702
+ });
15703
+ self.readyListener = [];
15500
15704
  };
15501
-
15502
- self.dayTab = function(day_id) {
15705
+ /**
15706
+ * Bring up the appropriate tab based on the meeting id.
15707
+ * 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.
15708
+ * @param string id meeting id.
15709
+ */
15710
+ self.dayTabFromId = function(id) {
15711
+ const day_id = self.meetingData.find((m)=>m.id_bigint == id).weekday_tinyint;
15503
15712
  self.hideAllPages();
15504
15713
  jQuery('.nav-tabs a[href="#tab' + day_id + '"]').tab('show');
15505
15714
  jQuery("#" + day_id).removeClass("hide").addClass("show");
15506
15715
  };
15507
- self.dayTabFromId = function(id) {
15508
- day_id = self.meetingData.find((m)=>m.id_bigint == id).weekday_tinyint;
15509
- self.dayTab(day_id);
15510
- };
15716
+ /**
15717
+ * Show a page from the table (weekday, distance, city...)
15718
+ * @param string id selector, id attribute of the HtML
15719
+ */
15511
15720
  self.showPage = function (id) {
15512
15721
  jQuery(id+" .bmlt-data-row-placeholder").each(function() {
15513
15722
  const meetingId = this.dataset.meetingid;
@@ -15520,7 +15729,11 @@ function Crouton(config) {
15520
15729
  self.addStripes();
15521
15730
  jQuery(id).removeClass("hide").addClass("show");
15522
15731
  };
15523
-
15732
+ /**
15733
+ * Bring up a view.
15734
+ * @param string viewName abstract viewname (weekday, distance, city...)
15735
+ * @param int showingNow number of items currently being displayed on the page
15736
+ */
15524
15737
  self.showView = function (viewName, showingNow=0) {
15525
15738
  if (viewName === 'distance' && !self.distanceTabAllowed) {
15526
15739
  viewName = self.config.groups ? 'city' : 'day';
@@ -15581,6 +15794,7 @@ function Crouton(config) {
15581
15794
  self.dayView();
15582
15795
  return;
15583
15796
  }
15797
+ self.currentView = field;
15584
15798
  self.lowlightButton("#day");
15585
15799
  self.lowlightButton(".groupingButton");
15586
15800
  self.highlightButton("#groupingButton_" + field);
@@ -15623,8 +15837,12 @@ function Crouton(config) {
15623
15837
  jQuery(value).addClass((index % 2) ? 'oddRow' : 'evenRow');
15624
15838
  });
15625
15839
  }
15840
+ /**
15841
+ *
15842
+ * @returns a list of the IDs of meetings matching the current filters.
15843
+ */
15626
15844
  self.calcShowingNow = function() {
15627
- var showingNow = [];
15845
+ let showingNow = [];
15628
15846
  jQuery(".bmlt-data-row:not(.hide)").each(function (index, value) {
15629
15847
  const rowId = value.id.split("-");
15630
15848
  showingNow.push(rowId[rowId.length-1]);
@@ -15647,26 +15865,13 @@ function Crouton(config) {
15647
15865
  }
15648
15866
  });
15649
15867
  this.addStripes();
15650
- var showingNow = this.calcShowingNow();
15868
+ const showingNow = this.calcShowingNow();
15651
15869
  self.updateMeetingCount(showingNow);
15652
- self.updateFilters();
15653
- if (croutonMap) croutonMap.fillMap(showingNow);
15654
- self.showView(self.currentView, showingNow.length);
15655
- };
15656
- self.resetFilter = function () {
15657
- croutonMap.filterVisible(false);
15658
- if ((self.config.map_page && self.filtering) || self.config.show_map) croutonMap.fillMap();
15659
- self.filtering = false;
15660
- self.updateFilters();
15661
- self.updateMeetingCount();
15662
- jQuery(".filter-dropdown").val(null).trigger("change");
15663
- jQuery(".group-header").removeClass("hide");
15664
- jQuery(".meeting-group").removeClass("hide");
15665
- jQuery(".bmlt-data-row").removeClass("hide");
15666
- jQuery(".evenRow").removeClass("evenRow");
15667
- jQuery(".oddRow").removeClass("oddRow");
15870
+ self.updateFilters(showingNow);
15871
+ if (croutonMap) croutonMap.setFilteredIds(showingNow);
15872
+ if (self.currentView !== 'map') self.showView(self.currentView, showingNow.length);
15668
15873
  };
15669
- self.updateFilters = function() {
15874
+ self.updateFilters = function(showingNow) {
15670
15875
  if (!self.dropdownData) return;
15671
15876
  const getId = function (row) {return row.id.replace("meeting-data-row-", "")};
15672
15877
  // The options available for this filter have to take into account all other filters, but ignore the
@@ -15689,6 +15894,12 @@ function Crouton(config) {
15689
15894
  let showing = self.meetingData.filter((m) => !(hidden.includes(m.id_bigint)));
15690
15895
  dropdown.optionsShowing = dropdown.uniqueData(showing).map((o) => dropdown.optionName(o));
15691
15896
  });
15897
+ const favoritesDropdown = self.dropdownData.find((d) => d.elementId === "filter-dropdown-favorites");
15898
+ if (!favoritesDropdown || !self.shouldOfferFavorites(showingNow)) {
15899
+ jQuery("#crouton_favorites_button").addClass("hide");
15900
+ } else {
15901
+ jQuery("#crouton_favorites_button").removeClass("hide");
15902
+ }
15692
15903
  }
15693
15904
  self.renderStandaloneMap = function (selector, context, callback=null, fitBounds=true) {
15694
15905
  hbs_Crouton['localization'] = self.localization;
@@ -15696,40 +15907,14 @@ function Crouton(config) {
15696
15907
  self.setUpPartials();
15697
15908
  croutonMap.initialize(self.createBmltMapElement(),self.meetingData,context,null,fitBounds,callback,self.config['noMap']);
15698
15909
  }
15699
- self.retrieveGeolocation = function() {
15700
- return new Promise((resolve, reject) => {
15701
- if (window.storedGeolocation) {
15702
- resolve(window.storedGeolocation);
15703
- } else if (navigator.geolocation) {
15704
- navigator.geolocation.getCurrentPosition((position) => {
15705
- window.storedGeolocation = {
15706
- latitude: position.coords.latitude,
15707
- longitude: position.coords.longitude
15708
- };
15709
- resolve(window.storedGeolocation);
15710
- }, (error) => {
15711
- reject(new Error('Error getting geolocation: ' + error.message));
15712
- });
15713
- } else {
15714
- reject(new Error('Geolocation is not supported by this browser.'));
15715
- }
15716
- });
15717
- };
15718
- self.getCurrentLocation = function(callback) {
15719
- self.gretrieveGeolocation().then(position => {
15720
- callback(position);
15721
- }).catch(error => {
15722
- jQuery('.geo').removeClass("hide").addClass("show").html(`<p>${error.message}</p>`);
15723
- });
15724
- };
15725
15910
  self.renderView = function (selector, context, callback, fitBounds) {
15726
15911
  hbs_Crouton['localization'] = self.localization;
15727
- var template = hbs_Crouton.templates['main'];
15912
+ const template = hbs_Crouton.templates['main'];
15728
15913
  jQuery(selector).html(template(context));
15729
15914
  callback();
15730
15915
  };
15731
15916
  self.updateMeetingCount = function(showingNow=null) {
15732
- var self = this;
15917
+ const self = this;
15733
15918
  let meetingCount = self.meetingData.length;
15734
15919
  if (self.meetingCountCallback) self.meetingCountCallback(meetingCount);
15735
15920
  if (self.groupCountCallback) self.groupCountCallback(
@@ -15742,8 +15927,8 @@ function Crouton(config) {
15742
15927
  }
15743
15928
  self.showingNowCount = meetingCount;
15744
15929
  jQuery(".crouton_root_service_body").each(function() {
15745
- var text = "";
15746
- var field = 'name';
15930
+ let text = "";
15931
+ let field = 'name';
15747
15932
  if (this.dataset.field) field = this.dataset.field;
15748
15933
  if (self.config['service_body'].length > 0) {
15749
15934
  const sb = self.getServiceBodyDetails(self.config['service_body'][0]);
@@ -15753,19 +15938,17 @@ function Crouton(config) {
15753
15938
  });
15754
15939
  jQuery(addLive('#bmlt_tabs_meeting_count')).text(meetingCount);
15755
15940
  jQuery(addLive('#bmlt_tabs_group_count')).each(function(){
15756
- var filteredMeetings = self.meetingData;
15757
- if (showingNow!==null) filteredMeetings = self.meetingData.filter((m) => showingNow.includes(m.id_bigint));
15941
+ const filteredMeetings = (showingNow!==null) ? self.meetingData.filter((m) => showingNow.includes(m.id_bigint)) : self.meetingData;
15758
15942
  const groups = self.config.groups ? filteredMeetings : self.convertToGroups([...filteredMeetings]);
15759
- jQuery(this).text(arrayUnique(groups).length);
15943
+ jQuery(this).text([...new Set(groups)].length);
15760
15944
  });
15761
15945
  jQuery(addLive('#bmlt_tabs_service_body_names')).each(function() {
15762
- var filteredMeetings = self.meetingData;
15763
- if (showingNow!==null) filteredMeetings = self.meetingData.filter((m) => showingNow.includes(m.id_bigint));
15764
- var ids = getUniqueValuesOfKey(filteredMeetings, 'service_body_bigint');
15765
- var me = this;
15946
+ const filteredMeetings = (showingNow!==null) ? self.meetingData.filter((m) => showingNow.includes(m.id_bigint)) : self.meetingData;
15947
+ const ids = getUniqueValuesOfKey(filteredMeetings, 'service_body_bigint');
15948
+ const me = this;
15766
15949
  self.getServiceBodies(ids, false).then(function (service_bodies) {
15767
- var n = service_bodies.length;
15768
- var names = service_bodies.map((m)=>m['name']);
15950
+ const n = service_bodies.length;
15951
+ const names = service_bodies.map((m)=>m['name']);
15769
15952
  names.sort();
15770
15953
  var ret = "";
15771
15954
  if (n===1) {
@@ -15784,16 +15967,23 @@ function Crouton(config) {
15784
15967
  });
15785
15968
  }
15786
15969
  self.getServiceBodies = function(service_bodies_id, requires_parents=true) {
15787
- var url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetServiceBodies'
15788
- + (requires_parents ? '&parents=1' : '') + getServiceBodiesQueryString(service_bodies_id);
15970
+ const url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetServiceBodies'
15971
+ + (requires_parents ? '&parents=1' : '') + self.getServiceBodiesQueryString(service_bodies_id);
15789
15972
  return fetchJsonp(url)
15790
15973
  .then(function(response) {
15791
15974
  return response.json();
15792
15975
  });
15793
15976
  };
15794
15977
 
15978
+ self.getServiceBodiesQueryString = function(service_bodies_id) {
15979
+ let service_bodies_query = "";
15980
+ for (var x = 0; x < service_bodies_id.length; x++) {
15981
+ service_bodies_query += "&services[]=" + service_bodies_id[x];
15982
+ }
15983
+ return service_bodies_query;
15984
+ }
15795
15985
  self.getMasterFormats = function() {
15796
- var url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetFormats&lang_enum=en&key_strings[]=TC&key_strings[]=VM&key_strings[]=HY';
15986
+ const url = this.config['root_server'] + '/client_interface/jsonp/?switcher=GetFormats&lang_enum=en&key_strings[]=TC&key_strings[]=VM&key_strings[]=HY';
15797
15987
  return fetchJsonp(url)
15798
15988
  .then(function(response) {
15799
15989
  return response.json();
@@ -15815,16 +16005,16 @@ function Crouton(config) {
15815
16005
  self.handlebarMapOptions.lng = parseFloat(meetingDetailsData.longitude);
15816
16006
  return "<div id='bmlt-handlebars-map' class='bmlt-map'></div>"
15817
16007
  });
15818
- var parser = new DOMParser();
16008
+ const parser = new DOMParser();
15819
16009
 
15820
16010
  while (elements.length > 0) {
15821
- var element = elements.item(0);
16011
+ const element = elements.item(0);
15822
16012
  if (!element.firstChild) {
15823
16013
  console.log('<bmlt-handlebar> tag must have at least one child');
15824
16014
  element.remove();
15825
16015
  continue;
15826
16016
  }
15827
- var templateString = '';
16017
+ let templateString = '';
15828
16018
  if (element.firstChild.nodeType === 1) {
15829
16019
  if (!element.firstChild.firstChild || element.firstChild.firstChild.nodeType !== 3) {
15830
16020
  console.log('<bmlt-handlebar> tag: cannot find textnode');
@@ -15837,13 +16027,13 @@ function Crouton(config) {
15837
16027
  }
15838
16028
  var handlebarResult;
15839
16029
  try {
15840
- var template = crouton_Handlebars.compile(templateString);
16030
+ const template = crouton_Handlebars.compile(templateString);
15841
16031
  handlebarResult = template(meetingDetailsData);
15842
16032
  } catch (e) {
15843
16033
  console.log(e);
15844
16034
  handlebarResult = e.message;
15845
16035
  }
15846
- var htmlDecode = parser.parseFromString('<body>'+handlebarResult+'</body>', "text/html");
16036
+ const htmlDecode = parser.parseFromString('<body>'+handlebarResult+'</body>', "text/html");
15847
16037
  if (!htmlDecode.body || !htmlDecode.body.firstChild) {
15848
16038
  console.log('<bmlt-handlebar> tag: could not parse the Handlebars result');
15849
16039
  element.replaceWith('<bmlt-handlebar> tag: could not parse the Handlebars result');
@@ -15915,7 +16105,12 @@ function Crouton(config) {
15915
16105
  n = n.replace(/PM|pm/g, x => ampm['PM']);
15916
16106
  return n;
15917
16107
  }
15918
- self.enrichMeetings = function (meetingData) {
16108
+ /**
16109
+ * Take raw meeting data as returned from server adding values that should be conveniently displayed.
16110
+ * @param array meetingData
16111
+ * @returns the array with enriched data
16112
+ */
16113
+ self.enrichMeetings = function(meetingData) {
15919
16114
  var meetings = [];
15920
16115
 
15921
16116
  let queryStringChar = '?';
@@ -15946,8 +16141,8 @@ function Crouton(config) {
15946
16141
  meetingData[m]['day_of_the_week'] = meetingData[m]['start_time_raw'].isoWeekday() === 7 ? 1 : meetingData[m]['start_time_raw'].isoWeekday() + 1;
15947
16142
  meetingData[m]['formatted_day'] = self.localization.getDayOfTheWeekWord(meetingData[m]['day_of_the_week']);
15948
16143
 
15949
- var formats = meetingData[m]['formats'].split(",");
15950
- var formats_expanded = [];
16144
+ const formats = meetingData[m]['formats'].split(",");
16145
+ const formats_expanded = [];
15951
16146
  let formatRootServer = self.formatsData.filter((f)=>f['root_server_uri'] == meetingData[m]['root_server_uri']);
15952
16147
  meetingData[m]['wheelchair'] = false;
15953
16148
  for (var f = 0; f < formats.length; f++) {
@@ -15969,14 +16164,13 @@ function Crouton(config) {
15969
16164
 
15970
16165
  meetingData[m]['venue_type'] = parseInt(meetingData[m]['venue_type']);
15971
16166
  meetingData[m]['venue_type_name'] = getVenueTypeName(meetingData[m]);
15972
- meetingData[m]['formats_expanded'] = formats_expanded;
15973
- var addressParts = [
16167
+ meetingData[m]['formats_expanded'] = formats_expanded.sortByKey('name');
16168
+ const addressParts = [
15974
16169
  meetingData[m]['location_street'],
15975
16170
  meetingData[m]['location_municipality'].trim(),
15976
16171
  meetingData[m]['location_province'].trim(),
15977
16172
  meetingData[m]['location_postal_code_1'].trim()
15978
- ];
15979
- addressParts.clean();
16173
+ ].filter((value)=>value!=="");
15980
16174
  meetingData[m]['formatted_address'] = addressParts.join(", ");
15981
16175
  meetingData[m]['formatted_location_info'] =
15982
16176
  meetingData[m]['location_info'] != null
@@ -15995,7 +16189,7 @@ function Crouton(config) {
15995
16189
  }
15996
16190
  }
15997
16191
 
15998
- var serviceBodyInfo = self.getServiceBodyDetails(meetingData[m]['service_body_bigint'])
16192
+ const serviceBodyInfo = self.getServiceBodyDetails(meetingData[m]['service_body_bigint'])
15999
16193
  meetingData[m]['serviceBodyUrl'] = serviceBodyInfo["url"];
16000
16194
  meetingData[m]['serviceBodyPhone'] = serviceBodyInfo["helpline"];
16001
16195
  meetingData[m]['serviceBodyName'] = serviceBodyInfo["name"];
@@ -16003,7 +16197,7 @@ function Crouton(config) {
16003
16197
  meetingData[m]['serviceBodyContactEmail'] = serviceBodyInfo["contact_email"];
16004
16198
  meetingData[m]['serviceBodyType'] = self.localization.getServiceBodyType(serviceBodyInfo["type"]);
16005
16199
 
16006
- var parentBodyInfo = self.getServiceBodyDetails(serviceBodyInfo["parent_id"]);
16200
+ const parentBodyInfo = self.getServiceBodyDetails(serviceBodyInfo["parent_id"]);
16007
16201
  if (parentBodyInfo !== undefined) {
16008
16202
  meetingData[m]['parentServiceBodyId'] = serviceBodyInfo["parent_id"];
16009
16203
  meetingData[m]['parentServiceBodyUrl'] = parentBodyInfo["url"];
@@ -16032,7 +16226,27 @@ function Crouton(config) {
16032
16226
  return self.convertToGroups(meetings);
16033
16227
  }
16034
16228
  return meetings;
16035
- };
16229
+ }
16230
+ // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16231
+ const masterFormatVenueType = {
16232
+ IN_PERSON: "IN_PERSON",
16233
+ VIRTUAL: "VIRTUAL",
16234
+ }
16235
+
16236
+ function getVenueTypeName(data) {
16237
+ if (data['venue_type'] === venueType.HYBRID || getFormats(data).includes(getMasterFormatId('HY', data))) {
16238
+ return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL), crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16239
+ } else if (data['venue_type'] === venueType.VIRTUAL || getFormats(data).includes(getMasterFormatId('VM', data))) {
16240
+ return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL)];
16241
+ } else {
16242
+ return [crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16243
+ }
16244
+ }
16245
+ /**
16246
+ * Convert from individual meetings to groups.
16247
+ * @param array meetings
16248
+ * @returns
16249
+ */
16036
16250
  self.convertToGroups = function(meetings) {
16037
16251
  if (!meetings || !meetings.length) return [];
16038
16252
  if (meetings[0].hasOwnProperty('membersOfGroup')) return meetings;
@@ -16079,6 +16293,11 @@ function Crouton(config) {
16079
16293
  });
16080
16294
  return groups;
16081
16295
  }
16296
+ /**
16297
+ * Update the distances displyed after geocoding or geolocation.
16298
+ * @param boolean initial
16299
+ * @returns
16300
+ */
16082
16301
  Crouton.prototype.updateDistances = function(initial=false) {
16083
16302
  const self = this;
16084
16303
  var knt = 0;
@@ -16113,8 +16332,8 @@ function Crouton(config) {
16113
16332
  });
16114
16333
  }
16115
16334
  const sorted = parent.children().sort(function (a, b) {
16116
- const idA =parseFloat( jQuery(a).data('meetingid').replace("meeting-data-row-", ""));
16117
- const idB =parseFloat( jQuery(b).data('meetingid').replace("meeting-data-row-", ""));
16335
+ const idA =parseFloat( (jQuery(a).data('meetingid') ?? jQuery(a).attr('id')).replace("meeting-data-row-", ""));
16336
+ const idB =parseFloat( (jQuery(b).data('meetingid') ?? jQuery(b).attr('id')).replace("meeting-data-row-", ""));
16118
16337
  const dataA = self.meetingData.find((m) => m.id_bigint==idA);
16119
16338
  const dataB = self.meetingData.find((m) => m.id_bigint==idB);
16120
16339
  const distanceA = dataA ? parseFloat(dataA['distance_in_km']) : Number.POSITIVE_INFINITY;
@@ -16146,8 +16365,6 @@ function Crouton(config) {
16146
16365
  ? "<td>{{> meetingStackedRow}}</td>"
16147
16366
  : hbs_Crouton.templates['meeting3ColumnRow'])
16148
16367
  );
16149
-
16150
-
16151
16368
  self.registerPartial("meetingDataTemplate", self.config['meeting_data_template']);
16152
16369
  self.registerPartial("meetingDataTemplate", self.config['meeting_data_template']);
16153
16370
  self.registerPartial("metaDataTemplate", self.config['metadata_template']);
@@ -16165,6 +16382,14 @@ function Crouton(config) {
16165
16382
  handlebarsExtensions.registerHelpers();
16166
16383
  handlebarsExtensions.registerPartials(self.config.groups);
16167
16384
  }
16385
+ self.getServiceBodyDetails = function(serviceBodyId) {
16386
+ return this.all_service_bodies.find((s)=>s['id'] === serviceBodyId)
16387
+ }
16388
+ /**
16389
+ * Calculate the distances sfter geocoding or geolocation, adding them to the meeting data.
16390
+ * @param boolean initial
16391
+ * @returns
16392
+ */
16168
16393
  self.calculateDistance = function(meetingData) {
16169
16394
  meetingData['distance'] = '';
16170
16395
  if (meetingData['venue_type'] != 2) {
@@ -16208,19 +16433,21 @@ function Crouton(config) {
16208
16433
  self.getUsedNext24 = function(meetings) {
16209
16434
  return [{name: 'Next24', value: 1}];
16210
16435
  }
16211
- self.isEmpty = function(obj) {
16212
- for (var key in obj) {
16213
- if(obj.hasOwnProperty(key))
16214
- return false;
16215
- }
16216
- return true;
16217
- };
16436
+ self.getUsedFavorites = function(meetings) {
16437
+ return [{name: 'Favorite', value: 1}]
16438
+ }
16218
16439
  self.createBmltMapElement = function() {
16219
16440
  if (!document.getElementById('bmlt-map')) {
16220
16441
  jQuery("#bmlt-tabs").before("<div id='bmlt-map' class='bootstrap-bmlt bmlt-map "+self.localization.getWord('css-direction')+" bmlt_map_container_div'></div>");
16221
16442
  }
16222
16443
  return 'bmlt-map';
16223
16444
  }
16445
+ self.createLocationSearchElement = function() {
16446
+ if (!document.getElementById('bmlt-location-search')) {
16447
+ 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>");
16448
+ }
16449
+ return 'bmlt-location-search';
16450
+ }
16224
16451
  if (typeof window.croutonMap === 'undefined') {
16225
16452
  window.croutonMap = new MeetingMap(self.config);
16226
16453
  if (self.config['map_search']) self.searchMap();
@@ -16230,7 +16457,7 @@ function Crouton(config) {
16230
16457
  }
16231
16458
 
16232
16459
  Crouton.prototype.setConfig = function(config) {
16233
- var self = this;
16460
+ const self = this;
16234
16461
  const deprecatedNames = {
16235
16462
  button_filters: 'grouping_buttons',
16236
16463
  button_format_filters: 'formattype_grouping_buttons',
@@ -16291,43 +16518,27 @@ Crouton.prototype.setConfig = function(config) {
16291
16518
  console.log("Error parsing custom translations: " + e.message);
16292
16519
  }
16293
16520
  }
16294
- };
16295
-
16296
- Crouton.prototype.reset = function() {
16297
- var self = this;
16298
- jQuery("#custom-css").remove();
16299
- jQuery("#" + self.config["placeholder_id"]).html("");
16300
- };
16301
-
16302
- Crouton.prototype.doFilters = function() {
16303
- return this.filterMeetingsFromView();
16304
- }
16305
- Crouton.prototype.getServiceBodyDetails = function(serviceBodyId) {
16306
- var self = this;
16307
- for (var s = 0; s < self.all_service_bodies.length; s++) {
16308
- var service_body = self.all_service_bodies[s];
16309
- if (service_body['id'] === serviceBodyId) {
16310
- return service_body;
16311
- }
16312
- }
16521
+ if (self.config.format_list_style !== 'formatNames') self.config.format_list_style = 'formatKeys';
16313
16522
  }
16314
-
16523
+ /**
16524
+ * This supports the [bmlt_handlebars] shortcode, which allows a meeting's details to be inserted into a page.
16525
+ */
16315
16526
  Crouton.prototype.doHandlebars = function() {
16316
16527
  var elements = document.getElementsByTagName('bmlt-handlebar');
16317
16528
  if (elements.length === 0) {
16318
16529
  console.log('No <bmlt-handlebar> tags found');
16319
16530
  return;
16320
16531
  };
16321
- var self = this;
16322
- self.lock(function() {
16323
- if (self.isEmpty(self.meetingData)) {
16532
+ const self = this;
16533
+ self.listenForReady(function() {
16534
+ if (!self.meetingData || self.meetingData.length === 0) {
16324
16535
  for (let i = 0; i < elements.length; i++) {
16325
16536
  var element = elements.item(i);
16326
16537
  element.innerHTML = "Meeting not found!";
16327
16538
  }
16328
16539
  return;
16329
16540
  }
16330
- var promises = [self.getServiceBodies([self.meetingData[0]['service_body_bigint']])];
16541
+ const promises = [self.getServiceBodies([self.meetingData[0]['service_body_bigint']])];
16331
16542
  Promise.all(promises)
16332
16543
  .then(function(data) {
16333
16544
  hbs_Crouton['localization'] = self.localization;
@@ -16348,10 +16559,21 @@ Crouton.prototype.doHandlebars = function() {
16348
16559
  });
16349
16560
  });
16350
16561
  };
16351
-
16562
+ /**
16563
+ * 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
16564
+ * itself. So we have to ask crouton if the map is showing or not.
16565
+ * @returns boolean
16566
+ */
16567
+ Crouton.prototype.isEmbeddedMapShowing = function() {
16568
+ if (this.config['show_map']) return true;
16569
+ const embeddedMap = document.getElementById("byfield_embeddedMapPage");
16570
+ if (embeddedMap) {
16571
+ return !embeddedMap.classList.contains('hide');
16572
+ }
16573
+ return true;
16574
+ }
16352
16575
  Crouton.prototype.meetingModal = function(meetingId) {
16353
- let self = this;
16354
- this.openMeetingModal(self.meetingData.find((m) => m.id_bigint == meetingId));
16576
+ this.openMeetingModal(this.meetingData.find((m) => m.id_bigint == meetingId));
16355
16577
  return;
16356
16578
  }
16357
16579
  Crouton.prototype.openMeetingModal = function(meeting) {
@@ -16372,7 +16594,7 @@ Crouton.prototype.openMeetingModal = function(meeting) {
16372
16594
  croutonMap.loadPopupMap("bmlt-handlebars-map", meeting, {
16373
16595
  lat: parseFloat(meeting.latitude),
16374
16596
  lng: parseFloat(meeting.longitude),
16375
- zoom: 14
16597
+ zoom: self.config.focusedMeetingPopupZoomLevel ?? 14
16376
16598
  });
16377
16599
  let visibleMeetings = jQuery('.bmlt-data-row:visible');
16378
16600
  let index = -1;
@@ -16413,8 +16635,11 @@ Crouton.prototype.openMeetingModal = function(meeting) {
16413
16635
  mm.getElementsByClassName('modal-right').item(0).addEventListener("click", ev=>doSwipe("left"));
16414
16636
  }
16415
16637
  }
16638
+ /**
16639
+ * Execute the [crouton_map] shortcode.
16640
+ */
16416
16641
  Crouton.prototype.searchMap = function() {
16417
- var self = this;
16642
+ const self = this;
16418
16643
  self.distanceTabAllowed = true;
16419
16644
  if (!self.config.map_search || typeof self.config.map_search !== 'object') {
16420
16645
  self.config.map_search = {
@@ -16432,12 +16657,6 @@ Crouton.prototype.searchMap = function() {
16432
16657
  }
16433
16658
  self.config['map_page'] = false;
16434
16659
  self.config['show_map'] = false;
16435
- var body = jQuery("body");
16436
- if (self.config['theme'] !== '') {
16437
- body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
16438
- }
16439
-
16440
- body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
16441
16660
 
16442
16661
  self.meetingData = null;
16443
16662
  self.renderStandaloneMap("#" + self.config['placeholder_id'], {
@@ -16454,29 +16673,26 @@ Crouton.prototype.searchMap = function() {
16454
16673
  "location": {'latitude':0,'longitude':0,'zoom':10} // TODO: Where is this used?
16455
16674
  });
16456
16675
  }
16676
+ /**
16677
+ * This methods does the main work of creating the crouton table.
16678
+ * @param boolean doMeetingMap MeetingMap is the old name for the [bmlt_map] shortcode.
16679
+ * @param boolean fitBounds Expand the scaale and center of the map to contain all meetings.
16680
+ */
16457
16681
  Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16458
- var self = this;
16682
+ const self = this;
16459
16683
 
16460
- self.lock(function() {
16461
- var body = jQuery("body");
16462
- if (self.config['theme'] !== '') {
16463
- body.append("<div id='custom-css'><link rel='stylesheet' type='text/css' href='" + self.config['template_path'] + '/themes/' + self.config['theme'] + ".css'>");
16464
- }
16465
-
16466
- body.append("<div id='custom-css'><style type='text/css'>" + self.config['custom_css'] + "</style></div>");
16467
-
16468
- if (self.isEmpty(self.meetingData)) {
16684
+ self.listenForReady(function() {
16685
+ if (!self.meetingData || self.meetingData.length === 0) {
16469
16686
  jQuery('#please-wait').remove();
16470
16687
  self.showMessage("No meetings found for parameters specified.");
16471
- alert("No meetings found for parameters specified.");
16472
16688
  if (self.config['refresh_map']) {
16473
- croutonMap.refreshMeetings(self.meetingData, fitBounds, true);
16689
+ croutonMap.refreshMeetings(self.meetingData, fitBounds);
16474
16690
  }
16475
16691
  return;
16476
16692
  }
16477
16693
 
16478
16694
  self.unique_service_bodies_ids = getUniqueValuesOfKey(self.meetingData, 'service_body_bigint').sort();
16479
- var promises = [self.getMasterFormats(), self.getServiceBodies(self.unique_service_bodies_ids)];
16695
+ const promises = [self.getMasterFormats(), self.getServiceBodies(self.unique_service_bodies_ids)];
16480
16696
  Promise.all(promises)
16481
16697
  .then(function(data) {
16482
16698
  self.all_service_bodies = [];
@@ -16513,7 +16729,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16513
16729
  var weekdaysData = [];
16514
16730
  while (day_counter < 7) {
16515
16731
  var day = self.config.day_sequence[day_counter];
16516
- var daysOfTheWeekMeetings = enrichedMeetingData.filterByObjectKeyValue('day_of_the_week', day);
16732
+ var daysOfTheWeekMeetings = enrichedMeetingData.filter((meeting)=>meeting['day_of_the_week'] == day);
16517
16733
  weekdaysData.push({
16518
16734
  "day": day,
16519
16735
  "meetings": daysOfTheWeekMeetings
@@ -16529,7 +16745,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16529
16745
  if (groupByName.startsWith('distance')) continue;
16530
16746
  var groupByData = getUniqueValuesOfKey(daysOfTheWeekMeetings, groupByName).sort();
16531
16747
  for (var i = 0; i < groupByData.length; i++) {
16532
- var groupByMeetings = daysOfTheWeekMeetings.filterByObjectKeyValue(groupByName, groupByData[i]);
16748
+ var groupByMeetings = daysOfTheWeekMeetings.filter((meeting)=>meeting[groupByName] == groupByData[i]);
16533
16749
  if (groupingButtonsData.hasOwnProperty(groupByName) && groupingButtonsData[groupByName].hasOwnProperty(groupByData[i])) {
16534
16750
  groupingButtonsData[groupByName][groupByData[i]] = groupingButtonsData[groupByName][groupByData[i]].concat(groupByMeetings);
16535
16751
  } else if (groupingButtonsData.hasOwnProperty(groupByName)) {
@@ -16604,7 +16820,7 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16604
16820
  self.dropdownData = [];
16605
16821
  if (self.config.has_days) self.dropdownData.push(
16606
16822
  {placeholder: self.localization.getWord('weekday'), pointer: 'weekdays', elementId: "filter-dropdown-weekdays",
16607
- uniqueData: (meetings) => sortListByList(getUniqueValuesOfKey(meetings, "formatted_day"), self.dayNamesSequenced),
16823
+ uniqueData: (meetings) => self.sortListByList(getUniqueValuesOfKey(meetings, "formatted_day"), self.dayNamesSequenced),
16608
16824
  objectPointer: convertToPunyCode, optionName: (s)=>s});
16609
16825
  if (self.config.has_states) self.dropdownData.push(
16610
16826
  {placeholder: self.localization.getWord('states'), pointer: 'States', elementId: "filter-dropdown-states",
@@ -16666,6 +16882,10 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16666
16882
  {placeholder: '', pointer: 'next24', elementId: "filter-dropdown-next24",
16667
16883
  uniqueData: (meetings) => self.getUsedNext24(meetings),
16668
16884
  objectPointer: (s)=>s.value, optionName: (s)=>s.name});
16885
+ if (self.config.has_favorites) self.dropdownData.push(
16886
+ {placeholder: '', pointer: 'favorite', elementId: "filter-dropdown-favorites",
16887
+ uniqueData: (meetings) => self.getUsedFavorites(meetings),
16888
+ objectPointer: (s)=>s.value, optionName: (s)=>s.name});
16669
16889
  let renderer = doMeetingMap ? self.renderStandaloneMap : self.renderView;
16670
16890
  renderer("#" + self.config['placeholder_id'], {
16671
16891
  "config": self.config,
@@ -16684,20 +16904,30 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16684
16904
  jQuery('#groupingButton_distance_in_km').addClass('hide');
16685
16905
  }
16686
16906
  self.addStripes();
16687
- self.calcShowingNow()
16907
+ const showingNow = self.calcShowingNow();
16688
16908
  self.updateMeetingCount();
16689
16909
  jQuery('#please-wait').remove();
16690
16910
  if (self.config['map_search'] != null || self.config['show_map']) {
16691
16911
  jQuery(".bmlt-data-row").css({cursor: "pointer"});
16692
16912
  jQuery(".bmlt-data-row").click(function (e) {
16693
- if (e.target.tagName !== 'A')
16913
+ if (e.target.tagName !== 'A' && !e.target.id.startsWith('crouton-favorite-')) {
16694
16914
  croutonMap.rowClick(parseInt(this.id.replace("meeting-data-row-", "")));
16915
+ }
16695
16916
  });
16696
16917
  }
16697
16918
 
16698
16919
  jQuery("#" + self.config['placeholder_id']).addClass("bootstrap-bmlt");
16699
16920
  jQuery("#filter-dropdown-visibile").removeClass("crouton-select").addClass("hide");
16921
+ jQuery("#filter-dropdown-visibile").parent().addClass("hide");
16700
16922
  jQuery("#filter-dropdown-next24").removeClass("crouton-select").addClass("hide");
16923
+ jQuery("#filter-dropdown-next24").parent().addClass("hide");
16924
+ jQuery("#filter-dropdown-favorites").removeClass("crouton-select").addClass("hide");
16925
+ jQuery("#filter-dropdown-favorites").parent().addClass("hide");
16926
+ if (self.shouldOfferFavorites(showingNow)) {
16927
+ jQuery("#crouton_favorites_button").removeClass("hide");
16928
+ } else {
16929
+ jQuery("#crouton_favorites_button").addClass("hide");
16930
+ }
16701
16931
  jQuery(".crouton-select").select2({
16702
16932
  dropdownAutoWidth: true,
16703
16933
  allowClear: false,
@@ -16734,6 +16964,57 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16734
16964
  jQuery('.filter-dropdown').on('select2:select', function (e) {
16735
16965
  self.filterMeetingsFromView();
16736
16966
  });
16967
+ jQuery('#crouton_favorites_button').on('click', function (e) {
16968
+ if (self.favoritesOn) {
16969
+ self.favoritesOn = false;
16970
+ jQuery("#filter-dropdown-favorites").val("a-");
16971
+ self.lowlightButton("#crouton_favorites_button");
16972
+ } else {
16973
+ self.favoritesOn = true;
16974
+ jQuery("#filter-dropdown-favorites").val("a-1");
16975
+ self.highlightButton("#crouton_favorites_button");
16976
+ }
16977
+ self.filterMeetingsFromView();
16978
+ return;
16979
+ });
16980
+ if (!self.config['has_favorites'] || !self.config['header']) {
16981
+ jQuery(".favorite-icon").addClass("hide");
16982
+ }
16983
+ jQuery(document).on('click', '.crouton-favorite', function(e) {
16984
+ e.preventDefault();
16985
+ e.stopPropagation();
16986
+ const meetingId = parseInt(this.id.replace("crouton-favorite-", ""));
16987
+ const localStorageKey = "crouton-favorites";
16988
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
16989
+ const index = favorites.indexOf(self.config.root_server + "_" + meetingId);
16990
+ const row = e.target.closest(".bmlt-data-row");
16991
+ let shouldFilterMeetings = self.favoritesOn;
16992
+ const showingNow = self.calcShowingNow();
16993
+ const favoritesButtonHidden = jQuery("#crouton_favorites_button").hasClass("hide");
16994
+ if (index !== -1) {
16995
+ favorites.splice(index, 1);
16996
+ e.target.classList.remove("glyphicon-heart");
16997
+ e.target.classList.add("glyphicon-heart-empty");
16998
+ row.setAttribute("data-favorite", 0);
16999
+ } else {
17000
+ shouldFilterMeetings = favoritesButtonHidden;
17001
+ favorites.push(self.config.root_server + "_" + meetingId);
17002
+ e.target.classList.remove("glyphicon-heart-empty");
17003
+ e.target.classList.add("glyphicon-heart");
17004
+ row.setAttribute("data-favorite", 1);
17005
+ }
17006
+ localStorage.setItem(localStorageKey, JSON.stringify(favorites));
17007
+ if (!self.shouldOfferFavorites(showingNow)) {
17008
+ shouldFilterMeetings = true;
17009
+ self.favoritesOn = false;
17010
+ jQuery("#filter-dropdown-favorites").val("a-");
17011
+ self.lowlightButton("#crouton_favorites_button");
17012
+ jQuery("#crouton_favorites_button").addClass("hide");
17013
+ }
17014
+ if (shouldFilterMeetings) {
17015
+ self.filterMeetingsFromView();
17016
+ }
17017
+ });
16737
17018
 
16738
17019
  jQuery("#day").on('click', function () {
16739
17020
  self.showView('day');
@@ -16759,8 +17040,8 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16759
17040
  jQuery(this).tab('show');
16760
17041
  });
16761
17042
 
16762
- var d = new Date();
16763
- var n = d.getDay();
17043
+ const d = new Date();
17044
+ let n = d.getDay();
16764
17045
  n++;
16765
17046
  jQuery('.nav-tabs a[href="#tab' + n + '"]').tab('show');
16766
17047
  jQuery('#tab' + n).show();
@@ -16782,27 +17063,46 @@ Crouton.prototype.render = function(doMeetingMap = false, fitBounds=true) {
16782
17063
  if (self.meetingData.filter(m => m.venue_type != 2).length==0) {
16783
17064
  jQuery('#groupingButton_embeddedMapPage').addClass('hide');
16784
17065
  }
16785
- else croutonMap.initialize('byfield_embeddedMapPage', self.meetingData, null, null, fitBoundsInitial);
17066
+ else {
17067
+ croutonMap.initialize('byfield_embeddedMapPage', self.meetingData, null, null, fitBoundsInitial);
17068
+ if (self.config['has_geolocation'] && self.config['header']) jQuery('#'+self.createLocationSearchElement()).append(croutonMap.createLocationSearchButton());
17069
+ }
16786
17070
  }
16787
17071
  if (self.config['refresh_map']) {
16788
- croutonMap.refreshMeetings(self.meetingData, fitBounds, true);
17072
+ croutonMap.refreshMeetings(self.meetingData, fitBounds);
16789
17073
  }
16790
17074
  if (self.config['view_by'] == 'map' && !self.config['map_page'])
16791
17075
  self.config['view_by'] = 'day';
16792
17076
  self.showView(self.config['view_by'], self.meetingData.length);
16793
- if (self.config['on_complete'] != null && isFunction(self.config['on_complete'])) {
17077
+ if (self.config['on_complete'] != null && {}.toString.call(self.config['on_complete']) === '[object Function]') {
16794
17078
  self.config['on_complete']();
16795
17079
  }
16796
- }, !doMeetingMap);
17080
+ }, !doMeetingMap || (!self.config['lat'] && !self.config['lng']));
16797
17081
  });
16798
17082
  });
16799
- Crouton.prototype.forceShowMap = function() {
16800
- if (this.config.map_page && jQuery('#byfield_embeddedMapPage').hasClass('hide')) {
16801
- this.mapView();
17083
+ self.shouldOfferFavorites = function(showingNow) {
17084
+ if (!self.config['has_favorites']) return false;
17085
+ const localStorageKey = "crouton-favorites";
17086
+ const favorites = JSON.parse(localStorage.getItem(localStorageKey) || "[]");
17087
+ for (let i = 0; i < favorites.length; i++) {
17088
+ const split = favorites[i].split("_");
17089
+ const meetingId = split[split.length-1];
17090
+ if (showingNow.includes(meetingId)) return true;
16802
17091
  }
17092
+ return false;
17093
+ }
17094
+ self.sortListByList = function(source, truth) {
17095
+ var goal = [];
17096
+ for (var x = 0; x < truth.length; x++) {
17097
+ for (var y = 0; y < source.length; y++) {
17098
+ if (truth[x] === source[y]) {
17099
+ goal.push(source[y])
17100
+ }
17101
+ }
17102
+ }
17103
+ return goal;
16803
17104
  }
16804
17105
  };
16805
-
16806
17106
  // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16807
17107
  function getMasterFormatId(code, data) {
16808
17108
  for (var f = 0; f < crouton.masterFormatCodes.length; f++) {
@@ -16813,28 +17113,6 @@ function getMasterFormatId(code, data) {
16813
17113
  }
16814
17114
  }
16815
17115
 
16816
- // [deprecated] Retire after root server 2.16.4 is rolled out everywhere.
16817
- var masterFormatVenueType = {
16818
- IN_PERSON: "IN_PERSON",
16819
- VIRTUAL: "VIRTUAL",
16820
- }
16821
-
16822
- var venueType = {
16823
- IN_PERSON: 1,
16824
- VIRTUAL: 2,
16825
- HYBRID: 3,
16826
- }
16827
-
16828
- function getVenueTypeName(data) {
16829
- if (data['venue_type'] === venueType.HYBRID || inArray(getMasterFormatId('HY', data), getFormats(data))) {
16830
- return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL), crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16831
- } else if (data['venue_type'] === venueType.VIRTUAL || inArray(getMasterFormatId('VM', data), getFormats(data))) {
16832
- return [crouton.localization.getVenueType(masterFormatVenueType.VIRTUAL)];
16833
- } else {
16834
- return [crouton.localization.getVenueType(masterFormatVenueType.IN_PERSON)];
16835
- }
16836
- }
16837
-
16838
17116
  // TODO: Change this logic when https://github.com/bmlt-enabled/bmlt-root-server/issues/353 is released and rolled out everywhere.
16839
17117
  function getFormats(data) {
16840
17118
  return data['formats'] !== "" ? data['format_shared_id_list'].split(",") : [];
@@ -16850,17 +17128,6 @@ function getUniqueValuesOfKey(array, key){
16850
17128
  return carry;
16851
17129
  }, []);
16852
17130
  }
16853
-
16854
- function getValuesFromObject(o) {
16855
- var arr = [];
16856
- for (key in o) {
16857
- if (o.hasOwnProperty(key)) {
16858
- arr.push(o[key]);
16859
- }
16860
- }
16861
-
16862
- return arr;
16863
- }
16864
17131
  function getUniqueFormats(array){
16865
17132
  return array.reduce(function(carry, val){
16866
17133
  if (!(val.formats_expanded)) return carry;
@@ -16878,13 +17145,13 @@ function getUniqueFormatsOfType(array, type){
16878
17145
  },[]).sortByKey('name');
16879
17146
  }
16880
17147
  Crouton.prototype.renderMeetingCount = function() {
16881
- var self = this;
16882
- self.lock(function() {
17148
+ const self = this;
17149
+ self.listenForReady(function() {
16883
17150
  self.updateMeetingCount()
16884
17151
  });
16885
17152
  }
16886
17153
  Crouton.prototype.simulateFilterDropdown = function() {
16887
- self = this;
17154
+ const self = this;
16888
17155
  jQuery('.bmlt-page:not(#byfield_embeddedMapPage)').each(function () {
16889
17156
  self.hidePage(this);
16890
17157
  });
@@ -16923,76 +17190,12 @@ Crouton.prototype.getAdjustedDateTime = function(meeting_day, meeting_time, meet
16923
17190
 
16924
17191
  return meeting_date_time_obj;
16925
17192
  };
16926
-
16927
- function arrayUnique(a, b, c) {
16928
- b = a.length;
16929
- while (c = --b)
16930
- while (c--) a[b] !== a[c] || a.splice(c, 1);
16931
- return a
16932
- }
16933
-
16934
- function sortListByList(source, truth) {
16935
- var goal = [];
16936
- for (var x = 0; x < truth.length; x++) {
16937
- for (var y = 0; y < source.length; y++) {
16938
- if (truth[x] === source[y]) {
16939
- goal.push(source[y])
16940
- }
16941
- }
16942
- }
16943
-
16944
- return goal;
16945
- }
16946
-
16947
- function inArray(needle, haystack) {
16948
- return haystack.indexOf(needle) !== -1;
16949
- }
16950
-
16951
- function isFunction(functionToCheck) {
16952
- return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
16953
- }
16954
-
16955
- function getServiceBodiesQueryString(service_bodies_id) {
16956
- var service_bodies_query = "";
16957
- for (var x = 0; x < service_bodies_id.length; x++) {
16958
- service_bodies_query += "&services[]=" + service_bodies_id[x];
16959
- }
16960
- return service_bodies_query;
16961
- }
16962
-
16963
- Array.prototype.clone = function() {
16964
- return this.slice();
17193
+ // TODO: why can't this be a const? If I set it to const, then I get an error from bootstrap???!!!!
17194
+ var venueType = {
17195
+ IN_PERSON: 1,
17196
+ VIRTUAL: 2,
17197
+ HYBRID: 3,
16965
17198
  }
16966
-
16967
- Array.prototype.filterByObjectKeyValue = function(key, value) {
16968
- var ret = [];
16969
- for (var i = 0; i < this.length; i++) {
16970
- if (this[i][key] === value) {
16971
- ret.push(this[i])
16972
- }
16973
- }
16974
-
16975
- return ret;
16976
- };
16977
-
16978
- Array.prototype.getArrayItemByObjectKeyValue = function(key, value) {
16979
- for (var i = 0; i < this.length; i++) {
16980
- if (this[i][key] === value) {
16981
- return this[i];
16982
- }
16983
- }
16984
- };
16985
-
16986
- Array.prototype.clean = function() {
16987
- for (var i = 0; i < this.length; i++) {
16988
- if (this[i] === "") {
16989
- this.splice(i, 1);
16990
- i--;
16991
- }
16992
- }
16993
- return this;
16994
- };
16995
-
16996
17199
  Array.prototype.sortByKey = function (key) {
16997
17200
  this.sort(function (a, b) {
16998
17201
  if (a[key] < b[key])
@@ -17036,21 +17239,14 @@ function swipedetect(el, callback){
17036
17239
  }, false)
17037
17240
  }
17038
17241
  function isIOSDevice() {
17039
- if (navigator.userAgentData && navigator.userAgentData.platform) {
17040
- if (navigator.userAgentData.platform === 'iOS') {
17041
- return true;
17042
- }
17043
- }
17044
- const userAgent = navigator.userAgent || navigator.vendor || window.opera;
17045
- const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
17046
- const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && !window.MSStream;
17047
- return isIOS || isIPadOS;
17242
+ return crouton.deviceType === "ios";
17048
17243
  }
17049
17244
 
17050
17245
  function isAndroidDevice() {
17051
- return /Android/i.test(navigator.userAgent);
17246
+ return crouton.deviceType === "android";
17052
17247
  }
17053
17248
 
17249
+
17054
17250
  function isMobileDevice() {
17055
17251
  return isIOSDevice() || isAndroidDevice() || /Mobi|Android/i.test(navigator.userAgent);
17056
17252
  }
@@ -17150,8 +17346,10 @@ function openDirectionsModal(e) {
17150
17346
 
17151
17347
  function closeDirectionsModal() {
17152
17348
  const modal = document.getElementById('directionsMapModal');
17153
- modal.style.display = 'none';
17154
- if (modal.className.includes('remove-after-use')) modal.remove();
17349
+ if (modal) {
17350
+ modal.style.display = 'none';
17351
+ if (modal.className.includes('remove-after-use')) modal.remove();
17352
+ }
17155
17353
  }
17156
17354
 
17157
17355
  function openDirections(url, latitude, longitude, fromModal = true) {
@@ -17174,33 +17372,31 @@ function MeetingMap(inConfig) {
17174
17372
  const config = inConfig;
17175
17373
  if (!config.maxZoom) config.maxZoom = 17;
17176
17374
  if (!config.minZoom) config.minZoom = 6;
17375
+ if (!config.locationSearchZoom) config.locationSearchZoom = 12; // TODO: for now, not in interface. Experience will show if it is worth adding to UI.
17177
17376
  if (!config.marker_contents_template) config.marker_contents_template = croutonDefaultTemplates.marker_contents_template;
17178
17377
  var gAllMeetings = [];
17179
17378
  var gMeetingIdsFromCrouton = null;
17180
17379
  var gSearchPoint = false;
17181
- var loadedCallbackFunction = null;
17182
- var loadedCallbackArgs = [];
17183
- var oldBounds = false;
17184
- var isMouseDown = false;
17380
+ var gLoadedCallbackFunction = null;
17381
+ var gLoadedCallbackArgs = [];
17382
+ var gOldBounds = false;
17383
+ var gCurrentlyDraggingMap = false;
17384
+ var gLocationSearchResult = null;
17185
17385
  function preloadApiLoadedCallback(f,a) {
17186
- loadedCallbackFunction = f;
17187
- loadedCallbackArgs = a;
17386
+ gLoadedCallbackFunction = f;
17387
+ gLoadedCallbackArgs = a;
17188
17388
  }
17189
17389
  function apiLoadedCallback() {
17190
- loadedCallbackFunction(...loadedCallbackArgs);
17390
+ gLoadedCallbackFunction(...gLoadedCallbackArgs);
17191
17391
  }
17192
-
17193
17392
  function retrieveGeolocation() {
17194
17393
  return new Promise((resolve, reject) => {
17195
- if (window.storedGeolocation) {
17196
- resolve(window.storedGeolocation);
17197
- } else if (navigator.geolocation) {
17394
+ if (navigator.geolocation) {
17198
17395
  navigator.geolocation.getCurrentPosition((position) => {
17199
- window.storedGeolocation = {
17200
- latitude: position.coords.latitude,
17201
- longitude: position.coords.longitude
17202
- };
17203
- resolve(window.storedGeolocation);
17396
+ resolve({
17397
+ lat: position.coords.latitude,
17398
+ lng: position.coords.longitude
17399
+ });
17204
17400
  }, (error) => {
17205
17401
  reject(new Error('Error getting geolocation: ' + error.message));
17206
17402
  });
@@ -17212,10 +17408,14 @@ function MeetingMap(inConfig) {
17212
17408
  function isFilterVisible() {
17213
17409
  return config.filter_visible && config.filter_visible == 1;
17214
17410
  }
17215
- /************************************************************************************//**
17216
- * \brief Load the map and set it up. *
17217
- ****************************************************************************************/
17218
-
17411
+ /**
17412
+ * Creates the map and adds the various ornaments like search buttons and menus.
17413
+ * @param HTMLElement inDiv Element that contains the map.
17414
+ * @param Object menuContext Contains info for the map menu. For instance, for [bmlt_map], the dropdown filters.
17415
+ * @param {*} handlebarMapOptions
17416
+ * @param Function cb
17417
+ * @param boolean hide
17418
+ */
17219
17419
  function loadMap(inDiv, menuContext, handlebarMapOptions=null,cb=null,hide=false) {
17220
17420
  if (inDiv) {
17221
17421
  crouton_Handlebars.registerPartial("markerContentsTemplate", crouton_Handlebars.compile(config['marker_contents_template']));
@@ -17242,8 +17442,8 @@ function MeetingMap(inConfig) {
17242
17442
  gDelegate.addListener('idle', triggerCroutonMapNewQuery, false);
17243
17443
  } else {
17244
17444
  gDelegate.addListener('zoomend', function (ev) {
17245
- if (shouldRedrawMarkers() && gAllMeetings) {
17246
- if (listOnlyVisible) {
17445
+ if (shouldRedrawMarkers() && gAllMeetings && !gLocationSearchResult) {
17446
+ if (gListOnlyVisible) {
17247
17447
  const oldValue = filterVisible(false);
17248
17448
  searchResponseCallback();
17249
17449
  filterVisible(oldValue);
@@ -17289,9 +17489,7 @@ function MeetingMap(inConfig) {
17289
17489
  controlDiv.querySelector("#bmltsearch-text-button").addEventListener('click', function () {
17290
17490
  let text = document.getElementById("bmltsearch-goto-text").value.trim();
17291
17491
  if (text === "") return;
17292
- showThrobber();
17293
- gDelegate.callGeocoder(text, null, mapSearchGeocode);
17294
- clearMessageAndClose(gSearchModal);
17492
+ gDelegate.callGeocoder(text, mapSearchGeocode);
17295
17493
  });
17296
17494
  controlDiv.querySelector("#modal-seach-parameters").style.display = 'none';
17297
17495
  controlDiv.querySelector("#show-search-parameters").addEventListener('click', function (e) {
@@ -17321,12 +17519,84 @@ function MeetingMap(inConfig) {
17321
17519
  });
17322
17520
 
17323
17521
  controlDiv.querySelector("#bmltsearch-clicksearch").addEventListener('click', clickSearch);
17324
- [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>clearMessageAndClose(e.target)));
17522
+ [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>closeModalWindow(e.target)));
17325
17523
  gSearchModal = controlDiv.querySelector("#bmltsearch_modal");
17326
17524
  gSearchModal.parentElement.removeChild(gSearchModal);
17327
17525
 
17328
17526
  return controlDiv;
17329
17527
  }
17528
+ var gLocationSearchModal;
17529
+ var gDefaultLocationSearchButtonLabel = '';
17530
+ function doGeolocationThenClose() {
17531
+ doGeolocation().then(closeModalWindow(gLocationSearchModal));
17532
+ }
17533
+ function createLocationSearchButton() {
17534
+ const template = hbs_Crouton.templates['locationSearch'];
17535
+ const controlDiv = document.createElement('div');
17536
+ const params = {};
17537
+ controlDiv.innerHTML = template(params);
17538
+ controlDiv.querySelector("#location-search-button").addEventListener('click', showLocationSearchDialog);
17539
+ gDefaultLocationSearchButtonLabel = controlDiv.querySelector("#location-search-button :first-child").innerHTML;
17540
+ controlDiv.querySelector("#bmlt-location-search-nearbyMeetings").addEventListener('click', doGeolocationThenClose);
17541
+ controlDiv.querySelector("#bmlt-location-search-goto-text").addEventListener('keypress', function (event) {
17542
+ if (event.key === "Enter") {
17543
+ event.preventDefault();
17544
+ document.getElementById("bmlt-location-search-text-button").click();
17545
+ }
17546
+ });
17547
+ controlDiv.querySelector("#bmlt-location-search-text-button").addEventListener('click', function () {
17548
+ let text = document.getElementById("bmlt-location-search-goto-text").value.trim();
17549
+ if (text === "") return;
17550
+ if (isMapVisible()) {
17551
+ gDelegate.callGeocoder(text, locationSearchOpenMapGeocode);
17552
+ } else {
17553
+ gDelegate.callGeocoder(text, locationSearchGeocode);
17554
+ }
17555
+ });
17556
+ controlDiv.querySelector("#bmlt-location-search-widen").addEventListener('click', function () {
17557
+ if (gLocationSearchResult === null) {
17558
+ if (gListOnlyVisible && gSearchPoint) {
17559
+ gLocationSearchResult = {center: gSearchPoint, bounds: gDelegate.getBounds(), zoom: gDelegate.getZoom()};
17560
+ } else return;
17561
+ }
17562
+ if (gLocationSearchResult.zoom == config.minZoom) return;
17563
+ filterVisible(false);
17564
+ let bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, gLocationSearchResult.zoom);
17565
+ let knt = filterMeetingsAndBounds(bounds).length;
17566
+ for (let zoom = gLocationSearchResult.zoom-1; zoom >= config.minZoom; zoom = zoom-1) {
17567
+ bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, zoom);
17568
+ if (filterMeetingsAndBounds(bounds).length > knt) {
17569
+ if (isMapVisible()) {
17570
+ gDelegate.flyToFixedZoom(gLocationSearchResult.center, zoom, filterVisible);
17571
+ gLocationSearchResult = null;
17572
+ } else {
17573
+ gLocationSearchResult.zoom = zoom;
17574
+ gLocationSearchResult.bounds = bounds;
17575
+ gListOnlyVisible = false; // force new calc.
17576
+ filterVisible(true, gLocationSearchResult.bounds);
17577
+ }
17578
+ closeModalWindow(gLocationSearchModal);
17579
+ return;
17580
+ }
17581
+ }
17582
+ bounds = gDelegate.calculateBoundsFromCenterAndZoom(gLocationSearchResult.center, gLocationSearchResult.zoom);
17583
+ filterVisible(true, bounds);
17584
+ alert("No further matches");
17585
+ });
17586
+ controlDiv.querySelector("#bmlt-location_search-cancel").addEventListener('click', function () {
17587
+ filterVisible(false);
17588
+ setLocationSearchButtonLabel('');
17589
+ closeModalWindow(gLocationSearchModal);
17590
+ });
17591
+ [...controlDiv.getElementsByClassName('modal-close')].forEach((elem)=>elem.addEventListener('click', (e)=>closeModalWindow(e.target)));
17592
+ gLocationSearchModal = controlDiv.querySelector("#bmlt_location_search_modal");
17593
+ gLocationSearchModal.parentElement.removeChild(gLocationSearchModal);
17594
+
17595
+ return controlDiv;
17596
+ }
17597
+ function isMapVisible() {
17598
+ return gDelegate.isMapVisible() && crouton.isEmbeddedMapShowing();
17599
+ }
17330
17600
  var next24status = false;
17331
17601
  function createNext24Toggle() {
17332
17602
  const toggleSrc = `
@@ -17352,14 +17622,14 @@ function MeetingMap(inConfig) {
17352
17622
  }`
17353
17623
  .replace("__text1__", crouton.localization.getWord("Upcoming Meetings"))
17354
17624
  .replace("__text2__", crouton.localization.getWord("All Meetings"));
17355
- var controlDiv = document.createElement('div');
17625
+ const controlDiv = document.createElement('div');
17356
17626
  controlDiv.innerHTML = toggleSrc;
17357
17627
  controlDiv.querySelector(".onoffswitch").addEventListener('click', function (event) {
17358
17628
  if (event.pointerId < 0) return;
17359
17629
  next24status = !next24status;
17360
- fitDuringFilter = false;
17630
+ gAllowExpandViewport = false;
17361
17631
  crouton.filterNext24(next24status);
17362
- fitDuringFilter = true;
17632
+ gAllowExpandViewport = true;
17363
17633
  });
17364
17634
  let style = document.createElement('style');
17365
17635
  style.innerHTML = rules;
@@ -17367,15 +17637,18 @@ function MeetingMap(inConfig) {
17367
17637
  return controlDiv;
17368
17638
  }
17369
17639
  function createMenuButton(menuContext) {
17370
- var template = hbs_Crouton.templates['mapMenu'];
17371
- var controlDiv = document.createElement('div');
17640
+ const template = hbs_Crouton.templates['mapMenu'];
17641
+ const controlDiv = document.createElement('div');
17372
17642
  controlDiv.innerHTML = template(menuContext);
17373
17643
  controlDiv.querySelector("#nearbyMeetings").addEventListener('click', function (e) {
17374
17644
  retrieveGeolocation().then(position => {
17375
17645
  filterVisible(false);
17376
- gDelegate.setViewToPosition(position, filterMeetingsAndBounds, filterVisible);
17377
- gSearchPoint = {"lat": position.latitude, "lng": position.longitude};
17646
+ gSearchPoint = {"lat": position.lat, "lng": position.lng};
17378
17647
  crouton.updateDistances();
17648
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(gSearchPoint, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
17649
+ gDelegate.flyToFixedZoom(position, locationSearchResult.zoom, filterVisible);
17650
+ filterVisible(true);
17651
+ setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
17379
17652
 
17380
17653
  }).catch(error => {
17381
17654
  console.log(error.message);
@@ -17397,7 +17670,7 @@ function MeetingMap(inConfig) {
17397
17670
  if (dropdownContent.style.display == "inline-block") {
17398
17671
  dropdownContent.style.display = "none";
17399
17672
  } else {
17400
- jQuery("#filteringByVisibility").html(listOnlyVisible?'&#10004;':'');
17673
+ jQuery("#filteringByVisibility").html(gListOnlyVisible?'&#10004;':'');
17401
17674
  dropdownContent.style.display = "inline-block";
17402
17675
  }
17403
17676
  });
@@ -17405,13 +17678,11 @@ function MeetingMap(inConfig) {
17405
17678
  controlDiv.querySelector("#close_table").addEventListener('click', hideListView);
17406
17679
  controlDiv.querySelector("#goto-text").addEventListener('keydown', function (event) {
17407
17680
  if (event && event.key == "Enter") {
17408
- closeModalWindow(event.target);
17409
- lookupLocation(g_suspendedFullscreen);
17681
+ lookupLocation(document.getElementById('goto-text').value,g_suspendedFullscreen, mapMenuGeocode);
17410
17682
  }
17411
17683
  });
17412
17684
  controlDiv.querySelector("#goto-button").addEventListener('click', function (event) {
17413
- closeModalWindow(event.target);
17414
- lookupLocation(g_suspendedFullscreen);
17685
+ lookupLocation(document.getElementById('goto-text').value, g_suspendedFullscreen, mapMenuGeocode);
17415
17686
  });
17416
17687
 
17417
17688
  return controlDiv;
@@ -17419,6 +17690,17 @@ function MeetingMap(inConfig) {
17419
17690
  function hasMapSearch() {
17420
17691
  return 'map_search' in config;
17421
17692
  }
17693
+ /**
17694
+ * Load the meetings for [bmlt_tabs] and [bmlt_map]: all the meetings, during map initialization.
17695
+ * @param string inDiv_id selector for the div that will contain the map.
17696
+ * @param Array meetings_responseObject the meetings returned from the server and enhanced by the crouton core.
17697
+ * @param {*} menuContext information about the dropdown filters.
17698
+ * @param {*} handlebarMapOptions
17699
+ * @param boolean fitBounds should we expand our map so that all the meetings are visible?
17700
+ * @param function callback called after map has been initialized
17701
+ * @param boolean hide make the map invisisble
17702
+ * @returns
17703
+ */
17422
17704
  function loadFromCrouton(inDiv_id, meetings_responseObject, menuContext = null, handlebarMapOptions = null, fitBounds = true, callback, hide) {
17423
17705
  if (!gDelegate.isApiLoaded()) {
17424
17706
  preloadApiLoadedCallback(loadFromCrouton, [inDiv_id, meetings_responseObject, menuContext, handlebarMapOptions, fitBounds, callback, hide]);
@@ -17427,8 +17709,15 @@ function MeetingMap(inConfig) {
17427
17709
  }
17428
17710
  let inDiv = document.getElementById(inDiv_id);
17429
17711
  loadMap(inDiv, menuContext, handlebarMapOptions, callback, hide);
17430
- loadAllMeetings(meetings_responseObject, fitBounds, true);
17712
+ loadAllMeetings(meetings_responseObject, fitBounds);
17431
17713
  };
17714
+ /**
17715
+ * The map on the meeting details popup modal.
17716
+ * @param string inDiv_id selector for the div that will contain the map.
17717
+ * @param Object meeting
17718
+ * @param {*} handlebarMapOptions
17719
+ * @returns
17720
+ */
17432
17721
  function loadPopupMap(inDiv_id, meeting, handlebarMapOptions = null) {
17433
17722
  if (!gDelegate.isApiLoaded()) {
17434
17723
  preloadApiLoadedCallback(loadPopupMap, [inDiv_id, meeting, handlebarMapOptions]);
@@ -17446,25 +17735,21 @@ function MeetingMap(inConfig) {
17446
17735
  gModalDelegate = delegate;
17447
17736
  }
17448
17737
  };
17449
- var fitDuringFilter = true;
17450
- function filterFromCrouton(filter) {
17451
- gMeetingIdsFromCrouton = filter;
17738
+ var gAllowExpandViewport = true;
17739
+ function setFilteredIds(ids) {
17740
+ gMeetingIdsFromCrouton = ids;
17452
17741
  if (gAllMeetings)
17453
- searchResponseCallback(fitDuringFilter && !listOnlyVisible);
17742
+ searchResponseCallback(gAllowExpandViewport && !gListOnlyVisible);
17454
17743
  };
17455
- function clearMessageAndClose(modal) {
17456
- jQuery('#zoomed-out-message').not('.hide').addClass('hide');
17457
- closeModalWindow(modal);
17458
- }
17459
17744
  function nearMeSearch() {
17460
17745
  retrieveGeolocation().then(position => {
17461
17746
  showThrobber();
17462
- gSearchPoint = {"lat": position.latitude, "lng": position.longitude};
17463
- crouton.searchByCoordinates(position.latitude, position.longitude, config.map_search.width);
17464
- if (activeModal == gSearchModal) clearMessageAndClose(gSearchModal);
17747
+ gSearchPoint = {"lat": position.lat, "lng": position.lng};
17748
+ crouton.searchByCoordinates(position.lat, position.lng, config.map_search.width);
17749
+ if (gActiveModal == gSearchModal) closeModalWindow(gSearchModal);
17465
17750
  }).catch(error => {
17466
17751
  console.log(error.message);
17467
- if (activeModal != gSearchModal) showBmltSearchDialog();
17752
+ if (gActiveModal != gSearchModal) showBmltSearchDialog();
17468
17753
  });
17469
17754
  };
17470
17755
  function clickSearch(e) {
@@ -17474,7 +17759,7 @@ function MeetingMap(inConfig) {
17474
17759
  gSearchPoint = {"lat": lat, "lng": lng};
17475
17760
  crouton.searchByCoordinates(lat, lng, config.map_search.width);
17476
17761
  });
17477
- clearMessageAndClose(gSearchModal);
17762
+ closeModalWindow(gSearchModal);
17478
17763
  }
17479
17764
  function createThrobber(inDiv) {
17480
17765
  if (!inDiv.myThrobber) {
@@ -17484,7 +17769,7 @@ function MeetingMap(inConfig) {
17484
17769
  inDiv.myThrobber.className = 'bmlt_map_throbber_div';
17485
17770
  inDiv.myThrobber.style.display = 'none';
17486
17771
  inDiv.appendChild(inDiv.myThrobber);
17487
- var img = document.createElement("img");
17772
+ const img = document.createElement("img");
17488
17773
 
17489
17774
  if (img) {
17490
17775
  img.src = config.BMLTPlugin_images ? config.BMLTPlugin_images + "/Throbber.gif"
@@ -17509,19 +17794,104 @@ function MeetingMap(inConfig) {
17509
17794
  gInDiv.myThrobber.style.display = 'none';
17510
17795
  };
17511
17796
  };
17797
+ function setLocationSearchButtonLabel(label) {
17798
+ if (!label || label==='')
17799
+ jQuery("#location-search-button :first-child").html(gDefaultLocationSearchButtonLabel);
17800
+ else if (gDefaultLocationSearchButtonLabel && gDefaultLocationSearchButtonLabel !== '') {
17801
+ let html = gDefaultLocationSearchButtonLabel.replace(crouton.localization.getWord("Search by Location"), label);
17802
+ jQuery("#location-search-button :first-child").html(html);
17803
+ }
17804
+ }
17805
+ function openMapGeocode(resp, modalName, initial=false) {
17806
+ chooseResponse(modalName, resp, function(resp, i) {
17807
+ let center = gDelegate.getGeocodeCenterAndBounds(resp,i).center;
17808
+ gSearchPoint = {"lat": center.lat, "lng": center.lng};
17809
+ crouton.updateDistances(initial);
17810
+ const modal = document.getElementById(modalName);
17811
+ closeModalWindow(modal);
17812
+ filterVisible(false);
17813
+ const centerAndBounds = gDelegate.getGeocodeCenterAndBounds(resp, i);
17814
+ if (!centerAndBounds) return;
17815
+ const zoom = calcZoomThatContainsBoundingBox(centerAndBounds);
17816
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(gSearchPoint, filterMeetingsAndBounds, zoom);
17817
+ gDelegate.flyToFixedZoom(gSearchPoint, locationSearchResult.zoom, filterVisible);
17818
+ searchResponseCallback();
17819
+ })
17820
+ }
17821
+ function mapMenuGeocode(resp) {
17822
+ openMapGeocode(resp, "geocoding_modal");
17823
+ }
17824
+ function mapMenuGeocodeInitial(resp) {
17825
+ openMapGeocode(resp, "geocoding_modal", true);
17826
+ }
17512
17827
  function mapSearchGeocode(resp) {
17513
- showThrobber();
17514
- if (document.getElementById("bmltsearch-goto-text"))
17515
- document.getElementById("bmltsearch-goto-text").value = "";
17516
- let latlng = gDelegate.getGeocodeCenter(resp);
17517
- if (!latlng) {
17518
- hideThrobber();
17828
+ chooseResponse('bmltsearch_modal', resp, function(resp, i) {
17829
+ closeModalWindow(gSearchModal);
17830
+ if (document.getElementById("bmltsearch-goto-text"))
17831
+ document.getElementById("bmltsearch-goto-text").value = "";
17832
+ let latlng = gDelegate.getGeocodeCenterAndBounds(resp,i).center;
17833
+ if (!latlng) return;
17834
+ showThrobber();
17835
+ gSearchPoint = {"lat": latlng.lat, "lng": latlng.lng};
17836
+ crouton.searchByCoordinates(latlng.lat, latlng.lng, config.map_search.width);
17837
+ });
17838
+ }
17839
+ function chooseResponse(modalName, resp, callback) {
17840
+ if (jQuery('#'+modalName).is(":hidden")) {
17841
+ callback(resp, 0);
17842
+ return;
17843
+ }
17844
+ const choices = gDelegate.getGeocodingChoices(resp);
17845
+ if (choices.length < 2) {
17846
+ setLocationSearchButtonLabel(choices[0]);
17847
+ callback(resp, 0);
17519
17848
  return;
17520
17849
  }
17521
- gSearchPoint = {"lat": latlng.lat, "lng": latlng.lng};
17522
- crouton.searchByCoordinates(latlng.lat, latlng.lng, config.map_search.width);
17850
+ const html = choices.map((choice, index) =>
17851
+ '<button class="location-choice" data-choice="'+index+'">'+choice+'</button>'
17852
+ );
17853
+ jQuery('#'+modalName+' .crouton-modal-search-page').addClass('hide');
17854
+ jQuery('#'+modalName+' .crouton-modal-search-choice').removeClass('hide')
17855
+ .html('<div class="choose-location"><h4>'+crouton.localization.getWord('Choose one')+'</h4>'+html.join('')+'</div>')
17856
+ jQuery('#'+modalName+' .location-choice').on('click', function() {
17857
+ const index = parseInt(jQuery(this).data("choice"))
17858
+ setLocationSearchButtonLabel(choices[index]);
17859
+ callback(resp, index);
17860
+ })
17861
+ }
17862
+ function locationSearchOpenMapGeocode(resp) {
17863
+ openMapGeocode(resp, 'bmlt_location_search_modal');
17864
+ }
17865
+ function calcZoomThatContainsBoundingBox(centerAndBounds) {
17866
+ const center = {lat: (centerAndBounds.southWest.lat + centerAndBounds.northEast.lat)/2,
17867
+ lng: (centerAndBounds.southWest.lng + centerAndBounds.northEast.lng)/2,};
17868
+ let zoom = config.locationSearchZoom + 1;
17869
+ do {
17870
+ if (zoom <= config.minZoom) break;
17871
+ zoom = zoom - 1;
17872
+ var bounds = gDelegate.calculateBoundsFromCenterAndZoom(center, zoom);
17873
+ } while (!gDelegate.contains(bounds, centerAndBounds.southWest.lat, centerAndBounds.southWest.lng)
17874
+ || !gDelegate.contains(bounds, centerAndBounds.northEast.lat, centerAndBounds.northEast.lng))
17875
+ return zoom;
17876
+ }
17877
+ function locationSearchGeocodeInitial(resp) {
17878
+ locationSearchGeocode(resp, true);
17879
+ }
17880
+ function locationSearchGeocode(resp, initial=false) {
17881
+ chooseResponse('bmlt_location_search_modal', resp, function(resp, i) {
17882
+ closeModalWindow(gLocationSearchModal);
17883
+ const centerAndBounds = gDelegate.getGeocodeCenterAndBounds(resp, i);
17884
+ if (!centerAndBounds) return;
17885
+ let center = centerAndBounds.center;
17886
+ filterVisible(false);
17887
+ let zoom = calcZoomThatContainsBoundingBox(centerAndBounds);
17888
+ gLocationSearchResult = gDelegate.getZoomAdjustedBounds(center, filterMeetingsAndBounds, zoom);
17889
+ gSearchPoint = {"lat": gLocationSearchResult.center.lat, "lng": gLocationSearchResult.center.lng};
17890
+ filterVisible(true, gLocationSearchResult.bounds);
17891
+ crouton.updateDistances(initial);
17892
+ });
17523
17893
  }
17524
- function loadAllMeetings(meetings_responseObject, fitBounds=true, fitAll=false) {
17894
+ function loadAllMeetings(meetings_responseObject, fitBounds=true) {
17525
17895
  if (meetings_responseObject === null && config.map_search) {
17526
17896
  if (config.map_search.auto) nearMeSearch();
17527
17897
  else if (config.map_search.coordinates_search) {
@@ -17530,12 +17900,12 @@ function MeetingMap(inConfig) {
17530
17900
  gSearchPoint = {"lat": config.map_search.latitude, "lng": config.map_search.longitude};
17531
17901
  crouton.searchByCoordinates(config.map_search.latitude, config.map_search.longitude, config.map_search.width);
17532
17902
  }
17533
- else if (config.map_search.location) gDelegate.callGeocoder(config.map_search.location, null, mapSearchGeocode);
17903
+ else if (config.map_search.location) gDelegate.callGeocoder(config.map_search.location, mapSearchGeocode);
17534
17904
  else showBmltSearchDialog();
17535
17905
  return;
17536
17906
  }
17537
17907
  gAllMeetings = meetings_responseObject.filter(m => m.venue_type != 2);
17538
- if (fitBounds) {
17908
+ if (fitBounds && !config.centerMe && !config.goto) {
17539
17909
  let lat_lngs = gAllMeetings.reduce(function(a,m) {a.push([m.latitude, m.longitude]); return a;},[]);
17540
17910
  const maxRadius = config.maxTomatoWidth/2.0;
17541
17911
  if (gSearchPoint) lat_lngs.push([gSearchPoint.lat, gSearchPoint.lng]);
@@ -17551,31 +17921,45 @@ function MeetingMap(inConfig) {
17551
17921
  }
17552
17922
  searchResponseCallback();
17553
17923
  hideThrobber();
17554
- if (isFilterVisible() || config.centerMe || config.goto) crouton.forceShowMap();
17555
- if (config.centerMe) {
17556
- if (navigator.geolocation) {
17557
- navigator.geolocation.getCurrentPosition(
17558
- function (position) {
17559
- coords = {latitude: position.coords.latitude, longitude: position.coords.longitude};
17560
- filterVisible(false);
17561
- if (config.zoom) gDelegate.setZoom(false, config.zoom);
17562
- gDelegate.setViewToPosition(coords, filterMeetingsAndBounds, () => {
17563
- filterVisible(isFilterVisible());
17564
- });
17565
- gSearchPoint = {"lat": position.coords.latitude, "lng": position.coords.longitude};
17566
- crouton.updateDistances(true);
17567
- },
17568
- showGeocodingDialog
17569
- );
17570
- } else if (fitAll) {
17571
- showGeocodingDialog();
17572
- }
17573
- } else {
17574
- if ((!config.centerMe && !config.goto) && !(config.map_search && isFilterVisible())) {
17575
- gDelegate.afterInit(()=>filterVisible(isFilterVisible()));
17924
+ gDelegate.afterInit(!crouton.isEmbeddedMapShowing(), () => {
17925
+ if (config.centerMe) {
17926
+ doGeolocation(isFilterVisible(), true).catch(error => showGeocodingDialog());
17927
+ } else {
17928
+ if ((!config.centerMe && !config.goto) && !(config.map_search && isFilterVisible())) {
17929
+ filterVisible(isFilterVisible());
17930
+ }
17931
+ if (config.goto) {
17932
+ if (isMapVisible()) {
17933
+ gDelegate.callGeocoder(config.goto, mapMenuGeocodeInitial);
17934
+ } else {
17935
+ gDelegate.callGeocoder(config.goto, locationSearchGeocodeInitial);
17936
+ }
17937
+ }
17576
17938
  }
17577
- if (config.goto) gDelegate.callGeocoder(config.goto, isFilterVisible() ? resetVisibleThenFilterMeetingsAndBounds : setVisibleThenFilterMeetingsAndBounds);
17578
- }
17939
+ });
17940
+ }
17941
+ function doGeolocation(makeFilterVisible=true, initial=false) {
17942
+ return new Promise((resolve, reject) =>
17943
+ retrieveGeolocation().then(function(coords) {
17944
+ filterVisible(false);
17945
+ if (isMapVisible() || !makeFilterVisible) {
17946
+ const locationSearchResult = gDelegate.getZoomAdjustedBounds(coords, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
17947
+ gDelegate.flyToFixedZoom(coords, locationSearchResult.zoom, () => {
17948
+ filterVisible(makeFilterVisible);
17949
+ if (makeFilterVisible) setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
17950
+ });
17951
+ } else {
17952
+ gLocationSearchResult = gDelegate.getZoomAdjustedBounds(coords, filterMeetingsAndBounds, config.locationSearchZoom ?? 12);
17953
+ filterVisible(true, gLocationSearchResult.bounds);
17954
+ setLocationSearchButtonLabel(crouton.localization.getWord('closest meetings'));
17955
+ }
17956
+ gSearchPoint = coords;
17957
+ crouton.updateDistances(initial);
17958
+ resolve(coords);
17959
+ }).catch(error => {
17960
+ reject(error);
17961
+ })
17962
+ );
17579
17963
  }
17580
17964
  function createCityHash(allMeetings) {
17581
17965
  return allMeetings.reduce(function(prev, meeting) {
@@ -17588,11 +17972,12 @@ function MeetingMap(inConfig) {
17588
17972
  }
17589
17973
  var g_suspendedFullscreen = false;
17590
17974
  var g_overflowX;
17591
- var activeModal = null;
17975
+ var gActiveModal = null;
17592
17976
  var swipableModal = false;
17593
17977
  function closeModalWindow(modal) {
17594
17978
  gDelegate.modalOff();
17595
- activeModal = null;
17979
+ gActiveModal = null;
17980
+ if (!modal) return;
17596
17981
  if (!modal.classList.contains("modal"))
17597
17982
  return closeModalWindow(modal.parentNode);
17598
17983
  modal.style.display = "none";
@@ -17612,8 +17997,8 @@ function MeetingMap(inConfig) {
17612
17997
  }
17613
17998
  }
17614
17999
  document.addEventListener("keydown", function(event) {
17615
- if (activeModal && event.key == "Escape") {
17616
- closeModalWindow(activeModal);
18000
+ if (gActiveModal && event.key == "Escape") {
18001
+ closeModalWindow(gActiveModal);
17617
18002
  }
17618
18003
  }, true);
17619
18004
  function openModalWindow(modal,swipe=false) {
@@ -17623,9 +18008,10 @@ function MeetingMap(inConfig) {
17623
18008
  }
17624
18009
  if (!modal) return;
17625
18010
  modal.style.display = "block";
18011
+ document.body.appendChild(modal);
17626
18012
  swipableModal = swipe;
17627
18013
  modal.focus();
17628
- activeModal = modal;
18014
+ gActiveModal = modal;
17629
18015
  dd = document.getElementById("map-menu-dropdown");
17630
18016
  if (dd) dd.style.display = "none";
17631
18017
  gDelegate.modalOn();
@@ -17643,15 +18029,30 @@ function MeetingMap(inConfig) {
17643
18029
  openModalWindow(document.getElementById('filter_modal'));
17644
18030
  }
17645
18031
  function showBmltSearchDialog(e) {
17646
- if (!document.getElementById('bmltsearch_modal')) gInDiv.appendChild(gSearchModal);
18032
+ openModalWindow(gSearchModal);
17647
18033
  if (gDelegate.isMapDefined())
17648
18034
  jQuery('#bmltsearch-clicksearch').parent().show();
17649
18035
  else
17650
18036
  jQuery('#bmltsearch-clicksearch').parent().hide();
17651
- openModalWindow(gSearchModal);
18037
+ jQuery('#zoomed-out-message').addClass('hide');
18038
+ jQuery('#bmltsearch_modal .crouton-modal-search-page').removeClass('hide');
18039
+ jQuery('#bmltsearch_modal .crouton-modal-search-choice').addClass('hide');
18040
+ }
18041
+ function showLocationSearchDialog(e) {
18042
+ openModalWindow(gLocationSearchModal);
18043
+ if ((gSearchPoint !== null) && gListOnlyVisible) {
18044
+ jQuery("#location-search-widen").removeClass('hide');
18045
+ } else {
18046
+ jQuery("#location-search-widen").addClass('hide');
18047
+ }
18048
+ jQuery('#bmlt_location_search_modal .crouton-modal-search-page').removeClass('hide');
18049
+ jQuery('#bmlt_location_search_modal .crouton-modal-search-choice').addClass('hide');
18050
+ jQuery('bmlt-location-search-goto-text').val('');
17652
18051
  }
17653
18052
  function showGeocodingDialog(e=null) {
17654
18053
  openModalWindow(document.getElementById('geocoding_modal'));
18054
+ jQuery('#geocoding_modal .crouton-modal-search-page').removeClass('hide');
18055
+ jQuery('#geocoding_modal .crouton-modal-search-choice').addClass('hide');
17655
18056
  }
17656
18057
  function showListView(e=null) {
17657
18058
  filterVisible();
@@ -17667,36 +18068,17 @@ function MeetingMap(inConfig) {
17667
18068
  jQuery("#table_page").addClass("hide");
17668
18069
  jQuery("#bmlt-map").css("display", "block");
17669
18070
  }
17670
- function resetVisibleThenFilterMeetingsAndBounds(bounds, center=null) {
17671
- filterVisible(false);
17672
- const ret = filterMeetingsAndBounds(bounds);
17673
- filterVisible(true);
17674
- if (gSearchPoint.lat != center.lat || gSearchPoint.lng != center.lng) {
17675
- gSearchPoint = center;
17676
- crouton.updateDistances();
17677
- }
17678
- return ret;
17679
- }
17680
- function setVisibleThenFilterMeetingsAndBounds(bounds, center=null) {
17681
- filterVisible(false);
17682
- const ret = filterMeetingsAndBounds(bounds);
17683
- if (gSearchPoint.lat != center.lat || gSearchPoint.lng != center.lng) {
17684
- gSearchPoint = center;
17685
- crouton.updateDistances();
17686
- }
17687
- return ret;
17688
- }
17689
- function lookupLocation(fullscreen) {
17690
- if (document.getElementById('goto-text').value != '') {
18071
+ function lookupLocation(location,fullscreen, callback) {
18072
+ if (location != '') {
17691
18073
  if (fullscreen) {
17692
18074
  gDelegate.addListener('idle', function () {
17693
- gDelegate.callGeocoder(document.getElementById('goto-text').value, resetVisibleThenFilterMeetingsAndBounds);
18075
+ gDelegate.callGeocoder(location, callback);
17694
18076
  }, true);
17695
18077
  } else {
17696
- gDelegate.callGeocoder(document.getElementById('goto-text').value, resetVisibleThenFilterMeetingsAndBounds);
18078
+ gDelegate.callGeocoder(location, callback);
17697
18079
  }
17698
18080
  } else {
17699
- alert("");
18081
+ alert("Location not found");
17700
18082
  };
17701
18083
  return true;
17702
18084
  };
@@ -17704,19 +18086,9 @@ function MeetingMap(inConfig) {
17704
18086
  if (!gAllMeetings || !gAllMeetings.length) {
17705
18087
  return;
17706
18088
  };
17707
- try {
17708
- drawMarkers(expand);
17709
- if (gSearchPoint) {
17710
- gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17711
- }
17712
- } catch (e) {
17713
- console.log(e);
17714
- gDelegate.addListener('projection_changed', function (ev) {
17715
- drawMarkers(expand);
17716
- if (gSearchPoint) {
17717
- gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17718
- }
17719
- }, true);
18089
+ drawMarkers(expand);
18090
+ if (gSearchPoint) {
18091
+ gDelegate.markSearchPoint([gSearchPoint.lat, gSearchPoint.lng]);
17720
18092
  }
17721
18093
  };
17722
18094
  /****************************************************************************************
@@ -17764,33 +18136,55 @@ function MeetingMap(inConfig) {
17764
18136
  gDelegate.fitBounds(lat_lngs);
17765
18137
  }
17766
18138
  };
18139
+ function latLngToWebMercator(latlng, zoom) {
18140
+ const lat = Math.max(-85.05112878, Math.min(85.05112878, latlng.lat));
18141
+ const phi = lat * Math.PI / 180;
18142
+ const scale = 256 * Math.pow(2, zoom);
18143
+
18144
+ const x = scale * ((latlng.lng/360.) + .5);
18145
+ const y =
18146
+ scale * (Math.PI - Math.log(Math.tan(Math.PI / 4 + phi / 2))) / (2 * Math.PI);
18147
+ return { x: x, y: y };
18148
+ }
18149
+ function webMercatorToLatLng(point, zoom) {
18150
+ const scale = 256 * Math.pow(2, zoom);
18151
+
18152
+ const lng = 360 * (point.x / scale - .5);
18153
+ const t = Math.exp(Math.PI - (2 * Math.PI) * (point.y / scale));
18154
+ const phi = 2 * Math.atan(t) - Math.PI / 2; // radians
18155
+
18156
+ return { lat: phi * 180 / Math.PI, lng: lng };
18157
+ }
17767
18158
  function mapOverlappingMarkersInCity(in_meeting_array) ///< Used to draw the markers when done.
17768
18159
  {
17769
- var tolerance = 8; /* This is how many pixels we allow. */
18160
+ const tolerance = 8; /* This is how many pixels we allow. */
17770
18161
 
17771
- var ret = new Array;
18162
+ const ret = new Array;
18163
+ const zoom = gDelegate.getZoom();
18164
+ const center = latLngToWebMercator(gDelegate.getCenter(), zoom)
17772
18165
  // We create this hash because we limit looking for "matches" to within one city.
17773
18166
  for (const [city, meetings] of Object.entries(createCityHash(in_meeting_array))) {
17774
18167
  // create a tmp object so we can mark which items haven't been matched yet.
17775
- var tmp = meetings.map((meeting) => {
18168
+ const tmp = meetings.map((meeting) => {
17776
18169
  item = new Object;
17777
18170
  item.matched = false;
17778
18171
  item.meeting = meeting;
17779
- item.coords = gDelegate.fromLatLngToPoint(meeting.latitude, meeting.longitude);
18172
+ const point = latLngToWebMercator({lat: meeting.latitude, lng: meeting.longitude}, zoom);
18173
+ item.coords = {x: point.x-center.x, y: point.y-center.y};
17780
18174
  return item;
17781
18175
  });
17782
18176
  tmp.reduce(function(prev, item, index) {
17783
18177
  if (item.matched) return prev;
17784
18178
  matches = [item.meeting];
17785
- var outer_coords = item.coords;
18179
+ const outer_coords = item.coords;
17786
18180
  for (c2 = index+1; c2<meetings.length; c2++) {
17787
18181
  if (tmp[c2].matched) continue;
17788
- var inner_coords = tmp[c2].coords;
18182
+ const inner_coords = tmp[c2].coords;
17789
18183
 
17790
- var xmin = outer_coords.x - tolerance;
17791
- var xmax = outer_coords.x + tolerance;
17792
- var ymin = outer_coords.y - tolerance;
17793
- var ymax = outer_coords.y + tolerance;
18184
+ const xmin = outer_coords.x - tolerance;
18185
+ const xmax = outer_coords.x + tolerance;
18186
+ const ymin = outer_coords.y - tolerance;
18187
+ const ymax = outer_coords.y + tolerance;
17794
18188
 
17795
18189
  /* We have an overlap. */
17796
18190
  if ((inner_coords.x >= xmin) && (inner_coords.x <= xmax) && (inner_coords.y >= ymin) && (inner_coords.y <= ymax)) {
@@ -17807,8 +18201,8 @@ function MeetingMap(inConfig) {
17807
18201
  return ret;
17808
18202
  };
17809
18203
  function sortMeetingSearchResponseCallback(mtg_a, mtg_b) {
17810
- var weekday_score_a = parseInt(mtg_a.weekday_tinyint, 10);
17811
- var weekday_score_b = parseInt(mtg_b.weekday_tinyint, 10);
18204
+ const weekday_score_a = parseInt(mtg_a.weekday_tinyint, 10);
18205
+ const weekday_score_b = parseInt(mtg_b.weekday_tinyint, 10);
17812
18206
 
17813
18207
  if (weekday_score_a < config.start_week) {
17814
18208
  weekday_score_a += 7;
@@ -17824,8 +18218,8 @@ function MeetingMap(inConfig) {
17824
18218
  else if (weekday_score_a > weekday_score_b) {
17825
18219
  return 1;
17826
18220
  };
17827
- var time_a = mtg_a.start_time.toString().split(':');
17828
- var time_b = mtg_b.start_time.toString().split(':');
18221
+ const time_a = mtg_a.start_time.toString().split(':');
18222
+ const time_b = mtg_b.start_time.toString().split(':');
17829
18223
  if (parseInt(time_a[0]) < parseInt(time_b[0])) {
17830
18224
  return -1;
17831
18225
  }
@@ -17857,77 +18251,77 @@ function MeetingMap(inConfig) {
17857
18251
  * \brief This creates a single meeting's marker on the map. *
17858
18252
  ****************************************************************************************/
17859
18253
  function createMapMarker(meetings, openMarker) {
17860
- var main_point = [meetings[0].latitude, meetings[0].longitude];
18254
+ const main_point = [meetings[0].latitude, meetings[0].longitude];
17861
18255
  const marker_html = markerTemplate(meetings);
17862
18256
  const marker = gDelegate.createMarker(main_point, (meetings.length > 1), null);
17863
18257
  gDelegate.bindPopup(marker, marker_html, meetings.map((m)=>parseInt(m.id_bigint)), openMarker);
17864
18258
  };
17865
18259
  function createGroupMarker(group, openMarker) {
17866
- var main_point = [group.latitude, group.longitude];
18260
+ const main_point = [group.latitude, group.longitude];
17867
18261
  const marker = gDelegate.createMarker(main_point, group['membersOfGroup'].length > 1, null);
17868
18262
  gDelegate.addMarkerCallback(marker, function() {
17869
18263
  crouton.openMeetingModal(group);
17870
18264
  });
17871
18265
  };
17872
- var listOnlyVisible = false;
17873
- var listener = null;
18266
+ var gListOnlyVisible = false;
18267
+ var gDragStartListener = null;
17874
18268
  function filterBounds(bounds) {
17875
18269
  return gAllMeetings.filter((meeting) => gDelegate.contains(bounds, meeting.latitude, meeting.longitude));
17876
18270
  }
17877
18271
  function onDragStart() {
17878
- isMouseDown = true;
18272
+ gCurrentlyDraggingMap = true;
17879
18273
  // if no [crouton_map], then show all meetings
17880
18274
  if (!config.map_search) filterVisible(false);
17881
18275
  gDelegate.addListener('dragend', onDragEnd, true);
17882
18276
  }
17883
18277
  function onDragEnd() {
17884
- isMouseDown = false;
18278
+ gCurrentlyDraggingMap = false;
17885
18279
  // if no [crouton_map], then turn filter visible back on.
17886
18280
  if (config.map_search && isFilterVisible()) triggerCroutonMapNewQuery(null);
17887
18281
  else filterVisible(true);
17888
18282
  }
17889
18283
  function triggerCroutonMapNewQuery(ev) {
17890
- if (isMouseDown) return;
18284
+ if (gCurrentlyDraggingMap) return;
17891
18285
  gMeetingIdsFromCrouton = null;
17892
18286
  corners = gDelegate.getCorners();
17893
- if (oldBounds && gDelegate.contains(oldBounds,corners.ne.lat,corners.ne.lng)
17894
- && gDelegate.contains(oldBounds,corners.sw.lat,corners.sw.lng)) {
18287
+ if (gOldBounds && gDelegate.contains(gOldBounds,corners.ne.lat,corners.ne.lng)
18288
+ && gDelegate.contains(gOldBounds,corners.sw.lat,corners.sw.lng)) {
17895
18289
  filterVisible();
17896
18290
  } else if (getScreenRadius('km') > config.maxTomatoWidth) {
17897
18291
  jQuery('#zoomed-out-message').removeClass('hide');
17898
18292
  showBmltSearchDialog(null);
17899
18293
  } else {
17900
- oldBounds = gDelegate.getBounds();
18294
+ gOldBounds = gDelegate.getBounds();
17901
18295
  showThrobber();
17902
18296
  crouton.searchByCoordinates(gDelegate.getCenter().lat, gDelegate.getCenter().lng, getScreenRadius(), false);
17903
18297
  }
17904
18298
  }
17905
- function filterVisible(on=true) {
17906
- if (on==listOnlyVisible && !config.map_search) return on;
17907
- let mtgs = on ? filterBounds(gDelegate.getBounds()) : gAllMeetings;
18299
+ function filterVisible(on=true, bounds = gDelegate.getBounds()) {
18300
+ if (on==gListOnlyVisible && !config.map_search) return on;
18301
+ let mtgs = on ? filterBounds(bounds) : gAllMeetings;
17908
18302
  let visible = mtgs.map((m)=>m.id_bigint);
17909
18303
  jQuery(".bmlt-data-row").each(function(index,row) {
17910
18304
  row.dataset.visible = (visible.includes(row.id.split('-').pop())) ? '1' : '0';
17911
18305
  });
17912
18306
  jQuery("#byday").removeClass('hide');
17913
18307
  jQuery("#filter-dropdown-visibile").val(on?'a-1':'');
17914
- fitDuringFilter = false;
17915
- crouton.simulateFilterDropdown();
17916
- fitDuringFilter = true;
18308
+ gAllowExpandViewport = false; // calling simulateFilterDropdown will callback croutonMap to set the filtered Ids.
18309
+ crouton.simulateFilterDropdown(); // but we don't want to expand the viewport.
18310
+ gAllowExpandViewport = true;
17917
18311
  jQuery("#filteringByVisibility").html(on?'&#10004;':'');
17918
- listOnlyVisible = on;
17919
- if (on) listener = gDelegate.addListener('dragstart', onDragStart, true);
17920
- else if (listener) {
17921
- gDelegate.removeListener(listener);
17922
- listener = null;
18312
+ gListOnlyVisible = on;
18313
+ if (on) gDragStartListener = gDelegate.addListener('dragstart', onDragStart, true);
18314
+ else if (gDragStartListener) {
18315
+ gDelegate.removeListener(gDragStartListener);
18316
+ gDragStartListener = null;
17923
18317
  }
17924
18318
  return !on;
17925
18319
  }
17926
18320
  function toggleVisible() {
17927
- filterVisible(!listOnlyVisible);
18321
+ filterVisible(!gListOnlyVisible);
17928
18322
  }
17929
18323
  function filterBounds(bounds) {
17930
- var ret = gAllMeetings.filter((meeting) =>
18324
+ const ret = gAllMeetings.filter((meeting) =>
17931
18325
  gDelegate.contains(bounds, meeting.latitude, meeting.longitude));
17932
18326
  return ret;
17933
18327
  }
@@ -17937,31 +18331,31 @@ function MeetingMap(inConfig) {
17937
18331
  if ((gDelegate.getZoom()>=14) && gDelegate.contains(gDelegate.getBounds(), meeting.latitude, meeting.longitude)) {
17938
18332
  gDelegate.openMarker(meetingId);
17939
18333
  } else {
17940
- gDelegate.setViewToPosition({latitude: meeting.latitude, longitude: meeting.longitude}, filterMeetingsAndBounds, function() {gDelegate.openMarker(meetingId);});
18334
+ gDelegate.flyToFixedZoom({lat: meeting.latitude, lng: meeting.longitude}, config.focusedMeetingPopupZoomLevel ?? 14, function() {gDelegate.openMarker(meetingId);});
17941
18335
  }
17942
18336
  }
17943
18337
  function filterMeetingsAndBounds(bounds) {
17944
18338
  return filterMeetings(filterBounds(bounds));
17945
18339
  }
17946
18340
  function filterMeetings(in_meetings_array) {
17947
- var ret = in_meetings_array.filter(m => m.venue_type != 2);
18341
+ const ret = in_meetings_array.filter(m => m.venue_type != 2);
17948
18342
  if (gMeetingIdsFromCrouton != null) {
17949
18343
  return ret.filter((m) => gMeetingIdsFromCrouton.includes(m.id_bigint));
17950
18344
  }
17951
18345
  return ret;
17952
18346
  }
17953
- var _isPseudoFullscreen = false;
18347
+ var gIsPseudoFullscreen = false;
17954
18348
  function isFullscreen() {
17955
- var fullscreenElement =
18349
+ const fullscreenElement =
17956
18350
  document.fullscreenElement ||
17957
18351
  document.mozFullScreenElement ||
17958
18352
  document.webkitFullscreenElement ||
17959
18353
  document.msFullscreenElement;
17960
18354
 
17961
- return (fullscreenElement === gInDiv) || _isPseudoFullscreen;
18355
+ return (fullscreenElement === gInDiv) || gIsPseudoFullscreen;
17962
18356
  }
17963
18357
  function toggleFullscreen(options) {
17964
- var container = gInDiv;
18358
+ const container = gInDiv;
17965
18359
  if (isFullscreen()) {
17966
18360
  if (options && options.pseudoFullscreen) {
17967
18361
  _setFullscreen(false);
@@ -17992,10 +18386,9 @@ function MeetingMap(inConfig) {
17992
18386
  }
17993
18387
  }
17994
18388
  }
17995
- var _isPseudoFullscreen = false;
17996
18389
  function _setFullscreen(fullscreen) {
17997
- _isPseudoFullscreen = fullscreen;
17998
- var container = gInDiv;
18390
+ gIsPseudoFullscreen = fullscreen;
18391
+ const container = gInDiv;
17999
18392
  if (fullscreen) {
18000
18393
  L.DomUtil.addClass(container, 'leaflet-pseudo-fullscreen');
18001
18394
  } else {
@@ -18010,6 +18403,12 @@ function MeetingMap(inConfig) {
18010
18403
  }
18011
18404
  gDelegate.invalidateSize();
18012
18405
  if (!gAllMeetings) return;
18406
+ if (gLocationSearchResult) {
18407
+ searchResponseCallback();
18408
+ filterVisible(false);
18409
+ gDelegate.flyToFixedZoom(gLocationSearchResult.center, gLocationSearchResult.zoom, filterVisible);
18410
+ gLocationSearchResult = null;
18411
+ }
18013
18412
  if (fitBounds) gDelegate.fitBounds(
18014
18413
  ((gMeetingIdsFromCrouton) ? gAllMeetings.filter((m) => gMeetingIdsFromCrouton.includes(m.id_bigint)) : gAllMeetings)
18015
18414
  .reduce(function(a,m) {a.push([m.latitude, m.longitude]); return a;},[])
@@ -18020,14 +18419,14 @@ function MeetingMap(inConfig) {
18020
18419
  }
18021
18420
 
18022
18421
  function getDistance(p1, p2) {
18023
- var R = 6378137; // Earth’s mean radius in meter
18024
- var dLat = rad(p2.lat - p1.lat);
18025
- var dLong = rad(p2.lng - p1.lng);
18026
- var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
18422
+ const R = 6378137; // Earth’s mean radius in meter
18423
+ const dLat = rad(p2.lat - p1.lat);
18424
+ const dLong = rad(p2.lng - p1.lng);
18425
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
18027
18426
  Math.cos(rad(p1.lat)) * Math.cos(rad(p2.lat)) *
18028
18427
  Math.sin(dLong / 2) * Math.sin(dLong / 2);
18029
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
18030
- var d = R * c;
18428
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
18429
+ const d = R * c;
18031
18430
  return d; // returns the distance in meter
18032
18431
  }
18033
18432
  function getDistanceFromSearch(p) {
@@ -18050,7 +18449,7 @@ function MeetingMap(inConfig) {
18050
18449
  ****************************************************************************************/
18051
18450
  this.initialize = loadFromCrouton;
18052
18451
  this.showMap = showMap;
18053
- this.fillMap = filterFromCrouton;
18452
+ this.setFilteredIds = setFilteredIds;
18054
18453
  this.rowClick = focusOnMeeting;
18055
18454
  this.apiLoadedCallback = apiLoadedCallback;
18056
18455
  this.refreshMeetings = loadAllMeetings;
@@ -18060,20 +18459,25 @@ function MeetingMap(inConfig) {
18060
18459
  this.loadPopupMap = loadPopupMap;
18061
18460
  this.filterVisible = filterVisible;
18062
18461
  this.hasMapSearch = hasMapSearch;
18462
+ this.createLocationSearchButton = createLocationSearchButton;
18463
+ this.latLngToWebMercator = latLngToWebMercator;
18464
+ this.webMercatorToLatLng = webMercatorToLatLng;
18063
18465
  };
18064
18466
  MeetingMap.prototype.initialize = null;
18065
18467
  MeetingMap.prototype.showMap = null;
18066
- MeetingMap.prototype.fillMap = null;
18468
+ MeetingMap.prototype.setFilteredIds = null;
18067
18469
  MeetingMap.prototype.rowClick = null;
18068
18470
  MeetingMap.prototype.apiLoadedCallback = null;
18069
18471
  MeetingMap.prototype.refreshMeetings = null;
18070
18472
  MeetingMap.prototype.getDistanceFromSearch = null;
18071
-
18473
+ MeetingMap.prototype.latLngToWebMercator = null; // called from delegates - yuck!
18474
+ MeetingMap.prototype.webMercatorToLatLng = null; // called from delegates - yuck!
18072
18475
  MeetingMap.prototype.openModalWindow = null;
18073
18476
  MeetingMap.prototype.closeModalWindow = null;
18074
18477
  MeetingMap.prototype.loadPopupMap = null;
18075
18478
  MeetingMap.prototype.filterVisible = null;
18076
18479
  MeetingMap.prototype.hasMapSearch = null;
18480
+ MeetingMap.prototype.createLocationSearchButton = null;
18077
18481
 
18078
18482
  function MapDelegate(in_config) {
18079
18483
  const config = in_config;
@@ -18082,6 +18486,7 @@ function MapDelegate(in_config) {
18082
18486
  var g_icon_image_selected = null;
18083
18487
  var g_icon_shadow = null;
18084
18488
  var g_icon_shape = null;
18489
+ var gDiv = null;
18085
18490
  var gMainMap;
18086
18491
  var gOms = null;
18087
18492
  var gMarkerClusterer = null;
@@ -18098,15 +18503,15 @@ function MapDelegate(in_config) {
18098
18503
  var tag = document.createElement('script');
18099
18504
  gIsLoaded = true;
18100
18505
  if (typeof config['api_key'] === 'undefined') config['api_key'] = "";
18101
- tag.src = "https://maps.googleapis.com/maps/api/js?key=" + config['api_key'] + "&callback=croutonMap.apiLoadedCallback";
18506
+ tag.src = "https://maps.googleapis.com/maps/api/js?key=" + config['api_key'] + "&loading=async&callback=croutonMap.apiLoadedCallback";
18102
18507
  tag.defer = true;
18103
18508
  tag.async = true;
18104
18509
  var firstScriptTag = document.getElementsByTagName('script')[0];
18105
18510
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
18106
18511
  };
18107
18512
  function createMap(inDiv, inCenter, inHidden = false) {
18513
+ gDiv = inDiv;
18108
18514
  if ( inHidden ) {
18109
- gDiv = inDiv;
18110
18515
  gDiv.style.height = 'auto';
18111
18516
  gDiv.style.marginBottom = '10px';
18112
18517
  gMainMap = null;
@@ -18196,12 +18601,14 @@ function MapDelegate(in_config) {
18196
18601
  }, start);
18197
18602
  gMainMap.fitBounds(bounds);
18198
18603
  }
18199
- function setViewToPosition(position, filterMeetings, f) {
18604
+ function flyToFixedZoom(position, zoom, extra) {
18200
18605
  if (!gMainMap) return;
18201
- var latlng = new google.maps.LatLng(position.latitude, position.longitude);
18606
+ google.maps.event.addListenerOnce(gMainMap, 'idle', function() {
18607
+ if (extra) extra();
18608
+ });
18609
+ const latlng = new google.maps.LatLng(position.lat, position.lng);
18202
18610
  gMainMap.setCenter(latlng);
18203
- gMainMap.setZoom(getZoomAdjust(false, filterMeetings));
18204
- f && f();
18611
+ gMainMap.setZoom(zoom);
18205
18612
  }
18206
18613
  function getOpenMarker() {
18207
18614
  return gOpenMarker;
@@ -18219,58 +18626,39 @@ function MapDelegate(in_config) {
18219
18626
  function isFilterVisible() {
18220
18627
  return config.filter_visible && config.filter_visible == 1;
18221
18628
  }
18222
- function getZoomAdjust(only_out,filterMeetings) {
18223
- if (!gMainMap) return 12;
18224
- var ret = gMainMap.getZoom();
18225
- if (config.map_search && isFilterVisible()) return ret;
18226
- var center = gMainMap.getCenter();
18227
- var bounds = gMainMap.getBounds();
18228
- var zoomedOut = false;
18229
- while(filterMeetings(bounds, {"lat":center.lat(), "lng":center.lng()}).length==0 && ret>6) {
18230
- zoomedOut = true;
18231
- // no exact, because earth is curved
18232
- ret -= 1;
18233
- var ne = new google.maps.LatLng({
18234
- lat: (2*bounds.getNorthEast().lat())-center.lat(),
18235
- lng: (2*bounds.getNorthEast().lng())-center.lng()});
18236
- var sw = new google.maps.LatLng({
18237
- lat: (2*bounds.getSouthWest().lat())-center.lat(),
18238
- lng: (2*bounds.getSouthWest().lng())-center.lng()});
18239
- bounds = new google.maps.LatLngBounds(sw,ne);
18240
- }
18241
- if (!only_out && !zoomedOut && ret<12) {
18242
- var knt = filterMeetings(bounds).length;
18243
- while(ret<12 && knt>0) {
18244
- // no exact, because earth is curved
18245
- ret += 1;
18246
- var ne = new google.maps.LatLng({
18247
- lat: 0.5*(bounds.getNorthEast().lat()+center.lat()),
18248
- lng: 0.5*(bounds.getNorthEast().lng()+center.lng())});
18249
- var sw = new google.maps.LatLng({
18250
- lat: 0.5*(bounds.getSouthWest().lat()+center.lat()),
18251
- lng: 0.5*(bounds.getSouthWest().lng()+center.lng())});
18252
- bounds = new google.maps.LatLngBounds(sw,ne);
18253
- knt = filterMeetings(bounds).length;
18254
- }
18255
- if (knt == 0) {
18256
- ret -= 1;
18257
- }
18258
- }
18629
+ function webMercatorToLatLng(point, zoom) {
18630
+ const latLng = croutonMap.webMercatorToLatLng(point, zoom);
18631
+ return new google.maps.LatLng(latLng.lat, latLng.lng);
18632
+ }
18633
+ function calculateBounds(center, zoom, width, height) {
18634
+ const centerPoint = croutonMap.latLngToWebMercator(center, zoom);
18635
+ const southwestWebMercator = {x: centerPoint.x-width/2, y: centerPoint.y+height/2};
18636
+ const northeastWebMercator = {x: centerPoint.x+width/2, y: centerPoint.y-height/2};
18637
+ return new google.maps.LatLngBounds(webMercatorToLatLng(southwestWebMercator, zoom), webMercatorToLatLng(northeastWebMercator, zoom));
18638
+ }
18639
+ function calcOffsetWidth(gDiv) {
18640
+ let ret = gDiv.offsetWidth;
18641
+ if (ret === 0) ret = gDiv.parentElement.offsetWidth;
18259
18642
  return ret;
18260
18643
  }
18261
- function setZoom(filterMeetings, force=0) {
18262
- if (!gMainMap) return;
18263
- (force > 0) ? gMainMap.setZoom(force) :
18264
- gMainMap.setZoom(getZoomAdjust(false,filterMeetings));
18265
- }
18644
+ function getZoomAdjust(filterMeetings, zoomLevel=gMainMap.getZoom(), center=gMainMap.getCenter()) {
18645
+ if (!gMainMap) return 12;
18646
+ const mapWidth = calcOffsetWidth(gDiv);
18647
+ const mapHeight = parseInt(jQuery(gDiv).css("height").replace("px",""));
18648
+ const center_latlng = {"lat":center.lat(), "lng":center.lng()};
18649
+ ret = zoomLevel;
18650
+ if (config.map_search && isFilterVisible()) return ret;
18651
+ var bounds = calculateBounds(center_latlng, ret, mapWidth, mapHeight);
18652
+ while(filterMeetings(bounds, center_latlng).length==0 && ret>6) {
18653
+ ret -= 1;
18654
+ bounds = calculateBounds(center_latlng, ret, mapWidth, mapHeight);
18655
+ }
18656
+ return ret;
18657
+ }
18266
18658
  function getZoom() {
18267
18659
  if (!gMainMap) return 12;
18268
18660
  return gMainMap.getZoom();
18269
18661
  }
18270
- function zoomOut(filterMeetings) {
18271
- if (!gMainMap) return;
18272
- gMainMap.setZoom(getZoomAdjust(true,filterMeetings));
18273
- }
18274
18662
  function contains(bounds, lat, lng) {
18275
18663
  if (!gMainMap) return true;
18276
18664
  return bounds.contains(new google.maps.LatLng ( lat, lng));
@@ -18279,13 +18667,6 @@ function MapDelegate(in_config) {
18279
18667
  if (!gMainMap) return null;
18280
18668
  return gMainMap.getBounds();
18281
18669
  }
18282
- function fromLatLngToPoint(lat, lng) {
18283
- if (!gMainMap) return null;
18284
- var latLng = new google.maps.LatLng ( lat, lng);
18285
- var scale = 1 << gMainMap.getZoom();
18286
- var worldPoint = gMainMap.getProjection().fromLatLngToPoint(latLng);
18287
- return new google.maps.Point(worldPoint.x * scale, worldPoint.y * scale);
18288
- };
18289
18670
  function createClusterLayer() {
18290
18671
  gIsClustering = true;
18291
18672
  }
@@ -18455,14 +18836,6 @@ function addControl(div,pos,cb) {
18455
18836
  observer.observe(document, {childList: true, subtree: true});
18456
18837
  }
18457
18838
  gMainMap.controls[p].push(div);
18458
- }
18459
- /************************************************************************************//**
18460
- * \brief This catches the AJAX response, and fills in the response form. *
18461
- ****************************************************************************************/
18462
- function fitAndZoom(ev) {
18463
- if (!gMainMap) return;
18464
- gMainMap.fitBounds(this.response[0].geometry.viewport);
18465
- gMainMap.setZoom(getZoomAdjust(true,this.filterMeetings));
18466
18839
  }
18467
18840
  function openMarker(id) {
18468
18841
  if (!gMainMap) return;
@@ -18472,22 +18845,23 @@ function openMarker(id) {
18472
18845
  openInfoWindow(marker.marker)
18473
18846
  }
18474
18847
  }
18475
- function getGeocodeCenter(in_geocode_response) {
18476
- if ( in_geocode_response && in_geocode_response[0] && in_geocode_response[0].geometry && in_geocode_response[0].geometry.location )
18477
- return {lat: in_geocode_response[0].geometry.location.lat(), lng: in_geocode_response[0].geometry.location.lng()};
18478
- else alert ( crouton.localization.getWord("address_lookup_fail") );
18848
+ function getGeocodingChoices(in_geocode_response) {
18849
+ if (!Array.isArray(in_geocode_response)) return [];
18850
+ return in_geocode_response.map((r) => r.formatted_address);
18479
18851
  }
18480
- function geoCallback( in_geocode_response ) {
18481
- var callback = fitAndZoom.bind({filterMeetings:this.filterMeetings,
18482
- response: in_geocode_response});
18483
- if ( in_geocode_response && in_geocode_response[0] && in_geocode_response[0].geometry && in_geocode_response[0].geometry.location ) {
18484
- gMainMap.panTo ( in_geocode_response[0].geometry.location );
18485
- google.maps.event.addListenerOnce( gMainMap, 'idle', callback);
18486
- } else {
18487
- alert ( crouton.localization.getWord("address_lookup_fail") );
18488
- };
18489
- };
18490
- function callGeocoder(in_loc, filterMeetings, callback=geoCallback) {
18852
+ function getGeocodeCenterAndBounds(in_geocode_response, i=0) {
18853
+ if ( in_geocode_response && in_geocode_response[i] && in_geocode_response[i].geometry && in_geocode_response[i].geometry.location )
18854
+ return {
18855
+ center: {lat: in_geocode_response[i].geometry.location.lat(), lng: in_geocode_response[i].geometry.location.lng()},
18856
+ southWest: {lat: in_geocode_response[i].geometry.viewport.getSouthWest().lat(),
18857
+ lng: in_geocode_response[i].geometry.viewport.getSouthWest().lng()},
18858
+ northEast: {lat: in_geocode_response[i].geometry.viewport.getNorthEast().lat(),
18859
+ lng: in_geocode_response[i].geometry.viewport.getNorthEast().lng()},
18860
+ };
18861
+ alert ( crouton.localization.getWord("address_lookup_fail") );
18862
+ return null;
18863
+ }
18864
+ function callGeocoder(in_loc, callback) {
18491
18865
  var geocoder = new google.maps.Geocoder;
18492
18866
 
18493
18867
  if ( geocoder )
@@ -18505,14 +18879,32 @@ function geoCallback( in_geocode_response ) {
18505
18879
  new google.maps.LatLng(config.bounds.south, config.bounds.west),
18506
18880
  new google.maps.LatLng(config.bounds.north, config.bounds.east));
18507
18881
  }
18508
- if (filterMeetings)
18509
- callback = callback.bind({filterMeetings: filterMeetings});
18510
18882
  geocoder.geocode ( geoCodeParams, callback );
18511
18883
  }
18512
18884
  else // None of that stuff is defined if we couldn't create the geocoder.
18513
18885
  {
18514
18886
  alert ( crouton.localization.getWord("address_lookup_fail") );
18515
18887
  };
18888
+ }
18889
+ function getZoomAdjustedBounds(center_latlng, filterMeetings, zoomLevel) {
18890
+ if (!center_latlng) return null;
18891
+ const center = new google.maps.LatLng(center_latlng.lat, center_latlng.lng);
18892
+ const mapWidth = calcOffsetWidth(gDiv);
18893
+ const mapHeight = parseInt(jQuery(gDiv).css("height").replace("px",""));
18894
+ if (center) {
18895
+ const zoom = getZoomAdjust(filterMeetings, zoomLevel, center);
18896
+ const bounds = calculateBounds(center_latlng, zoom, mapWidth, mapHeight);
18897
+ const ret = {"center": center_latlng, "bounds": bounds, "zoom": zoom};
18898
+ return ret;
18899
+ } else {
18900
+ alert ( crouton.localization.getWord("address_lookup_fail") );
18901
+ return null;
18902
+ }
18903
+ }
18904
+ function calculateBoundsFromCenterAndZoom(center, zoomLevel) {
18905
+ const mapWidth = calcOffsetWidth(gDiv);
18906
+ const mapHeight = parseInt(jQuery(gDiv).css("height").replace("px",""));
18907
+ return calculateBounds(center, zoomLevel, mapWidth, mapHeight);
18516
18908
  }
18517
18909
  function invalidateSize() {
18518
18910
  }
@@ -18546,24 +18938,28 @@ function geoCallback( in_geocode_response ) {
18546
18938
  var center = gMainMap.getCenter();
18547
18939
  return { "lat": center.lat(), "lng": center.lng()}
18548
18940
  }
18549
- function afterInit(f) {
18941
+ function afterInit(doNotWait, f) {
18550
18942
  if (!gMainMap) return;
18551
- if (typeof gMainMap.getBounds() !== 'undefined') f();
18552
- else addListener('idle', f, true);
18943
+ if (doNotWait || (typeof gMainMap.getBounds() !== 'undefined')) f();
18944
+ else addListener('idle', function() {
18945
+ f();
18946
+ }, true);
18553
18947
  }
18554
18948
  function modalOn() {}
18555
18949
  function modalOff() {}
18556
18950
  function isMapDefined() {
18557
- return gMainMap != null;
18951
+ return gMainMap !== null && gMainMap !== undefined;
18952
+ }
18953
+ function isMapVisible() {
18954
+ return gMainMap !== null && gMainMap !== undefined && gMainMap.getProjection() !== null && gMainMap.getProjection() !== undefined;
18558
18955
  }
18559
18956
  this.createMap = createMap;
18560
18957
  this.addListener = addListener;
18561
18958
  this.addControl = addControl;
18562
- this.setViewToPosition = setViewToPosition;
18959
+ this.flyToFixedZoom = flyToFixedZoom;
18563
18960
  this.clearAllMarkers = clearAllMarkers;
18564
- this.fromLatLngToPoint = fromLatLngToPoint;
18565
18961
  this.callGeocoder = callGeocoder;
18566
- this.setZoom = setZoom;
18962
+ this.getZoomAdjustedBounds = getZoomAdjustedBounds;
18567
18963
  this.getZoom = getZoom;
18568
18964
  this.createMarker = createMarker;
18569
18965
  this.bindPopup = bindPopup;
@@ -18571,7 +18967,6 @@ function geoCallback( in_geocode_response ) {
18571
18967
  this.contains = contains;
18572
18968
  this.getBounds = getBounds;
18573
18969
  this.invalidateSize = invalidateSize;
18574
- this.zoomOut = zoomOut;
18575
18970
  this.fitBounds = fitBounds;
18576
18971
  this.openMarker = openMarker;
18577
18972
  this.isApiLoaded = isApiLoaded;
@@ -18580,26 +18975,28 @@ function geoCallback( in_geocode_response ) {
18580
18975
  this.addClusterLayer = addClusterLayer;
18581
18976
  this.removeClusterLayer = removeClusterLayer;
18582
18977
  this.clickSearch = clickSearch;
18583
- this.getGeocodeCenter = getGeocodeCenter;
18978
+ this.getGeocodeCenterAndBounds = getGeocodeCenterAndBounds;
18979
+ this.getGeocodingChoices = getGeocodingChoices;
18584
18980
  this.modalOn = modalOn;
18585
18981
  this.modalOff = modalOff;
18586
18982
  this.removeListener = removeListener;
18587
18983
  this.afterInit = afterInit;
18588
18984
  this.isMapDefined = isMapDefined;
18985
+ this.isMapVisible = isMapVisible;
18589
18986
  this.getCorners = getCorners;
18590
18987
  this.getCenter = getCenter;
18591
18988
  this.markSearchPoint = markSearchPoint;
18592
18989
  this.getOpenMarker = getOpenMarker;
18990
+ this.calculateBoundsFromCenterAndZoom = calculateBoundsFromCenterAndZoom;
18593
18991
  }
18594
18992
  MapDelegate.prototype.createMap = null;
18595
18993
  MapDelegate.prototype.addListener = null;
18596
18994
  MapDelegate.prototype.removeListener = null;
18597
18995
  MapDelegate.prototype.addControl = null;
18598
- MapDelegate.prototype.setViewToPosition = null;
18996
+ MapDelegate.prototype.flyToFixedZoom = null;
18599
18997
  MapDelegate.prototype.clearAllMarkers = null;
18600
- MapDelegate.prototype.fromLatLngToPoint = null;
18601
18998
  MapDelegate.prototype.callGeocoder = null;
18602
- MapDelegate.prototype.setZoom = null;
18999
+ MapDelegate.prototype.getZoomAdjustedBounds = null;
18603
19000
  MapDelegate.prototype.getZoom = null;
18604
19001
  MapDelegate.prototype.createMarker = null;
18605
19002
  MapDelegate.prototype.bindPopup = null;
@@ -18607,7 +19004,6 @@ MapDelegate.prototype.addMarkerCallback = null;
18607
19004
  MapDelegate.prototype.contains = null;
18608
19005
  MapDelegate.prototype.getBounds = null;
18609
19006
  MapDelegate.prototype.invalidateSize = null;
18610
- MapDelegate.prototype.zoomOut = null;
18611
19007
  MapDelegate.prototype.fitBounds = null;
18612
19008
  MapDelegate.prototype.isApiLoaded = null;
18613
19009
  MapDelegate.prototype.loadApi = null;
@@ -18616,15 +19012,18 @@ MapDelegate.prototype.createClusterLayer = null;
18616
19012
  MapDelegate.prototype.addClusterLayer = null;
18617
19013
  MapDelegate.prototype.removeClusterLayer = null;
18618
19014
  MapDelegate.prototype.clickSearch = null;
18619
- MapDelegate.prototype.getGeocodeCenter = null;
19015
+ MapDelegate.prototype.getGeocodeCenterAndBounds = null;
19016
+ MapDelegate.prototype.getGeocodingChoices = null;
18620
19017
  MapDelegate.prototype.modalOn = null;
18621
19018
  MapDelegate.prototype.modalOff = null;
18622
19019
  MapDelegate.prototype.afterInit = null;
18623
19020
  MapDelegate.prototype.isMapDefined = null;
19021
+ MapDelegate.prototype,isMapVisible = null;
18624
19022
  MapDelegate.prototype.getCorners = null;
18625
19023
  MapDelegate.prototype.getCenter= null;
18626
19024
  MapDelegate.prototype.markSearchPoint = null;
18627
19025
  MapDelegate.prototype.getOpenMarker = null;
19026
+ MapDelegate.prototype.calculateBoundsFromCenterAndZoom = null;
18628
19027
  var markerClusterer=function(t){"use strict";function e(t,e){var s={};for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.indexOf(r)<0&&(s[r]=t[r]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(r=Object.getOwnPropertySymbols(t);o<r.length;o++)e.indexOf(r[o])<0&&Object.prototype.propertyIsEnumerable.call(t,r[o])&&(s[r[o]]=t[r[o]])}return s}class s{static isAdvancedMarkerAvailable(t){return google.maps.marker&&!0===t.getMapCapabilities().isAdvancedMarkersAvailable}static isAdvancedMarker(t){return google.maps.marker&&t instanceof google.maps.marker.AdvancedMarkerElement}static setMap(t,e){this.isAdvancedMarker(t)?t.map=e:t.setMap(e)}static getPosition(t){if(this.isAdvancedMarker(t)){if(t.position){if(t.position instanceof google.maps.LatLng)return t.position;if(t.position.lat&&t.position.lng)return new google.maps.LatLng(t.position.lat,t.position.lng)}return new google.maps.LatLng(null)}return t.getPosition()}static getVisible(t){return!!this.isAdvancedMarker(t)||t.getVisible()}}class r{constructor(t){let{markers:e,position:s}=t;this.markers=e,s&&(s instanceof google.maps.LatLng?this._position=s:this._position=new google.maps.LatLng(s))}get bounds(){if(0===this.markers.length&&!this._position)return;const t=new google.maps.LatLngBounds(this._position,this._position);for(const e of this.markers)t.extend(s.getPosition(e));return t}get position(){return this._position||this.bounds.getCenter()}get count(){return this.markers.filter((t=>s.getVisible(t))).length}push(t){this.markers.push(t)}delete(){this.marker&&(s.setMap(this.marker,null),this.marker=void 0),this.markers.length=0}}const o=(t,e,r,o)=>{const n=i(t.getBounds(),e,o);return r.filter((t=>n.contains(s.getPosition(t))))},i=(t,e,s)=>{const{northEast:r,southWest:o}=h(t,e),i=l({northEast:r,southWest:o},s);return c(i,e)},n=(t,e,s)=>{const r=i(t,e,s),o=r.getNorthEast(),n=r.getSouthWest();return[n.lng(),n.lat(),o.lng(),o.lat()]},a=(t,e)=>{const s=(e.lat-t.lat)*Math.PI/180,r=(e.lng-t.lng)*Math.PI/180,o=Math.sin(s/2),i=Math.sin(r/2),n=o*o+Math.cos(t.lat*Math.PI/180)*Math.cos(e.lat*Math.PI/180)*i*i;return 6371*(2*Math.atan2(Math.sqrt(n),Math.sqrt(1-n)))},h=(t,e)=>({northEast:e.fromLatLngToDivPixel(t.getNorthEast()),southWest:e.fromLatLngToDivPixel(t.getSouthWest())}),l=(t,e)=>{let{northEast:s,southWest:r}=t;return s.x+=e,s.y-=e,r.x-=e,r.y+=e,{northEast:s,southWest:r}},c=(t,e)=>{let{northEast:s,southWest:r}=t;const o=e.fromDivPixelToLatLng(r),i=e.fromDivPixelToLatLng(s);return new google.maps.LatLngBounds(o,i)};class u{constructor(t){let{maxZoom:e=16}=t;this.maxZoom=e}noop(t){let{markers:e}=t;return m(e)}}class p extends u{constructor(t){var{viewportPadding:s=60}=t;super(e(t,["viewportPadding"])),this.viewportPadding=60,this.viewportPadding=s}calculate(t){let{markers:e,map:s,mapCanvasProjection:r}=t;return s.getZoom()>=this.maxZoom?{clusters:this.noop({markers:e}),changed:!1}:{clusters:this.cluster({markers:o(s,r,e,this.viewportPadding),map:s,mapCanvasProjection:r})}}}const m=t=>t.map((t=>new r({position:s.getPosition(t),markers:[t]})));function d(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var g=function t(e,s){if(e===s)return!0;if(e&&s&&"object"==typeof e&&"object"==typeof s){if(e.constructor!==s.constructor)return!1;var r,o,i;if(Array.isArray(e)){if((r=e.length)!=s.length)return!1;for(o=r;0!=o--;)if(!t(e[o],s[o]))return!1;return!0}if(e.constructor===RegExp)return e.source===s.source&&e.flags===s.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===s.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===s.toString();if((r=(i=Object.keys(e)).length)!==Object.keys(s).length)return!1;for(o=r;0!=o--;)if(!Object.prototype.hasOwnProperty.call(s,i[o]))return!1;for(o=r;0!=o--;){var n=i[o];if(!t(e[n],s[n]))return!1}return!0}return e!=e&&s!=s},f=d(g);const k=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];class w{static from(t){if(!(t instanceof ArrayBuffer))throw new Error("Data must be an instance of ArrayBuffer.");const[e,s]=new Uint8Array(t,0,2);if(219!==e)throw new Error("Data does not appear to be in a KDBush format.");const r=s>>4;if(1!==r)throw new Error(`Got v${r} data when expected v1.`);const o=k[15&s];if(!o)throw new Error("Unrecognized array type.");const[i]=new Uint16Array(t,2,1),[n]=new Uint32Array(t,4,1);return new w(n,i,o,t)}constructor(t,e=64,s=Float64Array,r){if(isNaN(t)||t<0)throw new Error(`Unpexpected numItems value: ${t}.`);this.numItems=+t,this.nodeSize=Math.min(Math.max(+e,2),65535),this.ArrayType=s,this.IndexArrayType=t<65536?Uint16Array:Uint32Array;const o=k.indexOf(this.ArrayType),i=2*t*this.ArrayType.BYTES_PER_ELEMENT,n=t*this.IndexArrayType.BYTES_PER_ELEMENT,a=(8-n%8)%8;if(o<0)throw new Error(`Unexpected typed array class: ${s}.`);r&&r instanceof ArrayBuffer?(this.data=r,this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+n+a,2*t),this._pos=2*t,this._finished=!0):(this.data=new ArrayBuffer(8+i+n+a),this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+n+a,2*t),this._pos=0,this._finished=!1,new Uint8Array(this.data,0,2).set([219,16+o]),new Uint16Array(this.data,2,1)[0]=e,new Uint32Array(this.data,4,1)[0]=t)}add(t,e){const s=this._pos>>1;return this.ids[s]=s,this.coords[this._pos++]=t,this.coords[this._pos++]=e,s}finish(){const t=this._pos>>1;if(t!==this.numItems)throw new Error(`Added ${t} items when expected ${this.numItems}.`);return y(this.ids,this.coords,this.nodeSize,0,this.numItems-1,0),this._finished=!0,this}range(t,e,s,r){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:o,coords:i,nodeSize:n}=this,a=[0,o.length-1,0],h=[];for(;a.length;){const l=a.pop()||0,c=a.pop()||0,u=a.pop()||0;if(c-u<=n){for(let n=u;n<=c;n++){const a=i[2*n],l=i[2*n+1];a>=t&&a<=s&&l>=e&&l<=r&&h.push(o[n])}continue}const p=u+c>>1,m=i[2*p],d=i[2*p+1];m>=t&&m<=s&&d>=e&&d<=r&&h.push(o[p]),(0===l?t<=m:e<=d)&&(a.push(u),a.push(p-1),a.push(1-l)),(0===l?s>=m:r>=d)&&(a.push(p+1),a.push(c),a.push(1-l))}return h}within(t,e,s){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:r,coords:o,nodeSize:i}=this,n=[0,r.length-1,0],a=[],h=s*s;for(;n.length;){const l=n.pop()||0,c=n.pop()||0,u=n.pop()||0;if(c-u<=i){for(let s=u;s<=c;s++)C(o[2*s],o[2*s+1],t,e)<=h&&a.push(r[s]);continue}const p=u+c>>1,m=o[2*p],d=o[2*p+1];C(m,d,t,e)<=h&&a.push(r[p]),(0===l?t-s<=m:e-s<=d)&&(n.push(u),n.push(p-1),n.push(1-l)),(0===l?t+s>=m:e+s>=d)&&(n.push(p+1),n.push(c),n.push(1-l))}return a}}function y(t,e,s,r,o,i){if(o-r<=s)return;const n=r+o>>1;M(t,e,n,r,o,i),y(t,e,s,r,n-1,1-i),y(t,e,s,n+1,o,1-i)}function M(t,e,s,r,o,i){for(;o>r;){if(o-r>600){const n=o-r+1,a=s-r+1,h=Math.log(n),l=.5*Math.exp(2*h/3),c=.5*Math.sqrt(h*l*(n-l)/n)*(a-n/2<0?-1:1);M(t,e,s,Math.max(r,Math.floor(s-a*l/n+c)),Math.min(o,Math.floor(s+(n-a)*l/n+c)),i)}const n=e[2*s+i];let a=r,h=o;for(v(t,e,r,s),e[2*o+i]>n&&v(t,e,r,o);a<h;){for(v(t,e,a,h),a++,h--;e[2*a+i]<n;)a++;for(;e[2*h+i]>n;)h--}e[2*r+i]===n?v(t,e,r,h):(h++,v(t,e,h,o)),h<=s&&(r=h+1),s<=h&&(o=h-1)}}function v(t,e,s,r){x(t,s,r),x(e,2*s,2*r),x(e,2*s+1,2*r+1)}function x(t,e,s){const r=t[e];t[e]=t[s],t[s]=r}function C(t,e,s,r){const o=t-s,i=e-r;return o*o+i*i}const P={minZoom:0,maxZoom:16,minPoints:2,radius:40,extent:512,nodeSize:64,log:!1,generateId:!1,reduce:null,map:t=>t},_=Math.fround||(E=new Float32Array(1),t=>(E[0]=+t,E[0]));var E;const A=3,b=5,L=6;class O{constructor(t){this.options=Object.assign(Object.create(P),t),this.trees=new Array(this.options.maxZoom+1),this.stride=this.options.reduce?7:6,this.clusterProps=[]}load(t){const{log:e,minZoom:s,maxZoom:r}=this.options;e&&console.time("total time");const o=`prepare ${t.length} points`;e&&console.time(o),this.points=t;const i=[];for(let e=0;e<t.length;e++){const s=t[e];if(!s.geometry)continue;const[r,o]=s.geometry.coordinates,n=_(T(r)),a=_(j(o));i.push(n,a,1/0,e,-1,1),this.options.reduce&&i.push(0)}let n=this.trees[r+1]=this._createTree(i);e&&console.timeEnd(o);for(let t=r;t>=s;t--){const s=+Date.now();n=this.trees[t]=this._createTree(this._cluster(n,t)),e&&console.log("z%d: %d clusters in %dms",t,n.numItems,+Date.now()-s)}return e&&console.timeEnd("total time"),this}getClusters(t,e){let s=((t[0]+180)%360+360)%360-180;const r=Math.max(-90,Math.min(90,t[1]));let o=180===t[2]?180:((t[2]+180)%360+360)%360-180;const i=Math.max(-90,Math.min(90,t[3]));if(t[2]-t[0]>=360)s=-180,o=180;else if(s>o){const t=this.getClusters([s,r,180,i],e),n=this.getClusters([-180,r,o,i],e);return t.concat(n)}const n=this.trees[this._limitZoom(e)],a=n.range(T(s),j(i),T(o),j(r)),h=n.data,l=[];for(const t of a){const e=this.stride*t;l.push(h[e+b]>1?Z(h,e,this.clusterProps):this.points[h[e+A]])}return l}getChildren(t){const e=this._getOriginId(t),s=this._getOriginZoom(t),r="No cluster with the specified id.",o=this.trees[s];if(!o)throw new Error(r);const i=o.data;if(e*this.stride>=i.length)throw new Error(r);const n=this.options.radius/(this.options.extent*Math.pow(2,s-1)),a=i[e*this.stride],h=i[e*this.stride+1],l=o.within(a,h,n),c=[];for(const e of l){const s=e*this.stride;i[s+4]===t&&c.push(i[s+b]>1?Z(i,s,this.clusterProps):this.points[i[s+A]])}if(0===c.length)throw new Error(r);return c}getLeaves(t,e,s){e=e||10,s=s||0;const r=[];return this._appendLeaves(r,t,e,s,0),r}getTile(t,e,s){const r=this.trees[this._limitZoom(t)],o=Math.pow(2,t),{extent:i,radius:n}=this.options,a=n/i,h=(s-a)/o,l=(s+1+a)/o,c={features:[]};return this._addTileFeatures(r.range((e-a)/o,h,(e+1+a)/o,l),r.data,e,s,o,c),0===e&&this._addTileFeatures(r.range(1-a/o,h,1,l),r.data,o,s,o,c),e===o-1&&this._addTileFeatures(r.range(0,h,a/o,l),r.data,-1,s,o,c),c.features.length?c:null}getClusterExpansionZoom(t){let e=this._getOriginZoom(t)-1;for(;e<=this.options.maxZoom;){const s=this.getChildren(t);if(e++,1!==s.length)break;t=s[0].properties.cluster_id}return e}_appendLeaves(t,e,s,r,o){const i=this.getChildren(e);for(const e of i){const i=e.properties;if(i&&i.cluster?o+i.point_count<=r?o+=i.point_count:o=this._appendLeaves(t,i.cluster_id,s,r,o):o<r?o++:t.push(e),t.length===s)break}return o}_createTree(t){const e=new w(t.length/this.stride|0,this.options.nodeSize,Float32Array);for(let s=0;s<t.length;s+=this.stride)e.add(t[s],t[s+1]);return e.finish(),e.data=t,e}_addTileFeatures(t,e,s,r,o,i){for(const n of t){const t=n*this.stride,a=e[t+b]>1;let h,l,c;if(a)h=I(e,t,this.clusterProps),l=e[t],c=e[t+1];else{const s=this.points[e[t+A]];h=s.properties;const[r,o]=s.geometry.coordinates;l=T(r),c=j(o)}const u={type:1,geometry:[[Math.round(this.options.extent*(l*o-s)),Math.round(this.options.extent*(c*o-r))]],tags:h};let p;p=a||this.options.generateId?e[t+A]:this.points[e[t+A]].id,void 0!==p&&(u.id=p),i.features.push(u)}}_limitZoom(t){return Math.max(this.options.minZoom,Math.min(Math.floor(+t),this.options.maxZoom+1))}_cluster(t,e){const{radius:s,extent:r,reduce:o,minPoints:i}=this.options,n=s/(r*Math.pow(2,e)),a=t.data,h=[],l=this.stride;for(let s=0;s<a.length;s+=l){if(a[s+2]<=e)continue;a[s+2]=e;const r=a[s],c=a[s+1],u=t.within(a[s],a[s+1],n),p=a[s+b];let m=p;for(const t of u){const s=t*l;a[s+2]>e&&(m+=a[s+b])}if(m>p&&m>=i){let t,i=r*p,n=c*p,d=-1;const g=((s/l|0)<<5)+(e+1)+this.points.length;for(const r of u){const h=r*l;if(a[h+2]<=e)continue;a[h+2]=e;const c=a[h+b];i+=a[h]*c,n+=a[h+1]*c,a[h+4]=g,o&&(t||(t=this._map(a,s,!0),d=this.clusterProps.length,this.clusterProps.push(t)),o(t,this._map(a,h)))}a[s+4]=g,h.push(i/m,n/m,1/0,g,-1,m),o&&h.push(d)}else{for(let t=0;t<l;t++)h.push(a[s+t]);if(m>1)for(const t of u){const s=t*l;if(!(a[s+2]<=e)){a[s+2]=e;for(let t=0;t<l;t++)h.push(a[s+t])}}}}return h}_getOriginId(t){return t-this.points.length>>5}_getOriginZoom(t){return(t-this.points.length)%32}_map(t,e,s){if(t[e+b]>1){const r=this.clusterProps[t[e+L]];return s?Object.assign({},r):r}const r=this.points[t[e+A]].properties,o=this.options.map(r);return s&&o===r?Object.assign({},o):o}}function Z(t,e,s){return{type:"Feature",id:t[e+A],properties:I(t,e,s),geometry:{type:"Point",coordinates:[(r=t[e],360*(r-.5)),S(t[e+1])]}};var r}function I(t,e,s){const r=t[e+b],o=r>=1e4?`${Math.round(r/1e3)}k`:r>=1e3?Math.round(r/100)/10+"k":r,i=t[e+L],n=-1===i?{}:Object.assign({},s[i]);return Object.assign(n,{cluster:!0,cluster_id:t[e+A],point_count:r,point_count_abbreviated:o})}function T(t){return t/360+.5}function j(t){const e=Math.sin(t*Math.PI/180),s=.5-.25*Math.log((1+e)/(1-e))/Math.PI;return s<0?0:s>1?1:s}function S(t){const e=(180-360*t)*Math.PI/180;return 360*Math.atan(Math.exp(e))/Math.PI-90}class z extends u{constructor(t){var{maxZoom:s,radius:r=60}=t,o=e(t,["maxZoom","radius"]);super({maxZoom:s}),this.state={zoom:-1},this.superCluster=new O(Object.assign({maxZoom:this.maxZoom,radius:r},o))}calculate(t){let e=!1;const r={zoom:t.map.getZoom()};if(!f(t.markers,this.markers)){e=!0,this.markers=[...t.markers];const r=this.markers.map((t=>{const e=s.getPosition(t);return{type:"Feature",geometry:{type:"Point",coordinates:[e.lng(),e.lat()]},properties:{marker:t}}}));this.superCluster.load(r)}return e||(this.state.zoom<=this.maxZoom||r.zoom<=this.maxZoom)&&(e=!f(this.state,r)),this.state=r,e&&(this.clusters=this.cluster(t)),{clusters:this.clusters,changed:e}}cluster(t){let{map:e}=t;return this.superCluster.getClusters([-180,-90,180,90],Math.round(e.getZoom())).map((t=>this.transformCluster(t)))}transformCluster(t){let{geometry:{coordinates:[e,o]},properties:i}=t;if(i.cluster)return new r({markers:this.superCluster.getLeaves(i.cluster_id,1/0).map((t=>t.properties.marker)),position:{lat:o,lng:e}});const n=i.marker;return new r({markers:[n],position:s.getPosition(n)})}}class U{constructor(t,e){this.markers={sum:t.length};const s=e.map((t=>t.count)),r=s.reduce(((t,e)=>t+e),0);this.clusters={count:e.length,markers:{mean:r/e.length,sum:r,min:Math.min(...s),max:Math.max(...s)}}}}class B{render(t,e,r){let{count:o,position:i}=t;const n=`<svg fill="${o>Math.max(10,e.clusters.markers.mean)?"#ff0000":"#0000ff"}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="50" height="50">\n<circle cx="120" cy="120" opacity=".6" r="70" />\n<circle cx="120" cy="120" opacity=".3" r="90" />\n<circle cx="120" cy="120" opacity=".2" r="110" />\n<text x="50%" y="50%" style="fill:#fff" text-anchor="middle" font-size="50" dominant-baseline="middle" font-family="roboto,arial,sans-serif">${o}</text>\n</svg>`,a=`Cluster of ${o} markers`,h=Number(google.maps.Marker.MAX_ZINDEX)+o;if(s.isAdvancedMarkerAvailable(r)){const t=(new DOMParser).parseFromString(n,"image/svg+xml").documentElement;t.setAttribute("transform","translate(0 25)");const e={map:r,position:i,zIndex:h,title:a,content:t};return new google.maps.marker.AdvancedMarkerElement(e)}const l={position:i,zIndex:h,title:a,icon:{url:`data:image/svg+xml;base64,${btoa(n)}`,anchor:new google.maps.Point(25,25)}};return new google.maps.Marker(l)}}class D{constructor(){!function(t,e){for(let s in e.prototype)t.prototype[s]=e.prototype[s]}(D,google.maps.OverlayView)}}var N;t.MarkerClustererEvents=void 0,(N=t.MarkerClustererEvents||(t.MarkerClustererEvents={})).CLUSTERING_BEGIN="clusteringbegin",N.CLUSTERING_END="clusteringend",N.CLUSTER_CLICK="click";const F=(t,e,s)=>{s.fitBounds(e.bounds)};return t.AbstractAlgorithm=u,t.AbstractViewportAlgorithm=p,t.Cluster=r,t.ClusterStats=U,t.DefaultRenderer=B,t.GridAlgorithm=class extends p{constructor(t){var{maxDistance:s=4e4,gridSize:r=40}=t;super(e(t,["maxDistance","gridSize"])),this.clusters=[],this.state={zoom:-1},this.maxDistance=s,this.gridSize=r}calculate(t){let{markers:e,map:s,mapCanvasProjection:r}=t;const i={zoom:s.getZoom()};let n=!1;return this.state.zoom>=this.maxZoom&&i.zoom>=this.maxZoom||(n=!f(this.state,i)),this.state=i,s.getZoom()>=this.maxZoom?{clusters:this.noop({markers:e}),changed:n}:{clusters:this.cluster({markers:o(s,r,e,this.viewportPadding),map:s,mapCanvasProjection:r})}}cluster(t){let{markers:e,map:s,mapCanvasProjection:r}=t;return this.clusters=[],e.forEach((t=>{this.addToClosestCluster(t,s,r)})),this.clusters}addToClosestCluster(t,e,o){let n=this.maxDistance,h=null;for(let e=0;e<this.clusters.length;e++){const r=this.clusters[e],o=a(r.bounds.getCenter().toJSON(),s.getPosition(t).toJSON());o<n&&(n=o,h=r)}if(h&&i(h.bounds,o,this.gridSize).contains(s.getPosition(t)))h.push(t);else{const e=new r({markers:[t]});this.clusters.push(e)}}},t.MarkerClusterer=class extends D{constructor(t){let{map:e,markers:s=[],algorithmOptions:r={},algorithm:o=new z(r),renderer:i=new B,onClusterClick:n=F}=t;super(),this.markers=[...s],this.clusters=[],this.algorithm=o,this.renderer=i,this.onClusterClick=n,e&&this.setMap(e)}addMarker(t,e){this.markers.includes(t)||(this.markers.push(t),e||this.render())}addMarkers(t,e){t.forEach((t=>{this.addMarker(t,!0)})),e||this.render()}removeMarker(t,e){const r=this.markers.indexOf(t);return-1!==r&&(s.setMap(t,null),this.markers.splice(r,1),e||this.render(),!0)}removeMarkers(t,e){let s=!1;return t.forEach((t=>{s=this.removeMarker(t,!0)||s})),s&&!e&&this.render(),s}clearMarkers(t){this.markers.length=0,t||this.render()}render(){const e=this.getMap();if(e instanceof google.maps.Map&&e.getProjection()){google.maps.event.trigger(this,t.MarkerClustererEvents.CLUSTERING_BEGIN,this);const{clusters:r,changed:o}=this.algorithm.calculate({markers:this.markers,map:e,mapCanvasProjection:this.getProjection()});if(o||null==o){const t=new Set;for(const e of r)1==e.markers.length&&t.add(e.markers[0]);const e=[];for(const r of this.clusters)null!=r.marker&&(1==r.markers.length?t.has(r.marker)||s.setMap(r.marker,null):e.push(r.marker));this.clusters=r,this.renderClusters(),requestAnimationFrame((()=>e.forEach((t=>s.setMap(t,null)))))}google.maps.event.trigger(this,t.MarkerClustererEvents.CLUSTERING_END,this)}}onAdd(){this.idleListener=this.getMap().addListener("idle",this.render.bind(this)),this.render()}onRemove(){google.maps.event.removeListener(this.idleListener),this.reset()}reset(){this.markers.forEach((t=>s.setMap(t,null))),this.clusters.forEach((t=>t.delete())),this.clusters=[]}renderClusters(){const e=new U(this.markers,this.clusters),r=this.getMap();this.clusters.forEach((o=>{1===o.markers.length?o.marker=o.markers[0]:(o.marker=this.renderer.render(o,e,r),o.markers.forEach((t=>s.setMap(t,null))),this.onClusterClick&&o.marker.addListener("click",(e=>{google.maps.event.trigger(this,t.MarkerClustererEvents.CLUSTER_CLICK,o),this.onClusterClick(e,o,r)}))),s.setMap(o.marker,r)}))}},t.MarkerUtils=s,t.NoopAlgorithm=class extends u{constructor(t){super(e(t,[]))}calculate(t){let{markers:e,map:s,mapCanvasProjection:r}=t;return{clusters:this.cluster({markers:e,map:s,mapCanvasProjection:r}),changed:!1}}cluster(t){return this.noop(t)}},t.SuperClusterAlgorithm=z,t.SuperClusterViewportAlgorithm=class extends p{constructor(t){var{maxZoom:s,radius:r=60,viewportPadding:o=60}=t,i=e(t,["maxZoom","radius","viewportPadding"]);super({maxZoom:s,viewportPadding:o}),this.superCluster=new O(Object.assign({maxZoom:this.maxZoom,radius:r},i)),this.state={zoom:-1,view:[0,0,0,0]}}calculate(t){const e={zoom:Math.round(t.map.getZoom()),view:n(t.map.getBounds(),t.mapCanvasProjection,this.viewportPadding)};let r=!f(this.state,e);if(!f(t.markers,this.markers)){r=!0,this.markers=[...t.markers];const e=this.markers.map((t=>{const e=s.getPosition(t);return{type:"Feature",geometry:{type:"Point",coordinates:[e.lng(),e.lat()]},properties:{marker:t}}}));this.superCluster.load(e)}return r&&(this.clusters=this.cluster(t),this.state=e),{clusters:this.clusters,changed:r}}cluster(t){let{map:e,mapCanvasProjection:s}=t;const r={zoom:Math.round(e.getZoom()),view:n(e.getBounds(),s,this.viewportPadding)};return this.superCluster.getClusters(r.view,r.zoom).map((t=>this.transformCluster(t)))}transformCluster(t){let{geometry:{coordinates:[e,o]},properties:i}=t;if(i.cluster)return new r({markers:this.superCluster.getLeaves(i.cluster_id,1/0).map((t=>t.properties.marker)),position:{lat:o,lng:e}});const n=i.marker;return new r({markers:[n],position:s.getPosition(n)})}},t.defaultOnClusterClickHandler=F,t.distanceBetweenPoints=a,t.extendBoundsToPaddedViewport=i,t.extendPixelBounds=l,t.filterMarkersToPaddedViewport=o,t.getPaddedViewport=n,t.noop=m,t.pixelBoundsToLatLngBounds=c,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
18629
19028
  //# sourceMappingURL=index.min.js.map
18630
19029