diff --git a/js/devtoolsBackground.js b/js/devtoolsBackground.js index ae4057b..ffc83f1 100644 --- a/js/devtoolsBackground.js +++ b/js/devtoolsBackground.js @@ -1,11 +1,23 @@ -var panels = chrome.devtools.panels; +var panels = chrome && chrome.devtools && chrome.devtools.panels; + +function getScope(node) { + var scope = window.angular.element(node).scope(); + if (!scope) { + // Might be a child of a DocumentFragment... + while (node && node.nodeType === 1) node = node.parentNode; + if (node && node.nodeType === 11) node = (node.parentNode || node.host); + return getScope(node); + } + return scope; +} // The function below is executed in the context of the inspected page. var getPanelContents = function () { if (window.angular && $0) { //TODO: can we move this scope export into updateElementProperties - var scope = window.angular.element($0).scope(); + var scope = getScope($0); + // Export $scope to the console window.$scope = scope; return (function (scope) { @@ -29,17 +41,19 @@ var getPanelContents = function () { } }; -panels.elements.createSidebarPane( - "AngularJS Properties", - function (sidebar) { - panels.elements.onSelectionChanged.addListener(function updateElementProperties() { - sidebar.setExpression("(" + getPanelContents.toString() + ")()"); +if (panels) { + panels.elements.createSidebarPane( + "AngularJS Properties", + function (sidebar) { + panels.elements.onSelectionChanged.addListener(function updateElementProperties() { + sidebar.setExpression("(" + getPanelContents.toString() + ")()"); + }); }); - }); -// Angular panel -var angularPanel = panels.create( - "AngularJS", - "img/angular.png", - "panel.html" -); + // Angular panel + var angularPanel = panels.create( + "AngularJS", + "img/angular.png", + "panel.html" + ); +} diff --git a/karma.conf b/karma.conf index efe647b..8d70440 100644 --- a/karma.conf +++ b/karma.conf @@ -10,6 +10,7 @@ files = [ 'js/directives/*.js', 'js/filters/*.js', 'js/services/*.js', + 'js/devtoolsBackground.js' 'test/mock/*.js', 'test/*.js' diff --git a/karma.e2e.conf b/karma.e2e.conf index efe647b..0fc712a 100644 --- a/karma.e2e.conf +++ b/karma.e2e.conf @@ -10,6 +10,7 @@ files = [ 'js/directives/*.js', 'js/filters/*.js', 'js/services/*.js', + 'js/devtoolsBackground.js', 'test/mock/*.js', 'test/*.js' diff --git a/test/ElementsPanelSpec.js b/test/ElementsPanelSpec.js new file mode 100644 index 0000000..337f074 --- /dev/null +++ b/test/ElementsPanelSpec.js @@ -0,0 +1,41 @@ +describe('elements panel', function() { + beforeEach(module(function($provide) { + $provide.factory('chromeExtension', createChromeExtensionMock); + })); + + afterEach(function() { + $0 = null; + }); + + + describe('angular properties sidebar', function() { + describe('getPanelContents()', function() { + it('should return properties for scope of selected element', inject(function($rootScope) { + var element = angular.element('

Hello, world

'); + element.data('$scope', $rootScope); + $rootScope.text = "Hello, world!"; + $0 = element[0]; + expect (getPanelContents().text).toBe("Hello, world!"); + $0 = element.children().eq(0)[0]; + expect (getPanelContents().text).toBe("Hello, world!"); + })); + + + it('should cross shadow DOM barrier via DocumentFragment#host', inject(function($rootScope) { + var parent = document.createElement('div'), + fragment = document.createDocumentFragment(), + child = document.createElement('p'); + fragment.host = parent; + fragment.appendChild(child); + parent.appendChild(fragment); + + parent = angular.element(parent); + parent.data('$scope', $rootScope); + $rootScope.text = "Fragmented fun for everyone"; + + $0 = child; + expect(getPanelContents().text).toBe("Fragmented fun for everyone"); + })); + }); + }); +});