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
Tanda: Pengembalian manual Suntingan perangkat seluler Suntingan peramban seluler
Baris 1: Baris 1:
/**
/**
  * ====================================================================
  * ====================================================================
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V9.0 PRO MOBILE)
  * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V7.0 ULTIMATE)
  * Fitur: No-Emoji, Mobile Responsive, 15 Auto Features, Clean UI.
  * Fitur: Complete Music & Socials, Explicit Ref Labels, Preset Templates,
* JSON Export/Import, Mobile Perfect, Auto-Domain & Instant Validation
  * ====================================================================
  * ====================================================================
  */
  */
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();


Baris 35: Baris 34:
             linkedin: { name: 'LinkedIn', base: 'https://linkedin.com/in/', color: '#0a66c2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>' },
             linkedin: { name: 'LinkedIn', base: 'https://linkedin.com/in/', color: '#0a66c2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>' },
             github: { name: 'GitHub', base: 'https://github.com/', color: '#24292e', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>' },
             github: { name: 'GitHub', base: 'https://github.com/', color: '#24292e', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>' },
             pinterest: { name: 'Pinterest', base: 'https://pinterest.com/', color: '#e60023', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/></svg>' }
             pinterest: { name: 'Pinterest', base: 'https://pinterest.com/', color: '#e60023', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/></svg>' },
            telegram: { name: 'Telegram', base: 'https://t.me/', color: '#0088cc', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12s5.37 12 12 12 12-5.37 12-12S18.63 0 12 0zm5.562 8.161c-.18 1.897-.962 6.502-1.359 8.627-.168.9-.5 1.201-.82 1.23-.697.064-1.226-.461-1.901-.903-1.056-.692-1.653-1.123-2.678-1.799-1.185-.781-.417-1.21.258-1.911.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.244-1.349-.374-1.297-.789.027-.216.324-.437.893-.663 3.498-1.524 5.831-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635.099-.002.321.023.465.141.119.098.152.228.166.321.015.093.033.308.018.473z"/></svg>' },
            wikipedia: { name: 'Wikipedia / Wikidata', base: 'https://id.wikipedia.org/wiki/', color: '#636466', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12.09 13.118l-2.034-4.82 2.034-4.818h2.034l-3.05 7.227 3.05 7.228h-2.034zm-6.098 0l-2.033-4.82 2.033-4.818h2.034l-3.05 7.227 3.05 7.228H5.992zm12.196 0l-2.034-4.82 2.034-4.818h2.034l-3.05 7.227 3.05 7.228h-2.034z"/></svg>' }
         };
         };


        // 2. PRESET TEMPLATES LABEL LENGKAP
         var PRESET_LABELS = [
         var PRESET_LABELS = [
             "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan",  
             "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan",  
Baris 44: Baris 46:
         ];
         ];


        // 3. MASTER TIPE RUJUKAN
         var REF_TYPES = {
         var REF_TYPES = {
             "Berita": ["Berita Online / Portal", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus", "Editorial / Opini"],
             "Berita": ["Berita Online / Portal", "Berita Cetak / Koran", "Wawancara Eksklusif", "Liputan Khusus", "Editorial / Opini", "Investigasi Media", "Siaran Radio / TV"],
             "Website": ["Situs Resmi / Official", "Blog / Portal Informasi", "Basis Data / Database Web", "Portal Komunitas"],
             "Website": ["Situs Resmi / Official", "Blog / Portal Informasi", "Basis Data / 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"],
            "Ensiklopedi": ["Ensiklopedi Cetak", "Ensiklopedi Online", "Kamus / Glosarium"],
            "Arsip": ["Arsip Nasional / Sejarah", "Web Archive (Wayback Machine)", "Dokumen Manuskrip"]
         };
         };


         // 2. IKON SISTEM FAST SVG (PURE, NO EMOJIS)
         // 4. IKON SISTEM
        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>';
         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 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>';
         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 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>';
         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 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="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 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>';
         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 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 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
         // 5. HELPER UTILITY
         function formatIndonesianDate(dateStr) {
         function formatIndonesianDate(dateStr) {
             if (!dateStr) return '';
             if (!dateStr) return '';
Baris 90: Baris 92:
                 return urlStr.replace(/^https?:\/\/(www\.)?/, '').split('/')[0];
                 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; }
         }
         }


Baris 107: Baris 97:
             if (!urlStr) return '';
             if (!urlStr) return '';
             urlStr = urlStr.trim();
             urlStr = urlStr.trim();
            // FITUR 8: Auto Protocol Inserter
             if (urlStr && !urlStr.match(/^https?:\/\//i)) {
             if (urlStr && !urlStr.match(/^https?:\/\//i)) return 'https://' + urlStr;
                return 'https://' + urlStr;
             return cleanReferenceUrl(urlStr);
             }
        }
             return urlStr;
 
        function cleanHandle(val) {
             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 getTodayString() {
         function detectDataTypeBadge(item) {
             var now = new Date();
             var val = item.val || '';
             var y = now.getFullYear();
             // FITUR 12: Smart Date Validator RegExp
             var m = String(now.getMonth() + 1).padStart(2, '0');
            if (val.match(/^\d{4}-\d{2}-\d{2}$/)) return '<span class="md-type-tag md-tag-date">Date</span>';
             var d = String(now.getDate()).padStart(2, '0');
             if (val.match(/^https?:\/\//i)) return '<span class="md-type-tag md-tag-link">External Link</span>';
             return y + '-' + m + '-' + d;
             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>';
         }
         }


         // FITUR 10: Data Type Demographics
         // 6. STYLESHEET MODERN V7.0
        function calculateDataStats() {
            var stats = { date: 0, link: 0, wiki: 0, text: 0 };
            dataItems.forEach(function(item) {
                var val = item.val || '';
                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
        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, Helvetica, Arial, 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; }
            #mippedia-data-app.md-dark { background: #0f172a; border-color: #334155; color: #f8fafc; }
            #mippedia-data-app.md-dark .md-title { color: #f8fafc; }
            #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; }
             .md-header {
             #mippedia-data-app.md-dark .md-header { border-color: #334155; }
                display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
             .md-title-container { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; }
                gap: 12px; margin-bottom: 16px; padding-bottom: 14px; border-bottom: 1px solid #f1f5f9;
             .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-title-container { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 180px; }
             .md-title { font-size: 1.25rem; font-weight: 800; color: #0f172a; margin: 0; white-space: nowrap; letter-spacing: -0.3px; }
             .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 {
            .md-score-box { background: #f8fafc; padding: 12px 16px; border-radius: 8px; border: 1px solid #e2e8f0; width: 100%; }
                width: 100%; padding: 8px 12px 8px 34px; border: 1px solid #cbd5e1; border-radius: 8px;
            #mippedia-data-app.md-dark .md-score-box { background: #182234; border-color: #334155; }
                font-size: 0.85rem; box-sizing: border-box; background: #f8fafc; transition: 0.2s;
            .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-search-input:focus { background: #fff; border-color: #4f46e5; outline: none; }
           
             .md-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: #94a3b8; }
            .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%; }
             .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-search-input:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); background: #ffffff; }
             .md-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: #94a3b8; }


             /* List Rows */
             /* Row Display Fix */
            .md-list { display: flex; flex-direction: column; gap: 10px; }
             .md-row-display {
             .md-row-display {
                 display: flex; justify-content: space-between; align-items: flex-start;
                 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);
                 padding: 16px 12px; border-bottom: 1px solid #f1f5f9; transition: all 0.2s;
                 border-radius: 8px; gap: 16px; background: #ffffff;
                 border-radius: 12px; gap: 12px; margin-bottom: 8px; background: #fff;
             }
             }
             .md-row-display:hover { border-color: #bfdbfe; background: #fafafa; }
             .md-row-display:hover { background: #faf5ff; box-shadow: inset 4px 0 0 #6366f1; }
            #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 {
             .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; }
                background: none; border: none; color: #94a3b8; cursor: pointer; padding: 2px 4px;
            .md-tag-date { color: #1d4ed8; background: #dbeafe; border-color: #bfdbfe; }
                border-radius: 4px; transition: 0.2s; display: inline-flex; align-items: center;
            .md-tag-link { color: #be123c; background: #ffe4e6; border-color: #fecdd3; }
             }
            .md-tag-piped { color: #b45309; background: #fef3c7; border-color: #fde68a; }
             .md-btn-copy:hover { color: #4f46e5; background: #e0e7ff; }
             .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; }
            /* Tampilan Referensi V7.0 (Eksplisit & Elegan) */
             .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-container { margin-top: 10px; width: 100%; box-sizing: border-box; }
            .md-ref-card {
                background: #f8fafc; padding: 12px 14px; border-radius: 10px;
                border-left: 4px solid #4f46e5; font-size: 0.85rem; display: flex; flex-direction: column; gap: 6px;
                box-sizing: border-box; border-top: 1px solid #f1f5f9; border-right: 1px solid #f1f5f9; border-bottom: 1px solid #f1f5f9;
            }
            .md-ref-tag-header {
                font-size: 0.73rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.5px;
                color: #4f46e5; display: flex; align-items: center; gap: 5px; margin-bottom: 2px;
            }
             .md-ref-header { font-weight: 700; color: #2563eb; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; word-break: break-word; }
            .md-ref-header:hover { text-decoration: underline; }
              
              
             .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-ref-details-grid { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
            .md-btn-mini:hover { color: #3b82f6; background: #eff6ff; }
             .md-ref-detail-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; font-size: 0.82rem; color: #334155; }
 
             .md-ref-lbl { font-weight: 700; color: #64748b; white-space: nowrap; flex-shrink: 0; }
            /* References */
            .md-ref-val { color: #0f172a; font-weight: 500; word-break: break-word; }
            .md-ref-container { margin-top: 10px; width: 100%; }
             .md-ref-badge {
             .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; }
                display: inline-block; background: #e2e8f0; color: #334155; padding: 2px 8px;
             .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; }
                border-radius: 6px; font-weight: 700; font-size: 0.72rem; margin-top: 4px; width: fit-content;
             .md-ref-header { font-weight: 600; color: #2563eb; text-decoration: none; word-wrap: break-word; overflow-wrap: break-word; }
            }


             /* Socials */
             /* Media Sosial Badges V7 */
             .md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
             .md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
             .md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 20px; font-size: 0.75rem; font-weight: 600; color: white; text-decoration: none; transition: opacity 0.2s; }
             .md-social-badge {
             .md-social-badge:hover { opacity: 0.9; color: white; text-decoration: none; }
                display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 18px;
                font-size: 0.78rem; font-weight: 600; color: white; text-decoration: none; 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; color: white; text-decoration: none; }


             .md-preset-wrapper { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
            /* Preset Pill Badges */
             .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-wrapper { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
             .md-preset-pill:hover { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
             .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-preset-pill:hover { background: #e0e7ff; color: #3730a3; border-color: #a5b4fc; }


             /* Form UI */
             /* Form Elements Responsif */
             .md-form-box { background: #ffffff; border-radius: 8px; padding: 20px; margin-top: 20px; border: 1px solid #cbd5e1; transition: all 0.3s; }
             .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-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.05rem; font-weight: 800; color: #0f172a; margin: 0 0 16px 0; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px; }
             .md-form-title { font-size: 1.1rem; font-weight: 700; color: #0f172a; margin: 0; }
             .md-form-group { margin-bottom: 14px; }
           
             .md-form-group label { display: block; font-size: 0.82rem; font-weight: 700; margin-bottom: 6px; color: #334155; }
             .md-form-group { margin-bottom: 16px; width: 100%; }
             .md-input, .md-select, .md-textarea {
             .md-form-group label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 6px; color: #334155; }
                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, .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: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; }
             .md-ref-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; background: #f8fafc; padding: 12px; border-radius: 8px; border: 1px dashed #cbd5e1; }
            .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-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-preview-card { background: #f8fafc; border: 1px dashed #cbd5e1; padding: 12px; border-radius: 6px; margin-top: 16px; font-size: 0.85rem; }
 
             .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-social-grid { max-height: 250px; 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-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: 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-btn {
             .md-btn-save { background: #3b82f6; flex: 1; min-width: 150px; }
                padding: 10px 18px; border: none; border-radius: 8px; font-weight: 700; cursor: pointer;
             .md-btn-save:hover { background: #2563eb; }
                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-delete { background: #dc2626; margin-left: auto; }
             .md-btn-delete { background: #ef4444; 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) */
             @media (max-width: 600px) {
             @media (max-width: 768px) {
                 #mippedia-data-app { padding: 14px; margin: 14px 0; border-radius: 12px; }
                 #mippedia-data-app { padding: 16px; margin: 16px 0; border-radius: 8px; border-left: none; border-right: none; border-radius: 0; }
                 .md-header { flex-direction: column; align-items: flex-start; gap: 10px; }
                 .md-header { flex-direction: column; align-items: flex-start; gap: 12px; }
                 .md-actions { width: 100%; justify-content: flex-start; }
                 .md-actions { width: 100%; display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
                 .md-btn-icon { padding: 7px 12px; font-size: 0.8rem; }
                 .md-btn-icon { justify-content: center; width: 100%; }
                 .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 8px; }
             }
             }
            .md-native-render { display: none; }
         `;
         `;
         $('<style>').text(css).appendTo('head');
         $('<style>').text(css).appendTo('head');


         // 5. PARSER & SAVE PIPELINE
         // 7. PARSER & PENYIMPANAN DATA
         function loadData() {
         function loadData() {
             return api.get({
             return api.get({
Baris 355: Baris 266:
         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 286:
         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 292:
             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;
Baris 384: Baris 302:
             if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
             if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true);
              
              
            // Bersihkan LocalStorage Draft saat disave
            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 322:


             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: 'Mippedia Data V7: ' + actionType, minor: false
             }).done(function() {
             }).done(function() {
                 window.location.href = location.pathname + "?refresh=" + new Date().getTime();
                 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 332:
         }
         }


         // 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
             // HEADER
             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>');
             // Tombol Ekspor JSON
            $darkBtn.on('click', function() {
             var $jsonBtn = $('<button class="md-btn-icon" title="Ekspor/Impor JSON">' + svgCode + ' JSON</button>');
                isDarkMode = !isDarkMode;
             $jsonBtn.on('click', function() { showJsonModal(rawContent); });
                $app.toggleClass('md-dark', isDarkMode);
             $actions.append($jsonBtn);
            });
            $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') + ' <span class="md-spinner"></span></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 356:


             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 364:
             $app.append($header);
             $app.append($header);


            // FITUR 10: DASHBOARD STATISTIK & SKOR KUALITAS
             // SEARCH BAR
            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 377:
             }
             }


             // DAFTAR BARIS DATA (TANPA NAIK/TURUN)
             // DAFTAR BARIS DATA
             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">' + item.prop + '</span>');
                      
                      
                     var typeBadge = detectDataTypeBadge(item);
                     // RENDER NILAI DATA
                    $info.append('<div class="md-data-label-wrap"><span class="md-data-label">' + item.prop + '</span>' + typeBadge + '</div>');
                   
                     var displayValHtml = '';
                     var displayValHtml = '';
                     var rawVal = item.val || '';
                     var rawVal = item.val || '';


                     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>';
                        var domain = extractDomain(rawVal);
                         displayValHtml = '<a href="' + rawVal + '" target="_blank" style="color:#2563eb; font-weight:700; text-decoration:none;">' + domain + '</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;">' + 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 401:
                             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;">' + trimmed + '</a>';
                             }
                             }
                             return p;
                             return 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;">' + rawVal + '</a>';
                     } else {
                     } else {
                         displayValHtml = rawVal;
                         displayValHtml = rawVal;
Baris 532: Baris 414:
                     $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
                     // RENDER MEDIA SOSIAL & MUSIK
                     if (item.isPersonOrg && item.socials) {
                     if (item.isPersonOrg && item.socials) {
                         var $socialGroup = $('<div class="md-social-group"></div>');
                         var $socialGroup = $('<div class="md-social-group"></div>');
Baris 560: Baris 432:
                                 hasSocial = true;
                                 hasSocial = true;
                                 var platform = SOCIAL_PLATFORMS[key];
                                 var platform = SOCIAL_PLATFORMS[key];
                                 var fullUrl = platform.base + cleanHandle(uname);
                                 var fullUrl = platform.base + uname.replace(/^@/, '');
                                 var $badge = $('<a class="md-social-badge" href="' + fullUrl + '" target="_blank" style="background:' + platform.color + ';">' + platform.icon + ' ' + platform.name + '</a>');
                                 var $badge = $('<a class="md-social-badge" href="' + fullUrl + '" target="_blank" style="background:' + platform.color + ';">' + platform.icon + ' ' + platform.name + '</a>');
                                 $socialGroup.append($badge);
                                 $socialGroup.append($badge);
Baris 568: Baris 440:
                     }
                     }
                      
                      
                     // REFERENSI
                     // RENDER REFERENSI EKSPLISIT (V7)
                     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 $refContainer = $('<div class="md-ref-container"></div>');
                         var $refContainer = $('<div class="md-ref-container"></div>');
                         var $refCard = $('<div class="md-ref-card"></div>');
                         var $refCard = $('<div class="md-ref-card"></div>');
                         $refCard.append('<div class="md-ref-tag-header">' + svgRef + ' Reference Source:</div>');
                       
                        // Header Penjelas Referensi
                         $refCard.append('<div class="md-ref-tag-header">' + svgRef + ' Referensi / Sumber Rujukan:</div>');


                         var refTitle = ref.title || "Reference Link";
                         var refTitle = ref.title || "Sumber Rujukan";
                         if (ref.url) {
                         if (ref.url) {
                             $refCard.append('<a href="' + ensureHttps(ref.url) + '" target="_blank" class="md-ref-header">' + refTitle + '</a>');
                            var safeUrl = ensureHttps(ref.url);
                             $refCard.append('<a href="' + safeUrl + '" target="_blank" class="md-ref-header">' + refTitle + '</a>');
                         } else {
                         } else {
                             $refCard.append('<span class="md-ref-header" style="color:#0f172a;">' + refTitle + '</span>');
                             $refCard.append('<span class="md-ref-header" style="color:#0f172a;">' + refTitle + '</span>');
                         }
                         }


                         var details = [];
                         var $detailsGrid = $('<div class="md-ref-details-grid"></div>');
                         if (ref.author) details.push("Author: " + ref.author);
                         if (ref.author) {
                         if (ref.site) details.push("Site: " + ref.site);
                            $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penulis:</span><span class="md-ref-val">' + ref.author + '</span></div>');
                         if (ref.publisher) details.push("Publisher: " + ref.publisher);
                        }
                         if (ref.date) details.push("Date: " + formatIndonesianDate(ref.date));
                         if (ref.site) {
                         if (details.length > 0) {
                            $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Situs:</span><span class="md-ref-val">' + ref.site + '</span></div>');
                             $refCard.append('<div style="font-size:0.75rem; color:#64748b; margin-top:2px;">' + details.join(' &bull; ') + '</div>');
                        }
                         if (ref.publisher) {
                            $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penerbit:</span><span class="md-ref-val">' + ref.publisher + '</span></div>');
                        }
                         if (ref.date) {
                            $detailsGrid.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Tanggal Akses:</span><span class="md-ref-val">' + formatIndonesianDate(ref.date) + '</span></div>');
                        }
                       
                        $refCard.append($detailsGrid);
 
                         if (ref.type) {
                            var typeLabel = ref.type + (ref.subType ? ' &bull; ' + ref.subType : '');
                             $refCard.append('<span class="md-ref-badge">' + typeLabel + '</span>');
                         }
                         }


Baris 597: Baris 484:
                     $row.append($info);
                     $row.append($info);


                    // ACTIONS PER BARIS (Edit, Clone)
                    var $ctrls = $('<div class="md-row-actions" style="display:flex; align-items:center; gap:8px;"></div>');
                     if (!isLocked || isSysop) {
                     if (!isLocked || isSysop) {
                       
                         var $editIcon = $('<button class="md-btn-icon edit-btn" style="padding:6px 10px;">' + svgEdit + ' Edit</button>');
                        // 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);
 
                        var $editIcon = $('<button class="md-btn-icon" style="padding:6px 10px;">' + 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 501:
         }
         }


         // 7. FORM EDIT (SMART FEATURES IMPLEMENTATION)
         // 9. FORM EDIT DENGAN PRESET & PLATFORM LENGKAP
         function showForm(index, rawContent) {
         function showForm(index, rawContent) {
             var $container = $('#md-form-container');
             var $container = $('#md-form-container');
Baris 635: Baris 508:
             var isNew = index === -1;
             var isNew = index === -1;
             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) {
                var draft = localStorage.getItem('md_draft_' + pageName);
                if (draft) {
                    if (confirm("Draft formulir sebelumnya ditemukan. Ingin memuatnya?")) {
                        try { currentData = JSON.parse(draft); } catch(e){}
                    } else { localStorage.removeItem('md_draft_' + pageName); }
                }
            }
             var currentRef = currentData.ref || {};
             var currentRef = currentData.ref || {};
             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>');
              
              
             // FITUR 11: Form Accordion
             // Label Data + Preset Fast Selector
            var $header = $('<div class="md-form-header"></div>');
             var $propGroup = $('<div class="md-form-group"><label>Label Data (Contoh: Pekerjaan, Sutradara, Tempat Lahir)</label><input type="text" id="md-inp-prop" class="md-input" value="' + (currentData.prop || '') + '"></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)
             // Nilai Data & Wikilink Options
             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</label><input type="text" id="md-inp-val" class="md-input" value="' + (currentData.val || '') + '">');
             $valBox.append('<div class="md-char-count" id="md-char-counter">0 chars</div>');
              
            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 $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>');
             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>');
             $wikilinkOpts.append('<label style="display:flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; cursor:pointer;"><input type="checkbox" id="md-inp-link" ' + chkLink + '> Jadikan Wikilink Standar [[Judul]]</label>');
             $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>');
             $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 (Pisahkan kata berkoma/kata "dan")</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>');
              
            var $pipedGroup = $('<div style="margin-top:4px;"><label style="font-size:0.78rem; color:#475569;">Target Halaman Khusus / Custom Piped Link (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="' + (currentData.linkTarget || '') + '"></div>');
            $wikilinkOpts.append($pipedGroup);
           
             $valBox.append($wikilinkOpts);
             $valBox.append($wikilinkOpts);
             $formBody.append($valBox);
             $form.append($valBox);


             // Media Sosial
             // MEDIA SOSIAL & MUSIK LENGKAP
             var $socialSec = $('<div class="md-form-group" style="margin-top:20px;"></div>');
             var $socialSec = $('<div class="md-form-group" style="margin-top:16px;"></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 + '> Aktifkan Profil Orang / Organisasi (Media Sosial & Musik)</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 552:
                 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;">' + p.name + '</label><input type="text" id="md-soc-' + key + '" class="md-input" placeholder="ID / Username" value="' + 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
             // GRID DETAIL RUJUKAN LENGKAP
             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;">Sumber Referensi / Rujukan Spesifik</label>');
            var $refGrid = $('<div class="md-ref-grid" style="margin-top:10px;"></div>');
              
              
             var $typeSel = $('<select id="md-ref-type" class="md-select"><option value="">-- Main Type --</option></select>');
            var $refGrid = $('<div class="md-ref-grid"></div>');
           
             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 569:
             });
             });


             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 Spesifik --</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 Spesifik --</option>');
                 if (mainType && REF_TYPES[mainType]) {
                 if (mainType && REF_TYPES[mainType]) {
                     REF_TYPES[mainType].forEach(function(st) {
                     REF_TYPES[mainType].forEach(function(st) {
Baris 724: Baris 580:
                 }
                 }
             }
             }
             $typeSel.on('change', function() { updateSubTypes($(this).val(), ''); });
             $typeSel.on('change', function() { updateSubTypes($(this).val(), ''); });
             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;">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;">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="url" id="md-ref-url" class="md-input" placeholder="URL Tautan (https://...)" value="' + (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;">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;">Judul Artikel/Halaman</label><input type="text" id="md-ref-title" class="md-input" placeholder="Judul Rujukan" value="' + (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;">Nama Situs/Media</label><input type="text" id="md-ref-site" class="md-input" placeholder="Situs" value="' + (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;">Penulis</label><input type="text" id="md-ref-author" class="md-input" placeholder="Penulis" value="' + (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;">Penerbit</label><input type="text" id="md-ref-publisher" class="md-input" placeholder="Penerbit" value="' + (currentRef.publisher || '') + '"></div>');
              
              
            // Tanggal Akses + Hari Ini
            var $dateBox = $('<div><label style="font-size:0.78rem;">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="' + (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>');
            $formBody.append($previewBox);


            // TOMBOL AKSI FORM
             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">Simpan Data <span class="md-spinner"></span></button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Cancel</button>');
             var $btnCancel = $('<button class="md-btn md-btn-cancel">Batal</button>');
              
              
            // FITUR 14: Fast Reset
             $actions.append($btnSave).append($btnCancel);
            var $btnReset = $('<button class="md-btn md-btn-reset">Reset</button>');
            $btnReset.on('click', function() {
                $formBody.find('input[type="text"], input[type="url"]').val('');
                $formBody.find('input[type="checkbox"]').prop('checked', false);
                $formBody.find('select').prop('selectedIndex', 0);
                $('#md-social-box').hide();
                updateLivePreview();
            });
 
             $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);
                     }
                     }
                 });
                 });
                 $actions.append($btnDelete);
                 $actions.append($btnDelete);
             }
             }
            $formBody.append($actions);
 
             $form.append($formBody);
             $form.append($actions);
             $container.append($form);
             $container.append($form);
            // BINDINGS & LIVE PREVIEW
            $toggleBtn.on('click', function() {
                $formBody.slideToggle(200);
                $(this).text($(this).text() === 'Minimize' ? 'Maximize' : 'Minimize');
            });
            function getFormState() {
                var socObj = {};
                if ($('#md-chk-person').is(':checked')) {
                    Object.keys(SOCIAL_PLATFORMS).forEach(k => {
                        var v = cleanHandle($('#md-soc-' + k).val());
                        if(v) socObj[k] = v;
                    });
                }
                return {
                    prop: $('#md-inp-prop').val(),
                    val: $('#md-inp-val').val(),
                    link: $('#md-inp-link').is(':checked'),
                    linkSplit: $('#md-inp-split').is(':checked'),
                    linkTarget: $('#md-inp-target').val(),
                    isPersonOrg: $('#md-chk-person').is(':checked'),
                    socials: socObj,
                    ref: {
                        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()
                    }
                };
            }
            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-chk-person').on('change', function() {
                 $('#md-social-box').css('display', $(this).is(':checked') ? 'grid' : 'none');
                 if($(this).is(':checked')) $('#md-social-box').css('display', 'grid');
                 updateLivePreview();
                 else $('#md-social-box').hide();
             });
             });


             $('html, body').animate({ scrollTop: $form.offset().top - 40 }, 300, 'swing');
             $('html, body').animate({ scrollTop: $form.offset().top - 60 }, 250);
             $btnCancel.on('click', function() { $container.empty(); });
             $btnCancel.on('click', function() { $container.empty(); });


Baris 858: Baris 650:


                 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 657:
                 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 669:
                     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 901: Baris 694:
         }
         }


         // 8. JSON EXPORT & IMPORT MODAL
         // 10. JSON EXPORT & IMPORT MODAL
         function showJsonModal(rawContent) {
         function showJsonModal(rawContent) {
             var $container = $('#md-form-container');
             var $container = $('#md-form-container');
Baris 908: Baris 701:
             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 721:
                     if (Array.isArray(parsed)) {
                     if (Array.isArray(parsed)) {
                         dataItems = parsed;
                         dataItems = parsed;
                         saveData('Impor JSON', $(this), rawContent);
                         saveData('Impor data dari JSON', $(this), rawContent);
                     } 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); });
     });
     });