Merge pull request #109 from ing-bank/fix/containFocusForContentNode
fix(overlays): trapsKeyboardFocus should work with contentNode
This commit is contained in:
commit
d00439a24c
3 changed files with 154 additions and 80 deletions
|
|
@ -15,24 +15,48 @@ export class LocalOverlayController {
|
||||||
this.trapsKeyboardFocus = finalParams.trapsKeyboardFocus;
|
this.trapsKeyboardFocus = finalParams.trapsKeyboardFocus;
|
||||||
this.placement = finalParams.placement;
|
this.placement = finalParams.placement;
|
||||||
this.position = finalParams.position;
|
this.position = finalParams.position;
|
||||||
|
/**
|
||||||
|
* A wrapper to render into the invokerTemplate
|
||||||
|
*
|
||||||
|
* @property {HTMLElement}
|
||||||
|
*/
|
||||||
this.invoker = document.createElement('div');
|
this.invoker = document.createElement('div');
|
||||||
this.invoker.style.display = 'inline-block';
|
this.invoker.style.display = 'inline-block';
|
||||||
|
this.invokerTemplate = finalParams.invokerTemplate;
|
||||||
|
/**
|
||||||
|
* The actual invoker element we work with - it get's all the events and a11y
|
||||||
|
*
|
||||||
|
* @property {HTMLElement}
|
||||||
|
*/
|
||||||
|
this.invokerNode = this.invoker;
|
||||||
|
if (finalParams.invokerNode) {
|
||||||
|
this.invokerNode = finalParams.invokerNode;
|
||||||
|
this.invoker = this.invokerNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper the contentTemplate renders into
|
||||||
|
*
|
||||||
|
* @property {HTMLElement}
|
||||||
|
*/
|
||||||
this.content = document.createElement('div');
|
this.content = document.createElement('div');
|
||||||
this.content.style.display = 'inline-block';
|
this.content.style.display = 'inline-block';
|
||||||
|
this.contentTemplate = finalParams.contentTemplate;
|
||||||
|
this.contentNode = this.content;
|
||||||
|
if (finalParams.contentNode) {
|
||||||
|
this.contentNode = finalParams.contentNode;
|
||||||
|
this.content = this.contentNode;
|
||||||
|
}
|
||||||
|
|
||||||
this.contentId = `overlay-content-${Math.random()
|
this.contentId = `overlay-content-${Math.random()
|
||||||
.toString(36)
|
.toString(36)
|
||||||
.substr(2, 10)}`;
|
.substr(2, 10)}`;
|
||||||
this._contentData = {};
|
this._contentData = {};
|
||||||
this.invokerTemplate = finalParams.invokerTemplate;
|
|
||||||
this.invokerNode = finalParams.invokerNode;
|
|
||||||
this.contentTemplate = finalParams.contentTemplate;
|
|
||||||
this.contentNode = finalParams.contentNode;
|
|
||||||
this.syncInvoker();
|
this.syncInvoker();
|
||||||
this._updateContent();
|
this._updateContent();
|
||||||
this._prevShown = false;
|
this._prevShown = false;
|
||||||
this._prevData = {};
|
this._prevData = {};
|
||||||
|
this.__boundEscKeyHandler = this.__escKeyHandler.bind(this);
|
||||||
if (this.hidesOnEsc) this._setupHidesOnEsc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get isShown() {
|
get isShown() {
|
||||||
|
|
@ -109,10 +133,12 @@ export class LocalOverlayController {
|
||||||
|
|
||||||
if (this.trapsKeyboardFocus) this._setupTrapsKeyboardFocus();
|
if (this.trapsKeyboardFocus) this._setupTrapsKeyboardFocus();
|
||||||
if (this.hidesOnOutsideClick) this._setupHidesOnOutsideClick();
|
if (this.hidesOnOutsideClick) this._setupHidesOnOutsideClick();
|
||||||
|
if (this.hidesOnEsc) this._setupHidesOnEsc();
|
||||||
} else {
|
} else {
|
||||||
this._updateContent();
|
this._updateContent();
|
||||||
this.invokerNode.setAttribute('aria-expanded', false);
|
this.invokerNode.setAttribute('aria-expanded', false);
|
||||||
if (this.hidesOnOutsideClick) this._teardownHidesOnOutsideClick();
|
if (this.hidesOnOutsideClick) this._teardownHidesOnOutsideClick();
|
||||||
|
if (this.hidesOnEsc) this._teardownHidesOnEsc();
|
||||||
}
|
}
|
||||||
this._prevShown = shown;
|
this._prevShown = shown;
|
||||||
this._prevData = data;
|
this._prevData = data;
|
||||||
|
|
@ -127,15 +153,15 @@ export class LocalOverlayController {
|
||||||
this._containFocusHandler.disconnect();
|
this._containFocusHandler.disconnect();
|
||||||
this._containFocusHandler = undefined; // eslint-disable-line no-param-reassign
|
this._containFocusHandler = undefined; // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
this._containFocusHandler = containFocus(this.content.firstElementChild);
|
this._containFocusHandler = containFocus(this.contentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setupHidesOnEsc() {
|
_setupHidesOnEsc() {
|
||||||
this.content.addEventListener('keyup', event => {
|
this.contentNode.addEventListener('keyup', this.__boundEscKeyHandler);
|
||||||
if (event.keyCode === keyCodes.escape) {
|
}
|
||||||
this.hide();
|
|
||||||
}
|
_teardownHidesOnEsc() {
|
||||||
});
|
this.contentNode.removeEventListener('keyup', this.__boundEscKeyHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setupHidesOnOutsideClick() {
|
_setupHidesOnOutsideClick() {
|
||||||
|
|
@ -162,14 +188,14 @@ export class LocalOverlayController {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.content.addEventListener('click', this.__preventCloseOutsideClick, true);
|
this.contentNode.addEventListener('click', this.__preventCloseOutsideClick, true);
|
||||||
this.invoker.addEventListener('click', this.__preventCloseOutsideClick, true);
|
this.invokerNode.addEventListener('click', this.__preventCloseOutsideClick, true);
|
||||||
document.documentElement.addEventListener('click', this.__onCaptureHtmlClick, true);
|
document.documentElement.addEventListener('click', this.__onCaptureHtmlClick, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_teardownHidesOnOutsideClick() {
|
_teardownHidesOnOutsideClick() {
|
||||||
this.content.removeEventListener('click', this.__preventCloseOutsideClick, true);
|
this.contentNode.removeEventListener('click', this.__preventCloseOutsideClick, true);
|
||||||
this.invoker.removeEventListener('click', this.__preventCloseOutsideClick, true);
|
this.invokerNode.removeEventListener('click', this.__preventCloseOutsideClick, true);
|
||||||
document.documentElement.removeEventListener('click', this.__onCaptureHtmlClick, true);
|
document.documentElement.removeEventListener('click', this.__onCaptureHtmlClick, true);
|
||||||
this.__preventCloseOutsideClick = null;
|
this.__preventCloseOutsideClick = null;
|
||||||
this.__onCaptureHtmlClick = null;
|
this.__onCaptureHtmlClick = null;
|
||||||
|
|
@ -182,4 +208,10 @@ export class LocalOverlayController {
|
||||||
this.contentNode.style.display = 'none';
|
this.contentNode.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__escKeyHandler(e) {
|
||||||
|
if (e.keyCode === keyCodes.escape) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () =>
|
invokerTemplate: () =>
|
||||||
html`
|
html`
|
||||||
<button @click=${() => popup.show()}>UK</button>
|
<button @click=${() => popup.toggle()}>UK</button>
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -62,7 +62,7 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () =>
|
invokerTemplate: () =>
|
||||||
html`
|
html`
|
||||||
<button @click=${() => popup.show()}>UK</button>
|
<button @click=${() => popup.toggle()}>UK</button>
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -88,7 +88,7 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () =>
|
invokerTemplate: () =>
|
||||||
html`
|
html`
|
||||||
<button @click=${() => popup.show()}>Click me</button>
|
<button @click=${() => popup.toggle()}>Click me</button>
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -153,30 +153,6 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
.add('On toggle', () => {
|
|
||||||
const popup = overlays.add(
|
|
||||||
new LocalOverlayController({
|
|
||||||
hidesOnEsc: true,
|
|
||||||
hidesOnOutsideClick: true,
|
|
||||||
contentTemplate: () =>
|
|
||||||
html`
|
|
||||||
<div class="demo-popup">United Kingdom</div>
|
|
||||||
`,
|
|
||||||
invokerTemplate: () =>
|
|
||||||
html`
|
|
||||||
<button @click=${() => popup.toggle()}>UK</button>
|
|
||||||
`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
${popupDemoStyle}
|
|
||||||
</style>
|
|
||||||
<div class="demo-box">
|
|
||||||
<label for="input">Weather in ${popup.invoker}${popup.content} toggles.</label>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})
|
|
||||||
.add('trapsKeyboardFocus', () => {
|
.add('trapsKeyboardFocus', () => {
|
||||||
const popup = overlays.add(
|
const popup = overlays.add(
|
||||||
new LocalOverlayController({
|
new LocalOverlayController({
|
||||||
|
|
@ -198,7 +174,7 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () =>
|
invokerTemplate: () =>
|
||||||
html`
|
html`
|
||||||
<button @click=${() => popup.show()}>UK</button>
|
<button @click=${() => popup.toggle()}>UK</button>
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -210,4 +186,38 @@ storiesOf('Local Overlay System|Local Overlay', module)
|
||||||
${popup.invoker}${popup.content}
|
${popup.invoker}${popup.content}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
})
|
||||||
|
.add('trapsKeyboardFocus with nodes', () => {
|
||||||
|
const invokerNode = document.createElement('button');
|
||||||
|
invokerNode.innerHTML = 'Invoker Button';
|
||||||
|
|
||||||
|
const contentNode = document.createElement('div');
|
||||||
|
contentNode.classList.add('demo-popup');
|
||||||
|
const contentButton = document.createElement('button');
|
||||||
|
contentButton.innerHTML = 'Content Button';
|
||||||
|
const contentInput = document.createElement('input');
|
||||||
|
contentNode.appendChild(contentButton);
|
||||||
|
contentNode.appendChild(contentInput);
|
||||||
|
|
||||||
|
const popup = overlays.add(
|
||||||
|
new LocalOverlayController({
|
||||||
|
hidesOnEsc: true,
|
||||||
|
hidesOnOutsideClick: true,
|
||||||
|
trapsKeyboardFocus: true,
|
||||||
|
contentNode,
|
||||||
|
invokerNode,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
invokerNode.addEventListener('click', () => {
|
||||||
|
popup.toggle();
|
||||||
|
});
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
${popupDemoStyle}
|
||||||
|
</style>
|
||||||
|
<div class="demo-box">
|
||||||
|
${popup.invoker}${popup.content}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ describe('LocalOverlayController', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
controller.show();
|
controller.show();
|
||||||
expect(controller.content.firstElementChild.style.top).to.equal('8px');
|
expect(controller.contentNode.style.top).to.equal('8px');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses top as the default placement', async () => {
|
it('uses top as the default placement', async () => {
|
||||||
|
|
@ -218,7 +218,9 @@ describe('LocalOverlayController', () => {
|
||||||
<p>Content</p>
|
<p>Content</p>
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () => html`
|
invokerTemplate: () => html`
|
||||||
<button style="padding: 16px;" @click=${() => controller.show()}>Invoker</button>
|
<button style="padding: 16px;" @click=${() => controller.show()}>
|
||||||
|
Invoker
|
||||||
|
</button>
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
|
|
@ -227,15 +229,17 @@ describe('LocalOverlayController', () => {
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
controller.show();
|
controller.show();
|
||||||
const invokerChild = controller.content.firstElementChild;
|
const { contentNode } = controller;
|
||||||
expect(invokerChild.getAttribute('js-positioning-vertical')).to.equal('top');
|
expect(contentNode.getAttribute('js-positioning-vertical')).to.equal('top');
|
||||||
expect(invokerChild.getAttribute('js-positioning-horizontal')).to.equal('centerHorizontal');
|
expect(contentNode.getAttribute('js-positioning-horizontal')).to.equal('centerHorizontal');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('positions to preferred place if placement is set and space is available', async () => {
|
it('positions to preferred place if placement is set and space is available', async () => {
|
||||||
const controller = new LocalOverlayController({
|
const controller = new LocalOverlayController({
|
||||||
invokerTemplate: () => html`
|
invokerTemplate: () => html`
|
||||||
<button style="padding: 16px;" @click=${() => controller.show()}>Invoker</button>
|
<button style="padding: 16px;" @click=${() => controller.show()}>
|
||||||
|
Invoker
|
||||||
|
</button>
|
||||||
`,
|
`,
|
||||||
contentTemplate: () =>
|
contentTemplate: () =>
|
||||||
html`
|
html`
|
||||||
|
|
@ -250,9 +254,9 @@ describe('LocalOverlayController', () => {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
controller.show();
|
controller.show();
|
||||||
const contentChild = controller.content.firstElementChild;
|
const { contentNode } = controller;
|
||||||
expect(contentChild.getAttribute('js-positioning-vertical')).to.equal('top');
|
expect(contentNode.getAttribute('js-positioning-vertical')).to.equal('top');
|
||||||
expect(contentChild.getAttribute('js-positioning-horizontal')).to.equal('right');
|
expect(contentNode.getAttribute('js-positioning-horizontal')).to.equal('right');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('positions to different place if placement is set and no space is available', async () => {
|
it('positions to different place if placement is set and no space is available', async () => {
|
||||||
|
|
@ -262,7 +266,9 @@ describe('LocalOverlayController', () => {
|
||||||
<p>Content</p>
|
<p>Content</p>
|
||||||
`,
|
`,
|
||||||
invokerTemplate: () => html`
|
invokerTemplate: () => html`
|
||||||
<button style="padding: 16px;" @click=${() => controller.show()}>Invoker</button>
|
<button style="padding: 16px;" @click=${() => controller.show()}>
|
||||||
|
Invoker
|
||||||
|
</button>
|
||||||
`,
|
`,
|
||||||
placement: 'top right',
|
placement: 'top right',
|
||||||
});
|
});
|
||||||
|
|
@ -273,9 +279,9 @@ describe('LocalOverlayController', () => {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
controller.show();
|
controller.show();
|
||||||
const invokerChild = controller.content.firstElementChild;
|
const { contentNode } = controller;
|
||||||
expect(invokerChild.getAttribute('js-positioning-vertical')).to.equal('bottom');
|
expect(contentNode.getAttribute('js-positioning-vertical')).to.equal('bottom');
|
||||||
expect(invokerChild.getAttribute('js-positioning-horizontal')).to.equal('right');
|
expect(contentNode.getAttribute('js-positioning-horizontal')).to.equal('right');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -292,14 +298,14 @@ describe('LocalOverlayController', () => {
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(controller.invoker.firstElementChild.getAttribute('aria-controls')).to.contain(
|
expect(controller.invokerNode.getAttribute('aria-controls')).to.contain(
|
||||||
controller.content.id,
|
controller.content.id,
|
||||||
);
|
);
|
||||||
expect(controller.invoker.firstElementChild.getAttribute('aria-expanded')).to.equal('false');
|
expect(controller.invokerNode.getAttribute('aria-expanded')).to.equal('false');
|
||||||
controller.show();
|
controller.show();
|
||||||
expect(controller.invoker.firstElementChild.getAttribute('aria-expanded')).to.equal('true');
|
expect(controller.invokerNode.getAttribute('aria-expanded')).to.equal('true');
|
||||||
controller.hide();
|
controller.hide();
|
||||||
expect(controller.invoker.firstElementChild.getAttribute('aria-expanded')).to.equal('false');
|
expect(controller.invokerNode.getAttribute('aria-expanded')).to.equal('false');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('traps the focus via option { trapsKeyboardFocus: true }', async () => {
|
it('traps the focus via option { trapsKeyboardFocus: true }', async () => {
|
||||||
|
|
@ -317,17 +323,45 @@ describe('LocalOverlayController', () => {
|
||||||
trapsKeyboardFocus: true,
|
trapsKeyboardFocus: true,
|
||||||
});
|
});
|
||||||
// make sure we're connected to the dom
|
// make sure we're connected to the dom
|
||||||
await fixture(
|
await fixture(html`
|
||||||
html`
|
${controller.invoker}${controller.content}
|
||||||
${controller.invoker}${controller.content}
|
`);
|
||||||
`,
|
|
||||||
);
|
|
||||||
controller.show();
|
controller.show();
|
||||||
|
|
||||||
const elOutside = await fixture(`<button>click me</button>`);
|
const elOutside = await fixture(`<button>click me</button>`);
|
||||||
const [el1, el2] = [].slice.call(
|
const [el1, el2] = [].slice.call(controller.contentNode.querySelectorAll('[id]'));
|
||||||
controller.content.firstElementChild.querySelectorAll('[id]'),
|
el2.focus();
|
||||||
);
|
// this mimics a tab within the contain-focus system used
|
||||||
|
const event = new CustomEvent('keydown', { detail: 0, bubbles: true });
|
||||||
|
event.keyCode = keyCodes.tab;
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
|
||||||
|
expect(elOutside).to.not.equal(document.activeElement);
|
||||||
|
expect(el1).to.equal(document.activeElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('traps the focus via option { trapsKeyboardFocus: true } when using contentNode', async () => {
|
||||||
|
const invokerNode = await fixture('<button>Invoker</button>');
|
||||||
|
const contentNode = await fixture(`
|
||||||
|
<div>
|
||||||
|
<button id="el1">Button</button>
|
||||||
|
<a id="el2" href="#">Anchor</a>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
const controller = new LocalOverlayController({
|
||||||
|
contentNode,
|
||||||
|
invokerNode,
|
||||||
|
trapsKeyboardFocus: true,
|
||||||
|
});
|
||||||
|
// make sure we're connected to the dom
|
||||||
|
await fixture(html`
|
||||||
|
${controller.invoker}${controller.content}
|
||||||
|
`);
|
||||||
|
controller.show();
|
||||||
|
|
||||||
|
const elOutside = await fixture(`<button>click me</button>`);
|
||||||
|
const [el1, el2] = [].slice.call(controller.contentNode.querySelectorAll('[id]'));
|
||||||
|
|
||||||
el2.focus();
|
el2.focus();
|
||||||
// this mimics a tab within the contain-focus system used
|
// this mimics a tab within the contain-focus system used
|
||||||
|
|
@ -360,7 +394,7 @@ describe('LocalOverlayController', () => {
|
||||||
);
|
);
|
||||||
const elOutside = await fixture(`<button>click me</button>`);
|
const elOutside = await fixture(`<button>click me</button>`);
|
||||||
controller.show();
|
controller.show();
|
||||||
const el1 = controller.content.firstElementChild.querySelector('button');
|
const el1 = controller.content.querySelector('button');
|
||||||
|
|
||||||
el1.focus();
|
el1.focus();
|
||||||
simulateTab();
|
simulateTab();
|
||||||
|
|
@ -388,7 +422,7 @@ describe('LocalOverlayController', () => {
|
||||||
);
|
);
|
||||||
ctrl.show();
|
ctrl.show();
|
||||||
|
|
||||||
keyUpOn(ctrl.content, keyCodes.escape);
|
keyUpOn(ctrl.contentNode, keyCodes.escape);
|
||||||
ctrl.updateComplete;
|
ctrl.updateComplete;
|
||||||
expect(ctrl.isShown).to.equal(false);
|
expect(ctrl.isShown).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
@ -457,25 +491,23 @@ describe('LocalOverlayController', () => {
|
||||||
<button @click="${() => ctrl.show()}">Invoker</button>
|
<button @click="${() => ctrl.show()}">Invoker</button>
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
const { content, invoker, invokerNode } = ctrl;
|
const { content, invoker } = ctrl;
|
||||||
await fixture(
|
await fixture(html`
|
||||||
html`
|
${invoker}${content}
|
||||||
${invoker}${content}
|
`);
|
||||||
`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Don't hide on first invoker click
|
// Don't hide on first invoker click
|
||||||
invokerNode.click();
|
ctrl.invokerNode.click();
|
||||||
await aTimeout();
|
await aTimeout();
|
||||||
expect(ctrl.isShown).to.equal(true);
|
expect(ctrl.isShown).to.equal(true);
|
||||||
|
|
||||||
// Don't hide on inside (content) click
|
// Don't hide on inside (content) click
|
||||||
content.click();
|
ctrl.contentNode.click();
|
||||||
await aTimeout();
|
await aTimeout();
|
||||||
expect(ctrl.isShown).to.equal(true);
|
expect(ctrl.isShown).to.equal(true);
|
||||||
|
|
||||||
// Don't hide on invoker click when shown
|
// Don't hide on invoker click when shown
|
||||||
invokerNode.click();
|
ctrl.invokerNode.click();
|
||||||
await aTimeout();
|
await aTimeout();
|
||||||
expect(ctrl.isShown).to.equal(true);
|
expect(ctrl.isShown).to.equal(true);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue