Last active
January 25, 2016 13:52
-
-
Save d-akara/19efeb0724406745b54a to your computer and use it in GitHub Desktop.
Chrome devtools script for debugging. Older browser version
This file contains hidden or 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
(function () { | |
"use strict"; | |
var moduleName = "debug"; | |
var symbolOriginal = Symbol('original-implementation'); | |
function interceptFunction(object, methodName, beforeFunction, conditionFunction) { | |
// Reset original method if it has been overridden | |
if (object[methodName][symbolOriginal]) { | |
object[methodName] = object[methodName][symbolOriginal]; | |
delete object[methodName][symbolOriginal]; | |
} | |
var originalMethod = object[methodName]; | |
if (beforeFunction) { | |
object[methodName] = function _debugIntercept() { | |
if (!conditionFunction || conditionFunction(methodName, arguments, this)) { | |
if (beforeFunction) { | |
beforeFunction(methodName, arguments, this); | |
} | |
var result = originalMethod.apply(this, arguments); | |
return result; | |
} else { | |
return originalMethod.apply(this, arguments); | |
} | |
}; | |
// store original method | |
object[methodName][symbolOriginal] = originalMethod; | |
} | |
} | |
function interceptProperty(object, propertyName, getFunction, setFunction, conditionFunction) { | |
var originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, propertyName); | |
var newPropertyDescriptor = originalPropertyDescriptor ? Object.create(originalPropertyDescriptor) : {} ; | |
newPropertyDescriptor.configurable = true; | |
function shouldIntercept(object) { | |
if (!conditionFunction || conditionFunction(propertyName, arguments, object)) { | |
return true; | |
} | |
return false; | |
} | |
if (getFunction) { | |
var conditionalGetFunction = function conditionalGetFunction() { | |
if (shouldIntercept(this)) { | |
var value = getOriginal.apply(this, arguments); | |
getFunction(propertyName, arguments, this); | |
return value; | |
} else return getOriginal.apply(this, arguments); | |
}; | |
newPropertyDescriptor.get = conditionalGetFunction; | |
} | |
if (setFunction) { | |
var conditionalSetFunction = function conditionalSetFunction(value) { | |
if (shouldIntercept(this)) { | |
setFunction(propertyName, arguments, this); | |
return setOriginal.call(this, value); | |
} else setOriginal.call(this, value); | |
}; | |
newPropertyDescriptor.set = conditionalSetFunction; | |
} | |
function getOriginal() { | |
Object.defineProperty(object, propertyName, originalPropertyDescriptor); | |
var value = this[propertyName]; | |
Object.defineProperty(object, propertyName, newPropertyDescriptor); | |
return value; | |
} | |
function setOriginal(value) { | |
try { | |
Object.defineProperty(object, propertyName, originalPropertyDescriptor); | |
this[propertyName] = value; | |
Object.defineProperty(object, propertyName, newPropertyDescriptor); | |
} catch (e) { | |
console.log(e); | |
Object.defineProperty(object, propertyName, newPropertyDescriptor); | |
} | |
} | |
Object.defineProperty(object, propertyName, newPropertyDescriptor); | |
} | |
var recursionCount = 0; | |
function logElement(targetElement, parentElement, methodName) { | |
if ( recursionCount > 0 ) return; | |
recursionCount++; | |
console.groupCollapsed(moduleName + ": " + methodName, targetElement); | |
if (parentElement) console.log("parent: ", parentElement); | |
console.trace(); | |
console.groupEnd(); | |
recursionCount--; | |
} | |
function testContainsAttribute() {} | |
var inspectElementsConfig = { | |
appendChild: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
insertBefore: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
replaceChild: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
removeChild: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
appendData: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
deleteData: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
insertData: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
replaceData: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
substringData: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
innerHTML: { prototype: Element.prototype, fnInspectWhen: testContainsAttribute }, | |
outerHTML: { prototype: Element.prototype, fnInspectWhen: testContainsAttribute }, | |
textContent: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
innerText: {prototype: HTMLElement.prototype, fnInspectWhen: testContainsAttribute}, | |
outerText: {prototype: HTMLElement.prototype, fnInspectWhen: testContainsAttribute}, | |
data: { prototype: CharacterData.prototype, fnInspectWhen: testContainsAttribute }, | |
nodeValue: { prototype: Node.prototype, fnInspectWhen: testContainsAttribute }, | |
checked: { prototype: HTMLInputElement.prototype, fnInspectWhen: testContainsAttribute } | |
}; | |
var inspectElements_Settings = { | |
inspectWhen: { | |
attributeName: null, | |
attributeValue: null | |
}, | |
inspectOn: { | |
elementModifiers: { | |
appendChild: false, | |
insertBefore: false, | |
replaceChild: false, | |
removeChild: false | |
}, | |
textModifiers: { | |
appendData: true, | |
deleteData: false, | |
insertData: true, | |
replaceData: true, | |
substringData: false | |
}, | |
magicProperties: { | |
innerHTML: true, | |
outerHTML: true, | |
textContent: true, | |
innerText: true, | |
outerText: true, | |
data: true, | |
nodeValue: true, | |
checked: true | |
}, | |
inspect_insertAdjacentHTML: true, | |
inspect_selectOptions: true | |
}, | |
breakOnInspect: false | |
}; | |
function inspectElements() { | |
var settings = inspectElements_Settings; | |
var conditionFunction = function _debugTestContainsAttribute(inspectOnSettings, methodPropertyName, childElement, parentElement) { | |
if (!inspectOnSettings[methodPropertyName]) { | |
return false; | |
} | |
if (typeof childElement.getAttribute != 'function') return false; | |
var attributeName = settings.inspectWhen.attributeName; | |
var attributeValue = settings.inspectWhen.attributeValue; | |
var elementAttributeValue = childElement.getAttribute(attributeName); | |
if (!attributeName || elementAttributeValue && (!attributeValue || elementAttributeValue.indexOf(attributeValue) > -1)) { | |
return true; | |
} | |
return false; | |
}; | |
var conditionChildFunction = function _debugTestChildContainsAttribute(methodPropertyName, originalArguments, parentElement) { | |
return conditionFunction(inspectElements_Settings.inspectOn.elementModifiers, methodPropertyName, originalArguments[0], parentElement); | |
}; | |
var conditionParentFunction = function _debugTestParentContainsAttribute(methodPropertyName, originalArguments, parentElement) { | |
return conditionFunction(inspectElements_Settings.inspectOn.textModifiers, methodPropertyName, parentElement, parentElement); | |
}; | |
var conditionMagicPropertyFunction = function _debugTestParentContainsAttribute(methodPropertyName, originalArguments, parentElement) { | |
return conditionFunction(inspectElements_Settings.inspectOn.magicProperties, methodPropertyName, parentElement, parentElement); | |
}; | |
var beforeFunction = function _debugBeforeFunction(methodName, originalArguments, object) { | |
logElement(originalArguments[0], object, methodName); | |
if (settings.breakOnInspect) debugger; | |
}; | |
var setPropertyFunction = function _debugSetPropertyFunction(methodName, originalArguments, object) { | |
logElement(object, null, "set:" + methodName); | |
if (settings.breakOnInspect) debugger; | |
}; | |
for (var methodName in inspectElements_Settings.inspectOn.elementModifiers) { | |
interceptFunction(inspectElementsConfig[methodName].prototype, methodName, beforeFunction, conditionChildFunction); | |
} | |
for (var methodName in inspectElements_Settings.inspectOn.textModifiers) { | |
interceptFunction(inspectElementsConfig[methodName].prototype, methodName, beforeFunction, conditionParentFunction); | |
} | |
for (var propertyName in inspectElements_Settings.inspectOn.magicProperties) { | |
interceptProperty(inspectElementsConfig[propertyName].prototype, propertyName, null, setPropertyFunction, conditionMagicPropertyFunction); | |
} | |
console.log("inspecting elements active. modify returned properties object to configure."); | |
return settings; | |
} | |
function logEvent(event) { | |
console.log(event); | |
} | |
function testEvents(eventType, enable) { | |
if (eventType === undefined) { | |
console.log("EXAMPLE: testEvents('keydown', true)"); | |
return; | |
} | |
if (enable) { | |
document.addEventListener(eventType, logEvent, true); | |
console.log("logging all '" + eventType + "' events."); | |
} else { | |
document.removeEventListener(eventType, logEvent, true); | |
console.log("stoped logging all '" + eventType + "' events."); | |
} | |
} | |
function profileWaitForTrigger(startEventProperties, duration) { | |
if (startEventProperties === undefined) { | |
console.log("EXAMPLE: profileWaitForTrigger({type: 'click'}, 100)"); | |
return; | |
} | |
function armProfileTrigger() { | |
setEventTrigger(startEventProperties.type, function () { | |
return profile(duration); | |
}, function (event) { | |
return containsProperties(startEventProperties, event); | |
}, true); | |
console.log("profile trigger set. profiler will start when event matches:", startEventProperties); | |
} | |
setKeyTrigger({ | |
ctrlKey: true | |
}, armProfileTrigger); | |
console.log("profile trigger will be set when you press [ctrl]"); | |
} | |
function profile(duration) { | |
console.profile(moduleName + " " + new Date().toTimeString()); | |
if (duration) { | |
setTimeout(function () { | |
return console.profileEnd(); | |
}, duration); | |
} else { | |
setTimeout(function () { | |
return console.profileEnd(); | |
}); | |
} | |
} | |
function breakOnTimeout(duration) { | |
setTimeout(function () { | |
debugger; | |
}, duration); | |
} | |
function setEventTrigger(eventType, invokeFunction, conditionFunction, proccessEvent) { | |
document.addEventListener(eventType, function listener(event) { | |
if (!conditionFunction || conditionFunction(event)) { | |
document.removeEventListener(eventType, listener, true); | |
if (!proccessEvent) { | |
event.preventDefault(); | |
event.stopImmediatePropagation(); | |
} | |
invokeFunction(); | |
} | |
}, true); | |
} | |
function setKeyTrigger(keyEventProperties, invokeFunction) { | |
setEventTrigger('keydown', invokeFunction, function (event) { | |
return containsProperties(keyEventProperties, event); | |
}); | |
} | |
function containsProperties(objectWithProperties, objectToCheck) { | |
var _iteratorNormalCompletion = true; | |
var _didIteratorError = false; | |
var _iteratorError = undefined; | |
try { | |
for (var _iterator = Object.getOwnPropertyNames(objectWithProperties)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | |
var property = _step.value; | |
if (objectToCheck[property] !== objectWithProperties[property]) { | |
return false; | |
} | |
} | |
} catch (err) { | |
_didIteratorError = true; | |
_iteratorError = err; | |
} finally { | |
try { | |
if (!_iteratorNormalCompletion && _iterator["return"]) { | |
_iterator["return"](); | |
} | |
} finally { | |
if (_didIteratorError) { | |
throw _iteratorError; | |
} | |
} | |
} | |
return true; | |
} | |
function breakOnKeypress(keyEvent) { | |
keyEvent = keyEvent || { | |
ctrlKey: true | |
}; | |
setKeyTrigger(keyEvent, function () { | |
debugger; | |
}); | |
console.log("trigger set for key event: ", keyEvent); | |
} | |
function listPrototypes(object) { | |
console.group("Prototypes %O", object); | |
var prototype = object.prototype || object.__proto__; | |
while (prototype) { | |
console.log(prototype.constructor.name, prototype); | |
prototype = prototype.__proto__; | |
} | |
console.groupEnd(); | |
} | |
/* --------------------- Export public functions -------------------- */ | |
var exports = { | |
profileWaitForTrigger: profileWaitForTrigger, breakOnKeypress: breakOnKeypress, testEvents: testEvents, inspectElements: inspectElements, profile: profile, breakOnTimeout: breakOnTimeout, listPrototypes: listPrototypes | |
}; | |
window.d = exports; | |
console.log(moduleName + " module installed"); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment