Skip to content

Commit

Permalink
feat(ng-add): set up gestures in CLI projects (#12734)
Browse files Browse the repository at this point in the history
Introduces a new option for the `ng-add` schematic that enables automatic set up of HammerJS in the CLI project. By default, gestures will be set up if someone runs `ng add @angular/material`.
  • Loading branch information
devversion authored and jelbourn committed Aug 22, 2018
1 parent dad0ed0 commit b919a48
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 4 deletions.
2 changes: 1 addition & 1 deletion guides/schematics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
41 changes: 41 additions & 0 deletions src/lib/schematics/install/gestures/hammerjs-import.ts
Original file line number Diff line number Diff line change
@@ -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);
};
}
22 changes: 22 additions & 0 deletions src/lib/schematics/install/gestures/project-main-file.ts
Original file line number Diff line number Diff line change
@@ -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.');
}
28 changes: 28 additions & 0 deletions src/lib/schematics/install/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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.');
});
});
});
12 changes: 9 additions & 3 deletions src/lib/schematics/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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),
Expand All @@ -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
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/lib/schematics/install/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": []
Expand Down
3 changes: 3 additions & 0 deletions src/lib/schematics/install/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
3 changes: 3 additions & 0 deletions src/lib/schematics/install/version-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit b919a48

Please sign in to comment.