From 1c9839e91de42292d5b6076f3260aa0acb0b5f3f Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Thu, 17 May 2018 13:13:47 +0300 Subject: [PATCH] fix(aio): allow setting live-example title from content (#23960) Previously, it was possible to set the live-example title as content in the `` element. This relied on our custom loader functionality that extracted the content from the DOM element before passing it to the Angular compiler and stored it on a property for later retrieval. Since we switched to custom elements (and got rid of the custom loader), the property is no longer populated with the contents. As a result, many live examples show the default title ("live example") instead of the one specified as content. This commit fixes it by projecting the content into an invisible node for later retrieval (similar to what we do in other components, such as the `CodeExampleComponent`). PR Close #23960 --- .../live-example/live-example.component.html | 3 +++ .../live-example.component.spec.ts | 19 ++++++++----------- .../live-example/live-example.component.ts | 13 +++++++------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/aio/src/app/custom-elements/live-example/live-example.component.html b/aio/src/app/custom-elements/live-example/live-example.component.html index b5da2b8c90..a1537bfdc4 100644 --- a/aio/src/app/custom-elements/live-example/live-example.component.html +++ b/aio/src/app/custom-elements/live-example/live-example.component.html @@ -1,3 +1,6 @@ + + + {{title}} (not available on this device) 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 9879f0e69e..ea6209ebba 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 @@ -12,7 +12,6 @@ describe('LiveExampleComponent', () => { let liveExampleComponent: LiveExampleComponent; let fixture: ComponentFixture; let testPath: string; - let liveExampleContent: string|null; //////// test helpers //////// @@ -41,12 +40,11 @@ describe('LiveExampleComponent', () => { liveExampleDe = fixture.debugElement.children[0]; liveExampleComponent = liveExampleDe.componentInstance; - // Copy the LiveExample's innerHTML (content) - // into the `liveExampleContent` property as the DocViewer does - liveExampleDe.nativeElement.liveExampleContent = liveExampleContent; - + // Trigger `ngAfterContentInit()`. fixture.detectChanges(); - liveExampleComponent.onResize(1033); // wide by default + + // Ensure wide-screen by default. + liveExampleComponent.onResize(1033); fixture.detectChanges(); testFn(); @@ -64,7 +62,6 @@ describe('LiveExampleComponent', () => { .overrideComponent(EmbeddedStackblitzComponent, {set: {template: 'NO IFRAME'}}); testPath = defaultTestPath; - liveExampleContent = null; }); describe('when not embedded', () => { @@ -196,12 +193,12 @@ describe('LiveExampleComponent', () => { }); it('should add title from body', () => { - liveExampleContent = 'The Greatest Example'; - setHostTemplate(''); + const expectedTitle = 'The Greatest Example'; + setHostTemplate(`${expectedTitle}`); testComponent(() => { const anchor = getLiveExampleAnchor(); - expect(anchor.textContent).toBe(liveExampleContent, 'anchor content'); - expect(anchor.getAttribute('title')).toBe(liveExampleContent, 'title'); + expect(anchor.textContent).toBe(expectedTitle, 'anchor content'); + expect(anchor.getAttribute('title')).toBe(expectedTitle, 'title'); }); }); 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 9a19663224..cd4efedf58 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,5 +1,5 @@ /* tslint:disable component-selector */ -import { Component, ElementRef, HostListener, Input, OnInit, AfterViewInit, ViewChild } from '@angular/core'; +import { AfterContentInit, AfterViewInit, Component, ElementRef, HostListener, Input, ViewChild } from '@angular/core'; import { Location } from '@angular/common'; import { CONTENT_URL_PREFIX } from 'app/documents/document.service'; @@ -54,7 +54,7 @@ const zipBase = CONTENT_URL_PREFIX + 'zips/'; selector: 'live-example', templateUrl: 'live-example.component.html' }) -export class LiveExampleComponent implements OnInit { +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 @@ -71,6 +71,9 @@ export class LiveExampleComponent implements OnInit { zip: string; zipName: string; + @ViewChild('content') + private content: ElementRef; + constructor( private elementRef: ElementRef, location: Location ) { @@ -111,11 +114,9 @@ export class LiveExampleComponent implements OnInit { this.stackblitz = `${liveExampleBase}${exampleDir}/${this.stackblitzName}stackblitz.html${urlQuery}`; } - ngOnInit() { - // The `liveExampleContent` property is set by the DocViewer when it builds this component. - // It is the original innerHTML of the host element. + ngAfterContentInit() { // Angular will sanitize this title when displayed so should be plain text. - const title = this.elementRef.nativeElement.liveExampleContent; + const title = this.content.nativeElement.textContent; this.title = (title || this.attrs.title || 'live example').trim(); this.onResize(window.innerWidth); }