Engelstalige bestemmingen
December 12, 2024 11:33

Ga op een onvergetelijk avontuur met een uitwisselingsprogramma in een Engelstalig land! Dit is jouw kans om je onder te dompelen in een nieuwe cultuur, je taalvaardigheden te verbeteren en herinneringen te maken die een leven lang meegaan. Ervaar het land van de auto in de VS, ontdek de rijke geschiedenis in het Verenigd Koninkrijk, ga ver weg tot in Australië of verbaas je door de rijkheid van Canada.

Engelstalige bestemmingen zijn populaire bestemmingen. Over het algemeen zijn deze programma's de duurdere programma’s met strenge voorwaarden en beperkt aantal plaatsen. Bekijk daarom ook eens de tweetalige programma’s als eventueel interessante alternatieven.

Verenigde Staten schoolprogramma

Ontdek de American dream op het platteland of in de kleinere steden en ontdek het leven op een public school. Ga met de gele schoolbus naar school en ontdek de vele naschoolse mogelijkheden. Wie weet ontdek je wel een nieuw hobby?
Samen met je gastgezin ervaar je de voordelen van een hechte gemeenschap en leer je hun tradities kennen en op hun vertrouwen.

Australië schoolprogramma

In Australië ontdek je een multiculturele samenleving meteen commoon wealth achtegrond. Grijp de kans om samen met je gastgezin deze diverse samenleving te ontdekken. Op school wordt je ondergedompeld in de informele sfeer. Maak jouw keuzes en ontwikkel je eigen interesses.

Canada schoolprogramma

In dit diverse en gastvrije land studeer je in de week en geniet je in het weekend van de prachtige natuur. Als buitenlander zal je niet alleen zijn in deze multiculturele samenleving, maar jij geniet de originele ervaring omwille van je band met je gastgezin. De Canadese school in New Brunswick zal je een unieke mix van academische en buitenschoolse activiteiten bieden.

Verenigd Koninkrijk schoolprogramma

Een uitwisseling in het Verenigd Koninkrijk biedt de kans om de rijke geschiedenis en cultuur van een van de meest invloedrijke landen ter wereld te ontdekken. De state schools combineren academische strengheid met een focus op persoonlijke ontwikkeling en bieden tal van mogelijkheden voor buitenschoolse activiteiten. En, je houdt er nog een mooi accent aan over!

Ierland schoolprogramma

Dompel je onder in de betoverende natuur en de rijke Ierse cultuur, van groene landschappen tot levendige steden. Het Ierse schoolsysteem staat bekend om zijn nadruk op creatief en kritisch denken, waarbij leerlingen worden aangemoedigd om hun talenten te ontwikkelen in een vriendelijke en ondersteunende omgeving. Go green!

Engelstalige bestemmingen zijn populaire bestemmingen. Over het algemeen zijn deze programma's de duurdere programma’s met strenge voorwaarden en beperkt aantal plaatsen. Bekijk daarom ook eens de tweetalige programma’s als eventueel interessante alternatieven.


Zuid-Afrika - een unieke ervaring 

Je leert een gemeenschap en schoolomgeving kennen met een diverse en meertalige cultuur en een levendige schoolomgeving waar naschoolse activiteiten een integraal onderdeel van maken.
Opgelet: voor dit programma moet je voor 1 februari inschrijven. Anders is je dossier niet tijdig klaar.

Hongarije – Tweetalig program in een internationale school

Volg les in het Engels op een privéschool en verbeter actief jouw Engels terwijl je Hongaars als tweede taal leert om in jouw gastgezin vlot te integreren. Op school focus je op talen, alsook andere vakken en bij je gastgezin geniet je van de lekkere gerechten als goulash. Vergeet ook niet een tripje te maken naar Lake Ballaton of in te schrijven op één van de zeer betaalbare tripjes georganiseerd door YFU Hongarije.

Tsjechië - Tweetalig programma met lessen in het Engels

Volg les in het Engels op een privéschool en verrijk je kennis van de Tsjechische taal door dagelijks contact met je vrienden en gastgezin. Tsjechië ligt perfect in Centraal-Europa, met de bergen altijd binnen handbereik. Geniet van het ruime aanbod aan optionele reizen en voel je gedurende het hele jaar omringd door enthousiaste vrijwilligers die jou de rijke Tsjechische cultuur op een natuurlijke manier aanleren.

Verken deze landen en kom naar een infosessie als je meer wil weten!

Kies een continent op de kaart of onder "Alle Bestemmingen" om onze bestemmingen te ontdekken.
Lees de verhalen van onze uitwisselingsstudenten en bekijk de informatie die je nodig hebt om het perfecte land voor jou te vinden!

Country

Leeftijd

Duur

Prijs

Taal

Inschrijven tot

Extra's

              `; return div; }, "introduction": createWidgetHandler( { header: "string", subheader: "string", text: "string", icon: "icon", image1: "image", image2: "image", button: "button", layout: "string", side: "string" }, (text,attrs) => { const div = document.createElement("div"); div.classList.add("introduction","widget",`layout-${attrs.layout}`) div.innerHTML = `
              ${attrs.header ? `

              ${attrs.header}

              ` : ""} ${attrs.subheader ? `

              ${attrs.subheader}

              `: ""} ${attrs.text ? `

              ${attrs.text}

              `: ""} ${attrs.button ? `${attrs.button.label}` : ""}
              ${attrs.image1 ? ``: ""} ${attrs.image2 ? ``: ""} ${attrs.icon ? ``: ""}
              ` return div } ), "aside": createWidgetHandler( { header: "string", text: "string", icon: "icon", button: "button", unordered_list: "listPairs", ordered_list: "listPairs", offset: "string", nudge: "string" }, (text, attrs) => { const aside = document.createElement("aside"); if (attrs.offset) aside.style.gridRow = attrs.offset; if (attrs.nudge) aside.style.marginTop = `${attrs.nudge}rem`; aside.innerHTML = ` ${attrs.icon ? `` : ""} ${attrs.header ? `
              ${attrs.header}
              ` : ""} ${attrs.text ? `

              ${attrs.text}

              ` : ""} ${attrs.unordered_list ? `` : ""} ${attrs.ordered_list ? `
                ` : ""} ${attrs.button ? `
                ${attrs.button.label}
                ` : ""} `; if (attrs.unordered_list) { const ul = aside.querySelector("ul"); for (const { title, href } of attrs.unordered_list) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ul.appendChild(li); } } if (attrs.ordered_list) { const ol = aside.querySelector("ol"); for (const { title, href } of attrs.ordered_list) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ol.appendChild(li); } } return aside; } ), "your_widget": createWidgetHandler( { }, (text, attrs) => { } ), "sticky": createWidgetHandler( { icon: "icon", text: "string" }, (text, attrs) => { } ), "ordered_list": createWidgetHandler( { elements: "listPairs" }, (text, attrs) => { const div = document.createElement("div"); div.classList = "widget list" if (attrs.elements) { const ol = document.createElement("ol"); for (const { title, href } of attrs.elements) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ol.appendChild(li); } div.appendChild(ol); return div; } return null; } ), "unordered_list": createWidgetHandler( { elements: "listPairs" }, (text, attrs) => { const div = document.createElement("div"); div.classList = "widget list" if (attrs.elements) { const ul = document.createElement("ul"); for (const { title, href } of attrs.elements) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ul.appendChild(li); } div.appendChild(ul); return div; } return null; } ), "featured_boxes": createWidgetHandler( { header_1: "string", header_2: "string", icon_1: "icon", icon_2: "icon", text_1: "string", text_2: "string", unordered_list_1: "listPairs", unordered_list_2: "listPairs", ordered_list_1: "listPairs", ordered_list_2: "listPairs", button_1: "button", button_2: "button", color_1: "color", color_2: "color" }, (text, attrs) => { const wrapper = document.createElement("div") wrapper.classList = "widget featured-boxes" if (attrs.header_1 || attrs.text_1 || attrs.icon_1 || attrs.unordered_list_1 || attrs.ordered_list_1 || attrs.button_1) { const div1 = document.createElement("div") div1.classList = `option-1 ${attrs.color_1 ? `${attrs.color_1}` : ""}` div1.innerHTML = ` ${attrs.icon_1 ? `` : ""}
                ${attrs.header_1 ? `

                ${attrs.header_1}

                ` : ""} ${attrs.text_1 ? `

                ${attrs.text_1}

                ` : ""} ${attrs.unordered_list_1 ? `` : ""} ${attrs.ordered_list_1 ? `
                  ` : ""} ${attrs.button_1 ? `` : ""}
                  ` if (attrs.unordered_list_1) { const ul = div1.querySelector("ul"); for (const { title, href } of attrs.unordered_list_1) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ul.appendChild(li); } } if (attrs.ordered_list_1) { const ol = div1.querySelector("ol"); for (const { title, href } of attrs.ordered_list_1) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ol.appendChild(li); } } wrapper.appendChild(div1) } if (attrs.title_2 || attrs.text_2 || attrs.icon_2 || attrs.unordered_list_2 || attrs.ordered_list_2 || attrs.button_2) { const div2 = document.createElement("div") div2.classList = `option-2 ${attrs.color_1 ? `${attrs.color_2}` : ""}` div2.innerHTML = ` ${attrs.icon_2 ? `` : ""}
                  ${attrs.header_2 ? `

                  ${attrs.header_2}

                  ` : ""} ${attrs.text_2 ? `

                  ${attrs.text_2}

                  ` : ""} ${attrs.unordered_list_2 ? `` : ""} ${attrs.ordered_list_2 ? `
                    ` : ""} ${attrs.button_2 ? `` : ""}
                    ` if (attrs.unordered_list_2) { const ul = div2.querySelector("ul"); for (const { title, href } of attrs.unordered_list_2) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ul.appendChild(li); } } if (attrs.ordered_list_2) { const ol = div2.querySelector("ol"); for (const { title, href } of attrs.ordered_list_2) { const li = document.createElement("li"); if (href) { const a = document.createElement("a"); a.href = href; a.textContent = title; li.appendChild(a); } else { li.textContent = title; } ol.appendChild(li); } } wrapper.appendChild(div2) } return wrapper } ), "postcard": createWidgetHandler( { header: "string", quote: "string", image: "image", button: "button", duration: "string", program: "string", flag_alpha2_code: "alpha2", side: "string", layout: "string", link_to_country: "string" }, (text, attrs) => { const div = document.createElement("div") div.classList.add("widget","postcard",`${attrs.layout ? `layout-${attrs.layout}` : ""}`) div.innerHTML = `
                    ${attrs.header ? `

                    ${attrs.header}

                    ` : ""} ${attrs.flag_alpha2_code ? `
                    ` : '
                    '} ${attrs.quote ? `

                    ${attrs.quote}

                    ` : ""}
                    • YFU Vlaanderen
                    • Frans Halsvest 92
                    • Mechelen, 2800
                    • België
                    ${attrs.image ? `` : ""}
                    ` return div } ), "arrow_menu": createWidgetHandler( { steps: "listPairs" }, (text, attrs) => { const nav = document.createElement("nav"); nav.classList.add("widget","arrow-menu"); const ol = document.createElement("ol"); nav.appendChild(ol); if (attrs.steps) { attrs.steps.forEach(({ title, href }, index) => { const li = document.createElement("li"); // Create a wrapper (anchor or span) to hold the entire arrow const wrapper = href ? document.createElement("a") : document.createElement("span"); if (href) wrapper.href = href; wrapper.classList.add("arrow-step"); // Tail (skip first) if (index > 0) { const tail = document.createElementNS("http://www.w3.org/2000/svg", "svg"); tail.setAttribute("viewBox", "0 0 1 1"); ("viewBox", "0 0 1 1"); tail.classList.add("arrow-tail") const useTail = document.createElementNS("http://www.w3.org/2000/svg", "use"); useTail.setAttribute("href", "#svg_arrow_tail"); tail.appendChild(useTail); wrapper.appendChild(tail); } // Label const label = document.createElement("span"); label.classList.add("arrow-label"); label.textContent = title; wrapper.appendChild(label); // Head (always present) const head = document.createElementNS("http://www.w3.org/2000/svg", "svg"); head.setAttribute("viewBox", "0 0 1 1"); head.classList.add("arrow-head") const useHead = document.createElementNS("http://www.w3.org/2000/svg", "use"); useHead.setAttribute("href", "#svg_arrow_head"); head.appendChild(useHead); wrapper.appendChild(head); li.appendChild(wrapper); ol.appendChild(li); }); } return nav; } ), "homepage": createWidgetHandler( { image: "image", overlay_strength: "string" }, (text, attrs) => { homepageOverwrite = true if (attrs.image) { homepageImage = attrs.image } if (attrs.overlay_strength) { homepageOverlayStrength = attrs.overlay_strength } } ), "pages": createWidgetHandler( { previous: "button", // → [label, href] current: "button", next: "button" }, (text, attrs) => { const safeLabel = (label) => label?.trim() || "​"; const safeHref = (href) => href?.trim() || "#"; const isVisible = (label) => label && label.trim() !== ""; const prevLabel = safeLabel(attrs.previous?.label); const currLabel = safeLabel(attrs.current?.label); const nextLabel = safeLabel(attrs.next?.label); const prevHref = safeHref(attrs.previous?.href); const currHref = safeHref(attrs.current?.href); const nextHref = safeHref(attrs.next?.href); pagesNavElement = document.createElement("nav"); pagesNavElement.classList.add("pages-nav"); pagesNavElement.setAttribute("role", "navigation"); pagesNavElement.setAttribute("aria-label", "Page navigation"); pagesNavElement.innerHTML = ` ${isVisible(prevLabel) ? `${prevLabel}` : ""} ${isVisible(prevLabel) ? `<` : ""} ${isVisible(currLabel) ? `${currLabel}` : ""} ${isVisible(nextLabel) ? `>` : ""} ${isVisible(nextLabel) ? `${nextLabel}` : ""} `; } ) } // Restructure Widgets function restructureWidget(widget) { if (widget === h1) { const container = h1.querySelector("div.container"); const titleText = container?.childNodes[0]?.textContent?.trim() || ""; const subText = container?.querySelector("div.sub")?.textContent?.trim(); const fragment = document.createDocumentFragment(); // title (always) const title = document.createElement("h1"); title.innerText = titleText; fragment.appendChild(title); // subtitle (only if non-empty) if (subText) { const subtitle = document.createElement("h2"); subtitle.innerText = subText; fragment.appendChild(subtitle); } return fragment; } if (widget.classList.contains("picture-hero")) { const figure = document.createElement("figure"); const img = widget.querySelector("img"); const newImg = document.createElement("img"); newImg.src = img.src; newImg.alt = img.alt || ""; figure.appendChild(newImg); figure.id = "hero_image"; return figure; } if (widget.classList.contains("static_citation")) { const quoteSpan = widget.querySelector("h3 span"); if (quoteSpan) { const rawText = quoteSpan.innerText.trim(); const { keyword, attrs } = parseWidgetKeyword(rawText); if (keyword && widgetHandlers[keyword]) { return widgetHandlers[keyword](rawText, attrs); } else { // Fallback: treat it as a regular quote block const blockquote = document.createElement("blockquote"); blockquote.classList.add("widget", "static_citation"); blockquote.innerHTML = `

                    ${rawText}

                    `; return blockquote; } } } if (widget.classList.contains("program_related_programs_table")) { /* -------------------------------------------------- 1. BASIC SET-UP -------------------------------------------------- */ const originalDesktop = widget.querySelector(".desktop"); if (!originalDesktop) return; const desktopTable = originalDesktop.querySelector("table"); if (!desktopTable) return; /* Header → column index map ------------------------ */ const columnMap = {}; Array.from(desktopTable.querySelectorAll("thead th")).forEach((th, i) => { const txt = th.textContent.toLowerCase().trim(); if (txt.includes("land")) columnMap.country = i; else if (txt.includes("program")) columnMap.program = i; else if (txt.includes("duur") && !("duration" in columnMap)) columnMap.duration = i; else if (txt.includes("thema")) columnMap.theme = i; else if (txt.includes("leeftijd")) columnMap.age = i; else if (txt.includes("prijs")) columnMap.price = i; else if (txt.includes("begin")) columnMap.begin = i; else if (txt === "") columnMap.status = i; }); const rows = Array.from(desktopTable.querySelectorAll("tbody tr")); const SHOW_LIMIT = 7; let showAll = false; /* DOM scaffolding ---------------------------------- */ const div = document.createElement("div"); div.classList.add("widget", "program_related_programs_table"); const filtersContainer = document.createElement("div"); filtersContainer.classList.add("filters-container"); const newDesktop = document.createElement("div"); newDesktop.classList.add("desktop"); const newMobile = document.createElement("div"); newMobile.classList.add("mobile", "container"); /* “See all results” button ------------------------- */ const seeAllBtn = document.createElement("button"); seeAllBtn.innerHTML = "

                    Bekijk alle resultaten

                    "; seeAllBtn.className = "see-all-button"; seeAllBtn.style.display = "none"; seeAllBtn.addEventListener("click", () => { showAll = true; updateTables(); }); /* -------------------------------------------------- 2. HELPERS -------------------------------------------------- */ const filterElements = {}; function addFilterListeners(el) { ["input", "change"].forEach(evt => el.addEventListener(evt, () => { showAll = false; updateTables(); }) ); } function getUniqueOptions(idx) { return [...new Set( rows .filter(r => !r.classList.contains("group")) .map(r => r.children[idx]?.textContent.trim()) .filter(Boolean) )].sort(); } function createCheckboxGroup(name, options, labelText) { const wrap = document.createElement("details"); wrap.className = `checkbox-group ${name}`; const summary = document.createElement("summary"); summary.innerHTML = ` ${labelText || name.charAt(0).toUpperCase() + name.slice(1)}`; wrap.appendChild(summary); options.forEach(opt => { const id = `${name}-${opt}`; const row = document.createElement("div"); const chk = document.createElement("input"); chk.type = "checkbox"; chk.id = id; chk.name = name; chk.value = opt; const lbl = document.createElement("label"); lbl.htmlFor = id; lbl.textContent = opt; row.appendChild(chk); row.appendChild(lbl); wrap.appendChild(row); }); addFilterListeners(wrap); return wrap; } function extractAgesFromText(t) { const m = t.match(/(\d{1,2})\D+(\d{1,2})/); if (!m) return []; const a = +m[1], b = +m[2]; if (isNaN(a) || isNaN(b) || a > b) return []; return Array.from({ length: b - a + 1 }, (_, i) => a + i); } function getAllAges(idx) { const set = new Set(); rows.forEach(r => { if (r.classList.contains("group")) return; extractAgesFromText(r.children[idx]?.textContent.trim() || "") .forEach(a => set.add(a)); }); return [...set].sort((a, b) => a - b); } /* -------------------------------------------------- 3. STANDARD FILTERS --------------------------------------------------*/ const labelMap = { country: "Land", program: "Programma", duration: "Duur", theme: "Thema", begin: "Begin", age: "Leeftijd", price: "Prijs", status: "Status", language: "Taal" }; Object.entries(columnMap).forEach(([name, idx]) => { if (name === "price") return; if (name === "age") { const ages = getAllAges(idx); if (ages.length) { const grp = createCheckboxGroup("age", ages, labelMap.age); filtersContainer.appendChild(grp); filterElements.age = grp; } return; } // Get the unique options once you've skipped “age” const opts = getUniqueOptions(idx); if (!opts.length) return; // Use the Dutch label from labelMap const grp = createCheckboxGroup(name, opts, labelMap[name]); filtersContainer.appendChild(grp); filterElements[name] = grp; }); /* Price range -------------------------------------- */ ["price"].forEach(key => { const from = document.createElement("input"); const to = document.createElement("input"); from.type = to.type = "number"; from.placeholder = "Prijs van"; to.placeholder = "Prijs tot"; addFilterListeners(from); addFilterListeners(to); filtersContainer.appendChild(from); filtersContainer.appendChild(to); filterElements[`${key}From`] = from; filterElements[`${key}To`] = to; }); /* -------------------------------------------------- 4. LANGUAGE MAPPING (Dutch names, multi-language) – extend or adjust as needed -------------------------------------------------- */ const languageToCountries = { Nederlands: ["Nederland", "Suriname", "Aruba", "Curaçao"], Engels: ["Australië", "Canada", "Ierland", "Verenigde Staten", "Verenigd Koninkrijk", "Zuid-Afrika", "Nieuw-Zeeland", "India", "Ghana", "Botswana", "Kenya", "Liberia"], Frans: ["Frankrijk", "België", "Canada", "Zwitserland", "Luxemburg", "Marokko", "Tunesië", "Algerije", "Senegal", "Ivoorkust"], Duits: ["Duitsland", "Oostenrijk", "Zwitserland", "Luxemburg"], Spaans: ["Argentinië", "Spanje", "Mexico", "Colombia", "Chili", "Peru", "Uruguay", "Paraguay", "Ecuador", "Bolivia", "Costa Rica", "Dominicaanse Republiek", "El Salvador", "Guatemala", "Honduras", "Nicaragua", "Panama", "Venezuela"], Portugees: ["Brazilië", "Portugal", "Angola", "Mozambique"], Italiaans: ["Italië", "Zwitserland"], Deens: ["Denemarken"], Noors: ["Noorwegen"], Zweeds: ["Zweden"], Fins: ["Finland"], Ests: ["Estland"], Lets: ["Letland"], Litouws: ["Litouwen"], Pools: ["Polen"], Hongaars: ["Hongarije"], Bulgaars: ["Bulgarije"], Roemeens: ["Roemenië", "Moldavië"], Tsjechisch: ["Tsjechië"], Slowaaks: ["Slowakije"], Servisch: ["Servië", "Kosovo"], Kroatisch: ["Kroatië", "Bosnië en Herzegovina"], Sloveens: ["Slovenië"], Grieks: ["Griekenland"], Russisch: ["Rusland", "Wit-Rusland", "Kazachstan", "Kirgizië", "Tadzjikistan"], Oekraïens: ["Oekraïne"], Kazachs: ["Kazachstan"], Azerbeidzjaans: ["Azerbeidzjan"], Armeens: ["Armenië"], Georgisch: ["Georgië"], Oezbeeks: ["Oezbekistan"], Tadzjieks: ["Tadzjikistan"], Mongools: ["Mongolië"], Arabisch: ["Egypte", "Marokko", "Tunesië", "Algerije", "Saoedi-Arabië", "Jordanië", "Libanon", "Libië", "Palestijnse gebieden", "Qatar", "Verenigde Arabische Emiraten", "Bahrein", "Koeweit", "Oman", "Jemen"], Chinees: ["China", "Taiwan", "Singapore"], Japans: ["Japan"], Koreaans: ["Zuid-Korea"], Thais: ["Thailand"], Vietnamees: ["Vietnam"], Indonesisch: ["Indonesië"], Bengaals: ["Bangladesh"], Hindi: ["India"], Urdu: ["Pakistan"], Swahili: ["Tanzania"], Turks: ["Turkije"], }; /* Build language filter with only *represented* languages */ (function buildLanguageFilter() { const countriesInTable = getUniqueOptions(columnMap.country); const representedLangs = Object.keys(languageToCountries).filter(lang => languageToCountries[lang].some(c => countriesInTable.includes(c)) ); if (!representedLangs.length) return; // nothing to show const langGroup = createCheckboxGroup("language", representedLangs.sort(), "Taal"); if (filterElements.country) { /* ⬅️ put Language directly after the Country group */ filterElements.country.after(langGroup); } else { /* fallback, should never happen */ filtersContainer.appendChild(langGroup); } filterElements.language = langGroup; })(); /* -------------------------------------------------- 5. FILTER LOGIC -------------------------------------------------- */ function matchesFilters(row) { if (row.classList.contains("group")) return true; const country = row.children[columnMap.country]?.textContent.trim(); /* Language */ if (filterElements.language) { const selLangs = [...filterElements.language.querySelectorAll("input:checked")].map(i => i.value); if (selLangs.length) { const validCountries = new Set(); selLangs.forEach(l => (languageToCountries[l] || []).forEach(c => validCountries.add(c))); if (!validCountries.has(country)) return false; } } /* Other filters */ return Object.entries(columnMap).every(([name, idx]) => { const val = row.children[idx]?.textContent.trim() || ""; if (name === "price") { const num = +(val.match(/\d+/) || [null])[0]; const min = +filterElements.priceFrom?.value || -Infinity; const max = +filterElements.priceTo?.value || Infinity; return isNaN(num) || (num >= min && num <= max); } if (name === "age") { const selected = [...filterElements.age?.querySelectorAll("input:checked") || []].map(i => +i.value); if (!selected.length) return true; return extractAgesFromText(val).some(a => selected.includes(a)); } const checked = [...filterElements[name]?.querySelectorAll("input:checked") || []].map(i => i.value); return !checked.length || checked.includes(val); }); } /* -------------------------------------------------- 6. TABLE BUILDERS (limit aware) -------------------------------------------------- */ function buildDesktopTable(filtered, limit = Infinity) { const table = desktopTable.cloneNode(true); const tbody = table.querySelector("tbody"); tbody.innerHTML = ""; let count = 0; filtered.forEach(r => { if (count >= limit) return; if (r.classList.contains("group")) return; tbody.appendChild(r.cloneNode(true)); count++; const next = rows[rows.indexOf(r) + 1]; if (next?.classList.contains("group")) tbody.appendChild(next.cloneNode(true)); }); return table; } function buildMobileTable(filtered, limit = Infinity) { const cont = document.createElement("div"); let count = 0; filtered.forEach(r => { if (count >= limit) return; if (r.classList.contains("group")) return; const cells = [...r.children]; const details = document.createElement("details"); const summary = document.createElement("summary"); summary.innerHTML = ` ${[cells[columnMap.country]?.textContent, cells[columnMap.duration]?.textContent, cells[columnMap.begin]?.textContent, cells[columnMap.theme]?.textContent].filter(Boolean).join(", ")}` // [ // cells[columnMap.country]?.textContent, // cells[columnMap.duration]?.textContent, // cells[columnMap.begin]?.textContent, // cells[columnMap.theme]?.textContent // ].filter(Boolean).join(", "); details.appendChild(summary); const tbl = document.createElement("table"); const tb = document.createElement("tbody"); Object.entries(columnMap).forEach(([n, idx]) => { const tr = document.createElement("tr"); tr.innerHTML = `${n.charAt(0).toUpperCase() + n.slice(1)}${cells[idx]?.textContent || ""}`; tb.appendChild(tr); }); tbl.appendChild(tb); details.appendChild(tbl); cont.appendChild(details); count++; }); return cont; } /* -------------------------------------------------- 7. UPDATE TABLES -------------------------------------------------- */ function updateTables() { const filtered = rows.filter(matchesFilters); const limit = showAll ? Infinity : SHOW_LIMIT; newDesktop.innerHTML = ""; newDesktop.appendChild(buildDesktopTable(filtered, limit)); newMobile.innerHTML = ""; newMobile.appendChild(buildMobileTable(filtered, limit)); seeAllBtn.style.display = !showAll && filtered.length > SHOW_LIMIT ? "grid" : "none"; } /* Clear filters */ const clearBtn = document.createElement("button"); clearBtn.textContent = "Filters wissen"; clearBtn.className = "clear-filters"; clearBtn.addEventListener("click", () => { Object.entries(filterElements).forEach(([k, el]) => { if (k.endsWith("From") || k.endsWith("To")) { el.value = ""; return; } [...el.querySelectorAll("input[type='checkbox']")].forEach(c => (c.checked = false)); }); showAll = false; updateTables(); }); filtersContainer.appendChild(clearBtn); /* -------------------------------------------------- 8. INIT -------------------------------------------------- */ updateTables(); div.appendChild(filtersContainer); div.appendChild(newDesktop); div.appendChild(newMobile); div.appendChild(seeAllBtn); return div; } if (widget.classList.contains("program_related_featured_countries_and_programs")) { const rawCountries = widget.querySelectorAll(".country-page") const div = document.createElement("div") div.classList.add("widget", "program_related_featured_countries_and_programs") rawCountries.forEach (country => { if (country.querySelector(".title") && country.querySelector("img") && country.querySelector("table")) { const container = document.createElement("a") container.classList = "program" container.href = country.href const header = document.createElement("h3") header.textContent = country.querySelector(".title").textContent const image = country.querySelector("img") const table = country.querySelector("table").cloneNode(true) const newReadMore = document.createElement("a") newReadMore.classList = "button" newReadMore.textContent = country.querySelector(".read-more").textContent newReadMore.href = country.href container.appendChild(header) container.appendChild(image) container.appendChild(table) container.appendChild(newReadMore) div.appendChild(container) } }); return div } if (widget.classList.contains("static_rich_text")) { const output = document.createElement("div"); output.classList.add("widget", "static_rich_text", ...widget.classList); // Remove the original `.container` wrapper const container = widget.querySelector(".container") || widget; // Helper to downgrade headings function downgradeHeadings(el) { el.querySelectorAll("h2, h3").forEach(header => { const newTag = document.createElement(header.tagName === "H2" ? "h3" : "h4"); newTag.innerHTML = header.innerHTML; output.appendChild(newTag); }); } // Helper to process and clean paragraphs function processParagraphContent(html) { const splitContent = html.split(/\s*/i); return splitContent.map(fragment => { const p = document.createElement("p"); p.innerHTML = fragment.trim(); return p; }); } // Downgrade headers and add them to output downgradeHeadings(container); // Gather all text content (excluding nested widgets like columns/buttons) container.querySelectorAll("p").forEach(p => { const cleaned = p.cloneNode(true); // Remove inline styles and empty tags cleaned.removeAttribute("style"); if (!cleaned.innerHTML.trim()) return; const processedParas = processParagraphContent(cleaned.innerHTML); processedParas.forEach(p => output.appendChild(p)); }); // Include any standalone buttons or links that should remain const buttons = container.querySelectorAll("a.button"); buttons.forEach(btn => { const clone = btn.cloneNode(true); output.appendChild(clone); }); return output; } if (widget.classList.contains("static_picture")) { const figure = document.createElement("figure"); figure.classList.add("widget", "static_picture"); const img = widget.querySelector("img"); const caption = widget.querySelector(".caption"); if (img) { const newImg = document.createElement("img"); newImg.src = img.src; newImg.alt = caption || ""; if (img.className) newImg.className = img.className; figure.appendChild(newImg); } if (caption) { const figcaption = document.createElement("figcaption"); figcaption.innerText = caption.innerText.trim(); figure.appendChild(figcaption); } return figure; } if (widget.classList.contains("static_picture_gallery")) { const slider = widget.querySelector(".image-slider"); const images = slider.querySelectorAll("ul.images li"); const captionText = slider.querySelector(".caption")?.innerText || ""; // Create a scrollable container const scrollContainer = document.createElement("div"); scrollContainer.classList.add("carousel-scroll-container"); scrollContainer.setAttribute("role", "region"); scrollContainer.setAttribute("aria-label", "Image gallery"); images.forEach((li) => { const figure = document.createElement("figure"); figure.classList.add("carousel-slide"); const img = document.createElement("img"); const bgUrl = li.style.backgroundImage.match(/url\(["']?(.*?)["']?\)/); img.src = bgUrl ? bgUrl[1] : ""; img.alt = li.dataset.caption || captionText || ""; figure.appendChild(img); if (li.dataset.caption) { const figcaption = document.createElement("figcaption"); figcaption.textContent = li.dataset.caption.trim(); figure.appendChild(figcaption); } scrollContainer.appendChild(figure); }); // Replace old content widget.innerHTML = ""; widget.appendChild(scrollContainer); } if (widget.classList.contains("static_image_and_text")) { const container = widget.querySelector(".container"); if (!container) return; const heading = container.querySelector("h2"); const textContent = container.querySelector(".content"); const img = container.querySelector("img"); const layout = ["top", "right", "bottom", "left"].find(dir => container.classList.contains(dir)) || "left"; const shape = container.classList.contains("circle") ? "circle" : "rectangle"; const wrapper = document.createElement("div"); wrapper.classList.add("widget", "static_image_and_text", `text-${layout}`, `shape-${shape}`); // Create image element const newImg = document.createElement("img"); newImg.src = img?.src || ""; newImg.alt = img?.alt || ""; // ensure accessibility newImg.classList.add("image"); wrapper.appendChild(newImg); // Create text content const textDiv = document.createElement("div"); textDiv.classList.add("text-content"); if (heading) { const newHeading = document.createElement("h3"); newHeading.textContent = heading.textContent; textDiv.appendChild(newHeading); } if (textContent) { [...textContent.childNodes].forEach(node => { if (node !== heading) { textDiv.appendChild(node.cloneNode(true)); } }); } wrapper.appendChild(textDiv); return wrapper; } if (widget.classList.contains("static_image_and_table")) { const container = widget.querySelector(".container"); if (!container) return; const heading = container.querySelector("h2"); const textContent = container.querySelector(".content"); const img = container.querySelector("img"); const layout = ["top", "right", "bottom", "left"].find(dir => container.classList.contains(dir)) || "left"; const shape = container.classList.contains("circle") ? "circle" : "rectangle"; const wrapper = document.createElement("div"); wrapper.classList.add("widget", "static_image_and_table", `text-${layout}`, `shape-${shape}`); // Create image element const newImg = document.createElement("img"); newImg.src = img?.src || ""; newImg.alt = img?.alt || ""; // ensure accessibility newImg.classList.add("image"); wrapper.appendChild(newImg); // Create text content const textDiv = document.createElement("div"); textDiv.classList.add("text-content"); if (heading) { const newHeading = document.createElement("h3"); newHeading.textContent = heading.textContent; textDiv.appendChild(newHeading); } if (textContent) { [...textContent.childNodes].forEach(node => { if (node !== heading) { textDiv.appendChild(node.cloneNode(true)); } }); } wrapper.appendChild(textDiv); return wrapper; } if (widget.classList.contains("static_youtube_video")) { const iframe = widget.querySelector("iframe"); if (iframe) { iframe.removeAttribute("width"); iframe.removeAttribute("height"); iframe.removeAttribute("frameborder"); iframe.setAttribute("allow", "encrypted-media; picture-in-picture"); iframe.setAttribute("allowfullscreen", ""); iframe.setAttribute("loading", "lazy"); } } if (widget.classList.contains("static_collapsable_text")) { // Extract dynamic title and content const title = widget.querySelector(".headline .text")?.textContent?.trim() || "Untitled"; const contentHTML = widget.querySelector(".content")?.innerHTML || ""; // Create new widget wrapper const wrapper = document.createElement("div"); wrapper.classList.add("widget", "static_collapsible_text"); // Create
                    structure const details = document.createElement("details"); // Create with text and icon const summary = document.createElement("summary"); summary.innerHTML = ` ${title} `; // Create content container const content = document.createElement("div"); content.classList.add("collapsible-content"); content.innerHTML = contentHTML; // Assemble and return details.appendChild(summary); details.appendChild(content); wrapper.appendChild(details); return wrapper; } return widget.cloneNode(true); } function createArcSvg(section) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute('aria-hidden', 'true'); svg.setAttribute('focusable', 'false'); const use = document.createElementNS("http://www.w3.org/2000/svg", "use"); use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#svg_header_arc'); svg.appendChild(use); const colorClass = [...section.classList].find(cls => cls.startsWith('section-color_')); svg.classList.add(colorClass || 'section-color_none', 'section-arc'); return svg; } // 2) BUILD SECTIONS + TOC const newSections = []; const tocItems = []; let currentSection = null; let sectionCounter = 1; let lastColorIsPrimary = true; // Hero + h1/subtitle const firstSection = document.createElement("section"); firstSection.id = "hero_section"; firstSection.classList.add("section-color_base"); if (hero) firstSection.appendChild(restructureWidget(hero)); if (h1) firstSection.appendChild(restructureWidget(h1)); if (firstSection.children.length) newSections.push(firstSection); for (const el of rawWidgets) { if (isSectionMarker(el)) { const txt = el.querySelector("span")?.textContent || ""; const nameMatch = txt.match(/name\s*=\s*"([^"]*)"/i); const colorMatch = txt.match(/color\s*=\s*"([^"]*)"/i); const nameVal = nameMatch?.[1]?.trim(); const colorVal = colorMatch?.[1]?.trim(); let idString = sectionCounter++ if (nameVal) { idString = nameVal.replace(/ /g, "_"); } const section = document.createElement("section"); section.id = `section_${idString}`; const mapped = mapColorToClass(colorVal); if (mapped) { section.classList.add(mapped); lastColorIsPrimary = false; } else { const alt = lastColorIsPrimary ? "section-color_primary" : "section-color_base"; section.classList.add(alt); lastColorIsPrimary = !lastColorIsPrimary; } if (nameVal) { const title = document.createElement("h2"); title.innerText = nameVal; section.appendChild(title); tocItems.push({ id: section.id, name: nameVal }); } currentSection = section; newSections.push(section); continue; } // // Default: append processed widget to section const target = currentSection || firstSection; const processed = restructureWidget(el); if (processed) target.appendChild(processed); } // INSERT TOC under h1/subtitle if (tocItems.length >= 2) { const h1 = firstSection.querySelector("h1"); const h2 = firstSection.querySelector("h2"); if (h1) { const nav = document.createElement("nav"); nav.classList.add("table-of-contents"); const header = document.createElement("h2"); header.innerText = "Inhoud:"; nav.appendChild(header); const ol = document.createElement("ol"); tocItems.forEach(({ id, name }) => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = `#${id}`; a.innerText = name; li.appendChild(a); ol.appendChild(li); }); nav.appendChild(ol); if (h2) { const description = document.createElement("div") description.classList.add("table-of-contents-description") const descriptionText = document.createElement("div") descriptionText.innerHTML = `

                    ${h2.innerText}

                    ` h2.remove() description.appendChild(nav) h1.insertAdjacentElement("afterend", description); description.appendChild(descriptionText) } else { h1.insertAdjacentElement("afterend", nav); } } } // replace
                    content main.innerHTML = ""; newSections.forEach(section => { if (section.children.length) { section.appendChild(createArcSvg(section)); main.appendChild(section); } }); if (firstSection && homepageOverwrite) { firstSection.innerHTML = `
                    YOUTH FOR UNDERSTANDING Interculturele Uitwissilingen
                    ` } if (pagesNavElement && document.querySelector(".main-nav")) { document.querySelector(".main-nav").insertAdjacentElement('afterend', pagesNavElement); }; // Rail dots // 3) INJECT PROGRESS RAIL PLACEHOLDER if (tocItems.length >= 2) { const rail = document.createElement("nav"); rail.id = "progress-rail"; // styling via CSS; here only structural const fill = document.createElement("div"); fill.id = "progress-fill"; rail.appendChild(fill); // empty dots for each named section tocItems.forEach(({ id, name }) => { const dot = document.createElement("a"); dot.className = "rail-dot"; dot.href = `#${id}`; dot.dataset.section = id; dot.dataset.requireHover = ""; rail.appendChild(dot); const label = document.createElement("span"); label.innerText = `${name}`; label.ariaHidden = true; dot.appendChild(label) }); document.body.appendChild(rail); } }), // 4) ONCE EVERYTHING IS LOADED → POSITION DOTS & HOOK SCROLL window.addEventListener("load", () => { const dots = document.querySelectorAll(".rail-dot"); if (!dots.length) return; const docHeight = document.documentElement.scrollHeight - window.innerHeight; const fill = document.getElementById("progress-fill"); dots.forEach(dot => { const id = dot.dataset.section; const sec = document.getElementById(id); if (!sec) return; const topPx = sec.getBoundingClientRect().top + window.scrollY; dot.style.top = `${(topPx / docHeight) * 100}%`; dot.addEventListener("click", e => { e.preventDefault(); sec.scrollIntoView({ behavior: "smooth" }); }); }); const updateFill = () => { const pct = Math.min((window.scrollY / docHeight) * 100, 100); fill.style.height = pct + "%"; }; window.addEventListener("scroll", updateFill); updateFill(); }); function matchSvgTextSize() { const remRef = document.querySelector("#nav_pages_size_reference"); const svg = document.querySelector(".nav-pages-text"); const svgText = svg.querySelector("text"); if (!remRef || !svg || !svgText) return; const remPx = parseFloat(getComputedStyle(remRef).fontSize); // e.g. 40px const svgHeightPx = svg.getBoundingClientRect().height; const viewBoxHeight = parseFloat(svg.getAttribute("viewBox").split(" ")[3]); if (svgHeightPx && viewBoxHeight) { const correctedFontSize = (remPx * viewBoxHeight) / svgHeightPx; svgText.setAttribute("font-size", correctedFontSize); } } // Run on load and resize document.addEventListener("DOMContentLoaded", matchSvgTextSize); window.addEventListener("resize", matchSvgTextSize); // Ensure page is visible after processing const observer = new MutationObserver((mutations, obs) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if ( node.tagName === 'LINK' && node.getAttribute('rel') === 'stylesheet' ) { const href = node.getAttribute('href'); if ( href && ( href.includes('/assets/') || href.includes('/Bouwplaats 3 - Testing_files/') || href.includes('about') ) && href.endsWith('.css') ) { node.remove(); obs.disconnect(); // Stop observing after removal return; } } } } }); // Start observing the whole document for new elements observer.observe(document.documentElement, { childList: true, subtree: true }); function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } function updateArcHeights() { const svgs = document.querySelectorAll('.section-arc'); svgs.forEach(svg => { const rect = svg.getBoundingClientRect(); const top = rect.top; const start = window.innerHeight * 0.4; // 80% viewport height const end = window.innerHeight * 0.2; // 20% viewport height if (top <= start && top >= end) { // Normalize between 0 and 1 const progress = (start - top) / (start - end); const clampedProgress = clamp(progress, 0, 1); // Interpolate between 10rem and 0rem const maxHeightRem = 10; const newHeightRem = maxHeightRem * (1 - clampedProgress); svg.style.height = `${newHeightRem}rem`; } else if (top > start) { svg.style.height = `10rem`; } else if (top < end) { svg.style.height = `0rem`; } }); } window.addEventListener('scroll', updateArcHeights); window.addEventListener('resize', updateArcHeights); // Initial call to set heights correctly updateArcHeights(); // -------------------- document.addEventListener("DOMContentLoaded", () => { const nav = document.querySelector('nav'); const pagesNav = document.querySelector(".pages-nav") const brand = document.querySelector('.nav-brand'); const icons = document.querySelector('.nav-icons'); let isShrunk = false; function forceReflow(el) { void el.offsetWidth; // Forces layout reflow } function animateTransition(shrinking) { brand.classList.remove('animate-fly'); icons.classList.remove('animate-fly'); forceReflow(brand); // Ensure animations restart cleanly forceReflow(icons); brand.classList.add('animate-fly'); icons.classList.add('animate-fly'); if (pagesNav) { if (shrinking) { pagesNav.classList.add('shrink'); } else { pagesNav.classList.remove('shrink'); } } // Delay the class change (layout change) to AFTER 0.5s setTimeout(() => { if (shrinking) { nav.classList.add('shrink'); } else { nav.classList.remove('shrink'); } }, 500); } window.addEventListener('scroll', () => { const shouldShrink = window.scrollY > 1; if (shouldShrink && !isShrunk) { animateTransition(true); isShrunk = true; } else if (!shouldShrink && isShrunk) { animateTransition(false); isShrunk = false; } }); }); document.addEventListener("DOMContentLoaded", () => { const arcPath = document.querySelector('#svg_nav_pages_arc'); const arcDraw = document.querySelector(".nav-pages-arc"); window.addEventListener('scroll', () => { const isScrolled = window.scrollY > 1; // Animate the arc path itself gsap.to(arcPath, { delay: 0.55, duration: 0.5, attr: { d: isScrolled ? "M 0,15 C 32,15 66,15 100,15 134,15 168,15 200,15" // Flattened : "M 0,15 C 32,25 66,30 100,30 134,30 168,25 200,15" // Original curve }, ease: "ease" }); }); }); // 2 Tap Tooltips for Mobile (function () { const isTouchDevice = matchMedia('(hover: none) and (pointer: coarse)').matches; if (!isTouchDevice) return; let activeEl = null; document.addEventListener('click', function (e) { const el = e.target.closest('[data-require-hover]'); // If clicking somewhere else, remove active state if (activeEl && el !== activeEl) { activeEl.classList.remove('hover-active'); activeEl = null; } // If the clicked element does not require hover, do nothing else if (!el) return; // If it’s the first tap, activate hover and block action if (el !== activeEl) { e.preventDefault(); e.stopImmediatePropagation(); el.classList.add('hover-active'); activeEl = el; } else { // Second tap on the same element — allow action, remove hover el.classList.remove('hover-active'); activeEl = null; } }, true); // Use capture to block native handlers })(); -->