MediaWiki:Common.js: Perbedaan antara revisi

Admin (bicara | kontrib)
Tidak ada ringkasan suntingan
Tanda: Dikembalikan Suntingan perangkat seluler Suntingan peramban seluler
Admin (bicara | kontrib)
Tidak ada ringkasan suntingan
 
(23 revisi perantara oleh pengguna yang sama tidak ditampilkan)
Baris 1: Baris 1:
/**
/**
  * ====================================================================
  * ====================================================================
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V9.0 PRO MOBILE)
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.7 SECURE ULTIMATE)
  * Fitur: No-Emoji, Mobile Responsive, 15 Auto Features, Clean UI.
  * Fitur: ALL ORIGINAL V8 FEATURES KEPT + Global Social Media Box,
* Smart Autocomplete/Preview Wikilink, Ultra-Strict Security, Mobile Ready.
  * ====================================================================
  * ====================================================================
  */
  */
Baris 17: Baris 18:
         var dataItems = [];
         var dataItems = [];
         var isLocked = false;
         var isLocked = false;
        var isDarkMode = false;
        var isReadOnly = false;
         var api = new mw.Api();
         var api = new mw.Api();
        var DRAFT_KEY = 'mippedia_data_draft_' + pageName;


         // 1. DATA MASTER PLATFORM MEDIA SOSIAL & MUSIK
         // 1. DATA MASTER PLATFORM MEDIA SOSIAL & MUSIK (FULL ASLI)
         var SOCIAL_PLATFORMS = {
         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>' },
             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>' },
Baris 38: Baris 38:
         };
         };


        // 2. PRESET & MASTER RUJUKAN
         var PRESET_LABELS = [
         var PRESET_LABELS = [
             "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan",  
             "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan",  
Baris 45: Baris 46:


         var REF_TYPES = {
         var REF_TYPES = {
             "Berita": ["Berita Online / Portal", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus", "Editorial / Opini"],
             "Berita": ["Berita Online", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus", "Editorial", "Investigasi Media", "Siaran Radio / TV"],
             "Website": ["Situs Resmi / Official", "Blog / Portal Informasi", "Basis Data / Database Web", "Portal Komunitas"],
             "Website": ["Situs Resmi", "Portal Informasi", "Database Web", "Portal Komunitas", "Forum Diskusi", "Portal Edukasi", "Direktori Web"],
             "Buku": ["Buku Cetak", "E-Book", "Bab / Bagian Buku", "Monograf"],
             "Buku": ["Buku Cetak", "E-Book", "Bab / Bagian Buku", "Monograf", "Katalog / Biografi Cetak", "Buku Teks Akademik"],
             "Jurnal": ["Jurnal Ilmiah Peer-Reviewed", "Paper Konferensi", "Artikel Review"],
             "Jurnal": ["Jurnal Ilmiah Peer-Reviewed", "Paper Konferensi", "Artikel Review", "Pre-print / Draft Penelitian", "Tesis / Disertasi"],
             "Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists", "Apple Music Catalogue"],
            "Siaran Pers": ["Siaran Pers Resmi", "Pengumuman Instansi / BUMN", "Pernyataan Pers Hukrim", "Keterangan Pers Artis/Manajemen"],
             "Video": ["YouTube Video", "Film Dokumenter", "Wawancara Video"],
            "Dokumen PDF": ["Laporan Tahunan / Annual Report", "Dokumen Kebijakan / Regulasi", "Brosur / Pamflet Resmi", "Naskah Akademik"],
             "Media Sosial": ["Postingan / Tweet", "Video Singkat (Reels/TikTok)", "Live Stream"]
             "Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists", "Database BPI / RIAA", "Songfacts", "Apple Music Catalogue"],
             "Video": ["YouTube Video", "Film Dokumenter", "Wawancara Video", "Arsip Siaran TV", "Vlog Resmi"],
            "Podcast": ["Episode Podcast", "Siniar Audio Resmi", "Wawancara Audio"],
             "Media Sosial": ["Postingan / Tweet", "Video Singkat (Reels/TikTok/Shorts)", "Live Stream", "Thread Resmi"],
            "Ensiklopedia": ["Ensiklopedia Cetak", "Ensiklopedia Online", "Kamus / Glosarium"],
            "Arsip": ["Arsip Nasional / Sejarah", "Web Archive (Wayback Machine)", "Dokumen Manuskrip"]
         };
         };


         // 2. IKON SISTEM FAST SVG (PURE, NO EMOJIS)
         var VERIFIED_DOMAINS = [
        var svgDatabase = '<svg class="md-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path></svg>';
            'kompas.com', 'kompas.id', 'detik.com', 'cnnindonesia.com', 'tribunnews.com', 'kumparan.com', 'tirto.id',
         var svgEdit = '<svg class="md-icon" 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>';
            'youtube.com', 'spotify.com', 'apple.com', 'musicbrainz.org', 'billboard.com', 'rollingstone.com',  
         var svgLock = '<svg class="md-icon" width="14" height="14" 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>';
            'bbc.com', 'nytimes.com', 'instagram.com', 'x.com', 'twitter.com', 'facebook.com', 'wikipedia.org', 'imdb.com'
         var svgUnlock = '<svg class="md-icon" width="14" height="14" 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="13" height="13" 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>';
 
        // 3. IKON SISTEM
         var svgEdit = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>';
         var svgLock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>';
         var svgUnlock = '<svg class="md-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>';
         var svgRef = '<svg class="md-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>';
         var svgCopy = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
         var svgCopy = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
        var svgClone = '<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><line x1="15.5" y1="12" x2="15.5" y2="18"></line><line x1="12.5" y1="15" x2="18.5" y2="15"></line></svg>';
         var svgSearch = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>';
         var svgSearch = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>';
         var svgCode = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>';
         var svgCode = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>';
         var svgCsv = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="8" y1="13" x2="16" y2="13"></line><line x1="8" y1="17" x2="16" y2="17"></line></svg>';
         var svgVerified = '<svg width="15" height="15" viewBox="0 0 24 24" fill="#3b82f6" stroke="#ffffff" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>';
         var svgMoon = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>';
         var svgHelp = '<svg width="14" height="14" 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 svgWikitext = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7V4h16v3M9 20h6M12 4v16"/></svg>';
        var svgView = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>';


         // 3. HELPER & NEW AUTOMATION UTILITIES
         // 4. HELPER UTILITY & ADVANCED SECURITY
        function sanitizeHTML(str) {
            if (typeof str !== 'string') return str;
            return str.replace(/[&<>"'`=\/]/g, function(s) {
                return {
                    '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;',
                    "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;'
                }[s];
            });
        }
        function isVerifiedSite(urlStr) {
            if(!urlStr) return false;
            var domain = extractDomain(urlStr);
            return VERIFIED_DOMAINS.some(function(vd) { return domain === vd || domain.endsWith('.' + vd); });
        }
         function formatIndonesianDate(dateStr) {
         function formatIndonesianDate(dateStr) {
             if (!dateStr) return '';
             if (!dateStr) return '';
Baris 78: Baris 100:
             var monthIdx = parseInt(parts[1], 10) - 1;
             var monthIdx = parseInt(parts[1], 10) - 1;
             var year = parts[0];
             var year = parts[0];
             if (isNaN(day) || monthIdx < 0 || monthIdx > 11 || isNaN(year)) return dateStr;
             if (isNaN(day) || monthIdx < 0 || monthIdx > 11 || isNaN(year)) return sanitizeHTML(dateStr);
             return day + ' ' + months[monthIdx] + ' ' + year;
             return day + ' ' + months[monthIdx] + ' ' + year;
         }
         }
         function extractDomain(urlStr) {
         function extractDomain(urlStr) {
             try {
             try {
                 if (!urlStr.match(/^https?:\/\//i)) urlStr = 'https://' + urlStr;
                 if (!urlStr.match(/^https?:\/\//i)) urlStr = 'https://' + urlStr;
                 var parsed = new URL(urlStr);
                 return new URL(urlStr).hostname.replace(/^www\./, '');
                return parsed.hostname.replace(/^www\./, '');
             } catch(e) { return urlStr.replace(/^https?:\/\/(www\.)?/, '').split('/')[0]; }
             } catch(e) {
                return urlStr.replace(/^https?:\/\/(www\.)?/, '').split('/')[0];
            }
         }
         }
        // FITUR 13: Auto Reference Cleaner (Bersihkan URL Parameter Tracking)
        function cleanReferenceUrl(urlStr) {
            if (!urlStr) return '';
            try {
                if (!urlStr.match(/^https?:\/\//i)) urlStr = 'https://' + urlStr;
                var urlObj = new URL(urlStr);
                var paramsToStrip = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid'];
                paramsToStrip.forEach(p => urlObj.searchParams.delete(p));
                return urlObj.toString();
            } catch(e) { return urlStr; }
        }
         function ensureHttps(urlStr) {
         function ensureHttps(urlStr) {
             if (!urlStr) return '';
             if (!urlStr) return '';
             urlStr = urlStr.trim();
             urlStr = urlStr.trim();
             // FITUR 8: Auto Protocol Inserter
             var protoMatch = urlStr.match(/^([a-z0-9]+):/i);
            if (urlStr && !urlStr.match(/^https?:\/\//i)) return 'https://' + urlStr;
             if (protoMatch) {
             return cleanReferenceUrl(urlStr);
                var badProtos = ['javascript', 'data', 'vbscript', 'file', 'ws', 'wss', 'ftp'];
        }
                if (badProtos.indexOf(protoMatch[1].toLowerCase()) !== -1) return '';
 
             }
        function cleanHandle(val) {
            return (urlStr && !urlStr.match(/^https?:\/\//i)) ? 'https://' + urlStr : urlStr;
            if (!val) return '';
            val = val.trim();
            val = val.replace(/^https?:\/\/(www\.)?[^\/]+\/@?/, '');
            val = val.replace(/^@/, '');
            return val.split('/')[0].split('?')[0];
        }
 
        // FORMAT: NO EMOJIS. Professional Pure Text Badges
        function detectDataTypeBadge(item) {
            var val = item.val || '';
            // FITUR 12: Smart Date Validator RegExp
            if (val.match(/^\d{4}-\d{2}-\d{2}$/)) return '<span class="md-type-tag md-tag-date">Date</span>';
             if (val.match(/^https?:\/\//i)) return '<span class="md-type-tag md-tag-link">External Link</span>';
            if (item.linkTarget) return '<span class="md-type-tag md-tag-piped">Piped Link</span>';
            if (item.link) return '<span class="md-type-tag md-tag-wiki">Wikilink</span>';
            return '<span class="md-type-tag md-tag-text">Text</span>';
         }
         }
 
         function getTodayString() {
        // FITUR 10: Data Type Demographics
             var now = new Date();
         function calculateDataStats() {
             var y = now.getFullYear();
             var stats = { date: 0, link: 0, wiki: 0, text: 0 };
            var m = String(now.getMonth() + 1).padStart(2, '0');
             dataItems.forEach(function(item) {
             var d = String(now.getDate()).padStart(2, '0');
                var val = item.val || '';
             return y + '-' + m + '-' + d;
                if (val.match(/^\d{4}-\d{2}-\d{2}$/)) stats.date++;
                else if (val.match(/^https?:\/\//i)) stats.link++;
                else if (item.link || item.linkTarget) stats.wiki++;
                else stats.text++;
            });
            return stats;
        }
 
        function calculateQualityScore() {
            if (dataItems.length === 0) return 0;
             var score = 0;
            dataItems.forEach(function(item) {
                var itemScore = 50;
                if (item.ref && (item.ref.url || item.ref.title)) itemScore += 30;
                if (item.link || item.linkSplit || item.linkTarget) itemScore += 10;
                if (item.isPersonOrg && item.socials && Object.keys(item.socials).length > 0) itemScore += 10;
                score += itemScore;
            });
             return Math.min(100, Math.round(score / dataItems.length));
         }
         }


         // FITUR 4: CSV Export Logic
         // 5. STYLESHEET (TERMASUK LAYOUT MEDIA SOSIAL GLOBAL & AUTOCOMPLETE)
        function exportToCSV() {
            var headers = ["Label Data", "Nilai Data", "Tipe Link", "Target Piped", "URL Referensi", "Judul Referensi", "Situs Referensi"];
            var rows = [headers];
            dataItems.forEach(function(item) {
                var ref = item.ref || {};
                var linkType = item.linkSplit ? "Split" : (item.link ? "Standard" : "None");
                var row = [
                    '"' + (item.prop || '').replace(/"/g, '""') + '"',
                    '"' + (item.val || '').replace(/"/g, '""') + '"',
                    '"' + linkType + '"',
                    '"' + (item.linkTarget || '').replace(/"/g, '""') + '"',
                    '"' + (ref.url || '').replace(/"/g, '""') + '"',
                    '"' + (ref.title || '').replace(/"/g, '""') + '"',
                    '"' + (ref.site || '').replace(/"/g, '""') + '"'
                ];
                rows.push(row.join(","));
            });
            var csvContent = "data:text/csv;charset=utf-8," + rows.join("\n");
            var encodedUri = encodeURI(csvContent);
            var link = document.createElement("a");
            link.setAttribute("href", encodedUri);
            link.setAttribute("download", "Mippedia_Data_" + pageName + ".csv");
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
 
        // 4. STYLESHEET V9.0 (MOBILE OPTIMIZED, NO EMOJIS, HIGH-PERFORMANCE ANIMATIONS)
         var css = `
         var css = `
             #mippedia-data-app {
             #mippedia-data-app {
                 background: #ffffff; border-radius: 12px;
                 background: #ffffff; border-radius: 16px; box-shadow: 0 4px 24px rgba(0,0,0,0.06);
                 padding: 24px; margin: 24px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
                 padding: 20px; margin: 20px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                 border: 1px solid #e2e8f0; width: 100%; box-sizing: border-box;  
                 border: 1px solid #e2e8f0; max-width: 100%; box-sizing: border-box; overflow: hidden;
                transition: background 0.3s cubic-bezier(0.4, 0, 0.2, 1), border 0.3s;
                overflow: hidden;
             }
             }
            #mippedia-data-app * { box-sizing: border-box; }
             .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 #f1f5f9; }
            #mippedia-data-app.md-dark { background: #0f172a; border-color: #334155; color: #f8fafc; }
             .md-title-container { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 180px; }
            #mippedia-data-app.md-dark .md-title { color: #f8fafc; }
             .md-title { font-size: 1.25rem; font-weight: 800; color: #0f172a; margin: 0; white-space: nowrap; }
            #mippedia-data-app.md-dark .md-row-display { background: #1e293b; border-color: #334155; }
            #mippedia-data-app.md-dark .md-data-value { color: #f1f5f9; }
            #mippedia-data-app.md-dark .md-ref-card { background: #0f172a; border-color: #334155; }
            #mippedia-data-app.md-dark .md-form-box { background: #1e293b; border-color: #334155; }
            #mippedia-data-app.md-dark .md-input, #mippedia-data-app.md-dark .md-select, #mippedia-data-app.md-dark .md-textarea { background: #0f172a; border-color: #475569; color: #fff; }
           
             .md-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 16px; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid #f1f5f9; }
            #mippedia-data-app.md-dark .md-header { border-color: #334155; }
             .md-title-container { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; }
             .md-title { font-size: 1.25rem; font-weight: 700; color: #0f172a; margin: 0; letter-spacing: -0.5px; display:flex; align-items:center; gap:8px;}
             .md-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
             .md-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
              
              
             .md-btn-icon {
             .md-btn-icon {
                 background: #f8fafc; border: 1px solid #cbd5e1; cursor: pointer; color: #3b82f6;
                 background: #f8fafc; border: 1px solid #cbd5e1; cursor: pointer; color: #4f46e5;
                 padding: 8px 14px; border-radius: 6px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
                 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; white-space: nowrap;
                 display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600; white-space: nowrap;
             }
             }
             .md-btn-icon:hover:not(:disabled) { background: #eff6ff; border-color: #bfdbfe; transform: translateY(-1px); }
             .md-btn-icon:hover:not(:disabled) { background: #f1f5f9; border-color: #94a3b8; transform: translateY(-1px); }
            #mippedia-data-app.md-dark .md-btn-icon { background: #1e293b; border-color: #475569; color: #60a5fa; }
             .md-btn-lock { color: #dc2626; background: #fef2f2; border-color: #fca5a5; }
            #mippedia-data-app.md-dark .md-btn-icon:hover:not(:disabled) { background: #2dd4bf1a; border-color: #2dd4bf; }
             .md-btn-lock { color: #ef4444; background: #fef2f2; border-color: #fecaca; }


            /* Stats & Score Bar */
             .md-search-box { position: relative; margin-bottom: 16px; width: 100%; box-sizing: border-box; }
             .md-dashboard { display: grid; grid-template-columns: 1fr auto; gap: 16px; margin-bottom: 20px; align-items: center; }
             .md-search-input { width: 100%; padding: 8px 12px 8px 34px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 0.85rem; box-sizing: border-box; background: #f8fafc; transition: 0.2s; }
             .md-score-box { background: #f8fafc; padding: 12px 16px; border-radius: 8px; border: 1px solid #e2e8f0; width: 100%; }
             .md-search-input:focus { background: #fff; border-color: #4f46e5; outline: none; }
            #mippedia-data-app.md-dark .md-score-box { background: #182234; border-color: #334155; }
             .md-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: #94a3b8; }
            .md-score-bar-bg { background: #e2e8f0; height: 4px; border-radius: 4px; overflow: hidden; margin-top: 8px; }
            .md-score-bar-fill { background: linear-gradient(90deg, #3b82f6, #10b981); height: 100%; transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1); }
           
             .md-stats-group { display: flex; gap: 8px; font-size: 0.75rem; font-weight: 600; color: #64748b; flex-wrap: wrap; }
             .md-stat-badge { background: #f1f5f9; padding: 4px 10px; border-radius: 20px; border: 1px solid #cbd5e1; }
            #mippedia-data-app.md-dark .md-stat-badge { background: #0f172a; border-color: #475569; color: #94a3b8; }


             .md-search-box { position: relative; margin-bottom: 16px; width: 100%; }
            /* Kotak Global Sosial Media Terpisah di Atas */
             .md-search-input { width: 100%; padding: 10px 14px 10px 38px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 0.9rem; background: #f8fafc; transition: all 0.2s; outline: none; }
             .md-global-social-box { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 16px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.02); }
             .md-search-input:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); background: #ffffff; }
             .md-social-box-title { font-size: 0.85rem; font-weight: 800; color: #475569; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; border-bottom: 1px dashed #cbd5e1; padding-bottom: 8px; }
             .md-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: #94a3b8; }
            .md-social-group { display: flex; flex-wrap: wrap; gap: 8px; }
             .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: transform 0.2s, opacity 0.2s; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
             .md-social-badge:hover { transform: translateY(-2px); opacity: 0.92; }


            /* List Rows */
             .md-row-display { display: flex; justify-content: space-between; align-items: flex-start; padding: 16px 12px; border-bottom: 1px solid #f1f5f9; transition: all 0.2s; border-radius: 12px; gap: 12px; margin-bottom: 8px; background: #fff; }
            .md-list { display: flex; flex-direction: column; gap: 10px; }
             .md-row-display:hover { background: #faf5ff; box-shadow: inset 4px 0 0 #6366f1; }
             .md-row-display {
                display: flex; justify-content: space-between; align-items: flex-start;
                padding: 16px; border: 1px solid #e2e8f0; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
                border-radius: 8px; gap: 16px; background: #ffffff;
            }
            .md-row-display:hover { border-color: #bfdbfe; background: #fafafa; }
             #mippedia-data-app.md-dark .md-row-display:hover { border-color: #475569; background: #1e293b; }
            .md-row-highlight { border-color: #3b82f6 !important; box-shadow: 0 0 0 1px #3b82f6; }
              
              
             .md-data-group { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
             .md-data-group { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
             .md-data-label-wrap { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
             .md-data-label { font-size: 0.72rem; color: #64748b; font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; }
             .md-data-label { font-size: 0.75rem; color: #64748b; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; }
            .md-data-value-wrap { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
             .md-data-value { font-size: 1.02rem; color: #0f172a; line-height: 1.4; font-weight: 600; word-break: break-word; }
              
              
            /* Professional Tags */
             .md-btn-copy { background: none; border: none; color: #94a3b8; cursor: pointer; padding: 2px 4px; border-radius: 4px; transition: 0.2s; display: inline-flex; align-items: center; }
             .md-type-tag { font-size: 0.65rem; padding: 2px 8px; border-radius: 4px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; border: 1px solid transparent; }
             .md-btn-copy:hover { color: #4f46e5; background: #e0e7ff; }
            .md-tag-date { color: #1d4ed8; background: #dbeafe; border-color: #bfdbfe; }
            .md-tag-link { color: #be123c; background: #ffe4e6; border-color: #fecdd3; }
            .md-tag-piped { color: #b45309; background: #fef3c7; border-color: #fde68a; }
             .md-tag-wiki { color: #15803d; background: #dcfce7; border-color: #bbf7d0; }
            .md-tag-text { color: #475569; background: #f1f5f9; border-color: #cbd5e1; }


             .md-data-value-wrap { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
             .md-ref-container { margin-top: 10px; width: 100%; box-sizing: border-box; }
             .md-data-value { font-size: 1rem; color: #0f172a; line-height: 1.5; font-weight: 600; word-wrap: break-word; overflow-wrap: break-word; }
            .md-ref-details { background: #f8fafc; border-left: 3px solid #4f46e5; border-radius: 10px; overflow: hidden; border-top:1px solid #f1f5f9; border-right:1px solid #f1f5f9; border-bottom:1px solid #f1f5f9; transition: 0.3s; }
            .md-ref-details summary { display: flex; padding: 10px 14px; font-size: 0.85rem; font-weight: 700; color: #374151; cursor: pointer; user-select: none; list-style: none; flex-wrap: nowrap; align-items: center; gap: 8px; }
            .md-ref-details summary::-webkit-details-marker { display: none; }
             .md-ref-details[open] summary { border-bottom: 1px dashed #cbd5e1; background: #e0e7ff; color: #3730a3; }
            .md-ref-body { padding: 12px 14px; font-size: 0.85rem; display: flex; flex-direction: column; gap: 6px; }
              
              
             .md-btn-mini { background: none; border: none; color: #94a3b8; cursor: pointer; padding: 4px 6px; border-radius: 4px; transition: 0.2s; display: inline-flex; align-items: center; }
             .md-verified-badge { cursor: pointer; display: inline-flex; align-items: center; justify-content: center; margin-left: 4px; vertical-align: middle; transition: transform 0.2s; flex-shrink: 0; }
             .md-btn-mini:hover { color: #3b82f6; background: #eff6ff; }
            .md-verified-badge:hover { transform: scale(1.1); }
            .md-btn-visit { background: #f1f5f9; color: #0f172a; padding: 6px 12px; border-radius: 6px; text-decoration: none; font-size: 0.8rem; display: inline-block; width: fit-content; margin-top: 6px; font-weight:700; border:1px solid #cbd5e1; }
             .md-btn-visit:hover { background: #e2e8f0; text-decoration:none; }


            /* References */
             .md-preset-wrapper { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
             .md-ref-container { margin-top: 10px; width: 100%; }
             .md-preset-pill { background: #f1f5f9; border: 1px solid #cbd5e1; padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; color: #475569; cursor: pointer; transition: 0.2s; }
             .md-ref-card { background: #f8fafc; padding: 12px; border-radius: 6px; border-left: 3px solid #cbd5e1; font-size: 0.85rem; display: flex; flex-direction: column; gap: 4px; }
             .md-preset-pill:hover { background: #e0e7ff; color: #3730a3; border-color: #a5b4fc; }
            .md-ref-tag-header { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; color: #64748b; display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
             .md-ref-header { font-weight: 600; color: #2563eb; text-decoration: none; word-wrap: break-word; overflow-wrap: break-word; }


            /* Socials */
             .md-form-box { background: #ffffff; border-radius: 12px; padding: 18px; margin-top: 16px; border: 1px solid #cbd5e1; box-shadow: 0 4px 16px rgba(0,0,0,0.05); }
             .md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
             .md-form-title { font-size: 1.05rem; font-weight: 800; color: #0f172a; margin: 0 0 16px 0; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px; }
            .md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 20px; font-size: 0.75rem; font-weight: 600; color: white; text-decoration: none; transition: opacity 0.2s; }
             .md-form-group { margin-bottom: 14px; }
            .md-social-badge:hover { opacity: 0.9; color: white; text-decoration: none; }
             .md-form-group label { display: flex; align-items:center; font-size: 0.82rem; font-weight: 700; margin-bottom: 6px; color: #334155; }
 
             .md-preset-wrapper { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
            .md-preset-pill { background: #f1f5f9; border: 1px solid #cbd5e1; padding: 4px 10px; border-radius: 16px; font-size: 0.75rem; font-weight: 600; color: #475569; cursor: pointer; transition: 0.2s; }
            .md-preset-pill:hover { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
 
            /* Form UI */
            .md-form-box { background: #ffffff; border-radius: 8px; padding: 20px; margin-top: 20px; border: 1px solid #cbd5e1; transition: all 0.3s; }
            .md-form-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 16px; }
            .md-form-title { font-size: 1.1rem; font-weight: 700; color: #0f172a; margin: 0; }
           
             .md-form-group { margin-bottom: 16px; width: 100%; }
             .md-form-group label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 6px; color: #334155; }
              
              
             .md-input, .md-select, .md-textarea { width: 100%; padding: 10px 12px; border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box; font-family: inherit; font-size: 0.9rem; transition: all 0.2s; background: #fff; outline: none; }
             .md-input, .md-select, .md-textarea { width: 100%; padding: 9px 12px; border: 1px solid #cbd5e1; border-radius: 8px; box-sizing: border-box; font-family: inherit; font-size: 0.9rem; transition: 0.2s; background: #fff; }
             .md-input:focus, .md-select:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); }
             .md-input:focus, .md-select:focus, .md-textarea:focus { border-color: #4f46e5; outline: none; box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15); }
            .md-input.md-error { border-color: #ef4444; background: #fef2f2; }
              
              
             .md-char-count { font-size: 0.7rem; color: #94a3b8; text-align: right; margin-top: 4px; font-weight: 600; }
            /* Autocomplete Styles */
             .md-dup-alert { background: #fffbeb; border: 1px solid #fde68a; color: #b45309; padding: 8px 12px; border-radius: 6px; font-size: 0.8rem; margin-top: 6px; display: none; font-weight: 600; }
             .md-autocomplete-wrapper { position: relative; width: 100%; }
             .md-preview-card { background: #f8fafc; border: 1px dashed #cbd5e1; padding: 12px; border-radius: 6px; margin-top: 16px; font-size: 0.85rem; }
            .md-autocomplete-list { position: absolute; top: 100%; left: 0; right: 0; background: #fff; border: 1px solid #cbd5e1; border-radius: 0 0 8px 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 1000; display: none; max-height: 200px; overflow-y: auto; margin-top: -2px; }
             .md-autocomplete-item { padding: 10px 12px; font-size: 0.88rem; color: #0f172a; cursor: pointer; border-bottom: 1px solid #f1f5f9; transition: 0.2s; display: flex; align-items: center; gap: 8px; }
            .md-autocomplete-item:last-child { border-bottom: none; }
             .md-autocomplete-item:hover { background: #f8fafc; color: #4f46e5; padding-left: 16px; }


             .md-ref-grid, .md-social-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; background: #f8fafc; padding: 16px; border-radius: 6px; border: 1px solid #e2e8f0; }
             .md-ref-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: #f8fafc; padding: 12px; border-radius: 8px; border: 1px dashed #cbd5e1; }
             .md-social-grid { max-height: 250px; overflow-y: auto; }
             .md-social-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: #f1f5f9; padding: 12px; border-radius: 8px; border: 1px solid #cbd5e1; max-height: 280px; overflow-y: auto; }
             .md-grid-full { grid-column: span 2; }
             .md-grid-full { grid-column: span 2; }
              
              
             .md-form-actions { display: flex; gap: 10px; align-items: center; margin-top: 20px; padding-top: 16px; border-top: 1px solid #e2e8f0; flex-wrap: wrap; }
            .md-cc0-notice { background: #fef2f2; color: #991b1b; padding: 12px; border-radius: 8px; font-size: 0.82rem; line-height: 1.4; border-left: 4px solid #ef4444; margin-top: 15px; margin-bottom: 15px; }
             .md-btn { padding: 10px 18px; border: none; border-radius: 6px; font-weight: 600; cursor: pointer; color: white; font-size: 0.85rem; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; justify-content: center; }
            .md-edit-meta { background: #f8fafc; padding: 12px; border-radius: 8px; margin-bottom: 15px; border: 1px solid #e2e8f0; display:flex; flex-direction:column; gap:10px; }
             .md-btn-save { background: #3b82f6; flex: 1; min-width: 150px; }
           
             .md-btn-save:hover { background: #2563eb; }
            .md-help-icon { color: #64748b; cursor: pointer; margin-left: 6px; display:inline-flex; align-items:center; }
            .md-help-icon:hover { color: #4f46e5; }
            .md-tooltip-popup { position: absolute; background: #1e293b; color: #fff; padding: 10px 14px; border-radius: 8px; font-size: 0.8rem; width: 260px; max-width: calc(100vw - 30px); z-index: 1000; box-shadow: 0 4px 15px rgba(0,0,0,0.15); display: none; line-height: 1.4; text-align: left; font-weight:normal; }
            .md-tooltip-popup::after { content: ''; position: absolute; border-width: 6px; border-style: solid; border-color: #1e293b transparent transparent transparent; top: 100%; left: 15px; }
 
            .md-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); z-index: 9999; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(2px); }
            .md-modal-box { background: #fff; padding: 24px; border-radius: 12px; max-width: 400px; text-align: center; box-shadow: 0 10px 25px rgba(0,0,0,0.2); animation: mdPopIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
            @keyframes mdPopIn { 0% { transform: scale(0.8); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
 
             .md-form-actions { display: flex; gap: 10px; align-items: center; margin-top: 20px; padding-top: 14px; border-top: 1px solid #e2e8f0; flex-wrap: wrap; }
             .md-btn { padding: 10px 18px; border: none; border-radius: 8px; font-weight: 700; cursor: pointer; color: white; font-size: 0.85rem; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; justify-content: center; }
             .md-btn:hover:not(:disabled) { transform: translateY(-1px); }
             .md-btn-save { background: linear-gradient(135deg, #4f46e5, #4338ca); flex: 1; min-width: 140px; }
             .md-btn-cancel { background: #64748b; }
             .md-btn-cancel { background: #64748b; }
             .md-btn-cancel:hover { background: #475569; }
             .md-btn-draft { background: #10b981; }
             .md-btn-delete { background: #ef4444; margin-left: auto; }
             .md-btn-delete { background: #dc2626; margin-left: auto; }
            .md-btn-delete:hover { background: #dc2626; }
            .md-btn-reset { background: transparent; border: 1px solid #cbd5e1; color: #64748b; }
            .md-btn-reset:hover { background: #f1f5f9; color: #0f172a; }
              
              
             .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.6s linear infinite; }
             .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; }
             .is-loading .md-spinner { display: inline-block; }
             @keyframes md-spin { to { transform: rotate(360deg); } }
             @keyframes md-spin { to { transform: rotate(360deg); } }


             /* MOBILE OPTIMIZATION (FITUR RESPONSIVE) */
             /* Mobile Optimized Layout (Seluler) */
             @media (max-width: 768px) {
             @media (max-width: 600px) {
                 #mippedia-data-app { padding: 16px; margin: 16px 0; border-radius: 8px; border-left: none; border-right: none; border-radius: 0; }
                 #mippedia-data-app { padding: 14px; margin: 14px 0; border-radius: 12px; }
                 .md-header { flex-direction: column; align-items: flex-start; gap: 12px; }
                 .md-header { flex-direction: column; align-items: flex-start; gap: 10px; }
                 .md-actions { width: 100%; display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
                 .md-actions { width: 100%; justify-content: flex-start; overflow-x:auto; padding-bottom:5px; }
                .md-btn-icon { justify-content: center; width: 100%; }
                 .md-btn-icon { padding: 7px 12px; font-size: 0.8rem; }
               
                 .md-ref-grid, .md-social-grid { grid-template-columns: 1fr; }
                .md-dashboard { grid-template-columns: 1fr; gap: 12px; }
               
                .md-row-display { flex-direction: column; padding: 14px; }
                 .md-row-actions { width: 100%; display: flex; justify-content: flex-end; padding-top: 8px; border-top: 1px solid #f1f5f9; }
               
                 .md-ref-grid, .md-social-grid { grid-template-columns: 1fr; padding: 12px; }
                 .md-grid-full { grid-column: span 1; }
                 .md-grid-full { grid-column: span 1; }
               
                 .md-form-actions { flex-direction: column; width: 100%; }
                 .md-form-actions { flex-direction: column; width: 100%; gap: 10px; }
                 .md-btn { width: 100%; margin: 0 !important; }
                 .md-btn { width: 100%; margin: 0 !important; }
                .md-row-display { padding: 12px 10px; flex-direction:column; align-items:stretch;}
                .edit-btn { align-self:flex-end; margin-top:8px; }
                .md-ref-details summary { align-items: flex-start; }
             }
             }
            .md-native-render { display: none; }
         `;
         `;
         $('<style>').text(css).appendTo('head');
         $('<style>').text(css).appendTo('head');


         // 5. PARSER & SAVE PIPELINE
         // 6. POPUP, MODAL & TOOLTIPS
        function showModal(title, text) {
            $('.md-modal-overlay').remove();
            var $overlay = $('<div class="md-modal-overlay"></div>');
            var $box = $('<div class="md-modal-box"><h3 style="margin-top:0; color:#0f172a;">' + sanitizeHTML(title) + '</h3><p style="font-size:0.9rem; color:#475569; margin:15px 0;">' + sanitizeHTML(text) + '</p><button class="md-btn md-btn-save" style="width:100%;">Tutup & Mengerti</button></div>');
            $box.find('button').on('click', function() { $overlay.remove(); });
            $overlay.append($box);
            $('body').append($overlay);
        }
 
        function initTooltips() {
            $('.md-help-icon').off('click').on('click', function(e) {
                $('.md-tooltip-popup').remove();
                e.stopPropagation();
                var $icon = $(this);
                var text = sanitizeHTML($icon.data('help'));
                var $tt = $('<div class="md-tooltip-popup">' + text + '</div>');
                $('body').append($tt);
               
                var offset = $icon.offset();
                var ttWidth = $tt.outerWidth();
                var winWidth = $(window).width();
                var leftPos = offset.left - 15;
               
                if (leftPos + ttWidth > winWidth - 15) leftPos = winWidth - ttWidth - 15;
                if (leftPos < 10) leftPos = 10;
               
                $tt.css({ top: offset.top - $tt.outerHeight() - 10, left: leftPos }).fadeIn(200);
            });
            $(document).off('click.mdtt').on('click.mdtt', function() { $('.md-tooltip-popup').fadeOut(200, function(){ $(this).remove(); }); });
        }
 
        // 7. PARSER WIKITEXT & PENYIMPANAN DATA
         function loadData() {
         function loadData() {
             return api.get({
             return api.get({
Baris 355: Baris 299:
         function buildWikitextVal(item) {
         function buildWikitextVal(item) {
             var val = item.val;
             var val = item.val;
             if (item.linkTarget && item.linkTarget.trim() !== '') return "[[" + item.linkTarget.trim() + "|" + val + "]]";
             if (item.linkTarget && item.linkTarget.trim() !== '') {
                return "[[" + item.linkTarget.trim() + "|" + val + "]]";
            }
             if (item.linkSplit) {
             if (item.linkSplit) {
                 return val.replace(/([a-zA-Z0-9_À-ÿ\- ]+)/g, function(match) {
                 return val.replace(/([a-zA-Z0-9_À-ÿ\- ]+)/g, function(match) {
                     var trimmed = match.trim();
                     var trimmed = match.trim();
                     if (trimmed.length > 2 && trimmed.toLowerCase() !== 'dan' && trimmed.toLowerCase() !== 'atau') return "[[" + trimmed + "]]";
                     if (trimmed.length > 2 && trimmed.toLowerCase() !== 'dan' && trimmed.toLowerCase() !== 'atau') {
                        return "[[" + trimmed + "]]";
                    }
                     return match;
                     return match;
                 });
                 });
             }
             }
             if (item.link) return "[[" + val + "]]";
             if (item.link) {
                return "[[" + val + "]]";
            }
             return val;
             return val;
         }
         }
Baris 369: Baris 319:
         function buildWikitextRef(refObj) {
         function buildWikitextRef(refObj) {
             if (!refObj) return "";
             if (!refObj) return "";
             var title = refObj.title || "Referensi";
             var title = refObj.title || "Rujukan";
             var text = refObj.url ? "[" + ensureHttps(refObj.url) + " " + title + "]" : "'''" + title + "'''";
             var text = refObj.url ? "[" + ensureHttps(refObj.url) + " " + title + "]" : "'''" + title + "'''";
             var details = [];
             var details = [];
Baris 375: Baris 325:
             if (refObj.site) details.push("Situs: " + refObj.site);
             if (refObj.site) details.push("Situs: " + refObj.site);
             if (refObj.publisher) details.push("Penerbit: " + refObj.publisher);
             if (refObj.publisher) details.push("Penerbit: " + refObj.publisher);
             if (refObj.date) details.push("Akses: " + formatIndonesianDate(refObj.date));
             if (refObj.date) details.push("Tanggal Akses: " + formatIndonesianDate(refObj.date));
             if (refObj.type) details.push("Jenis: " + refObj.type + (refObj.subType ? " (" + refObj.subType + ")" : ""));
             if (refObj.type) details.push("Jenis: " + refObj.type + (refObj.subType ? " (" + refObj.subType + ")" : ""));
           
             if (details.length > 0) text += " &mdash; <small>" + details.join(" &bull; ") + "</small>";
             if (details.length > 0) text += " &mdash; <small>" + details.join(" &bull; ") + "</small>";
             return text;
             return text;
         }
         }


         function saveData(actionType, $btnEl, originalContent) {
         function saveData(actionType, $btnEl, originalContent, customSummary, isMinorEdit) {
             if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
             if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
              
              
             // Bersihkan LocalStorage Draft saat disave
             var summaryTxt = customSummary ? ('Mippedia Data: ' + customSummary) : ('Mippedia Data V8.7: ' + actionType);
            localStorage.removeItem('md_draft_' + pageName);
 
             var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems });
             var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems });
             var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n";
             var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n";
Baris 407: Baris 356:


             api.postWithToken('csrf', {
             api.postWithToken('csrf', {
                 action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V9: ' + actionType, minor: false
                 action: 'edit', title: pageName, text: newContent, summary: summaryTxt, minor: isMinorEdit || false
             }).done(function() {
             }).done(function() {
                 window.location.href = location.pathname + "?refresh=" + new Date().getTime();
                 localStorage.removeItem(DRAFT_KEY);
                var nocacheUrl = location.pathname + "?refresh=" + new Date().getTime();
                window.location.href = nocacheUrl;
             }).fail(function(err) {
             }).fail(function(err) {
                 if ($btnEl) $btnEl.removeClass('is-loading').prop('disabled', false);
                 if ($btnEl) $btnEl.removeClass('is-loading').prop('disabled', false);
Baris 416: Baris 367:
         }
         }


         // 6. BUILDER UI UTAMA
         // 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 & TOOLS
             var $header = $('<div class="md-header"></div>');
             var $header = $('<div class="md-header"></div>');
             var $titleContainer = $('<div class="md-title-container"><h3 class="md-title">' + svgDatabase + ' Structured Data</h3></div>');
             var $titleContainer = $('<div class="md-title-container"><h3 class="md-title">' + svgEdit + ' Data Terstruktur</h3></div>');
             var $actions = $('<div class="md-actions"></div>');
             var $actions = $('<div class="md-actions"></div>');
              
              
             var $darkBtn = $('<button class="md-btn-icon" title="Theme Toggle">' + svgMoon + ' Theme</button>');
             var $jsonBtn = $('<button class="md-btn-icon" title="Ekspor/Impor JSON">' + svgCode + ' JSON</button>');
            $darkBtn.on('click', function() {
             $jsonBtn.on('click', function() { showJsonModal(rawContent); });
                isDarkMode = !isDarkMode;
             $actions.append($jsonBtn);
                $app.toggleClass('md-dark', isDarkMode);
            });
            $actions.append($darkBtn);
 
            // FITUR 6: Read-Only Mode
            var $viewBtn = $('<button class="md-btn-icon" title="View Only Mode">' + svgView + ' View</button>');
             $viewBtn.on('click', function() {
                isReadOnly = !isReadOnly;
                $app.find('.md-row-actions, .md-btn-mini').toggle(!isReadOnly);
                $(this).css('background', isReadOnly ? '#e0e7ff' : '');
            });
            $actions.append($viewBtn);
 
            $actions.append($('<button class="md-btn-icon" title="Export JSON">' + svgCode + ' JSON</button>').on('click', function() { showJsonModal(rawContent); }));
           
            // FITUR 4: CSV Export
             $actions.append($('<button class="md-btn-icon" title="Export CSV">' + svgCsv + ' CSV</button>').on('click', exportToCSV));


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


             if (!isLocked || isSysop) {
             if (!isLocked || isSysop) {
                 var $addBtn = $('<button class="md-btn-icon" style="background:#3b82f6; color:#fff; border-color:#2563eb;">' + svgEdit + ' Add New</button>');
                 var $addBtn = $('<button class="md-btn-icon" title="Tambah Data Baru">' + svgEdit + ' Tambah</button>');
                 $addBtn.on('click', function() { showForm(-1, rawContent); });
                 $addBtn.on('click', function() { showForm(-1, rawContent); });
                 $actions.append($addBtn);
                 $actions.append($addBtn);
Baris 464: Baris 397:
             $app.append($header);
             $app.append($header);


             // FITUR 10: DASHBOARD STATISTIK & SKOR KUALITAS
             // Tampilkan kotak pencarian jika data banyak
            var $dashboard = $('<div class="md-dashboard"></div>');
             if (dataItems.length > 2) {
            var score = calculateQualityScore();
                 var $searchBox = $('<div class="md-search-box"><span class="md-search-icon">' + svgSearch + '</span><input type="text" class="md-search-input" placeholder="Cari data terstruktur..."></div>');
            var $scoreBox = $('<div class="md-score-box"><div style="display:flex; justify-content:space-between; font-size:0.8rem; font-weight:700;"><span>Data Completeness</span><span>' + score + '%</span></div><div class="md-score-bar-bg"><div class="md-score-bar-fill" style="width:' + score + '%;"></div></div></div>');
            $dashboard.append($scoreBox);
 
            var stats = calculateDataStats();
            var $statsGroup = $('<div class="md-stats-group"></div>');
            $statsGroup.append('<span class="md-stat-badge">Text: ' + stats.text + '</span>');
            $statsGroup.append('<span class="md-stat-badge">Link: ' + stats.wiki + '</span>');
            $statsGroup.append('<span class="md-stat-badge">Ext. Web: ' + stats.link + '</span>');
            $statsGroup.append('<span class="md-stat-badge">Date: ' + stats.date + '</span>');
            $dashboard.append($statsGroup);
            $app.append($dashboard);
 
            // SEARCH BAR & FITUR 15 (Highlighting)
             if (dataItems.length > 0) {
                 var $searchBox = $('<div class="md-search-box"><span class="md-search-icon">' + svgSearch + '</span><input type="text" class="md-search-input" placeholder="Search data..."></div>');
                 $searchBox.find('input').on('keyup input', function() {
                 $searchBox.find('input').on('keyup input', function() {
                     var q = $(this).val().toLowerCase();
                     var q = $(this).val().toLowerCase();
                     $app.find('.md-row-display').each(function() {
                     $app.find('.md-row-display').each(function() {
                         var text = $(this).text().toLowerCase();
                         var text = $(this).text().toLowerCase();
                         var match = text.indexOf(q) !== -1;
                         $(this).toggle(text.indexOf(q) !== -1);
                        $(this).toggle(match);
                        if (q.length > 1 && match) { $(this).addClass('md-row-highlight'); }
                        else { $(this).removeClass('md-row-highlight'); }
                     });
                     });
                 });
                 });
Baris 495: Baris 410:
             }
             }


             // DAFTAR BARIS DATA (TANPA NAIK/TURUN)
             // MENGUMPULKAN MEDIA SOSIAL GLOBAL (Memisahkan media sosial ke atas)
            var globalSocials = {};
            dataItems.forEach(function(item) {
                if (item.isPersonOrg && item.socials) {
                    Object.assign(globalSocials, item.socials);
                }
            });
 
            if (Object.keys(globalSocials).length > 0) {
                var $topSocials = $('<div class="md-global-social-box"></div>');
                $topSocials.append('<div class="md-social-box-title">Media Sosial & Platform Resmi</div>');
                var $socialGroupGlobal = $('<div class="md-social-group"></div>');
               
                Object.keys(SOCIAL_PLATFORMS).forEach(function(key) {
                    var uname = globalSocials[key];
                    if (uname) {
                        var platform = SOCIAL_PLATFORMS[key];
                        var fullUrl = platform.base + uname.replace(/^@/, '');
                        var $badge = $('<a class="md-social-badge" href="' + sanitizeHTML(fullUrl) + '" target="_blank" rel="noopener noreferrer" style="background:' + platform.color + ';">' + platform.icon + ' ' + sanitizeHTML(platform.name) + '</a>');
                        $socialGroupGlobal.append($badge);
                    }
                });
                $topSocials.append($socialGroupGlobal);
                $app.append($topSocials);
            }
 
             var $list = $('<div class="md-list"></div>');
             var $list = $('<div class="md-list"></div>');
             if (dataItems.length === 0) {
             if (dataItems.length === 0) {
                 $list.append('<div style="color:#64748b; text-align:center; padding: 30px 10px; background:#f8fafc; border-radius:8px; border:1px dashed #cbd5e1; font-size:0.9rem;">No data entries found. Click <b>Add New</b> to create.</div>');
                 $list.append('<div style="color:#64748b; text-align:center; padding: 25px 10px; background:#f8fafc; border-radius:10px; border:1px dashed #cbd5e1; font-size:0.88rem;">Belum ada data terstruktur. Klik <b>Tambah</b> untuk membuat baru.</div>');
             } else {
             } else {
                 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 class="md-data-group"></div>');
                     var $info = $('<div class="md-data-group"></div>');
                   
                     $info.append('<span class="md-data-label">' + sanitizeHTML(item.prop) + '</span>');
                    var typeBadge = detectDataTypeBadge(item);
                     $info.append('<div class="md-data-label-wrap"><span class="md-data-label">' + item.prop + '</span>' + typeBadge + '</div>');
                      
                      
                     var displayValHtml = '';
                     var displayValHtml = '';
Baris 511: Baris 449:


                     if (rawVal.match(/^https?:\/\//i)) {
                     if (rawVal.match(/^https?:\/\//i)) {
                         displayValHtml = '<a href="' + rawVal + '" target="_blank" style="color:#2563eb; font-weight:600; text-decoration:none;">' + extractDomain(rawVal) + '</a>';
                         displayValHtml = '<a href="' + sanitizeHTML(rawVal) + '" target="_blank" rel="noopener noreferrer" style="color:#2563eb; font-weight:700; text-decoration:none;">' + extractDomain(rawVal) + '</a>';
                     } else if (item.linkTarget && item.linkTarget.trim() !== '') {
                     } else if (item.linkTarget && item.linkTarget.trim() !== '') {
                         displayValHtml = '<a href="' + mw.util.getUrl(item.linkTarget.trim()) + '" style="color:#2563eb; font-weight:600; text-decoration:none;">' + rawVal + '</a>';
                         displayValHtml = '<a href="' + mw.util.getUrl(item.linkTarget.trim()) + '" style="color:#2563eb; font-weight:700; text-decoration:none;">' + sanitizeHTML(rawVal) + '</a>';
                     } else if (item.linkSplit) {
                     } else if (item.linkSplit) {
                         var parts = rawVal.split(/([,/\s]+dan\s+|[,/\s]+atau\s+|[,/]+)/gi);
                         var parts = rawVal.split(/([,/\s]+dan\s+|[,/\s]+atau\s+|[,/]+)/gi);
Baris 519: Baris 457:
                             var trimmed = p.trim();
                             var trimmed = p.trim();
                             if (trimmed && !p.match(/^[,/\s]+$/) && trimmed.toLowerCase() !== 'dan' && trimmed.toLowerCase() !== 'atau') {
                             if (trimmed && !p.match(/^[,/\s]+$/) && trimmed.toLowerCase() !== 'dan' && trimmed.toLowerCase() !== 'atau') {
                                 return '<a href="' + mw.util.getUrl(trimmed) + '" style="color:#2563eb; font-weight:600; text-decoration:none;">' + trimmed + '</a>';
                                 return '<a href="' + mw.util.getUrl(trimmed) + '" style="color:#2563eb; font-weight:700; text-decoration:none;">' + sanitizeHTML(trimmed) + '</a>';
                             }
                             }
                             return p;
                             return sanitizeHTML(p);
                         }).join('');
                         }).join('');
                     } else if (item.link) {
                     } else if (item.link) {
                         displayValHtml = '<a href="' + mw.util.getUrl(rawVal) + '" style="color:#2563eb; font-weight:600; text-decoration:none;">' + rawVal + '</a>';
                         displayValHtml = '<a href="' + mw.util.getUrl(rawVal) + '" style="color:#2563eb; font-weight:700; text-decoration:none;">' + sanitizeHTML(rawVal) + '</a>';
                     } else {
                     } else {
                         displayValHtml = rawVal;
                         displayValHtml = sanitizeHTML(rawVal);
                     }
                     }


Baris 532: Baris 470:
                     $valWrap.append('<span class="md-data-value">' + displayValHtml + '</span>');
                     $valWrap.append('<span class="md-data-value">' + displayValHtml + '</span>');
                      
                      
                     var $copyBtn = $('<button class="md-btn-mini" title="Copy Text">' + svgCopy + '</button>');
                     var $copyBtn = $('<button class="md-btn-copy" title="Salin teks">' + svgCopy + '</button>');
                     $copyBtn.on('click', function() {
                     $copyBtn.on('click', function() {
                         navigator.clipboard.writeText(rawVal);
                         navigator.clipboard.writeText(rawVal);
                         $(this).css('color', '#16a34a');
                         $(this).css('color', '#16a34a');
                         setTimeout(function(){ $copyBtn.css('color', '#94a3b8'); }, 1000);
                         setTimeout(function(){ $copyBtn.css('color', '#94a3b8'); }, 1200);
                     });
                     });
                     $valWrap.append($copyBtn);
                     $valWrap.append($copyBtn);
                    var $copyWtBtn = $('<button class="md-btn-mini" title="Copy Wikitext">' + svgWikitext + '</button>');
                    $copyWtBtn.on('click', function() {
                        var wtCode = "| " + item.prop + " = " + buildWikitextVal(item);
                        navigator.clipboard.writeText(wtCode);
                        $(this).css('color', '#3b82f6');
                        setTimeout(function(){ $copyWtBtn.css('color', '#94a3b8'); }, 1000);
                    });
                    $valWrap.append($copyWtBtn);
                     $info.append($valWrap);
                     $info.append($valWrap);
                    // MEDIA SOSIAL
                    if (item.isPersonOrg && item.socials) {
                        var $socialGroup = $('<div class="md-social-group"></div>');
                        var hasSocial = false;
                        Object.keys(SOCIAL_PLATFORMS).forEach(function(key) {
                            var uname = item.socials[key];
                            if (uname) {
                                hasSocial = true;
                                var platform = SOCIAL_PLATFORMS[key];
                                var fullUrl = platform.base + cleanHandle(uname);
                                var $badge = $('<a class="md-social-badge" href="' + fullUrl + '" target="_blank" style="background:' + platform.color + ';">' + platform.icon + ' ' + platform.name + '</a>');
                                $socialGroup.append($badge);
                            }
                        });
                        if (hasSocial) $info.append($socialGroup);
                    }
                      
                      
                    // REFERENSI
                     if (item.ref && (item.ref.url || item.ref.title)) {
                     if (item.ref && (item.ref.url || item.ref.title)) {
                         var ref = item.ref;
                         var ref = item.ref;
                        var isVer = isVerifiedSite(ref.url);
                        var verBadgeHtml = isVer ? '<span class="md-verified-badge" title="Situs Populer Terverifikasi">' + svgVerified + '</span>' : '';
                       
                        var safeUrl = ref.url ? ensureHttps(ref.url) : '';
                        var refTitle = ref.title || "Sumber Rujukan";
                       
                         var $refContainer = $('<div class="md-ref-container"></div>');
                         var $refContainer = $('<div class="md-ref-container"></div>');
                         var $refCard = $('<div class="md-ref-card"></div>');
                         var $refDetails = $(`
                        $refCard.append('<div class="md-ref-tag-header">' + svgRef + ' Reference Source:</div>');
                            <details class="md-ref-details">
                                <summary>
                                    <div style="color:#4f46e5; display:inline-flex; align-items:center; gap:5px; white-space:nowrap; flex-shrink:0;">${svgRef} REFERENSI:</div>
                                    <div style="color:#374151; display:flex; align-items:center; flex-wrap:wrap; flex:1;">
                                        <span style="word-break:break-word; line-height:1.3;">${sanitizeHTML(refTitle)}</span>${verBadgeHtml}
                                    </div>
                                </summary>
                                <div class="md-ref-body">
                                    ${ref.author ? '<div><span style="color:#64748b; font-weight:700;">Penulis:</span> ' + sanitizeHTML(ref.author) + '</div>' : ''}
                                    ${ref.site ? '<div><span style="color:#64748b; font-weight:700;">Situs:</span> ' + sanitizeHTML(ref.site) + '</div>' : ''}
                                    ${ref.publisher ? '<div><span style="color:#64748b; font-weight:700;">Penerbit:</span> ' + sanitizeHTML(ref.publisher) + '</div>' : ''}
                                    ${ref.date ? '<div><span style="color:#64748b; font-weight:700;">Tanggal Akses:</span> ' + formatIndonesianDate(ref.date) + '</div>' : ''}
                                    ${ref.type ? '<div style="margin-top:4px;"><span style="background:#e2e8f0; padding:2px 8px; border-radius:6px; font-weight:700; font-size:0.75rem;">' + sanitizeHTML(ref.type) + (ref.subType ? ' &bull; ' + sanitizeHTML(ref.subType) : '') + '</span></div>' : ''}
                                    ${safeUrl ? '<a href="' + sanitizeHTML(safeUrl) + '" target="_blank" rel="noopener noreferrer" class="md-btn-visit">Kunjungi Situs</a>' : ''}
                                </div>
                            </details>
                        `);
                       
                        $refDetails.find('.md-verified-badge').on('click', function(e) {
                            e.preventDefault(); e.stopPropagation();
                            showModal('Situs Terverifikasi', 'Centang biru menandakan bahwa URL referensi ini valid dan berasal dari entitas, media publikasi besar, portal populer, atau pangkalan data resmi (seperti Kompas, YouTube, Apple Music, Spotify, dll) yang bereputasi kredibel.');
                        });


                        var refTitle = ref.title || "Reference Link";
                         $refContainer.append($refDetails);
                        if (ref.url) {
                            $refCard.append('<a href="' + ensureHttps(ref.url) + '" target="_blank" class="md-ref-header">' + refTitle + '</a>');
                        } else {
                            $refCard.append('<span class="md-ref-header" style="color:#0f172a;">' + refTitle + '</span>');
                        }
 
                        var details = [];
                        if (ref.author) details.push("Author: " + ref.author);
                        if (ref.site) details.push("Site: " + ref.site);
                        if (ref.publisher) details.push("Publisher: " + ref.publisher);
                        if (ref.date) details.push("Date: " + formatIndonesianDate(ref.date));
                        if (details.length > 0) {
                            $refCard.append('<div style="font-size:0.75rem; color:#64748b; margin-top:2px;">' + details.join(' &bull; ') + '</div>');
                        }
 
                         $refContainer.append($refCard);
                         $info.append($refContainer);
                         $info.append($refContainer);
                     }
                     }
Baris 597: Baris 518:
                     $row.append($info);
                     $row.append($info);


                    // ACTIONS PER BARIS (Edit, Clone)
                     if (isLocked && !isSysop) {
                    var $ctrls = $('<div class="md-row-actions" style="display:flex; align-items:center; gap:8px;"></div>');
                         var $lockNotifyBtn = $('<button class="md-btn-icon edit-btn" style="color:#dc2626; border-color:#fca5a5; background:#fef2f2;">' + svgLock + ' Terkunci</button>');
                     if (!isLocked || isSysop) {
                         $lockNotifyBtn.on('click', function() {
                       
                             showModal('Halaman Dikunci', 'Halaman Data Terstruktur ini sedang dikunci sementara oleh pengurus untuk melindungi dari vandalisme atau perubahan yang tidak sah. Pengguna biasa atau anonim tidak dapat mengedit saat ini.');
                        // FITUR 5: Quick Clone Data
                         var $cloneBtn = $('<button class="md-btn-icon" style="padding:6px 10px;" title="Clone Row">' + svgClone + ' Clone</button>');
                         $cloneBtn.on('click', function() {
                             var clonedObj = JSON.parse(JSON.stringify(item));
                            clonedObj.prop = clonedObj.prop + " (Copy)";
                            dataItems.splice(index + 1, 0, clonedObj);
                            saveData('Kloning data', $(this), rawContent);
                         });
                         });
                         $ctrls.append($cloneBtn);
                         $row.append($lockNotifyBtn);
 
                    } else {
                         var $editIcon = $('<button class="md-btn-icon" style="padding:6px 10px;">' + svgEdit + ' Edit</button>');
                         var $editIcon = $('<button class="md-btn-icon edit-btn">' + svgEdit + ' Edit</button>');
                         $editIcon.on('click', function() { showForm(index, rawContent); });
                         $editIcon.on('click', function() { showForm(index, rawContent); });
                         $ctrls.append($editIcon);
                         $row.append($editIcon);
                     }
                     }
                     $row.append($ctrls);
                      
                     $list.append($row);
                     $list.append($row);
                 });
                 });
Baris 628: Baris 542:
         }
         }


         // 7. FORM EDIT (SMART FEATURES IMPLEMENTATION)
         // 9. FORM EDIT & DRAFT LOGIC
         function showForm(index, rawContent) {
         function showForm(index, rawContent) {
             var $container = $('#md-form-container');
             var $container = $('#md-form-container').empty();
            $container.empty();  
 
             var isNew = index === -1;
             var isNew = index === -1;
           
            var draftData = localStorage.getItem(DRAFT_KEY);
             var currentData = isNew ? { prop: '', val: '', link: false, linkTarget: '', linkSplit: false, ref: {}, isPersonOrg: false, socials: {} } : dataItems[index];
             var currentData = isNew ? { prop: '', val: '', link: false, linkTarget: '', linkSplit: false, ref: {}, isPersonOrg: false, socials: {} } : dataItems[index];
              
              
            // FITUR 3: Cek Draft dari Local Storage jika ini Form Baru
             if (isNew && draftData) {
             if (isNew) {
                 if(confirm("Anda memiliki draft yang belum tersimpan sebelumnya. Ingin melanjutkan draft tersebut?")) {
                var draft = localStorage.getItem('md_draft_' + pageName);
                    try { currentData = JSON.parse(draftData); } catch(e) {}
                 if (draft) {
                    if (confirm("Draft formulir sebelumnya ditemukan. Ingin memuatnya?")) {
                        try { currentData = JSON.parse(draft); } catch(e){}
                    } else { localStorage.removeItem('md_draft_' + pageName); }
                 }
                 }
             }
             }
Baris 649: Baris 559:
             var currentSocials = currentData.socials || {};
             var currentSocials = currentData.socials || {};


             var $form = $('<div class="md-form-box" id="md-main-form"></div>');
             var $form = $('<div class="md-form-box"></div>');
            $form.append('<h4 class="md-form-title">' + (isNew ? 'Tambah Data Baru' : 'Edit Data Terstruktur') + '</h4>');
           
            var $propGroup = $('<div class="md-form-group"></div>');
            $propGroup.append('<label>Label Data <span class="md-help-icon" data-help="Nama bidang data (contoh: Pekerjaan, Sutradara, Tempat Lahir). Klik tombol preset di bawah untuk isi otomatis.">' + svgHelp + '</span></label>');
            $propGroup.append('<input type="text" id="md-inp-prop" class="md-input" value="' + sanitizeHTML(currentData.prop || '') + '">');
              
              
            // FITUR 11: Form Accordion
            var $header = $('<div class="md-form-header"></div>');
            $header.append('<h4 class="md-form-title">' + (isNew ? 'Add New Data Entry' : 'Edit Data Entry') + '</h4>');
            var $toggleBtn = $('<button class="md-btn-mini">Minimize</button>');
            $header.append($toggleBtn);
            $form.append($header);
            var $formBody = $('<div></div>');
            // Label Box
            var $propGroup = $('<div class="md-form-group"><label>Data Label (Required)</label><input type="text" id="md-inp-prop" class="md-input" value="' + (currentData.prop || '') + '"><div class="md-dup-alert" id="md-dup-msg">Alert: This label already exists in the dataset!</div></div>');
             var $presetWrap = $('<div class="md-preset-wrapper"></div>');
             var $presetWrap = $('<div class="md-preset-wrapper"></div>');
             PRESET_LABELS.forEach(function(lbl) {
             PRESET_LABELS.forEach(function(lbl) {
                 var $pill = $('<span class="md-preset-pill">' + lbl + '</span>');
                 var $pill = $('<span class="md-preset-pill">' + lbl + '</span>');
                 $pill.on('click', function() { $('#md-inp-prop').val(lbl).trigger('input'); });
                 $pill.on('click', function() { $('#md-inp-prop').val(lbl); });
                 $presetWrap.append($pill);
                 $presetWrap.append($pill);
             });
             });
             $propGroup.append($presetWrap);
             $propGroup.append($presetWrap);
             $formBody.append($propGroup);
             $form.append($propGroup);
              
              
            // Value Box + FITUR 7 (Char Counter)
             var $valBox = $('<div class="md-form-group"></div>');
             var $valBox = $('<div class="md-form-group"></div>');
             $valBox.append('<label>Data Value (Required)</label><input type="text" id="md-inp-val" class="md-input" value="' + (currentData.val || '') + '">');
             $valBox.append('<label>Nilai Data <span class="md-help-icon" data-help="Ketik nilai. Jika halaman sudah ada di Wiki, saran akan muncul (pratinjau) dan otomatis mencentang opsi Wikilink.">' + svgHelp + '</span></label>');
            $valBox.append('<div class="md-char-count" id="md-char-counter">0 chars</div>');
              
              
             var $wikilinkOpts = $('<div style="margin-top:10px; display:flex; flex-direction:column; gap:8px; background:#f8fafc; padding:12px; border-radius:6px; border:1px solid #e2e8f0;"></div>');
            // FITUR AUTOCOMPLETE PRATINJAU DIMULAI DI SINI
            var $autoWrap = $('<div class="md-autocomplete-wrapper"></div>');
            var $valInput = $('<input type="text" id="md-inp-val" class="md-input" autocomplete="off" value="' + sanitizeHTML(currentData.val || '') + '">');
            var $autoList = $('<div class="md-autocomplete-list"></div>');
            $autoWrap.append($valInput).append($autoList);
            $valBox.append($autoWrap);
           
             var $wikilinkOpts = $('<div style="margin-top:8px; display:flex; flex-direction:column; gap:8px; background:#f8fafc; padding:10px; border-radius:8px; border:1px solid #e2e8f0;"></div>');
             var chkLink = currentData.link ? 'checked' : '';
             var chkLink = currentData.link ? 'checked' : '';
             var chkSplit = currentData.linkSplit ? 'checked' : '';
             var chkSplit = currentData.linkSplit ? 'checked' : '';
              
              
             $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.85rem;"><input type="checkbox" id="md-inp-link" ' + chkLink + '> Standard Wikilink [[Title]]</label>');
             var $linkCheck = $('<input type="checkbox" id="md-inp-link" ' + chkLink + '>');
             $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.85rem;"><input type="checkbox" id="md-inp-split" ' + chkSplit + '> Smart Split Wikilink</label>');
            var $lblLinkCheck = $('<label style="display:flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; cursor:pointer;"></label>');
             $wikilinkOpts.append('<div style="margin-top:4px;"><label style="font-size:0.8rem; color:#475569;">Custom Target (Piped Link):</label><input type="text" id="md-inp-target" class="md-input" style="padding:8px 10px; font-size:0.85rem;" value="' + (currentData.linkTarget || '') + '"></div>');
            $lblLinkCheck.append($linkCheck).append(' Jadikan Wikilink Standar');
 
            // Logika pratinjau ketika diketik
            var isAutoChecked = false;
            $valInput.on('input', function() {
                var q = $(this).val();
               
                // Jika input dikosongkan/berubah, kembalikan centang link ke false jika tadinya otomatis centang
                if (isAutoChecked) {
                    $linkCheck.prop('checked', false);
                    isAutoChecked = false;
                }
 
                if(q.length < 1) {
                    $autoList.empty().hide();
                    return;
                }
 
                // Panggil API MediaWiki Prefix Search
                api.get({
                    action: 'query',
                    list: 'prefixsearch',
                    pssearch: q,
                    pslimit: 6,
                    format: 'json'
                }).done(function(data) {
                    $autoList.empty();
                    if(data.query && data.query.prefixsearch && data.query.prefixsearch.length > 0) {
                        data.query.prefixsearch.forEach(function(res) {
                            var $item = $('<div class="md-autocomplete-item">' + svgSearch + ' ' + sanitizeHTML(res.title) + '</div>');
                            $item.on('click', function() {
                                $valInput.val(res.title);
                                $autoList.empty().hide();
                                $linkCheck.prop('checked', true); // OTOMATIS TERCENTANG
                                isAutoChecked = true;
                            });
                            $autoList.append($item);
                        });
                        $autoList.show();
                    } else {
                        $autoList.hide();
                    }
                });
            });
 
            // Sembunyikan pratinjau saat klik di luar
            $(document).on('click.mdauto', function(e) {
                if(!$(e.target).closest('.md-autocomplete-wrapper').length) {
                    $autoList.hide();
                }
            });
 
            $wikilinkOpts.append($lblLinkCheck);
             $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; cursor:pointer;"><input type="checkbox" id="md-inp-split" ' + chkSplit + '> Smart Split Wikilink</label>');
             var $pipedGroup = $('<div style="margin-top:4px;"><label style="font-size:0.78rem; color:#475569; margin-bottom:4px;">Target Halaman Khusus (Opsional):</label><input type="text" id="md-inp-target" class="md-input" style="padding:6px 10px; font-size:0.85rem;" placeholder="Contoh: Diskografi Rumi Haitami" value="' + sanitizeHTML(currentData.linkTarget || '') + '"></div>');
            $wikilinkOpts.append($pipedGroup);
             $valBox.append($wikilinkOpts);
             $valBox.append($wikilinkOpts);
             $formBody.append($valBox);
             $form.append($valBox);


            // Media Sosial
             var $socialSec = $('<div class="md-form-group" style="margin-top:16px;"></div>');
             var $socialSec = $('<div class="md-form-group" style="margin-top:20px;"></div>');
             var chkPerson = currentData.isPersonOrg ? 'checked' : '';
             var chkPerson = currentData.isPersonOrg ? 'checked' : '';
             $socialSec.append('<label style="display:flex; align-items:center; gap:8px; cursor:pointer; background:#eff6ff; padding:10px; border-radius:6px; color:#1e40af; border:1px solid #bfdbfe;"><input type="checkbox" id="md-chk-person" ' + chkPerson + '> Enable Social Media & Music Links</label>');
             $socialSec.append('<label style="display:flex; align-items:center; gap:8px; cursor:pointer; background:#e0e7ff; padding:10px; border-radius:8px; font-weight:700; color:#3730a3; font-size:0.85rem;"><input type="checkbox" id="md-chk-person" ' + chkPerson + '> Simpan Profil Media Sosial (Akan muncul di paling atas) <span class="md-help-icon" data-help="Centang ini untuk mengisi data sosial media. Datanya akan dihimpun dan dimunculkan di kotak teratas data struktur.">' + svgHelp + '</span></label>');
              
              
             var $socialGrid = $('<div class="md-social-grid" id="md-social-box" style="display:' + (currentData.isPersonOrg ? 'grid' : 'none') + '; margin-top:8px;"></div>');
             var $socialGrid = $('<div class="md-social-grid" id="md-social-box" style="display:' + (currentData.isPersonOrg ? 'grid' : 'none') + '; margin-top:8px;"></div>');
Baris 695: Baris 658:
                 var p = SOCIAL_PLATFORMS[key];
                 var p = SOCIAL_PLATFORMS[key];
                 var valUname = currentSocials[key] || '';
                 var valUname = currentSocials[key] || '';
                 var $socInp = $('<input type="text" id="md-soc-' + key + '" class="md-input" placeholder="Username / ID" value="' + valUname + '">');
                 $socialGrid.append('<div><label style="font-size:0.78rem; color:#334155; font-weight:700; margin-bottom:4px;">' + p.name + '</label><input type="text" id="md-soc-' + key + '" class="md-input" placeholder="ID / Username" value="' + sanitizeHTML(valUname) + '"></div>');
               
                $socInp.on('blur paste input', function() { $(this).val(cleanHandle($(this).val())); });
                $socialGrid.append('<div><label style="font-size:0.8rem;">' + p.name + '</label></div>').find('div').last().append($socInp);
             });
             });
             $socialSec.append($socialGrid);
             $socialSec.append($socialGrid);
             $formBody.append($socialSec);
             $form.append($socialSec);


            // Referensi
             var $refArea = $('<div class="md-form-group" style="margin-top:20px;"></div>');
             var $refArea = $('<div class="md-form-group" style="margin-top:20px;"></div>');
             $refArea.append('<label style="font-size:0.95rem; border-bottom:1px solid #e2e8f0; padding-bottom:6px;">Reference Source</label>');
             $refArea.append('<label style="font-size:0.95rem; font-weight:800; color:#0f172a; margin-bottom:10px;">Sumber Referensi <span class="md-help-icon" data-help="Mohon berikan sumber referensi yang valid, kredibel, dan dapat dipertanggungjawabkan (seperti portal berita resmi, jurnal akademik ilmiah, buku cetak ber-ISBN, atau pangkalan data terverifikasi). Referensi yang kuat sangat membantu memastikan keakuratan informasi. Jika URL rujukan Anda mengarah ke situs web besar yang terverifikasi, sistem keamanan akan secara otomatis menampilkan lencana centang biru premium sebagai tanda sumber tepercaya.">' + svgHelp + '</span></label>');
             var $refGrid = $('<div class="md-ref-grid" style="margin-top:10px;"></div>');
             var $refGrid = $('<div class="md-ref-grid"></div>');
              
              
             var $typeSel = $('<select id="md-ref-type" class="md-select"><option value="">-- Main Type --</option></select>');
             var $typeSel = $('<select id="md-ref-type" class="md-select"><option value="">-- Pilih Tipe Utama --</option></select>');
             Object.keys(REF_TYPES).forEach(function(t) {
             Object.keys(REF_TYPES).forEach(function(t) {
                 var sel = currentRef.type === t ? 'selected' : '';
                 var sel = currentRef.type === t ? 'selected' : '';
Baris 714: Baris 673:
             });
             });


             var $subTypeSel = $('<select id="md-ref-subtype" class="md-select"><option value="">-- Sub Type --</option></select>');
             var $subTypeSel = $('<select id="md-ref-subtype" class="md-select"><option value="">-- Pilih Sub-Tipe --</option></select>');
             function updateSubTypes(mainType, selectedSub) {
             function updateSubTypes(mainType, selectedSub) {
                 $subTypeSel.empty().append('<option value="">-- Sub Type --</option>');
                 $subTypeSel.empty().append('<option value="">-- Pilih Sub-Tipe --</option>');
                 if (mainType && REF_TYPES[mainType]) {
                 if (mainType && REF_TYPES[mainType]) {
                     REF_TYPES[mainType].forEach(function(st) {
                     REF_TYPES[mainType].forEach(function(st) {
Baris 727: Baris 686:
             updateSubTypes(currentRef.type, currentRef.subType);
             updateSubTypes(currentRef.type, currentRef.subType);


             $refGrid.append('<div><label style="font-size:0.8rem;">Main Type</label></div>').find('div').last().append($typeSel);
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Tipe Utama</label></div>').find('div').last().append($typeSel);
             $refGrid.append('<div><label style="font-size:0.8rem;">Sub Type</label></div>').find('div').last().append($subTypeSel);
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Sub-Tipe</label></div>').find('div').last().append($subTypeSel);


             var $urlInput = $('<input type="url" id="md-ref-url" class="md-input" placeholder="https://..." value="' + (currentRef.url || '') + '">');
             var $urlInput = $('<input type="text" id="md-ref-url" class="md-input" placeholder="https://...." value="' + sanitizeHTML(currentRef.url || '') + '">');
             $urlInput.on('blur', function() {
             $urlInput.on('blur', function() {
                 var u = ensureHttps($(this).val());
                 var u = ensureHttps($(this).val());
                 $(this).val(u);
                 $(this).val(u);
                 if (u && !$('#md-ref-site').val().trim()) $('#md-ref-site').val(extractDomain(u));
                 var $siteInp = $('#md-ref-site');
                 if (u && !$('#md-ref-title').val().trim()) $('#md-ref-title').val("Reference from " + extractDomain(u));
                 if (u && !$siteInp.val().trim()) $siteInp.val(extractDomain(u));
             });
             });


             $refGrid.append('<div class="md-grid-full"><label style="font-size:0.8rem;">Reference URL</label></div>').find('div').last().append($urlInput);
             $refGrid.append('<div class="md-grid-full"><label style="font-size:0.78rem; margin-bottom:4px;">URL Rujukan</label></div>').find('div').last().append($urlInput);
             $refGrid.append('<div><label style="font-size:0.8rem;">Article Title</label><input type="text" id="md-ref-title" class="md-input" value="' + (currentRef.title || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Judul Halaman</label><input type="text" id="md-ref-title" class="md-input" placeholder="Judul Rujukan" value="' + sanitizeHTML(currentRef.title || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.8rem;">Site Name</label><input type="text" id="md-ref-site" class="md-input" value="' + (currentRef.site || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Nama Situs</label><input type="text" id="md-ref-site" class="md-input" placeholder="Situs" value="' + sanitizeHTML(currentRef.site || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.8rem;">Author</label><input type="text" id="md-ref-author" class="md-input" value="' + (currentRef.author || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Penulis</label><input type="text" id="md-ref-author" class="md-input" placeholder="Penulis" value="' + sanitizeHTML(currentRef.author || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.8rem;">Publisher</label><input type="text" id="md-ref-publisher" class="md-input" value="' + (currentRef.publisher || '') + '"></div>');
             $refGrid.append('<div><label style="font-size:0.78rem; margin-bottom:4px;">Penerbit</label><input type="text" id="md-ref-publisher" class="md-input" placeholder="Penerbit" value="' + sanitizeHTML(currentRef.publisher || '') + '"></div>');
              
              
            var $dateBox = $('<div><label style="font-size:0.78rem; margin-bottom:4px;">Tanggal Akses</label></div>');
            var $dateInpWrap = $('<div style="display:flex; gap:6px;"></div>');
            var $dateInp = $('<input type="date" id="md-ref-date" class="md-input" value="' + sanitizeHTML(currentRef.date || '') + '">');
            var $todayBtn = $('<button type="button" class="md-btn-icon" style="padding:4px 8px; font-size:0.75rem;" title="Set Hari Ini">Hari Ini</button>');
            $todayBtn.on('click', function() { $dateInp.val(getTodayString()); });
            $dateInpWrap.append($dateInp).append($todayBtn);
            $dateBox.append($dateInpWrap);
            $refGrid.append($dateBox);
             $refArea.append($refGrid);
             $refArea.append($refGrid);
             $formBody.append($refArea);
             $form.append($refArea);


             var $previewBox = $('<div class="md-preview-card"><b>Live Preview:</b><div id="md-live-prev" style="margin-top:6px;"></div></div>');
             $form.append(`
             $formBody.append($previewBox);
                <div class="md-cc0-notice">
                    <b>Perhatian Lisensi:</b> Setiap data yang diterbitkan di sini akan terlihat publik dan dirilis di bawah lisensi <b>Creative Commons Zero (CC0)</b>. Jika Anda tidak ingin suntingan Anda digunakan secara bebas dan publik tanpa batas, jangan klik Terbitkan. <span class="md-help-icon" data-help="Dengan menerbitkan, Anda melepaskan seluruh hak cipta atas input data ini ke domain publik murni sesuai prinsip Wikidata.">${svgHelp}</span>
                </div>
                <div class="md-edit-meta">
                    <label style="font-size:0.85rem; font-weight:700;">Ringkasan Suntingan <span class="md-help-icon" data-help="Jelaskan secara singkat apa yang Anda ubah atau tambahkan. Contoh: Menambah data tanggal lahir rumi.">${svgHelp}</span></label>
                    <input type="text" id="md-edit-summary" class="md-input" placeholder="Jelaskan perubahan Anda secara singkat...">
                    <label style="font-size:0.85rem; cursor:pointer; font-weight:700; margin-top:5px; display:inline-flex; align-items:center; gap:6px;"><input type="checkbox" id="md-minor-edit"> Ini adalah suntingan kecil (minor)</label>
                </div>
             `);


             var $actions = $('<div class="md-form-actions"></div>');
             var $actions = $('<div class="md-form-actions"></div>');
             var $btnSave = $('<button class="md-btn md-btn-save">Save Entry <span class="md-spinner"></span></button>');
             var $btnSave = $('<button class="md-btn md-btn-save">Terbitkan <span class="md-spinner"></span></button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Cancel</button>');
            var $btnDraft = $('<button class="md-btn md-btn-draft">Simpan Draft</button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Batal</button>');
           
            $actions.append($btnSave).append($btnDraft).append($btnCancel);
              
              
             // FITUR 14: Fast Reset
             if (draftData && isNew) {
            var $btnReset = $('<button class="md-btn md-btn-reset">Reset</button>');
                var $btnDelDraft = $('<button class="md-btn" style="background:#eab308; color:#fff;">Hapus Draft</button>');
            $btnReset.on('click', function() {
                $btnDelDraft.on('click', function() {
                $formBody.find('input[type="text"], input[type="url"]').val('');
                    localStorage.removeItem(DRAFT_KEY);
                $formBody.find('input[type="checkbox"]').prop('checked', false);
                    alert("Draft berhasil dihapus!");
                $formBody.find('select').prop('selectedIndex', 0);
                    $(this).hide();
                 $('#md-social-box').hide();
                 });
                 updateLivePreview();
                 $actions.append($btnDelDraft);
             });
             }


            $actions.append($btnSave).append($btnReset).append($btnCancel);
           
             if (!isNew) {
             if (!isNew) {
                 var $btnDelete = $('<button class="md-btn md-btn-delete">Delete <span class="md-spinner"></span></button>');
                 var $btnDelete = $('<button class="md-btn md-btn-delete">Hapus Data <span class="md-spinner"></span></button>');
                 $btnDelete.on('click', function() {
                 $btnDelete.on('click', function() {
                     if(confirm('Are you sure you want to delete this item?')) {
                     if(confirm('Yakin ingin menghapus item data ini?')) {
                         dataItems.splice(index, 1);
                         dataItems.splice(index, 1);
                         saveData('Hapus data', $(this), rawContent);
                         saveData('Menghapus data', $(this), rawContent, $('#md-edit-summary').val(), $('#md-minor-edit').is(':checked'));
                     }
                     }
                 });
                 });
                 $actions.append($btnDelete);
                 $actions.append($btnDelete);
             }
             }
            $formBody.append($actions);
 
             $form.append($formBody);
             $form.append($actions);
             $container.append($form);
             $container.append($form);
            initTooltips();


            // BINDINGS & LIVE PREVIEW
             $('#md-chk-person').on('change', function() {
             $toggleBtn.on('click', function() {
                 if($(this).is(':checked')) $('#md-social-box').css('display', 'grid');
                 $formBody.slideToggle(200);
                else $('#md-social-box').hide();
                $(this).text($(this).text() === 'Minimize' ? 'Maximize' : 'Minimize');
             });
             });


             function getFormState() {
             $('html, body').animate({ scrollTop: $form.offset().top - 60 }, 250);
            $btnCancel.on('click', function() { $container.empty(); });
 
            $btnDraft.on('click', function() {
                 var socObj = {};
                 var socObj = {};
                 if ($('#md-chk-person').is(':checked')) {
                 if ($('#md-chk-person').is(':checked')) {
                     Object.keys(SOCIAL_PLATFORMS).forEach(k => {
                     Object.keys(SOCIAL_PLATFORMS).forEach(function(k) {
                         var v = cleanHandle($('#md-soc-' + k).val());
                         var valU = $('#md-soc-' + k).val().trim();
                         if(v) socObj[k] = v;
                         if (valU) socObj[k] = valU;
                     });
                     });
                 }
                 }
                 return {
                 var draftObj = {
                     prop: $('#md-inp-prop').val(),
                     prop: $('#md-inp-prop').val().trim(),
                     val: $('#md-inp-val').val(),
                     val: $('#md-inp-val').val().trim(),
                     link: $('#md-inp-link').is(':checked'),
                     link: $('#md-inp-link').is(':checked'),
                     linkSplit: $('#md-inp-split').is(':checked'),
                     linkSplit: $('#md-inp-split').is(':checked'),
                     linkTarget: $('#md-inp-target').val(),
                     linkTarget: $('#md-inp-target').val().trim(),
                     isPersonOrg: $('#md-chk-person').is(':checked'),
                     isPersonOrg: $('#md-chk-person').is(':checked'),
                     socials: socObj,
                     socials: socObj,
                     ref: {
                     ref: {
                         type: $('#md-ref-type').val(), subType: $('#md-ref-subtype').val(),
                         type: $('#md-ref-type').val(), subType: $('#md-ref-subtype').val(),
                         url: $('#md-ref-url').val(), title: $('#md-ref-title').val(), site: $('#md-ref-site').val()
                         url: ensureHttps($('#md-ref-url').val()), title: $('#md-ref-title').val().trim(),
                        site: $('#md-ref-site').val().trim(), author: $('#md-ref-author').val().trim(),
                        publisher: $('#md-ref-publisher').val().trim(), date: $('#md-ref-date').val()
                     }
                     }
                 };
                 };
            }
                 localStorage.setItem(DRAFT_KEY, JSON.stringify(draftObj));
 
                alert("Draft berhasil disimpan di memori peramban Anda!");
            function updateLivePreview() {
                var p = $('#md-inp-prop').val().trim() || 'Label';
                var v = $('#md-inp-val').val().trim() || 'Value';
                $('#md-char-counter').text(v.length + " chars");
 
                // FITUR 9: Required Validator Highlight
                $('#md-inp-prop').toggleClass('md-error', !$('#md-inp-prop').val().trim());
                $('#md-inp-val').toggleClass('md-error', !$('#md-inp-val').val().trim());
 
                var refT = $('#md-ref-title').val().trim();
                var refU = $('#md-ref-url').val().trim();
 
                var html = '<div><b style="color:#64748b; text-transform:uppercase; font-size:0.8rem;">' + p + ':</b> <span style="font-weight:600; color:#0f172a;">' + v + '</span></div>';
                if (refT || refU) { html += '<div style="font-size:0.75rem; color:#3b82f6; margin-top:4px; font-weight:600;">Ref: ' + (refT || refU) + '</div>'; }
                $('#md-live-prev').html(html);
 
                var isDup = dataItems.some(function(item, idx) { return idx !== index && item.prop.toLowerCase() === p.toLowerCase(); });
                 $('#md-dup-msg').toggle(isDup);
 
                // FITUR 3: Save state to localStorage
                if (isNew) localStorage.setItem('md_draft_' + pageName, JSON.stringify(getFormState()));
            }
 
            // FITUR 1: Auto Capitalize Labels & FITUR 2: Smart Space Trimmer
            $form.find('input[type="text"]').on('blur', function() {
                var val = $(this).val().replace(/\s+/g, ' ').trim();
                if ($(this).attr('id') === 'md-inp-prop') {
                    val = val.replace(/\b\w/g, function(l) { return l.toUpperCase(); });
                }
                $(this).val(val);
                updateLivePreview();
            });
 
            $form.find('input, select').on('keyup input change', updateLivePreview);
            updateLivePreview();
 
            $('#md-chk-person').on('change', function() {
                $('#md-social-box').css('display', $(this).is(':checked') ? 'grid' : 'none');
                updateLivePreview();
             });
             });
            $('html, body').animate({ scrollTop: $form.offset().top - 40 }, 300, 'swing');
            $btnCancel.on('click', function() { $container.empty(); });


             $btnSave.on('click', function() {
             $btnSave.on('click', function() {
Baris 858: Baris 798:


                 if (!newProp || !newVal) {
                 if (!newProp || !newVal) {
                     alert("Data Label and Value are required!"); return;
                     alert("Label Data dan Nilai wajib diisi!"); return;
                 }
                 }


Baris 865: Baris 805:
                 if (isPerson) {
                 if (isPerson) {
                     Object.keys(SOCIAL_PLATFORMS).forEach(function(k) {
                     Object.keys(SOCIAL_PLATFORMS).forEach(function(k) {
                         var valU = cleanHandle($('#md-soc-' + k).val());
                         var valU = $('#md-soc-' + k).val().trim();
                         if (valU) socObj[k] = valU;
                         if (valU) socObj[k] = valU;
                     });
                     });
Baris 877: Baris 817:
                     site: $('#md-ref-site').val().trim(),
                     site: $('#md-ref-site').val().trim(),
                     author: $('#md-ref-author').val().trim(),
                     author: $('#md-ref-author').val().trim(),
                     publisher: $('#md-ref-publisher').val().trim()
                     publisher: $('#md-ref-publisher').val().trim(),
                    date: $('#md-ref-date').val()
                 };
                 };


Baris 884: Baris 825:


                 var newItem = {
                 var newItem = {
                     prop: newProp,
                     prop: newProp, val: newVal,
                    val: newVal,
                     link: $('#md-inp-link').is(':checked'),
                     link: $('#md-inp-link').is(':checked'),
                     linkSplit: $('#md-inp-split').is(':checked'),
                     linkSplit: $('#md-inp-split').is(':checked'),
Baris 897: Baris 837:
                 else dataItems[index] = newItem;  
                 else dataItems[index] = newItem;  


                 saveData(isNew ? 'Tambah data' : 'Edit data', $(this), rawContent);
                 saveData(isNew ? 'Tambah data' : 'Edit data', $(this), rawContent, $('#md-edit-summary').val().trim(), $('#md-minor-edit').is(':checked'));
             });
             });
         }
         }


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


             var jsonStr = JSON.stringify(dataItems, null, 2);
             var jsonStr = JSON.stringify(dataItems, null, 2);
             var $box = $('<div class="md-form-box"></div>');
             var $box = $('<div class="md-form-box"></div>');
             $box.append('<div class="md-form-header"><h4 class="md-form-title">JSON Import / Export</h4></div>');
             $box.append('<h4 class="md-form-title">Ekspor / Impor JSON Data</h4>');
            $box.append('<p style="font-size:0.82rem; color:#64748b; margin-bottom:10px;">Anda dapat menyalin struktur JSON di bawah untuk cadangan atau menempelkan JSON dari artikel lain.</p>');
              
              
             var $txt = $('<textarea class="md-textarea" rows="12" style="font-family:monospace; font-size:0.8rem; background:#f8fafc;"></textarea>').val(jsonStr);
             var $txt = $('<textarea class="md-textarea" rows="10" style="font-family:monospace; font-size:0.8rem;"></textarea>').val(jsonStr);
             $box.append($txt);
             $box.append($txt);


             var $actions = $('<div class="md-form-actions"></div>');
             var $actions = $('<div class="md-form-actions"></div>');
             var $btnImport = $('<button class="md-btn md-btn-save">Import & Save <span class="md-spinner"></span></button>');
             var $btnImport = $('<button class="md-btn md-btn-save">Impor JSON & Simpan <span class="md-spinner"></span></button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Close</button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Tutup</button>');


             $actions.append($btnImport).append($btnCancel);
             $actions.append($btnImport).append($btnCancel);
             $box.append($actions);
             $box.append($actions);
             $container.append($box);
             $container.append($box);
            $('html, body').animate({ scrollTop: $box.offset().top - 40 }, 300);


             $btnCancel.on('click', function() { $container.empty(); });
             $btnCancel.on('click', function() { $container.empty(); });
Baris 929: Baris 867:
                     if (Array.isArray(parsed)) {
                     if (Array.isArray(parsed)) {
                         dataItems = parsed;
                         dataItems = parsed;
                         saveData('Impor JSON', $(this), rawContent);
                         saveData('Impor data dari JSON', $(this), rawContent, 'Impor struktur data JSON', false);
                     } else { alert("JSON format must be an Array!"); }
                     } else {
                 } catch(e) { alert("Invalid JSON: " + e.message); }
                        alert("Format JSON harus berupa Array items!");
                    }
                 } catch(e) {
                    alert("Format JSON tidak valid: " + e.message);
                }
             });
             });
         }
         }


         // 9. INITIALIZE
         // 11. EXECUTE
         loadData().then(function(rawContent) { buildUI(rawContent); });
         loadData().then(function(rawContent) { buildUI(rawContent); });
     });
     });
Baris 1.415: Baris 1.357:
             '<div style="font-size:11px; color:#718096; font-weight:800; text-transform:uppercase; letter-spacing:1px; margin-bottom:10px;">Lisensi, Atribusi & Penggunaan Data</div>' +
             '<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;">' +
             '<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 ' +
             'Seluruh data terstruktur yang tersaji dalam repositori ini merupakan milik publik dan tersedia di bawah ' +
             '<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>.' +
             '<a href="https://creativecommons.org/publicdomain/zero/1.0/"target="_blank" style="color:#6a5acd; text-decoration:none; font-weight:700;">Lisensi Creative Commons CC0</a>.' +
             '</p>' +
             '</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>';
             '<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>';