/** * pc-live | Browser App * IC URL schema: ic://slug */ const BrowserApp = (() => { const WIN_ID = 'app-browser'; const history = []; let histIdx = -1; /* ── IC page templates ─────────────────────────────────── */ const PageTemplates = { home: () => `

⚡ IC Browser

Browse the internal network. Enter an ic:// address above.

`, dpa: () => `

📰 DPA – Deutsche Presse-Agentur

New residential district approved in Vinewood Hills

The city council has approved plans for 120 new residential units in the Vinewood Hills area. Construction is set to begin next month pending environmental review.

Port Authority reports record cargo volume

Los Santos Port Authority announced a 14% increase in cargo processing year-over-year, citing improved logistics infrastructure and expanded berth capacity.

Traffic advisory: Freeway 1 maintenance

LSDOT warns of lane closures on Freeway 1 near Palomino Highlands between 22:00 and 06:00 for the next three nights.

`, psb: () => `

🚔 Los Santos Police Service Board

Official information and public notices from the Los Santos Police Department.

Public Safety Campaign – Q1

The LSPD is launching a public outreach campaign focused on traffic safety and community engagement. Residents are encouraged to report suspicious activity through official channels.

LSPD Cadet Applications Open

Applications for the upcoming cadet class are now open. Qualified candidates should contact the department for details on requirements and the application process.

`, weazel: () => `

📺 Weazel News

Los Santos' #1 Trusted News Source

Explosion reported near LSIA

Witnesses report a large explosion near the Los Santos International Airport. LSFD units are on scene. Air traffic has been temporarily halted as a precaution.

Vinewood Music Awards – Full List of Nominees

The annual Vinewood Music Awards nominees have been announced. This year's ceremony will take place at the Maze Bank Arena. Tickets available starting next week.

`, // ── Org pages ──────────────────────────────────────────── org_police: () => `
🚔

Los Santos Police Department

ic://police  ·  pd.gov

📞
Notruf 110
Polizeilicher Notruf
✉️
aktensystem@pd.gov
Offizielles Aktensystem

Strafverfolgung & Öffentliche Sicherheit

Das LSPD ist zuständig für die öffentliche Sicherheit, Strafverfolgung und Verbrechensbekämpfung in Los Santos. Bürger können sich jederzeit an unsere Beamten wenden.

Stellenausschreibung – Cadet Program

Das LSPD nimmt regelmäßig neue Bewerber für das Cadet-Programm an. Kontakt über das offizielle Aktensystem oder persönlich beim Department.

`, org_ambulance: () => `
🚑

Los Santos Medical Department

ic://ambulance  ·  md.gov

📞
Notruf 911
Medizinischer Notfall
✉️
aktensystem@md.gov
Patientenakten & Anfragen

Notfallversorgung rund um die Uhr

Das LSMD bietet medizinische Erstversorgung, Krankentransport und chirurgische Eingriffe. Im Notfall bitte sofort den Notruf 911 wählen.

`, org_fire: () => `
🚒

Los Santos Fire Department

ic://fire  ·  fd.gov

📞
Notruf 112
Feuerwehr & Technische Hilfe
✉️
aktensystem@fd.gov
Offizielle Korrespondenz

Brandbekämpfung & Technische Hilfe

Die LSFD schützt Leben und Eigentum bei Bränden, Unfällen und Naturkatastrophen. Für technische Hilfeleistungen steht das Department rund um die Uhr bereit.

`, org_doj: () => `
⚖️

Department of Justice

ic://doj  ·  doj.gov

📞
Hotline 200
DOJ Auskunft
✉️
aktensystem@doj.gov
Juristische Anfragen

Strafrecht & Zivilrecht in Los Santos

Das Department of Justice verwaltet das Rechtssystem von Los Santos. Anwälte, Richter und Staatsanwälte koordinieren alle rechtlichen Vorgänge über dieses Department.

`, org_dpa: () => `
🏛️

Department of Public Administration

ic://dpa  ·  dpa.gov

✉️
public@dpa.gov
Öffentliche Anfragen
✉️
traffic@dpa.gov
Verkehr & Infrastruktur

Staatliche Verwaltung & Öffentlicher Dienst

Die DPA koordiniert Verwaltungsaufgaben, Genehmigungen und öffentliche Dienstleistungen. Anfragen können per Mail oder telefonisch gestellt werden.

`, org_parking: () => `
🅿️

Parkraumüberwachung Los Santos

ic://parking  ·  parking.gov

✉️
aktensystem@parking.gov
Einsprüche & Anfragen

Knöllchen & Einsprüche

Bei Fragen zu Knöllchen oder Einsprüchen bitte schriftlich über aktensystem@parking.gov oder persönlich am Schalter.

`, classifieds: () => `
📋 LS CLASSIFIEDS
Los Santos' largest private marketplace  ·  ic://classifieds
🚗
Vehicles
47 listings
🏠
Real Estate
23 listings
💼
Jobs
12 listings
🔧
Services
31 listings
⭐ Featured Listings
🚗 FEATURED
2023 Ocelot Pariah
Low mileage, fully tuned at Benny's. Custom matte black wrap. Clean history, no damage.
$285,000
📍 Vinewood  ·  Posted 2h ago
🏍 Vehicles
Western Daemon Custom
Full performance upgrade, custom exhaust. Runs clean. Selling due to relocation.
$68,500
📍 Strawberry  ·  Posted 6h ago
🏠 Real Estate
3-Bed House · Mirror Park
Modern detached house, double garage, pool. Move-in ready. Quiet, well-connected area.
$1,200,000
📍 Mirror Park  ·  Posted 5h ago
💼 Jobs
Mechanic – Premium Auto
Looking for an experienced mechanic. Flexible shifts, good cut. Experience required.
$4,500 / week
📍 LSIA Area  ·  Posted 1d ago
🏢 Real Estate
Penthouse · Alta St.
Floor 28, panoramic city view, 2 bed/2 bath, concierge. Fully furnished, immediate occupancy.
$3,800,000
📍 Downtown LS  ·  Posted 12h ago
🔧 Services
24/7 Mobile Mechanic
On-call repairs, towing, custom builds. Competitive rates. Contact via IC mail.
Contact via mail
📍 Citywide  ·  Posted 3d ago
LS Classifieds is not responsible for the accuracy of listings. All trades are at your own risk.  ·  To post an ad, send a mail to classifieds@ls-net.ic
`, }; /* Fehlerseite für ic-web-Domänen. Als DOM gebaut, weil der Fehlertext vom Server kommt und die Domäne aus der Adressleiste stammt. */ function renderICError(domain, message) { const wrap = document.createElement('div'); wrap.className = 'browser-404 fade-in'; const h = document.createElement('h2'); h.textContent = '404'; const p1 = document.createElement('p'); p1.textContent = 'ic://' + domain; const p2 = document.createElement('p'); p2.textContent = message || 'Diese Adresse existiert nicht.'; wrap.append(h, p1, p2); return wrap; } function render404(slug) { return `

404

Page not found: ic://${slug}

Check the address and try again.

`; } /* ── URL helpers ────────────────────────────────────────── */ function isExternal(url) { return /^https?:\/\//i.test(url); } function normalizeUrl(raw) { raw = (raw || '').trim(); if (!raw) return 'ic://home'; // Already ic:// or http(s):// if (/^ic:\/\//i.test(raw) || /^https?:\/\//i.test(raw)) return raw; // Looks like a domain (contains dot) → assume https if (/^[a-z0-9\-]+\.[a-z]{2,}/i.test(raw)) return 'https://' + raw; // Otherwise treat as ic:// slug return 'ic://' + raw; } /* ── Navigate ─────────────────────────────────────────── */ async function navigate(rawUrl) { if (!rawUrl) return; const url = normalizeUrl(rawUrl); // Update address bar const bar = document.getElementById('browser-address'); if (bar) bar.value = url; // History if (histIdx < 0 || history[histIdx] !== url) { history.splice(histIdx + 1); history.push(url); histIdx = history.length - 1; } updateNavButtons(); const viewport = document.getElementById('browser-viewport'); if (!viewport) return; // ── External URL → iframe ────────────────────────────── if (isExternal(url)) { viewport.classList.add('browser-viewport-external'); viewport.innerHTML = ``; return; } // ── IC internal page ─────────────────────────────────── viewport.classList.remove('browser-viewport-external'); const slug = url.replace(/^ic:\/\//i, '').replace(/\/$/, '').trim() || 'home'; if (bar) bar.value = 'ic://' + slug; viewport.innerHTML = '

Loading…

'; if (PageTemplates[slug]) { viewport.innerHTML = PageTemplates[slug](); return; } // ── Von Spielern gepflegte Seiten (ic-web) ───────────── // Erkennbar an der Domänenform name.endung, optional mit Unterseite. // Vorrang haben die fest eingebauten Vorlagen oben. const parts = slug.split('/'); if (/^[a-z0-9\-]+\.[a-z]{2,}$/i.test(parts[0]) && typeof ICWebNet !== 'undefined') { const res = await ICWebNet.call('getSite', parts[0].toLowerCase(), parts[1] || 'home'); if (res && res.ok && res.data) { // Kein innerHTML: der Inhalt stammt von Spielern und wird als // DOM-Knoten aufgebaut, damit Markup darin niemals ausgeführt wird. viewport.replaceChildren(ICWebRender.renderPage(res.data)); return; } viewport.replaceChildren(renderICError(parts[0], res && res.error)); return; } const resp = await fetchNui('getBrowserPage', { slug }); if (resp && resp.found && resp.page) { const p = resp.page; if (p.content && PageTemplates[p.content]) { viewport.innerHTML = PageTemplates[p.content](); } else { viewport.innerHTML = `

${p.title || slug}

This page has no content yet.

`; } } else { viewport.innerHTML = render404(slug); } } function goBack() { if (histIdx > 0) { histIdx--; navigate(history[histIdx]); } } function goForward() { if (histIdx < history.length - 1) { histIdx++; navigate(history[histIdx]); } } function updateNavButtons() { const b = document.getElementById('browser-back'); const f = document.getElementById('browser-fwd'); if (b) b.style.opacity = histIdx > 0 ? '1' : '0.35'; if (f) f.style.opacity = histIdx < history.length - 1 ? '1' : '0.35'; } /* ── Open window ────────────────────────────────────────── */ function open(startUrl) { const el = WindowManager.create({ id: WIN_ID, title: 'Browser', icon: '🌐', width: 900, height: 600, content: `
`, }); if (!el) return; navigate(startUrl || 'ic://home'); } function refresh() { if (histIdx >= 0) navigate(history[histIdx]); } return { open, navigate, goBack, goForward, refresh }; })();