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 ):
|
def formfield_for_dbfield( self, db_field, **kwargs ):
|
||||||
formfield = super().formfield_for_dbfield(db_field, **kwargs)
|
formfield = super().formfield_for_dbfield(db_field, **kwargs)
|
||||||
if isinstance( formfield, JSONField ):
|
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)
|
custom_widget = getattr(self, "field_widgets", {}).get(db_field.name, None)
|
||||||
if custom_widget:
|
if custom_widget:
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
tab-size: {{ tab_size }};
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
@ -44,11 +45,65 @@
|
||||||
const textarea = codearea.querySelector('textarea');
|
const textarea = codearea.querySelector('textarea');
|
||||||
const code = codearea.querySelector('code');
|
const code = codearea.querySelector('code');
|
||||||
|
|
||||||
textarea.addEventListener('input', (e) => {
|
//function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
|
||||||
code.innerHTML = textarea.value;
|
function sync(){
|
||||||
|
code.innerHTML = new Option(textarea.value).innerHTML; //encode(textarea.value);
|
||||||
delete code.dataset.highlighted;
|
delete code.dataset.highlighted;
|
||||||
hljs.highlightElement( code )
|
hljs.highlightElement( code )
|
||||||
});
|
}
|
||||||
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>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,65 @@
|
||||||
|
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.forms import Textarea
|
from django.forms import Textarea
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
class Codearea( Textarea ):
|
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.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 )
|
super().__init__( *args, **kwargs )
|
||||||
|
|
||||||
def render( self, name, value, attrs = None, renderer = None ):
|
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({
|
return loader.get_template("asyncron/codearea-widget.html").render({
|
||||||
"textarea": super().render( name, value, attrs, renderer ),
|
"textarea": super().render( name, value, attrs, renderer ),
|
||||||
"value": value,
|
"value": value,
|
||||||
"target": name,
|
"target": name,
|
||||||
"language": self.language
|
"tab_size": self.tab_size,
|
||||||
|
"language": self.language,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user