Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle links in XML text values (#202)
* feature (viewer): handle links in XML text values * feature (viewer): add listeners for internal links * feature (viewer): add @outputs to propagate events * tests (viewer): add specs for TextValueHtmlLinkDirective * tests (viewer): add specs for TextValueHtmlLinkDirective * tests (viewer): deactivate test * docs (design docs): clarify handling of internal links * tests (viewer): reactivate test * tests (viewer): adapt test for external link * tests (viewer): adapt test for external link * refactor (viewer): rename method
- Loading branch information
1 parent
9a5b537
commit c0522e6
Showing
5 changed files
with
194 additions
and
21 deletions.
There are no files selected for viewing
This file contains 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
135 changes: 135 additions & 0 deletions
135
projects/dsp-ui/src/lib/viewer/directives/text-value-html-link.directive.spec.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { Component } from '@angular/core'; | ||
import { TextValueHtmlLinkDirective } from './text-value-html-link.directive'; | ||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { By } from '@angular/platform-browser'; | ||
|
||
/** | ||
* Test host component to simulate parent component. | ||
*/ | ||
@Component({ | ||
template: ` | ||
<div [innerHTML]="html" dspHtmlLink (internalLinkClicked)="clicked($event)" (internalLinkHovered)="hovered($event)"></div>` | ||
}) | ||
class TestHostComponent { | ||
|
||
// the href attribute of the external link is empty | ||
// because otherwise the test browser would attempt to access it | ||
html = | ||
'This is a test <a>external link</a> and a test <a class="salsah-link" href="http://rdfh.ch/0001/H6gBWUuJSuuO-CilHV8kQw">internal link</a>'; | ||
|
||
internalLinkClickedIri: string; | ||
|
||
internalLinkHoveredIri: string; | ||
|
||
clicked(iri: string) { | ||
this.internalLinkClickedIri = iri; | ||
} | ||
|
||
hovered(iri: string) { | ||
this.internalLinkHoveredIri = iri; | ||
} | ||
} | ||
|
||
describe('TextValueHtmlLinkDirective', () => { | ||
let testHostComponent: TestHostComponent; | ||
let testHostFixture: ComponentFixture<TestHostComponent>; | ||
|
||
beforeEach(async(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [ | ||
BrowserAnimationsModule | ||
], | ||
declarations: [ | ||
TextValueHtmlLinkDirective, | ||
TestHostComponent | ||
] | ||
}).compileComponents(); | ||
|
||
})); | ||
|
||
beforeEach(() => { | ||
|
||
testHostFixture = TestBed.createComponent(TestHostComponent); | ||
testHostComponent = testHostFixture.componentInstance; | ||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent).toBeTruthy(); | ||
}); | ||
|
||
it('should create an instance', () => { | ||
expect(testHostComponent).toBeTruthy(); | ||
}); | ||
|
||
it('should react to clicking on an internal link', () => { | ||
expect(testHostComponent).toBeTruthy(); | ||
|
||
const hostCompDe = testHostFixture.debugElement; | ||
const directiveDe = hostCompDe.query(By.directive(TextValueHtmlLinkDirective)); | ||
|
||
const internalLinkDe = directiveDe.query(By.css('a.salsah-link')); | ||
|
||
internalLinkDe.nativeElement.click(); | ||
|
||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent.internalLinkClickedIri).toEqual('http://rdfh.ch/0001/H6gBWUuJSuuO-CilHV8kQw'); | ||
|
||
}); | ||
|
||
it('should not react to clicking on an external link', () => { | ||
expect(testHostComponent).toBeTruthy(); | ||
|
||
const hostCompDe = testHostFixture.debugElement; | ||
const directiveDe = hostCompDe.query(By.directive(TextValueHtmlLinkDirective)); | ||
|
||
const externalLinkDe = directiveDe.query(By.css('a:not(.salsah-link)')); | ||
|
||
externalLinkDe.nativeElement.click(); | ||
|
||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent.internalLinkClickedIri).toBeUndefined(); | ||
|
||
}); | ||
|
||
it('should react to hovering over an internal link', () => { | ||
expect(testHostComponent).toBeTruthy(); | ||
|
||
const hostCompDe = testHostFixture.debugElement; | ||
const directiveDe = hostCompDe.query(By.directive(TextValueHtmlLinkDirective)); | ||
|
||
const internalLinkDe = directiveDe.query(By.css('a.salsah-link')); | ||
|
||
internalLinkDe.nativeElement.dispatchEvent(new MouseEvent('mouseover', { | ||
view: window, | ||
bubbles: true, | ||
cancelable: true | ||
})); | ||
|
||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent.internalLinkHoveredIri).toEqual('http://rdfh.ch/0001/H6gBWUuJSuuO-CilHV8kQw'); | ||
|
||
}); | ||
|
||
it('should not react to hovering over an external link', () => { | ||
expect(testHostComponent).toBeTruthy(); | ||
|
||
const hostCompDe = testHostFixture.debugElement; | ||
const directiveDe = hostCompDe.query(By.directive(TextValueHtmlLinkDirective)); | ||
|
||
const externalLinkDe = directiveDe.query(By.css('a:not(.salsah-link)')); | ||
|
||
externalLinkDe.nativeElement.dispatchEvent(new MouseEvent('mouseover', { | ||
view: window, | ||
bubbles: true, | ||
cancelable: true | ||
})); | ||
|
||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent.internalLinkHoveredIri).toBeUndefined(); | ||
|
||
}); | ||
}); |
44 changes: 44 additions & 0 deletions
44
projects/dsp-ui/src/lib/viewer/directives/text-value-html-link.directive.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Directive, EventEmitter, HostListener, Output } from '@angular/core'; | ||
import { Constants } from '@dasch-swiss/dsp-js'; | ||
|
||
@Directive({ | ||
selector: '[dspHtmlLink]' | ||
}) | ||
export class TextValueHtmlLinkDirective { | ||
|
||
@Output() internalLinkClicked = new EventEmitter<string>(); | ||
@Output() internalLinkHovered = new EventEmitter<string>(); | ||
|
||
/** | ||
* React to a click event for an internal link. | ||
* | ||
* @param targetElement the element that was clicked. | ||
*/ | ||
@HostListener('click', ['$event.target']) | ||
onClick(targetElement) { | ||
if (targetElement.nodeName.toLowerCase() === 'a' | ||
&& targetElement.className.toLowerCase().indexOf(Constants.SalsahLink) !== -1) { | ||
this.internalLinkClicked.emit(targetElement.href); | ||
|
||
// preventDefault (propagation) | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* React to a mouseover event for an internal link. | ||
* | ||
* @param targetElement the element that was hovered. | ||
*/ | ||
@HostListener('mouseover', ['$event.target']) | ||
onMouseOver(targetElement) { | ||
if (targetElement.nodeName.toLowerCase() === 'a' | ||
&& targetElement.className.toLowerCase().indexOf(Constants.SalsahLink) !== -1) { | ||
this.internalLinkHovered.emit(targetElement.href); | ||
|
||
// preventDefault (propagation) | ||
return false; | ||
} | ||
} | ||
|
||
} |
This file contains 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
This file contains 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