build(aio): migrate plunker to stackblitz (#20165)

PR Close #20165
This commit is contained in:
Jesus Rodriguez
2017-11-03 18:08:28 +01:00
committed by Miško Hevery
parent 1e9cd95f5c
commit 1a75934cc0
123 changed files with 735 additions and 1317 deletions

View File

@ -25,7 +25,7 @@ import { ContributorListComponent } from './contributor/contributor-list.compone
import { ContributorComponent } from './contributor/contributor.component';
import { CurrentLocationComponent } from './current-location.component';
import { FileNotFoundSearchComponent } from './search/file-not-found-search.component';
import { LiveExampleComponent, EmbeddedPlunkerComponent } from './live-example/live-example.component';
import { LiveExampleComponent, EmbeddedStackblitzComponent } from './live-example/live-example.component';
import { ResourceListComponent } from './resource/resource-list.component';
import { ResourceService } from './resource/resource.service';
@ -50,7 +50,7 @@ export const embeddedComponents: Type<any>[] = [
embeddedComponents,
CodeComponent,
ContributorComponent,
EmbeddedPlunkerComponent
EmbeddedStackblitzComponent
],
providers: [
ApiService,

View File

@ -1,10 +1,9 @@
<span [ngSwitch]="mode">
<span *ngSwitchCase="'disabled'">{{title}} <em>(not available on this device)</em></span>
<span *ngSwitchCase="'embedded'">
<div *ngIf="showEmbedded" title="{{title}}">
<aio-embedded-plunker [src]="plnkr"></aio-embedded-plunker>
<div title="{{title}}">
<aio-embedded-stackblitz [src]="stackblitz"></aio-embedded-stackblitz>
</div>
<img *ngIf="!showEmbedded" (click)="toggleEmbedded()" [src]="plnkrImg" alt="{{title}}">
<p *ngIf="enableDownload">
You can also <a [href]="zip" download title="Download example">download this example</a>.
</p>
@ -13,7 +12,7 @@
<a [href]="zip" download title="{{title}}">{{title}}</a>
</span>
<span *ngSwitchDefault>
<a [href]="plnkr" target="_blank" title="{{title}}">{{title}}</a>
<a [href]="stackblitz" target="_blank" title="{{title}}">{{title}}</a>
<span *ngIf="enableDownload">
/ <a [href]="zip" download title="Download example">download example</a>
</span>

View File

@ -3,12 +3,11 @@ import { By } from '@angular/platform-browser';
import { Component, DebugElement } from '@angular/core';
import { Location } from '@angular/common';
import { LiveExampleComponent, EmbeddedPlunkerComponent } from './live-example.component';
import { LiveExampleComponent, EmbeddedStackblitzComponent } from './live-example.component';
const defaultTestPath = '/test';
describe('LiveExampleComponent', () => {
let hostComponent: HostComponent;
let liveExampleDe: DebugElement;
let liveExampleComponent: LiveExampleComponent;
let fixture: ComponentFixture<HostComponent>;
@ -39,7 +38,6 @@ describe('LiveExampleComponent', () => {
function testComponent(testFn: () => void) {
fixture = TestBed.createComponent(HostComponent);
hostComponent = fixture.componentInstance;
liveExampleDe = fixture.debugElement.children[0];
liveExampleComponent = liveExampleDe.componentInstance;
@ -57,13 +55,13 @@ describe('LiveExampleComponent', () => {
//////// tests ////////
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ HostComponent, LiveExampleComponent, EmbeddedPlunkerComponent ],
declarations: [ HostComponent, LiveExampleComponent, EmbeddedStackblitzComponent ],
providers: [
{ provide: Location, useClass: TestLocation }
]
})
// Disable the <iframe> within the EmbeddedPlunkerComponent
.overrideComponent(EmbeddedPlunkerComponent, {set: {template: 'NO IFRAME'}});
// Disable the <iframe> within the EmbeddedStackblitzComponent
.overrideComponent(EmbeddedStackblitzComponent, {set: {template: 'NO IFRAME'}});
testPath = defaultTestPath;
liveExampleContent = null;
@ -78,68 +76,68 @@ describe('LiveExampleComponent', () => {
});
});
it('should have expected plunker & download hrefs', () => {
it('should have expected stackblitz & download hrefs', () => {
testPath = '/tutorial/toh-pt1';
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html');
expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html');
expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should have expected plunker & download hrefs even when path has # frag', () => {
it('should have expected stackblitz & download hrefs even when path has # frag', () => {
testPath = '/tutorial/toh-pt1#somewhere';
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html');
expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html');
expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should have expected plunker & download hrefs even when path has ? params', () => {
it('should have expected stackblitz & download hrefs even when path has ? params', () => {
testPath = '/tutorial/toh-pt1?foo=1&bar="bar"';
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html');
expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html');
expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should have expected flat-style plunker when has `flat-style`', () => {
it('should have expected flat-style stackblitz when has `flat-style`', () => {
testPath = '/tutorial/toh-pt1';
setHostTemplate('<live-example flat-style></live-example>');
testComponent(() => {
// The file should be "plnkr.html", not "eplnkr.html"
expect(getLiveExampleAnchor().href).toContain('/plnkr.html');
// The file should be "stackblitz.html", not "stackblitz.html"
expect(getLiveExampleAnchor().href).toContain('/stackblitz.html');
});
});
it('should have expected plunker & download hrefs when has example directory (name)', () => {
it('should have expected stackblitz & download hrefs when has example directory (name)', () => {
testPath = '/guide/somewhere';
setHostTemplate('<live-example name="toh-pt1"></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html');
expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html');
expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should have expected plunker & download hrefs when has `plnkr`', () => {
it('should have expected stackblitz & download hrefs when has `stackblitz`', () => {
testPath = '/testing';
setHostTemplate('<live-example plnkr="app-specs"></live-example>');
setHostTemplate('<live-example stackblitz="app-specs"></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/testing/app-specs.eplnkr.html');
expect(hrefs[0]).toContain('/testing/app-specs.stackblitz.html');
expect(hrefs[1]).toContain('/testing/app-specs.testing.zip');
});
});
it('should have expected plunker & download hrefs when has `name` & `plnkr`', () => {
it('should have expected stackblitz & download hrefs when has `name` & `stackblitz`', () => {
testPath = '/guide/somewhere';
setHostTemplate('<live-example name="testing" plnkr="app-specs"></live-example>');
setHostTemplate('<live-example name="testing" stackblitz="app-specs"></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/testing/app-specs.eplnkr.html');
expect(hrefs[0]).toContain('/testing/app-specs.stackblitz.html');
expect(hrefs[1]).toContain('/testing/app-specs.testing.zip');
});
});
@ -148,7 +146,7 @@ describe('LiveExampleComponent', () => {
setHostTemplate('<live-example></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html');
expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
});
});
@ -156,7 +154,7 @@ describe('LiveExampleComponent', () => {
setHostTemplate('<live-example flat-style></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain(defaultTestPath + '/plnkr.html');
expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
});
});
@ -164,8 +162,8 @@ describe('LiveExampleComponent', () => {
setHostTemplate('<live-example noDownload></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs.length).toBe(1, 'only the plunker live-example anchor');
expect(hrefs[0]).toContain('plnkr.html');
expect(hrefs.length).toBe(1, 'only the stackblitz live-example anchor');
expect(hrefs[0]).toContain('stackblitz.html');
});
});
@ -211,7 +209,7 @@ describe('LiveExampleComponent', () => {
setHostTemplate('<live-example name="testing/ts"></live-example>');
testComponent(() => {
const hrefs = getHrefs();
expect(hrefs[0]).toContain('/testing/ts/eplnkr.html');
expect(hrefs[0]).toContain('/testing/ts/stackblitz.html');
expect(hrefs[1]).toContain('/testing/ts/testing.zip');
});
});
@ -224,77 +222,33 @@ describe('LiveExampleComponent', () => {
return anchor && anchor.nativeElement as HTMLAnchorElement;
}
function getEmbeddedPlunkerComponent() {
const compDe = liveExampleDe.query(By.directive(EmbeddedPlunkerComponent));
return compDe && compDe.componentInstance as EmbeddedPlunkerComponent;
function getEmbeddedStackblitzComponent() {
const compDe = liveExampleDe.query(By.directive(EmbeddedStackblitzComponent));
return compDe && compDe.componentInstance as EmbeddedStackblitzComponent;
}
function getImg() {
const img = liveExampleDe.query(By.css('img'));
return img && img.nativeElement as HTMLImageElement;
}
describe('before click', () => {
it('should have hidden, embedded plunker', () => {
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded');
expect(liveExampleComponent.showEmbedded).toBe(false, 'component.showEmbedded');
expect(getEmbeddedPlunkerComponent()).toBeNull('no EmbeddedPlunkerComponent');
});
it('should have hidden, embedded stackblitz', () => {
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded');
expect(getEmbeddedStackblitzComponent()).toBeTruthy('EmbeddedStackblitzComponent');
});
it('should have default plunker placeholder image', () => {
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
expect(getImg().src).toContain('plunker/placeholder.png');
});
});
it('should have specified plunker placeholder image', () => {
const expectedSrc = 'example/demo.png';
setHostTemplate(`<live-example embedded img="${expectedSrc}"></live-example>`);
testComponent(() => {
expect(getImg().src).toContain(expectedSrc);
});
});
it('should have download paragraph with expected anchor href', () => {
testPath = '/tutorial/toh-pt1';
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
expect(getDownloadAnchor().href).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should not have download paragraph when has `nodownload`', () => {
testPath = '/tutorial/toh-pt1';
setHostTemplate('<live-example embedded nodownload></live-example>');
testComponent(() => {
expect(getDownloadAnchor()).toBeNull();
});
});
});
describe('after click', () => {
function clickImg() {
getImg().click();
fixture.detectChanges();
}
it('should show plunker in the page', () => {
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
clickImg();
expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded');
expect(liveExampleComponent.showEmbedded).toBe(true, 'component.showEmbedded');
expect(getEmbeddedPlunkerComponent()).toBeDefined('has EmbeddedPlunkerComponent');
});
it('should have download paragraph with expected anchor href', () => {
testPath = '/tutorial/toh-pt1';
setHostTemplate('<live-example embedded></live-example>');
testComponent(() => {
expect(getDownloadAnchor().href).toContain('/toh-pt1/toh-pt1.zip');
});
});
it('should not have download paragraph when has `nodownload`', () => {
testPath = '/tutorial/toh-pt1';
setHostTemplate('<live-example embedded nodownload></live-example>');
testComponent(() => {
expect(getDownloadAnchor()).toBeNull();
});
});
});
@ -306,7 +260,7 @@ describe('LiveExampleComponent', () => {
liveExampleComponent.onResize(600); // narrow
fixture.detectChanges();
const hrefs = getHrefs();
expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html');
expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
});
});
@ -316,7 +270,7 @@ describe('LiveExampleComponent', () => {
liveExampleComponent.onResize(600); // narrow
fixture.detectChanges();
const hrefs = getHrefs();
expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html');
expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
});
});
});

View File

@ -5,8 +5,6 @@ import { CONTENT_URL_PREFIX } from 'app/documents/document.service';
import { boolFromValue, getAttrs, getAttrValue } from 'app/shared/attribute-utils';
const defaultPlnkrImg = 'plunker/placeholder.png';
const imageBase = CONTENT_URL_PREFIX + 'images/';
const liveExampleBase = CONTENT_URL_PREFIX + 'live-examples/';
const zipBase = CONTENT_URL_PREFIX + 'zips/';
@ -19,49 +17,38 @@ const zipBase = CONTENT_URL_PREFIX + 'zips/';
*
* Usage:
* <live-example
* [name="..."] // name of the example directory
* [plnkr="...""] // name of the plunker file (becomes part of zip file name as well)
* [embedded] // embed the plunker in the doc page, else display in new browser tab (default)
* [img="..."] // image to display if embedded in doc page
* [embedded-style] // show plnkr in embedded style (default and on narrow screens)
* [flat-style] // show plnkr in flat (original) style
* [noDownload] // no downloadable zip option
* [downloadOnly] // just the zip
* [title="..."]> // text for live example link and tooltip
* text // higher precedence way to specify text for live example link and tooltip
* [name="..."] // name of the example directory
* [stackblitz="...""] // name of the stackblitz file (becomes part of zip file name as well)
* [embedded] // embed the stackblitz in the doc page, else display in new browser tab (default)
* [noDownload] // no downloadable zip option
* [downloadOnly] // just the zip
* [title="..."]> // text for live example link and tooltip
* text // higher precedence way to specify text for live example link and tooltip
* </live-example>
* Example:
* <p>Run <live-example>Try the live example</live-example></p>.
* // ~/resources/live-examples/{page}/plnkr.html
* // ~/resources/live-examples/{page}/stackblitz.json
*
* <p>Run <live-example name="toh-pt1">this example</live-example></p>.
* // ~/resources/live-examples/toh-pt1/plnkr.html
* // ~/resources/live-examples/toh-pt1/stackblitz.json
*
* // Link to the default plunker in the toh-pt1 sample
* // Link to the default stackblitz in the toh-pt1 sample
* // The title overrides default ("live example") with "Tour of Heroes - Part 1"
* <p>Run <live-example name="toh-pt1" title="Tour of Heroes - Part 1"></live-example></p>.
* // ~/resources/live-examples/toh-pt1/plnkr.html
* // ~/resources/live-examples/toh-pt1/stackblitz.json
*
* <p>Run <live-example plnkr="minimal"></live-example></p>.
* // ~/resources/live-examples/{page}/minimal.plnkr.html
* <p>Run <live-example stackblitz="minimal"></live-example></p>.
* // ~/resources/live-examples/{page}/minimal.stackblitz.json
*
* // Embed the current page's default plunker
* // Embed the current page's default stackblitz
* // Text within tag is "live example"
* // No title (no tooltip)
* <live-example embedded title=""></live-example>
* // ~/resources/live-examples/{page}/eplnkr.html
* // ~/resources/live-examples/{page}/stackblitz.json
*
* // Links to a *new* browser tab as an embedded style plunker editor
* <live-example embedded-style>this example</live-example>
* // ~/resources/live-examples/{page}/eplnkr.html
*
* // Links to a *new* browser tab in the flat (original editor) style plunker editor
* <live-example flat-style>this example</live-example>
* // ~/resources/live-examples/{page}/plnkr.html
*
* // Displays within the document page as an embedded style plunker editor
* <live-example name="toh-pt1" embedded plnkr="minimal" img="toh>Tour of Heroes - Part 1</live-example>
* // ~/resources/live-examples/toh-pt1/minimal.eplnkr.html
* // Displays within the document page as an embedded style stackblitz editor
* <live-example name="toh-pt1" embedded stackblitz="minimal">Tour of Heroes - Part 1</live-example>
* // ~/resources/live-examples/toh-pt1/minimal.stackblitz.json
*/
@Component({
selector: 'live-example',
@ -78,10 +65,8 @@ export class LiveExampleComponent implements OnInit {
exampleDir: string;
isEmbedded = false;
mode = 'disabled';
plnkr: string;
plnkrName: string;
plnkrImg: string;
showEmbedded = false;
stackblitz: string;
stackblitzName: string;
title: string;
zip: string;
zipName: string;
@ -98,46 +83,32 @@ export class LiveExampleComponent implements OnInit {
}
this.exampleDir = exampleDir.trim();
this.zipName = exampleDir.indexOf('/') === -1 ? this.exampleDir : exampleDir.split('/')[0];
this.plnkrName = attrs.plnkr ? attrs.plnkr.trim() + '.' : '';
this.zip = `${zipBase}${exampleDir}/${this.plnkrName}${this.zipName}.zip`;
this.stackblitzName = attrs.stackblitz ? attrs.stackblitz.trim() + '.' : '';
this.zip = `${zipBase}${exampleDir}/${this.stackblitzName}${this.zipName}.zip`;
this.enableDownload = !boolFromValue(getAttrValue(attrs, 'nodownload'));
this.plnkrImg = imageBase + (attrs.img || defaultPlnkrImg);
if (boolFromValue(getAttrValue(attrs, 'downloadonly'))) {
this.mode = 'downloadOnly';
}
}
calcPlnkrLink(width: number) {
calcStackblitzLink(width: number) {
const attrs = this.attrs;
const exampleDir = this.exampleDir;
let urlQuery = '';
let plnkrStyle = 'eplnkr'; // embedded style by default
this.mode = 'default'; // display in another browser tab by default
this.isEmbedded = boolFromValue(attrs.embedded);
if (this.isEmbedded) {
this.mode = 'embedded'; // display embedded in the doc
} else {
// Not embedded in doc page; determine if is embedded- or flat-style in another browser tab.
// Embedded style if on tiny screen (reg. plunker no good on narrow screen)
// If wide enough, choose style based on style attributes
if (width > this.narrowWidth) {
// Make flat style with `flat-style` or `embedded-style="false`; support atty aliases
const flatStyle = getAttrValue(attrs, ['flat-style', 'flatstyle']);
const isFlatStyle = boolFromValue(flatStyle);
const embeddedStyle = getAttrValue(attrs, ['embedded-style', 'embeddedstyle']);
const isEmbeddedStyle = boolFromValue(embeddedStyle, !isFlatStyle);
plnkrStyle = isEmbeddedStyle ? 'eplnkr' : 'plnkr';
}
urlQuery = '?ctl=1';
}
this.plnkr = `${liveExampleBase}${exampleDir}/${this.plnkrName}${plnkrStyle}.html`;
this.stackblitz = `${liveExampleBase}${exampleDir}/${this.stackblitzName}stackblitz.html${urlQuery}`;
}
ngOnInit() {
@ -152,31 +123,29 @@ export class LiveExampleComponent implements OnInit {
@HostListener('window:resize', ['$event.target.innerWidth'])
onResize(width: number) {
if (this.mode !== 'downloadOnly') {
this.calcPlnkrLink(width);
this.calcStackblitzLink(width);
}
}
toggleEmbedded () { this.showEmbedded = !this.showEmbedded; }
}
///// EmbeddedPlunkerComponent ///
///// EmbeddedStackblitzComponent ///
/**
* Hides the <iframe> so we can test LiveExampleComponent without actually triggering
* a call to plunker to load the iframe
* a call to stackblitz to load the iframe
*/
@Component({
selector: 'aio-embedded-plunker',
selector: 'aio-embedded-stackblitz',
template: `<iframe #iframe frameborder="0" width="100%" height="100%"></iframe>`,
styles: [ 'iframe { min-height: 400px; }']
})
export class EmbeddedPlunkerComponent implements AfterViewInit {
export class EmbeddedStackblitzComponent implements AfterViewInit {
@Input() src: string;
@ViewChild('iframe') iframe: ElementRef;
ngAfterViewInit() {
// DEVELOPMENT TESTING ONLY
// this.src = 'https://angular.io/resources/live-examples/quickstart/ts/eplnkr.html';
// this.src = 'https://angular.io/resources/live-examples/quickstart/ts/stackblitz.json';
if (this.iframe) {
// security: the `src` is always authored by the documentation team