Skip to content

Commit

Permalink
Merge pull request #17256 from emberjs/impl-build-routeinfo-metadata
Browse files Browse the repository at this point in the history
[FEATURE] Impl. buildRouteInfoMetadata
  • Loading branch information
rwjblue authored Dec 10, 2018
2 parents 1edb3f9 + cf2ae90 commit de301b6
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
"puppeteer": "^1.3.0",
"qunit": "^2.8.0",
"route-recognizer": "^0.3.4",
"router_js": "^6.1.3",
"router_js": "^6.2.0",
"rsvp": "^4.8.4",
"semver": "^5.5.0",
"serve-static": "^1.13.2",
Expand Down
8 changes: 8 additions & 0 deletions packages/@ember/-internals/routing/lib/system/route-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@
@public
*/

/**
Will contain the result `Route#buildRouteInfoMetadata`
for the corresponding Route.
@property {Any} metadata
@category ember-routing-build-routeinfo-metadata
@public
*/

/**
A reference to the parent route's RouteInfo.
This can be used to traverse upward to the topmost
Expand Down
46 changes: 45 additions & 1 deletion packages/@ember/-internals/routing/lib/system/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
Object as EmberObject,
typeOf,
} from '@ember/-internals/runtime';
import { EMBER_ROUTING_ROUTER_SERVICE } from '@ember/canary-features';
import {
EMBER_ROUTING_BUILD_ROUTEINFO_METADATA,
EMBER_ROUTING_ROUTER_SERVICE,
} from '@ember/canary-features';
import { assert, deprecate, info, isTesting } from '@ember/debug';
import { ROUTER_EVENTS } from '@ember/deprecated-features';
import { assign } from '@ember/polyfills';
Expand Down Expand Up @@ -2554,4 +2557,45 @@ if (EMBER_ROUTING_ROUTER_SERVICE && ROUTER_EVENTS) {
});
}

if (EMBER_ROUTING_BUILD_ROUTEINFO_METADATA) {
Route.reopen({
/**
Allows you to produce custom metadata for the route.
The return value of this method will be attatched to
its corresponding RouteInfoWithAttributes obejct.
Example
```app/routes/posts/index.js
import Route from '@ember/routing/route';
export default Route.extend({
buildRouteInfoMetadata() {
return { title: 'Posts Page' }
}
});
```
```app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
router: service('router'),
init() {
this._super(...arguments);
this.router.on('routeDidChange', transition => {
document.title = transition.to.metadata.title;
// would update document's title to "Posts Page"
});
}
});
```
@return any
@category ember-routing-build-routeinfo-metadata
*/
buildRouteInfoMetadata() {},
});
}

export default Route;
5 changes: 5 additions & 0 deletions packages/@ember/canary-features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const DEFAULT_FEATURES = {
EMBER_METAL_TRACKED_PROPERTIES: null,
EMBER_GLIMMER_ANGLE_BRACKET_INVOCATION: true,
EMBER_GLIMMER_ARRAY_HELPER: null,
EMBER_ROUTING_BUILD_ROUTEINFO_METADATA: null,
};

/**
Expand Down Expand Up @@ -87,3 +88,7 @@ export const EMBER_GLIMMER_ANGLE_BRACKET_INVOCATION = featureValue(
);
export const GLIMMER_MODIFIER_MANAGER = featureValue(FEATURES.GLIMMER_MODIFIER_MANAGER);
export const EMBER_GLIMMER_ARRAY_HELPER = featureValue(FEATURES.EMBER_GLIMMER_ARRAY_HELPER);

export const EMBER_ROUTING_BUILD_ROUTEINFO_METADATA = featureValue(
FEATURES.EMBER_ROUTING_BUILD_ROUTEINFO_METADATA
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import {
EMBER_ROUTING_ROUTER_SERVICE,
EMBER_ROUTING_BUILD_ROUTEINFO_METADATA,
} from '@ember/canary-features';
import { RouterTestCase, moduleFor } from 'internal-test-helpers';
import { inject as service } from '@ember/service';
import { Route } from '@ember/-internals/routing';

if (EMBER_ROUTING_BUILD_ROUTEINFO_METADATA && EMBER_ROUTING_ROUTER_SERVICE) {
moduleFor(
'buildRouteInfoMetadata',
class extends RouterTestCase {
'@test basic metadata'(assert) {
this.add(
`route:application`,
Route.extend({
router: service('router'),
init() {
this._super(...arguments);

this.router.on('routeDidChange', transition => {
assert.equal(transition.to.name, 'parent.index');
assert.equal(transition.to.metadata, 'parent-index-page');
});
},
})
);

this.add(
`route:parent.index`,
Route.extend({
buildRouteInfoMetadata() {
return 'parent-index-page';
},
})
);

return this.visit('/');
}

'@test hierarchical metadata'(assert) {
this.add(
`route:application`,
Route.extend({
router: service('router'),
buildRouteInfoMetadata() {
return 'application-shell';
},
init() {
this._super(...arguments);

this.router.on('routeDidChange', transition => {
assert.equal(transition.to.name, 'parent.index');
assert.equal(transition.to.metadata, 'parent-index-page');
assert.equal(transition.to.parent.name, 'parent');
assert.equal(transition.to.parent.metadata, 'parent-page');
assert.equal(transition.to.parent.parent.name, 'application');
assert.equal(transition.to.parent.parent.metadata, 'application-shell');
});
},
})
);

this.add(
`route:parent`,
Route.extend({
buildRouteInfoMetadata() {
return 'parent-page';
},
})
);

this.add(
`route:parent.index`,
Route.extend({
buildRouteInfoMetadata() {
return 'parent-index-page';
},
})
);

return this.visit('/');
}

'@test metadata can be complex objects'(assert) {
this.add(
`route:application`,
Route.extend({
router: service('router'),
init() {
this._super(...arguments);

this.router.on('routeDidChange', transition => {
assert.equal(transition.to.name, 'parent.index');
assert.equal(transition.to.metadata.name, 'parent-index-page');
assert.equal(transition.to.metadata.title('PARENT'), 'My Name is PARENT');
});
},
})
);

this.add(`route:parent`, Route.extend({}));

this.add(
`route:parent.index`,
Route.extend({
buildRouteInfoMetadata() {
return {
name: 'parent-index-page',
title: name => `My Name is ${name}`,
};
},
})
);

return this.visit('/');
}

'@test metadata is placed on the `from`'(assert) {
assert.expect(6);
this.add(
`route:application`,
Route.extend({
router: service('router'),
init() {
this._super(...arguments);

this.router.on('routeDidChange', transition => {
if (transition.to.name === 'parent.index') {
assert.equal(transition.to.metadata.name, 'parent-index-page');
assert.equal(transition.to.metadata.title('INDEX'), 'My Name is INDEX');
} else {
assert.equal(transition.from.metadata.name, 'parent-index-page');
assert.equal(transition.from.metadata.title('INDEX'), 'My Name is INDEX');
assert.equal(transition.to.metadata.name, 'parent-child-page');
assert.equal(transition.to.metadata.title('CHILD'), 'My Name is CHILD!!');
}
});
},
})
);

this.add(`route:parent`, Route.extend({}));

this.add(
`route:parent.index`,
Route.extend({
buildRouteInfoMetadata() {
return {
name: 'parent-index-page',
title: name => `My Name is ${name}`,
};
},
})
);

this.add(
`route:parent.child`,
Route.extend({
buildRouteInfoMetadata() {
return {
name: 'parent-child-page',
title: name => `My Name is ${name}!!`,
};
},
})
);

return this.visit('/').then(() => {
return this.visit('/child');
});
}

'@test can be used with model data from `attributes`'(assert) {
assert.expect(6);
this.add(
`route:application`,
Route.extend({
router: service('router'),
init() {
this._super(...arguments);

this.router.on('routeDidChange', transition => {
if (transition.to.name === 'parent.index') {
assert.equal(transition.to.metadata.name, 'parent-index-page');
assert.equal(
transition.to.metadata.title(transition.to.attributes),
'My Name is INDEX'
);
} else {
assert.equal(transition.from.metadata.name, 'parent-index-page');
assert.equal(
transition.from.metadata.title(transition.from.attributes),
'My Name is INDEX'
);
assert.equal(transition.to.metadata.name, 'parent-child-page');
assert.equal(
transition.to.metadata.title(transition.to.attributes),
'My Name is CHILD!!'
);
}
});
},
})
);

this.add(`route:parent`, Route.extend({}));

this.add(
`route:parent.index`,
Route.extend({
model() {
return { name: 'INDEX' };
},
buildRouteInfoMetadata() {
return {
name: 'parent-index-page',
title: model => `My Name is ${model.name}`,
};
},
})
);

this.add(
`route:parent.child`,
Route.extend({
model() {
return { name: 'CHILD' };
},
buildRouteInfoMetadata() {
return {
name: 'parent-child-page',
title: model => `My Name is ${model.name}!!`,
};
},
})
);

return this.visit('/').then(() => {
return this.visit('/child');
});
}
}
);
}
1 change: 1 addition & 0 deletions tests/docs/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ module.exports = {
'merge',
'mergedProperties',
'meta',
'metadata',
'metaForProperty',
'method',
'min',
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7404,10 +7404,10 @@ route-recognizer@^0.3.4:
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3"
integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==

router_js@^6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/router_js/-/router_js-6.1.3.tgz#9fbecbb4b173f5a6c4580d15f94737cfeb4629e6"
integrity sha512-I3l/4wMpSl/Fd9SZQCa7kVAIn5H3v10KjA4CuJPg1gjihC5GKFi4owetf/psNg2lAqevmMn81yLCsIxBwoeK1A==
router_js@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/router_js/-/router_js-6.2.0.tgz#df2eac625169997f03d7cdf67507bda49d98be3a"
integrity sha512-K57PWU58OiXlaGzHw1vXg0PeC8NpMRIsd3poXq0qXZRIzB3OtMJQolHUuJ0c88544gv+tKw1kaYYM/0E1XNmng==
dependencies:
"@types/node" "^10.5.5"

Expand Down

0 comments on commit de301b6

Please sign in to comment.