Skip to content

Instantly share code, notes, and snippets.

@anonyco
Created July 30, 2018 02:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonyco/e947f259912c0849e077bdb78cd2e38e to your computer and use it in GitHub Desktop.
Save anonyco/e947f259912c0849e077bdb78cd2e38e to your computer and use it in GitHub Desktop.
A Destroy Method On All CodeMirror Objects To Ensure Garbage Collection
if (!CodeMirror.prototype.destroy) (function(){
// A destroy extension. Absolutely positively beyond a shadow of a doubt obliterate a CodeMirror instance from memory.
function hasExclusion(stringArr, regexpArr){
return function(exclusion){
var iSA = stringArr.length, cur = null, iEL = 0, iC = 0, iRA = regexpArr.length;
if (isRegExp(exclusion)){
while (iRA--)
if (regexpArr[iRA].source === exclusion.source && regexpArr[iRA].flags === exclusion.flags)
return iRA;
} else {
iEL = exclusion.length;
a: while (iSA--) {
cur = stringArr[iSA], iC = cur.length;
if (iEL !== iC) continue a; // they must be the same length
while (iC--) if (cur[iC] !== exclusion[iC]) continue a; // they must contain same strings
return iSA;
}
}
return -1;
}
}
function addExclude(has, stringArr, regexpArr){
return function(exclusion){
if (has(exclusion) !== -1) return false;
if (isRegExp(exclusion)) {
regexpArr.push(exclusion);
} else {
if (typeof exclusion !== "object") exclusion = (""+exclusion).split(".");
stringArr.push(exclusion);
}
return true;
};
}
function removeExclude(has, stringArr, regexpArr){
return function(exclusion){
var index = has(exclusion);
if (index !== -1) {
if (isRegExp(exclusion)) {
regexpArr.splice(index, 1);
} else {
stringArr.splice(index, 1);
}
return true;
} else {
return false;
}
};
}
function listExclusions(stringArr, regexpArr) {
return stringArr.concat.bind(stringArr, regexpArr);
}
var signal = CodeMirror["signal"], Doc = CodeMirror["Doc"];
var destructionObj = CodeMirror["destruction"] = {};
var isNode = isPrototypeOf.bind(window.Node.prototype);
function copyAll(){
}
function destroy(obj, acc, level, stringExclusions, regexpExclusions){
var isArray = Object_toString.call(obj) === "[object Array]";
var regexpLen = regexpExclusions.length, iRE = 0;;
var newAcc = "", newStringExs = null, found = false, cur = null
if (isArray) {
a: for (var k=obj.length; k--; ) {
if (!obj.hasOwnProperty(k)) continue;
cur = obj[k];
try { delete obj[k]; } catch(e){}
if (typeof cur === "object" && cur !== null && !isRegExp(cur)) {
newAcc = acc + '["' + k + '"]';
iRE = regexpLen;
while (iRE--)
if (regexpExclusions[iRE].test(newAcc))
continue a;
newStringExs = stringExclusions.filter(function(cur){
if (cur[level] === k) {
if ((cur.length-1) === level) found = true; else return true;
}
});
if (!found) {
if (isNode(cur)) { cur.innerHTML = ""; cur.remove ? cur.remove() : cur.parentNode && cur.parentNode.removeChild(k); }
destroy(cur, newAcc, level + 1, newStringExs, regexpExclusions);
}
found = false;
}
}
obj.length = 0;
}
var allOwnProperties = getOwnPropertyNames(obj);
var i = allOwnProperties.length, k="";
var cmInst = obj["cm"];
b: while (i--) {
k = allOwnProperties[i];
cur = obj[k];
if (k !== "length" || !isArray) {
try {
// try/catch is much much faster than checking the property decriptor
delete obj[k];
} catch(e){}
}
if (typeof cur === "object" && cur !== null && !isRegExp(cur)) {
newAcc = acc + "[" + JSON_stringify(k) + "]";
iRE = regexpLen;
while (iRE--)
if (regexpExclusions[iRE].test(newAcc))
continue b;
newStringExs = stringExclusions.filter(function(cur){
if (cur[level] === k) {
if ((cur.length-1) === level) found = true; else return true;
}
});
if (!found) {
if (isNode(cur)) { cur.innerHTML = ""; cur.remove ? cur.remove() : cur.parentNode && cur.parentNode.removeChild(k); }
destroy(cur, newAcc, level + 1, newStringExs, regexpExclusions);
}
found = false;
}
}
}
function addDestructor(stringArr, regexpArr, name, handle, constructor){
constructor = constructor || CodeMirror[name];
constructor["prototype"]["destroy"] = function(){
signal(this, "destroy");
if (typeof handle === "function") handle.apply(this, arguments);
destroy(this, name, 0, stringArr, regexpArr)
};
var has = hasExclusion(stringArr, regexpArr);
destructionObj["has" + name + "Exclusion"] = function(exclusion){
return has(exclusion) !== -1;
};
destructionObj["add" + name + "Exclusion"] = addExclude(has, stringArr, regexpArr);
destructionObj["remove" + name + "Exclusion"] = removeExclude(has, stringArr, regexpArr);
destructionObj["list" + name + "Exclusion"] = listExclusions(stringArr, regexpArr);
}
destructionObj["createDestructor"] = addDestructor;
addDestructor([], [], "Editor", function(noDestroyDoc, noDestroyLinkedDocs){
this["doc"]["cm"] = null;
if(!noDestroyDoc){ this["doc"]["destroy"]( noDestroyLinkedDocs ); }
else { this["doc"] = null; }
}, CodeMirror);
destructionObj["addEditorExclusion"]("doc");
addDestructor([], [], "Doc", function(noDestroyLinkedDocs){
try {
if (this["cm"]) this["cm"]["swapDoc"]( new Doc("", "null", 0, "\n") );
} catch(e) {}
if (!noDestroyLinkedDocs) this["iterLinkedDocs"](function(doc){ doc["destroy"](true); });
this["setValue"]("");
});
destructionObj["addDocExclusion"]("cm");
destructionObj["addDocExclusion"]("linked");
addDestructor([], [], "Line", function(thenFunc){
return function(){
if (this["parent"] !== null) {
// the line is still attatched, so detatch it
var doc = this["parent"];
while (doc["parent"]) doc = doc["parent"];
if (Doc["prototype"]["isPrototypeOf"](doc)) {
var lineNumber = this["lineNo"]();
if (lineNumber === doc["lastLine"]()) {
if (lineNumber === doc["firstLine"]()) {
doc["setValue"]("");
} else {
doc["replaceRange"]("", {
"line": lineNumber - 1,
"ch": doc["getLine"](lineNumber-1)["length"]
}, {
"line": lineNumber,
"ch": this["text"]["length"]
});
}
} else {
doc["replaceRange"]("", {
"line": lineNumber,
"ch": 0
}, {
"line": lineNumber + 1,
"ch": 0
});
}
}
}
};
});
destructionObj["addLineExclusion"]("parent");
addDestructor([], [], "TextMarker");
destructionObj["addTextMarkerExclusion"]("doc");
destructionObj["addTextMarkerExclusion"]("lines");
addDestructor([], [], "LineWidget");
destructionObj["addLineWidgetExclusion"]("doc");
destructionObj["addLineWidgetExclusion"]("line");
addDestructor([], [], "LineWidget");
destructionObj["addLineWidgetExclusion"]("doc");
destructionObj["addLineWidgetExclusion"]("line");
addDestructor([], [], "StringStream");
destructionObj["addStringStreamExclusion"]("lineOracle.doc");
//addDestructor();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment