JSFiddle - React, Tailwind, and code Playground
by waxwing
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-debug.js"></script>
<script src="http://www.fakeyourbeauty.com/jquery.autosize.input.debug.js"></script>
<i-editor></i-editor>
CSS
i-editor {
outline: none;
}
i-editor .i-term {
font-family: monospace;
padding: 2px;
border-radius: 3px;
font-size: 14px;
border: 1px solid transparent;
}
i-editor span input {
font-family: monospace;
font-size: 14px;
border: none;
background: transparent;
display: inline;
outline: none;
}
i-editor .selected {
border: 1px solid black;
}
JavaScript
ko.components.register('i-editor', {
viewModel: {
createViewModel: function (params, componentInfo) {
function Compound(term) {
this.children = ko.observableArray(term.map(createTerm));
this.template = 'i-compound';
}
function Atom(value) {
this.value = ko.observable(value);
this.template = 'i-atom';
}
function createTerm(expr) {
if (Array.isArray(expr)) {
return new Compound(expr);
} else {
return new Atom(expr);
}
}
var model = new function () {
var self = this;
this.root = createTerm(['value', '>', ['a', '+', 10]], this);
this.editMode = ko.observable(false);
this.selected = ko.observable();
this.isSelected = function (term) {
return self.selected() === term;
};
this.isEditing = function (term) {
return self.editMode() && self.isSelected(term);
};
};
var element = componentInfo.element;
element.tabIndex = 0;
function walkPostOrder(term, callback) {
if (term.children) {
return ko.unwrap(term.children).every(function (it) {
return walkPostOrder(it, callback);
});
}
return callback(term);
}
ko.utils.registerEventHandler(element, 'keydown', function (event) {
if (event.keyCode === 39) {
var selectNext = false;
walkPostOrder(model.root, function (term) {
if (selectNext) {
console.log('selecting');
...