diff --git a/platform/representation/bundle.json b/platform/representation/bundle.json index 84120541e0..c9872367aa 100644 --- a/platform/representation/bundle.json +++ b/platform/representation/bundle.json @@ -4,12 +4,12 @@ { "key": "mctInclude", "implementation": "MCTInclude.js", - "depends": [ "templates[]" ] + "depends": [ "templates[]", "$sce" ] }, { "key": "mctRepresentation", "implementation": "MCTRepresentation.js", - "depends": [ "representations[]", "views[]", "representers[]", "$q", "$log" ] + "depends": [ "representations[]", "views[]", "representers[]", "$q", "$sce", "$log" ] } ], "gestures": [ @@ -51,4 +51,4 @@ } ] } -} \ No newline at end of file +} diff --git a/platform/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js index 900d12b7f6..41a319e259 100644 --- a/platform/representation/src/MCTInclude.js +++ b/platform/representation/src/MCTInclude.js @@ -53,17 +53,17 @@ define( * @param {TemplateDefinition[]} templates an array of * template extensions */ - function MCTInclude(templates) { + function MCTInclude(templates, $sce) { var templateMap = {}; // Prepopulate templateMap for easy look up by key templates.forEach(function (template) { var key = template.key, - path = [ + path = $sce.trustAsResourceUrl([ template.bundle.path, template.bundle.resources, template.templateUrl - ].join("/"); + ].join("/")); // First found should win (priority ordering) templateMap[key] = templateMap[key] || path; }); @@ -91,4 +91,4 @@ define( return MCTInclude; } -); \ No newline at end of file +); diff --git a/platform/representation/src/MCTRepresentation.js b/platform/representation/src/MCTRepresentation.js index 6008e515e3..ac498f9140 100644 --- a/platform/representation/src/MCTRepresentation.js +++ b/platform/representation/src/MCTRepresentation.js @@ -52,7 +52,7 @@ define( * representation extensions * @param {ViewDefinition[]} views an array of view extensions */ - function MCTRepresentation(representations, views, representers, $q, $log) { + function MCTRepresentation(representations, views, representers, $q, $sce, $log) { var representationMap = {}, gestureMap = {}; @@ -69,11 +69,11 @@ define( // Get a path to a representation function getPath(representation) { - return [ + return $sce.trustAsResourceUrl([ representation.bundle.path, representation.bundle.resources, representation.templateUrl - ].join("/"); + ].join("/")); } // Look up a matching representation for this domain object @@ -215,4 +215,4 @@ define( return MCTRepresentation; } -); \ No newline at end of file +); diff --git a/platform/representation/test/MCTIncludeSpec.js b/platform/representation/test/MCTIncludeSpec.js index 37193bcdf8..135988b509 100644 --- a/platform/representation/test/MCTIncludeSpec.js +++ b/platform/representation/test/MCTIncludeSpec.js @@ -31,6 +31,7 @@ define( describe("The mct-include directive", function () { var testTemplates, + mockSce, mctInclude; beforeEach(function () { @@ -46,7 +47,14 @@ define( templateUrl: "z/template.html" } ]; - mctInclude = new MCTInclude(testTemplates); + mockSce = jasmine.createSpyObj( + '$sce', + ['trustAsResourceUrl'] + ); + mockSce.trustAsResourceUrl.andCallFake(function (url) { + return url; + }); + mctInclude = new MCTInclude(testTemplates, mockSce); }); it("has a built-in template, with ng-include src=inclusion", function () { @@ -69,6 +77,12 @@ define( expect(scope.inclusion).toEqual("x/y/z/template.html"); }); + it("trusts template URLs", function () { + mctInclude.controller({ key: "xyz" }); + expect(mockSce.trustAsResourceUrl) + .toHaveBeenCalledWith("x/y/z/template.html"); + }); + }); } -); \ No newline at end of file +); diff --git a/platform/representation/test/MCTRepresentationSpec.js b/platform/representation/test/MCTRepresentationSpec.js index cb5820a065..643f5cd0af 100644 --- a/platform/representation/test/MCTRepresentationSpec.js +++ b/platform/representation/test/MCTRepresentationSpec.js @@ -38,6 +38,7 @@ define( testViews, mockRepresenters, mockQ, + mockSce, mockLog, mockScope, mockElement, @@ -95,8 +96,16 @@ define( }); mockQ = { when: mockPromise }; + mockSce = jasmine.createSpyObj( + '$sce', + ['trustAsResourceUrl'] + ); mockLog = jasmine.createSpyObj("$log", LOG_FUNCTIONS); + + mockSce.trustAsResourceUrl.andCallFake(function (url) { + return url; + }); mockScope = jasmine.createSpyObj("scope", [ "$watch" ]); mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS); mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS); @@ -125,9 +134,18 @@ define( it("watches scope when linked", function () { mctRepresentation.link(mockScope, mockElement); - expect(mockScope.$watch).toHaveBeenCalledWith("key", jasmine.any(Function)); - expect(mockScope.$watch).toHaveBeenCalledWith("domainObject", jasmine.any(Function)); - expect(mockScope.$watch).toHaveBeenCalledWith("domainObject.getModel().modified", jasmine.any(Function)); + expect(mockScope.$watch).toHaveBeenCalledWith( + "key", + jasmine.any(Function) + ); + expect(mockScope.$watch).toHaveBeenCalledWith( + "domainObject", + jasmine.any(Function) + ); + expect(mockScope.$watch).toHaveBeenCalledWith( + "domainObject.getModel().modified", + jasmine.any(Function) + ); }); it("recognizes keys for representations", function () { @@ -152,6 +170,18 @@ define( expect(mockScope.inclusion).toEqual("x/y/z/template.html"); }); + it("trusts template URLs", function () { + mctRepresentation.link(mockScope, mockElement); + + mockScope.key = "xyz"; + + // Trigger the watch + mockScope.$watch.calls[0].args[1](); + + expect(mockSce.trustAsResourceUrl) + .toHaveBeenCalledWith("x/y/z/template.html"); + }); + it("loads declared capabilities", function () { mctRepresentation.link(mockScope, mockElement); @@ -183,4 +213,4 @@ define( }); }); } -); \ No newline at end of file +);