Enhance markup inserter with logging and auto-attach functionality for textareas

This commit is contained in:
Ross
2026-03-23 12:15:49 +00:00
parent 5a5eaa04a2
commit 3ae6ce53bc
2 changed files with 75 additions and 47 deletions
+29 -1
View File
@@ -1,5 +1,6 @@
// Simple markup inserter module
(function(global){
console.log('markup_inserter.js loaded');
function insertAtCursor(el, text){
if(!el) return;
const start = el.selectionStart || 0;
@@ -32,6 +33,7 @@
if(!textarea) return null;
// avoid double attaching
if(textarea._markupToolbarAttached) return null;
console.log('Attaching markup toolbar to textarea', textarea);
const toolbar = createToolbar();
textarea.parentNode.insertBefore(toolbar, textarea);
toolbar.querySelectorAll('.markup-insert-button').forEach(function(btn){
@@ -53,6 +55,7 @@
function initForNames(names){
if(!Array.isArray(names)) return;
document.addEventListener('DOMContentLoaded', function(){
console.log('markupInserter.initForNames DOMContentLoaded handler running for', names);
names.forEach(function(name){
const el = document.querySelector('textarea[name="'+name+'"]');
if(el) attachToolbarToTextarea(el);
@@ -70,23 +73,48 @@
// Auto-attach to placeholders rendered in HTMX responses or server-side includes.
document.addEventListener('DOMContentLoaded', function(){
console.log('markupInserter DOMContentLoaded auto-attach running');
// Attach to explicit placeholders
document.querySelectorAll('.markup-toolbar-placeholder').forEach(function(ph){
// find next textarea sibling
let ta = ph.nextElementSibling;
if(ta && ta.tagName === 'TEXTAREA') attachToolbarToTextarea(ta);
});
// Also auto-init for common case textarea names to cover full-page forms
try{ initForNames(['description','history','discussion','report','notes']); }catch(e){}
});
document.addEventListener('htmx:afterSwap', function(evt){
console.log('markupInserter htmx:afterSwap event', evt && evt.detail && evt.detail.target);
try{
const target = evt.detail && evt.detail.target ? evt.detail.target : document;
(target.querySelectorAll ? target : document).querySelectorAll('.markup-toolbar-placeholder').forEach(function(ph){
let ta = ph.nextElementSibling;
if(ta && ta.tagName === 'TEXTAREA') attachToolbarToTextarea(ta);
});
// Also attach to any textareas within the swapped target that match our common names
var ctx = evt.detail && evt.detail.target ? evt.detail.target : document;
['description','history','discussion','report','notes'].forEach(function(name){
ctx.querySelectorAll && ctx.querySelectorAll('textarea[name="'+name+'"]') && ctx.querySelectorAll('textarea[name="'+name+'"]').forEach(function(ta){ attachToolbarToTextarea(ta); });
});
}catch(e){/* ignore */}
});
// Fallback: attach toolbar when a textarea receives focus (covers dynamically created editors)
document.addEventListener('focusin', function(e){
console.log('markupInserter focusin event for', e && e.target);
try{
var el = e.target;
if(!el || el.tagName !== 'TEXTAREA') return;
// Attach for common names or if a placeholder is present
var name = el.getAttribute('name') || '';
if(['description','history','discussion','report','notes'].includes(name) || (el.previousElementSibling && el.previousElementSibling.classList && el.previousElementSibling.classList.contains('markup-toolbar-placeholder'))){
attachToolbarToTextarea(el);
}
}catch(err){/* ignore */}
}, true);
// Expose API
global.markupInserter = {
attachToolbarToTextarea: attachToolbarToTextarea,
+46 -46
View File
@@ -146,58 +146,58 @@
<!-- Differential Collapsible Panel -->
<div class="card my-3 bg-dark text-white">
<div class="card-header">
<a class="collapsed text-white" data-bs-toggle="collapse" href="#differentialPanel" role="button" aria-expanded="false" aria-controls="differentialPanel">
<h3 class="d-inline">Differential</h3>
<span class="ms-2">(click to expand/collapse)</span>
</a>
</div>
<div class="collapse" id="differentialPanel">
<input type="button" value="Add Another Differential" id="add_more_differential" class="btn btn-sm btn-primary float-end">
<div class="card-body">
<div id="casedifferential_formset" class="list_formset">
<ol>
{% for form in casedifferential_formset %}
<li class="no-error casedifferential_formset">
{{form.non_field_errors}}
{{form.errors}}
{{ form | crispy}}
</li>
{% endfor %}
</ol>
<div class="card my-3 bg-dark text-white">
<div class="card-header">
<a class="collapsed text-white" data-bs-toggle="collapse" href="#differentialPanel" role="button" aria-expanded="false" aria-controls="differentialPanel">
<h3 class="d-inline">Differential</h3>
<span class="ms-2">(click to expand/collapse)</span>
</a>
</div>
<div class="collapse" id="differentialPanel">
<input type="button" value="Add Another Differential" id="add_more_differential" class="btn btn-sm btn-primary float-end">
<div class="card-body">
<div id="casedifferential_formset" class="list_formset">
<ol>
{% for form in casedifferential_formset %}
<li class="no-error casedifferential_formset">
{{form.non_field_errors}}
{{form.errors}}
{{ form | crispy}}
</li>
{% endfor %}
</ol>
</div>
{{ casedifferential_formset.management_form | crispy }}
</div>
</div>
{{ casedifferential_formset.management_form | crispy }}
</div>
</div>
</div>
<!-- Resource Collapsible Panel -->
<div class="card my-3 bg-dark text-white">
<div class="card-header">
<a class="collapsed text-white" data-bs-toggle="collapse" href="#resourcePanel" role="button" aria-expanded="false" aria-controls="resourcePanel">
<h3 class="d-inline">Resource</h3>
<span class="ms-2">(click to expand/collapse)</span>
</a>
</div>
<div class="collapse" id="resourcePanel">
<input type="button" value="Add Another Resource" id="add_more_resource" class="btn btn-sm btn-primary float-end">
<div class="card-body">
<div id="caseresource_formset" class="list_formset">
<ol>
{% for form in caseresource_formset %}
<li class="no-error caseresource_formset">
{{form.non_field_errors}}
{{form.errors}}
{{ form | crispy}}
</li>
{% endfor %}
</ol>
<div class="card my-3 bg-dark text-white">
<div class="card-header">
<a class="collapsed text-white" data-bs-toggle="collapse" href="#resourcePanel" role="button" aria-expanded="false" aria-controls="resourcePanel">
<h3 class="d-inline">Resource</h3>
<span class="ms-2">(click to expand/collapse)</span>
</a>
</div>
<div class="collapse" id="resourcePanel">
<input type="button" value="Add Another Resource" id="add_more_resource" class="btn btn-sm btn-primary float-end">
<div class="card-body">
<div id="caseresource_formset" class="list_formset">
<ol>
{% for form in caseresource_formset %}
<li class="no-error caseresource_formset">
{{form.non_field_errors}}
{{form.errors}}
{{ form | crispy}}
</li>
{% endfor %}
</ol>
</div>
{{ caseresource_formset.management_form | crispy}}
</div>
</div>
{{ caseresource_formset.management_form | crispy}}
</div>
</div>
</div>
<br/>
<input type="submit" class="submit-button" value="Submit" name="submit">
</form>