Created
July 30, 2018 02:26
-
-
Save anonyco/e947f259912c0849e077bdb78cd2e38e to your computer and use it in GitHub Desktop.
A Destroy Method On All CodeMirror Objects To Ensure Garbage Collection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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