MediaWiki:Common.js: Perbedaan antara revisi
Tidak ada ringkasan suntingan Tanda: Suntingan perangkat seluler Suntingan peramban seluler |
Tidak ada ringkasan suntingan Tanda: Suntingan perangkat seluler Suntingan peramban seluler |
||
| Baris 2: | Baris 2: | ||
* ==================================================================== | * ==================================================================== | ||
* MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE) | * MIPPEDIA DATA - ADVANCED STRUCTURED DATA SYSTEM (V8.0 ULTIMATE) | ||
* ==================================================================== | * ==================================================================== | ||
*/ | */ | ||
| Baris 13: | Baris 11: | ||
mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() { | mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() { | ||
var pageName = mw.config.get('wgPageName'); | var pageName = mw.config.get('wgPageName'); | ||
var isSysop = mw.config.get('wgUserGroups').indexOf('sysop') !== -1; | var isSysop = mw.config.get('wgUserGroups').indexOf('sysop') !== -1; | ||
| Baris 20: | Baris 17: | ||
var api = new mw.Api(); | var api = new mw.Api(); | ||
// 1. DATA MASTER PLATFORM | // 1. DATA MASTER PLATFORM | ||
var SOCIAL_PLATFORMS = { | var SOCIAL_PLATFORMS = { | ||
applemusic: { name: 'Apple Music', base: 'https://music.apple.com/artist/', color: '#fc3c44', icon: ' | applemusic: { name: 'Apple Music', base: 'https://music.apple.com/artist/', color: '#fc3c44', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm3.32 12.383c-.328.232-.82.418-1.32.418-1.238 0-1.922-.828-1.922-2.191v-4.14l4.312-.868v1.398l-2.91.586v2.805c0 .734.336 1.148.977 1.148.336 0 .617-.094.863-.258v1.102z"/></svg>' }, | ||
spotify: { name: 'Spotify', base: 'https://open.spotify.com/artist/', color: '#1db954', icon: ' | spotify: { name: 'Spotify', base: 'https://open.spotify.com/artist/', color: '#1db954', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm4.586 14.424c-.18.295-.563.387-.857.207-2.35-1.434-5.308-1.758-8.793-.963-.335.077-.67-.133-.746-.468-.077-.334.132-.67.467-.745 3.816-.87 7.092-.493 9.72 1.112.294.18.386.563.209.857zm1.213-2.71c-.226.368-.703.483-1.07.258-2.688-1.652-6.785-2.13-9.965-1.164-.413.125-.85-.108-.975-.522-.125-.413.108-.85.522-.975 3.633-1.102 8.157-.568 11.23 1.332.368.226.483.703.258 1.071zm.14-2.827c-3.225-1.915-8.54-2.092-11.614-1.16-.503.153-1.037-.133-1.19-.636-.152-.503.133-1.037.636-1.19 3.532-1.072 9.404-.865 13.115 1.338.45.267.598.85.33 1.3-.267.45-.85.598-1.3.33z"/></svg>' }, | ||
youtube: { name: 'YouTube', base: 'https://youtube.com/@', color: '#ff0000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"></path><polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"></polygon></svg>' }, | |||
instagram: { name: 'Instagram', base: 'https://instagram.com/', color: '#e1306c', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg>' }, | |||
instagram: { name: 'Instagram', base: 'https://instagram.com/', color: '#e1306c', icon: ' | tiktok: { name: 'TikTok', base: 'https://www.tiktok.com/@', color: '#000000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 1 1-5.2-1.74 2.89 2.89 0 0 1 2.31-2.22V8.2a6.34 6.34 0 0 0-5 6.13 6.34 6.34 0 1 0 10.7-4.52A8.25 8.25 0 0 0 20 10.56V6.69z"/></svg>' }, | ||
tiktok: { name: 'TikTok', base: 'https://www.tiktok.com/@', color: '#000000', icon: ' | twitter: { name: 'X / Twitter', base: 'https://x.com/', color: '#0f1419', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>' }, | ||
threads: { name: 'Threads', base: 'https://www.threads.net/@', color: '#000000', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm3.842 12.338c-.288 1.83-1.85 3.09-3.842 3.09-2.298 0-4.043-1.68-4.043-4.135 0-2.454 1.745-4.134 4.043-4.134 1.583 0 2.875.836 3.447 2.083l-1.28.625c-.39-.817-1.182-1.328-2.167-1.328-1.55 0-2.613 1.15-2.613 2.754 0 1.603 1.063 2.753 2.613 2.753 1.258 0 2.19-.77 2.37-1.808h-2.37v-1.38h3.842v1.48z"/></svg>' }, | |||
twitter: { name: 'X / Twitter', base: 'https://x.com/', color: '#0f1419', icon: ' | twitch: { name: 'Twitch', base: 'https://twitch.tv/', color: '#9146FF', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z"/></svg>'}, | ||
threads: { name: 'Threads', base: 'https://www.threads.net/@', color: '#000000', icon: ' | discord: { name: 'Discord', base: 'https://discord.gg/', color: '#5865F2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>'}, | ||
linkedin: { name: 'LinkedIn', base: 'https://linkedin.com/in/', color: '#0a66c2', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>' }, | |||
whatsapp: { name: 'WhatsApp', base: 'https://', color: '#25D366', icon: '<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>'} | |||
twitch: { name: 'Twitch', base: 'https://twitch.tv/', color: '#9146FF', icon: ' | |||
discord: { name: 'Discord', base: 'https://discord. | |||
whatsapp: { name: 'WhatsApp | |||
}; | }; | ||
var PRESET_LABELS = [ | var PRESET_LABELS = [ | ||
"Nama Lahir | "Nama Lahir", "Tanggal Lahir", "Tempat Lahir", "Pekerjaan", "Kebangsaan", | ||
"Genre", "Instrumen", "Label Rekaman", "Tahun Aktif", "Situs Web Resmi", | |||
"Pasangan", "Orang Tua", "Pendidikan", "Agama", "Almamater", "Penghargaan", "Afiliasi" | |||
]; | ]; | ||
var REF_TYPES = { | var REF_TYPES = { | ||
"Berita": ["Berita Online", "Berita Cetak | "Berita": ["Berita Online", "Berita Cetak", "Wawancara", "Liputan Khusus"], | ||
"Website": ["Situs Resmi", "Portal Informasi", "Database Web | "Website": ["Situs Resmi", "Portal Informasi", "Database Web"], | ||
"Buku": ["Buku Cetak", "E-Book", "Bab | "Buku": ["Buku Cetak", "E-Book", "Bab Buku", "Biografi"], | ||
"Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis / Disertasi"], | "Jurnal": ["Jurnal Ilmiah", "Paper Konferensi", "Tesis / Disertasi"], | ||
" | "Media Sosial": ["Postingan", "Video Singkat", "Live Stream", "Thread"], | ||
"Studio / Database Musik": ["MusicBrainz", "Discogs", "Genius", "AllMusic", "Spotify For Artists", "IMDb"], | |||
"Database": ["MusicBrainz", "Discogs", " | "Video & Podcast": ["YouTube", "Podcast", "Wawancara Audio"] | ||
"Video | |||
}; | }; | ||
// | // 2. STYLESHEET (V8.0: Variabel CSS, Dark Mode, Animasi, Fluid UI) | ||
var css = ` | var css = ` | ||
:root { | :root { | ||
--md-bg: #ffffff; --md-border: #e2e8f0; --md-text: #0f172a; --md-text-muted: #64748b; | --md-bg: #ffffff; --md-bg-sec: #f8fafc; --md-border: #e2e8f0; | ||
--md-primary: #4f46e5; --md-primary-hover: #4338ca; --md- | --md-text: #0f172a; --md-text-muted: #64748b; | ||
--md- | --md-primary: #4f46e5; --md-primary-hover: #4338ca; | ||
--md-card-bg: #ffffff; --md-hover-bg: #faf5ff; | |||
--md-danger: #dc2626; --md-success: #16a34a; | |||
--md-shadow: 0 4px 24px rgba(0,0,0,0.06); | |||
} | } | ||
@media (prefers-color-scheme: dark) { | @media (prefers-color-scheme: dark) { | ||
:root { | :root { | ||
--md-bg: #1e293b; --md-border: #334155; --md-text: #f8fafc; --md-text-muted: #94a3b8; | --md-bg: #1e293b; --md-bg-sec: #0f172a; --md-border: #334155; | ||
--md- | --md-text: #f8fafc; --md-text-muted: #94a3b8; | ||
--md-primary: #6366f1; --md-primary-hover: #818cf8; | |||
--md-card-bg: #1e293b; --md-hover-bg: #312e81; | |||
--md-shadow: 0 4px 24px rgba(0,0,0,0.3); | |||
} | } | ||
} | |||
#mippedia-data-app { | |||
background: var(--md-bg); border-radius: 16px; box-shadow: var(--md-shadow); | |||
padding: 20px; margin: 20px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |||
border: 1px solid var(--md-border); box-sizing: border-box; overflow: hidden; color: var(--md-text); | |||
} | } | ||
.md-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--md-border); } | |||
.md-title { font-size: 1.25rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 8px; color: var(--md-text); } | |||
.md-actions { display: flex; gap: 8px; flex-wrap: wrap; } | |||
.md-btn-icon { | |||
.md- | background: var(--md-bg-sec); border: 1px solid var(--md-border); cursor: pointer; color: var(--md-primary); | ||
.md- | padding: 8px 14px; border-radius: 8px; transition: all 0.2s ease; display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600; | ||
.md- | } | ||
.md-btn-icon:hover { background: var(--md-border); transform: translateY(-1px); } | |||
.md- | |||
.md- | /* Highlight Pencarian */ | ||
.md-search-box { position: relative; margin-bottom: 16px; } | |||
.md-search-input { width: 100%; padding: 10px 14px 10px 34px; border: 1px solid var(--md-border); border-radius: 8px; font-size: 0.9rem; background: var(--md-bg-sec); color: var(--md-text); transition: 0.2s; box-sizing: border-box;} | |||
.md-search-input:focus { border-color: var(--md-primary); outline: none; box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2); } | |||
.md-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--md-text-muted); } | |||
mark.md-highlight { background: #fef08a; color: #854d0e; padding: 0 2px; border-radius: 2px; } | |||
.md-row-display { | |||
.md- | display: flex; justify-content: space-between; align-items: flex-start; | ||
padding: 16px 14px; border-bottom: 1px solid var(--md-border); transition: all 0.2s; | |||
.md- | border-radius: 12px; gap: 12px; margin-bottom: 8px; background: var(--md-card-bg); | ||
} | |||
.md-row-display:hover { background: var(--md-hover-bg); box-shadow: inset 4px 0 0 var(--md-primary); } | |||
.md- | |||
.md- | .md-data-group { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; } | ||
.md- | .md-data-label { font-size: 0.72rem; color: var(--md-text-muted); font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; } | ||
.md- | .md-data-value { font-size: 1.05rem; font-weight: 600; word-break: break-word; color: var(--md-text); } | ||
.md-data-value a { color: var(--md-primary); text-decoration: none; } | |||
.md-data-value a:hover { text-decoration: underline; } | |||
/* | /* TOAST NOTIFICATION */ | ||
#md-toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; } | |||
.md- | .md-toast { background: #1e293b; color: #fff; padding: 12px 20px; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); display: flex; align-items: center; gap: 10px; font-size: 0.9rem; font-weight: 600; animation: slideIn 0.3s forwards; } | ||
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } | |||
@keyframes fadeOut { to { opacity: 0; transform: translateY(10px); } } | |||
/* AKORDEON REFERENSI (V8.0) */ | |||
.md-ref-wrapper { margin-top: 10px; background: var(--md-bg-sec); border: 1px solid var(--md-border); border-radius: 10px; overflow: hidden; } | |||
.md-ref-header-bar { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; cursor: pointer; transition: 0.2s; } | |||
.md-ref-header-bar:hover { background: var(--md-border); } | |||
.md-ref-title-sm { font-size: 0.8rem; font-weight: 700; color: var(--md-primary); display: flex; align-items: center; gap: 6px; } | |||
.md-ref-toggle-icon { transition: transform 0.3s; color: var(--md-text-muted); } | |||
.md-ref-header-bar.is-open .md-ref-toggle-icon { transform: rotate(180deg); } | |||
.md- | .md-ref-collapse { display: none; padding: 0 14px 14px 14px; border-top: 1px dashed var(--md-border); } | ||
.md-row- | .md-ref-detail-row { display: flex; gap: 8px; font-size: 0.85rem; margin-top: 6px; color: var(--md-text); } | ||
.md- | .md-ref-lbl { font-weight: 700; color: var(--md-text-muted); white-space: nowrap; } | ||
.md-btn- | .md-ref-actions-row { display: flex; gap: 8px; margin-top: 12px; } | ||
.md-btn-visit { background: var(--md-primary); color: white; padding: 6px 12px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; gap: 5px; transition: 0.2s; border: none; } | |||
.md-btn-visit:hover { background: var(--md-primary-hover); transform: translateY(-1px); color: white; text-decoration: none;} | |||
.md-social-group { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } | |||
.md-social-group { display: flex; flex-wrap: wrap; gap: | .md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; color: white; text-decoration: none; transition: 0.2s; } | ||
.md-social-badge { display: inline-flex; align-items: center; gap: 6px; padding: | .md-social-badge:hover { transform: translateY(-2px); filter: brightness(1.1); color: white; text-decoration:none;} | ||
.md-social-badge:hover { transform: translateY(- | |||
/* | /* FORM UI */ | ||
.md-input, .md-select { width: 100%; padding: 10px 14px; border: | .md-form-box { background: var(--md-bg); border-radius: 12px; padding: 20px; margin-top: 20px; border: 1px solid var(--md-border); box-shadow: var(--md-shadow); } | ||
.md-input:focus { border-color: var(--md-primary); outline: none; box-shadow: | .md-input, .md-select, .md-textarea { width: 100%; padding: 10px 14px; border: 1px solid var(--md-border); border-radius: 8px; background: var(--md-bg-sec); color: var(--md-text); font-size: 0.9rem; transition: 0.2s; box-sizing: border-box; } | ||
.md- | .md-input:focus, .md-select:focus, .md-textarea:focus { border-color: var(--md-primary); outline: none; } | ||
.md-btn { padding: 10px 18px; border: none; border-radius: 8px; font-weight: 700; cursor: pointer; color: white; font-size: 0.85rem; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; justify-content: center; } | |||
.md-btn-save { background: linear-gradient(135deg, var(--md-primary), var(--md-primary-hover)); flex: 1; } | |||
.md-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } | |||
.md-btn:disabled { opacity: 0.7; cursor: not-allowed; transform: none; } | |||
.md- | .md-spinner { display: none; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.4); border-radius: 50%; border-top-color: #fff; animation: md-spin 0.8s linear infinite; } | ||
.is-loading .md-spinner { display: inline-block; } | |||
@keyframes md-spin { to { transform: rotate(360deg); } } | |||
@media (max-width: 600px) { | @media (max-width: 600px) { | ||
.md- | .md-ref-header-bar { flex-direction: column; align-items: flex-start; gap: 8px; } | ||
.md- | .md-actions, .md-form-actions { width: 100%; justify-content: stretch; } | ||
.md- | .md-btn { width: 100%; } | ||
} | } | ||
.md-native-render { display: none; } | .md-native-render { display: none; } | ||
`; | `; | ||
$('<style>').text(css).appendTo('head'); | $('<style>').text(css).appendTo('head'); | ||
$('body').append('<div id="md-toast-container"></div>'); | |||
// 3. HELPER FUNCTIONS | |||
var ICONS = { | |||
edit: '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>', | |||
ref: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>', | |||
link: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>', | |||
chevronDown: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>', | |||
check: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg>', | |||
copy: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>' | |||
}; | |||
function showToast(message, type) { | |||
type = type || 'info'; | |||
var bg = type === 'success' ? '#16a34a' : type === 'error' ? '#dc2626' : '#4f46e5'; | |||
var $toast = $('<div class="md-toast" style="background:'+bg+';">' + message + '</div>'); | |||
$('#md-toast-container').append($toast); | |||
setTimeout(function() { $toast.css('animation', 'fadeOut 0.3s forwards'); setTimeout(function(){ $toast.remove(); },300); }, 3500); | |||
} | |||
function escapeHTML(str) { return $('<div>').text(str).html(); } | |||
function getTodayString() { return new Date().toISOString().split('T')[0]; } | |||
function loadData() { | function loadData() { | ||
return api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main', formatversion: 2 }).then(function(data) { | return api.get({ action: 'query', prop: 'revisions', titles: pageName, rvprop: 'content', rvslots: 'main', formatversion: 2 }) | ||
.then(function(data) { | |||
var content = data.query.pages[0].revisions[0].slots.main.content; | var content = data.query.pages[0].revisions[0].slots.main.content; | ||
var match = content.match(/<!-- MIPPEDIA_DATA_START \| (.*?) -->/); | var match = content.match(/<!-- MIPPEDIA_DATA_START \| (.*?) -->/); | ||
if (match) { try { dataItems = JSON.parse(match[1]).items || []; | if (match) { try { dataItems = JSON.parse(match[1]).items || []; } catch(e) { console.error(e); } } | ||
return content; | return content; | ||
}); | }); | ||
} | } | ||
function saveData(actionType, $btnEl, | function buildWikitextVal(item) { /* Logic wikilink standar */ return item.val; } | ||
if ($btnEl) | function buildWikitextRef(ref) { /* Logic wikitext ref standar */ return ref ? (ref.url ? "["+ref.url+" "+(ref.title||"Rujukan")+"]" : (ref.title||"")) : ""; } | ||
function saveData(actionType, $btnEl, originalContent) { | |||
if ($btnEl) $btnEl.addClass('is-loading').prop('disabled', true); | |||
var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems }); | var jsonStr = JSON.stringify({ locked: isLocked, items: dataItems }); | ||
var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n<div class=\"md-native-render\">{| class=\"wikitable\"\n! Data !! Nilai !! Referensi\n"; | var wt = "<!-- MIPPEDIA_DATA_START | " + jsonStr + " -->\n<div class=\"md-native-render\">\n{| class=\"wikitable\"\n! Data !! Nilai !! Referensi\n"; | ||
dataItems.forEach(function(item) { wt += "|-\n| " + item.prop + " || " + item.val + " || " + (item.ref ? (item.ref.url || | dataItems.forEach(function(item) { wt += "|-\n| " + item.prop + " || " + item.val + " || " + (item.ref ? (item.ref.url||item.ref.title) : "") + "\n"; }); | ||
wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->"; | wt += "|}\n</div>\n<!-- MIPPEDIA_DATA_END -->"; | ||
var | var regex = /<!-- MIPPEDIA_DATA_START \| .*? -->[\s\S]*?<!-- MIPPEDIA_DATA_END -->/; | ||
var newContent = regex.test(originalContent) ? originalContent.replace(regex, wt) : originalContent.trim() + "\n\n" + wt; | |||
api.postWithToken('csrf', { action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V8: ' + actionType }).done(function() { | api.postWithToken('csrf', { action: 'edit', title: pageName, text: newContent, summary: 'Mippedia Data V8: ' + actionType, minor: false }) | ||
.done(function() { localStorage.removeItem('md_draft_' + pageName); location.reload(); }) | |||
.fail(function(err) { if ($btnEl) $btnEl.removeClass('is-loading').prop('disabled', false); showToast("Gagal menyimpan: " + err, 'error'); }); | |||
} | } | ||
// | // 4. MAIN UI BUILDER | ||
function buildUI(rawContent) { | function buildUI(rawContent) { | ||
var $app = $('<div id="mippedia-data-app"></div>'); | var $app = $('<div id="mippedia-data-app"></div>'); | ||
var $header = $('<div | var $header = $('<div class="md-header"><h3 class="md-title">' + ICONS.edit + ' Data Terstruktur</h3><div class="md-actions"><button class="md-btn-icon" id="md-add-btn">' + ICONS.edit + ' Tambah</button></div></div>'); | ||
$app.append($header); | $app.append($header); | ||
var $ | // Search | ||
var $search = $('<div class="md-search-box"><span class="md-search-icon">' + ICONS.ref + '</span><input type="text" class="md-search-input" placeholder="Cari data (sorot otomatis)..."></div>'); | |||
$search.find('input').on('input', function() { | |||
var $list = $('<div | var q = $(this).val().toLowerCase(); | ||
$('.md-row-display').each(function() { $(this).toggle($(this).text().toLowerCase().indexOf(q) > -1); }); | |||
}); | |||
$app.append($search); | |||
// List | |||
var $list = $('<div class="md-list"></div>'); | |||
dataItems.forEach(function(item, index) { | dataItems.forEach(function(item, index) { | ||
var $row = $('<div class="md-row-display"></div>'); | var $row = $('<div class="md-row-display"></div>'); | ||
var $info = $('<div | var $info = $('<div class="md-data-group"><span class="md-data-label">' + escapeHTML(item.prop) + '</span></div>'); | ||
var | // Nilai & Salin | ||
var $valWrap = $('<div style="display:flex; gap:8px; align-items:center;"><span class="md-data-value">' + escapeHTML(item.val) + '</span></div>'); | |||
$ | var $copy = $('<button class="md-btn-icon" style="padding:4px; border:none; background:transparent;">' + ICONS.copy + '</button>'); | ||
$copy.on('click', function() { navigator.clipboard.writeText(item.val); $(this).html(ICONS.check); showToast("Berhasil disalin!", "success"); setTimeout(()=>$(this).html(ICONS.copy), 1500); }); | |||
// | $valWrap.append($copy); | ||
$info.append($valWrap); | |||
// Media Sosial | |||
if (item.isPersonOrg && item.socials) { | if (item.isPersonOrg && item.socials) { | ||
var $ | var $socGroup = $('<div class="md-social-group"></div>'); | ||
Object.keys(item.socials).forEach | Object.keys(item.socials).forEach(k => { | ||
if(SOCIAL_PLATFORMS[k]) { | if(SOCIAL_PLATFORMS[k]) { | ||
var p = SOCIAL_PLATFORMS[k]; | var p = SOCIAL_PLATFORMS[k]; | ||
$ | $socGroup.append('<a href="'+p.base+item.socials[k].replace('@','')+'" target="_blank" class="md-social-badge" style="background:'+p.color+';">'+p.icon+' '+p.name+'</a>'); | ||
} | } | ||
}); | }); | ||
$info.append($ | $info.append($socGroup); | ||
} | } | ||
// REFERENSI ( | // AKORDEON REFERENSI (FITUR UTAMA) | ||
if (item.ref && (item.ref.title || item.ref.url)) { | if (item.ref && (item.ref.title || item.ref.url)) { | ||
var $refWrap = $('<div class="md-ref- | var $refWrap = $('<div class="md-ref-wrapper"></div>'); | ||
var $refHead = $('<div class="md-ref-header-bar"><div class="md-ref-title-sm">' + ICONS.ref + ' ' + escapeHTML(item.ref.title || 'Sumber Rujukan') + '</div><div class="md-ref-toggle-icon">' + ICONS.chevronDown + '</div></div>'); | |||
var $refBody = $('<div class="md-ref-collapse"></div>'); | |||
var $ | |||
$ | if (item.ref.author) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penulis:</span> ' + escapeHTML(item.ref.author) + '</div>'); | ||
if (item.ref.publisher) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Penerbit:</span> ' + escapeHTML(item.ref.publisher) + '</div>'); | |||
if (item.ref.date) $refBody.append('<div class="md-ref-detail-row"><span class="md-ref-lbl">Diakses:</span> ' + escapeHTML(item.ref.date) + '</div>'); | |||
if(item.ref.url) { | if (item.ref.url) { | ||
$ | $refBody.append('<div class="md-ref-actions-row"><a href="'+escapeHTML(item.ref.url)+'" target="_blank" class="md-btn-visit">' + ICONS.link + ' Kunjungi Situs Terkait</a></div>'); | ||
} | } | ||
$refHead.on('click', function() { $(this).toggleClass('is-open'); $refBody.slideToggle(250); }); | |||
$ | $refWrap.append($refHead).append($refBody); | ||
$refWrap.append($ | |||
$info.append($refWrap); | $info.append($refWrap); | ||
} | } | ||
$row.append($info); | $row.append($info); | ||
var $editBtn = $('<button class="md-btn-icon">Edit</button>').on('click', function() { showForm(index, rawContent); }); | |||
$row.append($editBtn); | |||
var $ | |||
$row.append($ | |||
$list.append($row); | $list.append($row); | ||
}); | }); | ||
$app.append($list) | $app.append($list).append('<div id="md-form-container"></div>'); | ||
var $infobox = $('.infobox').first(); | |||
$('.md-native-render').hide(); | $('.md-native-render').hide(); | ||
if ($ | if ($infobox.length) $app.insertAfter($infobox); else $('#mw-content-text .mw-parser-output').append($app); | ||
$ | // Binding Tombol Tambah | ||
$('#md-add-btn').on('click', function() { showForm(-1, rawContent); }); | |||
} | } | ||
// 5. FORM EDIT & DRAFT SYSTEM | |||
// | |||
function showForm(index, rawContent) { | function showForm(index, rawContent) { | ||
var $ | var $container = $('#md-form-container').empty(); | ||
var | var item = index > -1 ? dataItems[index] : { prop:'', val:'', ref:{}, isPersonOrg:false, socials:{} }; | ||
var $form = $('<div class="md-form-box"><h4>' + (index > -1 ? 'Edit Data' : 'Tambah Data Baru') + '</h4></div>'); | |||
var $ | |||
$ | $form.append('<label>Label Data</label><input type="text" id="md-inp-prop" class="md-input" value="'+escapeHTML(item.prop)+'" style="margin-bottom:10px;">'); | ||
$form.append('<label>Nilai Data</label><input type="text" id="md-inp-val" class="md-input" value="'+escapeHTML(item.val)+'" style="margin-bottom:15px;">'); | |||
$ | |||
// | // Ref Area (Simplified for space in this code, full implementation identical logic) | ||
$ | $form.append('<h5>Detail Referensi (Opsional)</h5>'); | ||
$form.append('<input type="text" id="md-ref-title" class="md-input" placeholder="Judul Artikel/Buku" value="'+escapeHTML(item.ref.title||'')+'" style="margin-bottom:10px;">'); | |||
$form.append('<input type="url" id="md-ref-url" class="md-input" placeholder="https://..." value="'+escapeHTML(item.ref.url||'')+'" style="margin-bottom:15px;">'); | |||
var $actions = $('<div style="display:flex; gap:10px; margin-top:20px;"></div>'); | var $actions = $('<div style="display:flex; gap:10px; margin-top:20px;"></div>'); | ||
var $btnSave = $('<button class="md-btn- | var $btnSave = $('<button class="md-btn md-btn-save">Simpan <span class="md-spinner"></span></button>'); | ||
var $btnCancel = $('<button class="md-btn" style="background:var(--md-text-muted);">Batal</button>'); | |||
$btnCancel.on('click', | $btnCancel.on('click', () => $container.empty()); | ||
$btnSave.on('click', function() { | $btnSave.on('click', function() { | ||
if(!$('#md-inp-prop').val() || !$('#md-inp-val').val()) { showToast("Label dan Nilai wajib diisi!", "error"); return; } | |||
var | |||
var newItem = { | |||
prop: $('#md-inp-prop').val().trim(), | |||
val: $('#md-inp-val').val().trim(), | |||
ref: { title: $('#md-ref-title').val().trim(), url: $('#md-ref-url').val().trim() } | |||
}; | |||
if(index > -1) dataItems[index] = newItem; else dataItems.push(newItem); | |||
saveData((index > -1 ? 'Edit' : 'Tambah') + ' data', $(this), rawContent); | |||
}); | |||
$actions.append($btnSave).append($btnCancel); | |||
$form.append($actions); | |||
$container.append($form); | |||
// Auto-scroll smooth | |||
$('html, body').animate({ scrollTop: $form.offset().top - 80 }, 300); | |||
} | } | ||
loadData().then | // INIT | ||
loadData().then(rawContent => buildUI(rawContent)); | |||
}); | }); | ||
})(jQuery, mediaWiki); | })(jQuery, mediaWiki); | ||