-
-
Save pilate/4eeaa5766ace769a71dc5e7486e726fa to your computer and use it in GitHub Desktop.
Recursively searches the entire object tree for a given value
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
/** | |
* Recursively searches the startObject for the given value. | |
* | |
* All matches are displayed in the browser console and stored in the global variable "gsResults" | |
* The function tries to simplify DOM element names by using their ID, when possible. | |
* | |
* Usage samples: | |
* | |
* globalSearch( document, 'someValue' ); // Search entire DOM document for the string value. | |
* globalSearch( document, '^start' ); // Simple regex search (function recognizes prefix/suffix patterns: "^..." or "...$"). | |
* globalSearch( document, new Regex('[a|b]') ); // Advanced Regex search. | |
* globalSearch( 'myObj', 'value', 'key' ); // Searches all keys with the name "value" inside the object window.myObj | |
* globalSearch( window, 'value', 'key', 3 ); // Ends the search after 3 results were found. | |
* globalSearch( window, 'value', 'all', 3 ); // Finds the first three occurances of "value" in either a object key or value. | |
* | |
* globalSearch( document, 'some_value', 'key', 20 ) | |
* Output: | |
* | |
* 1. Match: KEY | |
* Value: [string] on | |
* Address: window.gsResults[1] | |
* document.getElementById("the-id").childNodes[1].__reactInternalInstance$v9o4el5z24e.alternate..memoizedProps._owner.alternate.memoizedState.attrs.some_value | |
* | |
* @param {string|object} startObject The object to search. Either an object, or the global object name as string. | |
* @param {mixed} value The value to find. Can be any type, or a Regex string. | |
* @param {string} searchField Either of [value|key|all]. | |
* @param {int} limit Max results to return. Default is -1, which means "unlimited". | |
*/ | |
function globalSearch(startObject, value, searchField = 'value', limit = -1) { | |
var startName = ''; | |
if ('string' === typeof startObject) { | |
startName = startObject; | |
startObject = eval(startObject); | |
} else if (window === startObject) { | |
startName = 'window'; | |
} else if (document === startObject) { | |
startName = 'document'; | |
} | |
var stack = [[startObject, startName, startName]]; | |
var searched = []; | |
var found = 0; | |
var count = 1; | |
var isRegex = 'string' === typeof value && (-1 !== value.indexOf('*') || '^' === value[0] || '$' === value[value.length-1]); | |
window.gsResults = []; | |
if (isRegex) { | |
value = new RegExp(value); | |
} else if ('object' === typeof value && value instanceof RegExp) { | |
isRegex = true; | |
} | |
if (!searchField) { | |
searchField = 'value'; | |
} | |
if (-1 === ['value', 'key', 'all'].indexOf(searchField)) { | |
console.error('The "searchField" parameter must be either of [value|key|all]. Found:', searchField); | |
return; | |
} | |
function isArray(test) { | |
var type = Object.prototype.toString.call(test); | |
return '[object Array]' === type || '[object NodeList]' === type; | |
} | |
function isElement(o){ | |
try { | |
return ( | |
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2 | |
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string" | |
); | |
} catch (e) { | |
return false; | |
} | |
} | |
function isMatch(item) { | |
if (isRegex) { | |
return value.test(item); | |
} else { | |
return item === value; | |
} | |
} | |
function result(type, address, shortAddr, value) { | |
var msg = []; | |
found++; | |
window.gsResults[found] = { | |
match: type, | |
value: value, | |
pathOrig: address, | |
pathShort: shortAddr | |
}; | |
msg.push(found + ". Match: \t" + type.toUpperCase()), | |
msg.push(" Value: \t[" + (typeof value ) + '] ' + value); | |
msg.push(" Address: \twindow.gsResults[" + found + ']'); | |
msg.push('%c' + shortAddr); | |
console.log(msg.join("\n"), 'background:Highlight;color:HighlightText;margin-left:12px'); | |
} | |
function skip(obj, key) { | |
var traversing = [ | |
'firstChild', | |
'previousSibling', | |
'nextSibling', | |
'lastChild', | |
'previousElementSibling', | |
'nextElementSibling', | |
'firstEffect', | |
'nextEffect', | |
'lastEffect' | |
]; | |
var scopeChange = [ | |
'ownerDocument', | |
]; | |
var deprecatedDOM = [ | |
'webkitStorageInfo', | |
]; | |
if (-1 !== traversing.indexOf(key)) { return true; } | |
if (-1 !== scopeChange.indexOf(key)) { return true; } | |
if (-1 !== deprecatedDOM.indexOf(key)) { return true; } | |
var isInvalid = false; | |
try { | |
obj[key] | |
} catch(ex) { | |
isInvalid = true; | |
} | |
return isInvalid; | |
} | |
while (stack.length) { | |
if (limit > 0 && found >= limit) { break; } | |
var fromStack = stack.pop(); | |
var obj = fromStack[0]; | |
var address = fromStack[1]; | |
var display = fromStack[2]; | |
if ('key' !== searchField && isMatch(obj)) { | |
result( 'value', address, display, obj); | |
if (limit > 0 && found >= limit) { break; } | |
} | |
if (obj && typeof obj == 'object' && -1 === searched.indexOf(obj)) { | |
var objIsArray = isArray(obj); | |
if ( isElement(obj) && obj.id ) { | |
display = 'document.getElementById("' + obj.id + '")'; | |
} | |
for (i in obj) { | |
if (skip(obj, i)) { continue; } | |
var subAddr = (objIsArray || 'number' === typeof i) ? '[' + i + ']' : '.' + i; | |
var addr = address + subAddr; | |
var displayAddr = display + subAddr; | |
stack.push([obj[i], addr, displayAddr]); | |
count++; | |
if ('value' !== searchField && isMatch(i)) { | |
result( 'key', address, displayAddr, obj[i]); | |
if (limit > 0 && found >= limit) { break; } | |
} | |
} | |
searched.push(obj); | |
} | |
} | |
searched = null; | |
console.log('-----'); | |
console.log('All Done!'); | |
console.log('Searched', count.toLocaleString(), 'items'); | |
console.log('Found', found.toLocaleString(), 'results'); | |
return found; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment