Codearea: Added tab-size and tab insertion to the widget
This commit is contained in:
parent
9d7e1b080d
commit
9ee0798006
|
|
@ -11,7 +11,7 @@ class BaseModelAdmin( admin.ModelAdmin ):
|
|||
def formfield_for_dbfield( self, db_field, **kwargs ):
|
||||
formfield = super().formfield_for_dbfield(db_field, **kwargs)
|
||||
if isinstance( formfield, JSONField ):
|
||||
formfield.widget = Codearea( language = "json" )
|
||||
formfield.widget = Codearea( language = "json-pretty" )
|
||||
|
||||
custom_widget = getattr(self, "field_widgets", {}).get(db_field.name, None)
|
||||
if custom_widget:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
padding: 5px;
|
||||
font-size: 1em;
|
||||
border-radius: 3px;
|
||||
tab-size: {{ tab_size }};
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -44,11 +45,65 @@
|
|||
const textarea = codearea.querySelector('textarea');
|
||||
const code = codearea.querySelector('code');
|
||||
|
||||
textarea.addEventListener('input', (e) => {
|
||||
code.innerHTML = textarea.value;
|
||||
//function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
|
||||
function sync(){
|
||||
code.innerHTML = new Option(textarea.value).innerHTML; //encode(textarea.value);
|
||||
delete code.dataset.highlighted;
|
||||
hljs.highlightElement( code )
|
||||
});
|
||||
}
|
||||
hljs.highlightElement( code )
|
||||
|
||||
textarea.addEventListener('keydown', function o(e){
|
||||
if (e.key != 'Tab') return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
//Largly From: https://stackoverflow.com/a/45396754
|
||||
if (this.selectionStart == this.selectionEnd){
|
||||
document.execCommand('insertText', false, "\t");
|
||||
return;
|
||||
}
|
||||
|
||||
// Block indent/unindent trashes undo stack.
|
||||
// Select whole lines
|
||||
var selStart = this.selectionStart;
|
||||
var selEnd = this.selectionEnd;
|
||||
var text = this.value;
|
||||
while (selStart > 0 && text[selStart-1] != '\n')
|
||||
selStart--;
|
||||
while (selEnd > 0 && text[selEnd-1]!='\n' && selEnd < text.length)
|
||||
selEnd++;
|
||||
|
||||
// Get selected text
|
||||
var lines = text.substr(selStart, selEnd - selStart).split('\n');
|
||||
|
||||
// Insert tabs
|
||||
for (var i=0; i<lines.length; i++)
|
||||
{
|
||||
// Don't indent last line if cursor at start of line
|
||||
if (i==lines.length-1 && lines[i].length==0)
|
||||
continue;
|
||||
|
||||
// Tab or Shift+Tab?
|
||||
if (e.shiftKey)
|
||||
{
|
||||
if (lines[i].startsWith('\t'))
|
||||
lines[i] = lines[i].substr(1);
|
||||
else if (lines[i].startsWith(" "))
|
||||
lines[i] = lines[i].substr(4);
|
||||
}
|
||||
else
|
||||
lines[i] = "\t" + lines[i];
|
||||
}
|
||||
lines = lines.join('\n');
|
||||
|
||||
// Update the text area
|
||||
this.value = text.substr(0, selStart) + lines + text.substr(selEnd);
|
||||
this.selectionStart = selStart;
|
||||
this.selectionEnd = selStart + lines.length;
|
||||
sync();
|
||||
})
|
||||
textarea.addEventListener('input', () => sync() );
|
||||
|
||||
})()
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,65 @@
|
|||
|
||||
from django.template import loader
|
||||
from django.forms import Textarea
|
||||
|
||||
import json
|
||||
|
||||
class Codearea( Textarea ):
|
||||
|
||||
def __init__( self, *args, language = "auto", **kwargs ):
|
||||
def __init__( self,
|
||||
*args,
|
||||
language = "auto",
|
||||
spell_check = False,
|
||||
extra_rows = 2, extra_cols = 10,
|
||||
min_rows = 10, min_cols = 40,
|
||||
tab_size = 4,
|
||||
**kwargs
|
||||
):
|
||||
self.language = language
|
||||
self.spell_check = spell_check
|
||||
self.extra_rows = extra_rows
|
||||
self.extra_cols = extra_cols
|
||||
self.min_rows = min_rows
|
||||
self.min_cols = min_cols
|
||||
self.tab_size = tab_size
|
||||
|
||||
super().__init__( *args, **kwargs )
|
||||
|
||||
def render( self, name, value, attrs = None, renderer = None ):
|
||||
if not self.spell_check:
|
||||
attrs.update({
|
||||
"autocomplete": "off",
|
||||
"autocorrect": "off",
|
||||
"autocapitalize": "off",
|
||||
"spellcheck": "false"
|
||||
})
|
||||
|
||||
value = value or ""
|
||||
|
||||
if self.language == "json-pretty":
|
||||
self.language = "json"
|
||||
value = json.dumps(json.loads(value), indent = 4 )
|
||||
|
||||
|
||||
if self.extra_rows is not False:
|
||||
attrs.update(
|
||||
rows = max( value.count("\n") + self.extra_rows, self.min_rows )
|
||||
)
|
||||
|
||||
if self.extra_cols is not False:
|
||||
try:
|
||||
max_line_chars = max( len(line) + line.count("\t") * (self.tab_size - 1) for line in value.split("\n") )
|
||||
except ValueError:
|
||||
max_line_chars = 0
|
||||
|
||||
attrs.update(
|
||||
cols = max( max_line_chars + self.extra_cols, self.min_cols )
|
||||
)
|
||||
|
||||
|
||||
return loader.get_template("asyncron/codearea-widget.html").render({
|
||||
"textarea": super().render( name, value, attrs, renderer ),
|
||||
"value": value,
|
||||
"target": name,
|
||||
"language": self.language
|
||||
"tab_size": self.tab_size,
|
||||
"language": self.language,
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user