Enhance JSON display by integrating pretty JSON formatter in various templates
This commit is contained in:
@@ -169,7 +169,13 @@
|
|||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<details>
|
<details>
|
||||||
<summary class="small">Annotation JSON</summary>
|
<summary class="small">Annotation JSON</summary>
|
||||||
<div class="mt-2 small">{% if question.image_annotations %}<pre class="mb-0">{{ question.image_annotations }}</pre>{% else %}No saved annotations.{% endif %}</div>
|
<div class="mt-2 small">
|
||||||
|
{% if question.image_annotations %}
|
||||||
|
{% include 'atlas/partials/json_pretty.html' with json_value=question.image_annotations title='Image annotations' %}
|
||||||
|
{% else %}
|
||||||
|
No saved annotations.
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -743,12 +743,10 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary class="small text-muted" style="cursor:pointer;">Show advanced (viewer state & annotations)</summary>
|
<summary class="small text-muted" style="cursor:pointer;">Show advanced (viewer state & annotations)</summary>
|
||||||
<div>
|
<div>
|
||||||
<strong>Viewer State:</strong>
|
{% include 'atlas/partials/json_pretty.html' with json_value=ds.viewerstate title='Viewer State' %}
|
||||||
<pre class="small">{{ ds.viewerstate|default:"{}" }}</pre>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Annotations:</strong>
|
{% include 'atlas/partials/json_pretty.html' with json_value=ds.annotations title='Annotations' %}
|
||||||
<pre class="small">{{ ds.annotations|default:"{}" }}</pre>
|
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,12 +67,10 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary class="small text-muted" style="cursor:pointer;">Show advanced (viewer state & annotations)</summary>
|
<summary class="small text-muted" style="cursor:pointer;">Show advanced (viewer state & annotations)</summary>
|
||||||
<div>
|
<div>
|
||||||
<strong>Viewer State:</strong>
|
{% include 'atlas/partials/json_pretty.html' with json_value=ds.viewerstate title='Viewer State' %}
|
||||||
<pre class="small">{{ ds.viewerstate|default:"{}" }}</pre>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Annotations:</strong>
|
{% include 'atlas/partials/json_pretty.html' with json_value=ds.annotations title='Annotations' %}
|
||||||
<pre class="small">{{ ds.annotations|default:"{}" }}</pre>
|
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -71,26 +71,26 @@
|
|||||||
hx-after
|
hx-after
|
||||||
class="btn btn-warning btn-sm"
|
class="btn btn-warning btn-sm"
|
||||||
onclick="
|
onclick="
|
||||||
this.style.display='none';
|
this.style.display='none';
|
||||||
var li = this.closest('li');
|
var li = this.closest('li');
|
||||||
var ul = li.parentNode;
|
var ul = li.parentNode;
|
||||||
ul.insertBefore(li, ul.firstChild);
|
ul.insertBefore(li, ul.firstChild);
|
||||||
li.scrollIntoView({behavior: 'smooth', block: 'center'});
|
li.scrollIntoView({behavior: 'smooth', block: 'center'});
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var form = document.querySelector('#displayset-edit-form-{{ ds.pk }} form');
|
var form = document.querySelector('#displayset-edit-form-{{ ds.pk }} form');
|
||||||
if (form) {
|
if (form) {
|
||||||
var cancelBtn = document.createElement('button');
|
var cancelBtn = document.createElement('button');
|
||||||
cancelBtn.type = 'button';
|
cancelBtn.type = 'button';
|
||||||
cancelBtn.className = 'btn btn-secondary btn-sm ms-2';
|
cancelBtn.className = 'btn btn-secondary btn-sm ms-2';
|
||||||
cancelBtn.textContent = 'Cancel';
|
cancelBtn.textContent = 'Cancel';
|
||||||
cancelBtn.onclick = function() {
|
cancelBtn.onclick = function() {
|
||||||
document.querySelector('#displayset-edit-form-{{ ds.pk }}').innerHTML = '';
|
document.querySelector('#displayset-edit-form-{{ ds.pk }}').innerHTML = '';
|
||||||
document.querySelector('#displayset-{{ ds.pk }}-edit-btn').style.display = '';
|
document.querySelector('#displayset-{{ ds.pk }}-edit-btn').style.display = '';
|
||||||
};
|
};
|
||||||
form.appendChild(cancelBtn);
|
form.appendChild(cancelBtn);
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
"
|
"
|
||||||
>Edit</button>
|
>Edit</button>
|
||||||
<button
|
<button
|
||||||
hx-delete="{% url 'atlas:case_displaysets_delete' ds.pk %}"
|
hx-delete="{% url 'atlas:case_displaysets_delete' ds.pk %}"
|
||||||
|
|||||||
@@ -10,69 +10,69 @@
|
|||||||
<div class="json-container small" style="max-height:360px; overflow:auto; font-family: monospace; background: #f8f9fa; padding: .5rem; border-radius: .25rem;"></div>
|
<div class="json-container small" style="max-height:360px; overflow:auto; font-family: monospace; background: #f8f9fa; padding: .5rem; border-radius: .25rem;"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function(){
|
(function(){
|
||||||
// Parse template-provided JSON value into a JS object
|
// Parse template-provided JSON value into a JS object
|
||||||
var obj;
|
var obj;
|
||||||
try{
|
try{
|
||||||
obj = {{ json_value|default:"{}"|safe }};
|
obj = {{ json_value|default:"{}"|safe }};
|
||||||
}catch(e){
|
}catch(e){
|
||||||
try{ obj = JSON.parse(String({{ json_value|default:"{}"|safe }})); }catch(e){ obj = {}; }
|
try{ obj = JSON.parse(String({{ json_value|default:"{}"|safe }})); }catch(e){ obj = {}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = document.currentScript.previousElementSibling;
|
var container = document.currentScript.previousElementSibling;
|
||||||
var btnCopy = document.currentScript.parentNode.querySelector('.btn-copy-json');
|
var btnCopy = document.currentScript.parentNode.querySelector('.btn-copy-json');
|
||||||
var btnToggle = document.currentScript.parentNode.querySelector('.btn-toggle-json');
|
var btnToggle = document.currentScript.parentNode.querySelector('.btn-toggle-json');
|
||||||
|
|
||||||
function renderWithFormatter(depth){
|
function renderWithFormatter(depth){
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
if (window.JSONFormatter){
|
if (window.JSONFormatter){
|
||||||
try{
|
try{
|
||||||
var fmt = new JSONFormatter(obj, depth || 1, {hoverPreviewEnabled: false, animateOpen: false});
|
var fmt = new JSONFormatter(obj, depth || 1, {hoverPreviewEnabled: false, animateOpen: false});
|
||||||
container.appendChild(fmt.render());
|
container.appendChild(fmt.render());
|
||||||
return fmt;
|
return fmt;
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
container.textContent = JSON.stringify(obj, null, 2);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
container.textContent = JSON.stringify(obj, null, 2);
|
container.textContent = JSON.stringify(obj, null, 2);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
container.textContent = JSON.stringify(obj, null, 2);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamic load of json-formatter-js if not already present
|
// Dynamic load of json-formatter-js if not already present
|
||||||
function ensureFormatter(cb){
|
function ensureFormatter(cb){
|
||||||
if (window.JSONFormatter) return cb();
|
if (window.JSONFormatter) return cb();
|
||||||
var s = document.createElement('script');
|
var s = document.createElement('script');
|
||||||
s.src = 'https://unpkg.com/json-formatter-js@2.3.3/dist/json-formatter.umd.js';
|
s.src = 'https://unpkg.com/json-formatter-js@2.3.3/dist/json-formatter.umd.js';
|
||||||
s.onload = function(){ setTimeout(cb, 0); };
|
s.onload = function(){ setTimeout(cb, 0); };
|
||||||
s.onerror = function(){ cb(); };
|
s.onerror = function(){ cb(); };
|
||||||
document.head.appendChild(s);
|
document.head.appendChild(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep current formatter instance so we can re-render collapsed/expanded
|
// Keep current formatter instance so we can re-render collapsed/expanded
|
||||||
var currentFormatter = null;
|
var currentFormatter = null;
|
||||||
ensureFormatter(function(){ currentFormatter = renderWithFormatter(1); });
|
ensureFormatter(function(){ currentFormatter = renderWithFormatter(1); });
|
||||||
|
|
||||||
btnToggle.addEventListener('click', function(){
|
btnToggle.addEventListener('click', function(){
|
||||||
// Toggle between collapsed (depth=1) and expanded (depth=0 => fully expanded)
|
// Toggle between collapsed (depth=1) and expanded (depth=0 => fully expanded)
|
||||||
if (btnToggle.dataset.state === 'expanded'){
|
if (btnToggle.dataset.state === 'expanded'){
|
||||||
currentFormatter = renderWithFormatter(1);
|
currentFormatter = renderWithFormatter(1);
|
||||||
btnToggle.dataset.state = 'collapsed';
|
btnToggle.dataset.state = 'collapsed';
|
||||||
btnToggle.textContent = 'Show';
|
btnToggle.textContent = 'Show';
|
||||||
} else {
|
} else {
|
||||||
currentFormatter = renderWithFormatter(0);
|
currentFormatter = renderWithFormatter(0);
|
||||||
btnToggle.dataset.state = 'expanded';
|
btnToggle.dataset.state = 'expanded';
|
||||||
btnToggle.textContent = 'Hide';
|
btnToggle.textContent = 'Hide';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
btnCopy.addEventListener('click', function(){
|
btnCopy.addEventListener('click', function(){
|
||||||
var text = JSON.stringify(obj, null, 2);
|
var text = JSON.stringify(obj, null, 2);
|
||||||
if (navigator.clipboard){ navigator.clipboard.writeText(text).catch(function(){}); }
|
if (navigator.clipboard){ navigator.clipboard.writeText(text).catch(function(){}); }
|
||||||
else { var ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); try{document.execCommand('copy');}catch(e){} document.body.removeChild(ta); }
|
else { var ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta); ta.select(); try{document.execCommand('copy');}catch(e){} document.body.removeChild(ta); }
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user