Skip to content

Commit

Permalink
Merge pull request #12456 from rwjblue/DIE-ATTRS-DIE
Browse files Browse the repository at this point in the history
[BUGFIX beta] Allow usage of bound properties in {{link-to}}.
  • Loading branch information
rwjblue committed Oct 8, 2015
2 parents c8c79de + 036bf4e commit 1f85853
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 15 deletions.
24 changes: 12 additions & 12 deletions packages/ember-routing-views/lib/components/link-to.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,14 +623,16 @@ let LinkComponent = EmberComponent.extend({
_invoke(event) {
if (!isSimpleClick(event)) { return true; }

if (this.attrs.preventDefault !== false) {
let targetAttribute = this.attrs.target;
let preventDefault = get(this, 'preventDefault');
let targetAttribute = get(this, 'target');

if (preventDefault !== false) {
if (!targetAttribute || targetAttribute === '_self') {
event.preventDefault();
}
}

if (this.attrs.bubbles === false) { event.stopPropagation(); }
if (get(this, 'bubbles') === false) { event.stopPropagation(); }

if (get(this, '_isDisabled')) { return false; }

Expand All @@ -639,24 +641,23 @@ let LinkComponent = EmberComponent.extend({
return false;
}

let targetAttribute2 = this.attrs.target;
if (targetAttribute2 && targetAttribute2 !== '_self') {
if (targetAttribute && targetAttribute !== '_self') {
return false;
}

let routing = get(this, '_routing');
let qualifiedRouteName = get(this, 'qualifiedRouteName');
let models = get(this, 'models');
let queryParamValues = get(this, 'queryParams.values');
let shouldReplace = get(this, 'attrs.replace');
let shouldReplace = get(this, 'replace');

routing.transitionTo(qualifiedRouteName, models, queryParamValues, shouldReplace);
},

queryParams: null,

qualifiedRouteName: computed('targetRouteName', '_routing.currentState', function computeLinkToComponentQualifiedRouteName() {
let params = this.attrs.params.slice();
let params = get(this, 'params').slice();
let lastParam = params[params.length - 1];
if (lastParam && lastParam.isQueryParams) {
params.pop();
Expand Down Expand Up @@ -738,15 +739,14 @@ let LinkComponent = EmberComponent.extend({
willRender() {
let queryParams;

let attrs = this.attrs;

// Do not mutate params in place
let params = attrs.params.slice();
let params = get(this, 'params').slice();

assert('You must provide one or more parameters to the link-to component.', params.length);

if (attrs.disabledWhen) {
this.set('disabled', attrs.disabledWhen);
let disabledWhen = get(this, 'disabledWhen');
if (disabledWhen) {
this.set('disabled', disabledWhen);
}

// Process the positional arguments, in order.
Expand Down
194 changes: 191 additions & 3 deletions packages/ember/tests/helpers/link_to_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,62 @@ QUnit.test('The {{link-to}} helper supports URL replacement', function() {
equal(replaceCount, 1, 'replaceURL should be called once');
});

QUnit.test('The {{link-to}} helper supports URL replacement via replace=boundTruthyThing', function() {
Ember.TEMPLATES.index = compile('<h3>Home</h3>{{#link-to \'about\' id=\'about-link\' replace=boundTruthyThing}}About{{/link-to}}');

App.IndexController = Controller.extend({
boundTruthyThing: true
});

Router.map(function() {
this.route('about');
});

bootApplication();

run(function() {
router.handleURL('/');
});

equal(updateCount, 0, 'precond: setURL has not been called');
equal(replaceCount, 0, 'precond: replaceURL has not been called');

run(function() {
jQuery('#about-link', '#qunit-fixture').click();
});

equal(updateCount, 0, 'setURL should not be called');
equal(replaceCount, 1, 'replaceURL should be called once');
});

QUnit.test('The {{link-to}} helper supports setting replace=boundFalseyThing', function() {
Ember.TEMPLATES.index = compile('<h3>Home</h3>{{#link-to \'about\' id=\'about-link\' replace=boundFalseyThing}}About{{/link-to}}');

App.IndexController = Controller.extend({
boundFalseyThing: false
});

Router.map(function() {
this.route('about');
});

bootApplication();

run(function() {
router.handleURL('/');
});

equal(updateCount, 0, 'precond: setURL has not been called');
equal(replaceCount, 0, 'precond: replaceURL has not been called');

run(function() {
jQuery('#about-link', '#qunit-fixture').click();
});

equal(updateCount, 1, 'setURL should be called');
equal(replaceCount, 0, 'replaceURL should not be called');
});

QUnit.test('the {{link-to}} helper doesn\'t add an href when the tagName isn\'t \'a\'', function() {
Ember.TEMPLATES.index = compile('{{#link-to \'about\' id=\'about-link\' tagName=\'div\'}}About{{/link-to}}');

Expand All @@ -207,9 +263,14 @@ QUnit.test('the {{link-to}} helper doesn\'t add an href when the tagName isn\'t


QUnit.test('the {{link-to}} applies a \'disabled\' class when disabled', function () {
Ember.TEMPLATES.index = compile('{{#link-to "about" id="about-link" disabledWhen="shouldDisable"}}About{{/link-to}}');
Ember.TEMPLATES.index = compile(`
{{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}}
{{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}}
`);

App.IndexController = Controller.extend({
shouldDisable: true
shouldDisable: true,
dynamicDisabledWhen: 'shouldDisable'
});

Router.map(function() {
Expand All @@ -222,7 +283,8 @@ QUnit.test('the {{link-to}} applies a \'disabled\' class when disabled', functio
router.handleURL('/');
});

equal(jQuery('#about-link.disabled', '#qunit-fixture').length, 1, 'The link is disabled when its disabledWhen is true');
equal(jQuery('#about-link-static.disabled', '#qunit-fixture').length, 1, 'The static link is disabled when its disabledWhen is true');
equal(jQuery('#about-link-dynamic.disabled', '#qunit-fixture').length, 1, 'The dynamic link is disabled when its disabledWhen is true');
});

QUnit.test('the {{link-to}} doesn\'t apply a \'disabled\' class if disabledWhen is not provided', function () {
Expand Down Expand Up @@ -605,6 +667,45 @@ QUnit.test('The {{link-to}} helper supports bubbles=false', function() {
equal(hidden, 0, 'The link didn\'t bubble');
});

QUnit.test('The {{link-to}} helper supports bubbles=boundFalseyThing', function() {
Ember.TEMPLATES.about = compile('<div {{action \'hide\'}}>{{#link-to \'about.contact\' id=\'about-contact\' bubbles=boundFalseyThing}}About{{/link-to}}</div>{{outlet}}');
Ember.TEMPLATES['about/contact'] = compile('<h1 id=\'contact\'>Contact</h1>');

App.AboutController = Controller.extend({
boundFalseyThing: false
});

Router.map(function() {
this.route('about', function() {
this.route('contact');
});
});

var hidden = 0;

App.AboutRoute = Route.extend({
actions: {
hide() {
hidden++;
}
}
});

bootApplication();

run(function() {
router.handleURL('/about');
});

run(function() {
jQuery('#about-contact', '#qunit-fixture').click();
});

equal(jQuery('#contact', '#qunit-fixture').text(), 'Contact', 'precond - the link worked');

equal(hidden, 0, 'The link didn\'t bubble');
});

QUnit.test('The {{link-to}} helper moves into the named route with context', function() {
Router.map(function(match) {
this.route('about');
Expand Down Expand Up @@ -686,6 +787,23 @@ QUnit.test('The {{link-to}} helper supports `target` attribute', function() {
equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute');
});

QUnit.test('The {{link-to}} helper supports `target` attribute specified as a bound param', function() {
Ember.TEMPLATES.index = compile('<h3>Home</h3>{{#link-to \'index\' id=\'self-link\' target=boundLinkTarget}}Self{{/link-to}}');

App.IndexController = Controller.extend({
boundLinkTarget: '_blank'
});

bootApplication();

run(function() {
router.handleURL('/');
});

var link = jQuery('#self-link', '#qunit-fixture');
equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute');
});

QUnit.test('The {{link-to}} helper does not call preventDefault if `target` attribute is provided', function() {
Ember.TEMPLATES.index = compile('<h3>Home</h3>{{#link-to \'index\' id=\'self-link\' target=\'_blank\'}}Self{{/link-to}}');
bootApplication();
Expand Down Expand Up @@ -1267,6 +1385,27 @@ QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefau
equal(event.isDefaultPrevented(), false, 'should not preventDefault');
});

QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefault=boundFalseyThing` is passed as an option', function() {
Ember.TEMPLATES.index = compile('{{#link-to \'about\' id=\'about-link\' preventDefault=boundFalseyThing}}About{{/link-to}}');

App.IndexController = Controller.extend({
boundFalseyThing: false
});

Router.map(function() {
this.route('about');
});

bootApplication();

run(router, 'handleURL', '/');

var event = jQuery.Event('click');
jQuery('#about-link', '#qunit-fixture').trigger(event);

equal(event.isDefaultPrevented(), false, 'should not preventDefault');
});

QUnit.test('the {{link-to}} helper does not throw an error if its route has exited', function() {
expect(0);

Expand Down Expand Up @@ -1523,3 +1662,52 @@ QUnit.test('Block-less {{link-to}} with only query-params updates when route cha
});
equal(jQuery('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href');
});

QUnit.test('The {{link-to}} helper can use dynamic params', function() {
Router.map(function(match) {
this.route('foo', { path: 'foo/:some/:thing' });
this.route('bar', { path: 'bar/:some/:thing/:else' });
});

let controller;
App.IndexController = Controller.extend({
init() {
this._super(...arguments);

controller = this;

this.dynamicLinkParams = [
'foo',
'one',
'two'
];
}
});

Ember.TEMPLATES.index = compile(`
<h3>Home</h3>
{{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}}
`);

bootApplication();

run(function() {
router.handleURL('/');
});

let link = jQuery('#dynamic-link', '#qunit-fixture');

equal(link.attr('href'), '/foo/one/two');

run(function() {
controller.set('dynamicLinkParams', [
'bar',
'one',
'two',
'three'
]);
});

equal(link.attr('href'), '/bar/one/two/three');
});

0 comments on commit 1f85853

Please sign in to comment.