diff --git a/docs/en/UI/Angular/Dom-Insertion-Service.md b/docs/en/UI/Angular/Dom-Insertion-Service.md index d5ea9fe3a2..489a7a4e1f 100644 --- a/docs/en/UI/Angular/Dom-Insertion-Service.md +++ b/docs/en/UI/Angular/Dom-Insertion-Service.md @@ -35,17 +35,19 @@ class DemoComponent { constructor(private domInsertionService: DomInsertionService) {} ngOnInit() { - this.domInsertionService.insertContent( + const scriptElement = this.domInsertionService.insertContent( CONTENT_STRATEGY.AppendScriptToBody('alert()') ); } } ``` -In the example above, `` element will place at the **end** of ``. +In the example above, `` element will place at the **end** of `` and `scriptElement` will be an `HTMLScriptElement`. Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy. +> Important Note: `DomInsertionService` does not insert the same content twice. In order to add a content again, you first should remove the old content using `removeContent` method. + ### How to Insert Styles If you pass a `StyleContentStrategy` instance as the first parameter of `insertContent` method, the `DomInsertionService` will create a `` element will place at the **end** of ``. +In the example above, `` element will place at the **end** of `` and `styleElement` will be an `HTMLStyleElement`. Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy. +> Important Note: `DomInsertionService` does not insert the same content twice. In order to add a content again, you first should remove the old content using `removeContent` method. + +### How to Remove Inserted Scripts & Styles + +If you pass the inserted `HTMLScriptElement` or `HTMLStyleElement` element as the first parameter of `removeContent` method, the `DomInsertionService` will remove the given element. + +```js +import { DomInsertionService, CONTENT_STRATEGY } from '@abp/ng.core'; + +@Component({ + /* class metadata here */ +}) +class DemoComponent { + private styleElement: HTMLStyleElement; + + constructor(private domInsertionService: DomInsertionService) {} + + ngOnInit() { + this.styleElement = this.domInsertionService.insertContent( + CONTENT_STRATEGY.AppendStyleToHead('body {margin: 0;}') + ); + } + + ngOnDestroy() { + this.domInsertionService.removeContent(this.styleElement); + } +} +``` + +In the example above, `` element **will be removed** from `` when the component is destroyed. + ## API ### insertContent ```js -insertContent(contentStrategy: ContentStrategy): void +insertContent( + contentStrategy: ContentStrategy, +): T ``` - `contentStrategy` parameter is the primary focus here and is explained above. +- returns `HTMLScriptElement` or `HTMLStyleElement` based on given strategy. + +### removeContent + +```js +removeContent(element: HTMLScriptElement | HTMLStyleElement): void +``` +- `element` parameter is the inserted `HTMLScriptElement` or `HTMLStyleElement` element, which was returned by `insertContent` method. ## What's Next? diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index c3434e6e27..1307644acd 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -55,7 +55,14 @@ namespace Volo.Abp.Cli.ProjectModification if (IsAngularProject(fileDirectory)) { - await CreateNpmrcFileAsync(Path.GetDirectoryName(file)); + if (includePreviews) + { + await CreateNpmrcFileAsync(Path.GetDirectoryName(file)); + } + else if (switchToStable) + { + await DeleteNpmrcFileAsync(Path.GetDirectoryName(file)); + } } RunYarn(fileDirectory); @@ -69,11 +76,21 @@ namespace Volo.Abp.Cli.ProjectModification } } + private async Task DeleteNpmrcFileAsync(string directoryName) + { + var fileName = Path.Combine(directoryName, ".npmrc"); + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } + private async Task CreateNpmrcFileAsync(string directoryName) { var fileName = Path.Combine(directoryName, ".npmrc"); - var abpRegistry = "@abp:registry:https://www.myget.org/F/abp-nightly/npm"; + var abpRegistry = "@abp:registry=https://www.myget.org/F/abp-nightly/npm"; var voloRegistry = await GetVoloRegistryAsync(); if (File.Exists(fileName)) diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts index d4b30b731d..71f59798ae 100644 --- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts @@ -6,12 +6,23 @@ import { generateHash } from '../utils'; export class DomInsertionService { readonly inserted = new Set(); - insertContent(contentStrategy: ContentStrategy) { + insertContent( + contentStrategy: ContentStrategy, + ): T { const hash = generateHash(contentStrategy.content); if (this.inserted.has(hash)) return; - contentStrategy.insertElement(); + const element = contentStrategy.insertElement(); this.inserted.add(hash); + + return element; + } + + removeContent(element: HTMLScriptElement | HTMLStyleElement) { + const hash = generateHash(element.textContent); + this.inserted.delete(hash); + + element.parentNode.removeChild(element); } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts index 1d58f6bb3d..05261bc5e4 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts @@ -10,11 +10,13 @@ export abstract class ContentStrategy { domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {}) as any; const strategy = new StyleContentStrategy('', domStrategy, contentSecurityStrategy); - const element = strategy.createElement(); - strategy.insertElement(); + strategy.createElement(); + const element = strategy.insertElement(); expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element); expect(domStrategy.insertElement).toHaveBeenCalledWith(element); diff --git a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts index f8e8565496..556583643e 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts @@ -9,7 +9,7 @@ describe('DomInsertionService', () => { beforeEach(() => (spectator = createService())); - afterEach(() => styleElements.forEach(element => element.remove())); + afterEach(() => (document.head.innerHTML = '')); describe('#insertContent', () => { it('should be able to insert given content', () => { @@ -19,6 +19,11 @@ describe('DomInsertionService', () => { expect(styleElements[0].textContent).toBe('.test {}'); }); + it('should set a hash for the inserted content', () => { + spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}')); + expect(spectator.service.inserted.has(1437348290)).toBe(true); + }); + it('should insert only once', () => { expect(spectator.service.inserted.has(1437348290)).toBe(false); @@ -37,9 +42,25 @@ describe('DomInsertionService', () => { expect(spectator.service.inserted.has(1437348290)).toBe(true); }); - it('should be able to insert given content', () => { - spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}')); + it('should return inserted element', () => { + const element = spectator.service.insertContent( + CONTENT_STRATEGY.AppendStyleToHead('.test {}'), + ); + expect(element.tagName).toBe('STYLE'); + }); + }); + + describe('#removeContent', () => { + it('should remove inserted element and the hash for the content', () => { + expect(document.head.querySelector('style')).toBeNull(); + const element = spectator.service.insertContent( + CONTENT_STRATEGY.AppendStyleToHead('.test {}'), + ); expect(spectator.service.inserted.has(1437348290)).toBe(true); + + spectator.service.removeContent(element); + expect(spectator.service.inserted.has(1437348290)).toBe(false); + expect(document.head.querySelector('style')).toBeNull(); }); }); }); diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index b8e5be4397..65e02593f0 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "ng serve", + "start": "ng serve --open", "build": "ng build", "test": "ng test", "lint": "ng lint", diff --git a/templates/app/angular/start.ps1 b/templates/app/angular/start.ps1 new file mode 100644 index 0000000000..dac71a8164 --- /dev/null +++ b/templates/app/angular/start.ps1 @@ -0,0 +1,2 @@ +yarn +yarn start \ No newline at end of file