Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion goldens/material/bottom-sheet/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
enter(): void;
exit(): void;
// (undocumented)
protected _handleAnimationEvent(isStart: boolean, animationName: string): void;
protected _handleAnimationEvent(isStart: boolean, animationName: string, target: EventTarget | null): void;
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
Expand Down
4 changes: 2 additions & 2 deletions scripts/approve-api-golden.mts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/bin/env node

import chalk from 'chalk';
import {execFileSync} from 'child_process';
import {join} from 'path';
import sh from 'shelljs';
import {guessPackageName} from './util.mjs';

const bazel = process.env['BAZEL'] || 'pnpm -s bazel';
const targetsToRun = new Set<string>();

if (process.argv.length < 3) {
Expand Down Expand Up @@ -34,5 +34,5 @@ for (const searchPackageName of process.argv.slice(2)) {
}

for (const target of targetsToRun) {
sh.exec(`${bazel} run ${target}`);
execFileSync('pnpm', ['-s', 'bazel', 'run', target], {stdio: 'inherit'});
}
33 changes: 28 additions & 5 deletions scripts/create-package-archives.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/

import {join} from 'path';
import {execFileSync} from 'child_process';
import sh from 'shelljs';
import chalk from 'chalk';
import yargs from 'yargs';
Expand Down Expand Up @@ -40,16 +41,38 @@ const builtPackages = sh
// If multiple packages should be archived, we also generate a single archive that
// contains all packages. This makes it easier to transfer the release packages.
if (builtPackages.length > 1) {
console.info('Creating archive with all packages..');
sh.exec(
`tar --create --gzip --directory ${releasesDir} --file ${archivesDir}/all-${suffix}.tgz .`,
console.info('Creating archive with all packages...');
execFileSync(
'tar',
[
'--create',
'--gzip',
'--directory',
releasesDir,
'--file',
`${archivesDir}/all-${suffix}.tgz`,
'.',
],
{stdio: 'inherit'},
);
}

// Note that we're using `exec` here, rather than interpolating the arguments into `sh.exec`,
// to avoid a potential command injection through the `suffix` which is user-provided.
for (const pkg of builtPackages) {
console.info(`Creating archive for package: ${pkg.name}`);
sh.exec(
`tar --create --gzip --directory ${pkg.path} --file ${archivesDir}/${pkg.name}-${suffix}.tgz .`,
execFileSync(
'tar',
[
'--create',
'--gzip',
'--directory',
pkg.path,
'--file',
`${archivesDir}/${pkg.name}-${suffix}.tgz`,
'.',
],
{stdio: 'inherit'},
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class KeyboardEventManager<T extends KeyboardEvent> extends EventManager<
}

private _normalizeInputs(...args: unknown[]) {
const withModifiers = Array.isArray(args[0]) || (args[0] as string) in Modifier;
const withModifiers = Array.isArray(args[0]) || Modifier.hasOwnProperty(args[0] as string);
const modifiers = withModifiers ? args[0] : Modifier.None;
const key = withModifiers ? args[1] : args[0];
const handler = withModifiers ? args[2] : args[1];
Expand Down
7 changes: 6 additions & 1 deletion src/cdk/layout/media-matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ function createEmptyStyleRule(query: string, nonce: string | undefined | null) {
}

if (mediaQueryStyleNode.sheet) {
mediaQueryStyleNode.sheet.insertRule(`@media ${query} {body{ }}`, 0);
mediaQueryStyleNode.sheet.insertRule(
// Drop the curly braces to avoid injection attacks. Curly braces aren't
// valid media query syntax so this should be a no-op in valid cases.
`@media ${query.replace(/[{}]/g, '')} {body{ }}`,
0,
);
mediaQueriesForWebkitCompatibility.add(query);
}
} catch (e) {
Expand Down
34 changes: 20 additions & 14 deletions src/material/bottom-sheet/bottom-sheet-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const EXIT_ANIMATION = '_mat-bottom-sheet-exit';
'[attr.role]': '_config.role',
'[attr.aria-modal]': '_config.ariaModal',
'[attr.aria-label]': '_config.ariaLabel',
'(animationstart)': '_handleAnimationEvent(true, $event.animationName)',
'(animationend)': '_handleAnimationEvent(false, $event.animationName)',
'(animationcancel)': '_handleAnimationEvent(false, $event.animationName)',
'(animationstart)': '_handleAnimationEvent(true, $event.animationName, $event.target)',
'(animationend)': '_handleAnimationEvent(false, $event.animationName, $event.target)',
'(animationcancel)': '_handleAnimationEvent(false, $event.animationName, $event.target)',
},
imports: [CdkPortalOutlet],
})
Expand Down Expand Up @@ -125,8 +125,8 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes

private _simulateAnimation(name: typeof ENTER_ANIMATION | typeof EXIT_ANIMATION) {
this._ngZone.run(() => {
this._handleAnimationEvent(true, name);
setTimeout(() => this._handleAnimationEvent(false, name));
this._handleAnimationEvent(true, name, this._elementRef.nativeElement);
setTimeout(() => this._handleAnimationEvent(false, name, this._elementRef.nativeElement));
});
}

Expand All @@ -139,15 +139,21 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
super._trapFocus({preventScroll: true});
}

protected _handleAnimationEvent(isStart: boolean, animationName: string) {
const isEnter = animationName === ENTER_ANIMATION;
const isExit = animationName === EXIT_ANIMATION;

if (isEnter || isExit) {
this._animationStateChanged.emit({
toState: isEnter ? 'visible' : 'hidden',
phase: isStart ? 'start' : 'done',
});
protected _handleAnimationEvent(
isStart: boolean,
animationName: string,
target: EventTarget | null,
) {
if (target === this._elementRef.nativeElement) {
const isEnter = animationName === ENTER_ANIMATION;
const isExit = animationName === EXIT_ANIMATION;

if (isEnter || isExit) {
this._animationStateChanged.emit({
toState: isEnter ? 'visible' : 'hidden',
phase: isStart ? 'start' : 'done',
});
}
}
}
}
5 changes: 2 additions & 3 deletions src/material/grid-list/tile-coordinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,9 @@ export class TileCoordinator {

/** Finds the next available space large enough to fit the tile. */
private _findMatchingGap(tileCols: number): number {
if (tileCols > this.tracker.length && (typeof ngDevMode === 'undefined' || ngDevMode)) {
if (tileCols > this.tracker.length) {
throw Error(
`mat-grid-list: tile with colspan ${tileCols} is wider than ` +
`grid with cols="${this.tracker.length}".`,
`mat-grid-list: tile with colspan ${tileCols} is wider than grid with cols="${this.tracker.length}".`,
);
}

Expand Down
8 changes: 7 additions & 1 deletion src/material/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,13 @@ export class MatStepper extends CdkStepper implements AfterViewInit, AfterConten
return this._animationDuration;
}
set animationDuration(value: string) {
this._animationDuration = /^\d+$/.test(value) ? value + 'ms' : value;
if (/^[0-9]+(?:\.[0-9]+)?$/.test(value)) {
this._animationDuration = value + 'ms';
} else if (/^[0-9]+(?:\.[0-9]+)?(?:ms|s)$/.test(value)) {
this._animationDuration = value;
} else {
this._animationDuration = '';
}
}
private _animationDuration = '';

Expand Down
21 changes: 17 additions & 4 deletions tools/markdown-to-html/docs-marked-renderer.mts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ export class DocsMarkdownRenderer extends Renderer {
file: string;
region: string;
};
replacement = `<div material-docs-example="${example}"
${file ? `file="${file}"` : ''}
${region ? `region="${region}"` : ''}></div>`;
replacement = `<div material-docs-example="${this._escapeHtml(example)}"
${file ? `file="${this._escapeHtml(file)}"` : ''}
${region ? `region="${this._escapeHtml(region)}"` : ''}></div>`;
} else {
replacement = `<div material-docs-example="${content}"></div>`;
replacement = `<div material-docs-example="${this._escapeHtml(content)}"></div>`;
}

return `${exampleStartMarker}${replacement}${exampleEndMarker}`;
Expand Down Expand Up @@ -154,4 +154,17 @@ export class DocsMarkdownRenderer extends Renderer {

return `${markdownOpen}${output}</div>`;
}

private _escapeHtml(text: string): string {
if (!text) {
return text;
}

return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
}
Loading