diff --git a/guides/schematics.md b/guides/schematics.md index 859e79be370b..002f87cc0924 100644 --- a/guides/schematics.md +++ b/guides/schematics.md @@ -20,7 +20,7 @@ This schematic will: - Add Prebuilt or Setup Custom Theme - Add Roboto fonts to your index.html - Apply simple CSS reset to body - +- Install and load `hammerjs` for gestures in your project. ## Generator Schematics In addition to the install schematic, Angular Material has three schematics it comes packaged with: diff --git a/src/lib/schematics/install/gestures/hammerjs-import.ts b/src/lib/schematics/install/gestures/hammerjs-import.ts new file mode 100644 index 000000000000..586cdf90d1ab --- /dev/null +++ b/src/lib/schematics/install/gestures/hammerjs-import.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Rule, Tree} from '@angular-devkit/schematics'; +import {getWorkspace} from '@schematics/angular/utility/config'; +import {getProjectFromWorkspace} from '../../utils/get-project'; +import {Schema} from '../schema'; +import {getProjectMainFile} from './project-main-file'; + +const hammerjsImportStatement = `import 'hammerjs';`; + +/** Adds HammerJS to the main file of the specified Angular CLI project. */ +export function addHammerJsToMain(options: Schema): Rule { + return (host: Tree) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace(workspace, options.project); + const mainFile = getProjectMainFile(project); + + const recorder = host.beginUpdate(mainFile); + const buffer = host.read(mainFile); + + if (!buffer) { + return console.error(`Could not read the project main file (${mainFile}). Please manually ` + + `import HammerJS in your main TypeScript file.`); + } + + const fileContent = buffer.toString('utf8'); + + if (fileContent.includes(hammerjsImportStatement)) { + return console.log(`HammerJS is already imported in the project main file (${mainFile}).`); + } + + recorder.insertRight(0, `${hammerjsImportStatement}\n`); + host.commitUpdate(recorder); + }; +} diff --git a/src/lib/schematics/install/gestures/project-main-file.ts b/src/lib/schematics/install/gestures/project-main-file.ts new file mode 100644 index 000000000000..14ce6f603e02 --- /dev/null +++ b/src/lib/schematics/install/gestures/project-main-file.ts @@ -0,0 +1,22 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {SchematicsException} from '@angular-devkit/schematics'; +import {WorkspaceProject} from '@schematics/angular/utility/config'; + +/** Looks for the main TypeScript file in the given project and returns its path. */ +export function getProjectMainFile(project: WorkspaceProject): string { + const buildTarget = project.architect.build.options; + + if (buildTarget.main) { + return buildTarget.main; + } + + throw new SchematicsException( + 'Could not find the project main file inside of the workspace config.'); +} diff --git a/src/lib/schematics/install/index.spec.ts b/src/lib/schematics/install/index.spec.ts index 6047c5615541..b3b52f7d5ff4 100644 --- a/src/lib/schematics/install/index.spec.ts +++ b/src/lib/schematics/install/index.spec.ts @@ -34,10 +34,19 @@ describe('material-install-schematic', () => { expect(packageJson.dependencies['@angular/material']).toBeDefined(); expect(packageJson.dependencies['@angular/cdk']).toBeDefined(); + expect(packageJson.dependencies['hammerjs']).toBeDefined(); expect(packageJson.dependencies['@angular/animations']).toBe(angularCoreVersion, 'Expected the @angular/animations package to have the same version as @angular/core.'); }); + it('should add hammerjs import to project main file', () => { + const tree = runner.runSchematic('ng-add', {}, appTree); + const fileContent = getFileContent(tree, '/projects/material/src/main.ts'); + + expect(fileContent).toContain(`import 'hammerjs';`, + 'Expected the project main file to contain a HammerJS import.'); + }); + it('should add default theme', () => { const tree = runner.runSchematic('ng-add', {}, appTree); @@ -106,4 +115,23 @@ describe('material-install-schematic', () => { expect(htmlContent).toContain( 'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }'); }); + + describe('gestures disabled', () => { + + it('should not add hammerjs to package.json', () => { + const tree = runner.runSchematic('ng-add', {gestures: false}, appTree); + const packageJson = JSON.parse(getFileContent(tree, '/package.json')); + + expect(packageJson.dependencies['hammerjs']) + .toBeUndefined(`Expected 'hammerjs' to be not added to the package.json`); + }); + + it('should not add hammerjs import to project main file', () => { + const tree = runner.runSchematic('ng-add', {gestures: false}, appTree); + const fileContent = getFileContent(tree, '/projects/material/src/main.ts'); + + expect(fileContent).not.toContain(`import 'hammerjs';`, + 'Expected the project main file to not contain a HammerJS import.'); + }); + }); }); diff --git a/src/lib/schematics/install/index.ts b/src/lib/schematics/install/index.ts index 3cd9f44e173a..839d4a2b3cc2 100644 --- a/src/lib/schematics/install/index.ts +++ b/src/lib/schematics/install/index.ts @@ -22,9 +22,10 @@ import {getProjectFromWorkspace} from '../utils/get-project'; import {addPackageToPackageJson, getPackageVersionFromPackageJson} from '../utils/package-json'; import {getProjectStyleFile} from '../utils/project-style-file'; import {addFontsToIndex} from './fonts/material-fonts'; +import {addHammerJsToMain} from './gestures/hammerjs-import'; import {Schema} from './schema'; import {addThemeToAppStyles} from './theming/theming'; -import {materialVersion, requiredAngularVersionRange} from './version-names'; +import {hammerjsVersion, materialVersion, requiredAngularVersionRange} from './version-names'; /** * Scaffolds the basics of a Angular Material application, this includes: @@ -39,7 +40,8 @@ export default function(options: Schema): Rule { } return chain([ - options && options.skipPackageJson ? noop() : addMaterialToPackageJson(), + options && options.skipPackageJson ? noop() : addMaterialToPackageJson(options), + options && options.gestures ? addHammerJsToMain(options) : noop(), addThemeToAppStyles(options), addAnimationRootConfig(options), addFontsToIndex(options), @@ -48,7 +50,7 @@ export default function(options: Schema): Rule { } /** Add material, cdk, animations to package.json if not already present. */ -function addMaterialToPackageJson() { +function addMaterialToPackageJson(options: Schema) { return (host: Tree, context: SchematicContext) => { // Version tag of the `@angular/core` dependency that has been loaded from the `package.json` // of the CLI project. This tag should be preferred because all Angular dependencies should @@ -60,6 +62,10 @@ function addMaterialToPackageJson() { addPackageToPackageJson(host, 'dependencies', '@angular/animations', ngCoreVersionTag || requiredAngularVersionRange); + if (options.gestures) { + addPackageToPackageJson(host, 'dependencies', 'hammerjs', hammerjsVersion); + } + context.addTask(new NodePackageInstallTask()); return host; diff --git a/src/lib/schematics/install/schema.json b/src/lib/schematics/install/schema.json index 340db20a3e0b..778b7484e8ff 100644 --- a/src/lib/schematics/install/schema.json +++ b/src/lib/schematics/install/schema.json @@ -13,6 +13,11 @@ "enum": ["indigo-pink", "deeppurple-amber", "pink-bluegrey", "purple-green", "custom"], "default": "indigo-pink", "description": "The theme to apply" + }, + "gestures": { + "type": "boolean", + "default": true, + "description": "Whether gesture support should be set up or not." } }, "required": [] diff --git a/src/lib/schematics/install/schema.ts b/src/lib/schematics/install/schema.ts index e58b43333aab..429b4c222984 100644 --- a/src/lib/schematics/install/schema.ts +++ b/src/lib/schematics/install/schema.ts @@ -10,6 +10,9 @@ export interface Schema { /** Whether to skip package.json install. */ skipPackageJson: boolean; + /** Whether gesture support should be set up or not. */ + gestures: boolean; + /** Name of pre-built theme to install. */ theme: 'indigo-pink' | 'deeppurple-amber' | 'pink-bluegrey' | 'purple-green' | 'custom'; diff --git a/src/lib/schematics/install/version-names.ts b/src/lib/schematics/install/version-names.ts index 4c34cf83c1f7..eaf84bba7b35 100644 --- a/src/lib/schematics/install/version-names.ts +++ b/src/lib/schematics/install/version-names.ts @@ -17,6 +17,9 @@ export const materialVersion = */ export const requiredAngularVersionRange = '0.0.0-NG'; +/** HammerJS version that should be installed if gestures will be set up. */ +export const hammerjsVersion = '^2.0.8'; + /** Loads the full version from the given Angular package gracefully. */ function loadPackageVersionGracefully(packageName: string): string | null { try {