(function() {
function isChildOf(el, parent) {
do {
el = el.parentNode;
} while (el !== null && el !== parent && el !== document.body);
return (el === parent);
}
var readOnlyCodeMirror = CodeMirror.fromTextArea(document.getElementById('codesnippet_readonly'), {
mode: "javascript",
theme: "default",
lineNumbers: true,
readOnly: true
});
var editableCodeMirror = CodeMirror.fromTextArea(document.getElementById('codesnippet_editable'), {
mode: "javascript",
theme: "default",
lineNumbers: true
});
var activeEditor = null,
newActiveEditor = null;
for (let cm of document.querySelectorAll('.CodeMirror')) {
let overlay = document.createElement('div');
overlay.classList.add('cm__overlay');
cm.insertBefore(overlay, cm.firstChild);
overlay.addEventListener('click', function(event) {
overlay.classList.add('cm__overlay--hidden');
if (activeEditor === null) {
activeEditor = cm;
} else {
newActiveEditor = cm;
}
});
}
document.body.addEventListener('click', function(event) {
if (activeEditor !== null && !isChildOf(event.target, activeEditor)) {
activeEditor.firstChild.classList.remove('cm__overlay--hidden');
activeEditor = null;
if (newActiveEditor !== null) {
activeEditor = newActiveEditor;
newActiveEditor = null;
}
}
});
}());
.cm__overlay {
position: absolute;
z-index: 10;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.cm__overlay--hidden {
pointer-events: none;
border: 1px solid red;
}
<h1>Using CodeMirror (readonly and editable code)</h1>
<p><a href="http://codemirror.net/mode/javascript/index.html">http://codemirror.net/mode/javascript/index.html</a></p>
<link rel="stylesheet" href="http://codemirror.net/lib/codemirror.css">
<script src="http://codemirror.net/lib/codemirror.js"></script>
<script src="http://codemirror.net/addon/edit/matchbrackets.js"></script>
<script src="http://codemirror.net/mode/javascript/javascript.js"></script>
<h2>Readonly</h2>
<div>
<textarea rows="4" cols="50" id="codesnippet_readonly" name="codesnippet_readonly">
// Demo code (the actual new parser character stream implementation)
function StringStream(string) {
this.pos = 0;
this.string = string;
}
StringStream.prototype = {
done: function() {return this.pos >= this.string.length;},
peek: function() {return this.string.charAt(this.pos);},
next: function() {
if (this.pos < this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch && match.test ? match.test(ch) : match(ch);
if (ok) {this.pos++; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match));
if (this.pos > start) return this.string.slice(start, this.pos);
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.pos;},
eatSpace: function() {
var start = this.pos;
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
return this.pos - start;
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += str.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match && consume !== false) this.pos += match[0].length;
return match;
}
}
};
</textarea>
</div>
<div>
<h2>Editable</h2>
<textarea rows="4" cols="50" name="codesnippet_editable" id="codesnippet_editable">
// Demo code (the actual new parser character stream implementation)
function StringStream(string) {
this.pos = 0;
this.string = string;
}
StringStream.prototype = {
done: function() {return this.pos >= this.string.length;},
peek: function() {return this.string.charAt(this.pos);},
next: function() {
if (this.pos < this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch && match.test ? match.test(ch) : match(ch);
if (ok) {this.pos++; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match));
if (this.pos > start) return this.string.slice(start, this.pos);
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.pos;},
eatSpace: function() {
var start = this.pos;
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
return this.pos - start;
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += str.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match && consume !== false) this.pos += match[0].length;
return match;
}
}
};
</textarea>
</div>