@@ -0,0 +1,79 @@
// ctrl - shift - J on Tabs Outliner to open dev tools,
// then Sources -> Snippets -> New Snippet.
// Rightclick -> Run to execute.
// cyrb53 stolen from https://stackoverflow.com/a/52171480
const cyrb53 = function ( str , seed = 0 ) {
let h1 = 0xdeadbeef ^ seed , h2 = 0x41c6ce57 ^ seed ;
for ( let i = 0 , ch ; i < str . length ; i ++ ) {
ch = str . charCodeAt ( i ) ;
h1 = Math . imul ( h1 ^ ch , 2654435761 ) ;
h2 = Math . imul ( h2 ^ ch , 1597334677 ) ;
}
h1 = Math . imul ( h1 ^ ( h1 >>> 16 ) , 2246822507 ) ^ Math . imul ( h2 ^ ( h2 >>> 13 ) , 3266489909 ) ;
h2 = Math . imul ( h2 ^ ( h2 >>> 16 ) , 2246822507 ) ^ Math . imul ( h1 ^ ( h1 >>> 13 ) , 3266489909 ) ;
return 4294967296 * ( 2097151 & h2 ) + ( h1 >>> 0 ) ;
} ;
function nodeterate ( currentNode , stringBuilder ) {
if ( currentNode . type == "separatorline" ) stringBuilder . push ( "separatorline" ) ;
else if ( currentNode . type == "textnote" ) stringBuilder . push ( `textnote ${ currentNode ?. persistentData ?. note } ` ) ;
else if ( currentNode . type == "win" || currentNode . type == "savedwin" ) stringBuilder . push ( "window" ) ;
else stringBuilder . push ( currentNode . getHref ( ) ) ;
for ( const sn of currentNode . subnodes ) {
nodeterate ( sn , stringBuilder ) ;
}
}
function nukeNodeArray ( nodeArray ) {
const DUMMY = false ;
for ( const currentNode of nodeArray ) {
if ( currentNode . type !== "win" && currentNode . type !== "savedwin" ) {
console . log ( "this node should not have almost died:" ) ;
console . log ( currentNode ) ;
continue ;
}
if ( DUMMY ) {
console . log ( "would now kill:" ) ;
console . log ( currentNode ) ;
} else {
console . log ( "removing node:" ) ;
console . log ( currentNode ) ;
currentNode . removeOwnTreeFromParent ( ) ;
}
}
}
function killDupes ( killActive = false ) {
let dupes = { } ;
for ( const nod of treeView . treeModel . currentSession_rootNode . subnodes ) { // only check root level nodes, don't do complex recursive checks for "sub-roots"
const strbld = [ ] ;
nodeterate ( nod , strbld ) ;
const hash = cyrb53 ( strbld . join ( ) ) ;
if ( dupes . hasOwnProperty ( hash ) ) dupes [ hash ] . push ( nod ) ;
else dupes [ hash ] = [ nod ] ;
}
for ( const duperino of Object . values ( dupes ) ) {
if ( duperino . length < 2 ) continue ;
const inactiveNodes = duperino . filter ( x => x . type !== "win" ) ; // keep loaded window(s) alive
if ( inactiveNodes . length < duperino . length ) {
if ( ( duperino . length - inactiveNodes . length ) > 1 ) {
console . log ( "WARNING: duplicate active windows ->" ) ;
for ( const loadedWindow of duperino . filter ( x => x . type == "win" ) ) console . log ( loadedWindow ) ;
}
nukeNodeArray ( inactiveNodes ) ;
if ( killActive ) nukeNodeArray ( duperino . filter ( x => x . type == "win" ) . slice ( 1 ) ) ;
}
else { // keep oldest
nukeNodeArray ( duperino . slice ( 1 ) ) ;
}
}
}
killDupes ( ) ;
// to also prune duplicate *loaded* windows down to a single one, try: killDupes(true);
// note that this will disregard how many subnodes are loaded!