Last active
August 17, 2018 13:42
-
-
Save RomkeVdMeulen/29b8818fb673175bf316eb28da9a32ae to your computer and use it in GitHub Desktop.
An Aurelia component showing a textarea with line-numbers and locked height
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
<template> | |
<div class="element-wrapper ${invoerFocus ? 'focus' : ''} ${invoerRegels.length >= 10 ? 'vol' : ''}" | |
e2e="wrapper" data-focus.bind="invoerFocus"> | |
<ol class="regelnummers" ref="regelnummers" e2e="regelnummer-wrapper" css="height: ${hoogte + 24}px"> | |
<li repeat.for="i of aantalGetoondeRegels" e2e="regelnummer" | |
data-actief.bind="invoerRegels.length > i && invoerRegels[i].trim() !== ''" | |
class="regelnummer ${invoerRegels.length > i && invoerRegels[i].trim() !== '' ? 'actief' : ''}"></li> | |
</ol> | |
<div class="invoer-wrapper"> | |
<textarea value.bind="invoer" ref="invoerElement" e2e="invoer" | |
placeholder="${placeholder}" aria-labelledby.bind="ariaLabelledby" | |
focus.bind="invoerFocus" css="height: ${hoogte}px"></textarea> | |
</div> | |
</div> | |
</template> |
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 {bindable, bindingMode, computedFrom, observable, TaskQueue} from "aurelia-framework"; | |
import {autoinject} from "aurelia-property-injection"; | |
export class Tekstvlak { | |
private readonly REGELNUMMERS_MINIMUM = 11; | |
@autoinject | |
private taskQueue: TaskQueue; | |
@bindable | |
ariaLabelledby?: string; | |
@bindable({defaultBindingMode: bindingMode.twoWay}) | |
invoer: string; | |
@bindable | |
placeholder?: string; | |
aantalGetoondeRegels = this.REGELNUMMERS_MINIMUM; | |
@observable | |
regelnummers: HTMLElement; | |
hoogte: number; | |
@computedFrom("invoer") | |
get invoerRegels() { | |
return this.invoer.split("\n"); | |
} | |
regelnummersChanged() { | |
this.taskQueue.queueTask(this.updateHoogte.bind(this)); | |
} | |
invoerChanged() { | |
this.updateHoogte(); | |
} | |
private updateHoogte() { | |
if (!this.regelnummers) { | |
return; | |
} | |
const regel = <HTMLElement> this.regelnummers.querySelector(":first-child"); | |
const regelhoogte = regel.offsetHeight; | |
this.aantalGetoondeRegels = Math.max(this.REGELNUMMERS_MINIMUM, this.invoerRegels.length); | |
this.hoogte = this.aantalGetoondeRegels * regelhoogte; | |
} | |
} |
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
numbered-textarea { | |
display: block; | |
&::after { | |
content: ''; | |
display: block; | |
clear: both; | |
} | |
.element-wrapper { | |
height: 224px; | |
overflow-x: hidden; | |
overflow-y: hidden; | |
border: 1px solid $grijs-licht; | |
border-radius: 8px 0 0 8px; | |
&.focus { | |
outline: 3px solid $vevida-groen; | |
outline-offset: 1px; | |
} | |
&.vol { | |
overflow-y: scroll; | |
} | |
.regelnummers { | |
float: left; | |
height: 244px; | |
overflow: hidden; | |
margin: 0; | |
padding: 10px 5px 0 40px; | |
background-color: $grijs-licht; | |
line-height: 20px; | |
.regelnummer:not(.actief) { | |
color: $grijs-donker; | |
} | |
} | |
.invoer-wrapper { | |
float: right; | |
overflow: hidden; | |
width: calc(100% - 47px); | |
padding: 10px; | |
textarea { | |
width: 100%; | |
height: 220px; | |
padding: 0; | |
overflow: hidden; | |
resize: none; | |
border: none; | |
outline: none; | |
background: none; | |
line-height: 20px; | |
} | |
} | |
} | |
} |
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 {UiPart} from "bestelapp/component/helpers/uipart"; | |
export class TekstvlakUiPart extends UiPart { | |
private scopeOverride?: HTMLElement; | |
private get scope() { | |
return this.scopeOverride ? this.scopeOverride : this.component.element; | |
} | |
setScope(scope: HTMLElement) { | |
this.scopeOverride = scope; | |
} | |
get wrapper() { | |
const wrapper = this.scope.querySelector('[e2e="wrapper"]')!; | |
return { | |
get aanwezig() { | |
return wrapper !== null; | |
}, | |
get toontFocus() { | |
return wrapper.getAttribute("data-focus") === "true"; | |
}, | |
}; | |
} | |
get regelnummerWrapper() { | |
const wrapper = <HTMLElement> this.scope.querySelector('[e2e="regelnummer-wrapper"]'); | |
return { | |
get styleHoogte() { | |
return wrapper.style.height!; | |
}, | |
}; | |
} | |
get regelnummers() { | |
return [...this.scope.querySelectorAll('[e2e="regelnummer"]')].map(rn => ({ | |
get actief() { | |
return rn.getAttribute("data-actief") === "true"; | |
}, | |
})); | |
} | |
get invoer() { | |
const invoer = <HTMLTextAreaElement> this.scope.querySelector('[e2e="invoer"]'); | |
return { | |
get aanwezig() { | |
return invoer !== null; | |
}, | |
get value() { | |
return invoer.value; | |
}, | |
get styleHoogte() { | |
return invoer.style.height!; | |
}, | |
get placeholder() { | |
return invoer.placeholder; | |
}, | |
get ariaLabelledby() { | |
return invoer.getAttribute("aria-labelledby"); | |
}, | |
get gefocust() { | |
return invoer.matches(":focus"); | |
}, | |
vulIn(waarde: string) { | |
invoer.focus(); | |
invoer.value = waarde; | |
invoer.dispatchEvent(new Event("change")); | |
}, | |
}; | |
} | |
} |
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 {TekstvlakUiPart} from "bestelapp/component/aurelia/componenten/form/tekstvlak.part"; | |
import {TekstvlakTest} from "bestelapp/component/aurelia/componenten/form/tekstvlak.test"; | |
import {expect} from "chai"; | |
describe("aurelia/aurelia/componenten/form/tekstvlak", () => { | |
let test: TekstvlakTest, tekstvlak: TekstvlakUiPart; | |
beforeEach(() => { | |
test = new TekstvlakTest(); | |
test.setUp(); | |
tekstvlak = test.uiPart; | |
}); | |
afterEach(() => test.tearDown()); | |
it("toont een invoerveld met regelnummers die aangeven welke regels ingevuld staan", async () => { | |
await test.start(); | |
expect(tekstvlak.wrapper.aanwezig).to.be.true; | |
expect(tekstvlak.wrapper.toontFocus).to.be.false; | |
expect(tekstvlak.invoer.aanwezig).to.be.true; | |
expect(tekstvlak.invoer.gefocust).to.be.false; | |
expect(tekstvlak.invoer.placeholder).to.equal(test.placeholder); | |
expect(tekstvlak.invoer.ariaLabelledby).to.equal(test.ariaLabelledby); | |
expect(tekstvlak.invoer.value).to.be.empty; | |
expect(tekstvlak.regelnummers).to.be.an("array").with.lengthOf.at.least(1); | |
test.invoer = "een\ntwee"; | |
await test.wachtOpRender(); | |
expect(tekstvlak.invoer.value).to.equal("een\ntwee"); | |
expect(tekstvlak.invoer.gefocust).to.be.false; | |
expect(tekstvlak.regelnummers.slice(0, 2)).to.deep.equal([ | |
{actief: true}, | |
{actief: true}, | |
]); | |
tekstvlak.invoer.vulIn("1\n \n3\n"); | |
await test.wachtOpRender(); | |
expect(test.invoer).to.equal("1\n \n3\n"); | |
expect(tekstvlak.regelnummers.slice(0, 4)).to.deep.equal([ | |
{actief: true}, | |
{actief: false}, | |
{actief: true}, | |
{actief: false}, | |
]); | |
}); | |
it("past de hoogte van het invoerveld en de regelnummers aan op het aantal regels", async () => { | |
await test.start(); | |
test.invoer = " "; | |
await test.wachtOpRender(); | |
const rnHoogteInitieel = parseInt(tekstvlak.regelnummerWrapper.styleHoogte, 10); | |
const tvHoogteInitieel = parseInt(tekstvlak.invoer.styleHoogte, 10); | |
expect(rnHoogteInitieel).to.be.greaterThan(0); | |
expect(tvHoogteInitieel).to.be.greaterThan(0); | |
test.invoer = Array(20).join("a\n"); | |
await test.wachtOpRender(); | |
expect(parseInt(tekstvlak.regelnummerWrapper.styleHoogte, 10)).to.be.greaterThan(rnHoogteInitieel); | |
expect(parseInt(tekstvlak.invoer.styleHoogte, 10)).to.be.greaterThan(tvHoogteInitieel); | |
test.invoer = " "; | |
await test.wachtOpRender(); | |
expect(parseInt(tekstvlak.regelnummerWrapper.styleHoogte, 10)).to.equal(rnHoogteInitieel); | |
expect(parseInt(tekstvlak.invoer.styleHoogte, 10)).to.equal(tvHoogteInitieel); | |
}); | |
}); |
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 {Tekstvlak} from "bestelapp/aurelia/componenten/form/tekstvlak"; | |
import {TekstvlakUiPart} from "bestelapp/component/aurelia/componenten/form/tekstvlak.part"; | |
import {ComponentTest} from "bestelapp/component/helpers/componenttest"; | |
export class TekstvlakTest extends ComponentTest<Tekstvlak, TekstvlakUiPart> { | |
protected getComponentnaam() { return "tekstvlak"; } | |
protected getPartClass() { return TekstvlakUiPart; } | |
protected getComponentPad() { | |
return "componenten/form/tekstvlak"; | |
} | |
invoer = ""; | |
readonly placeholder = "Dit is een placeholder"; | |
readonly ariaLabelledby = "een-id"; | |
setUp() { | |
super.setUp(); | |
this.component | |
.inView('<tekstvlak invoer.bind="invoer" placeholder.bind="placeholder"' | |
+ 'aria-labelledby.bind="ariaLabelledby"></tekstvlak>') | |
.boundTo(this); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment