@@ -17,7 +16,7 @@
{{title}}
- / download example
+ / download example
diff --git a/aio/src/app/custom-elements/live-example/live-example.component.spec.ts b/aio/src/app/custom-elements/live-example/live-example.component.spec.ts
index ea6209ebba..8974c4a5d3 100644
--- a/aio/src/app/custom-elements/live-example/live-example.component.spec.ts
+++ b/aio/src/app/custom-elements/live-example/live-example.component.spec.ts
@@ -43,10 +43,6 @@ describe('LiveExampleComponent', () => {
// Trigger `ngAfterContentInit()`.
fixture.detectChanges();
- // Ensure wide-screen by default.
- liveExampleComponent.onResize(1033);
- fixture.detectChanges();
-
testFn();
}
@@ -100,15 +96,6 @@ describe('LiveExampleComponent', () => {
});
});
- it('should have expected flat-style stackblitz when has `flat-style`', () => {
- testPath = '/tutorial/toh-pt1';
- setHostTemplate('
');
- testComponent(() => {
- // The file should be "stackblitz.html", not "stackblitz.html"
- expect(getLiveExampleAnchor().href).toContain('/stackblitz.html');
- });
- });
-
it('should have expected stackblitz & download hrefs when has example directory (name)', () => {
testPath = '/guide/somewhere';
setHostTemplate('
');
@@ -147,15 +134,7 @@ describe('LiveExampleComponent', () => {
});
});
- it('should be flat style when flat-style requested', () => {
- setHostTemplate('
');
- testComponent(() => {
- const hrefs = getHrefs();
- expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
- });
- });
-
- it('should not have a download link when `noDownload` atty present', () => {
+ it('should not have a download link when `noDownload` attr present', () => {
setHostTemplate('
');
testComponent(() => {
const hrefs = getHrefs();
@@ -164,7 +143,7 @@ describe('LiveExampleComponent', () => {
});
});
- it('should only have a download link when `downloadOnly` atty present', () => {
+ it('should only have a download link when `downloadOnly` attr present', () => {
setHostTemplate('
download this');
testComponent(() => {
const hrefs = getHrefs();
@@ -248,27 +227,4 @@ describe('LiveExampleComponent', () => {
});
});
});
-
- describe('when narrow display (mobile)', () => {
-
- it('should be embedded style when no style defined', () => {
- setHostTemplate('
');
- testComponent(() => {
- liveExampleComponent.onResize(600); // narrow
- fixture.detectChanges();
- const hrefs = getHrefs();
- expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
- });
- });
-
- it('should be embedded style even when flat-style requested', () => {
- setHostTemplate('
');
- testComponent(() => {
- liveExampleComponent.onResize(600); // narrow
- fixture.detectChanges();
- const hrefs = getHrefs();
- expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html');
- });
- });
- });
});
diff --git a/aio/src/app/custom-elements/live-example/live-example.component.ts b/aio/src/app/custom-elements/live-example/live-example.component.ts
index cd4efedf58..bc52ef32d3 100644
--- a/aio/src/app/custom-elements/live-example/live-example.component.ts
+++ b/aio/src/app/custom-elements/live-example/live-example.component.ts
@@ -1,131 +1,131 @@
/* tslint:disable component-selector */
-import { AfterContentInit, AfterViewInit, Component, ElementRef, HostListener, Input, ViewChild } from '@angular/core';
+import { AfterContentInit, AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
import { Location } from '@angular/common';
import { CONTENT_URL_PREFIX } from 'app/documents/document.service';
+import { AttrMap, boolFromValue, getAttrs, getAttrValue } from 'app/shared/attribute-utils';
-import { boolFromValue, getAttrs, getAttrValue } from 'app/shared/attribute-utils';
-const liveExampleBase = CONTENT_URL_PREFIX + 'live-examples/';
-const zipBase = CONTENT_URL_PREFIX + 'zips/';
+const LIVE_EXAMPLE_BASE = CONTENT_URL_PREFIX + 'live-examples/';
+const ZIP_BASE = CONTENT_URL_PREFIX + 'zips/';
/**
-* Angular.io Live Example Embedded Component
-*
-* Renders a link to a live/host example of the doc page.
-*
-* All attributes and the text content are optional
-*
-* Usage:
-*
// text for live example link and tooltip
-* text // higher precedence way to specify text for live example link and tooltip
-*
-* Example:
-*
Run Try the live example
.
-* // ~/resources/live-examples/{page}/stackblitz.json
-*
-*
Run this example
.
-* // ~/resources/live-examples/toh-pt1/stackblitz.json
-*
-* // Link to the default stackblitz in the toh-pt1 sample
-* // The title overrides default ("live example") with "Tour of Heroes - Part 1"
-*
Run
.
-* // ~/resources/live-examples/toh-pt1/stackblitz.json
-*
-*
Run
.
-* // ~/resources/live-examples/{page}/minimal.stackblitz.json
-*
-* // Embed the current page's default stackblitz
-* // Text within tag is "live example"
-* // No title (no tooltip)
-*
-* // ~/resources/live-examples/{page}/stackblitz.json
-*
-* // Displays within the document page as an embedded style stackblitz editor
-*
Tour of Heroes - Part 1
-* // ~/resources/live-examples/toh-pt1/minimal.stackblitz.json
-*/
+ * Angular.io Live Example Embedded Component
+ *
+ * Renders a link to a live/host example of the doc page.
+ *
+ * All attributes and the text content are optional
+ *
+ * Usage:
+ *
// text for live example link and tooltip
+ * text // higher precedence way to specify text for live example link and tooltip
+ *
+ * Example:
+ *
Run Try the live example
.
+ * // ~/resources/live-examples/{page}/stackblitz.json
+ *
+ *
Run this example
.
+ * // ~/resources/live-examples/toh-pt1/stackblitz.json
+ *
+ * // Link to the default stackblitz in the toh-pt1 sample
+ * // The title overrides default ("live example") with "Tour of Heroes - Part 1"
+ *
Run
.
+ * // ~/resources/live-examples/toh-pt1/stackblitz.json
+ *
+ *
Run
.
+ * // ~/resources/live-examples/{page}/minimal.stackblitz.json
+ *
+ * // Embed the current page's default stackblitz
+ * // Text within tag is "live example"
+ * // No title (no tooltip)
+ *
+ * // ~/resources/live-examples/{page}/stackblitz.json
+ *
+ * // Displays within the document page as an embedded style stackblitz editor
+ *
Tour of Heroes - Part 1
+ * // ~/resources/live-examples/toh-pt1/minimal.stackblitz.json
+ */
@Component({
selector: 'live-example',
templateUrl: 'live-example.component.html'
})
export class LiveExampleComponent implements AfterContentInit {
- // Will force to embedded-style when viewport width is narrow
- // "narrow" value was picked based on phone dimensions from http://screensiz.es/phone
- readonly narrowWidth = 1000;
-
- attrs: any;
- enableDownload = true;
- exampleDir: string;
- isEmbedded = false;
- mode = 'disabled';
- stackblitz: string;
- stackblitzName: string;
+ readonly mode: 'default' | 'embedded' | 'downloadOnly';
+ readonly enableDownload: boolean;
+ readonly stackblitz: string;
+ readonly zip: string;
title: string;
- zip: string;
- zipName: string;
@ViewChild('content')
private content: ElementRef;
- constructor(
- private elementRef: ElementRef,
- location: Location ) {
+ constructor(elementRef: ElementRef, location: Location) {
+ const attrs = getAttrs(elementRef);
+ const exampleDir = this.getExampleDir(attrs, location.path(false));
+ const stackblitzName = this.getStackblitzName(attrs);
- const attrs = this.attrs = getAttrs(this.elementRef);
- let exampleDir = attrs.name;
- if (!exampleDir) {
- // take last segment, excluding hash fragment and query params
- exampleDir = (location.path(false).match(/[^\/?\#]+(?=\/?(?:$|\#|\?))/) || [])[0];
- }
- this.exampleDir = exampleDir.trim();
- this.zipName = exampleDir.indexOf('/') === -1 ? this.exampleDir : exampleDir.split('/')[0];
- this.stackblitzName = attrs.stackblitz ? attrs.stackblitz.trim() + '.' : '';
- this.zip = `${zipBase}${exampleDir}/${this.stackblitzName}${this.zipName}.zip`;
-
- this.enableDownload = !boolFromValue(getAttrValue(attrs, 'nodownload'));
-
- if (boolFromValue(getAttrValue(attrs, 'downloadonly'))) {
- this.mode = 'downloadOnly';
- }
- }
-
- calcStackblitzLink(width: number) {
-
- const attrs = this.attrs;
- const exampleDir = this.exampleDir;
- let urlQuery = '';
-
- 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
- urlQuery = '?ctl=1';
- }
-
- this.stackblitz = `${liveExampleBase}${exampleDir}/${this.stackblitzName}stackblitz.html${urlQuery}`;
+ this.mode = this.getMode(attrs);
+ this.enableDownload = this.getEnableDownload(attrs);
+ this.stackblitz = this.getStackblitz(exampleDir, stackblitzName, this.mode === 'embedded');
+ this.zip = this.getZip(exampleDir, stackblitzName);
+ this.title = this.getTitle(attrs);
}
ngAfterContentInit() {
- // Angular will sanitize this title when displayed so should be plain text.
- const title = this.content.nativeElement.textContent;
- this.title = (title || this.attrs.title || 'live example').trim();
- this.onResize(window.innerWidth);
+ // Angular will sanitize this title when displayed, so it should be plain text.
+ const textContent = this.content.nativeElement.textContent.trim();
+ if (textContent) {
+ this.title = textContent;
+ }
}
- @HostListener('window:resize', ['$event.target.innerWidth'])
- onResize(width: number) {
- if (this.mode !== 'downloadOnly') {
- this.calcStackblitzLink(width);
+ private getEnableDownload(attrs: AttrMap) {
+ const downloadDisabled = boolFromValue(getAttrValue(attrs, 'noDownload'));
+ return !downloadDisabled;
+ }
+
+ private getExampleDir(attrs: AttrMap, path: string) {
+ let exampleDir = getAttrValue(attrs, 'name');
+ if (!exampleDir) {
+ // Take the last path segment, excluding query params and hash fragment.
+ const match = path.match(/[^/?#]+(?=\/?(?:\?|#|$))/);
+ exampleDir = match ? match[0] : 'index';
}
+ return exampleDir.trim();
+ }
+
+ private getMode(this: LiveExampleComponent, attrs: AttrMap): typeof this.mode {
+ const downloadOnly = boolFromValue(getAttrValue(attrs, 'downloadOnly'));
+ const isEmbedded = boolFromValue(getAttrValue(attrs, 'embedded'));
+
+ return downloadOnly ? 'downloadOnly'
+ : isEmbedded ? 'embedded' :
+ 'default';
+ }
+
+ private getStackblitz(exampleDir: string, stackblitzName: string, isEmbedded: boolean) {
+ const urlQuery = isEmbedded ? '?ctl=1' : '';
+ return `${LIVE_EXAMPLE_BASE}${exampleDir}/${stackblitzName}stackblitz.html${urlQuery}`;
+ }
+
+ private getStackblitzName(attrs: AttrMap) {
+ const attrValue = (getAttrValue(attrs, 'stackblitz') || '').trim();
+ return attrValue && `${attrValue}.`;
+ }
+
+ private getTitle(attrs: AttrMap) {
+ return (getAttrValue(attrs, 'title') || 'live example').trim();
+ }
+
+ private getZip(exampleDir: string, stackblitzName: string) {
+ const zipName = exampleDir.split('/')[0];
+ return `${ZIP_BASE}${exampleDir}/${stackblitzName}${zipName}.zip`;
}
}
@@ -137,7 +137,7 @@ export class LiveExampleComponent implements AfterContentInit {
@Component({
selector: 'aio-embedded-stackblitz',
template: `
`,
- styles: [ 'iframe { min-height: 400px; }']
+ styles: [ 'iframe { min-height: 400px; }' ]
})
export class EmbeddedStackblitzComponent implements AfterViewInit {
@Input() src: string;