Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

feat: add button to copy link to example #922

Merged
merged 1 commit into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/app/shared/example-viewer/example-viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
<div class="docs-example-viewer-title" *ngIf="view !== 'snippet'">
<div class="docs-example-viewer-title-spacer">{{exampleData?.title}}</div>

<button mat-icon-button type="button" (click)="toggleCompactView()" [matTooltip]="'View snippet only'"
<button
mat-icon-button
type="button"
[attr.aria-label]="'Copy link to ' + exampleData?.title + ' example to the clipboard'"
matTooltip="Copy link to example"
(click)="_copyLink()">
<mat-icon>link</mat-icon>
</button>

<button mat-icon-button type="button" (click)="toggleCompactView()" matTooltip="View snippet only"
aria-label="View less" *ngIf="showCompactToggle">
<mat-icon>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" focusable="false">
Expand All @@ -13,7 +22,7 @@
</button>

<button mat-icon-button type="button" (click)="toggleSourceView()"
[matTooltip]="view==='demo' ? 'View code' : 'Hide code'" aria-label="View source">
[matTooltip]="view === 'demo' ? 'View code' : 'Hide code'" aria-label="View source">
<mat-icon>code</mat-icon>
</button>

Expand All @@ -25,7 +34,7 @@
<mat-tab *ngFor="let tabName of _getExampleTabNames()" [label]="tabName">
<div class="button-bar">
<button mat-icon-button type="button" (click)="copySource(snippet.toArray()[selectedTab].viewer.textContent)"
class="docs-example-source-copy docs-example-button" [matTooltip]="'Copy example source'"
class="docs-example-source-copy docs-example-button" matTooltip="Copy example source"
title="Copy example source" aria-label="Copy example source to clipboard">
<mat-icon>content_copy</mat-icon>
</button>
Expand All @@ -38,12 +47,12 @@
<div class="docs-example-viewer-source-compact" *ngIf="view === 'snippet'">
<div class="button-bar">
<button mat-icon-button type="button" (click)="copySource(snippet.first.viewer.textContent)"
class="docs-example-source-copy docs-example-button" [matTooltip]="'Copy snippet'"
class="docs-example-source-copy docs-example-button" matTooltip="Copy snippet"
title="Copy example source" aria-label="Copy example source to clipboard">
<mat-icon>content_copy</mat-icon>
</button>
<button mat-icon-button type="button" (click)="toggleCompactView()"
class="docs-example-compact-toggle docs-example-button" [matTooltip]="'View full example'"
class="docs-example-compact-toggle docs-example-button" matTooltip="View full example"
aria-label="View less">
<mat-icon>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" focusable="false">
Expand Down
28 changes: 26 additions & 2 deletions src/app/shared/example-viewer/example-viewer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {
Component,
ElementRef,
HostBinding,
Input,
NgModuleFactory, OnInit, QueryList,
NgModuleFactory,
OnInit,
QueryList,
Type,
ViewChildren,
ɵNgModuleFactory
Expand Down Expand Up @@ -53,6 +57,7 @@ export class ExampleViewer implements OnInit {
@Input() showCompactToggle = false;

/** String key of the currently displayed example. */
@HostBinding('attr.id')
@Input()
get example() { return this._example; }
set example(exampleName: string) {
Expand All @@ -75,7 +80,8 @@ export class ExampleViewer implements OnInit {

constructor(
private readonly snackbar: MatSnackBar,
private readonly clipboard: Clipboard) {}
private readonly clipboard: Clipboard,
private readonly elementRef: ElementRef<HTMLElement>) {}

ngOnInit() {
if (this.file) {
Expand Down Expand Up @@ -152,6 +158,17 @@ export class ExampleViewer implements OnInit {
});
}

_copyLink() {
// Reconstruct the URL using `origin + pathname` so we drop any pre-existing hash.
const fullUrl = location.origin + location.pathname + '#' + this._example;

if (this.clipboard.copy(fullUrl)) {
this.snackbar.open('Link copied', '', {duration: 2500});
} else {
this.snackbar.open('Link copy failed. Please try again!', '', {duration: 2500});
}
}

/** Loads the component and module factory for the currently selected example. */
private async _loadExampleComponent() {
const {componentName, module} = EXAMPLE_COMPONENTS[this._example];
Expand All @@ -170,6 +187,13 @@ export class ExampleViewer implements OnInit {
// class symbol to Ivy's module factory constructor. There is no equivalent for View Engine,
// where factories are stored in separate files. Hence the API is currently Ivy-only.
this._exampleModuleFactory = new ɵNgModuleFactory(moduleExports[module.name]);

// Since the data is loaded asynchronously, we can't count on the native behavior
// that scrolls the element into view automatically. We do it ourselves while giving
// the page some time to render.
if (typeof location !== 'undefined' && location.hash.slice(1) === this._example) {
setTimeout(() => this.elementRef.nativeElement.scrollIntoView(), 300);
}
}

private _generateExampleTabs() {
Expand Down