JSFiddle - React, Tailwind, and code Playground
by Josh Pullen
HTML
<div id="editor" class="editor" tabindex="-1">
<!--
<div class="editor-selection">
<div class="editor-selection-section"></div>
</div>
<div class="editor-text">
<div class="editor-text-line">testing this out</div>
<div class="editor-text-line">test test</div>
<div class="editor-text-line">yo yo pineapple</div>
</div>
-->
</div>
CSS
.editor {
background: #ddd;
position: relative;
cursor: text;
overflow: auto;
}
.editor-text {
font-family: monospace;
white-space: nowrap;
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
user-select: none;
}
.editor-selection {
position:absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.editor-selection-cursor {
position: absolute;
background: #00f;
width: 1px;
height: 15px;
}
.editor-selection-section {
position: absolute;
background: rgba(0,0,255,0.2);
}
JavaScript
class Editor {
constructor(editorElem) {
this.input = [
'testing this test',
'testing test testing test',
'really test test testing',
'testing again more testing'
];
this.elem = editorElem;
let selectionElem = document.createElement('div');
selectionElem.className = 'editor-selection';
editorElem.append(selectionElem);
this.selectionElem = selectionElem;
let textElem = document.createElement('div');
textElem.className = 'editor-text';
editorElem.append(textElem);
this.textElem = textElem;
this.renderText();
this.initEventListeners();
}
renderText() {
// TODO: Restructure to only change things that have been updated (diff-style)
this.textElem.innerHTML = '';
for(let i = 0; i < this.input.length; i++) {
let line = document.createElement('div');
line.innerText = this.input[i];
this.textElem.append(line);
}
}
initEventListeners() {
let _this = this;
this.elem.addEventListener('click', function(e) {
let x = e.pageX - _this.elem.offsetLeft;
let y = e.pageY - _this.elem.offsetTop;
testSelection = new Selection(Loc.nearest(x, y).restrain(_this));
testSelection.render(editor);
});
this.elem.addEventListener('keydown', function(e) {
let keycode = e.keycode || e.which;
switch(keycode) {
case 37: // Left arrow
testSelection.loc2.changeCol(-1, _this).restrain(_this);
if(!e.shiftKey) testSelection.loc1 = testSelection.loc2.clone();
testSelection.render(_this);
break;
case 38: // Up arrow
testSelection.loc2.changeRow(-1).restrain(_this);
if(!e.shiftKey) testSelection.loc1 = testSelection.loc2.clone();
testSelection.render(_this);
break;
case 39: // Right arrow
testSelection.loc2.changeCol(1, _this).restrain(_this);
if(!e.shiftKey) testSelection.loc1 = testSelection.loc2.clone();
...