Skip to content

Commit

Permalink
Minor improvement to editor. Now working fairly reliably in WebKit.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed May 15, 2011
1 parent 9aaf9ab commit 6c3ce20
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 81 deletions.
12 changes: 3 additions & 9 deletions examples/ex.editor.html
Expand Up @@ -19,16 +19,10 @@ <h1>Syntax Editor</h1>

<h2>Ruby Editor</h2>

<pre class="syntax ruby"># This file is part of the "Utopia Framework" project, and is licensed under the GNU AGPLv3.
# Copyright 2010 Samuel Williams. All rights reserved.
# See &lt;utopia.rb&gt; for licensing details.
<pre class="syntax clang">/* Foo Bar */
namespace x {

require &#x27;yaml&#x27;

require &#x27;utopia/extensions/date&#x27;
require &#x27;utopia/extensions/string&#x27;
require &#x27;utopia/extensions/hash&#x27;
require &#x27;utopia/extensions/array&#x27;
}
</pre>
</body>
</html>
122 changes: 52 additions & 70 deletions source/jquery.syntax.layout.editor.js
Expand Up @@ -12,23 +12,32 @@ Syntax.Editor = function(container, text) {
Syntax.Editor.prototype.getLines = function() {
var children = this.container.children, lines = [], offsets = [];

for (var j = 0; j < children.length; j += 1) {
if (children[j].nodeType == 3) {
$(children[j]).remove();
}
}

// Sometimes, e.g. when deleting text, children elements are not complete lines.
// We need to accumulate incomplete lines (1), and then append them to the
// start of the next complete line (2)
var text = "";
for (var i = 0; i < children.length; i += 1) {
var childLines = Syntax.getCDATA([children[i]]).split('\n');

childLines.pop();
if (childLines.length > 1) {
childLines[0] = text + childLines[0]; // (2)
text = "";
childLines.pop();
} else {
text += childLines[0]; // (1)
continue;
}

for (var j = 0; j < childLines.length; j += 1) {
offsets.push(i - lines.length);
lines.push(childLines[j]);
}
}

offsets.push(offsets[offsets.length-1]);

Syntax.log(offsets, lines, children);

return {lines: lines, offsets: offsets};
}

Expand Down Expand Up @@ -108,7 +117,7 @@ Syntax.Editor.prototype.textForLines = function(start, end) {
}

Syntax.Editor.prototype.updateLines = function(changed, newLines) {
console.log("updateLines", changed.start, changed.originalEnd, "->", changed.start, changed.end, changed);
Syntax.log("updateLines", changed.start, changed.originalEnd, "->", changed.start, changed.end, changed);

// We have two cases to handle, either we are replacing lines
// (1a) Replacing old lines with one more more new lines (update)
Expand All @@ -117,29 +126,29 @@ Syntax.Editor.prototype.updateLines = function(changed, newLines) {
// (2a) We are inserting lines at the start of the element
// (2b) We are inserting lines after an existing element.

if (changed.start != changed.originalEnd) {
if (changed.start != changed.end) {
// When text is deleted, at most two elements can remain:
// (1) Whatever was partially remaining on the first line.
// (2) Whatever was partially remaining on the last line.
// All other lines have already been removed by the container.
// changed.difference tells us how many elements have already been removed.

// Cases (1a) and (1b)
var start = changed.start, end = changed.originalEnd;
var start = changed.start, end = changed.end;

if (changed.difference < 0)
end += changed.difference;
//if (changed.difference < 0)
//end += changed.difference;

console.log("original", start, end);
Syntax.log("original", start, end);

start += this.current.offsets[start];
//end += this.current.offsets[end];
end += this.current.offsets[end];

console.log("slice", start, end)
Syntax.log("slice", start, end)

var oldLines = Array.prototype.slice.call(this.container.children, start, end);

console.log("Replacing old lines", oldLines, "with", newLines);
Syntax.log("Replacing old lines", oldLines, "with", newLines);

$(oldLines).replaceWith(newLines);
} else {
Expand All @@ -155,31 +164,23 @@ Syntax.Editor.prototype.updateLines = function(changed, newLines) {
}
}

// http://jsfiddle.net/timdown/2YcaX/3/
Syntax.Editor.getCharacterOffset = function(range, node) {
// Are \n being considered?
var treeWalker = document.createTreeWalker(
node,
NodeFilter.SHOW_TEXT,
function(node) {
var nodeRange = document.createRange();
nodeRange.selectNode(node);
return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
},
false
);

var charCount = 0;
while (treeWalker.nextNode()) {
charCount += treeWalker.currentNode.length;
}

if (range.startContainer.nodeType == 3) {
charCount += range.startOffset;
// http://jsfiddle.net/TjXEG/1/
Syntax.Editor.getCharacterOffset = function(element) {
var caretOffset = 0;
if (typeof window.getSelection != "undefined") {
var range = window.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
} else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
var textRange = document.selection.createRange();
var preCaretTextRange = document.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}

return charCount;
return caretOffset;
};

Syntax.Editor.getNodesForCharacterOffsets = function(offsets, node) {
Expand Down Expand Up @@ -217,7 +218,7 @@ Syntax.Editor.prototype.getClientState = function() {
state.range = selection.getRangeAt(0);

if (state.range) {
state.startOffset = Syntax.Editor.getCharacterOffset(state.range, this.container);
state.startOffset = Syntax.Editor.getCharacterOffset(this.container);
}

return state;
Expand All @@ -240,14 +241,7 @@ Syntax.Editor.prototype.setClientState = function(state) {
Syntax.layouts.editor = function(options, code/*, container*/) {
var container = jQuery('<div class="editor syntax highlighted" contentEditable="true">');

// Setup the initial html for the layout
code.children().each(function() {
var line = document.createElement('div');
line.className = "source " + this.className;

line.appendChild(this);
container.append(line);
});
container.append(code.children());

var editor = new Syntax.Editor(container.get(0));

Expand All @@ -256,29 +250,17 @@ Syntax.layouts.editor = function(options, code/*, container*/) {
var clientState = editor.getClientState();
var changed = editor.updateChangedLines();



var text = editor.textForLines(changed.start, changed.end);
console.log("textForLines", changed.start, changed.end, text);
//console.log("Updating lines from", changed.start, "to", changed.end, "original end", changed.originalEnd);
//console.log("Children length", editor.container.children.length, editor.lines.length);
Syntax.log("textForLines", changed.start, changed.end, text);
//Syntax.log("Updating lines from", changed.start, "to", changed.end, "original end", changed.originalEnd);
//Syntax.log("Children length", editor.container.children.length, editor.lines.length);

if (changed.start == changed.end) {
editor.updateLines(changed, []);
} else {
// Lines have been added, update the highlighting.
Syntax.highlightText(text, options, function(html) {
var newLines = [];

html.children().each(function() {
var line = document.createElement('div');
line.className = "source " + this.className;

line.appendChild(this);
newLines.push(line);
});

editor.updateLines(changed, newLines);
editor.updateLines(changed, html.children().get());

// Restore cusor position/selection if possible
editor.setClientState(clientState);
Expand All @@ -298,12 +280,12 @@ Syntax.layouts.editor = function(options, code/*, container*/) {
container.bind('keydown', function(event){
if (event.keyCode == 9) {
event.preventDefault();
document.execCommand('insertHTML', true, " ");
document.execCommand('insertHTML', false, " ");
}
else if (event.keyCode == 13) {
event.preventDefault();
document.execCommand('insertHTML', false, "\n");
}
// else if (event.keyCode == 13) {
// event.preventDefault();
// document.execCommand('insertHTML', true, "\n");
//}
});

ED = editor;
Expand Down
4 changes: 2 additions & 2 deletions themes/modern/jquery.syntax.layout.editor.sass
Expand Up @@ -5,5 +5,5 @@
.syntax-container.syntax-theme-modern
div.editor.syntax
-webkit-box-shadow: inset 0px 2px 3px #969696
div.editor.syntax > div
border: 1px solid #ccf
div.editor.syntax > span
border: 1px solid #eef

0 comments on commit 6c3ce20

Please sign in to comment.