Skip to content

Commit 6c3ce20

Browse files
committed
Minor improvement to editor. Now working fairly reliably in WebKit.
1 parent 9aaf9ab commit 6c3ce20

File tree

3 files changed

+57
-81
lines changed

3 files changed

+57
-81
lines changed

examples/ex.editor.html

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,10 @@ <h1>Syntax Editor</h1>
1919

2020
<h2>Ruby Editor</h2>
2121

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

26-
require &#x27;yaml&#x27;
27-
28-
require &#x27;utopia/extensions/date&#x27;
29-
require &#x27;utopia/extensions/string&#x27;
30-
require &#x27;utopia/extensions/hash&#x27;
31-
require &#x27;utopia/extensions/array&#x27;
25+
}
3226
</pre>
3327
</body>
3428
</html>

source/jquery.syntax.layout.editor.js

Lines changed: 52 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,32 @@ Syntax.Editor = function(container, text) {
1212
Syntax.Editor.prototype.getLines = function() {
1313
var children = this.container.children, lines = [], offsets = [];
1414

15-
for (var j = 0; j < children.length; j += 1) {
16-
if (children[j].nodeType == 3) {
17-
$(children[j]).remove();
18-
}
19-
}
20-
15+
// Sometimes, e.g. when deleting text, children elements are not complete lines.
16+
// We need to accumulate incomplete lines (1), and then append them to the
17+
// start of the next complete line (2)
18+
var text = "";
2119
for (var i = 0; i < children.length; i += 1) {
2220
var childLines = Syntax.getCDATA([children[i]]).split('\n');
2321

24-
childLines.pop();
22+
if (childLines.length > 1) {
23+
childLines[0] = text + childLines[0]; // (2)
24+
text = "";
25+
childLines.pop();
26+
} else {
27+
text += childLines[0]; // (1)
28+
continue;
29+
}
2530

2631
for (var j = 0; j < childLines.length; j += 1) {
2732
offsets.push(i - lines.length);
2833
lines.push(childLines[j]);
2934
}
3035
}
3136

37+
offsets.push(offsets[offsets.length-1]);
38+
39+
Syntax.log(offsets, lines, children);
40+
3241
return {lines: lines, offsets: offsets};
3342
}
3443

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

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

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

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

127136
// Cases (1a) and (1b)
128-
var start = changed.start, end = changed.originalEnd;
137+
var start = changed.start, end = changed.end;
129138

130-
if (changed.difference < 0)
131-
end += changed.difference;
139+
//if (changed.difference < 0)
140+
//end += changed.difference;
132141

133-
console.log("original", start, end);
142+
Syntax.log("original", start, end);
134143

135144
start += this.current.offsets[start];
136-
//end += this.current.offsets[end];
145+
end += this.current.offsets[end];
137146

138-
console.log("slice", start, end)
147+
Syntax.log("slice", start, end)
139148

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

142-
console.log("Replacing old lines", oldLines, "with", newLines);
151+
Syntax.log("Replacing old lines", oldLines, "with", newLines);
143152

144153
$(oldLines).replaceWith(newLines);
145154
} else {
@@ -155,31 +164,23 @@ Syntax.Editor.prototype.updateLines = function(changed, newLines) {
155164
}
156165
}
157166

158-
// http://jsfiddle.net/timdown/2YcaX/3/
159-
Syntax.Editor.getCharacterOffset = function(range, node) {
160-
// Are \n being considered?
161-
var treeWalker = document.createTreeWalker(
162-
node,
163-
NodeFilter.SHOW_TEXT,
164-
function(node) {
165-
var nodeRange = document.createRange();
166-
nodeRange.selectNode(node);
167-
return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
168-
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
169-
},
170-
false
171-
);
172-
173-
var charCount = 0;
174-
while (treeWalker.nextNode()) {
175-
charCount += treeWalker.currentNode.length;
176-
}
177-
178-
if (range.startContainer.nodeType == 3) {
179-
charCount += range.startOffset;
167+
// http://jsfiddle.net/TjXEG/1/
168+
Syntax.Editor.getCharacterOffset = function(element) {
169+
var caretOffset = 0;
170+
if (typeof window.getSelection != "undefined") {
171+
var range = window.getSelection().getRangeAt(0);
172+
var preCaretRange = range.cloneRange();
173+
preCaretRange.selectNodeContents(element);
174+
preCaretRange.setEnd(range.endContainer, range.endOffset);
175+
caretOffset = preCaretRange.toString().length;
176+
} else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
177+
var textRange = document.selection.createRange();
178+
var preCaretTextRange = document.body.createTextRange();
179+
preCaretTextRange.moveToElementText(element);
180+
preCaretTextRange.setEndPoint("EndToEnd", textRange);
181+
caretOffset = preCaretTextRange.text.length;
180182
}
181-
182-
return charCount;
183+
return caretOffset;
183184
};
184185

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

219220
if (state.range) {
220-
state.startOffset = Syntax.Editor.getCharacterOffset(state.range, this.container);
221+
state.startOffset = Syntax.Editor.getCharacterOffset(this.container);
221222
}
222223

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

243-
// Setup the initial html for the layout
244-
code.children().each(function() {
245-
var line = document.createElement('div');
246-
line.className = "source " + this.className;
247-
248-
line.appendChild(this);
249-
container.append(line);
250-
});
244+
container.append(code.children());
251245

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

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

259-
260-
261253
var text = editor.textForLines(changed.start, changed.end);
262-
console.log("textForLines", changed.start, changed.end, text);
263-
//console.log("Updating lines from", changed.start, "to", changed.end, "original end", changed.originalEnd);
264-
//console.log("Children length", editor.container.children.length, editor.lines.length);
254+
Syntax.log("textForLines", changed.start, changed.end, text);
255+
//Syntax.log("Updating lines from", changed.start, "to", changed.end, "original end", changed.originalEnd);
256+
//Syntax.log("Children length", editor.container.children.length, editor.lines.length);
265257

266258
if (changed.start == changed.end) {
267259
editor.updateLines(changed, []);
268260
} else {
269261
// Lines have been added, update the highlighting.
270262
Syntax.highlightText(text, options, function(html) {
271-
var newLines = [];
272-
273-
html.children().each(function() {
274-
var line = document.createElement('div');
275-
line.className = "source " + this.className;
276-
277-
line.appendChild(this);
278-
newLines.push(line);
279-
});
280-
281-
editor.updateLines(changed, newLines);
263+
editor.updateLines(changed, html.children().get());
282264

283265
// Restore cusor position/selection if possible
284266
editor.setClientState(clientState);
@@ -298,12 +280,12 @@ Syntax.layouts.editor = function(options, code/*, container*/) {
298280
container.bind('keydown', function(event){
299281
if (event.keyCode == 9) {
300282
event.preventDefault();
301-
document.execCommand('insertHTML', true, " ");
283+
document.execCommand('insertHTML', false, " ");
284+
}
285+
else if (event.keyCode == 13) {
286+
event.preventDefault();
287+
document.execCommand('insertHTML', false, "\n");
302288
}
303-
// else if (event.keyCode == 13) {
304-
// event.preventDefault();
305-
// document.execCommand('insertHTML', true, "\n");
306-
//}
307289
});
308290

309291
ED = editor;

themes/modern/jquery.syntax.layout.editor.sass

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
.syntax-container.syntax-theme-modern
66
div.editor.syntax
77
-webkit-box-shadow: inset 0px 2px 3px #969696
8-
div.editor.syntax > div
9-
border: 1px solid #ccf
8+
div.editor.syntax > span
9+
border: 1px solid #eef

0 commit comments

Comments
 (0)