diff --git a/app-route-converter-behavior.html b/app-route-converter-behavior.html index 23cc9dc..9682175 100644 --- a/app-route-converter-behavior.html +++ b/app-route-converter-behavior.html @@ -80,7 +80,8 @@ this.route = { prefix: '', path: this.path, - __queryParams: this.queryParams + __queryParams: this.queryParams, + active: true }; }, diff --git a/app-route.html b/app-route.html index 197dab9..0da565b 100644 --- a/app-route.html +++ b/app-route.html @@ -137,7 +137,7 @@ */ tail: { type: Object, - value: function() {return {path: null, prefix: null, __queryParams: null};}, + value: function() {return {path: null, prefix: null, __queryParams: null, active: false};}, notify: true }, @@ -166,7 +166,8 @@ '__tailPathChanged(tail.path)', '__routeQueryParamsChanged(route.__queryParams)', '__tailQueryParamsChanged(tail.__queryParams)', - '__queryParamsChanged(queryParams.*)' + '__queryParamsChanged(queryParams.*)', + '__parentActiveChanged(route.active)' ], created: function() { @@ -235,11 +236,10 @@ this.set('route.__' + changes.path, changes.value); }, - __resetProperties: function() { + __deactivate: function() { this._setActive(false); + this.set('tail.active', false); this._matched = null; - //this.tail = { path: null, prefix: null, queryParams: null }; - //this.data = {}; }, /** @@ -256,7 +256,7 @@ } if (!path) { - this.__resetProperties(); + this.__deactivate(); return; } @@ -275,7 +275,7 @@ // We don't match this path. if (!pathPiece && pathPiece !== '') { - this.__resetProperties(); + this.__deactivate(); return; } matched.push(pathPiece); @@ -283,7 +283,7 @@ if (patternPiece.charAt(0) == ':') { namedMatches[patternPiece.slice(1)] = pathPiece; } else if (patternPiece !== pathPiece) { - this.__resetProperties(); + this.__deactivate(); return; } } @@ -306,11 +306,13 @@ } if (!this.tail || this.tail.prefix !== tailPrefix || - this.tail.path !== tailPath) { + this.tail.path !== tailPath || + this.tail.active !== this.active) { propertyUpdates.tail = { prefix: tailPrefix, path: tailPath, - __queryParams: this.route.__queryParams + __queryParams: this.route.__queryParams, + active: true }; } @@ -345,13 +347,13 @@ /** * @export */ - __updatePathOnDataChange: function() { - if (!this.route || !this.active) { + __updatePathOnDataChange: function(data) { + if (!this.active) { return; } var newPath = this.__getLink({}); var oldPath = this.__getLink(this._dataInUrl); - if (newPath === oldPath) { + if (this._dataInUrl && newPath === oldPath) { return; } this.set('route.path', newPath); @@ -382,6 +384,14 @@ return interp.join('/'); }, + __parentActiveChanged: function(active) { + if (!active) { + this.__deactivate(); + } else { + this.__tryToMatch(); + } + }, + __setMulti: function(setObj) { // HACK(rictic): skirting around 1.0's lack of a setMulti by poking at // internal data structures. I would not advise that you copy this diff --git a/test/app-route-converter.html b/test/app-route-converter.html index b5b8c55..514a2da 100644 --- a/test/app-route-converter.html +++ b/test/app-route-converter.html @@ -40,7 +40,8 @@ expect(converter.route).to.be.deep.equal({ prefix: '', path: '/a/b/c', - __queryParams: queryParams + __queryParams: queryParams, + active: true }); converter.set('route.path', '/d/e/f'); diff --git a/test/app-route.html b/test/app-route.html index da4af2c..4059d46 100644 --- a/test/app-route.html +++ b/test/app-route.html @@ -45,8 +45,21 @@ + + + + + + @@ -64,14 +77,17 @@ numberOneTopRoute: { path: route.path || '', prefix: route.prefix || '', - __queryParams: route.__queryParams || {} + __queryParams: route.__queryParams || {}, + active: route.active !== undefined ? route.active : true } }); return { foo: routes[0], bar: routes[1], - baz: routes[2] + baz: routes[2], + bay: routes[3], + page: routes[4] }; } @@ -93,7 +109,8 @@ route.route = { prefix: '', path: '/user/papyrus/details', - __queryParams: {} + __queryParams: {}, + active: true } expect(route.tail.prefix).to.be.equal('/user/papyrus'); expect(route.tail.path).to.be.equal('/details'); @@ -104,7 +121,8 @@ route.route = { prefix: '', path: '/user/papyrus/details', - __queryParams: {} + __queryParams: {}, + active: true }; route.set('tail.path', '/messages'); @@ -113,14 +131,16 @@ expect(route.tail).to.be.deep.equal({ prefix: '/user/toriel', path: '', - __queryParams: {} + __queryParams: {}, + active: true }); }); test('it creates data as described by pattern', function() { route.route = { prefix: '', - path: '/user/sans' + path: '/user/sans', + active: true }; expect(route.data).to.be.deep.equal({username: 'sans'}); @@ -145,7 +165,8 @@ test('changing data changes the path', function() { route.route = { prefix: '', - path: '/user/asgore' + path: '/user/asgore', + active: true }; expect(route.data).to.be.deep.equal({username: 'asgore'}); @@ -153,6 +174,22 @@ expect(route.route.path).to.be.equal('/user/toriel'); }); + test('it becomes inactive if parent became inactive', function() { + var routes = fixtureChainedRoutes({ path: '/foo/123/baz/abc/bay' }); + + expect(routes.bay.active).to.be.eql(true); + routes.foo.set('route.path', '/foo/123/bar/abc'); + expect(routes.bay.active).to.be.eql(false); + }); + + test('it becomes active again after parent got active', function() { + var routes = fixtureChainedRoutes({ path: '/foo/123/baz/abc/bay' }); + + routes.foo.set('route.path', '/foo/123/bar/abc'); + routes.foo.set('route.path', '/foo/123/baz/abc/bay'); + expect(routes.bay.active).to.be.eql(true); + }); + suite('propagating data', function() { test('data is empty if no routes in the tree have matched', function() { var routes = fixtureChainedRoutes({ path: '' }); @@ -200,27 +237,49 @@ test('ignores changes when the route is inactive', function() { var routes = fixtureChainedRoutes({ path: '/foo/123/bar/abc' }); - expect(routes.baz.active).to.be.eql(false); - routes.baz.set('data.baz', 'cba'); + expect(routes.bay.active).to.be.eql(false); + routes.bay.set('data.bay', 'cba'); expect(routes.foo.route.path).to.be.eql('/foo/123/bar/abc'); }); - test('ignores changes after a route deactives', function() { - var routes = fixtureChainedRoutes({ path: '/foo/123/bar/abc' }); - - routes.foo.set('route.path', '/foo/123/baz/zyx'); - - expect(routes.bar.active).to.be.eql(false); - expect(routes.baz.active).to.be.eql(true); - routes.bar.set('data.bar', 'cba'); - expect(routes.foo.route.path).to.be.eql('/foo/123/baz/zyx'); + suite('updates when path could be matched', function() { + test('with literal part', function() { + var routes = fixtureChainedRoutes({ path: '/foo/123/bar/' }); + expect(routes.bar.active).to.be.eql(true); + routes.bar.set('data.bar', 'zyx'); + expect(routes.foo.route.path).to.be.eql('/foo/123/bar/zyx'); + }); + + test('correctly sets tail', function() { + var routes = fixtureChainedRoutes({ path: '/foo/' }); + routes.foo.set('data.foo', '123'); + expect(routes.page.route).to.be.eql({ + prefix: '/foo/123', + path: '', + __queryParams: {}, + active: true + }); + }); + + test('with only match and trailing slash', function() { + var routes = fixtureChainedRoutes({ path: '/foo/123/' }); + expect(routes.page.active).to.be.eql(true); + routes.page.set('data.page', 'page1'); + expect(routes.foo.route.path).to.be.eql('/foo/123/page1'); + }); + + test('nested does not become active when empty path', function() { + var routes = fixtureChainedRoutes({ path: '/foo/' }); + expect(routes.page.active).to.be.eql(false); + expect(routes.foo.data.foo).to.be.eql(''); + }); }); }); }); suite('propagating query params', function() { test('query params are empty if no routes match', function() { - var routes = fixtureChainedRoutes({ path: '', __queryParams: { + var routes = fixtureChainedRoutes({ path: '', active: false, __queryParams: { qux: 'zot' }}); expect(routes.foo.queryParams).to.be.eql({}); diff --git a/test/test-app-example-1.html b/test/test-app-example-1.html index 29b8104..fcfc5c4 100644 --- a/test/test-app-example-1.html +++ b/test/test-app-example-1.html @@ -57,12 +57,14 @@ expect(exampleApp.route).to.be.deep.eq({ prefix: '', path: '/lol', - __queryParams: {} + __queryParams: {}, + active: true }); expect(exampleApp.userRoute).to.be.deep.eq({ prefix: null, path: null, - __queryParams: {} + __queryParams: {}, + active: false }); expect(window.location.pathname).to.be.equal('/lol'); @@ -77,12 +79,14 @@ expect(exampleApp.route).to.be.deep.eq({ prefix: '', path: '/user/view', - __queryParams: {} + __queryParams: {}, + active: true }); expect(exampleApp.userRoute).to.be.deep.eq({ prefix: '/user', path: '/view', - __queryParams: {} + __queryParams: {}, + active: true }); expect(window.location.pathname).to.be.equal('/user/view'); @@ -97,12 +101,14 @@ expect(exampleApp.route).to.be.deep.eq({ prefix: '', path: '/user/details', - __queryParams: {} + __queryParams: {}, + active: true }); expect(exampleApp.userRoute).to.be.deep.eq({ prefix: '/user', path: '/details', - __queryParams: {} + __queryParams: {}, + active: true }); expect(window.location.pathname).to.be.equal('/user/details');