Lompat ke isi

MediaWiki:Common.js: Perbedaan antara revisi

Dari Mippedia Data, basis data terbuka
Admin (bicara | kontrib)
Tidak ada ringkasan suntingan
Tanda: Suntingan perangkat seluler Suntingan peramban seluler
Admin (bicara | kontrib)
Tidak ada ringkasan suntingan
Tanda: Suntingan perangkat seluler Suntingan peramban seluler
Baris 2: Baris 2:
  * ====================================================================
  * ====================================================================
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE)
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE)
* Fitur Utama: Collapsible References, Direct Visit Links, Toast UI,
* Dark Mode Ready, Move Up/Down, Auto-Domain, 45+ Pro Features.
  * ====================================================================
  * ====================================================================
  */
  */
Baris 13: Baris 11:


     mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() {
     mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() {
       
         var pageName = mw.config.get('wgPageName');
         var pageName = mw.config.get('wgPageName');
         var isSysop = mw.config.get('wgUserGroups').indexOf('sysop') !== -1;
         var isSysop = mw.config.get('wgUserGroups').indexOf('sysop') !== -1;
Baris 20: Baris 17:
         var api = new mw.Api();
         var api = new mw.Api();


         // 1. DATA MASTER PLATFORM MEDIA SOSIAL & MUSIK (DIPERLUAS 20+ PLATFORM)
         // 1. DATA MASTER PLATFORM
         var SOCIAL_PLATFORMS = {
         var SOCIAL_PLATFORMS = {
             applemusic: { name: 'Apple Music', base: 'https://music.apple.com/artist/', color: '#fc3c44', icon: '🎵' },
             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: '🎧' },
             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: '☁️' },
             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>' },
            bandcamp: { name: 'Bandcamp', base: 'https://bandcamp.com/', color: '#1da0c3', icon: '🎸' },
             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><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg>' },
             instagram: { name: 'Instagram', base: 'https://instagram.com/', color: '#e1306c', icon: '📸' },
             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>' },
             tiktok: { name: 'TikTok', base: 'https://www.tiktok.com/@', color: '#000000', icon: '📱' },
             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>' },
            youtube: { name: 'YouTube', base: 'https://youtube.com/@', color: '#ff0000', icon: '▶️' },
             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>' },
             twitter: { name: 'X / Twitter', base: 'https://x.com/', color: '#0f1419', icon: '🐦' },
             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>'},
             threads: { name: 'Threads', base: 'https://www.threads.net/@', color: '#000000', icon: '🧵' },
             discord: { name: 'Discord', base: 'https://discord.gg/', color: '#5865F2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>'},
            facebook: { name: 'Facebook', base: 'https://facebook.com/', color: '#1877f2', icon: '📘' },
             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>' },
            linkedin: { name: 'LinkedIn', base: 'https://linkedin.com/in/', color: '#0a66c2', icon: '💼' },
             whatsapp: { name: 'WhatsApp', base: 'https://', color: '#25D366', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>'}
            github: { name: 'GitHub', base: 'https://github.com/', color: '#24292e', icon: '💻' },
            pinterest: { name: 'Pinterest', base: 'https://pinterest.com/', color: '#e60023', icon: '📌' },
             twitch: { name: 'Twitch', base: 'https://twitch.tv/', color: '#9146FF', icon: '🎮' },
            reddit: { name: 'Reddit', base: 'https://reddit.com/user/', color: '#FF4500', icon: '👽' },
             discord: { name: 'Discord', base: 'https://discord.com/users/', color: '#5865F2', icon: '👾' },
             telegram: { name: 'Telegram', base: 'https://t.me/', color: '#0088cc', icon: '✈️' },
             whatsapp: { name: 'WhatsApp Channel', base: 'https://whatsapp.com/channel/', color: '#25D366', icon: '💬' },
            patreon: { name: 'Patreon', base: 'https://patreon.com/', color: '#FF424D', icon: '🧡' },
            imdb: { name: 'IMDb', base: 'https://www.imdb.com/name/', color: '#F5C518', icon: '🎬' }
         };
         };


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


         var REF_TYPES = {
         var REF_TYPES = {
             "Berita": ["Berita Online", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus"],
             "Berita": ["Berita Online", "Berita Cetak", "Wawancara", "Liputan Khusus"],
             "Website": ["Situs Resmi", "Portal Informasi", "Database Web", "Portal Komunitas"],
             "Website": ["Situs Resmi", "Portal Informasi", "Database Web"],
             "Buku": ["Buku Cetak", "E-Book", "Bab / Bagian Buku", "Monograf", "Biografi"],
             "Buku": ["Buku Cetak", "E-Book", "Bab Buku", "Biografi"],
             "Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis / Disertasi"],
             "Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis / Disertasi"],
             "Siaran Pers": ["Siaran Pers Resmi", "Pengumuman Instansi", "Keterangan Manajemen"],
             "Media Sosial": ["Postingan", "Video Singkat", "Live Stream", "Thread"],
            "Dokumen": ["Dokumen PDF", "Laporan Tahunan", "Regulasi Resmi"],
             "Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists", "IMDb"],
             "Database": ["MusicBrainz", "Discogs", "IMDb", "Genius", "Wikipedia"],
             "Video & Podcast": ["YouTube", "Podcast", "Wawancara Audio"]
             "Video/Audio": ["YouTube Video", "Podcast", "Wawancara TV/Radio", "Dokumenter"],
            "Media Sosial": ["Postingan / Tweet", "Video Singkat", "Live Stream"]
        };
 
        // IKON SVG
        var icons = {
            edit: '<svg width="14" height="14" 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>',
            ref: '<svg 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>',
            visit: '<svg width="14" height="14" 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>',
            up: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="18 15 12 9 6 15"></polyline></svg>',
            down: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>',
            copy: '<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>'
         };
         };


         // 3. TOAST NOTIFICATION SYSTEM
         // 2. STYLESHEET (V8.0: Variabel CSS, Dark Mode, Animasi, Fluid UI)
        function showToast(message, type) {
            $('.md-toast').remove();
            var bg = type === 'error' ? '#ef4444' : (type === 'success' ? '#10b981' : '#3b82f6');
            var $toast = $('<div class="md-toast" 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 cubic-bezier(0.68, -0.55, 0.265, 1.55);">'+message+'</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);
        }
 
        // UTILITIES
        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'];
            return parseInt(parts[2], 10) + ' ' + months[parseInt(parts[1], 10) - 1] + ' ' + parts[0];
        }
 
        function extractDomain(urlStr) {
            try { return new URL(urlStr.startsWith('http') ? urlStr : 'https://'+urlStr).hostname.replace(/^www\./, ''); }
            catch(e) { return urlStr.split('/')[0]; }
        }
 
        function ensureHttps(urlStr) {
            return (urlStr && !urlStr.match(/^https?:\/\//i)) ? 'https://' + urlStr.trim() : urlStr.trim();
        }
 
        // 4. CSS MODERN & ANIMASI V8.0
         var css = `
         var css = `
             :root {
             :root {
                 --md-bg: #ffffff; --md-border: #e2e8f0; --md-text: #0f172a; --md-text-muted: #64748b;
                 --md-bg: #ffffff; --md-bg-sec: #f8fafc; --md-border: #e2e8f0;
                 --md-primary: #4f46e5; --md-primary-hover: #4338ca; --md-surface: #f8fafc;
                --md-text: #0f172a; --md-text-muted: #64748b;  
                 --md-radius: 12px; --md-transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
                 --md-primary: #4f46e5; --md-primary-hover: #4338ca;
                --md-card-bg: #ffffff; --md-hover-bg: #faf5ff;
                 --md-danger: #dc2626; --md-success: #16a34a;
                --md-shadow: 0 4px 24px rgba(0,0,0,0.06);
             }
             }
             @media (prefers-color-scheme: dark) {
             @media (prefers-color-scheme: dark) {
                 :root {
                 :root {
                     --md-bg: #1e293b; --md-border: #334155; --md-text: #f8fafc; --md-text-muted: #94a3b8;
                     --md-bg: #1e293b; --md-bg-sec: #0f172a; --md-border: #334155;
                     --md-surface: #0f172a; --md-primary: #6366f1;
                    --md-text: #f8fafc; --md-text-muted: #94a3b8;  
                     --md-primary: #6366f1; --md-primary-hover: #818cf8;
                    --md-card-bg: #1e293b; --md-hover-bg: #312e81;
                    --md-shadow: 0 4px 24px rgba(0,0,0,0.3);
                 }
                 }
            }
            #mippedia-data-app {
                background: var(--md-bg); border-radius: 16px; box-shadow: 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); box-sizing: border-box; overflow: hidden; color: var(--md-text);
             }
             }
              
              
             #mippedia-data-app { background: var(--md-bg); border-radius: var(--md-radius); box-shadow: 0 10px 30px -10px rgba(0,0,0,0.1); padding: 20px; margin: 20px 0; border: 1px solid var(--md-border); font-family: system-ui, sans-serif; color: var(--md-text); }
             .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); }
            .md-title { font-size: 1.25rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 8px; color: var(--md-text); }
            .md-actions { display: flex; gap: 8px; flex-wrap: wrap; }
              
              
            /* Baris Data */
             .md-btn-icon {
             .md-row-display { display: flex; justify-content: space-between; align-items: flex-start; padding: 16px; border: 1px solid var(--md-border); border-radius: var(--md-radius); margin-bottom: 12px; background: var(--md-surface); transition: var(--md-transition); }
                background: var(--md-bg-sec); border: 1px solid var(--md-border); cursor: pointer; color: var(--md-primary);
             .md-row-display:hover { border-color: var(--md-primary); box-shadow: 0 4px 12px rgba(79,70,229,0.08); transform: translateY(-2px); }
                padding: 8px 14px; border-radius: 8px; transition: all 0.2s ease; display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600;
             .md-data-label { font-size: 0.75rem; color: var(--md-text-muted); font-weight: 800; text-transform: uppercase; letter-spacing: 0.5px; }
            }
            .md-data-value { font-size: 1.1rem; font-weight: 600; margin-top: 4px; display: inline-block; word-break: break-word; }
             .md-btn-icon:hover { background: var(--md-border); transform: translateY(-1px); }
             .md-data-value a { color: var(--md-primary); text-decoration: none; border-bottom: 2px solid transparent; transition: var(--md-transition); }
 
             .md-data-value a:hover { border-bottom-color: var(--md-primary); }
            /* Highlight Pencarian */
             .md-search-box { position: relative; margin-bottom: 16px; }
            .md-search-input { width: 100%; padding: 10px 14px 10px 34px; border: 1px solid var(--md-border); border-radius: 8px; font-size: 0.9rem; background: var(--md-bg-sec); color: var(--md-text); transition: 0.2s; box-sizing: border-box;}
             .md-search-input:focus { 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-muted); }
            mark.md-highlight { background: #fef08a; color: #854d0e; padding: 0 2px; border-radius: 2px; }


            /* Referensi Collapsible V8 */
             .md-row-display {
             .md-ref-container { margin-top: 12px; }
                display: flex; justify-content: space-between; align-items: flex-start;
            .md-ref-summary { background: rgba(79,70,229,0.08); color: var(--md-primary); padding: 8px 14px; border-radius: 8px; cursor: pointer; display: flex; align-items: center; justify-content: space-between; font-size: 0.85rem; font-weight: 700; transition: var(--md-transition); border: 1px solid rgba(79,70,229,0.1); }
                padding: 16px 14px; border-bottom: 1px solid var(--md-border); transition: all 0.2s;
             .md-ref-summary:hover { background: rgba(79,70,229,0.15); }
                border-radius: 12px; gap: 12px; margin-bottom: 8px; background: var(--md-card-bg);
            .md-ref-icon-rot { transition: transform 0.3s ease; }
            }
            .md-ref-icon-rot.open { transform: rotate(180deg); }
             .md-row-display:hover { background: var(--md-hover-bg); box-shadow: inset 4px 0 0 var(--md-primary); }
             .md-ref-content { display: none; padding: 14px; border: 1px solid var(--md-border); border-top: none; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; background: var(--md-bg); font-size: 0.85rem; }
           
             .md-ref-grid-info { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; margin-bottom: 12px; }
             .md-data-group { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
             .md-ref-lbl { color: var(--md-text-muted); font-weight: 600; }
            .md-data-label { font-size: 0.72rem; color: var(--md-text-muted); font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; }
             .md-ref-val { color: var(--md-text); font-weight: 500; }
             .md-data-value { font-size: 1.05rem; font-weight: 600; word-break: break-word; color: var(--md-text); }
             .md-data-value a { color: var(--md-primary); text-decoration: none; }
             .md-data-value a:hover { text-decoration: underline; }
              
              
             /* Tombol Aksi */
             /* TOAST NOTIFICATION */
             .md-btn-visit { display: inline-flex; align-items: center; gap: 6px; background: var(--md-primary); color: white !important; padding: 6px 12px; border-radius: 6px; text-decoration: none !important; font-weight: 600; transition: var(--md-transition); box-shadow: 0 2px 8px rgba(79,70,229,0.3); }
             #md-toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; }
             .md-btn-visit:hover { background: var(--md-primary-hover); transform: scale(1.02); }
            .md-toast { background: #1e293b; color: #fff; padding: 12px 20px; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); display: flex; align-items: center; gap: 10px; font-size: 0.9rem; font-weight: 600; animation: slideIn 0.3s forwards; }
            @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
            @keyframes fadeOut { to { opacity: 0; transform: translateY(10px); } }
 
            /* AKORDEON REFERENSI (V8.0) */
            .md-ref-wrapper { margin-top: 10px; background: var(--md-bg-sec); border: 1px solid var(--md-border); border-radius: 10px; overflow: hidden; }
            .md-ref-header-bar { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; cursor: pointer; transition: 0.2s; }
            .md-ref-header-bar:hover { background: var(--md-border); }
            .md-ref-title-sm { font-size: 0.8rem; font-weight: 700; color: var(--md-primary); display: flex; align-items: center; gap: 6px; }
             .md-ref-toggle-icon { transition: transform 0.3s; color: var(--md-text-muted); }
            .md-ref-header-bar.is-open .md-ref-toggle-icon { transform: rotate(180deg); }
              
              
             .md-row-actions { display: flex; flex-direction: column; gap: 6px; opacity: 0.5; transition: var(--md-transition); }
             .md-ref-collapse { display: none; padding: 0 14px 14px 14px; border-top: 1px dashed var(--md-border); }
             .md-row-display:hover .md-row-actions { opacity: 1; }
             .md-ref-detail-row { display: flex; gap: 8px; font-size: 0.85rem; margin-top: 6px; color: var(--md-text); }
             .md-btn-small { background: var(--md-bg); border: 1px solid var(--md-border); color: var(--md-text-muted); cursor: pointer; padding: 6px; border-radius: 6px; display: flex; transition: var(--md-transition); }
             .md-ref-lbl { font-weight: 700; color: var(--md-text-muted); white-space: nowrap; }
             .md-btn-small:hover { color: var(--md-primary); border-color: var(--md-primary); background: rgba(79,70,229,0.05); }
            .md-ref-actions-row { display: flex; gap: 8px; margin-top: 12px; }
            .md-btn-visit { background: var(--md-primary); color: white; padding: 6px 12px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; gap: 5px; transition: 0.2s; border: none; }
             .md-btn-visit:hover { background: var(--md-primary-hover); transform: translateY(-1px); color: white; text-decoration: none;}


            /* Media Sosial */
             .md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
             .md-social-group { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
             .md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; color: white; text-decoration: none; transition: 0.2s; }
             .md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 20px; font-size: 0.8rem; font-weight: 600; color: white !important; text-decoration: none !important; transition: var(--md-transition); box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
             .md-social-badge:hover { transform: translateY(-2px); filter: brightness(1.1); color: white; text-decoration:none;}
             .md-social-badge:hover { transform: translateY(-3px) scale(1.03); box-shadow: 0 5px 12px rgba(0,0,0,0.2); filter: brightness(1.1); }


             /* Input & Form */
             /* FORM UI */
             .md-input, .md-select { width: 100%; padding: 10px 14px; border: 2px solid var(--md-border); border-radius: 8px; background: var(--md-bg); color: var(--md-text); font-size: 0.9rem; transition: var(--md-transition); box-sizing: border-box; }
            .md-form-box { background: var(--md-bg); border-radius: 12px; padding: 20px; margin-top: 20px; border: 1px solid var(--md-border); box-shadow: var(--md-shadow); }
             .md-input:focus { border-color: var(--md-primary); outline: none; box-shadow: 0 0 0 4px rgba(79,70,229,0.1); }
             .md-input, .md-select, .md-textarea { width: 100%; padding: 10px 14px; border: 1px solid var(--md-border); border-radius: 8px; background: var(--md-bg-sec); color: var(--md-text); font-size: 0.9rem; transition: 0.2s; box-sizing: border-box; }
             .md-input.error { border-color: #ef4444; background: #fef2f2; }
             .md-input:focus, .md-select:focus, .md-textarea:focus { border-color: var(--md-primary); outline: none; }
            .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-save { background: linear-gradient(135deg, var(--md-primary), var(--md-primary-hover)); flex: 1; }
            .md-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
             .md-btn:disabled { opacity: 0.7; cursor: not-allowed; transform: none; }
              
              
             .md-form-box { background: var(--md-surface); padding: 20px; border-radius: var(--md-radius); border: 1px solid var(--md-border); margin-top: 20px; animation: slideIn 0.3s ease-out; }
             .md-spinner { display: none; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.4); border-radius: 50%; border-top-color: #fff; animation: md-spin 0.8s linear infinite; }
             @keyframes slideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
             .is-loading .md-spinner { display: inline-block; }
            @keyframes md-spin { to { transform: rotate(360deg); } }


             @media (max-width: 600px) {
             @media (max-width: 600px) {
                 .md-row-display { flex-direction: column; }
                 .md-ref-header-bar { flex-direction: column; align-items: flex-start; gap: 8px; }
                 .md-row-actions { flex-direction: row; margin-top: 10px; width: 100%; justify-content: flex-end; opacity: 1; }
                 .md-actions, .md-form-actions { width: 100%; justify-content: stretch; }
                 .md-ref-grid-info { grid-template-columns: 1fr; gap: 2px; }
                 .md-btn { width: 100%; }
             }
             }
             .md-native-render { display: none; }
             .md-native-render { display: none; }
         `;
         `;
         $('<style>').text(css).appendTo('head');
         $('<style>').text(css).appendTo('head');
        $('body').append('<div id="md-toast-container"></div>');
        // 3. HELPER FUNCTIONS
        var ICONS = {
            edit: '<svg 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>',
            ref: '<svg 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>',
            link: '<svg width="14" height="14" 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>',
            chevronDown: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>',
            check: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg>',
            copy: '<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>'
        };
        function showToast(message, type) {
            type = type || 'info';
            var bg = type === 'success' ? '#16a34a' : type === 'error' ? '#dc2626' : '#4f46e5';
            var $toast = $('<div class="md-toast" style="background:'+bg+';">' + message + '</div>');
            $('#md-toast-container').append($toast);
            setTimeout(function() { $toast.css('animation', 'fadeOut 0.3s forwards'); setTimeout(function(){ $toast.remove(); },300); }, 3500);
        }
        function escapeHTML(str) { return $('<div>').text(str).html(); }
       
        function getTodayString() { return new Date().toISOString().split('T')[0]; }


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


         function saveData(actionType, $btnEl, rawContent) {
        function buildWikitextVal(item) { /* Logic wikilink standar */ return item.val; }
             if ($btnEl) { $btnEl.html('<span style="animation: spin 1s linear infinite;">⏳</span> Menyimpan...').prop('disabled', true); }
        function buildWikitextRef(ref) { /* Logic wikitext ref standar */ return ref ? (ref.url ? "["+ref.url+" "+(ref.title||"Rujukan")+"]" : (ref.title||"")) : ""; }
 
         function saveData(actionType, $btnEl, originalContent) {
             if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
             var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems });
             var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems });
             var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n<div class=\"md-native-render\">{| class=\"wikitable\"\n! Data !! Nilai !! Referensi\n";
             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 + " || " + item.val + " || " + (item.ref ? (item.ref.url || "Ref") : "") + "\n"; });
             dataItems.forEach(function(item) { wt += "|-\n| " + item.prop + " || " + item.val + " || " + (item.ref ? (item.ref.url||item.ref.title) : "") + "\n"; });
             wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";
             wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";


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


             api.postWithToken('csrf', { action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V8: ' + actionType }).done(function() {
             api.postWithToken('csrf', { action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V8: ' + actionType, minor: false })
                showToast("Data berhasil disimpan! Memuat ulang...", "success");
            .done(function() { localStorage.removeItem('md_draft_' + pageName); location.reload(); })
                setTimeout(function(){ window.location.href = location.pathname + "?refresh=" + Date.now(); }, 1000);
             .fail(function(err) { if ($btnEl) $btnEl.removeClass('is-loading').prop('disabled', false); showToast("Gagal menyimpan: " + err, 'error'); });
             }).fail(function() { showToast("Gagal menyimpan data!", "error"); if($btnEl) $btnEl.prop('disabled', false).text('Coba Lagi'); });
         }
         }


         // 6. BUILDER UI
         // 4. MAIN UI BUILDER
         function buildUI(rawContent) {
         function buildUI(rawContent) {
             var $app = $('<div id="mippedia-data-app"></div>');
             var $app = $('<div id="mippedia-data-app"></div>');
             var $header = $('<div style="display:flex; justify-content:space-between; margin-bottom:15px; flex-wrap:wrap; gap:10px;"><h3 style="margin:0;">Data Terstruktur</h3><div id="md-top-actions"></div></div>');
             var $header = $('<div class="md-header"><h3 class="md-title">' + ICONS.edit + ' Data Terstruktur</h3><div class="md-actions"><button class="md-btn-icon" id="md-add-btn">' + ICONS.edit + ' Tambah</button></div></div>');
             $app.append($header);
             $app.append($header);


             var $actions = $header.find('#md-top-actions');
            // Search
            $actions.append('<button class="md-btn-small md-add-btn" style="background:var(--md-primary); color:white; padding:8px 16px;">' + icons.edit + ' Tambah Data</button>');
             var $search = $('<div class="md-search-box"><span class="md-search-icon">' + ICONS.ref + '</span><input type="text" class="md-search-input" placeholder="Cari data (sorot otomatis)..."></div>');
              
            $search.find('input').on('input', function() {
             var $list = $('<div id="md-data-list"></div>');
                var q = $(this).val().toLowerCase();
           
                $('.md-row-display').each(function() { $(this).toggle($(this).text().toLowerCase().indexOf(q) > -1); });
            });
            $app.append($search);
 
             // List
             var $list = $('<div class="md-list"></div>');
             dataItems.forEach(function(item, index) {
             dataItems.forEach(function(item, index) {
                 var $row = $('<div class="md-row-display"></div>');
                 var $row = $('<div class="md-row-display"></div>');
                 var $info = $('<div style="flex:1; width:100%;"></div>');
                 var $info = $('<div class="md-data-group"><span class="md-data-label">' + escapeHTML(item.prop) + '</span></div>');
                $info.append('<div class="md-data-label">' + item.prop + '</div>');
                  
                  
                 var displayVal = item.val;
                // Nilai & Salin
                if(item.link) displayVal = '<a href="' + mw.util.getUrl(item.val) + '">' + item.val + '</a>';
                 var $valWrap = $('<div style="display:flex; gap:8px; align-items:center;"><span class="md-data-value">' + escapeHTML(item.val) + '</span></div>');
                 $info.append('<div class="md-data-value">' + displayVal + ' <span class="md-btn-small copy-val" style="display:inline-flex; padding:2px; border:none;" title="Salin">' + icons.copy + '</span></div>');
                 var $copy = $('<button class="md-btn-icon" style="padding:4px; border:none; background:transparent;">' + ICONS.copy + '</button>');
                  
                $copy.on('click', function() { navigator.clipboard.writeText(item.val); $(this).html(ICONS.check); showToast("Berhasil disalin!", "success"); setTimeout(()=>$(this).html(ICONS.copy), 1500); });
                 // SOCIALS
                $valWrap.append($copy);
                 $info.append($valWrap);
 
                 // Media Sosial
                 if (item.isPersonOrg && item.socials) {
                 if (item.isPersonOrg && item.socials) {
                     var $soc = $('<div class="md-social-group"></div>');
                     var $socGroup = $('<div class="md-social-group"></div>');
                     Object.keys(item.socials).forEach(function(k) {
                     Object.keys(item.socials).forEach(k => {
                         if(SOCIAL_PLATFORMS[k]) {
                         if(SOCIAL_PLATFORMS[k]) {
                             var p = SOCIAL_PLATFORMS[k];
                             var p = SOCIAL_PLATFORMS[k];
                             $soc.append('<a class="md-social-badge" href="' + p.base + item.socials[k].replace(/^@/,'') + '" target="_blank" style="background:'+p.color+';">' + p.icon + ' ' + p.name + '</a>');
                             $socGroup.append('<a href="'+p.base+item.socials[k].replace('@','')+'" target="_blank" class="md-social-badge" style="background:'+p.color+';">'+p.icon+' '+p.name+'</a>');
                         }
                         }
                     });
                     });
                     $info.append($soc);
                     $info.append($socGroup);
                 }
                 }


                 // REFERENSI (SISTEM ACCORDION BARU)
                 // AKORDEON REFERENSI (FITUR UTAMA)
                 if (item.ref && (item.ref.title || item.ref.url)) {
                 if (item.ref && (item.ref.title || item.ref.url)) {
                     var $refWrap = $('<div class="md-ref-container"></div>');
                     var $refWrap = $('<div class="md-ref-wrapper"></div>');
                    var refTitleDisplay = item.ref.title || (item.ref.url ? extractDomain(item.ref.url) : "Sumber");
                     var $refHead = $('<div class="md-ref-header-bar"><div class="md-ref-title-sm">' + ICONS.ref + ' ' + escapeHTML(item.ref.title || 'Sumber Rujukan') + '</div><div class="md-ref-toggle-icon">' + ICONS.chevronDown + '</div></div>');
                   
                     var $refBody = $('<div class="md-ref-collapse"></div>');
                     var $summary = $('<div class="md-ref-summary"><span>' + icons.ref + ' Referensi: ' + refTitleDisplay + '</span> <span class="md-ref-icon-rot">▼</span></div>');
                    var $content = $('<div class="md-ref-content"></div>');
                   
                    var $grid = $('<div class="md-ref-grid-info"></div>');
                    if(item.ref.author) $grid.append('<div class="md-ref-lbl">Penulis</div><div class="md-ref-val">' + item.ref.author + '</div>');
                    if(item.ref.site) $grid.append('<div class="md-ref-lbl">Situs</div><div class="md-ref-val">' + item.ref.site + '</div>');
                    if(item.ref.publisher) $grid.append('<div class="md-ref-lbl">Penerbit</div><div class="md-ref-val">' + item.ref.publisher + '</div>');
                    if(item.ref.date) $grid.append('<div class="md-ref-lbl">Diakses</div><div class="md-ref-val">' + formatIndonesianDate(item.ref.date) + '</div>');
                     if(item.ref.type) $grid.append('<div class="md-ref-lbl">Kategori</div><div class="md-ref-val"><span style="background:#e2e8f0; color:#334155; padding:2px 8px; border-radius:12px; font-size:0.75rem;">' + item.ref.type + '</span></div>');
                      
                      
                     $content.append($grid);
                     if (item.ref.author) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penulis:</span> ' + escapeHTML(item.ref.author) + '</div>');
                    if (item.ref.publisher) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penerbit:</span> ' + escapeHTML(item.ref.publisher) + '</div>');
                    if (item.ref.date) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Diakses:</span> ' + escapeHTML(item.ref.date) + '</div>');
                      
                      
                     if(item.ref.url) {
                     if (item.ref.url) {
                         $content.append('<div style="margin-top:10px; border-top:1px dashed var(--md-border); padding-top:10px;"><a href="' + ensureHttps(item.ref.url) + '" target="_blank" class="md-btn-visit">' + icons.visit + ' Kunjungi Link Website</a></div>');
                         $refBody.append('<div class="md-ref-actions-row"><a href="'+escapeHTML(item.ref.url)+'" target="_blank" class="md-btn-visit">' + ICONS.link + ' Kunjungi Situs Terkait</a></div>');
                     }
                     }


                    // Logika Accordion Toggle
                     $refHead.on('click', function() { $(this).toggleClass('is-open'); $refBody.slideToggle(250); });
                     $summary.on('click', function() {
                     $refWrap.append($refHead).append($refBody);
                        $content.slideToggle(250);
                        $(this).find('.md-ref-icon-rot').toggleClass('open');
                    });
 
                     $refWrap.append($summary).append($content);
                     $info.append($refWrap);
                     $info.append($refWrap);
                 }
                 }


                 $row.append($info);
                 $row.append($info);
 
                 var $editBtn = $('<button class="md-btn-icon">Edit</button>').on('click', function() { showForm(index, rawContent); });
                // Row Actions (Edit, Move Up, Move Down, Delete)
                 $row.append($editBtn);
                 var $rowActs = $('<div class="md-row-actions"></div>');
                var $btnEdit = $('<button class="md-btn-small" title="Edit">' + icons.edit + '</button>');
                $btnEdit.on('click', function() { showForm(index, rawContent); });
               
                var $btnUp = $('<button class="md-btn-small" title="Geser ke Atas">' + icons.up + '</button>');
                $btnUp.on('click', function() { if(index > 0) swap(index, index-1, rawContent); });
               
                var $btnDown = $('<button class="md-btn-small" title="Geser ke Bawah">' + icons.down + '</button>');
                $btnDown.on('click', function() { if(index < dataItems.length-1) swap(index, index+1, rawContent); });
 
                $rowActs.append($btnEdit).append($btnUp).append($btnDown);
                 $row.append($rowActs);
                 $list.append($row);
                 $list.append($row);
                // Copy Value Event
                $row.find('.copy-val').on('click', function() {
                    navigator.clipboard.writeText(item.val);
                    showToast("Teks disalin: " + item.val, "success");
                });
             });
             });


             $app.append($list);
             $app.append($list).append('<div id="md-form-container"></div>');
            $app.append('<div id="md-form-container"></div>');
            var $infobox = $('.infobox').first();
 
             $('.md-native-render').hide();
             $('.md-native-render').hide();
             if ($('.infobox').length) $app.insertAfter($('.infobox').first());
             if ($infobox.length) $app.insertAfter($infobox); else $('#mw-content-text .mw-parser-output').append($app);
            else $('#mw-content-text .mw-parser-output').append($app);


             $app.find('.md-add-btn').on('click', function() { showForm(-1, rawContent); });
            // Binding Tombol Tambah
             $('#md-add-btn').on('click', function() { showForm(-1, rawContent); });
         }
         }


        function swap(idx1, idx2, rawContent) {
         // 5. FORM EDIT & DRAFT SYSTEM
            var temp = dataItems[idx1];
            dataItems[idx1] = dataItems[idx2];
            dataItems[idx2] = temp;
            saveData('Reorder urutan data', null, rawContent);
        }
 
         // 7. FORM EDITOR V8
         function showForm(index, rawContent) {
         function showForm(index, rawContent) {
             var $c = $('#md-form-container').empty();
             var $container = $('#md-form-container').empty();
             var isNew = index === -1;
             var item = index > -1 ? dataItems[index] : { prop:'', val:'', ref:{}, isPersonOrg:false, socials:{} };
            var d = isNew ? { prop: '', val: '', link: false, ref: {}, isPersonOrg: false, socials: {} } : dataItems[index];
           
 
             var $form = $('<div class="md-form-box"><h4>' + (index > -1 ? 'Edit Data' : 'Tambah Data Baru') + '</h4></div>');
             var $f = $('<div class="md-form-box"><h4>' + (isNew ? 'Tambah Data Baru' : 'Edit Data') + '</h4></div>');
              
              
             $f.append('<label style="font-size:0.8rem; font-weight:700;">Label (Contoh: Pekerjaan)</label><input type="text" id="fm-prop" class="md-input" style="margin-bottom:10px;" value="' + (d.prop||'') + '">');
             $form.append('<label>Label Data</label><input type="text" id="md-inp-prop" class="md-input" value="'+escapeHTML(item.prop)+'" style="margin-bottom:10px;">');
            $f.append('<label style="font-size:0.8rem; font-weight:700;">Nilai Data</label><input type="text" id="fm-val" class="md-input" style="margin-bottom:10px;" value="' + (d.val||'') + '">');
             $form.append('<label>Nilai Data</label><input type="text" id="md-inp-val" class="md-input" value="'+escapeHTML(item.val)+'" style="margin-bottom:15px;">');
             $f.append('<label style="font-size:0.85rem; display:flex; gap:8px; margin-bottom:15px; cursor:pointer;"><input type="checkbox" id="fm-link" '+(d.link?'checked':'')+'> Jadikan Tautan Wiki (Wikilink)</label>');
 
            // REFERENSI EDITOR
            var $refArea = $('<div style="background:rgba(0,0,0,0.02); padding:15px; border-radius:8px; margin-bottom:15px; border:1px solid var(--md-border);"><h5>Sumber Referensi</h5></div>');
            $refArea.append('<input type="url" id="fm-ref-url" class="md-input" placeholder="URL Lengkap (https://...)" style="margin-bottom:8px;" value="'+(d.ref?.url||'')+'">');
            $refArea.append('<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-bottom:8px;"><input type="text" id="fm-ref-title" class="md-input" placeholder="Judul Artikel" value="'+(d.ref?.title||'')+'"><input type="text" id="fm-ref-site" class="md-input" placeholder="Nama Situs" value="'+(d.ref?.site||'')+'"></div>');
            $refArea.append('<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-bottom:8px;"><input type="text" id="fm-ref-author" class="md-input" placeholder="Penulis" value="'+(d.ref?.author||'')+'"><input type="date" id="fm-ref-date" class="md-input" value="'+(d.ref?.date||'')+'"></div>');
              
              
             // Auto Domain Fill
             // Ref Area (Simplified for space in this code, full implementation identical logic)
             $refArea.find('#fm-ref-url').on('blur', function() {
             $form.append('<h5>Detail Referensi (Opsional)</h5>');
                var url = $(this).val();
            $form.append('<input type="text" id="md-ref-title" class="md-input" placeholder="Judul Artikel/Buku" value="'+escapeHTML(item.ref.title||'')+'" style="margin-bottom:10px;">');
                if(url && !$('#fm-ref-site').val()) { $('#fm-ref-site').val(extractDomain(url)); showToast("Situs otomatis terdeteksi", "success"); }
            $form.append('<input type="url" id="md-ref-url" class="md-input" placeholder="https://..." value="'+escapeHTML(item.ref.url||'')+'" style="margin-bottom:15px;">');
            });
            $f.append($refArea);


             var $actions = $('<div style="display:flex; gap:10px; margin-top:20px;"></div>');
             var $actions = $('<div style="display:flex; gap:10px; margin-top:20px;"></div>');
             var $btnSave = $('<button class="md-btn-visit" style="flex:1; justify-content:center; cursor:pointer; border:none; padding:10px;">Simpan Data</button>');
             var $btnSave = $('<button class="md-btn md-btn-save">Simpan <span class="md-spinner"></span></button>');
            var $btnCancel = $('<button class="md-btn-visit" style="background:#64748b; cursor:pointer; border:none; padding:10px;">Batal</button>');
             var $btnCancel = $('<button class="md-btn" style="background:var(--md-text-muted);">Batal</button>');
              
            $actions.append($btnSave).append($btnCancel);
            if (!isNew) {
                var $btnDel = $('<button class="md-btn-visit" style="background:#ef4444; margin-left:auto; cursor:pointer; border:none; padding:10px;">Hapus</button>');
                $btnDel.on('click', function() { if(confirm('Hapus data ini?')) { dataItems.splice(index, 1); saveData('Hapus data', $(this), rawContent); }});
                $actions.append($btnDel);
            }
            $f.append($actions);
            $c.append($f);


             $btnCancel.on('click', function() { $c.empty(); });
             $btnCancel.on('click', () => $container.empty());
             $btnSave.on('click', function() {
             $btnSave.on('click', function() {
                 var p = $('#fm-prop').val().trim();
                 if(!$('#md-inp-prop').val() || !$('#md-inp-val').val()) { showToast("Label dan Nilai wajib diisi!", "error"); return; }
                 var v = $('#fm-val').val().trim();
               
                if(!p || !v) { $('#fm-prop, #fm-val').addClass('error'); showToast('Label dan Nilai wajib diisi!', 'error'); return; }
                 var newItem = {
                    prop: $('#md-inp-prop').val().trim(),
                    val: $('#md-inp-val').val().trim(),
                    ref: { title: $('#md-ref-title').val().trim(), url: $('#md-ref-url').val().trim() }
                };
                if(index > -1) dataItems[index] = newItem; else dataItems.push(newItem);
                saveData((index > -1 ? 'Edit' : 'Tambah') + ' data', $(this), rawContent);
            });


                var refObj = { url: $('#fm-ref-url').val(), title: $('#fm-ref-title').val(), site: $('#fm-ref-site').val(), author: $('#fm-ref-author').val(), date: $('#fm-ref-date').val() };
            $actions.append($btnSave).append($btnCancel);
                Object.keys(refObj).forEach(k => { if(!refObj[k]) delete refObj[k]; });
            $form.append($actions);
            $container.append($form);


                var newItem = { prop: p, val: v, link: $('#fm-link').is(':checked'), isPersonOrg: d.isPersonOrg, socials: d.socials, ref: Object.keys(refObj).length ? refObj : null };
            // Auto-scroll smooth
                isNew ? dataItems.push(newItem) : dataItems[index] = newItem;
            $('html, body').animate({ scrollTop: $form.offset().top - 80 }, 300);
                saveData(isNew ? 'Tambah data' : 'Edit data', $(this), rawContent);
            });
         }
         }


         loadData().then(function(rawContent) { buildUI(rawContent); });
        // INIT
         loadData().then(rawContent => buildUI(rawContent));
     });
     });
})(jQuery, mediaWiki);
})(jQuery, mediaWiki);



Revisi per 18 Agustus 2026 01.00

/**
 * ====================================================================
 * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE)
 * ====================================================================
 */
(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();

        // 1. DATA MASTER PLATFORM
        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>' },
            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>' },
            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><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></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>' },
            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>' },
            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>'},
            discord: { name: 'Discord', base: 'https://discord.gg/', color: '#5865F2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></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>' },
            whatsapp: { name: 'WhatsApp', base: 'https://', color: '#25D366', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>'}
        };

        var PRESET_LABELS = [
            "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan", "Kebangsaan", 
            "Genre", "Instrumen", "Label Rekaman", "Tahun Aktif", "Situs Web Resmi", 
            "Pasangan", "Orang Tua", "Pendidikan", "Agama", "Almamater", "Penghargaan", "Afiliasi"
        ];

        var REF_TYPES = {
            "Berita": ["Berita Online", "Berita Cetak", "Wawancara", "Liputan Khusus"],
            "Website": ["Situs Resmi", "Portal Informasi", "Database Web"],
            "Buku": ["Buku Cetak", "E-Book", "Bab Buku", "Biografi"],
            "Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis / Disertasi"],
            "Media Sosial": ["Postingan", "Video Singkat", "Live Stream", "Thread"],
            "Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists", "IMDb"],
            "Video & Podcast": ["YouTube", "Podcast", "Wawancara Audio"]
        };

        // 2. STYLESHEET (V8.0: Variabel CSS, Dark Mode, Animasi, Fluid UI)
        var css = `
            :root {
                --md-bg: #ffffff; --md-bg-sec: #f8fafc; --md-border: #e2e8f0;
                --md-text: #0f172a; --md-text-muted: #64748b; 
                --md-primary: #4f46e5; --md-primary-hover: #4338ca;
                --md-card-bg: #ffffff; --md-hover-bg: #faf5ff;
                --md-danger: #dc2626; --md-success: #16a34a;
                --md-shadow: 0 4px 24px rgba(0,0,0,0.06);
            }
            @media (prefers-color-scheme: dark) {
                :root {
                    --md-bg: #1e293b; --md-bg-sec: #0f172a; --md-border: #334155;
                    --md-text: #f8fafc; --md-text-muted: #94a3b8; 
                    --md-primary: #6366f1; --md-primary-hover: #818cf8;
                    --md-card-bg: #1e293b; --md-hover-bg: #312e81;
                    --md-shadow: 0 4px 24px rgba(0,0,0,0.3);
                }
            }

            #mippedia-data-app {
                background: var(--md-bg); border-radius: 16px; box-shadow: 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); box-sizing: border-box; overflow: hidden; color: var(--md-text);
            }
            
            .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); }
            .md-title { font-size: 1.25rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 8px; color: var(--md-text); }
            .md-actions { display: flex; gap: 8px; flex-wrap: wrap; }
            
            .md-btn-icon {
                background: var(--md-bg-sec); border: 1px solid var(--md-border); cursor: pointer; color: var(--md-primary);
                padding: 8px 14px; border-radius: 8px; transition: all 0.2s ease; display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600;
            }
            .md-btn-icon:hover { background: var(--md-border); transform: translateY(-1px); }

            /* Highlight Pencarian */
            .md-search-box { position: relative; margin-bottom: 16px; }
            .md-search-input { width: 100%; padding: 10px 14px 10px 34px; border: 1px solid var(--md-border); border-radius: 8px; font-size: 0.9rem; background: var(--md-bg-sec); color: var(--md-text); transition: 0.2s; box-sizing: border-box;}
            .md-search-input:focus { 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-muted); }
            mark.md-highlight { background: #fef08a; color: #854d0e; padding: 0 2px; border-radius: 2px; }

            .md-row-display {
                display: flex; justify-content: space-between; align-items: flex-start;
                padding: 16px 14px; border-bottom: 1px solid var(--md-border); transition: all 0.2s;
                border-radius: 12px; gap: 12px; margin-bottom: 8px; background: var(--md-card-bg);
            }
            .md-row-display:hover { background: var(--md-hover-bg); box-shadow: inset 4px 0 0 var(--md-primary); }
            
            .md-data-group { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
            .md-data-label { font-size: 0.72rem; color: var(--md-text-muted); font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; }
            .md-data-value { font-size: 1.05rem; font-weight: 600; word-break: break-word; color: var(--md-text); }
            .md-data-value a { color: var(--md-primary); text-decoration: none; }
            .md-data-value a:hover { text-decoration: underline; }
            
            /* TOAST NOTIFICATION */
            #md-toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; }
            .md-toast { background: #1e293b; color: #fff; padding: 12px 20px; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); display: flex; align-items: center; gap: 10px; font-size: 0.9rem; font-weight: 600; animation: slideIn 0.3s forwards; }
            @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
            @keyframes fadeOut { to { opacity: 0; transform: translateY(10px); } }

            /* AKORDEON REFERENSI (V8.0) */
            .md-ref-wrapper { margin-top: 10px; background: var(--md-bg-sec); border: 1px solid var(--md-border); border-radius: 10px; overflow: hidden; }
            .md-ref-header-bar { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; cursor: pointer; transition: 0.2s; }
            .md-ref-header-bar:hover { background: var(--md-border); }
            .md-ref-title-sm { font-size: 0.8rem; font-weight: 700; color: var(--md-primary); display: flex; align-items: center; gap: 6px; }
            .md-ref-toggle-icon { transition: transform 0.3s; color: var(--md-text-muted); }
            .md-ref-header-bar.is-open .md-ref-toggle-icon { transform: rotate(180deg); }
            
            .md-ref-collapse { display: none; padding: 0 14px 14px 14px; border-top: 1px dashed var(--md-border); }
            .md-ref-detail-row { display: flex; gap: 8px; font-size: 0.85rem; margin-top: 6px; color: var(--md-text); }
            .md-ref-lbl { font-weight: 700; color: var(--md-text-muted); white-space: nowrap; }
            .md-ref-actions-row { display: flex; gap: 8px; margin-top: 12px; }
            .md-btn-visit { background: var(--md-primary); color: white; padding: 6px 12px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; gap: 5px; transition: 0.2s; border: none; }
            .md-btn-visit:hover { background: var(--md-primary-hover); transform: translateY(-1px); color: white; text-decoration: none;}

            .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 12px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; color: white; text-decoration: none; transition: 0.2s; }
            .md-social-badge:hover { transform: translateY(-2px); filter: brightness(1.1); color: white; text-decoration:none;}

            /* FORM UI */
            .md-form-box { background: var(--md-bg); border-radius: 12px; padding: 20px; margin-top: 20px; border: 1px solid var(--md-border); box-shadow: var(--md-shadow); }
            .md-input, .md-select, .md-textarea { width: 100%; padding: 10px 14px; border: 1px solid var(--md-border); border-radius: 8px; background: var(--md-bg-sec); color: var(--md-text); font-size: 0.9rem; transition: 0.2s; box-sizing: border-box; }
            .md-input:focus, .md-select:focus, .md-textarea:focus { border-color: var(--md-primary); outline: none; }
            .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-save { background: linear-gradient(135deg, var(--md-primary), var(--md-primary-hover)); flex: 1; }
            .md-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
            .md-btn:disabled { opacity: 0.7; cursor: not-allowed; transform: none; }
            
            .md-spinner { display: none; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.4); border-radius: 50%; border-top-color: #fff; animation: md-spin 0.8s linear infinite; }
            .is-loading .md-spinner { display: inline-block; }
            @keyframes md-spin { to { transform: rotate(360deg); } }

            @media (max-width: 600px) {
                .md-ref-header-bar { flex-direction: column; align-items: flex-start; gap: 8px; }
                .md-actions, .md-form-actions { width: 100%; justify-content: stretch; }
                .md-btn { width: 100%; }
            }
            .md-native-render { display: none; }
        `;
        $('<style>').text(css).appendTo('head');
        $('body').append('<div id="md-toast-container"></div>');

        // 3. HELPER FUNCTIONS
        var ICONS = {
            edit: '<svg 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>',
            ref: '<svg 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>',
            link: '<svg width="14" height="14" 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>',
            chevronDown: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>',
            check: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg>',
            copy: '<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>'
        };

        function showToast(message, type) {
            type = type || 'info';
            var bg = type === 'success' ? '#16a34a' : type === 'error' ? '#dc2626' : '#4f46e5';
            var $toast = $('<div class="md-toast" style="background:'+bg+';">' + message + '</div>');
            $('#md-toast-container').append($toast);
            setTimeout(function() { $toast.css('animation', 'fadeOut 0.3s forwards'); setTimeout(function(){ $toast.remove(); },300); }, 3500);
        }

        function escapeHTML(str) { return $('<div>').text(str).html(); }
        
        function getTodayString() { return new Date().toISOString().split('T')[0]; }

        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 { dataItems = JSON.parse(match[1]).items || []; } catch(e) { console.error(e); } }
                return content; 
            });
        }

        function buildWikitextVal(item) { /* Logic wikilink standar */ return item.val; } 
        function buildWikitextRef(ref) { /* Logic wikitext ref standar */ return ref ? (ref.url ? "["+ref.url+" "+(ref.title||"Rujukan")+"]" : (ref.title||"")) : ""; }

        function saveData(actionType, $btnEl, originalContent) {
            if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
            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 + " || " + item.val + " || " + (item.ref ? (item.ref.url||item.ref.title) : "") + "\n"; });
            wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";

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

            api.postWithToken('csrf', { action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V8: ' + actionType, minor: false })
            .done(function() { localStorage.removeItem('md_draft_' + pageName); location.reload(); })
            .fail(function(err) { if ($btnEl) $btnEl.removeClass('is-loading').prop('disabled', false); showToast("Gagal menyimpan: " + err, 'error'); });
        }

        // 4. MAIN UI BUILDER
        function buildUI(rawContent) {
            var $app = $('<div id="mippedia-data-app"></div>');
            var $header = $('<div class="md-header"><h3 class="md-title">' + ICONS.edit + ' Data Terstruktur</h3><div class="md-actions"><button class="md-btn-icon" id="md-add-btn">' + ICONS.edit + ' Tambah</button></div></div>');
            $app.append($header);

            // Search
            var $search = $('<div class="md-search-box"><span class="md-search-icon">' + ICONS.ref + '</span><input type="text" class="md-search-input" placeholder="Cari data (sorot otomatis)..."></div>');
            $search.find('input').on('input', function() {
                var q = $(this).val().toLowerCase();
                $('.md-row-display').each(function() { $(this).toggle($(this).text().toLowerCase().indexOf(q) > -1); });
            });
            $app.append($search);

            // List
            var $list = $('<div class="md-list"></div>');
            dataItems.forEach(function(item, index) {
                var $row = $('<div class="md-row-display"></div>');
                var $info = $('<div class="md-data-group"><span class="md-data-label">' + escapeHTML(item.prop) + '</span></div>');
                
                // Nilai & Salin
                var $valWrap = $('<div style="display:flex; gap:8px; align-items:center;"><span class="md-data-value">' + escapeHTML(item.val) + '</span></div>');
                var $copy = $('<button class="md-btn-icon" style="padding:4px; border:none; background:transparent;">' + ICONS.copy + '</button>');
                $copy.on('click', function() { navigator.clipboard.writeText(item.val); $(this).html(ICONS.check); showToast("Berhasil disalin!", "success"); setTimeout(()=>$(this).html(ICONS.copy), 1500); });
                $valWrap.append($copy);
                $info.append($valWrap);

                // Media Sosial
                if (item.isPersonOrg && item.socials) {
                    var $socGroup = $('<div class="md-social-group"></div>');
                    Object.keys(item.socials).forEach(k => {
                        if(SOCIAL_PLATFORMS[k]) {
                            var p = SOCIAL_PLATFORMS[k];
                            $socGroup.append('<a href="'+p.base+item.socials[k].replace('@','')+'" target="_blank" class="md-social-badge" style="background:'+p.color+';">'+p.icon+' '+p.name+'</a>');
                        }
                    });
                    $info.append($socGroup);
                }

                // AKORDEON REFERENSI (FITUR UTAMA)
                if (item.ref && (item.ref.title || item.ref.url)) {
                    var $refWrap = $('<div class="md-ref-wrapper"></div>');
                    var $refHead = $('<div class="md-ref-header-bar"><div class="md-ref-title-sm">' + ICONS.ref + ' ' + escapeHTML(item.ref.title || 'Sumber Rujukan') + '</div><div class="md-ref-toggle-icon">' + ICONS.chevronDown + '</div></div>');
                    var $refBody = $('<div class="md-ref-collapse"></div>');
                    
                    if (item.ref.author) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penulis:</span> ' + escapeHTML(item.ref.author) + '</div>');
                    if (item.ref.publisher) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penerbit:</span> ' + escapeHTML(item.ref.publisher) + '</div>');
                    if (item.ref.date) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Diakses:</span> ' + escapeHTML(item.ref.date) + '</div>');
                    
                    if (item.ref.url) {
                        $refBody.append('<div class="md-ref-actions-row"><a href="'+escapeHTML(item.ref.url)+'" target="_blank" class="md-btn-visit">' + ICONS.link + ' Kunjungi Situs Terkait</a></div>');
                    }

                    $refHead.on('click', function() { $(this).toggleClass('is-open'); $refBody.slideToggle(250); });
                    $refWrap.append($refHead).append($refBody);
                    $info.append($refWrap);
                }

                $row.append($info);
                var $editBtn = $('<button class="md-btn-icon">Edit</button>').on('click', function() { showForm(index, rawContent); });
                $row.append($editBtn);
                $list.append($row);
            });

            $app.append($list).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);

            // Binding Tombol Tambah
            $('#md-add-btn').on('click', function() { showForm(-1, rawContent); });
        }

        // 5. FORM EDIT & DRAFT SYSTEM
        function showForm(index, rawContent) {
            var $container = $('#md-form-container').empty();
            var item = index > -1 ? dataItems[index] : { prop:'', val:'', ref:{}, isPersonOrg:false, socials:{} };
            
            var $form = $('<div class="md-form-box"><h4>' + (index > -1 ? 'Edit Data' : 'Tambah Data Baru') + '</h4></div>');
            
            $form.append('<label>Label Data</label><input type="text" id="md-inp-prop" class="md-input" value="'+escapeHTML(item.prop)+'" style="margin-bottom:10px;">');
            $form.append('<label>Nilai Data</label><input type="text" id="md-inp-val" class="md-input" value="'+escapeHTML(item.val)+'" style="margin-bottom:15px;">');
            
            // Ref Area (Simplified for space in this code, full implementation identical logic)
            $form.append('<h5>Detail Referensi (Opsional)</h5>');
            $form.append('<input type="text" id="md-ref-title" class="md-input" placeholder="Judul Artikel/Buku" value="'+escapeHTML(item.ref.title||'')+'" style="margin-bottom:10px;">');
            $form.append('<input type="url" id="md-ref-url" class="md-input" placeholder="https://..." value="'+escapeHTML(item.ref.url||'')+'" style="margin-bottom:15px;">');

            var $actions = $('<div style="display:flex; gap:10px; margin-top:20px;"></div>');
            var $btnSave = $('<button class="md-btn md-btn-save">Simpan <span class="md-spinner"></span></button>');
            var $btnCancel = $('<button class="md-btn" style="background:var(--md-text-muted);">Batal</button>');

            $btnCancel.on('click', () => $container.empty());
            $btnSave.on('click', function() {
                if(!$('#md-inp-prop').val() || !$('#md-inp-val').val()) { showToast("Label dan Nilai wajib diisi!", "error"); return; }
                
                var newItem = {
                    prop: $('#md-inp-prop').val().trim(),
                    val: $('#md-inp-val').val().trim(),
                    ref: { title: $('#md-ref-title').val().trim(), url: $('#md-ref-url').val().trim() }
                };
                if(index > -1) dataItems[index] = newItem; else dataItems.push(newItem);
                saveData((index > -1 ? 'Edit' : 'Tambah') + ' data', $(this), rawContent);
            });

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

            // Auto-scroll smooth
            $('html, body').animate({ scrollTop: $form.offset().top - 80 }, 300);
        }

        // INIT
        loadData().then(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);
            }
        }
    });
})();