JSON Github - Preview with Editor
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON Data Table and Editor</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/9.5.6/jsoneditor.min.css">
<style>
#editor {
width: 100%;
height: 80vh;
}
#successMessage {
display: none;
color: green;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container mt-5">
<h2 class="mb-4">JSON Data Table and Editor</h2>
<!-- File Links -->
<div class="row" id="fileLinks">
<!-- Links will be populated dynamically -->
</div>
<!-- Nav pills -->
<ul class="nav nav-pills mb-3 mt-3" id="pills-tab" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" id="pills-show-tab" data-toggle="pill" href="#pills-show" role="tab" aria-controls="pills-show" aria-selected="true">Show Data</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="pills-edit-tab" data-toggle="pill" href="#pills-edit" role="tab" aria-controls="pills-edit" aria-selected="false">Edit Data</a>
</li>
</ul>
<!-- Tab content -->
<div class="tab-content" id="pills-tabContent">
<!-- Show Data Tab -->
<div class="tab-pane fade show active" id="pills-show" role="tabpanel" aria-labelledby="pills-show-tab">
<div id="jsonTable" class="mt-3"></div>
</div>
<!-- Edit Data Tab -->
<div class="tab-pane fade" id="pills-edit" role="tabpanel" aria-labelledby="pills-edit-tab">
<label for="editorMode">Editor Mode:</label>
<select id="editorMode" onchange="changeEditorMode()">
<option value="tree">Tree</option>
<option value="text">Text</option>
</select>
<div id="editor" class="mt-3"></div>
<div id="successMessage">Changes saved successfully!</div>
<button class="btn btn-primary mt-3" onclick="saveChanges()">Save Changes</button>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/9.5.6/jsoneditor.min.js"></script>
<script>
const token = 'ghp_xxx'; // Ganti dengan token GitHub Anda
const owner = 'konokae';
const repo = 'sl';
const branch = 'main';
let editor = null;
async function fetchRepoContents(path = '') {
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${branch}`, {
headers: {
'Authorization': `token ${token}`
}
});
return await response.json();
}
async function populateFileLinks() {
const contents = await fetchRepoContents('datatheme');
const fileLinksDiv = document.getElementById('fileLinks');
fileLinksDiv.innerHTML = ''; // Clear previous links
let fileCount = 1; // Initialize file counter starting from 1
let columnCount = 0;
let column = document.createElement('div');
column.className = 'col-md-4';
contents.forEach(item => {
if (item.type === 'file' && item.name.endsWith('.json')) {
const link = document.createElement('a');
link.href = '#';
link.className = 'd-block';
link.textContent = `${fileCount}: ${item.name}`; // Display with the file count
link.setAttribute('data-filepath', item.path);
link.onclick = function() {
loadSelectedFile(item.path);
};
column.appendChild(link);
fileCount++; // Increment file counter
if (fileCount % 5 === 1) {
fileLinksDiv.appendChild(column);
column = document.createElement('div');
column.className = 'col-md-4';
}
}
});
if (column.children.length > 0) {
fileLinksDiv.appendChild(column);
}
}
async function fetchJson(path) {
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${branch}`, {
headers: {
'Authorization': `token ${token}`
}
});
const data = await response.json();
const content = atob(data.content);
return JSON.parse(content);
}
async function saveChanges() {
const newContent = editor.get();
const encodedContent = btoa(JSON.stringify(newContent, null, 2));
const filePath = document.querySelector('.nav-link.active').getAttribute('data-filepath');
// Get the current file SHA for updating
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${filePath}?ref=${branch}`, {
headers: {
'Authorization': `token ${token}`
}
});
const data = await response.json();
const sha = data.sha;
// Update the file
await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${filePath}`, {
method: 'PUT',
headers: {
'Authorization': `token ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: 'Updated JSON file via JSON editor',
content: encodedContent,
sha: sha,
branch: branch
})
});
showSuccessMessage();
}
function showSuccessMessage() {
const successMessage = document.getElementById('successMessage');
successMessage.style.display = 'block';
setTimeout(() => {
successMessage.style.display = 'none';
}, 3000);
}
function changeEditorMode() {
const mode = document.getElementById('editorMode').value;
const content = editor.get();
editor.destroy();
editor = new JSONEditor(document.getElementById('editor'), { mode: mode });
editor.set(content);
}
async function loadSelectedFile(filePath) {
if (filePath) {
if (editor) {
editor.destroy();
}
const mode = document.getElementById('editorMode').value;
editor = new JSONEditor(document.getElementById('editor'), { mode: mode });
const jsonContent = await fetchJson(filePath);
editor.set(jsonContent);
// Load data in show data tab
loadSelectedFileShow(filePath);
}
}
async function loadSelectedFileShow(filePath) {
if (filePath) {
const jsonContent = await fetchJson(filePath);
const table = document.createElement('table');
table.className = 'table table-striped';
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
// Create table header
const headerRow = document.createElement('tr');
Object.keys(jsonContent[0]).forEach(key => {
const th = document.createElement('th');
th.textContent = key;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
// Create table body
jsonContent.forEach(item => {
const row = document.createElement('tr');
Object.values(item).forEach(value => {
const td = document.createElement('td');
td.textContent = value;
row.appendChild(td);
});
tbody.appendChild(row);
});
table.appendChild(thead);
table.appendChild(tbody);
const jsonTableDiv = document.getElementById('jsonTable');
jsonTableDiv.innerHTML = ''; // Clear previous table
jsonTableDiv.appendChild(table);
}
}
document.addEventListener('DOMContentLoaded', async () => {
document.getElementById('editorMode').value = 'tree'; // Set default mode to tree
editor = new JSONEditor(document.getElementById('editor'), { mode: 'tree' });
await populateFileLinks();
// Load the first file initially
const firstLink = document.querySelector('#fileLinks a');
if (firstLink) {
loadSelectedFile(firstLink.getAttribute('data-filepath'));
}
});
</script>
</body>
</html>
Audio Title