extract rendering code
This commit is contained in:
parent
7e462ec372
commit
bf3266a83a
1 changed files with 181 additions and 121 deletions
302
editor.html
302
editor.html
|
|
@ -11,25 +11,25 @@
|
|||
|
||||
#container {
|
||||
position: absolute;
|
||||
border: 1px solid black;
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
#container.focus {
|
||||
border: 1px solid #327fbd;;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
position: absolute;
|
||||
border: 1px solid black;
|
||||
margin: 4px;
|
||||
width: 590px;
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
font-family: Courier New;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#canvas.focus {
|
||||
border: 1px solid #327fbd;;
|
||||
}
|
||||
|
||||
|
||||
.composition {
|
||||
position: absolute;
|
||||
text-decoration: underline;
|
||||
|
|
@ -55,7 +55,6 @@
|
|||
<body>
|
||||
|
||||
<div id="container">
|
||||
<div id="canvas"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
|
@ -229,13 +228,13 @@ function KeyBinding(element, host)
|
|||
});
|
||||
};
|
||||
|
||||
function Editor(containerId, canvasId)
|
||||
function Editor(renderer)
|
||||
{
|
||||
this.container = document.getElementById(containerId);
|
||||
this.canvas = document.getElementById(canvasId);
|
||||
var container = renderer.getContainerElement();
|
||||
this.renderer = renderer;
|
||||
|
||||
var textInput = new TextInput(container, this);
|
||||
new KeyBinding(this.container, this);
|
||||
new KeyBinding(container, this);
|
||||
|
||||
var self = this;
|
||||
addListener(container, "mousedown", function(e) {
|
||||
|
|
@ -244,16 +243,6 @@ function Editor(containerId, canvasId)
|
|||
return preventDefault(e);
|
||||
});
|
||||
|
||||
this.measureSizes();
|
||||
|
||||
this.composition = document.createElement("div");
|
||||
this.composition.className = "composition";
|
||||
this.composition.style.height = this.lineHeight + "px";
|
||||
|
||||
this.cursor = document.createElement("div");
|
||||
this.cursor.className = "cursor";
|
||||
this.cursor.style.height = this.lineHeight + "px";
|
||||
|
||||
this.row = 0;
|
||||
this.col = 0;
|
||||
this.lines = [""];
|
||||
|
|
@ -261,103 +250,30 @@ function Editor(containerId, canvasId)
|
|||
this.draw();
|
||||
}
|
||||
|
||||
Editor.prototype = {
|
||||
|
||||
measureSizes : function()
|
||||
{
|
||||
var measureNode = document.createElement("div");
|
||||
var style = measureNode.style;
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = "-1000px";
|
||||
style.visibility = "hidden";
|
||||
style.position = "absolute";
|
||||
style.overflow = "visible";
|
||||
|
||||
measureNode.innerHTML = "X<br>X";
|
||||
this.canvas.appendChild(measureNode);
|
||||
|
||||
this.lineHeight = Math.round(measureNode.offsetHeight / 2);
|
||||
this.characterWidth = measureNode.offsetWidth;
|
||||
|
||||
this.canvas.removeChild(measureNode);
|
||||
},
|
||||
|
||||
Editor.prototype =
|
||||
{
|
||||
draw : function()
|
||||
{
|
||||
if (this.cursor.parentNode) {
|
||||
this.canvas.removeChild(this.cursor);
|
||||
}
|
||||
|
||||
// TODO HACK
|
||||
var longestLine = this.canvas.clientWidth;
|
||||
for (var i=0; i < this.lines.length; i++) {
|
||||
longestLine = Math.max(longestLine, (this.lines[i].length * this.characterWidth));
|
||||
}
|
||||
|
||||
var html = [];
|
||||
for (var i=0; i < this.lines.length; i++)
|
||||
{
|
||||
html.push(
|
||||
"<div class='line ",
|
||||
i % 2 == 0 ? "even" : "odd",
|
||||
"' style='height:" + this.lineHeight + "px;",
|
||||
"width:", longestLine, "px'>",
|
||||
this.lines[i].
|
||||
replace(/&/g, "&").
|
||||
replace(/</g, "<").
|
||||
replace(/\s/g, " "),
|
||||
"</div>"
|
||||
);
|
||||
};
|
||||
this.canvas.innerHTML = html.join("");
|
||||
|
||||
this.updateCursor();
|
||||
this.renderer.draw(this.lines);
|
||||
this.renderer.updateCursor(this.row, this.col);
|
||||
},
|
||||
|
||||
updateCursor : function()
|
||||
{
|
||||
var left = this.col * this.characterWidth;
|
||||
var top = this.row * this.lineHeight;
|
||||
|
||||
this.cursor.style.left = left + "px";
|
||||
this.cursor.style.top = top + "px";
|
||||
|
||||
this.canvas.appendChild(this.cursor);
|
||||
|
||||
if (this.canvas.scrollLeft > left) {
|
||||
this.canvas.scrollLeft = left;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollLeft + this.canvas.clientWidth < left + this.characterWidth) {
|
||||
this.canvas.scrollLeft = left + this.characterWidth - this.canvas.clientWidth;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollTop > top) {
|
||||
this.canvas.scrollTop = top;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollTop + this.canvas.clientHeight < top + this.lineHeight) {
|
||||
this.canvas.scrollTop = top + this.lineHeight - this.canvas.clientHeight;
|
||||
}
|
||||
updateCursor : function() {
|
||||
this.renderer.updateCursor(this.row, this.col);
|
||||
},
|
||||
|
||||
onFocus : function() {
|
||||
this.canvas.className = "focus";
|
||||
this.renderer.visualizeFocus();
|
||||
},
|
||||
|
||||
onBlur : function() {
|
||||
this.canvas.className = "";
|
||||
this.renderer.visualizeBlur();
|
||||
},
|
||||
|
||||
placeCursorToMouse : function(pageX, pageY)
|
||||
{
|
||||
var canvas = this.canvas;
|
||||
var canvasPos = canvas.getBoundingClientRect();
|
||||
|
||||
var row = Math.floor((pageY + canvas.scrollTop - canvasPos.top) / this.lineHeight);
|
||||
var col = Math.floor((pageX + canvas.scrollLeft - canvasPos.left) / this.characterWidth);
|
||||
|
||||
this.moveTo(row, col)
|
||||
var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
|
||||
this.moveTo(pos.row, pos.column);
|
||||
},
|
||||
|
||||
onTextInput: function(text)
|
||||
|
|
@ -443,25 +359,16 @@ Editor.prototype = {
|
|||
|
||||
onCompositionStart : function()
|
||||
{
|
||||
setText(this.composition, "");
|
||||
|
||||
this.composition.style.left = (this.col * this.characterWidth) + "px";
|
||||
this.composition.style.top = (this.row * this.lineHeight) + "px";
|
||||
|
||||
this.renderer.showComposition(this.row, this.col);
|
||||
this.onTextInput(" ");
|
||||
|
||||
this.canvas.appendChild(this.composition);
|
||||
},
|
||||
|
||||
onCompositionUpdate : function(text) {
|
||||
setText(this.composition, text);
|
||||
this.renderer.setCompositionText(text);
|
||||
},
|
||||
|
||||
onCompositionEnd : function() {
|
||||
if (this.composition.parentNode) {
|
||||
this.canvas.removeChild(this.composition);
|
||||
}
|
||||
|
||||
this.renderer.hideComposition();
|
||||
this.removeLeft();
|
||||
},
|
||||
|
||||
|
|
@ -473,7 +380,8 @@ Editor.prototype = {
|
|||
this.moveBy(1, 0);
|
||||
},
|
||||
|
||||
moveLeft : function() {
|
||||
moveLeft : function()
|
||||
{
|
||||
if (this.col == 0) {
|
||||
if (this.row > 0) {
|
||||
this.moveTo(this.row-1, this.lines[this.row-1].length);
|
||||
|
|
@ -513,7 +421,159 @@ Editor.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
new Editor("container", "canvas", "text");
|
||||
|
||||
function DumbRenderer(containerId)
|
||||
{
|
||||
this.container = document.getElementById(containerId);
|
||||
this.canvas = document.createElement("div");
|
||||
this.canvas.className = "canvas";
|
||||
this.container.appendChild(this.canvas);
|
||||
|
||||
this._measureSizes();
|
||||
|
||||
this.composition = document.createElement("div");
|
||||
this.composition.className = "composition";
|
||||
this.composition.style.height = this.lineHeight + "px";
|
||||
|
||||
this.cursor = document.createElement("div");
|
||||
this.cursor.className = "cursor";
|
||||
this.cursor.style.height = this.lineHeight + "px";
|
||||
}
|
||||
|
||||
DumbRenderer.prototype =
|
||||
{
|
||||
getContainerElement : function() {
|
||||
return this.container;
|
||||
},
|
||||
|
||||
_measureSizes : function()
|
||||
{
|
||||
var measureNode = document.createElement("div");
|
||||
var style = measureNode.style;
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = "-1000px";
|
||||
style.visibility = "hidden";
|
||||
style.position = "absolute";
|
||||
style.overflow = "visible";
|
||||
|
||||
measureNode.innerHTML = "X<br>X";
|
||||
this.canvas.appendChild(measureNode);
|
||||
|
||||
this.lineHeight = Math.round(measureNode.offsetHeight / 2);
|
||||
this.characterWidth = measureNode.offsetWidth;
|
||||
|
||||
this.canvas.removeChild(measureNode);
|
||||
},
|
||||
|
||||
draw : function(lines)
|
||||
{
|
||||
// TODO HACK
|
||||
var longestLine = this.canvas.clientWidth;
|
||||
for (var i=0; i < lines.length; i++) {
|
||||
longestLine = Math.max(longestLine, (lines[i].length * this.characterWidth));
|
||||
}
|
||||
|
||||
var html = [];
|
||||
for (var i=0; i < lines.length; i++)
|
||||
{
|
||||
html.push(
|
||||
"<div class='line ",
|
||||
i % 2 == 0 ? "even" : "odd",
|
||||
"' style='height:" + this.lineHeight + "px;",
|
||||
"width:", longestLine, "px'>",
|
||||
lines[i].
|
||||
replace(/&/g, "&").
|
||||
replace(/</g, "<").
|
||||
replace(/\s/g, " "),
|
||||
"</div>"
|
||||
);
|
||||
};
|
||||
this.canvas.innerHTML = html.join("");
|
||||
|
||||
this.canvas.appendChild(this.cursor)
|
||||
},
|
||||
|
||||
updateCursor : function(row, column)
|
||||
{
|
||||
var left = column * this.characterWidth;
|
||||
var top = row * this.lineHeight;
|
||||
|
||||
this.cursor.style.left = left + "px";
|
||||
this.cursor.style.top = top + "px";
|
||||
|
||||
this.canvas.appendChild(this.cursor);
|
||||
|
||||
if (this.canvas.scrollLeft > left) {
|
||||
this.canvas.scrollLeft = left;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollLeft + this.canvas.clientWidth < left + this.characterWidth) {
|
||||
this.canvas.scrollLeft = left + this.characterWidth - this.canvas.clientWidth;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollTop > top) {
|
||||
this.canvas.scrollTop = top;
|
||||
}
|
||||
|
||||
if (this.canvas.scrollTop + this.canvas.clientHeight < top + this.lineHeight) {
|
||||
this.canvas.scrollTop = top + this.lineHeight - this.canvas.clientHeight;
|
||||
}
|
||||
},
|
||||
|
||||
screenToTextCoordinates : function(pageX, pageY)
|
||||
{
|
||||
var canvas = this.canvas;
|
||||
var canvasPos = canvas.getBoundingClientRect();
|
||||
|
||||
if (pageX < canvasPos.left || pageX > canvasPos.right) {
|
||||
row = null;
|
||||
} else {
|
||||
var row = Math.floor((pageY + canvas.scrollTop - canvasPos.top) / this.lineHeight);
|
||||
}
|
||||
|
||||
if (pageY < canvasPos.top || pageY > canvasPos.bottom) {
|
||||
col = null;
|
||||
} else {
|
||||
var col = Math.floor((pageX + canvas.scrollLeft - canvasPos.left) / this.characterWidth);
|
||||
}
|
||||
|
||||
return {
|
||||
row: row,
|
||||
column: col
|
||||
}
|
||||
},
|
||||
|
||||
visualizeFocus : function() {
|
||||
this.container.className = "focus";
|
||||
},
|
||||
|
||||
visualizeBlur : function() {
|
||||
this.container.className = "";
|
||||
},
|
||||
|
||||
showComposition : function(row, column)
|
||||
{
|
||||
setText(this.composition, "");
|
||||
|
||||
this.composition.style.left = (column * this.characterWidth+1) + "px";
|
||||
this.composition.style.top = (row * this.lineHeight+1) + "px";
|
||||
|
||||
this.container.appendChild(this.composition);
|
||||
},
|
||||
|
||||
setCompositionText : function(text) {
|
||||
setText(this.composition, text);
|
||||
},
|
||||
|
||||
hideComposition : function() {
|
||||
if (this.composition.parentNode) {
|
||||
this.container.removeChild(this.composition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
new Editor(new DumbRenderer("container"), "text");
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue