Last active
September 27, 2020 18:15
-
-
Save NullVoxPopuli/c268d280e51a5dd64e780f860faa1330 to your computer and use it in GitHub Desktop.
Custom Link Component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Component from '@glimmer/component'; | |
import { inject as service } from '@ember/service'; | |
export default class extends Component { | |
@service router; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Component from '@glimmer/component'; | |
import { inject as service } from '@ember/service'; | |
import { action } from '@ember/object'; | |
import { assert } from '@ember/debug'; | |
//import { DEBUG } from '@glimmer/env'; | |
export default class extends Component { | |
@service router; | |
/** | |
* Validate the href | |
* | |
* This component accepts: | |
* - absolute URL (with explicit or relative protocol) | |
* - relative URL with leading / | |
* | |
* NOTE: the assert is removed in production, so there is no | |
* customer-impact to providing dev-time assisstance. | |
* NOTE: DEBUG blocks are removed in production as well | |
*/ | |
get href() { | |
let { href } = this.args; | |
if (/* DEBUG */ true) { | |
assert(`@href is required`, href); | |
let hasProtocol = href.includes('://'); | |
let isProtocolRelative = href.startsWith('//'); | |
let isAbsoluteUrl = href[0] === '/' && href[1] !== '/'; | |
assert( | |
`provided @href argument must begin with a protocol, ` + | |
`such as "https://", or begin with a "/".`, | |
hasProtocol || isProtocolRelative || isAbsoluteUrl | |
); | |
} | |
return href; | |
} | |
/** | |
* If the href needs to navigate us to a different domain, | |
* it will need to specify so. | |
* Additionally, we'd fallback to regular anchor tag behovior. | |
*/ | |
get isSameDomain() { | |
return !this.href.includes('//'); | |
} | |
get hrefInfo() { | |
if (this.isSameDomain) { | |
return this.router.recognize(this.href); | |
} | |
} | |
get isActive() { | |
// TODO: Remove when ember-twiddle supports to ember 3.22 | |
this.router.currentURL; | |
// --------------------- | |
if (!this.isSameDomain) { | |
return false; | |
} | |
let routeInfo = this.hrefInfo; | |
let dynamicSegments = getParams(routeInfo); | |
return this.router.isActive( | |
routeInfo.name, | |
...dynamicSegments, | |
{ queryParams: routeInfo.queryParams } | |
); | |
} | |
@action | |
navigate(clickEvent) { | |
// if the href isn't in our app, | |
// don't prevent the default behavior | |
console.log(this.isSameDomain); | |
if (!this.isSameDomain) { | |
return true; | |
} | |
// in-app navigations should not cause the page to reload | |
clickEvent.preventDefault(); | |
this.router.transitionTo(this.href); | |
} | |
} | |
function getParams(currentRouteInfo) { | |
let params = []; | |
while (currentRouteInfo.parent) { | |
params = [currentRouteInfo.params, ...params]; | |
currentRouteInfo = currentRouteInfo.parent; | |
} | |
return params.map(Object.values).flat(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Controller from '@ember/controller'; | |
export default class CSubC extends Controller { | |
queryParams = ['applicationQP']; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Controller from '@ember/controller'; | |
export default class CSubSubC extends Controller { | |
queryParams = ['foo']; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Controller from '@ember/controller'; | |
export default class CSubC extends Controller { | |
queryParams = ['q']; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import EmberRouter from '@ember/routing/router'; | |
import config from './config/environment'; | |
export default class Router extends EmberRouter { | |
location = 'none'; | |
// rootURL is typically set to config.rootURL | |
// but in ember-twiddle, config.rootURL is `undefined` | |
rootURL = '/'; | |
} | |
Router.map(function() { | |
this.route('a'); | |
this.route('b'); | |
this.route('c', function() { | |
this.route('sub-c', { path: ':id' }, function () { | |
this.route('sub-sub-c', { path: ':dynamic-param' }); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 12px 16px; | |
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
font-size: 12pt; | |
} | |
/* Tailwind Lite*/ | |
.grid { | |
display: grid; | |
} | |
.gap-4 { | |
grid-gap: 1rem; | |
} | |
.grid-flow-col { | |
grid-auto-flow: column; | |
} | |
.text-color-red { | |
color: red; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { module, test } from 'qunit'; | |
import { setupRenderingTest } from 'ember-qunit'; | |
import { render, setupOnerror } from '@ember/test-helpers'; | |
import hbs from 'htmlbars-inline-precompile'; | |
import EmberRouter from '@ember/routing/router'; | |
module('Component | Link', function(hooks) { | |
setupRenderingTest(hooks); | |
hooks.beforeEach(function() { | |
class TestRouter extends EmberRouter {} | |
TestRouter.map(function() { | |
this.route('foo', function() { | |
this.route('bar'); | |
}); | |
}); | |
this.owner.register('router:main', TestRouter); | |
this.owner.lookup('router:main').setupRouter(); | |
}); | |
module('Argument Validity', function() { | |
module('@href', function() { | |
test('is required', async function(assert) { | |
setupOnerror(function(err) { | |
assert.equal(err.message, "Assertion Failed: @href is required"); | |
}); | |
await render(hbs`<Link />`); | |
assert.dom('a').doesNotExist(); | |
}); | |
test('cannot be relative path', async function(assert) { | |
setupOnerror(function(err) { | |
assert.ok(err.message.includes("provided @href"), err.message); | |
}); | |
await render(hbs`<Link @href="foo/bar" />`); | |
assert.dom('a').doesNotExist(); | |
}); | |
test('cannot omit a protocol', async function(assert) { | |
setupOnerror(function(err) { | |
assert.ok(err.message.includes("provided @href"), err.message); | |
}); | |
await render(hbs`<Link @href="emberjs.com/foo/bar" />`); | |
assert.dom('a').doesNotExist(); | |
}); | |
test('can be absolute', async function(assert) { | |
setupOnerror(function(err) { | |
assert.equal(err.message, "Error is unexpected"); | |
}); | |
await render(hbs`<Link @href="https://emberjs.com/foo/bar" />`); | |
assert.dom('a').exists(); | |
}); | |
test('can be protocol-relative', async function(assert) { | |
setupOnerror(function(err) { | |
assert.equal(err.message, "Error is unexpected"); | |
}); | |
await render(hbs`<Link @href="//emberjs.com/foo/bar" />`); | |
assert.dom('a').exists(); | |
}); | |
test('can be relative URL', async function(assert) { | |
setupOnerror(function(err) { | |
assert.equal(err.message, "Error is unexpected"); | |
}); | |
await render(hbs`<Link @href="/foo/bar" />`); | |
assert.dom('a').exists(); | |
}); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Application from '../app'; | |
import config from '../config/environment'; | |
import { setApplication } from '@ember/test-helpers'; | |
import { assign } from '@ember/polyfills'; | |
import { start } from 'ember-qunit'; | |
import { resetOnerror } from '@ember/test-helpers'; | |
import QUnit from 'qunit'; | |
QUnit.testDone(function() { | |
resetOnerror(); | |
}) | |
let attributes = { | |
rootElement: '#ember-testing', | |
autoboot: false | |
}; | |
attributes = assign(attributes, config.APP); | |
let application = Application.create(attributes); | |
setApplication(application); | |
start(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "0.17.2", | |
"EmberENV": { | |
"FEATURES": {}, | |
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": true, | |
"_APPLICATION_TEMPLATE_WRAPPER": false, | |
"_JQUERY_INTEGRATION": false | |
}, | |
"options": { | |
"use_pods": false, | |
"enable-testing": false | |
}, | |
"dependencies": { | |
"ember": "3.18.1", | |
"ember-template-compiler": "3.18.1", | |
"ember-testing": "3.18.1" | |
}, | |
"addons": { | |
"@glimmer/component": "1.0.0" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment