Lompat ke isi

MediaWiki:Common.js

Dari Mippedia Data, basis data terbuka
Revisi sejak 18 Agustus 2026 00.08 oleh Admin (bicara | kontrib)

Catatan: Setelah menerbitkan, Anda mungkin perlu melewati tembolok peramban web Anda untuk melihat perubahan.

  • Firefox/Safari: Tekan dan tahan Shift sembari mengeklik Reload, atau tekan Ctrl-F5 atau Ctrl-R (⌘-R di Mac)
  • Google Chrome: Tekan Ctrl-Shift-R (⌘-Shift-R di Mac)
  • Edge: Tahan Ctrl sembari mengeklik Refresh, atau tekan Ctrl-F5
/**
 * ====================================================================
 * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 TITANIUM)
 * Fitur: 25+ Fitur Baru, Collapsible References, Direct Link Button,
 * Dark Mode, Toast Notifications, Drag & Drop, Export CSV, Auto-Fill
 * ====================================================================
 */
(function($, mw) {
    'use strict';

    if (mw.config.get('wgNamespaceNumber') !== 0 || mw.config.get('wgIsMainPage')) return;
    if (mw.config.get('wgAction') !== 'view') return;

    mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() {
        
        var pageName = mw.config.get('wgPageName');
        var isSysop = mw.config.get('wgUserGroups').indexOf('sysop') !== -1;
        var dataItems = [];
        var isLocked = false;
        var api = new mw.Api();
        var isDarkMode = localStorage.getItem('md-dark-mode') === 'true';

        // 1. DATA MASTER PLATFORM MEDIA SOSIAL & MUSIK (+5 Baru)
        var SOCIAL_PLATFORMS = {
            applemusic: { name: 'Apple Music', base: 'https://music.apple.com/artist/', color: '#fc3c44', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm3.32 12.383c-.328.232-.82.418-1.32.418-1.238 0-1.922-.828-1.922-2.191v-4.14l4.312-.868v1.398l-2.91.586v2.805c0 .734.336 1.148.977 1.148.336 0 .617-.094.863-.258v1.102z"/></svg>' },
            spotify: { name: 'Spotify', base: 'https://open.spotify.com/artist/', color: '#1db954', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm4.586 14.424c-.18.295-.563.387-.857.207-2.35-1.434-5.308-1.758-8.793-.963-.335.077-.67-.133-.746-.468-.077-.334.132-.67.467-.745 3.816-.87 7.092-.493 9.72 1.112.294.18.386.563.209.857zm1.213-2.71c-.226.368-.703.483-1.07.258-2.688-1.652-6.785-2.13-9.965-1.164-.413.125-.85-.108-.975-.522-.125-.413.108-.85.522-.975 3.633-1.102 8.157-.568 11.23 1.332.368.226.483.703.258 1.071zm.14-2.827c-3.225-1.915-8.54-2.092-11.614-1.16-.503.153-1.037-.133-1.19-.636-.152-.503.133-1.037.636-1.19 3.532-1.072 9.404-.865 13.115 1.338.45.267.598.85.33 1.3-.267.45-.85.598-1.3.33z"/></svg>' },
            soundcloud: { name: 'SoundCloud', base: 'https://soundcloud.com/', color: '#ff5500', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M1.175 12.225c-.062 0-.115.053-.115.116v4.636c0 .062.053.115.115.115h.411c.063 0 .116-.053.116-.115v-4.636c0-.063-.053-.116-.116-.116h-.411zm1.312-1.28c-.062 0-.115.052-.115.115v6.52c0 .063.053.115.115.115h.43c.062 0 .115-.052.115-.115v-6.52c0-.063-.053-.115-.115-.115h-.43zm1.33-1.258c-.063 0-.115.052-.115.115v8.322c0 .063.052.115.115.115h.43c.063 0 .115-.052.115-.115V9.802c0-.063-.052-.115-.115-.115h-.43zm1.33-.86c-.063 0-.115.053-.115.116v9.542c0 .063.052.115.115.115h.43c.063 0 .115-.052.115-.115V8.942c0-.063-.052-.116-.115-.116h-.43zm21.43 3.652c-.413 0-.802.08-1.157.228-.312-2.73-2.613-4.858-5.422-4.858-1.08 0-2.083.315-2.928.858-.2-.702-.592-1.332-1.12-1.826-.78-.727-1.812-1.13-2.882-1.13-.815 0-1.6.236-2.272.684v10.822c0 .063.052.115.115.115h15.666c1.666 0 3.018-1.352 3.018-3.018 0-1.666-1.352-3.018-3.018-3.018z"/></svg>' },
            bandcamp: { name: 'Bandcamp', base: 'https://bandcamp.com/', color: '#1da0c3', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M0 18.75l7.437-13.5H24l-7.438 13.5H0z"/></svg>' },
            instagram: { name: 'Instagram', base: 'https://instagram.com/', color: '#e1306c', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path></svg>' },
            tiktok: { name: 'TikTok', base: 'https://www.tiktok.com/@', color: '#000000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 1 1-5.2-1.74 2.89 2.89 0 0 1 2.31-2.22V8.2a6.34 6.34 0 0 0-5 6.13 6.34 6.34 0 1 0 10.7-4.52A8.25 8.25 0 0 0 20 10.56V6.69z"/></svg>' },
            youtube: { name: 'YouTube', base: 'https://youtube.com/@', color: '#ff0000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"></path><polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"></polygon></svg>' },
            twitter: { name: 'X / Twitter', base: 'https://x.com/', color: '#0f1419', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>' },
            threads: { name: 'Threads', base: 'https://www.threads.net/@', color: '#000000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm3.842 12.338c-.288 1.83-1.85 3.09-3.842 3.09-2.298 0-4.043-1.68-4.043-4.135 0-2.454 1.745-4.134 4.043-4.134 1.583 0 2.875.836 3.447 2.083l-1.28.625c-.39-.817-1.182-1.328-2.167-1.328-1.55 0-2.613 1.15-2.613 2.754 0 1.603 1.063 2.753 2.613 2.753 1.258 0 2.19-.77 2.37-1.808h-2.37v-1.38h3.842v1.48z"/></svg>' },
            facebook: { name: 'Facebook', base: 'https://facebook.com/', color: '#1877f2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg>' },
            linkedin: { name: 'LinkedIn', base: 'https://linkedin.com/in/', color: '#0a66c2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>' },
            github: { name: 'GitHub', base: 'https://github.com/', color: '#24292e', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>' },
            pinterest: { name: 'Pinterest', base: 'https://pinterest.com/', color: '#e60023', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/></svg>' },
            twitch: { name: 'Twitch', base: 'https://twitch.tv/', color: '#9146ff', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z"/></svg>' },
            reddit: { name: 'Reddit', base: 'https://reddit.com/user/', color: '#ff4500', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M24 11.779c0-1.459-1.192-2.645-2.657-2.645-.715 0-1.363.275-1.84.734-1.605-1.056-3.868-1.739-6.38-1.815l1.341-4.218 3.238.683c.038 1.168 1.002 2.1 2.189 2.1 1.212 0 2.193-.984 2.193-2.2s-.981-2.2-2.193-2.2c-1.01 0-1.868.682-2.131 1.606l-3.619-.763c-.156-.033-.311.042-.366.19l-1.547 4.86c-2.61.037-4.978.711-6.643 1.785-.477-.47-1.135-.754-1.861-.754-1.465 0-2.656 1.187-2.656 2.646 0 .97.533 1.811 1.317 2.271-.052.282-.086.567-.086.857 0 3.911 4.808 7.093 10.719 7.093s10.72-3.182 10.72-7.093c0-.274-.029-.544-.075-.81.832-.447 1.405-1.312 1.405-2.318zm-17.224 1.816c0-.868.71-1.575 1.582-1.575.872 0 1.581.707 1.581 1.575s-.709 1.574-1.581 1.574-1.582-.706-1.582-1.574zm9.014 4.597c-1.233 1.234-3.535 1.294-5.068 1.294-1.531 0-3.834-.06-5.068-1.294-.216-.216-.216-.566 0-.783.216-.217.567-.217.784 0 1.019 1.018 3.033 1.109 4.284 1.109 1.253 0 3.266-.09 4.284-1.109.217-.217.568-.217.784 0 .216.217.216.566 0 .783zm.18-2.923c-.872 0-1.582-.706-1.582-1.574 0-.868.71-1.575 1.582-1.575.871 0 1.581.707 1.581 1.575s-.71 1.574-1.581 1.574z"/></svg>' },
            discord: { name: 'Discord', base: 'https://discord.com/users/', color: '#5865f2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189z"/></svg>' },
            wikipedia: { name: 'Wikipedia', base: 'https://id.wikipedia.org/wiki/', color: '#000000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M11.964 1.488C5.467 1.488.2 6.756.2 13.253s5.267 11.765 11.764 11.765 11.765-5.268 11.765-11.765S18.461 1.488 11.964 1.488zm-2.003 18.06l-4.706-9.412h1.412l2.353 5.378 1.954-5.378h1.41l2.42 5.513 2.164-5.513h1.365l-4.47 9.412h-1.554l-1.954-5.464-2.046 5.464h-1.348z"/></svg>' }
        };

        // 2. PRESET TEMPLATES LABEL LENGKAP
        var PRESET_LABELS = [
            "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan", 
            "Kebangsaan", "Genre", "Instrumen", "Label Rekaman", 
            "Tahun Aktif", "Situs Web Resmi", "Pasangan", "Orang Tua", "Agama", "Pendidikan"
        ];

        // 3. MASTER TIPE RUJUKAN
        var REF_TYPES = {
            "Berita": ["Berita Online", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus"],
            "Website": ["Situs Resmi", "Portal Informasi", "Database Web", "Forum Diskusi"],
            "Buku": ["Buku Cetak", "E-Book", "Bab / Bagian Buku", "Monograf"],
            "Jurnal": ["Jurnal Ilmiah Peer-Reviewed", "Paper Konferensi", "Tesis / Disertasi"],
            "Siaran Pers": ["Siaran Pers Resmi", "Pengumuman Instansi / BUMN"],
            "Dokumen PDF": ["Laporan Tahunan / Annual Report", "Dokumen Kebijakan"],
            "Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists"],
            "Video": ["YouTube Video", "Film Dokumenter", "Wawancara Video"],
            "Podcast": ["Episode Podcast", "Siniar Audio Resmi"],
            "Media Sosial": ["Postingan / Tweet", "Video Singkat", "Live Stream"],
            "Ensiklopedia": ["Ensiklopedia Cetak", "Ensiklopedia Online"],
            "Arsip": ["Arsip Nasional", "Web Archive (Wayback Machine)"]
        };

        // 4. IKON SISTEM (SVG)
        var svgEdit = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>';
        var svgLock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>';
        var svgUnlock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>';
        var svgRef = '<svg class="md-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>';
        var svgCopy = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
        var svgSearch = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>';
        var svgCode = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>';
        var svgExternal = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>';
        var svgMoon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>';
        var svgSun = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>';
        var svgDownload = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>';
        var svgClone = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
        var svgDrag = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="cursor:grab; color:#94a3b8;"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>';

        // 5. HELPER UTILITY
        function showToast(msg, type) {
            var bg = type === 'error' ? '#ef4444' : '#10b981';
            var $toast = $('<div style="position:fixed; bottom:20px; right:20px; background:'+bg+'; color:white; padding:12px 20px; border-radius:8px; box-shadow:0 10px 25px rgba(0,0,0,0.2); z-index:9999; font-weight:600; font-size:0.9rem; transform:translateY(100px); opacity:0; transition:all 0.3s ease;">' + msg + '</div>');
            $('body').append($toast);
            setTimeout(function() { $toast.css({transform: 'translateY(0)', opacity: 1}); }, 50);
            setTimeout(function() { $toast.css({transform: 'translateY(100px)', opacity: 0}); setTimeout(function(){ $toast.remove(); }, 300); }, 3000);
        }

        function formatIndonesianDate(dateStr) {
            if (!dateStr) return '';
            var parts = dateStr.split('-');
            if (parts.length !== 3) return dateStr;
            var months = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'];
            var day = parseInt(parts[2], 10);
            var monthIdx = parseInt(parts[1], 10) - 1;
            var year = parts[0];
            if (isNaN(day) || monthIdx < 0 || monthIdx > 11 || isNaN(year)) return dateStr;
            return day + ' ' + months[monthIdx] + ' ' + year;
        }

        function extractDomain(urlStr) {
            try {
                if (!urlStr.match(/^https?:\/\//i)) urlStr = 'https://' + urlStr;
                return new URL(urlStr).hostname.replace(/^www\./, '');
            } catch(e) { return urlStr.replace(/^https?:\/\/(www\.)?/, '').split('/')[0]; }
        }

        function ensureHttps(urlStr) {
            if (!urlStr) return '';
            urlStr = urlStr.trim();
            if (urlStr && !urlStr.match(/^https?:\/\//i)) return 'https://' + urlStr;
            return urlStr;
        }

        function getTodayString() {
            var now = new Date();
            var y = now.getFullYear();
            var m = String(now.getMonth() + 1).padStart(2, '0');
            var d = String(now.getDate()).padStart(2, '0');
            return y + '-' + m + '-' + d;
        }
        
        function toTitleCase(str) {
            return str.replace(/\w\S*/g, function(txt){ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
        }

        function getRefQuality(ref) {
            if (!ref || (!ref.url && !ref.title)) return 0;
            var score = 0;
            if(ref.url) score++; if(ref.title) score++; if(ref.publisher || ref.site) score++;
            if(ref.date) score++; if(ref.author) score++;
            return score;
        }

        // 6. STYLESHEET MODERN V8.0 TITANIUM (Dark Mode Ready & Animations)
        var css = `
            :root {
                --md-bg: #ffffff; --md-surface: #f8fafc; --md-border: #e2e8f0;
                --md-text-main: #0f172a; --md-text-sub: #64748b; --md-primary: #4f46e5;
                --md-primary-hover: #4338ca; --md-shadow: rgba(0,0,0,0.06);
                --md-glass: rgba(255, 255, 255, 0.8);
            }
            .md-dark {
                --md-bg: #1e1e2f; --md-surface: #2a2a40; --md-border: #3b3b5c;
                --md-text-main: #f1f5f9; --md-text-sub: #94a3b8; --md-primary: #6366f1;
                --md-primary-hover: #818cf8; --md-shadow: rgba(0,0,0,0.3);
                --md-glass: rgba(30, 30, 47, 0.8);
            }

            #mippedia-data-app {
                background: var(--md-bg); border-radius: 16px; box-shadow: 0 4px 24px var(--md-shadow);
                padding: 20px; margin: 20px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
                border: 1px solid var(--md-border); max-width: 100%; box-sizing: border-box; overflow: hidden;
                color: var(--md-text-main); transition: background 0.3s, color 0.3s;
            }
            
            /* Sticky Header */
            .md-header {
                display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
                gap: 12px; margin-bottom: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--md-border);
                position: sticky; top: 0; background: var(--md-glass); backdrop-filter: blur(10px); z-index: 10;
            }
            .md-title-container { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 180px; }
            .md-title { font-size: 1.25rem; font-weight: 800; margin: 0; white-space: nowrap; letter-spacing: -0.3px; }
            .md-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
            
            .md-btn-icon {
                background: var(--md-surface); border: 1px solid var(--md-border); cursor: pointer; color: var(--md-primary);
                padding: 8px 12px; border-radius: 8px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
                display: inline-flex; align-items: center; gap: 6px; font-size: 0.8rem; font-weight: 600; white-space: nowrap;
            }
            .md-btn-icon:hover:not(:disabled) { background: var(--md-border); transform: translateY(-2px); box-shadow: 0 4px 10px var(--md-shadow); }

            /* Tab Filters */
            .md-tabs { display: flex; gap: 10px; margin-bottom: 15px; border-bottom: 2px solid var(--md-surface); padding-bottom: 5px; }
            .md-tab { background: none; border: none; font-weight: 700; color: var(--md-text-sub); cursor: pointer; padding: 5px 10px; border-bottom: 2px solid transparent; transition: 0.2s; font-size: 0.85rem;}
            .md-tab.active { color: var(--md-primary); border-bottom-color: var(--md-primary); }
            .md-tab:hover { color: var(--md-primary); }

            .md-search-box { position: relative; margin-bottom: 16px; width: 100%; box-sizing: border-box; }
            .md-search-input {
                width: 100%; padding: 10px 12px 10px 34px; border: 1px solid var(--md-border); border-radius: 8px;
                font-size: 0.9rem; box-sizing: border-box; background: var(--md-surface); color: var(--md-text-main); transition: 0.2s;
            }
            .md-search-input:focus { background: var(--md-bg); border-color: var(--md-primary); outline: none; box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2); }
            .md-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--md-text-sub); }

            /* Row Display & Drag */
            .md-row-display {
                display: flex; justify-content: space-between; align-items: flex-start;
                padding: 14px 12px; border-bottom: 1px solid var(--md-border); transition: all 0.3s;
                border-radius: 12px; gap: 12px; margin-bottom: 8px; background: var(--md-bg);
            }
            .md-row-display.dragging { opacity: 0.5; background: var(--md-surface); }
            .md-row-display:hover { background: var(--md-surface); box-shadow: inset 4px 0 0 var(--md-primary); }
            
            .md-drag-handle { cursor: grab; padding-top: 5px; color: var(--md-text-sub); display:flex; align-items:center;}
            .md-data-group { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
            .md-data-label { font-size: 0.72rem; color: var(--md-text-sub); font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; }
            .md-data-value-wrap { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
            .md-data-value { font-size: 1.05rem; font-weight: 600; word-break: break-word; color: var(--md-text-main); }
            .md-data-value a { color: var(--md-primary); text-decoration: none; }
            .md-data-value a:hover { text-decoration: underline; }

            /* AKORDEON REFERENSI V8.0 */
            .md-ref-container { margin-top: 6px; width: 100%; box-sizing: border-box; }
            .md-ref-toggle {
                background: var(--md-surface); border: 1px solid var(--md-border); padding: 6px 12px; border-radius: 20px;
                font-size: 0.78rem; font-weight: 700; color: var(--md-text-sub); cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
                transition: 0.2s; user-select: none;
            }
            .md-ref-toggle:hover { background: var(--md-border); color: var(--md-primary); }
            .md-ref-toggle.open { background: var(--md-primary); color: white; border-color: var(--md-primary); }
            
            .md-ref-panel {
                display: none; /* Disembunyikan by default */
                background: var(--md-surface); padding: 12px 14px; border-radius: 10px; margin-top: 8px;
                border-left: 4px solid var(--md-primary); font-size: 0.85rem; flex-direction: column; gap: 8px;
                border-top: 1px solid var(--md-border); border-right: 1px solid var(--md-border); border-bottom: 1px solid var(--md-border);
                animation: mdFadeIn 0.3s ease-out;
            }
            @keyframes mdFadeIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } }
            
            .md-ref-header { font-weight: 800; font-size: 0.9rem; color: var(--md-text-main); word-break: break-word; }
            .md-ref-details-grid { display: flex; flex-direction: column; gap: 4px; }
            .md-ref-detail-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; font-size: 0.82rem; }
            .md-ref-lbl { font-weight: 700; color: var(--md-text-sub); white-space: nowrap; flex-shrink: 0; }
            .md-ref-val { color: var(--md-text-main); font-weight: 500; }
            
            .md-ref-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; border-top: 1px dashed var(--md-border); padding-top: 8px; }
            .md-ref-badge { display: inline-block; background: var(--md-border); color: var(--md-text-main); padding: 3px 8px; border-radius: 6px; font-weight: 700; font-size: 0.72rem; }
            .md-btn-direct {
                background: var(--md-primary); color: white !important; text-decoration: none; padding: 5px 12px; border-radius: 6px;
                font-weight: 700; font-size: 0.78rem; display: inline-flex; align-items: center; gap: 5px; transition: 0.2s;
            }
            .md-btn-direct:hover { background: var(--md-primary-hover); transform: scale(1.05); text-decoration: none; }
            .md-q-indicator { display:inline-block; width:8px; height:8px; border-radius:50%; margin-left:5px; }

            /* Media Sosial Badges */
            .md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
            .md-social-badge {
                display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 18px;
                font-size: 0.78rem; font-weight: 600; color: white !important; text-decoration: none; transition: transform 0.2s, opacity 0.2s;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            .md-social-badge:hover { transform: translateY(-2px); opacity: 0.9; text-decoration: none; }

            /* Form Elements */
            .md-form-box { background: var(--md-bg); border-radius: 12px; padding: 18px; margin-top: 16px; border: 1px solid var(--md-border); box-shadow: 0 8px 30px var(--md-shadow); animation: mdFadeIn 0.3s; }
            .md-form-title { font-size: 1.1rem; font-weight: 800; margin: 0 0 16px 0; border-bottom: 2px solid var(--md-border); padding-bottom: 8px; display:flex; justify-content:space-between;}
            .md-form-group { margin-bottom: 14px; position:relative;}
            .md-form-group label { display: block; font-size: 0.82rem; font-weight: 700; margin-bottom: 6px; color: var(--md-text-sub); }
            .md-input, .md-select, .md-textarea {
                width: 100%; padding: 9px 12px; border: 1px solid var(--md-border); border-radius: 8px;
                box-sizing: border-box; font-family: inherit; font-size: 0.9rem; transition: 0.2s; background: var(--md-surface); color: var(--md-text-main);
            }
            .md-input:focus, .md-select:focus, .md-textarea:focus { border-color: var(--md-primary); outline: none; box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15); }
            .md-input.error { border-color: #ef4444; background: #fef2f2; }
            .md-dark .md-input.error { background: #3f1a1a; }
            
            .md-preset-pill { background: var(--md-surface); border: 1px solid var(--md-border); padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; cursor: pointer; transition: 0.2s; display:inline-block; margin:2px;}
            .md-preset-pill:hover { background: var(--md-primary); color:white; border-color:var(--md-primary);}
            
            .md-ref-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: var(--md-surface); padding: 12px; border-radius: 8px; border: 1px dashed var(--md-border); }
            .md-social-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: var(--md-surface); padding: 12px; border-radius: 8px; border: 1px solid var(--md-border); max-height: 280px; overflow-y: auto; }
            .md-grid-full { grid-column: span 2; }
            
            .md-form-actions { display: flex; gap: 10px; align-items: center; margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--md-border); flex-wrap: wrap; }
            .md-btn { padding: 10px 18px; border: none; border-radius: 8px; font-weight: 700; cursor: pointer; color: white; font-size: 0.85rem; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; justify-content: center; }
            .md-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 10px rgba(0,0,0,0.15); }
            .md-btn-save { background: linear-gradient(135deg, #4f46e5, #4338ca); flex: 1; min-width: 140px; }
            .md-btn-cancel { background: #64748b; }
            .md-btn-delete { background: #dc2626; margin-left: auto; }
            
            .md-char-count { position:absolute; right:10px; top:35px; font-size:0.7rem; color:var(--md-text-sub); }

            @media (max-width: 600px) {
                #mippedia-data-app { padding: 14px; margin: 10px 0; border-radius: 12px; }
                .md-header { position: relative; backdrop-filter: none; }
                .md-actions { width: 100%; justify-content: flex-start; overflow-x: auto; padding-bottom: 5px;}
                .md-btn-icon { padding: 7px 10px; font-size: 0.75rem; }
                .md-ref-grid, .md-social-grid { grid-template-columns: 1fr; }
                .md-grid-full { grid-column: span 1; }
                .md-form-actions { flex-direction: column; width: 100%; }
                .md-btn { width: 100%; margin: 0 !important; }
                .md-row-display { padding: 12px 8px; gap: 8px; }
                .md-data-value { font-size: 0.95rem; }
                .md-drag-handle { display:none; } /* Hide drag on mobile to prevent scrolling issues */
            }
            .md-native-render { display: none; }
        `;
        $('<style id="md-styles">').text(css).appendTo('head');
        if(isDarkMode) $('body').addClass('md-dark');

        // 7. PARSER & PENYIMPANAN DATA
        function loadData() {
            return api.get({
                action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main', formatversion: 2
            }).then(function(data) {
                var content = data.query.pages[0].revisions[0].slots.main.content;
                var match = content.match(/<!-- MIPPEDIA_DATA_START \| (.*?) -->/);
                if (match) {
                    try {
                        var parsed = JSON.parse(match[1]);
                        dataItems = parsed.items || [];
                        isLocked = parsed.locked || false;
                    } catch(e) { console.error("JSON Error", e); }
                }
                return content; 
            });
        }

        function buildWikitextVal(item) {
            var val = item.val;
            if (item.linkTarget && item.linkTarget.trim() !== '') return "[[" + item.linkTarget.trim() + "|" + val + "]]";
            if (item.linkSplit) {
                return val.replace(/([a-zA-Z0-9_À-ÿ\- ]+)/g, function(match) {
                    var trimmed = match.trim();
                    if (trimmed.length > 2 && trimmed.toLowerCase() !== 'dan' && trimmed.toLowerCase() !== 'atau') return "[[" + trimmed + "]]";
                    return match;
                });
            }
            if (item.link) return "[[" + val + "]]";
            return val;
        }

        function buildWikitextRef(refObj) {
            if (!refObj) return "";
            var title = refObj.title || extractDomain(refObj.url) || "Rujukan";
            var text = refObj.url ? "[" + ensureHttps(refObj.url) + " " + title + "]" : "'''" + title + "'''";
            var details = [];
            if (refObj.author) details.push("Penulis: " + refObj.author);
            if (refObj.site) details.push("Situs: " + refObj.site);
            if (refObj.publisher) details.push("Penerbit: " + refObj.publisher);
            if (refObj.date) details.push("Tanggal Akses: " + formatIndonesianDate(refObj.date));
            if (refObj.type) details.push("Jenis: " + refObj.type + (refObj.subType ? " (" + refObj.subType + ")" : ""));
            
            if (details.length > 0) text += " &mdash; <small>" + details.join(" &bull; ") + "</small>";
            return text;
        }

        function saveData(actionMsg, $btnEl, originalContent, isMinor) {
            if ($btnEl) { $btnEl.prop('disabled', true).html('Menyimpan...⏳'); }
            
            var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems });
            var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n<div class=\"md-native-render\">\n{| class=\"wikitable\"\n! Data !! Nilai !! Referensi\n";
            
            dataItems.forEach(function(item) {
                wt += "|-\n| " + item.prop + " || " + buildWikitextVal(item) + " || " + buildWikitextRef(item.ref) + "\n";
            });
            wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";

            var newContent;
            var regex = /<!-- MIPPEDIA_DATA_START \| .*? -->[\s\S]*?<!-- MIPPEDIA_DATA_END -->/;
            if (regex.test(originalContent)) newContent = originalContent.replace(regex, wt);
            else newContent = originalContent.trim() + "\n\n" + wt;

            api.postWithToken('csrf', {
                action: 'edit', title: pageName, text: newContent, 
                summary: 'Mippedia V8: ' + actionMsg, minor: isMinor || false
            }).done(function() {
                showToast('Berhasil disimpan! Memuat ulang...', 'success');
                setTimeout(function(){ window.location.reload(true); }, 1000);
            }).fail(function(err) {
                if ($btnEl) $btnEl.prop('disabled', false).html('Coba Lagi');
                showToast("Gagal menyimpan: " + err, 'error');
            });
        }

        // 8. BUILDER UI UTAMA
        function buildUI(rawContent) {
            var $app = $('<div id="mippedia-data-app"></div>');
            
            // HEADER & ACTION BAR
            var $header = $('<div class="md-header"></div>');
            var $titleContainer = $('<div class="md-title-container"><h3 class="md-title">' + svgEdit + ' Data Terstruktur V8</h3></div>');
            var $actions = $('<div class="md-actions"></div>');
            
            // Toggle Dark Mode
            var $darkBtn = $('<button class="md-btn-icon" title="Mode Gelap">' + (isDarkMode ? svgSun : svgMoon) + '</button>');
            $darkBtn.on('click', function() {
                isDarkMode = !isDarkMode;
                localStorage.setItem('md-dark-mode', isDarkMode);
                $('body').toggleClass('md-dark', isDarkMode);
                $(this).html(isDarkMode ? svgSun : svgMoon);
            });
            $actions.append($darkBtn);

            // Export CSV
            var $csvBtn = $('<button class="md-btn-icon" title="Ekspor CSV">' + svgDownload + ' CSV</button>');
            $csvBtn.on('click', function() { exportCSV(); });
            $actions.append($csvBtn);

            var $jsonBtn = $('<button class="md-btn-icon" title="JSON Tool">' + svgCode + ' JSON</button>');
            $jsonBtn.on('click', function() { showJsonModal(rawContent); });
            $actions.append($jsonBtn);

            if (isSysop) {
                var $lockBtn = $('<button class="md-btn-icon">' + (isLocked ? svgUnlock + ' Buka Kunci' : svgLock + ' Kunci') + '</button>');
                $lockBtn.on('click', function() {
                    isLocked = !isLocked;
                    saveData(isLocked ? 'Mengunci data' : 'Membuka kunci data', $(this), rawContent, true);
                });
                $actions.append($lockBtn);
            }

            if (!isLocked || isSysop) {
                var $addBtn = $('<button class="md-btn-icon" style="background:var(--md-primary); color:white; border-color:var(--md-primary);">' + svgEdit + ' Tambah</button>');
                $addBtn.on('click', function() { showForm(-1, rawContent); });
                $actions.append($addBtn);
            }

            $header.append($titleContainer).append($actions);
            $app.append($header);

            // FILTER TABS & SEARCH
            if (dataItems.length > 1) {
                var $tabArea = $('<div class="md-tabs"><button class="md-tab active" data-filter="all">Semua Data</button><button class="md-tab" data-filter="social">Punya Sosmed</button><button class="md-tab" data-filter="ref">Ada Referensi</button></div>');
                var $searchBox = $('<div class="md-search-box"><span class="md-search-icon">' + svgSearch + '</span><input type="text" class="md-search-input" placeholder="Cari data (label/nilai)..."></div>');
                
                $tabArea.find('.md-tab').on('click', function() {
                    $tabArea.find('.md-tab').removeClass('active'); $(this).addClass('active');
                    filterList();
                });
                $searchBox.find('input').on('keyup input', filterList);
                
                $app.append($tabArea).append($searchBox);

                function filterList() {
                    var q = $searchBox.find('input').val().toLowerCase();
                    var filter = $tabArea.find('.active').data('filter');
                    
                    $app.find('.md-row-display').each(function() {
                        var $r = $(this);
                        var text = $r.text().toLowerCase();
                        var hasSocial = $r.find('.md-social-group').length > 0;
                        var hasRef = $r.find('.md-ref-container').length > 0;
                        
                        var matchSearch = text.indexOf(q) !== -1;
                        var matchTab = filter === 'all' ? true : (filter === 'social' ? hasSocial : hasRef);
                        
                        $r.toggle(matchSearch && matchTab);
                    });
                }
            }

            // DAFTAR BARIS DATA (List)
            var $list = $('<div class="md-list"></div>');
            if (dataItems.length === 0) {
                $list.append('<div style="text-align:center; padding: 30px 10px; color:var(--md-text-sub); border:2px dashed var(--md-border); border-radius:12px; margin-top:10px;">Belum ada data. Klik <b>Tambah</b> untuk mulai menyusun mahakarya.</div>');
            } else {
                dataItems.forEach(function(item, index) {
                    var $row = $('<div class="md-row-display" draggable="true" data-index="'+index+'"></div>');
                    var $dragHandle = $('<div class="md-drag-handle" title="Tahan & Geser">' + svgDrag + '</div>');
                    
                    var $info = $('<div class="md-data-group"></div>');
                    $info.append('<span class="md-data-label">' + item.prop + '</span>');
                    
                    // Render Nilai Data
                    var rawVal = item.val || '';
                    var displayValHtml = rawVal;
                    if (rawVal.match(/^https?:\/\//i)) {
                        displayValHtml = '<a href="' + rawVal + '" target="_blank">' + extractDomain(rawVal) + ' ' + svgExternal + '</a>';
                    } else if (item.linkTarget && item.linkTarget.trim() !== '') {
                        displayValHtml = '<a href="' + mw.util.getUrl(item.linkTarget.trim()) + '">' + rawVal + '</a>';
                    } else if (item.linkSplit) {
                        var parts = rawVal.split(/([,/\s]+dan\s+|[,/\s]+atau\s+|[,/]+)/gi);
                        displayValHtml = parts.map(function(p) {
                            var trimmed = p.trim();
                            if (trimmed && !p.match(/^[,/\s]+$/) && !/^(dan|atau)$/i.test(trimmed)) {
                                return '<a href="' + mw.util.getUrl(trimmed) + '">' + trimmed + '</a>';
                            }
                            return p;
                        }).join('');
                    } else if (item.link) {
                        displayValHtml = '<a href="' + mw.util.getUrl(rawVal) + '">' + rawVal + '</a>';
                    }

                    var $valWrap = $('<div class="md-data-value-wrap"></div>');
                    $valWrap.append('<span class="md-data-value">' + displayValHtml + '</span>');
                    
                    var $copyBtn = $('<button class="md-btn-icon" style="padding:4px; border:none; background:transparent;" title="Salin teks">' + svgCopy + '</button>');
                    $copyBtn.on('click', function() { navigator.clipboard.writeText(rawVal); showToast('Teks disalin: ' + rawVal, 'success'); });
                    $valWrap.append($copyBtn);
                    $info.append($valWrap);

                    // Render Media Sosial (+ Twitch dll)
                    if (item.isPersonOrg && item.socials) {
                        var $socialGroup = $('<div class="md-social-group"></div>');
                        var hasSocial = false;
                        Object.keys(SOCIAL_PLATFORMS).forEach(function(key) {
                            var uname = item.socials[key];
                            if (uname) {
                                hasSocial = true; var platform = SOCIAL_PLATFORMS[key];
                                var fullUrl = platform.base + uname.replace(/^@/, '');
                                $socialGroup.append('<a class="md-social-badge" href="'+fullUrl+'" target="_blank" style="background:'+platform.color+';">'+platform.icon+' '+platform.name+'</a>');
                            }
                        });
                        if (hasSocial) $info.append($socialGroup);
                    }
                    
                    // Render FITUR AKORDEON REFERENSI
                    if (item.ref && (item.ref.url || item.ref.title)) {
                        var ref = item.ref;
                        var $refContainer = $('<div class="md-ref-container"></div>');
                        var refTitle = ref.title || extractDomain(ref.url) || "Rujukan Eksternal";
                        
                        // Toggle Button
                        var qScore = getRefQuality(ref);
                        var qColor = qScore >= 4 ? '#10b981' : (qScore >= 2 ? '#f59e0b' : '#ef4444');
                        var $toggleBtn = $('<button class="md-ref-toggle">' + svgRef + ' Lihat Referensi <span class="md-q-indicator" style="background:'+qColor+';" title="Kualitas Ref: '+qScore+'/5"></span></button>');
                        
                        // Panel Detail
                        var $refPanel = $('<div class="md-ref-panel"></div>');
                        $refPanel.append('<div class="md-ref-header">' + refTitle + '</div>');
                        
                        var $detailsGrid = $('<div class="md-ref-details-grid"></div>');
                        if(ref.author) $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penulis:</span><span class="md-ref-val">'+ref.author+'</span></div>');
                        if(ref.site) $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Situs:</span><span class="md-ref-val">'+ref.site+'</span></div>');
                        if(ref.publisher) $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penerbit:</span><span class="md-ref-val">'+ref.publisher+'</span></div>');
                        if(ref.date) $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Akses:</span><span class="md-ref-val">'+formatIndonesianDate(ref.date)+'</span></div>');
                        $refPanel.append($detailsGrid);

                        var $refBottom = $('<div class="md-ref-bottom"></div>');
                        if (ref.type) {
                            var tLbl = ref.type + (ref.subType ? ' • ' + ref.subType : '');
                            $refBottom.append('<span class="md-ref-badge">' + tLbl + '</span>');
                        } else {
                            $refBottom.append('<span></span>'); // spacer
                        }

                        // Tombol Kunjungi Tautan Langsung
                        if (ref.url) {
                            var safeUrl = ensureHttps(ref.url);
                            $refBottom.append('<a href="' + safeUrl + '" target="_blank" class="md-btn-direct">' + svgExternal + ' Kunjungi</a>');
                        }
                        $refPanel.append($refBottom);

                        // Logic Buka-Tutup (Akordeon)
                        $toggleBtn.on('click', function() {
                            var isOpen = $(this).hasClass('open');
                            $(this).toggleClass('open');
                            if(isOpen) {
                                $refPanel.slideUp(200);
                                $(this).html(svgRef + ' Lihat Referensi <span class="md-q-indicator" style="background:'+qColor+';"></span>');
                            } else {
                                $refPanel.slideDown(200).css('display', 'flex');
                                $(this).html(svgRef + ' Tutup Detail');
                            }
                        });

                        $refContainer.append($toggleBtn).append($refPanel);
                        $info.append($refContainer);
                    }
                    
                    $row.append($dragHandle).append($info);

                    if (!isLocked || isSysop) {
                        var $actionGroup = $('<div style="display:flex; flex-direction:column; gap:4px; align-items:flex-end;"></div>');
                        var $editIcon = $('<button class="md-btn-icon" style="padding:6px;">' + svgEdit + ' Edit</button>');
                        $editIcon.on('click', function() { showForm(index, rawContent); });
                        
                        var $cloneIcon = $('<button class="md-btn-icon" style="padding:6px; background:transparent; border:none; color:var(--md-text-sub);" title="Duplikasi Data">' + svgClone + '</button>');
                        $cloneIcon.on('click', function() { 
                            var cloned = JSON.parse(JSON.stringify(item));
                            dataItems.splice(index+1, 0, cloned);
                            saveData('Menduplikasi baris', null, rawContent, true);
                        });

                        $actionGroup.append($editIcon).append($cloneIcon);
                        $row.append($actionGroup);
                    }

                    // Simple Drag and Drop Event Binding
                    $row.on('dragstart', function(e) { $(this).addClass('dragging'); e.originalEvent.dataTransfer.setData('text/plain', index); });
                    $row.on('dragend', function() { $(this).removeClass('dragging'); });
                    $row.on('dragover', function(e) { e.preventDefault(); $(this).css('border-top', '3px solid var(--md-primary)'); });
                    $row.on('dragleave', function() { $(this).css('border-top', ''); });
                    $row.on('drop', function(e) {
                        e.preventDefault(); $(this).css('border-top', '');
                        var oldIdx = parseInt(e.originalEvent.dataTransfer.getData('text/plain'), 10);
                        var newIdx = parseInt($(this).data('index'), 10);
                        if (oldIdx === newIdx) return;
                        var movedItem = dataItems.splice(oldIdx, 1)[0];
                        dataItems.splice(newIdx, 0, movedItem);
                        saveData('Mengubah urutan baris', null, rawContent, true);
                    });

                    $list.append($row);
                });
            }
            $app.append($list);
            $app.append('<div id="md-form-container"></div>');

            var $infobox = $('.infobox').first();
            $('.md-native-render').hide(); 
            if ($infobox.length) $app.insertAfter($infobox);
            else $('#mw-content-text .mw-parser-output').append($app);
        }

        // Ekspor ke CSV Generator
        function exportCSV() {
            if(dataItems.length === 0) return showToast('Tidak ada data untuk diekspor', 'error');
            var csv = 'Label,Nilai,Tipe Referensi,URL Referensi\n';
            dataItems.forEach(function(item) {
                var l = '"'+(item.prop||'').replace(/"/g,'""')+'"';
                var v = '"'+(item.val||'').replace(/"/g,'""')+'"';
                var rt = '"'+((item.ref && item.ref.type) ? item.ref.type : '')+'"';
                var ru = '"'+((item.ref && item.ref.url) ? item.ref.url : '')+'"';
                csv += [l, v, rt, ru].join(',') + '\n';
            });
            var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
            var link = document.createElement('a');
            var url = URL.createObjectURL(blob);
            link.setAttribute('href', url); link.setAttribute('download', 'Data_Mippedia_' + getTodayString() + '.csv');
            link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link);
            showToast('File CSV berhasil diunduh!', 'success');
        }

        // 9. FORM EDIT V8
        function showForm(index, rawContent) {
            var $container = $('#md-form-container');
            $container.empty(); 

            var isNew = index === -1;
            var currentData = isNew ? { prop: '', val: '', link: false, linkTarget: '', linkSplit: false, ref: {}, isPersonOrg: false, socials: {} } : dataItems[index];
            var currentRef = currentData.ref || {};
            var currentSocials = currentData.socials || {};

            var $form = $('<div class="md-form-box"></div>');
            var $closeIcon = $('<button style="background:none;border:none;cursor:pointer;color:var(--md-text-sub);font-size:1.2rem;line-height:1;">&times;</button>');
            $closeIcon.on('click', function(){ $container.empty(); });
            
            var $titleWrap = $('<div class="md-form-title"></div>').append('<span>' + (isNew ? 'Tambah Data Baru' : 'Edit Data Terstruktur') + '</span>').append($closeIcon);
            $form.append($titleWrap);
            
            // Label Data + Auto Capitalize + Presets
            var $propGroup = $('<div class="md-form-group"><label>Label Data (Kategori)</label></div>');
            var $propInp = $('<input type="text" id="md-inp-prop" class="md-input" placeholder="Misal: Tanggal Lahir" value="' + (currentData.prop || '') + '">');
            $propInp.on('blur', function() { $(this).val(toTitleCase($(this).val())); }); // Auto Format
            $propGroup.append($propInp);
            
            var $presetWrap = $('<div style="margin-top:6px;"></div>');
            PRESET_LABELS.forEach(function(lbl) {
                var $pill = $('<span class="md-preset-pill">' + lbl + '</span>');
                $pill.on('click', function() { $propInp.val(lbl); $propInp.removeClass('error'); });
                $presetWrap.append($pill);
            });
            $propGroup.append($presetWrap);
            $form.append($propGroup);
            
            // Nilai Data & Char Counter
            var $valBox = $('<div class="md-form-group"></div>');
            $valBox.append('<label>Nilai Data Utama</label>');
            var $valInp = $('<input type="text" id="md-inp-val" class="md-input" value="' + (currentData.val || '') + '">');
            var $charCount = $('<span class="md-char-count">0</span>');
            $valInp.on('input', function() { $charCount.text($(this).val().length); }).trigger('input');
            
            $valBox.append($valInp).append($charCount);
            
            var $wikilinkOpts = $('<div style="margin-top:8px; display:flex; flex-direction:column; gap:8px; background:var(--md-surface); padding:10px; border-radius:8px; border:1px solid var(--md-border);"></div>');
            $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; cursor:pointer;"><input type="checkbox" id="md-inp-link" ' + (currentData.link?'checked':'') + '> Buat Wikilink Standar</label>');
            $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; cursor:pointer;"><input type="checkbox" id="md-inp-split" ' + (currentData.linkSplit?'checked':'') + '> Pisah Otomatis (Dan/Atau/Koma)</label>');
            $wikilinkOpts.append('<div style="margin-top:4px;"><label style="font-size:0.75rem; color:var(--md-text-sub);">Halaman Target (Opsional):</label><input type="text" id="md-inp-target" class="md-input" style="padding:6px; font-size:0.8rem;" value="' + (currentData.linkTarget || '') + '"></div>');
            $valBox.append($wikilinkOpts);
            $form.append($valBox);

            // SOSIAL MEDIA
            var $socialSec = $('<div class="md-form-group" style="margin-top:16px;"></div>');
            $socialSec.append('<label style="display:flex; align-items:center; gap:8px; cursor:pointer; background:rgba(79,70,229,0.1); padding:10px; border-radius:8px; font-weight:700; color:var(--md-primary);"><input type="checkbox" id="md-chk-person" ' + (currentData.isPersonOrg?'checked':'') + '> Aktifkan Profil Sosial / Musik</label>');
            
            var $socialGrid = $('<div class="md-social-grid" id="md-social-box" style="display:' + (currentData.isPersonOrg ? 'grid' : 'none') + '; margin-top:8px;"></div>');
            Object.keys(SOCIAL_PLATFORMS).forEach(function(key) {
                var p = SOCIAL_PLATFORMS[key];
                $socialGrid.append('<div><label style="font-size:0.75rem; color:var(--md-text-sub);">' + p.name + '</label><input type="text" id="md-soc-' + key + '" class="md-input" placeholder="@username" value="' + (currentSocials[key]||'') + '"></div>');
            });
            $socialSec.append($socialGrid);
            $form.append($socialSec);

            // REFERENSI
            var $refArea = $('<div class="md-form-group" style="margin-top:20px;"></div>');
            $refArea.append('<label style="font-size:0.95rem; font-weight:800; color:var(--md-text-main); border-bottom:1px solid var(--md-border); padding-bottom:5px;">Sumber Referensi</label>');
            
            var $refGrid = $('<div class="md-ref-grid" style="margin-top:10px;"></div>');
            var $typeSel = $('<select id="md-ref-type" class="md-select"><option value="">-- Tipe Utama --</option></select>');
            Object.keys(REF_TYPES).forEach(function(t) { $typeSel.append('<option value="'+t+'" '+(currentRef.type===t?'selected':'')+'>'+t+'</option>'); });
            var $subTypeSel = $('<select id="md-ref-subtype" class="md-select"><option value="">-- Sub-Tipe --</option></select>');
            
            function updateSubTypes(mainType, selectedSub) {
                $subTypeSel.empty().append('<option value="">-- Sub-Tipe --</option>');
                if (mainType && REF_TYPES[mainType]) {
                    REF_TYPES[mainType].forEach(function(st) { $subTypeSel.append('<option value="'+st+'" '+(selectedSub===st?'selected':'')+'>'+st+'</option>'); });
                }
            }
            $typeSel.on('change', function() { updateSubTypes($(this).val(), ''); });
            updateSubTypes(currentRef.type, currentRef.subType);

            $refGrid.append('<div><label style="font-size:0.75rem;">Tipe Utama</label></div>').find('div').last().append($typeSel);
            $refGrid.append('<div><label style="font-size:0.75rem;">Sub-Tipe</label></div>').find('div').last().append($subTypeSel);

            // Auto-Fill URL Logic
            var $urlInput = $('<input type="url" id="md-ref-url" class="md-input" placeholder="https://..." value="' + (currentRef.url || '') + '">');
            var $siteInp = $('<input type="text" id="md-ref-site" class="md-input" placeholder="Nama Situs" value="' + (currentRef.site || '') + '">');
            var $titleInp = $('<input type="text" id="md-ref-title" class="md-input" placeholder="Judul Halaman" value="' + (currentRef.title || '') + '">');
            
            $urlInput.on('blur', function() {
                var u = ensureHttps($(this).val()); $(this).val(u);
                if (u) {
                    var domain = extractDomain(u);
                    if (!$siteInp.val().trim()) $siteInp.val(domain);
                    if (!$titleInp.val().trim()) $titleInp.val(domain);
                    // Auto Select Tipe
                    if(u.indexOf('youtube.com') !== -1 || u.indexOf('youtu.be') !== -1) $typeSel.val('Video').trigger('change');
                    else if(u.indexOf('instagram.com') !== -1 || u.indexOf('twitter.com') !== -1 || u.indexOf('x.com') !== -1) $typeSel.val('Media Sosial').trigger('change');
                }
            });

            $refGrid.append('<div class="md-grid-full"><label style="font-size:0.75rem;">URL Rujukan</label></div>').find('div').last().append($urlInput);
            $refGrid.append('<div><label style="font-size:0.75rem;">Judul Halaman</label></div>').find('div').last().append($titleInp);
            $refGrid.append('<div><label style="font-size:0.75rem;">Nama Situs</label></div>').find('div').last().append($siteInp);
            $refGrid.append('<div><label style="font-size:0.75rem;">Penulis/Kreator</label><input type="text" id="md-ref-author" class="md-input" value="' + (currentRef.author || '') + '"></div>');
            $refGrid.append('<div><label style="font-size:0.75rem;">Penerbit (Opsional)</label><input type="text" id="md-ref-publisher" class="md-input" value="' + (currentRef.publisher || '') + '"></div>');
            
            var $dateBox = $('<div><label style="font-size:0.75rem;">Tgl Akses</label></div>');
            var $dateInpWrap = $('<div style="display:flex; gap:4px;"></div>');
            var $dateInp = $('<input type="date" id="md-ref-date" class="md-input" value="' + (currentRef.date || '') + '">');
            var $todayBtn = $('<button type="button" class="md-btn-icon" style="padding:4px 6px;" title="Set Hari Ini">Cetak H.Ini</button>');
            $todayBtn.on('click', function() { $dateInp.val(getTodayString()); });
            $dateInpWrap.append($dateInp).append($todayBtn);
            $dateBox.append($dateInpWrap);
            $refGrid.append($dateBox);

            $refArea.append($refGrid);
            $form.append($refArea);

            // Edit Summary & Actions
            var $summaryBox = $('<div class="md-form-group" style="margin-top:10px;"><input type="text" id="md-edit-summary" class="md-input" placeholder="Ringkasan suntingan (opsional)..." style="font-size:0.8rem; background:var(--md-bg);"></div>');
            var $minorChk = $('<label style="font-size:0.75rem; margin-left:10px;"><input type="checkbox" id="md-edit-minor"> Suntingan Kecil</label>');
            $summaryBox.append($minorChk);
            $form.append($summaryBox);

            var $actions = $('<div class="md-form-actions"></div>');
            var $btnSave = $('<button class="md-btn md-btn-save">Simpan Perubahan</button>');
            var $btnCancel = $('<button class="md-btn md-btn-cancel">Batal</button>');
            $actions.append($btnSave).append($btnCancel);
            
            if (!isNew) {
                var $btnDelete = $('<button class="md-btn md-btn-delete">Hapus Baris</button>');
                $btnDelete.on('click', function() {
                    if(confirm('Yakin ingin membuang data ini ke tong sampah?')) {
                        dataItems.splice(index, 1);
                        saveData('Menghapus data (' + currentData.prop + ')', $(this), rawContent, false);
                    }
                });
                $actions.append($btnDelete);
            }

            $form.append($actions);
            $container.append($form);

            // Interaksi Form
            $('#md-chk-person').on('change', function() {
                if($(this).is(':checked')) $('#md-social-box').slideDown(200).css('display', 'grid');
                else $('#md-social-box').slideUp(200);
            });

            $('html, body').animate({ scrollTop: $form.offset().top - 80 }, 300);
            $btnCancel.on('click', function() { $container.empty(); });
            
            // Hotkeys (Ctrl+S & Esc)
            $form.on('keydown', function(e) {
                if (e.ctrlKey && e.key === 's') { e.preventDefault(); $btnSave.click(); }
                if (e.key === 'Escape') $btnCancel.click();
            });
            $propInp.focus(); // Auto focus

            $btnSave.on('click', function() {
                // Validation
                $propInp.removeClass('error'); $valInp.removeClass('error');
                var newProp = $propInp.val().trim();
                var newVal = $valInp.val().trim();
                
                if (!newProp || !newVal) {
                    if(!newProp) $propInp.addClass('error');
                    if(!newVal) $valInp.addClass('error');
                    showToast("Label dan Nilai wajib diisi!", "error");
                    return;
                }

                var isPerson = $('#md-chk-person').is(':checked');
                var socObj = {};
                if (isPerson) {
                    Object.keys(SOCIAL_PLATFORMS).forEach(function(k) {
                        var valU = $('#md-soc-' + k).val().trim();
                        if (valU) socObj[k] = valU;
                    });
                }

                var refObj = {
                    type: $typeSel.val(), subType: $subTypeSel.val(),
                    url: ensureHttps($urlInput.val()), title: $titleInp.val().trim(),
                    site: $siteInp.val().trim(), author: $('#md-ref-author').val().trim(),
                    publisher: $('#md-ref-publisher').val().trim(), date: $dateInp.val()
                };

                // Clean empty refs
                Object.keys(refObj).forEach(function(key) { if (!refObj[key]) delete refObj[key]; });
                if (Object.keys(refObj).length === 0) refObj = null;

                var newItem = {
                    prop: newProp, val: newVal,
                    link: $('#md-inp-link').is(':checked'), linkSplit: $('#md-inp-split').is(':checked'),
                    linkTarget: $('#md-inp-target').val().trim(),
                    isPersonOrg: isPerson, socials: socObj, ref: refObj
                };

                if (isNew) dataItems.push(newItem); 
                else dataItems[index] = newItem; 

                var cSum = $('#md-edit-summary').val().trim();
                var sumMsg = cSum ? cSum : (isNew ? 'Tambah data ' + newProp : 'Edit data ' + newProp);
                var isMin = $('#md-edit-minor').is(':checked');
                
                saveData(sumMsg, $(this), rawContent, isMin);
            });
        }

        // 10. JSON EXPORT & IMPORT (MODAL V8)
        function showJsonModal(rawContent) {
            var $container = $('#md-form-container');
            $container.empty();

            var jsonStr = JSON.stringify(dataItems, null, 2);
            var $box = $('<div class="md-form-box"></div>');
            $box.append('<h4 class="md-form-title">Console Data (JSON)</h4>');
            $box.append('<p style="font-size:0.8rem; color:var(--md-text-sub); margin-bottom:10px;">Gunakan ini untuk backup data atau migrasi cepat antar halaman.</p>');
            
            var $txt = $('<textarea class="md-textarea" rows="12" style="font-family:monospace; font-size:0.8rem; background:#1e1e1e; color:#d4d4d4;"></textarea>').val(jsonStr);
            $box.append($txt);

            var $actions = $('<div class="md-form-actions"></div>');
            var $btnImport = $('<button class="md-btn md-btn-save">Timpa Data dengan JSON di Atas</button>');
            var $btnCopy = $('<button class="md-btn" style="background:#10b981;">Salin Kode</button>');
            var $btnCancel = $('<button class="md-btn md-btn-cancel">Tutup</button>');

            $actions.append($btnImport).append($btnCopy).append($btnCancel);
            $box.append($actions);
            $container.append($box);

            $btnCancel.on('click', function() { $container.empty(); });
            $btnCopy.on('click', function() { navigator.clipboard.writeText($txt.val()); showToast('JSON Disalin!', 'success'); });
            
            $btnImport.on('click', function() {
                try {
                    var parsed = JSON.parse($txt.val());
                    if (Array.isArray(parsed)) {
                        dataItems = parsed;
                        saveData('Impor massal dari JSON', $(this), rawContent, false);
                    } else showToast("Format JSON salah! Harus berawal [ dan berakhir ]", "error");
                } catch(e) { showToast("Error JSON: " + e.message, "error"); }
            });
        }

        // 11. EKSEKUSI UTAMA
        loadData().then(function(rawContent) { buildUI(rawContent); });
    });

})(jQuery, mediaWiki)

/* ==========================================================
   ⚡ MIPPEDIA SPEED OPTIMIZER - PURE SPEED & STABLE (V1.1)
   Features: Instant Link Pre-fetching Engine (No Animation/Pure Performance).
   Optimization: Zero-flicker, scoped lifecycle protection, advanced anti-cache clutter.
   Target: Built for maximum long-term stability and bulletproof caching.
   ========================================================= */

(function() {
    // Ambil nama host secara dinamis (contoh: data.mippedia.org)
    var currentHost = window.location.hostname;

    // --- 🗲 ENGINE PRE-FETCH CORES ---
    function injectPrefetchLink(url) {
        // Jaring Pengaman 1: Jangan injeksi jika link prefetch untuk URL ini sudah ada di head browser
        if (document.querySelector('link[href="' + url + '"]')) return;

        var prefetcher = document.createElement('link');
        prefetcher.rel = 'prefetch';
        prefetcher.href = url;
        
        // Jaring Pengaman 2: Failsafe anti-eror cache jika network mendadak sibuk
        prefetcher.onerror = function() { prefetcher.remove(); };
        
        document.head.appendChild(prefetcher);
    }

    function initPrefetchDispatch(href) {
        // Memanfaatkan requestIdleCallback agar proses prefetch hanya berjalan saat browser senggang 
        // sehingga tidak akan membuat scrolling halaman terasa berat/patah-patah
        if (window.requestIdleCallback) {
            window.requestIdleCallback(function() { injectPrefetchLink(href); });
        } else {
            setTimeout(function() { injectPrefetchLink(href); }, 20);
        }
    }

    // --- 🎮 COGNITIVE EVENT LISTENERS (UNIVERSAL HOVER & TOUCH) ---
    // Mendengarkan area konten utama MediaWiki (Desktop & Tampilan Mobile HP)
    $(document).on('mouseenter pointerdown', '#mw-content-text a, .mw-body-content a, #bodyContent a, .mw-parser-output a', function() {
        var $link = $(this);
        var href = $link.attr('href');

        // --- 🛡️ FILTER STRATA TINGGI: ABREVIASI LINK BERGUNA (ANTI CRASH CACHE) ---
        // 1. Abaikan link kosong, javascript void, atau buka tab baru (_blank)
        if (!href || href.startsWith('#') || href.startsWith('javascript:') || $link.attr('target') === '_blank') return;
        
        // 2. Abaikan link merah (artikel belum ada), link sunting teks, riwayat versi, dan aksi form MediaWiki
        if ($link.hasClass('new') || href.includes('action=') || href.includes('diff=') || href.includes('oldid=')) return;
        
        // 3. Abaikan link perkakas krusial pengurus / sistem otentikasi (hindari prefetch logout tidak sengaja)
        if (href.includes('Istimewa:') || href.includes('Special:') || href.includes('do=logout')) return;

        // Pastikan hanya mengeksekusi routing internal ekosistem Mippedia
        var isInternal = href.indexOf(currentHost) !== -1 || href.startsWith('/') || !href.includes('://');
        if (isInternal) {
            initPrefetchDispatch(href);
        }
    });
})();

/* ==========================================================
   🧠 MIPPEDIA DATA - SMART CONTEXT + AUTO THUMBNAIL (V10.1)
   Features: Priority Check (ID > EN > CONCISE), Auto-Age, 
             Auto-Bold, Smart Links, Dynamic Context,
             Targeted Isolation (Safe for Forms), Dynamic Noindex,
             Aesthetic Centered Empty State + 🚀 Instant Action Hub (3 Buttons)
   Fixes: Mobile View Visibility & Custom Short URL Route (No /w/)
   ========================================================= */
(function() {
    $(document).ready(function() {
        var $descSection = $('#mip-desc-section'), $descBox = $('#mip-auto-description'),
            $sourceInfo = $('#mip-source-info'), $portalLinks = $('#mip-portal-links'),
            $projectPortal = $('#mip-project-portal'), $mainContent = $('#mw-content-text');
        
        if (!$descBox.length) return;

        var pageTitle = mw.config.get('wgPageName').replace(/_/g, ' '),
            cacheKey = 'mip_smart_context_thumb_' + pageTitle, now = new Date().getTime(),
            currentYear = 2026;

        // --- KONFIGURASI PROYEK ---
        var projects = [
            { id: 'id', name: 'Mippedia bahasa Indonesia', url: 'https://id.mippedia.org/api.php', base: 'https://id.mippedia.org/wiki/', label: 'Mippedia Indonesia' },
            { id: 'en', name: 'Mippedia bahasa Inggris', url: 'https://en.mippedia.org/api.php', base: 'https://en.mippedia.org/wiki/', label: 'Mippedia Inggris' },
            { id: 'concise', name: 'Mippedia bahasa Indonesia ringkas', url: 'https://concise.mippedia.org/api.php', base: 'https://concise.mippedia.org/wiki/', label: 'Mippedia Ringkas' }
        ];

        // --- 🎨 ANIMASI, HOVER EFFECT & RESPONSIVE STYLE ---
        if (!$('#mip-clean-style').length) {
            $('head').append(
                '<style id="mip-clean-style">' +
                    '@keyframes mipFadeInUp {' +
                        'from { opacity: 0; transform: translateY(15px); }' +
                        'to { opacity: 1; transform: translateY(0); }' +
                    '}' +
                    '#mip-empty-state-notice {' +
                        'display: block !important;' + /* Memaksa tampil di seluler/mobile */
                        'animation: mipFadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;' +
                    '}' +
                    '.mip-btn-container {' +
                        'display: flex;' +
                        'flex-wrap: wrap;' + /* Supaya otomatis turun ke bawah kalau di HP */
                        'justify-content: center;' +
                        'margin-bottom: 30px;' +
                        'padding-top: 5px;' +
                    '}' +
                    '.mip-action-btn {' +
                        'display: inline-flex; align-items: center; justify-content: center;' +
                        'padding: 10px 18px; margin: 6px; font-size: 0.88em; font-weight: 600;' +
                        'color: #6a5acd !important; background: #ffffff; border: 1.5px solid #6a5acd;' +
                        'border-radius: 30px; text-decoration: none !important; cursor: pointer;' +
                        'transition: all 0.25s ease-in-out; box-shadow: 0 2px 5px rgba(106,92,205,0.08);' +
                        'flex-grow: 1; max-width: 220px; min-width: 150px;' + /* Penyesuaian porsi tombol di HP */
                    '}' +
                    '.mip-action-btn:hover {' +
                        'color: #ffffff !important; background: #6a5acd;' +
                        'transform: translateY(-2px); box-shadow: 0 4px 12px rgba(106,92,205,0.2);' +
                    '}' +
                    '.mip-action-btn:active {' +
                        'transform: translateY(0);' +
                    '}' +
                '</style>'
            );
        }

        // --- FUNGSI TOOLS ---
        function applyAutoBold(text) { return text.replace(new RegExp('(' + pageTitle + ')', 'gi'), '<strong>$1</strong>'); }
        function cleanExtract(text) { return text.replace(/\[\d+\]/g, '').replace(/\{\{[^}]+\}\}/g, '').replace(/\(\s*\)/g, '').replace(/\s\s+/g, ' ').trim(); }
        
        function applyDynamicContext(text) {
            var date = new Date();
            var hari = ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"];
            var bulan = ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"];
            var tglSkrg = hari[date.getDay()] + ", " + date.getDate() + " " + bulan[date.getMonth()] + " " + date.getFullYear();
            return text.replace(/(hari ini|saat ini|sekarang)/gi, '$1 (' + tglSkrg + ')')
                .replace(/(\d{1,2}\s(?:Januari|Februari|Maret|April|Mei|Juni|Juli|Agustus|September|Oktober|November|Desember)\s(\d{4}))/gi, function(m, f, y) { 
                    return f + " <span style='color: #444; font-weight: bold;'>– usia " + (currentYear - parseInt(y)) + " tahun</span>"; 
                })
                .replace(/(sejak|tahun)\s(\d{4})/gi, function(m, k, y) {
                    var gap = currentYear - parseInt(y);
                    if (gap > 0 && gap < 100) return k + " " + y + " <small style='color: #888;'>(" + gap + " thn lalu)</small>";
                    return m;
                });
        }

        function applySummary(text) {
            var limit = 250;
            if (text.length <= limit) return '<span>' + text + '</span>';
            return '<span>' + text.substring(0, limit) + '</span><span class="mip-dots">... </span><span class="mip-more" style="display:none;">' + text.substring(limit) + '</span><span class="mip-read-btn" style="color: #6a5acd; cursor: pointer; font-weight: bold; margin-left: 5px;">Baca selengkapnya</span>';
        }

        // --- SMART LINKS PORTAL ---
        function buildSmartLinks(currentId, validatedEnTitle) {
            $portalLinks.empty();
            var validLinks = [];
            
            var checkRequests = projects.filter(p => p.id !== currentId).map(function(p) {
                var targetTitle = (p.id === 'en' && validatedEnTitle) ? validatedEnTitle : pageTitle;
                if (p.id === 'en' && !validatedEnTitle) return $.Deferred().resolve();

                return $.ajax({ url: p.url, data: { action: 'query', titles: targetTitle, format: 'json', origin: '*' }, dataType: 'json' })
                    .then(function(data) { 
                        if (data.query.pages["-1"] === undefined) { 
                            validLinks.push('<a href="' + p.base + encodeURIComponent(targetTitle) + '" target="_blank" style="color: #6a5acd; text-decoration: underline; font-weight: bold;">' + p.label + '</a>'); 
                        } 
                    });
            });

            $.when.apply($, checkRequests).done(function() {
                if (validLinks.length > 0) { $portalLinks.html(validLinks.join(' <span style="color:#ccc; margin: 0 5px;">•</span> ')); $projectPortal.fadeIn(); }
            });
        }

        // --- 🧠 RENDER EMPTY STATE + INTERACTIVE HUB ---
        function toggleMippediaLayout(isEmpty) {
            var $existingNotice = $('#mip-empty-state-notice');
            var userGroups = mw.config.get('wgUserGroups') || [];
            var isSysop = userGroups.indexOf('sysop') !== -1;

            var $wikiDataElements = $mainContent.children().not('#mip-empty-state-notice, #mip-desc-section, script, style, .printfooter');
            var $editElements = $('#ca-edit, .mw-editsection, .wb-editsection, .mip-edit-trigger, [id*="edit"], [class*="edit-pencil"]');
            var $metaRobots = $('meta[name="robots"]');

            if (isEmpty) {
                if (!$existingNotice.length) {
                    // Perbaikan Jalur URL tanpa sub-folder /w/ langsung menembak Short URL root parameter
                    var createUrlID = 'https://id.mippedia.org/index.php?title=' + encodeURIComponent(pageTitle) + '&action=edit';
                    var createUrlEN = 'https://en.mippedia.org/index.php?title=' + encodeURIComponent(pageTitle) + '&action=edit';
                    var createUrlConcise = 'https://concise.mippedia.org/index.php?title=' + encodeURIComponent(pageTitle) + '&action=edit';

                    var noticeHtml = 
                        '<div id="mip-empty-state-notice" style="text-align: center; max-width: 600px; margin: 40px auto; padding: 10px; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">' +
                            '<!-- Ikon Warning Besar -->' +
                            '<div style="margin-bottom: 22px; display: inline-block;">' +
                                '<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#d9534f" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">' +
                                    '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>' +
                                    '<line x1="12" y1="9" x2="12" y2="13"></line>' +
                                    '<line x1="12" y1="17" x2="12.01" y2="17"></line>' +
                                '</' + 'svg>' +
                            '</div>' +
                            '<!-- Judul Utama -->' +
                            '<h4 style="color: #2c3e50; margin: 0 0 12px 0; font-size: 1.35em; font-weight: 700; letter-spacing: -0.3px;">Item Data Struktur Tidak Memiliki Sumber Artikel</h4>' +
                            '<!-- Deskripsi Utama -->' +
                            '<p style="color: #555; margin: 0 0 25px 0; font-size: 0.98em; line-height: 1.6;">' +
                                'Item data ini saat ini <strong>tidak memiliki artikel rujukan satu pun</strong> di Mippedia Indonesia, Mippedia Inggris, maupun Mippedia Indonesia Ringkas.' +
                            '</p>' +
                            
                            '<!-- 🚀 INSTANT ACTION HUB (Flexbox-Responsive Mobile & URL No /w/) -->' +
                            '<div class="mip-btn-container">' +
                                '<a href="' + createUrlID + '" target="_blank" class="mip-action-btn">' +
                                    '<span style="margin-right: 6px;"></span>Buat Artikel ID' +
                                '</a>' +
                                '<a href="' + createUrlEN + '" target="_blank" class="mip-action-btn">' +
                                    '<span style="margin-right: 6px;"></span>Buat Artikel EN' +
                                '</a>' +
                                '<a href="' + createUrlConcise + '" target="_blank" class="mip-action-btn">' +
                                    '<span style="margin-right: 6px;"></span>Buat Artikel Ringkas' +
                                '</a>' +
                            '</div>' +

                            '<!-- Catatan Kaki Info Kecil -->' +
                            '<div style="font-size: 0.85em; color: #a0a0a0; line-height: 1.5; font-style: italic; border-top: 1px solid #f0f0f0; padding-top: 15px;">' +
                                'Informasi: Item data yang tidak terikat dengan artikel ensiklopedia apa pun dalam ekosistem Mippedia akan dihapus secara otomatis oleh pengurus dalam waktu dekat.' +
                            '</div>' +
                        '</div>';
                    $mainContent.prepend(noticeHtml);
                }

                $wikiDataElements.hide();
                $descSection.hide();

                if (!isSysop) {
                    $editElements.css({ 'pointer-events': 'none', 'opacity': '0.3', 'cursor': 'not-allowed' }).hide();
                    $(document).on('keydown.miplock', function(e) {
                        if (e.key.toLowerCase() === 'e' && !$(e.target).is('input, textarea')) {
                            e.preventDefault();
                            return false;
                        }
                    });
                }

                mw.config.set('wgRobotsPolicies', { 'index': 'noindex', 'follow': 'nofollow' });
                if ($metaRobots.length) {
                    $metaRobots.attr('content', 'noindex, nofollow');
                } else {
                    $('head').append('<meta name="robots" content="noindex, nofollow">');
                }

            } else {
                if ($existingNotice.length) $existingNotice.remove();
                
                $wikiDataElements.show();
                $descSection.show();

                if (!isSysop) {
                    $(document).off('keydown.miplock');
                }

                mw.config.set('wgRobotsPolicies', { 'index': 'index', 'follow': 'follow' });
                if ($metaRobots.length) {
                    $metaRobots.attr('content', 'index, follow');
                }
            }
        }

        // --- SISTEM PRIORITAS ---
        var cached = JSON.parse(localStorage.getItem(cacheKey) || "{}");
        var globalEnTitle = cached.enTitle || ""; 

        function init() {
            var pPrimary = projects[0]; 
            $.ajax({
                url: pPrimary.url,
                data: { action: 'query', prop: 'revisions|pageimages|langlinks', lllang: 'en', rvprop: 'timestamp', piprop: 'thumbnail', pithumbsize: 150, titles: pageTitle, format: 'json', origin: '*' },
                dataType: 'json',
                success: function(res) {
                    var pg = res.query.pages, id = Object.keys(pg)[0];
                    var latestTS = (id != "-1") ? pg[id].revisions[0].timestamp : "0";
                    var thumbUrl = (id != "-1" && pg[id].thumbnail) ? pg[id].thumbnail.source : "";
                    
                    if (id != "-1" && pg[id].langlinks && pg[id].langlinks[0]) {
                        globalEnTitle = pg[id].langlinks[0]['*'];
                    }

                    if (cached.content && cached.ts === latestTS && latestTS !== "0" && !cached.isEmpty) {
                        toggleMippediaLayout(false);
                        renderAll(cached.p, cached.content, cached.isTrans, cached.orig, cached.img, cached.customUrl, cached.enTitle);
                    } else { 
                        fetchPriorityData(0, latestTS, thumbUrl); 
                    }
                },
                error: function() { 
                    if (cached.content) {
                        toggleMippediaLayout(cached.isEmpty || false);
                        if (!cached.isEmpty) renderAll(cached.p, cached.content, cached.isTrans, cached.orig, cached.img, cached.customUrl, cached.enTitle);
                    } 
                }
            });
        }

        function fetchPriorityData(index, newTS, img) {
            if (index >= projects.length) {
                localStorage.setItem(cacheKey, JSON.stringify({isEmpty: true, ts: newTS, content: ""}));
                toggleMippediaLayout(true);
                return;
            }

            var p = projects[index];

            if (p.id === 'en') {
                if (!globalEnTitle) {
                    $.ajax({
                        url: 'https://concise.mippedia.org/api.php',
                        data: { action: 'query', prop: 'langlinks', lllang: 'en', titles: pageTitle, format: 'json', origin: '*' },
                        dataType: 'json',
                        async: false, 
                        success: function(cRes) {
                            var cPg = cRes.query.pages, cId = Object.keys(cPg)[0];
                            if (cId != "-1" && cPg[cId].langlinks && cPg[cId].langlinks[0]) {
                                globalEnTitle = cPg[cId].langlinks[0]['*'];
                            }
                        }
                    });
                }

                if (globalEnTitle) {
                    $.ajax({
                        url: p.url,
                        data: { action: 'query', prop: 'extracts', exintro: 1, explaintext: 1, titles: globalEnTitle, format: 'json', origin: '*' },
                        dataType: 'json',
                        success: function(data) {
                            var pages = data.query.pages, pageId = Object.keys(pages)[0];
                            if (pageId != "-1" && pages[pageId].extract) {
                                var extract = cleanExtract(pages[pageId].extract);
                                finalize(p, extract, false, "", newTS, img, p.base + encodeURIComponent(globalEnTitle), globalEnTitle);
                            } else {
                                fetchPriorityData(index + 1, newTS, img);
                            }
                        },
                        error: function() { fetchPriorityData(index + 1, newTS, img); }
                    });
                } else {
                    fetchPriorityData(index + 1, newTS, img);
                }
            } else {
                $.ajax({
                    url: p.url,
                    data: { action: 'query', prop: 'extracts', exintro: 1, explaintext: 1, titles: pageTitle, format: 'json', origin: '*' },
                    dataType: 'json',
                    success: function(data) {
                        var pages = data.query.pages, pageId = Object.keys(pages)[0];
                        if (pageId != "-1" && pages[pageId].extract) {
                            var extract = cleanExtract(pages[pageId].extract);
                            finalize(p, extract, false, "", newTS, img, p.base + encodeURIComponent(pageTitle), globalEnTitle); 
                        } else {
                            fetchPriorityData(index + 1, newTS, img);
                        }
                    },
                    error: function() { fetchPriorityData(index + 1, newTS, img); }
                });
            }
        }

        function finalize(p, c, t, o, ts, img, customUrl, enTitle) {
            localStorage.setItem(cacheKey, JSON.stringify({isEmpty: false, p:p, content:c, isTrans:t, orig:o, ts:ts, img:img, customUrl: customUrl, enTitle: enTitle}));
            toggleMippediaLayout(false); 
            renderAll(p, c, t, o, img, customUrl, enTitle);
        }

        function renderAll(p, currentText, isTranslated, originalText, img, customUrl, enTitle) {
            var processedText = applyAutoBold(applyDynamicContext(currentText));
            var thumbHtml = img ? '<div style="float: right; margin-left: 15px; margin-bottom: 10px; border: 1px solid #ddd; padding: 3px; background: #fff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"><img src="'+img+'" style="max-width: 100px; display: block; height: auto;"></div>' : '';

            if (!$mainContent.find('#mip-desc-section').length) {
                $mainContent.prepend($descSection);
            }

            $descSection.show();
            $descBox.show().html(thumbHtml + applySummary(processedText) + '<div style="clear:both;"></div>');
            
            var targetLink = customUrl ? customUrl : p.base + encodeURIComponent(pageTitle);
            var footer = '<div style="font-size: 0.9em; color: #777;">Sumber : <a href="' + targetLink + '" target="_blank" style="color: #6a5acd; font-weight: bold; text-decoration: none;">' + p.name + '.</a>';
            if (isTranslated) { footer += '<br><span style="font-size: 0.85em; font-style: italic;">(Diterjemahkan secara otomatis)</span> <span id="mip-toggle-orig" style="color: #6a5acd; cursor: pointer; text-decoration: underline; margin-left: 5px;">Tampilkan versi asli</span>'; }
            $sourceInfo.show().html(footer);
            
            buildSmartLinks(p.id, enTitle);
            
            $(document).off('click', '.mip-read-btn').on('click', '.mip-read-btn', function() { $(this).hide(); $('.mip-dots').hide(); $('.mip-more').fadeIn(); });
            $(document).off('click', '#mip-toggle-orig').on('click', '#mip-toggle-orig', function() {
                var isOrig = ($(this).text() === 'Tampilkan versi asli');
                var textToDisplay = applyAutoBold(applyDynamicContext(isOrig ? originalText : currentText));
                $descBox.html(thumbHtml + applySummary(textToDisplay) + '<div style="clear:both;"></div>');
                $(this).text(isOrig ? 'Tampilkan terjemahan' : 'Tampilkan versi asli');
            });
        }

        init();
    });
})();

/* ==========================================================
   🚀 MIPPEDIA DATA - CORE SYSTEM (ULTIMATE BUNDLE)
   Status: FINAL & REVISED (Visual Fix + Permission Logic)
   Fix: Mobile Responsive Notification Position
   ========================================================== */

(function() {
    $(document).ready(function() {
        // --- 1. FILTER GLOBAL (Namespace 0 & Bukan Halaman Utama) ---
        if (mw.config.get('wgNamespaceNumber') !== 0 || 
            mw.config.get('wgIsMainPage') || 
            mw.config.get('wgAction') !== 'view') return;

        var pageTitle = mw.config.get('wgPageName');
        var dataPage = 'MediaWiki:Sitelinks-Data.json';
        var userGroups = mw.config.get('wgUserGroups');
        var isAdmin = userGroups.includes('sysop') || userGroups.includes('interface-admin');

        var projects = {
            'id': { name: 'ID', url: 'https://id.mippedia.org/api.php', base: 'https://id.mippedia.org/wiki/', color: '#6a5acd' },
            'en': { name: 'EN', url: 'https://en.mippedia.org/api.php', base: 'https://en.mippedia.org/wiki/', color: '#4169e1' },
            'concise': { name: 'Concise', url: 'https://concise.mippedia.org/api.php', base: 'https://concise.mippedia.org/wiki/', color: '#20b2aa' }
        };

        // --- 2. KOTAK NOTIFIKASI INFORMASI MODERN (FIXED MOBILE POSITION) ---
        function showBoxNotif(title, msg, type) {
            $('.mip-box-notif').remove();
            var theme = type === 'success' ? {bg:'#e6fffa', border:'#38b2ac', text:'#234e52', icon:''} : 
                        {bg:'#fff5f5', border:'#f56565', text:'#742a2a', icon:''};
            
            // Logika CSS Responsif untuk posisi
            var isMobile = window.innerWidth <= 768;
            var desktopStyle = "top:25px; right:25px; width:350px;";
            var mobileStyle = "top:15px; left:50%; transform:translateX(-50%); width:90%; max-width:400px;";
            var finalPos = isMobile ? mobileStyle : desktopStyle;

            var $notif = $('<div class="mip-box-notif" style="position:fixed; ' + finalPos + ' background:'+theme.bg+'; border-left:6px solid '+theme.border+'; padding:18px; z-index:10001; border-radius:12px; box-shadow:0 15px 35px rgba(0,0,0,0.2); font-family:sans-serif; animation:mipSlideIn 0.4s ease-out;">' +
                '<div style="display:flex; align-items:center; gap:12px; margin-bottom:8px;">' +
                    '<span style="font-size:20px;">'+theme.icon+'</span>' +
                    '<strong style="color:'+theme.text+'; font-size:15px; letter-spacing:-0.3px;">'+title+'</strong>' +
                '</div>' +
                '<p style="margin:0; font-size:13px; color:'+theme.text+'; line-height:1.6; opacity:0.9;">'+msg+'</p>' +
            '</div>').appendTo('body');

            setTimeout(function() { $notif.fadeOut(function(){ $(this).remove(); }); }, 5500);
        }

        // --- 3. UI GENERATOR (DIPERTEBAL) ---

      // A. Header Pro
        var headerHtml = '<div id="mip-header" style="background:#f8f9fa; border:1px solid #ddd; border-left:6px solid #6a5acd; padding:18px; margin-bottom:25px; border-radius:6px; box-shadow:inset 0 0 10px rgba(0,0,0,0.02);">' +
            '<div style="display:flex; align-items:center; gap:10px; margin-bottom:8px;">' +
            '<span style="background:#6a5acd; color:white; padding:3px 10px; border-radius:4px; font-size:11px; font-weight:bold; text-transform:uppercase; letter-spacing:0.5px;">Basis Data Terstruktur</span>' +
            '<strong style="color:#111; font-size:16px;"></strong></div>' +
            '<p style="margin:0; font-size:13px; color:#444; line-height:1.6;">' +
            'Halaman ini adalah metadata entitas repositori pusat yang disinkronisasi secara otomatis lintas ekosistem. ' +
            'Informasi di bawah ini bersifat teknis dan bebas digunakan sebagai referensi data terbuka bagi semua orang di seluruh dunia berdasarkan lisensi atribusi yang sesuai.' +
            '</p></div>';

        // B. Connector Box
        var editBtn = '<span id="mip-open-editor" style="cursor:pointer; font-size:20px; color:#6a5acd; opacity:0.8; transition:0.3s;" onmouseover="this.style.opacity=1" onmouseout="this.style.opacity=0.8">✎</span>';
        var connectorHtml = '<div id="mip-connector" style="background:#fff; border:1px solid #e2e8f0; border-radius:16px; padding:22px; margin-top:30px; box-shadow:0 10px 25px rgba(0,0,0,0.04);">' +
            '<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">' +
            '<strong style="font-size:15px; color:#1a202c; display:flex; align-items:center; gap:8px;">ID situs</strong>'+editBtn+'</div>' +
            '<div id="mip-display" style="display:flex; gap:12px; flex-wrap:wrap;"><small style="color:#a0aec0;">Mensinkronisasi basis data...</small></div>' +
            '<div id="mip-editor" style="display:none; margin-top:20px; border-top:2px solid #f7fafc; padding-top:20px;">' +
                Object.keys(projects).map(p => '<div style="margin-bottom:12px; display:flex; gap:10px;"><span style="width:75px; font-size:11px; font-weight:bold; background:#edf2f7; display:flex; align-items:center; justify-content:center; border-radius:8px; color:#4a5568;">'+projects[p].name+'</span><input type="text" id="in-'+p+'" placeholder="Judul artikel di '+projects[p].name+'..." style="flex:1; padding:10px; font-size:13px; border:1.5px solid #e2e8f0; border-radius:10px; outline:none; transition:0.2s;" onfocus="this.style.borderColor=\'#6a5acd\'"></div>').join('') +
                '<button id="mip-save" style="width:100%; padding:14px; background:#6a5acd; color:white; border:none; border-radius:12px; font-size:14px; font-weight:bold; cursor:pointer; box-shadow:0 4px 12px rgba(106,90,205,0.3); transition:0.3s;">Terbitkan</button>' +
            '</div></div>';

        // C. Footer Lisensi Lengkap
        var footerHtml = '<div id="mip-footer" style="background:#fafafa; border:1px solid #eee; border-radius:10px; padding:20px; margin-top:30px; text-align:center;">' +
            '<div style="font-size:11px; color:#718096; font-weight:800; text-transform:uppercase; letter-spacing:1px; margin-bottom:10px;">Lisensi, Atribusi & Penggunaan Data</div>' +
            '<p style="margin:0 0 10px; font-size:13px; color:#4a5568; line-height:1.6;">' +
            'Seluruh data terstruktur yang tersaji dalam repositori ini merupakan milik publik dan tersedia di bawah lisensi resmi ' +
            '<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" style="color:#6a5acd; text-decoration:none; font-weight:700;">Creative Commons Attribution-ShareAlike 4.0 International</a>.' +
            '</p>' +
            '<p style="margin:0; font-size:12px; color:#a0aec0;">Akses API dan penggunaan data secara massal wajib mencantumkan atribusi kepada <strong>Mippedia Community</strong> selaku pengelola proyek.</p></div>';

        // Injeksi
        $('#mw-content-text').prepend(headerHtml);
        $('#mw-content-text').append(connectorHtml).append(footerHtml);

        // --- 4. LOGIC ENGINE ---
        function loadLinks() {
            new mw.Api().get({ action: 'query', prop: 'revisions', titles: dataPage, rvprop: 'content', formatversion: 2 }).done(function(d) {
                var json = d.query.pages[0].revisions ? JSON.parse(d.query.pages[0].revisions[0].content) : {};
                var data = json[pageTitle] || {};
                var $box = $('#mip-display').empty();
                var found = false;
                Object.keys(projects).forEach(p => {
                    if (data[p]) {
                        found = true;
                        $box.append('<a style="background:'+projects[p].color+'; color:white; padding:8px 16px; border-radius:10px; font-size:12px; font-weight:bold; text-decoration:none; border-bottom:3px solid rgba(0,0,0,0.15);" href="'+projects[p].base+encodeURIComponent(data[p])+'" target="_blank">Mippedia '+projects[p].name+': '+data[p]+'</a>');
                        $('#in-' + p).val(data[p]);
                    }
                });
                if (!found) $box.html('<em style="color:#cbd5e0; font-size:13px;">Entitas ini belum terhubung ke cabang Mippedia manapun.</em>');
            });
        }

        $(document).on('click', '#mip-save', function() {
            // CEK IZIN: Tolak user biasa
            if (!isAdmin) {
                showBoxNotif('Suntingan anda tidak di terbitkan', 'Halaman ini dilindungi. Hanya <b>Pengurus</b> yang memiliki otoritas untuk memodifikasi metadata ekosistem secara langsung.', 'error');
                return;
            }

            var $btn = $(this).text('Sedang Memvalidasi...').prop('disabled', true);
            var api = new mw.Api();
            var newData = {}, promises = [], invalid = [], isDel = true;

            Object.keys(projects).forEach(p => {
                var v = $('#in-' + p).val().trim();
                if (v) {
                    isDel = false;
                    promises.push($.ajax({ url: projects[p].url, data: { action: 'query', titles: v, format: 'json', origin: '*' }, dataType: 'json' }).done(function(res){
                        if (res.query.pages["-1"]) invalid.push(projects[p].name); else newData[p] = v;
                    }));
                }
            });

            $.when.apply($, promises).then(function() {
                if (invalid.length > 0) {
                    showBoxNotif('Suntingan anda tidak di terbitkan', 'Artikel dengan judul tersebut tidak ditemukan di basis data Mippedia cabang: ' + invalid.join(', ') + '. Periksa kembali ejaan dan kapitalisasi.', 'error');
                    $btn.text('Terbitkan').prop('disabled', false); return;
                }
                
                api.get({ action: 'query', prop: 'revisions', titles: dataPage, rvprop: 'content', formatversion: 2 }).done(function(r) {
                    var full = r.query.pages[0].revisions ? JSON.parse(r.query.pages[0].revisions[0].content) : {};
                    if (isDel) delete full[pageTitle]; else full[pageTitle] = newData;
                    
                    api.postWithEditToken({ action: 'edit', title: dataPage, text: JSON.stringify(full, null, 2), summary: 'Sync Metadata: ' + pageTitle })
                    .done(function() {
                        showBoxNotif('Suntingan anda berhasil di terbitkan!', 'Metadata entitas berhasil disinkronisasi ke seluruh jaringan ekosistem Mippedia.', 'success');
                        setTimeout(function(){ location.reload(); }, 1500);
                    }).fail(function(c) {
                        showBoxNotif('Gagal Menyimpan', 'Terjadi kesalahan pada token API atau koneksi server. Kode: ' + c, 'error');
                        $btn.text('Simpan & Sinkronkan Data').prop('disabled', false);
                    });
                });
            });
        });

        $(document).on('click', '#mip-open-editor', function() { $('#mip-editor').slideToggle(); });
        loadLinks();
    });
})();

(function() {
    // Fungsi utama suntik teks
    function forcePreload() {
        var ns = mw.config.get('wgNamespaceNumber');
        var pageExists = mw.config.get('wgArticleId') > 0;
        
        // Cek Namespace Utama & Halaman Baru
        if (ns === 0 && !pageExists) {
            // Cari textarea secara spesifik (Desktop & Mobile punya selector beda)
            var $textbox = $('#wpTextbox1, textarea.mw-ui-input, .editor-container textarea');
            
            if ($textbox.length && $textbox.val().trim() === "") {
                var pageName = mw.config.get('wgTitle');
                $textbox.val('{{Infobox umum\n|nama = ' + pageName + '\n}}');
                console.log("Mippedia: Infobox injected!");
            }
        }
    }

    // 1. Jalankan pas halaman beres load
    $(document).ready(forcePreload);

    // 2. Jalankan tiap ada klik (karena mobile buka editor pake klik tanpa refresh)
    $(document).on('click', function() {
        setTimeout(forcePreload, 800); // Kasih delay dikit nunggu overlay muncul
    });

    // 3. Pake MutationObserver buat mantau elemen yang baru muncul secara gaib
    var observer = new MutationObserver(function() {
        forcePreload();
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();

/* ==========================================================
   🚀 MIPPEDIA DATA - CONTENT GUARD (MODIFIED FOR RELATED)
   ========================================================== */
(function() {
    function handleBlock(e) {
        var ns = mw.config.get('wgNamespaceNumber');
        if (ns !== 0 || mw.config.get('wgIsMainPage')) return;

        var $el = $(e.currentTarget);
        
        if ($el.closest('.mw-parser-output').length && $el.text().toLowerCase().includes('buat item')) {
            return; 
        }

        var $textbox = $('#wpTextbox1, .editor-container textarea, textarea.mw-ui-input');
        
        if ($textbox.length) {
            var content = $textbox.val() || "";
            
            // Pengecekan: Harus ada {{Infobox ATAU setidaknya ada kode #related
            var hasInfobox = content.includes('{{Infobox');
            var hasRelated = content.includes('#related:');

            if (!hasInfobox && !hasRelated) {
                e.preventDefault();
                e.stopPropagation();
                e.stopImmediatePropagation();

                window.alert("SUNTINGAN ANDA TIDAK BISA DI TERBITKAN!\n\nMippedia Data bukan tempat untuk menulis artikel ensiklopedia, Jika anda ingin membuat artikel ensiklopedia bukan di sini tempat nya.\n");
                return false;
            }
        }
    }

    $(document).on('click mousedown touchstart', 
        '#wpSave, .editor-save, .mw-ui-button.primary, button[type="submit"], .save-button, .header-action button', 
        function(e) {
            handleBlock(e);
        }
    );

    window.addEventListener('submit', function(e) {
        handleBlock(e);
    }, true);
})();

/* ==========================================================
   🛡️ MIPPEDIA CORE SYSTEM - NEURAL ENGINE V12
   Update: Brain Upgrade - Semantic Search & Anti-Duplicate
   Semua fitur asli (Patroli, Promo, Kategori) tetap UTUH.
   ========================================================== */
mw.hook('postEdit').add(function() {
    var rawUser = mw.config.get('wgUserName');
    var userName = rawUser ? rawUser.replace(/_/g, ' ') : 'Anonim';
    var isPatroli = (userName === 'Admin');
    
    if (mw.config.get('wgNamespaceNumber') !== 0) return;

    var api = new mw.Api();
    var pageTitle = mw.config.get('wgPageName').replace(/_/g, ' ');

    api.get({
        action: 'query',
        titles: pageTitle,
        prop: 'revisions|categories|links',
        rvprop: 'content',
        clshow: '!hidden',
        pllimit: 'max'
    }).done(function(resData) {
        var page = resData.query.pages[Object.keys(resData.query.pages)[0]];
        if (!page || !page.revisions) return;

        var rawContent = page.revisions[0]['*'];
        var content = rawContent;
        var summaryParts = [];

        // --- 2. SUPER INTELLIGENCE RELATED (UPGRADE OTAK V12) ---
        // Cek jumlah related saat ini
        var currentRelatedMatch = content.match(/\{\{#related:.*?\}\}/g) || [];
        
        // Jika kurang dari 3, kita jalankan otak pencarian canggih
        if (currentRelatedMatch.length < 3) {
            // Hapus yang lama dulu agar tidak ada duplikat atau "pake yang bekas"
            content = content.replace(/\n*\{\{#related:.*?\}\}/g, '');

            // Langkah A: Ambil kandidat dari Search Engine (Ranking Skor)
            api.get({
                action: 'query',
                list: 'search',
                srsearch: pageTitle, // Gunakan judul sebagai basis pencarian semantic
                srlimit: 15,
                srprop: ''
            }).done(function(searchRes) {
                var candidates = {};

                // Masukkan hasil pencarian ke pool skor
                if (searchRes.query && searchRes.query.search) {
                    searchRes.query.search.forEach(function(item, index) {
                        if (item.title === pageTitle) return;
                        candidates[item.title] = (15 - index); // Skor berdasarkan urutan relevansi
                    });
                }

                // Langkah B: Tambah skor jika artikel ada di daftar Link Internal
                if (page.links) {
                    page.links.forEach(function(link) {
                        if (link.title === pageTitle) return;
                        candidates[link.title] = (candidates[link.title] || 0) + 5; // Bonus skor link
                    });
                }

                // Langkah C: Urutkan berdasarkan skor tertinggi (yang paling nyambung)
                var sortedTitles = Object.keys(candidates).sort(function(a, b) {
                    return candidates[b] - candidates[a];
                });

                // Ambil TOP 3
                var finalRelated = sortedTitles.filter(t => t.indexOf(':') === -1).slice(0, 3);

                if (finalRelated.length > 0) {
                    var relatedTags = '\n\n' + finalRelated.map(t => '{{#related: ' + t + '}}').join('\n');
                    content += relatedTags;
                    summaryParts.push('NeuralRelated');
                }
                
                runPatroliAndSave();
            });
        } else {
            runPatroliAndSave();
        }

        function runPatroliAndSave() {
            // --- 3. PATROLI ENGINE (FITUR ASLI - TETAP BERFUNGSI) ---
            if (isPatroli) {
                var placeholders = [];
                // Lindungi Brankas: Template, Header, Kategori, Ref, dan Kalimat Pembuka
                content = content.replace(/(\{\{[\s\S]*?\}\}|==+.*?==+|\[\[Kategori:.*?\]\]|<ref[\s\S]*?<\/ref>|^.*?adalah)/gi, function(match) {
                    placeholders.push(match);
                    return '___MIP_SKIP_' + (placeholders.length - 1) + '___';
                });

                // Proses Auto-Link (Wajib ambil daftar AllPages dulu)
                api.get({ action: 'query', list: 'allpages', apnamespace: 0, aplimit: 'max' }).done(function(apData) {
                    var allTitles = apData.query.allpages.map(p => p.title);
                    var lowerTitles = allTitles.map(t => t.toLowerCase());

                    var tokens = content.split(/(\s+|\[\[|\]\])/);
                    var inLink = false;
                    for (var i = 0; i < tokens.length; i++) {
                        if (tokens[i] === '[[' ) { inLink = true; continue; }
                        if (tokens[i] === ']]' ) { inLink = false; continue; }
                        if (inLink || tokens[i].trim().length < 3 || tokens[i].includes('___MIP_SKIP_')) continue;

                        var wordsInToken = tokens[i].match(/\b\w+\b/g);
                        if (wordsInToken) {
                            wordsInToken.forEach(function(word) {
                                var idx = lowerTitles.indexOf(word.toLowerCase());
                                if (idx !== -1 && allTitles[idx] !== pageTitle) {
                                    tokens[i] = tokens[i].replace(new RegExp('\\b' + word + '\\b', 'g'), '[[' + allTitles[idx] + '|' + word + ']]');
                                }
                            });
                        }
                    }
                    content = tokens.join('');
                    
                    // Kembalikan dari Brankas
                    content = content.replace(/___MIP_SKIP_(\d+)___/g, function(match, id) { return placeholders[id]; });

                    // Bersihkan Link Merah
                    content = content.replace(/\[\[([^|\]:]+)\]\]/g, function(match, p1) {
                        return lowerTitles.includes(p1.toLowerCase()) ? match : p1;
                    });

                    saveAction();
                });
            } else {
                saveAction();
            }
        }

        function saveAction() {
            // --- 4. EKSEKUSI ---
            if (content.trim() !== rawContent.trim()) {
                api.postWithToken('edit', {
                    action: 'edit',
                    title: pageTitle,
                    text: content,
                    summary: 'Mippedia Neural Engine V12: ' + summaryParts.join(', '),
                    bot: true, markasbot: true
                }).done(function() { location.reload(); });
            }
        }
    });
});

/* ==========================================================
   🌐 MIPPEDIA SHORTDESC - DATA CENTER (PREMIUM UI)
   Status: INDEPENDENT & REFINED VISUAL
   Storage: MediaWiki:ShortDesc-Data.json
   ========================================================== */
(function($, mw) {
    "use strict";
    $(document).ready(function() {
        if (mw.config.get('wgNamespaceNumber') !== 0 || mw.config.get('wgIsMainPage')) return;

        var pageTitle = mw.config.get('wgPageName');
        var storagePage = 'MediaWiki:ShortDesc-Data.json';
        var isAdmin = mw.config.get('wgUserGroups').some(g => ['sysop', 'interface-admin'].includes(g));

        var langs = {
            id: { label: 'Mippedia bahasa Indonesia', short: 'ID', color: '#6366f1' },
            en: { label: 'Mippedia bahasa Inggris', short: 'EN', color: '#3b82f6' },
            concise: { label: 'Mippedia bahasa Indonesia ringkas', short: 'CON', color: '#14b8a6' }
        };

        // UI Box dengan Spasi dan Desain Baru
        var html = `
            <div id="desc-manager" style="background:#ffffff; border:1px solid #f1f5f9; border-left:4px solid #6366f1; border-radius:12px; padding:20px; margin: 20px 0 25px 0; box-shadow:0 4px 12px rgba(0,0,0,0.03); font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
                <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:12px;">
                    <span style="font-size:13px; font-weight:700; color:#475569; text-transform:uppercase; letter-spacing:0.5px; display:flex; align-items:center; gap:6px;">
                        Label Deskripsi
                    </span>
                    <span id="desc-open-editor" style="cursor:pointer; padding:5px; transition:0.2s;" title="Edit Deskripsi">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
                    </span>
                </div>
                
                <div id="desc-status-display" style="display:flex; flex-direction:column; gap:8px;">
                    <small style="color:#94a3b8; font-style:italic;">Sinkronisasi data...</small>
                </div>

                <div id="desc-editor" style="display:none; margin-top:18px; border-top:1px dashed #e2e8f0; padding-top:18px;">
                    ${Object.keys(langs).map(k => `
                        <div style="margin-bottom:12px;">
                            <label style="display:block; font-size:11px; font-weight:bold; color:#64748b; margin-bottom:4px;">${langs[k].label}</label>
                            <input type="text" id="desc-in-${k}" placeholder="Tulis deskripsi..." style="width:100%; padding:10px; font-size:13px; border:1px solid #e2e8f0; border-radius:8px; box-sizing:border-box; outline:none; focus:border-color:#6366f1;">
                        </div>
                    `).join('')}
                    <button id="desc-save" style="width:100%; padding:12px; background:#6366f1; color:white; border:none; border-radius:8px; font-size:13px; font-weight:600; cursor:pointer; margin-top:5px;">Terbitkan</button>
                </div>
            </div>`;

        $('.mw-parser-output').prepend(html);

        function loadDescStatus() {
            new mw.Api().get({ action: 'query', prop: 'revisions', titles: storagePage, rvprop: 'content', formatversion: 2 }).done(function(res) {
                var content = res.query.pages[0].revisions ? res.query.pages[0].revisions[0].content : "{}";
                var fullData = JSON.parse(content);
                var myData = fullData[pageTitle] || {};
                var $statusBox = $('#desc-status-display').empty();
                var foundAny = false;

                Object.keys(langs).forEach(k => {
                    var val = myData[k];
                    if (val && val.trim() !== "") {
                        foundAny = true;
                        $statusBox.append(`
                            <div style="display:flex; align-items:center; gap:10px;">
                                <span style="background:${langs[k].color}15; color:${langs[k].color}; padding:3px 10px; border-radius:20px; font-size:10px; font-weight:800; border:1px solid ${langs[k].color}30; min-width:35px; text-align:center;">${langs[k].short}</span>
                                <span style="font-size:13px; color:#334155; line-height:1.4;">${val}</span>
                            </div>
                        `);
                        $('#desc-in-' + k).val(val);
                    }
                });

                if (!foundAny) {
                    $statusBox.html('<div style="color:#cbd5e0; font-size:13px; background:#f8fafc; padding:10px; border-radius:8px; border:1px dashed #e2e8f0;">Belum ada metadata deskripsi yang dikaitkan dengan entitas ini.</div>');
                }
            });
        }

        $(document).on('click', '#desc-open-editor', function() { $('#desc-editor').slideToggle(); });

        $(document).on('click', '#desc-save', function() {
            if (!isAdmin) { alert('Akses ditolak. Anda memerlukan izin pengurus.'); return; }
            var $btn = $(this).text('Proses Sinkronisasi...').css('opacity','0.7');
            var api = new mw.Api();
            var newData = { id: $('#desc-in-id').val().trim(), en: $('#desc-in-en').val().trim(), concise: $('#desc-in-concise').val().trim() };

            api.get({ action: 'query', prop: 'revisions', titles: storagePage, rvprop: 'content', formatversion: 2 }).done(function(r) {
                var json = r.query.pages[0].revisions ? JSON.parse(r.query.pages[0].revisions[0].content) : {};
                if (!newData.id && !newData.en && !newData.concise) { delete json[pageTitle]; } else { json[pageTitle] = newData; }

                api.postWithEditToken({
                    action: 'edit',
                    title: storagePage,
                    text: JSON.stringify(json, null, 2),
                    summary: 'Update Entity Description: ' + pageTitle
                }).done(function() { location.reload(); });
            });
        });

        loadDescStatus();
    });
})(jQuery, mediaWiki);

/* ==========================================================
   📍 MIPPEDIA DATA - ULTIMATE TEXT-TO-MAP LOCATOR
   Fitur: Deteksi lokasi dari teks dengan database label lengkap
   ========================================================== */
(function() {
    $(document).ready(function() {
        var locationText = "";
        
        // --- DAFTAR LABEL SUPER LENGKAP & MASUK AKAL ---
        var locationLabels = [
            // Umum & Geografis
            'lokasi', 'tempat', 'wilayah', 'daerah', 'koordinat', 'alamat',
            // Orang (Biografi)
            'tempat lahir', 'asal', 'kediaman', 'domisili', 'negara asal',
            // Organisasi & Perusahaan
            'kantor pusat', 'markas', 'cabang utama', 'titik operasi',
            // Makanan & Budaya
            'asal wilayah', 'daerah asal', 'negara sumber', 'kawasan',
            // Sejarah & Bangunan
            'letak', 'posisi', 'titik temu', 'orbit'
        ];

        // Jalankan pencarian di tabel data (infobox atau wikitable)
        $('.wikitable tr, .infobox tr, .mip-data-table tr').each(function() {
            var label = $(this).find('th').text().toLowerCase().trim();
            // Hilangkan karakter spesial kayak titik dua biar matching-nya akurat
            label = label.replace(/[:]/g, '');

            var isMatch = locationLabels.some(function(target) {
                return label === target || label.includes(target);
            });

            if (isMatch) {
                var rawValue = $(this).find('td').text().trim();
                // Ambil bagian utama sebelum tanda koma, kurung, atau titik koma
                // Misal: "Bandung, Jawa Barat" -> ambil "Bandung"
                locationText = rawValue.split(/[,(\[;]/)[0].trim(); 
                
                if (locationText.length > 2) return false; // Stop jika sudah ketemu yang valid
            }
        });

        // Eksekusi Render Peta
        if (locationText && locationText.length > 2) {
            var $mapWrapper = $('<div>').css({
                'margin': '15px 0',
                'padding': '12px',
                'border': '1px solid #ddd',
                'background': '#ffffff',
                'border-radius': '10px',
                'box-shadow': '0 4px 12px rgba(0,0,0,0.08)'
            });

            $mapWrapper.append('<div style="font-weight:bold; font-size:0.9em; margin-bottom:10px; color:#444; display:flex; align-items:center;">' +
                               '<span style="margin-right:8px;">🗺️</span>Pratinjau Lokasi : ' + locationText + '</div>');

            // Embed URL dengan pencarian teks (Nominatim)
            var embedUrl = "https://www.openstreetmap.org/export/embed.html?layer=mapnik&q=" + encodeURIComponent(locationText);

            var $iframe = $('<iframe>').attr({
                'src': embedUrl,
                'width': '100%',
                'height': '280',
                'frameborder': '0',
                'style': 'border-radius: 8px; border: 1px solid #eee;'
            });

            $mapWrapper.append($iframe);
            
            // Link eksternal yang lebih rapi
            var gMapsUrl = "https://www.google.com/maps/search/" + encodeURIComponent(locationText);
            $mapWrapper.append('<div style="text-align:right; margin-top:8px;">' +
                               '<a href="' + gMapsUrl + '" target="_blank" style="font-size:0.75em; color:#6a5acd; font-weight:bold; text-decoration:none; text-transform:uppercase; letter-spacing:0.5px;">Buka di Google Maps →</a></div>');

            // Masukkan ke bawah section deskripsi otomatis
            if ($('#mip-desc-section').length) {
                $('#mip-desc-section').after($mapWrapper);
            }
        }
    });
})();