|
|
|
@ -49,16 +49,15 @@ var inject = function () {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
// =======
|
|
|
|
|
|
|
|
|
|
// polyfill for performance.now on older webkit
|
|
|
|
|
if (!performance.now) {
|
|
|
|
|
performance.now = performance.webkitNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
// =======
|
|
|
|
|
|
|
|
|
|
// Based on cycle.js
|
|
|
|
|
// 2011-08-24
|
|
|
|
|
// https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
|
|
|
|
|
|
|
|
|
|
// Make a deep copy of an object or array, assuring that there is at most
|
|
|
|
@ -66,7 +65,7 @@ var inject = function () {
|
|
|
|
|
// duplicate references (which might be forming cycles) are replaced with
|
|
|
|
|
// an object of the form
|
|
|
|
|
// {$ref: PATH}
|
|
|
|
|
// where the PATH is a JSONPath string that locates the first occurance.
|
|
|
|
|
// where the PATH is a JSONPath string that locates the first occurrence.
|
|
|
|
|
var decycle = function (object) {
|
|
|
|
|
var objects = [], // Keep a reference to each unique object or array
|
|
|
|
|
paths = []; // Keep the path to each unique object or array
|
|
|
|
@ -112,9 +111,8 @@ var inject = function () {
|
|
|
|
|
// End
|
|
|
|
|
// ===
|
|
|
|
|
|
|
|
|
|
// Instrumentation
|
|
|
|
|
// ---------------
|
|
|
|
|
|
|
|
|
|
// given a scope object, return an object with deep clones
|
|
|
|
|
// of the models exposed on that scope
|
|
|
|
|
var getScopeLocals = function (scope) {
|
|
|
|
|
var scopeLocals = {}, prop;
|
|
|
|
|
for (prop in scope) {
|
|
|
|
@ -125,16 +123,73 @@ var inject = function () {
|
|
|
|
|
return scopeLocals;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//var bootstrap = window.angular.bootstrap;
|
|
|
|
|
var debug = window.__ngDebug = {
|
|
|
|
|
watchers: {}, // map of scopes --> watchers
|
|
|
|
|
// helper to extract dependencies from function arguments
|
|
|
|
|
// not all versions of AngularJS expose annotate
|
|
|
|
|
var annotate = angular.injector().annotate;
|
|
|
|
|
if (!annotate) {
|
|
|
|
|
annotate = (function () {
|
|
|
|
|
|
|
|
|
|
watchPerf: {}, // maps of watch/apply exp/fns to perf data
|
|
|
|
|
applyPerf: {},
|
|
|
|
|
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
|
|
|
|
|
var FN_ARG_SPLIT = /,/;
|
|
|
|
|
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
|
|
|
|
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
|
|
|
|
|
|
|
|
|
scopes: {}, // map of scope.$ids --> model objects
|
|
|
|
|
rootScopes: {}, // map of $ids --> refs to root scopes
|
|
|
|
|
rootScopeDirty: {},
|
|
|
|
|
// TODO: should I keep these assertions?
|
|
|
|
|
function assertArg(arg, name, reason) {
|
|
|
|
|
if (!arg) {
|
|
|
|
|
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
|
|
|
|
|
}
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
function assertArgFn(arg, name, acceptArrayAnnotation) {
|
|
|
|
|
if (acceptArrayAnnotation && angular.isArray(arg)) {
|
|
|
|
|
arg = arg[arg.length - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assertArg(angular.isFunction(arg), name, 'not a function, got ' +
|
|
|
|
|
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return function (fn) {
|
|
|
|
|
var $inject,
|
|
|
|
|
fnText,
|
|
|
|
|
argDecl,
|
|
|
|
|
last;
|
|
|
|
|
|
|
|
|
|
if (typeof fn == 'function') {
|
|
|
|
|
if (!($inject = fn.$inject)) {
|
|
|
|
|
$inject = [];
|
|
|
|
|
fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
|
|
|
|
argDecl = fnText.match(FN_ARGS);
|
|
|
|
|
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
|
|
|
|
|
arg.replace(FN_ARG, function(all, underscore, name) {
|
|
|
|
|
$inject.push(name);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
fn.$inject = $inject;
|
|
|
|
|
}
|
|
|
|
|
} else if (angular.isArray(fn)) {
|
|
|
|
|
last = fn.length - 1;
|
|
|
|
|
assertArgFn(fn[last], 'fn');
|
|
|
|
|
$inject = fn.slice(0, last);
|
|
|
|
|
} else {
|
|
|
|
|
assertArgFn(fn, 'fn', true);
|
|
|
|
|
}
|
|
|
|
|
return $inject;
|
|
|
|
|
};
|
|
|
|
|
}());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Public API
|
|
|
|
|
// ==========
|
|
|
|
|
|
|
|
|
|
var api = window.__ngDebug = {
|
|
|
|
|
|
|
|
|
|
getDeps: function () {
|
|
|
|
|
return debug.deps;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getRootScopeIds: function () {
|
|
|
|
|
var ids = [];
|
|
|
|
@ -143,6 +198,7 @@ var inject = function () {
|
|
|
|
|
});
|
|
|
|
|
return ids;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getScopeTree: function (id) {
|
|
|
|
|
if (debug.rootScopeDirty[id] === false) {
|
|
|
|
|
return;
|
|
|
|
@ -174,6 +230,20 @@ var inject = function () {
|
|
|
|
|
return tree;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getWatchPerf: function () {
|
|
|
|
|
var changes = [];
|
|
|
|
|
angular.forEach(debug.watchPerf, function (info, name) {
|
|
|
|
|
if (info.time > 0) {
|
|
|
|
|
changes.push({
|
|
|
|
|
name: name,
|
|
|
|
|
time: info.time
|
|
|
|
|
});
|
|
|
|
|
info.time = 0;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return changes;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getWatchTree: function (id) {
|
|
|
|
|
var traverse = function (sc) {
|
|
|
|
|
var tree = {
|
|
|
|
@ -196,68 +266,37 @@ var inject = function () {
|
|
|
|
|
var tree = traverse(root);
|
|
|
|
|
|
|
|
|
|
return tree;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
deps: []
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var annotate = angular.injector().annotate;
|
|
|
|
|
|
|
|
|
|
// not all versions of AngularJS expose annotate
|
|
|
|
|
if (!annotate) {
|
|
|
|
|
annotate = (function () {
|
|
|
|
|
// Private state
|
|
|
|
|
// =============
|
|
|
|
|
|
|
|
|
|
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
|
|
|
|
|
var FN_ARG_SPLIT = /,/;
|
|
|
|
|
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
|
|
|
|
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
|
|
|
|
//var bootstrap = window.angular.bootstrap;
|
|
|
|
|
var debug = {
|
|
|
|
|
// map of scopes --> watcher function name strings
|
|
|
|
|
watchers: {},
|
|
|
|
|
|
|
|
|
|
// TODO: should I keep these assertions?
|
|
|
|
|
function assertArg(arg, name, reason) {
|
|
|
|
|
if (!arg) {
|
|
|
|
|
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
|
|
|
|
|
}
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
function assertArgFn(arg, name, acceptArrayAnnotation) {
|
|
|
|
|
if (acceptArrayAnnotation && angular.isArray(arg)) {
|
|
|
|
|
arg = arg[arg.length - 1];
|
|
|
|
|
}
|
|
|
|
|
// maps of watch/apply exp/fns to perf data
|
|
|
|
|
watchPerf: {},
|
|
|
|
|
applyPerf: {},
|
|
|
|
|
|
|
|
|
|
assertArg(angular.isFunction(arg), name, 'not a function, got ' +
|
|
|
|
|
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
// map of scope.$ids --> model objects
|
|
|
|
|
scopes: {},
|
|
|
|
|
|
|
|
|
|
return function (fn) {
|
|
|
|
|
var $inject,
|
|
|
|
|
fnText,
|
|
|
|
|
argDecl,
|
|
|
|
|
last;
|
|
|
|
|
// map of $ids --> refs to root scopes
|
|
|
|
|
rootScopes: {},
|
|
|
|
|
|
|
|
|
|
if (typeof fn == 'function') {
|
|
|
|
|
if (!($inject = fn.$inject)) {
|
|
|
|
|
$inject = [];
|
|
|
|
|
fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
|
|
|
|
argDecl = fnText.match(FN_ARGS);
|
|
|
|
|
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
|
|
|
|
|
arg.replace(FN_ARG, function(all, underscore, name) {
|
|
|
|
|
$inject.push(name);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
fn.$inject = $inject;
|
|
|
|
|
}
|
|
|
|
|
} else if (angular.isArray(fn)) {
|
|
|
|
|
last = fn.length - 1;
|
|
|
|
|
assertArgFn(fn[last], 'fn');
|
|
|
|
|
$inject = fn.slice(0, last);
|
|
|
|
|
} else {
|
|
|
|
|
assertArgFn(fn, 'fn', true);
|
|
|
|
|
}
|
|
|
|
|
return $inject;
|
|
|
|
|
};
|
|
|
|
|
}());
|
|
|
|
|
}
|
|
|
|
|
// map of $ids --> bools
|
|
|
|
|
rootScopeDirty: {},
|
|
|
|
|
|
|
|
|
|
deps: []
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Instrumentation
|
|
|
|
|
// ===============
|
|
|
|
|
|
|
|
|
|
var ng = angular.module('ng');
|
|
|
|
|
ng.config(function ($provide) {
|
|
|
|
@ -327,7 +366,6 @@ var inject = function () {
|
|
|
|
|
|
|
|
|
|
// patch watchExpression
|
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
|
|
var w = watchExpression;
|
|
|
|
|
if (typeof w === 'function') {
|
|
|
|
|
watchExpression = function () {
|
|
|
|
@ -378,9 +416,8 @@ var inject = function () {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// patch destroy
|
|
|
|
|
// -------------
|
|
|
|
|
|
|
|
|
|
// patch $destroy
|
|
|
|
|
// --------------
|
|
|
|
|
var _destroy = $delegate.__proto__.$destroy;
|
|
|
|
|
$delegate.__proto__.$destroy = function () {
|
|
|
|
|
if (debug.watchers[this.$id]) {
|
|
|
|
@ -392,6 +429,8 @@ var inject = function () {
|
|
|
|
|
return _destroy.apply(this, arguments);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// patch $new
|
|
|
|
|
// ----------
|
|
|
|
|
var _new = $delegate.__proto__.$new;
|
|
|
|
|
$delegate.__proto__.$new = function () {
|
|
|
|
|
|
|
|
|
@ -410,8 +449,8 @@ var inject = function () {
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// patch apply
|
|
|
|
|
// -----------
|
|
|
|
|
// patch $apply
|
|
|
|
|
// ------------
|
|
|
|
|
var _apply = $delegate.__proto__.$apply;
|
|
|
|
|
$delegate.__proto__.$apply = function (fn) {
|
|
|
|
|
var start = performance.now();
|
|
|
|
|