MediaWiki:Common.js: Perbedaan antara revisi

Tidak ada ringkasan suntingan
Tanda: Suntingan perangkat seluler Suntingan peramban seluler
Tidak ada ringkasan suntingan
Tanda: Suntingan perangkat seluler Suntingan peramban seluler
Baris 1: Baris 1:
/**
/**
  * ====================================================================
  * ====================================================================
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 EVOLUTION)
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE)
  * Fitur: Full Modal UI, Smart References, Floating Guides, Dark Mode,  
  * Peningkatan: Sistem Modal Pop-up, Viewer Referensi, Tour Bantuan,
  * Toast Notifications, Advanced Validations, Mobile FAB, etc.
  * Smart Lock Notification, Toast Alerts, Reorder Data, Animasi Mulus.
  * ====================================================================
  * ====================================================================
  */
  */
Baris 20: Baris 20:
         var api = new mw.Api();
         var api = new mw.Api();


         // --- MASTER DATA PLATFORM ---
         // 1. DATA MASTER PLATFORM MEDIA SOSIAL & MUSIK
         var SOCIAL_PLATFORMS = {
         var SOCIAL_PLATFORMS = {
             applemusic: { name: 'Apple Music', base: 'https://music.apple.com/artist/', color: '#fc3c44' },
             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' },
             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' },
             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' },
             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' },
             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' },
             twitter: { name: 'X / Twitter', base: 'https://x.com/', color: '#0f1419' }
         };
         };


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


         var REF_TYPES = {
         var REF_TYPES = {
             "Berita": ["Berita Online", "Berita Cetak", "Wawancara"],
             "Berita": ["Berita Online", "Berita Cetak / Koran", "Wawancara Eksklusif"],
             "Website": ["Situs Resmi", "Portal Informasi", "Database Web"],
             "Website": ["Situs Resmi", "Portal Informasi", "Database Web"],
             "Buku": ["Buku Cetak", "E-Book", "Jurnal Ilmiah"],
             "Buku": ["Buku Cetak", "E-Book", "Bab Buku"],
             "Media": ["Video YouTube", "Podcast", "Media Sosial"]
            "Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis"],
             "Siaran Pers": ["Pernyataan Resmi", "Keterangan Manajemen"],
            "Video": ["YouTube Video", "Film Dokumenter"]
         };
         };


         // --- IKON SVG ---
         // IKON SISTEM
         var svgs = {
         var svgEdit = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>';
            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>',
        var svgLock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>';
            lock: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>',
        var svgUnlock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>';
            unlock: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>',
        var svgRef = '<svg class="md-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>';
            ref: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg>',
        var svgCopy = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
            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>',
        var svgHelp = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>';
            close: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>',
        var svgExternal = '<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>';
            external: '<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>',
        var svgUp = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="18 15 12 9 6 15"></polyline></svg>';
            help: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>'
        var svgDown = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>';
        };


         // --- STYLESHEET V8.0 (Modern UI & Animations) ---
         // 5. HELPER UTILITY
        var css = `
        function formatIndonesianDate(dateStr) {
            :root {
             if (!dateStr) return '';
                --md-primary: #4f46e5; --md-primary-hover: #4338ca; --md-bg: #ffffff;
             var parts = dateStr.split('-');
                --md-surface: #f8fafc; --md-border: #e2e8f0; --md-text: #0f172a;
             if (parts.length !== 3) return dateStr;
                --md-text-muted: #64748b; --md-danger: #ef4444; --md-radius: 12px;
             var months = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'];
             }
             return parseInt(parts[2], 10) + ' ' + months[parseInt(parts[1], 10) - 1] + ' ' + parts[0];
            @media (prefers-color-scheme: dark) {
        }
                :root {
                    --md-bg: #0f172a; --md-surface: #1e293b; --md-border: #334155;
                    --md-text: #f8fafc; --md-text-muted: #94a3b8;
                }
            }
             #mippedia-data-app {
                background: var(--md-bg); border-radius: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.08);
                padding: 24px; margin: 24px 0; font-family: system-ui, -apple-system, sans-serif;
                border: 1px solid var(--md-border); position: relative; color: var(--md-text);
             }
            .md-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--md-border); padding-bottom: 16px; margin-bottom: 20px; flex-wrap: wrap; gap: 10px; }
            .md-title { font-size: 1.3rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 8px; }
            .md-stats { font-size: 0.8rem; color: var(--md-text-muted); background: var(--md-surface); padding: 4px 10px; border-radius: 20px; font-weight: 600; }
           
             .md-btn {
                background: var(--md-surface); border: 1px solid var(--md-border); color: var(--md-text);
                padding: 8px 14px; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 0.85rem;
                display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
            }
            .md-btn:hover { background: var(--md-primary); color: white; border-color: var(--md-primary); transform: translateY(-2px); box-shadow: 0 4px 10px rgba(79, 70, 229, 0.2); }
            .md-btn-primary { background: linear-gradient(135deg, var(--md-primary), #3b82f6); color: white; border: none; }
             .md-btn-danger { background: #fef2f2; color: var(--md-danger); border-color: #fca5a5; }
           
            .md-row-display {
                display: flex; justify-content: space-between; padding: 14px 16px; margin-bottom: 8px;
                background: var(--md-surface); border-radius: var(--md-radius); border: 1px solid var(--md-border);
                transition: 0.3s;
            }
            .md-row-display:hover { transform: scale(1.01); border-color: var(--md-primary); box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
            .md-data-label { font-size: 0.75rem; text-transform: uppercase; color: var(--md-text-muted); font-weight: 800; letter-spacing: 0.5px; }
            .md-data-value { font-size: 1.1rem; font-weight: 700; display: block; margin-top: 4px; }
           
            /* Referensi Badge */
            .md-ref-trigger {
                background: #e0e7ff; color: var(--md-primary); border: none; padding: 4px 10px;
                border-radius: 20px; font-size: 0.75rem; font-weight: 700; cursor: pointer; margin-top: 8px;
                display: inline-flex; align-items: center; gap: 4px; transition: 0.2s;
            }
            .md-ref-trigger:hover { background: var(--md-primary); color: white; }


            /* Modal System (Pop-ups) */
        function extractDomain(urlStr) {
             .md-overlay {
             try { return new URL(urlStr.startsWith('http') ? urlStr : 'https://' + urlStr).hostname.replace(/^www\./, ''); } catch(e) { return urlStr; }
                position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5);
        }
                backdrop-filter: blur(8px); z-index: 99999; display: flex; justify-content: center; align-items: center;
        function ensureHttps(url) { return (url && !url.match(/^https?:\/\//i)) ? 'https://' + url : url; }
                opacity: 0; animation: fadeIn 0.3s forwards; padding: 20px; box-sizing: border-box;
            }
            .md-modal {
                background: var(--md-bg); width: 100%; max-width: 550px; border-radius: 20px;
                box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); transform: translateY(20px);
                animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
                max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--md-border);
            }
            .md-modal-header { padding: 20px 24px; border-bottom: 1px solid var(--md-border); display: flex; justify-content: space-between; align-items: center; background: var(--md-surface); }
            .md-modal-title { font-size: 1.2rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 8px; }
            .md-modal-close { background: none; border: none; color: var(--md-text-muted); cursor: pointer; padding: 5px; border-radius: 50%; transition: 0.2s; }
            .md-modal-close:hover { background: #f1f5f9; color: var(--md-danger); }
            .md-modal-body { padding: 24px; overflow-y: auto; flex: 1; }
            .md-modal-footer { padding: 16px 24px; border-top: 1px solid var(--md-border); display: flex; justify-content: flex-end; gap: 10px; background: var(--md-surface); }
 
            /* Formulir Inputs */
            .md-form-group { margin-bottom: 16px; }
            .md-form-group label { display: block; font-weight: 700; font-size: 0.85rem; margin-bottom: 6px; color: var(--md-text); }
            .md-input {
                width: 100%; padding: 12px; border: 2px solid var(--md-border); border-radius: 10px;
                background: var(--md-bg); color: var(--md-text); font-size: 0.95rem; transition: 0.2s; box-sizing: border-box;
            }
            .md-input:focus { border-color: var(--md-primary); outline: none; box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.1); }
            .md-input.error { border-color: var(--md-danger); animation: shake 0.4s; }
 
            /* Toast Notification */
            .md-toast {
                position: fixed; bottom: 30px; right: 30px; background: #10b981; color: white;
                padding: 12px 24px; border-radius: 12px; font-weight: 700; z-index: 100000;
                box-shadow: 0 10px 25px rgba(16, 185, 129, 0.4); animation: slideInRight 0.3s forwards;
            }
 
            /* Help Tooltip Box */
            .md-help-box {
                background: linear-gradient(135deg, #1e293b, #0f172a); color: #f8fafc; padding: 16px;
                border-radius: 12px; margin-bottom: 20px; font-size: 0.85rem; position: relative; border-left: 4px solid #38bdf8;
            }
            .md-help-box::after {
                content: ''; position: absolute; bottom: -8px; left: 20px;
                border-width: 8px 8px 0; border-style: solid; border-color: #0f172a transparent transparent transparent;
            }
 
            @keyframes fadeIn { to { opacity: 1; } }
            @keyframes slideUp { to { transform: translateY(0); } }
            @keyframes slideInRight { from { transform: translateX(100px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
            @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }


            @media (max-width: 768px) {
        // TOAST NOTIFICATION
                #mippedia-data-app { padding: 16px; }
        function showToast(msg, type) {
                .md-overlay { padding: 10px; align-items: flex-end; }
            $('.md-toast').remove();
                .md-modal { max-height: 95vh; border-radius: 20px 20px 0 0; animation: slideUpMobile 0.4s forwards; transform: translateY(100%); }
            var bg = type === 'success' ? '#10b981' : (type === 'error' ? '#ef4444' : '#3b82f6');
                @keyframes slideUpMobile { to { transform: translateY(0); } }
            var $toast = $('<div class="md-toast" style="position:fixed; bottom:20px; right:20px; background:'+bg+'; color:#fff; padding:12px 20px; border-radius:8px; box-shadow:0 4px 12px rgba(0,0,0,0.15); z-index:10001; font-weight:600; opacity:0; transform:translateY(20px); transition:all 0.3s;">' + msg + '</div>');
                .md-btn-fab {
            $('body').append($toast);
                    position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; border-radius: 30px;
            setTimeout(() => { $toast.css({'opacity': '1', 'transform': 'translateY(0)'}); }, 10);
                    background: var(--md-primary); color: white; display: flex; justify-content: center; align-items: center;
             setTimeout(() => { $toast.css({'opacity': '0', 'transform': 'translateY(20px)'}); setTimeout(()=> $toast.remove(), 300); }, 3000);
                    box-shadow: 0 10px 25px rgba(79, 70, 229, 0.4); z-index: 9000; cursor: pointer; border: none;
                }
            }
            .md-native-render { display: none; }
        `;
        $('<style>').text(css).appendTo('head');
 
        // --- HELPER FUNCTIONS ---
        function showToast(msg) {
            var $t = $('<div class="md-toast">' + msg + '</div>').appendTo('body');
             setTimeout(() => { $t.fadeOut(300, function(){ $(this).remove(); }); }, 3000);
         }
         }


         // --- SISTEM POP-UP MODAL UTAMA ---
         // 6. STYLESHEET CSS V8.0 (MODALS, TOASTS, UI)
        function openModal(title, contentHtml, footerHtml, onOpen) {
        var css = `
             var $overlay = $('<div class="md-overlay"></div>');
            #mippedia-data-app { background: #fff; border-radius: 16px; box-shadow: 0 4px 24px rgba(0,0,0,0.06); padding: 20px; margin: 20px 0; border: 1px solid #e2e8f0; font-family: sans-serif; position: relative;}
             var $modal = $('<div class="md-modal"></div>');
            .md-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 16px; border-bottom: 1px solid #f1f5f9; padding-bottom:14px; }
            .md-title { font-size: 1.25rem; font-weight: 800; color: #0f172a; margin: 0; display:flex; align-items:center; gap:8px;}
            .md-actions { display: flex; gap: 8px; flex-wrap:wrap; }
             .md-btn-icon { background: #f8fafc; border: 1px solid #cbd5e1; cursor: pointer; color: #4f46e5; padding: 8px 14px; border-radius: 8px; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size:0.85rem;}
            .md-btn-icon:hover { background: #e0e7ff; }
             .md-btn-lock { color: #dc2626; background: #fef2f2; border-color: #fca5a5; }
              
              
             var $header = $('<div class="md-modal-header"><h3 class="md-modal-title">' + title + '</h3><button class="md-modal-close">' + svgs.close + '</button></div>');
             .md-row-display { display: flex; justify-content: space-between; align-items: flex-start; padding: 14px; border-bottom: 1px solid #f1f5f9; border-radius: 12px; gap: 12px; background: #fff; transition:0.3s; margin-bottom:8px;}
             var $body = $('<div class="md-modal-body">' + contentHtml + '</div>');
            .md-row-display:hover { background: #f8fafc; box-shadow: inset 4px 0 0 #4f46e5; }
             var $footer = $('<div class="md-modal-footer">' + footerHtml + '</div>');
            .md-data-group { display: flex; flex-direction: column; gap: 4px; flex: 1; }
            .md-data-label { font-size: 0.72rem; color: #64748b; font-weight: 800; text-transform: uppercase; }
            .md-data-value { font-size: 1.05rem; color: #0f172a; font-weight: 600; }
             .md-btn-copy { background: none; border: none; color: #94a3b8; cursor: pointer; display:inline-flex; transition:0.2s; margin-left:8px;}
             .md-btn-copy:hover { color:#4f46e5; }
              
              
             $modal.append($header).append($body).append($footer);
             /* Reference Badge (Mini) */
             $overlay.append($modal).appendTo('body');
            .md-ref-badge-trigger { display:inline-flex; align-items:center; gap:4px; font-size:0.75rem; background:#eff6ff; color:#2563eb; padding:2px 8px; border-radius:12px; cursor:pointer; font-weight:700; border:1px solid #bfdbfe; transition:0.2s; margin-top:4px; width:fit-content;}
             .md-ref-badge-trigger:hover { background:#dbeafe; transform:scale(1.05); }


             var closeFunc = function() {
             /* MODAL SYSTEM (V8.0) */
                $modal.css('transform', 'translateY(20px)').css('opacity', '0');
             .md-modal-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(15, 23, 42, 0.6); backdrop-filter:blur(4px); z-index:9999; display:flex; justify-content:center; align-items:center; opacity:0; animation: fadeIn 0.2s forwards; padding:16px;}
                $overlay.fadeOut(200, function() { $(this).remove(); });
            .md-modal-box { background:#fff; border-radius:16px; width:100%; max-width:600px; max-height:90vh; overflow-y:auto; box-shadow:0 20px 25px -5px rgba(0,0,0,0.1); transform:translateY(20px); animation: slideUp 0.3s forwards; display:flex; flex-direction:column;}
            };
            .md-modal-header { padding:16px 20px; border-bottom:1px solid #e2e8f0; display:flex; justify-content:space-between; align-items:center; background:#f8fafc; border-radius:16px 16px 0 0;}
 
            .md-modal-header h3 { margin:0; font-size:1.1rem; font-weight:800; color:#0f172a;}
             $header.find('.md-modal-close').on('click', closeFunc);
            .md-btn-close { background:none; border:none; font-size:1.5rem; cursor:pointer; color:#64748b; line-height:1;}
            $overlay.on('click', function(e) { if(e.target === this) closeFunc(); });
            .md-modal-body { padding:20px; flex:1;}
            $(document).on('keydown.mdmodal', function(e) { if(e.key === 'Escape') { closeFunc(); $(document).off('keydown.mdmodal'); } });
           
 
            /* Tour / Help Tooltip */
            if(typeof onOpen === 'function') onOpen($body, $footer, closeFunc);
            .md-tour-overlay { position:fixed; z-index:10000; background:rgba(0,0,0,0.8); color:white; padding:16px; border-radius:12px; max-width:250px; text-align:center; box-shadow:0 10px 15px rgba(0,0,0,0.3); animation: bounceIn 0.5s;}
        }
             .md-tour-overlay::after { content:''; position:absolute; border-width:10px; border-style:solid; }
 
            .md-tour-arrow-up::after { bottom:100%; left:50%; transform:translateX(-50%); border-color:transparent transparent rgba(0,0,0,0.8) transparent; }
        // --- 3. NOTIFIKASI GEMBOK (UNTUK BUKAN PENGURUS) ---
        function showLockNotice() {
            var content = `
                <div style="text-align:center; padding: 20px 0;">
                    <div style="background:#fef2f2; width:80px; height:80px; border-radius:40px; display:flex; align-items:center; justify-content:center; margin: 0 auto 20px; color:#ef4444;">
                        <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
                    </div>
                    <h2 style="margin:0 0 10px; font-weight:800; font-size:1.4rem;">Halaman Dilindungi</h2>
                    <p style="color:var(--md-text-muted); line-height:1.6;">Struktur data pada halaman ini telah dikunci oleh Pengurus. Pengguna biasa atau anonim tidak dapat mengedit atau menambahkan data baru untuk mencegah vandalisme.</p>
                    <div style="background:var(--md-surface); border:1px solid var(--md-border); padding:12px; border-radius:8px; margin-top:20px; font-size:0.85rem; text-align:left;">
                        💡 <b>Tips:</b> Jika Anda memiliki pembaruan data yang valid, silakan hubungi pengurus melalui halaman Pembicaraan artikel ini.
                    </div>
                </div>
            `;
             openModal(svgs.lock + ' Akses Ditolak', content, '<button class="md-btn md-btn-primary md-close-btn">Mengerti</button>', function($b, $f, close) {
                $f.find('.md-close-btn').on('click', close);
            });
        }


        // --- 1. REFERENSI POP-UP DETAIL ---
            /* Form Elements inside Modal */
        function showRefDetails(refObj) {
            .md-form-group { margin-bottom: 14px; }
             var dateStr = refObj.date ? new Date(refObj.date).toLocaleDateString('id-ID', {day:'numeric', month:'long', year:'numeric'}) : '-';
            .md-form-group label { display: block; font-size: 0.85rem; font-weight: 700; margin-bottom: 6px; color: #334155; }
             var safeUrl = refObj.url ? refObj.url : '#';
            .md-input, .md-select { width: 100%; padding: 10px 12px; border: 1px solid #cbd5e1; border-radius: 8px; box-sizing: border-box; font-size: 0.9rem; transition: 0.2s; background:#f8fafc;}
             var title = refObj.title || 'Sumber Referensi';
             .md-input:focus { border-color: #4f46e5; outline: none; background:#fff; box-shadow:0 0 0 3px rgba(79, 70, 229, 0.1); }
            .md-btn { padding: 10px 18px; border: none; border-radius: 8px; font-weight: 700; cursor: pointer; color: white; display: inline-flex; align-items: center; justify-content:center; gap: 6px; transition: 0.2s; }
            .md-btn-save { background: linear-gradient(135deg, #4f46e5, #4338ca); flex:1;}
             .md-btn-save:hover { filter:brightness(1.1); transform:translateY(-1px);}
             .md-btn-cancel { background: #64748b; }
              
              
             var content = `
             /* Animations */
                <div style="display:flex; flex-direction:column; gap:12px; font-size:0.95rem;">
            @keyframes fadeIn { to { opacity:1; } }
                    <div style="background:var(--md-surface); padding:16px; border-radius:12px; border-left:4px solid var(--md-primary);">
            @keyframes slideUp { to { transform:translateY(0); } }
                        <h4 style="margin:0 0 5px; font-size:1.1rem; color:var(--md-primary);">${title}</h4>
            @keyframes bounceIn { 0% {transform:scale(0.8); opacity:0;} 50% {transform:scale(1.05);} 100% {transform:scale(1); opacity:1;} }
                        ${refObj.site ? `<div style="color:var(--md-text-muted); font-size:0.85rem;">Milik: <b>${refObj.site}</b></div>` : ''}
            .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; }
                    </div>
            .is-loading .md-spinner { display: inline-block; }
                   
            @keyframes md-spin { to { transform: rotate(360deg); } }
                    <div style="display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:10px;">
                        ${refObj.author ? `<div style="background:var(--md-surface); padding:12px; border-radius:8px;"><b>Penulis</b><br>${refObj.author}</div>` : ''}
                        ${refObj.publisher ? `<div style="background:var(--md-surface); padding:12px; border-radius:8px;"><b>Penerbit</b><br>${refObj.publisher}</div>` : ''}
                        <div style="background:var(--md-surface); padding:12px; border-radius:8px;"><b>Tipe Rujukan</b><br>${refObj.type || 'Umum'}</div>
                        <div style="background:var(--md-surface); padding:12px; border-radius:8px;"><b>Diakses Pada</b><br>${dateStr}</div>
                    </div>
 
                    <div style="margin-top:15px; padding:12px; background:#f1f5f9; border-radius:8px; font-family:monospace; font-size:0.8rem; color:#475569;">
                        <b>Format Sitasi APA:</b><br>
                        ${refObj.author ? refObj.author + '.' : 'Anonim.'} (${new Date().getFullYear()}). <i>${title}</i>. ${refObj.site || ''}. Diakses pada ${dateStr}.
                    </div>
                </div>
            `;
              
              
             var footer = '';
             .md-preset-pill { background: #f1f5f9; padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; cursor: pointer; border:1px solid #cbd5e1; display:inline-block; margin:2px;}
             if (refObj.url) footer += `<a href="${safeUrl}" target="_blank" class="md-btn md-btn-primary" style="text-decoration:none;">Kunjungi Website ${svgs.external}</a>`;
             .md-preset-pill:hover { background: #e0e7ff; border-color:#a5b4fc;}
             footer += `<button class="md-btn md-close-btn">Tutup</button>`;
             .md-native-render { display: none; }
 
        `;
            openModal(svgs.ref + ' Detail Rujukan', content, footer, function($b, $f, close) {
        $('<style>').text(css).appendTo('head');
                $f.find('.md-close-btn').on('click', close);
            });
        }


         // --- CORE LOAD & SAVE ---
         // 7. PARSER DATA
         function loadData() {
         function loadData() {
             return api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main', formatversion: 2 })
             return api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main', formatversion: 2 }).then(function(data) {
            .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 \| (.*?) -->/);
Baris 266: Baris 144:
         }
         }


         function saveData(actionType, rawContent, $btn) {
        function buildWikitextVal(item) {
             if($btn) { $btn.prop('disabled', true).html('Menyimpan...⏳'); }
            var val = item.val;
           
            if (item.linkTarget) return "[[" + item.linkTarget.trim() + "|" + val + "]]";
            if (item.link) return "[[" + val + "]]";
            return val;
        }
 
        function buildWikitextRef(refObj) {
            if (!refObj) return "";
            var title = refObj.title || "Rujukan";
            return refObj.url ? "[" + ensureHttps(refObj.url) + " " + title + "]" : "'''" + 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\">\n{| class=\"wikitable\"\n! Data !! Nilai\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 + "\n"; });
             dataItems.forEach(function(item) { wt += "|-\n| " + item.prop + " || " + buildWikitextVal(item) + " || " + buildWikitextRef(item.ref) + "\n"; });
             wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";
             wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->";


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


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


         // --- 2 & 4. FORMULIR MODAL DENGAN PANDUAN ---
         // ==========================================
         function showFormModal(index, rawContent) {
        // SISTEM MODAL POP-UP & PANDUAN
             var isNew = index === -1;
        // ==========================================
             var item = isNew ? { prop:'', val:'', ref:{} } : dataItems[index];
         function openModal(title, contentHtml, onInit) {
             var r = item.ref || {};
            $('.md-modal-overlay').remove(); // Clear existing
             var $overlay = $('<div class="md-modal-overlay"></div>');
            var $box = $('<div class="md-modal-box"></div>');
             var $header = $('<div class="md-modal-header"><h3>'+title+'</h3><button class="md-btn-close">&times;</button></div>');
             var $body = $('<div class="md-modal-body">'+contentHtml+'</div>');
           
            $box.append($header).append($body);
            $overlay.append($box);
            $('body').append($overlay);


             // 4. TEKS BANTUAN INTERAKTIF
             $header.find('.md-btn-close').on('click', function() { $overlay.remove(); });
             var helpUI = `
             $overlay.on('click', function(e) { if(e.target === this) $overlay.remove(); });
                <div class="md-help-box">
            $(document).on('keydown.mdmodal', function(e) { if(e.key === "Escape") { $overlay.remove(); $(document).off('keydown.mdmodal'); } });
                    <strong>Panduan Memasukkan Data:</strong>
                    <ul style="margin:5px 0 0; padding-left:20px;">
                        <li><b>Label Data:</b> Gunakan kata benda (Contoh: "Pekerjaan", "Tanggal Lahir").</li>
                        <li><b>Nilai Data:</b> Isi dengan data sebenarnya. Sistem mendukung format tautan otomatis.</li>
                        <li><b>Referensi (Opsional):</b> Jika ada sumber, klik tab referensi di bawah untuk mengisi.</li>
                    </ul>
                </div>
            `;


             var formHtml = `
             if(onInit) onInit($body, $overlay);
                ${isNew ? helpUI : ''}
        }
                <div class="md-form-group">
                    <label>Label Data <span style="color:red">*</span></label>
                    <input type="text" id="md-inp-prop" class="md-input" value="${item.prop}" placeholder="Cth: Tempat Lahir" autocomplete="off">
                </div>
                <div class="md-form-group">
                    <label>Nilai Data <span style="color:red">*</span></label>
                    <input type="text" id="md-inp-val" class="md-input" value="${item.val}" placeholder="Cth: Jakarta, Indonesia">
                </div>
               
                <hr style="border:0; border-top:1px dashed var(--md-border); margin:20px 0;">
                <h4 style="margin:0 0 10px; display:flex; align-items:center; gap:8px;">${svgs.ref} Tambah Referensi</h4>
               
                <div style="display:grid; grid-template-columns:1fr 1fr; gap:10px;">
                    <div class="md-form-group" style="grid-column:span 2;"><input type="url" id="md-ref-url" class="md-input" value="${r.url||''}" placeholder="URL Website (https://...)"></div>
                    <div class="md-form-group"><input type="text" id="md-ref-title" class="md-input" value="${r.title||''}" placeholder="Judul Halaman"></div>
                    <div class="md-form-group"><input type="text" id="md-ref-site" class="md-input" value="${r.site||''}" placeholder="Nama Situs"></div>
                    <div class="md-form-group"><input type="text" id="md-ref-author" class="md-input" value="${r.author||''}" placeholder="Penulis"></div>
                    <div class="md-form-group"><input type="date" id="md-ref-date" class="md-input" value="${r.date||''}"></div>
                </div>
            `;


             var footerHtml = `
        // Pop-up Notifikasi Gembok Admin
                ${!isNew ? `<button class="md-btn md-btn-danger" id="md-btn-delete" style="margin-right:auto;">Hapus</button>` : ''}
        function showLockExplanation() {
                <button class="md-btn md-close-btn">Batal</button>
             var html = '<div style="text-align:center; padding:10px;">' +
                <button class="md-btn md-btn-primary" id="md-btn-save">${svgs.edit} Terbitkan</button>
                      '<div style="font-size:3rem; color:#ef4444; margin-bottom:10px;">' + svgLock + '</div>' +
             `;
                      '<h2 style="margin:0 0 10px 0; color:#0f172a;">Data Ini Dikunci</h2>' +
                      '<p style="color:#475569; font-size:0.95rem; line-height:1.5;">Halaman struktur data ini sedang dikunci oleh <b>Pengurus Mippedia</b>. Pengguna biasa atau anonim tidak dapat menambah atau mengedit data ini untuk mencegah vandalisme atau perubahan informasi penting.</p>' +
                      '<button id="md-close-lock" class="md-btn md-btn-cancel" style="margin-top:20px; width:100%;">Saya Mengerti</button>' +
                      '</div>';
            openModal('Informasi Keamanan', html, function($body, $overlay) {
                $body.find('#md-close-lock').on('click', () => $overlay.remove());
             });
        }


             openModal(isNew ? 'Tambah Data Baru' : 'Edit Data', formHtml, footerHtml, function($b, $f, closeFunc) {
        // Pop-up Penampil Referensi (Viewer Mode)
                // Auto Capitalize Label
        function showRefModal(ref) {
                $b.find('#md-inp-prop').on('input', function() {
             var html = '<div style="display:flex; flex-direction:column; gap:12px; font-size:0.95rem;">';
                    let val = $(this).val();
            html += '<div><span style="color:#64748b; font-weight:700; font-size:0.8rem; text-transform:uppercase;">Judul Referensi</span><div style="font-size:1.1rem; font-weight:800; color:#0f172a;">' + (ref.title || 'Tanpa Judul') + '</div></div>';
                    $(this).val(val.replace(/\b\w/g, l => l.toUpperCase()));
           
                });
            var grid = '<div style="display:grid; grid-template-columns:1fr 1fr; gap:10px; background:#f8fafc; padding:16px; border-radius:12px; border:1px solid #e2e8f0;">';
            if(ref.author) grid += '<div><b style="color:#64748b; font-size:0.8rem;">Penulis:</b><br>' + ref.author + '</div>';
            if(ref.site) grid += '<div><b style="color:#64748b; font-size:0.8rem;">Situs:</b><br>' + ref.site + '</div>';
            if(ref.publisher) grid += '<div><b style="color:#64748b; font-size:0.8rem;">Penerbit:</b><br>' + ref.publisher + '</div>';
            if(ref.date) grid += '<div><b style="color:#64748b; font-size:0.8rem;">Tanggal Akses:</b><br>' + formatIndonesianDate(ref.date) + '</div>';
            if(ref.type) grid += '<div style="grid-column:span 2;"><b style="color:#64748b; font-size:0.8rem;">Kategori:</b><br><span style="background:#dbeafe; color:#1e40af; padding:4px 10px; border-radius:12px; font-size:0.8rem; font-weight:700;">' + ref.type + (ref.subType ? ' - ' + ref.subType : '') + '</span></div>';
            grid += '</div>';
            html += grid;


                // Auto Fix URL
            if (ref.url) {
                $b.find('#md-ref-url').on('blur', function() {
                html += '<a href="'+ensureHttps(ref.url)+'" target="_blank" class="md-btn md-btn-save" style="margin-top:10px; text-decoration:none; display:flex; justify-content:center;">' + svgExternal + ' Kunjungi Website Referensi</a>';
                    let u = $(this).val().trim();
            }
                    if(u && !/^https?:\/\//i.test(u)) $(this).val('https://' + u);
            html += '</div>';
                });


                $f.find('.md-close-btn').on('click', closeFunc);
            openModal('Detail Referensi Terstruktur', html);
               
        }
                $f.find('#md-btn-save').on('click', function() {
                    var p = $b.find('#md-inp-prop').val().trim();
                    var v = $b.find('#md-inp-val').val().trim();
                   
                    // Validasi Animasi Getar (Shake)
                    if(!p || !v) {
                        if(!p) $b.find('#md-inp-prop').addClass('error').on('animationend', function(){$(this).removeClass('error')});
                        if(!v) $b.find('#md-inp-val').addClass('error').on('animationend', function(){$(this).removeClass('error')});
                        return;
                    }


                    var refObj = {
        // Bantuan Tooltip Otomatis
                        url: $b.find('#md-ref-url').val().trim(),
        function startHelpTour() {
                        title: $b.find('#md-ref-title').val().trim(),
            var $tour = $('<div class="md-tour-overlay md-tour-arrow-up"><b>Panduan Tambah Data!</b><br><span style="font-size:0.85rem;">Klik di sini untuk menambah data baru. Form akan muncul sebagai pop-up yang praktis!</span><br><button class="md-btn md-btn-cancel" style="padding:4px 8px; margin-top:8px; font-size:0.75rem;" onclick="$(\'.md-tour-overlay\').remove();">Tutup</button></div>');
                        site: $b.find('#md-ref-site').val().trim(),
            var offset = $('#btn-add-data').offset();
                        author: $b.find('#md-ref-author').val().trim(),
            if(offset) {
                        date: $b.find('#md-ref-date').val()
                $tour.css({ top: offset.top + 45 + 'px', left: offset.left - 50 + 'px' });
                    };
                 $('body').append($tour);
                    Object.keys(refObj).forEach(k => { if(!refObj[k]) delete refObj[k]; });
                setTimeout(() => $tour.remove(), 10000);
 
             }
                    var newItem = { prop: p, val: v, ref: Object.keys(refObj).length ? refObj : null };
                   
                    if(isNew) dataItems.push(newItem); else dataItems[index] = newItem;
                    saveData(isNew ? 'Tambah data' : 'Edit data', rawContent, $(this));
                });
 
                 $f.find('#md-btn-delete').on('click', function() {
                    if(confirm("Yakin ingin menghapus data ini secara permanen?")) {
                        dataItems.splice(index, 1);
                        saveData('Hapus data', rawContent, $(this));
                    }
                });
             });
         }
         }


         // --- MAIN UI BUILDER ---
         // 8. BUILDER UI UTAMA
         function buildUI(rawContent) {
         function buildUI(rawContent) {
             var $app = $('<div id="mippedia-data-app"></div>');
             var $app = $('<div id="mippedia-data-app"></div>');
              
              
             // Header & Statistik
             // HEADER
             var $header = $('<div class="md-header"></div>');
             var $header = $('<div class="md-header"></div>');
             $header.append(`<div class="md-title">${svgs.edit} Struktur Data <span class="md-stats">${dataItems.length} Item</span></div>`);
             var $titleContainer = $('<h3 class="md-title">' + svgEdit + ' Data Terstruktur</h3>');
              
            var $actions = $('<div class="md-actions"></div>');
             var $actions = $('<div style="display:flex; gap:8px;"></div>');
 
              
             // Tombol Panduan Bantuan
             // Logika Gembok
             var $helpBtn = $('<button class="md-btn-icon" title="Panduan Fitur">' + svgHelp + ' Bantuan</button>');
             if(isSysop) {
             $helpBtn.on('click', startHelpTour);
                var lockTxt = isLocked ? svgs.unlock + ' Buka Kunci' : svgs.lock + ' Kunci';
             $actions.append($helpBtn);
                 var $btnLock = $(`<button class="md-btn ${isLocked ? 'md-btn-danger' : ''}">${lockTxt}</button>`);
 
                 $btnLock.on('click', function() {
             if (isSysop) {
                    isLocked = !isLocked;
                 var $lockBtn = $('<button class="md-btn-icon ' + (isLocked ? 'md-btn-lock' : '') + '">' + (isLocked ? svgLock+' Terkunci' : svgUnlock+' Terbuka') + '</button>');
                    saveData(isLocked ? 'Mengunci' : 'Membuka Kunci', rawContent, $(this));
                 $lockBtn.on('click', function() { isLocked = !isLocked; saveData('Ubah status gembok', $(this), rawContent); });
                });
                 $actions.append($lockBtn);
                 $actions.append($btnLock);
             } else if (isLocked) {
             } else if (isLocked) {
                 var $btnLockedView = $(`<button class="md-btn md-btn-danger">${svgs.lock} Dilindungi</button>`);
                 $actions.append('<button class="md-btn-icon md-btn-lock" id="btn-lock-info">' + svgLock + ' Terkunci</button>');
                 $btnLockedView.on('click', showLockNotice);
                 setTimeout(()=> $('#btn-lock-info').on('click', showLockExplanation), 100);
                $actions.append($btnLockedView);
             }
             }


             if(!isLocked || isSysop) {
             var $addBtn = $('<button class="md-btn-icon" id="btn-add-data" style="background:#4f46e5; color:#fff; border-color:#4338ca;">' + svgEdit + ' Tambah Data</button>');
                var $btnAdd = $(`<button class="md-btn md-btn-primary">${svgs.edit} Tambah</button>`);
            $addBtn.on('click', function() {
                $btnAdd.on('click', function() { showFormModal(-1, rawContent); });
                 if(!isSysop && isLocked) { showLockExplanation(); return; }
                $actions.append($btnAdd);
                showFormModal(-1, rawContent);
               
            });
                // FAB untuk Mobile
            $actions.append($addBtn);
                 if(window.innerWidth < 768) {
                    var $fab = $(`<button class="md-btn-fab">${svgs.edit}</button>`);
                    $fab.on('click', function() { showFormModal(-1, rawContent); });
                    $('body').append($fab);
                }
            }


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


             // Render List Data
             // DAFTAR DATA
             var $list = $('<div></div>');
             var $list = $('<div class="md-list"></div>');
             if(dataItems.length === 0) {
             if (dataItems.length === 0) {
                 $list.append('<div style="text-align:center; padding:30px; color:var(--md-text-muted);">Belum ada data tersedia.</div>');
                 $list.append('<div style="text-align:center; padding: 25px 10px; background:#f8fafc; border-radius:10px; color:#64748b;">Belum ada data. Klik Tambah Data.</div>');
             } else {
             } else {
                 dataItems.forEach(function(item, idx) {
                 dataItems.forEach(function(item, index) {
                     var $row = $('<div class="md-row-display"></div>');
                     var $row = $('<div class="md-row-display"></div>');
                    var $info = $('<div></div>');
                      
                      
                     $info.append(`<div class="md-data-label">${item.prop}</div>`);
                    // REORDER BUTTONS (Naik / Turun)
                     $info.append(`<div class="md-data-value">${item.val}</div>`);
                    if (!isLocked || isSysop) {
                        var $orderCol = $('<div style="display:flex; flex-direction:column; gap:4px; margin-right:12px;"></div>');
                        var $up = $('<button style="background:none; border:none; color:#cbd5e1; cursor:pointer;" title="Naikkan Data">'+svgUp+'</button>');
                        var $down = $('<button style="background:none; border:none; color:#cbd5e1; cursor:pointer;" title="Turunkan Data">'+svgDown+'</button>');
                       
                        if(index > 0) {
                            $up.on('click', function() {
                                var temp = dataItems[index-1];
                                dataItems[index-1] = dataItems[index];
                                dataItems[index] = temp;
                                saveData('Reorder baris data', null, rawContent);
                            });
                            $up.css('color', '#64748b').hover(function(){$(this).css('color','#4f46e5')}, function(){$(this).css('color','#64748b')});
                        } else { $up.css('visibility', 'hidden'); }
 
                        if(index < dataItems.length - 1) {
                            $down.on('click', function() {
                                var temp = dataItems[index+1];
                                dataItems[index+1] = dataItems[index];
                                dataItems[index] = temp;
                                saveData('Reorder baris data', null, rawContent);
                            });
                            $down.css('color', '#64748b').hover(function(){$(this).css('color','#4f46e5')}, function(){$(this).css('color','#64748b')});
                        } else { $down.css('visibility', 'hidden'); }
 
                        $orderCol.append($up).append($down);
                        $row.append($orderCol);
                    }
 
                    var $info = $('<div class="md-data-group"></div>');
                     $info.append('<span class="md-data-label">' + item.prop + '</span>');
                   
                    var displayValHtml = item.val;
                    if(item.val.match(/^https?:\/\//i)) displayValHtml = '<a href="'+item.val+'" target="_blank" style="color:#2563eb;">'+extractDomain(item.val)+'</a>';
                   
                    var $valWrap = $('<div style="display:flex; align-items:center;"></div>');
                     $valWrap.append('<span class="md-data-value">' + displayValHtml + '</span>');
                      
                      
                     // 1. TAMPILAN REFERENSI BARU (TOMBOL BADGE -> POP-UP)
                     var $copyBtn = $('<button class="md-btn-copy" title="Salin">' + svgCopy + '</button>');
                     if(item.ref && (item.ref.url || item.ref.title)) {
                    $copyBtn.on('click', function() {
                         var $refBtn = $(`<button class="md-ref-trigger">${svgs.ref} Referensi [${idx+1}]</button>`);
                        navigator.clipboard.writeText(item.val);
                         $refBtn.on('click', function() { showRefDetails(item.ref); });
                        showToast('Nilai data tersalin!', 'success');
                         $info.append($refBtn);
                    });
                    $valWrap.append($copyBtn);
                    $info.append($valWrap);
 
                    // MINI REFERENCE BADGE (Click to open Popup)
                     if (item.ref && (item.ref.url || item.ref.title)) {
                         var $refBadge = $('<div class="md-ref-badge-trigger" title="Klik untuk lihat detail referensi">' + svgRef + ' [1] Rujukan</div>');
                         $refBadge.on('click', function() { showRefModal(item.ref); });
                         $info.append($refBadge);
                     }
                     }
 
                   
                     $row.append($info);
                     $row.append($info);


                     if(!isLocked || isSysop) {
                     if (!isLocked || isSysop) {
                         var $editBtn = $(`<button class="md-btn" style="height:fit-content;">Edit</button>`);
                         var $editBtn = $('<button class="md-btn-icon" style="padding:6px 10px; font-size:0.75rem;">' + svgEdit + '</button>');
                         $editBtn.on('click', function() { showFormModal(idx, rawContent); });
                         $editBtn.on('click', function() { showFormModal(index, rawContent); });
                         $row.append($editBtn);
                         $row.append($editBtn);
                     }
                     }
Baris 451: Baris 350:
                 });
                 });
             }
             }
            $app.append($list);
            $('.md-native-render').hide();
            var $infobox = $('.infobox').first();
            if ($infobox.length) $app.insertAfter($infobox); else $('#mw-content-text .mw-parser-output').append($app);
        }
        // 9. FORM EDIT POP-UP MODAL
        function showFormModal(index, rawContent) {
            var isNew = index === -1;
            var cData = isNew ? { prop:'', val:'', ref:{} } : dataItems[index];
            var cRef = cData.ref || {};
            var html = '';
            html += '<div class="md-form-group"><label>Label Data</label><input type="text" id="md-inp-prop" class="md-input" value="'+(cData.prop||'')+'"></div>';
              
              
             $app.append($list);
             // Presets
            html += '<div style="margin-bottom:14px;">';
            PRESET_LABELS.forEach(l => html += '<span class="md-preset-pill" onclick="$(\'#md-inp-prop\').val(\''+l+'\'); $(\'#md-inp-val\').focus();">'+l+'</span>');
            html += '</div>';
 
            html += '<div class="md-form-group"><label>Nilai Data</label><input type="text" id="md-inp-val" class="md-input" value="'+(cData.val||'')+'"></div>';
              
              
             var $infobox = $('.infobox').first();
             // Referensi Area
            $('.md-native-render').hide();
            html += '<div style="background:#f8fafc; padding:14px; border-radius:12px; border:1px solid #e2e8f0; margin-top:20px;">';
            if($infobox.length) $app.insertAfter($infobox);
            html += '<h4 style="margin:0 0 10px 0; font-size:0.9rem; color:#4f46e5; display:flex; align-items:center; gap:6px;">'+svgRef+' Tambah Rujukan (Opsional)</h4>';
            else $('#mw-content-text .mw-parser-output').append($app);
            html += '<div style="display:grid; grid-template-columns:1fr 1fr; gap:10px;">';
            html += '<input type="text" id="md-ref-title" class="md-input" style="grid-column:span 2;" placeholder="Judul Referensi" value="'+(cRef.title||'')+'">';
            html += '<input type="url" id="md-ref-url" class="md-input" style="grid-column:span 2;" placeholder="URL / Link (https://...)" value="'+(cRef.url||'')+'">';
            html += '<input type="text" id="md-ref-author" class="md-input" placeholder="Penulis" value="'+(cRef.author||'')+'">';
            html += '<input type="text" id="md-ref-publisher" class="md-input" placeholder="Penerbit / Web" value="'+(cRef.publisher||'')+'">';
            html += '</div></div>';
 
            html += '<div style="display:flex; gap:10px; margin-top:20px; flex-wrap:wrap;">';
            html += '<button id="md-modal-save" class="md-btn md-btn-save">Simpan Data <span class="md-spinner"></span></button>';
            if(!isNew) html += '<button id="md-modal-del" class="md-btn" style="background:#ef4444;">Hapus</button>';
            html += '</div>';
 
            openModal(isNew ? 'Tambah Data Baru' : 'Edit Data', html, function($body, $overlay) {
                // Auto Capitalize Event
                $body.find('#md-inp-prop').on('input', function() {
                    var val = $(this).val();
                    if(val.length > 0) $(this).val(val.charAt(0).toUpperCase() + val.slice(1));
                });
 
                $body.find('#md-modal-save').on('click', function() {
                    var nProp = $('#md-inp-prop').val().trim();
                    var nVal = $('#md-inp-val').val().trim();
                    if(!nProp || !nVal) { showToast('Label dan Nilai harus diisi!', 'error'); return; }
 
                    var rTitle = $('#md-ref-title').val().trim();
                    var rUrl = $('#md-ref-url').val().trim();
                    var refObj = null;
                    if(rTitle || rUrl) {
                        refObj = {
                            title: rTitle, url: ensureHttps(rUrl),
                            author: $('#md-ref-author').val().trim(), publisher: $('#md-ref-publisher').val().trim()
                        };
                    }
 
                    var newItem = { prop: nProp, val: nVal, ref: refObj };
                    if(isNew) dataItems.push(newItem); else dataItems[index] = newItem;
                    saveData(isNew ? 'Tambah data popup' : 'Edit data popup', $(this), rawContent);
                });
 
                if(!isNew) {
                    $body.find('#md-modal-del').on('click', function() {
                        if(confirm('Yakin hapus data ini?')) {
                            dataItems.splice(index, 1);
                            saveData('Hapus data popup', $(this), rawContent);
                        }
                    });
                }
            });
         }
         }


        // --- EXECUTE ---
         loadData().then(function(rawContent) { buildUI(rawContent); });
         loadData().then(function(rawContent) { buildUI(rawContent); });
     });
     });