mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: remove obsolete bundling test apps (#60591)
This commit removes a few bundling test apps that do not provide any value, but require time on CI and during local development to update golden files. The functionality that was tested in those apps is covered by various other tests that we have in a repository (either in the same `packages/core/test/bundling` folder or in other unit/integration tests). PR Close #60591
This commit is contained in:
committed by
Jessica Janiuk
parent
d15fda3e03
commit
cbd6ec8c6a
@@ -1,35 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "http_server", "ng_module")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "animation_world",
|
||||
srcs = ["index.ts"],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":animation_world",
|
||||
"//packages/core",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "server",
|
||||
srcs = [
|
||||
"animation_world.css",
|
||||
"base.css",
|
||||
"index.html",
|
||||
],
|
||||
deps = [
|
||||
":bundle.debug.min",
|
||||
":bundle.min.js.br",
|
||||
],
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
html, body {
|
||||
padding:0;
|
||||
margin:0;
|
||||
font-family: Verdana;
|
||||
}
|
||||
|
||||
animation-world {
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
max-width:1000px;
|
||||
border:2px solid black;
|
||||
}
|
||||
|
||||
animation-world nav {
|
||||
padding:1em;
|
||||
border-bottom:2px solid black;
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
animation-world .list {
|
||||
display:grid;
|
||||
grid-template-columns: 33% 33% 34%;
|
||||
grid-template-rows: 33% 33% 34%;
|
||||
height:1000px;
|
||||
}
|
||||
animation-world .record {
|
||||
line-height:333px;
|
||||
text-align:center;
|
||||
font-weight: bold;
|
||||
font-size:50px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.record-1 { color:white; background: green;}
|
||||
.record-2 { color:white; background: red;}
|
||||
.record-3 { color:white; background: blue;}
|
||||
.record-4 { color:white; background: orange;}
|
||||
.record-5 { color:white; background: purple;}
|
||||
.record-6 { color:white; background: black;}
|
||||
.record-7 { color:white; background: silver;}
|
||||
.record-8 { color:white; background: teal;}
|
||||
.record-9 { color:white; background: pink;}
|
||||
|
||||
@keyframes fadeInOut {
|
||||
from { opacity: 0; background: white; }
|
||||
33% { opacity: 1; background: black; }
|
||||
66% { opacity: 0.5; background: black; }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
border: 0;
|
||||
border-top: 1px dashed #c5c5c5;
|
||||
border-bottom: 1px dashed #f7f7f7;
|
||||
}
|
||||
|
||||
.learn a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #b83f45;
|
||||
}
|
||||
|
||||
.learn a:hover {
|
||||
text-decoration: underline;
|
||||
color: #787e7e;
|
||||
}
|
||||
|
||||
.learn h3,
|
||||
.learn h4,
|
||||
.learn h5 {
|
||||
margin: 10px 0;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.learn h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.learn h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.learn h5 {
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.learn ul {
|
||||
padding: 0;
|
||||
margin: 0 0 30px 25px;
|
||||
}
|
||||
|
||||
.learn li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.learn p {
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 1.3;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#issue-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quote {
|
||||
border: none;
|
||||
margin: 20px 0 60px 0;
|
||||
}
|
||||
|
||||
.quote p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.quote p:before {
|
||||
content: '“';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.quote p:after {
|
||||
content: '”';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
bottom: -42px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.quote footer {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.quote footer img {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.quote footer a {
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.speech-bubble {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .04);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.speech-bubble:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 30px;
|
||||
border: 13px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
position: absolute;
|
||||
width: 272px;
|
||||
top: 8px;
|
||||
left: -300px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: rgba(255, 255, 255, .6);
|
||||
transition-property: left;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
@media (min-width: 899px) {
|
||||
.learn-bar {
|
||||
width: auto;
|
||||
padding-left: 300px;
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.border {
|
||||
outline:2px solid maroon;
|
||||
display:block;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="base.css" />
|
||||
<link rel="stylesheet" href="animation_world.css" />
|
||||
<title>Angular Hello World Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
<animation-world></animation-world>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write(
|
||||
'<script src="' +
|
||||
(document.location.search.endsWith('debug')
|
||||
? '/bundle.debug.min.js'
|
||||
: '/bundle.min.js.br') +
|
||||
'"></' +
|
||||
'script>'
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,155 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ApplicationRef,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Directive,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
HostListener,
|
||||
NgModule,
|
||||
} from '../../../src/core';
|
||||
import {BrowserModule, platformBrowser} from '@angular/platform-browser';
|
||||
|
||||
@Directive({
|
||||
selector: '[make-color-grey]',
|
||||
exportAs: 'makeColorGrey',
|
||||
host: {'style': 'font-family: Times New Roman;'},
|
||||
standalone: false,
|
||||
})
|
||||
class MakeColorGreyDirective {
|
||||
@HostBinding('style.background-color') protected backgroundColor: string | null = null;
|
||||
@HostBinding('style.color') protected textColor: string | null = null;
|
||||
|
||||
on() {
|
||||
this.backgroundColor = 'grey';
|
||||
this.textColor = 'black';
|
||||
}
|
||||
|
||||
off() {
|
||||
this.backgroundColor = null;
|
||||
this.textColor = null;
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.backgroundColor ? this.off() : this.on();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'box-with-overridden-styles',
|
||||
template: '...',
|
||||
standalone: false,
|
||||
})
|
||||
class BoxWithOverriddenStylesComponent {
|
||||
public active = false;
|
||||
|
||||
@HostBinding('style') styles = {};
|
||||
|
||||
constructor(private readonly cdr: ChangeDetectorRef) {
|
||||
this.onInActive();
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
toggle() {
|
||||
if (this.active) {
|
||||
this.onInActive();
|
||||
} else {
|
||||
this.onActive();
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
onActive() {
|
||||
this.active = true;
|
||||
this.styles = {height: '500px', 'font-size': '200px', background: 'red'};
|
||||
}
|
||||
|
||||
onInActive() {
|
||||
this.active = false;
|
||||
this.styles = {width: '200px', height: '500px', border: '10px solid black', background: 'grey'};
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'animation-world',
|
||||
template: `
|
||||
<div class="list">
|
||||
<div
|
||||
#makeColorGrey="makeColorGrey"
|
||||
make-color-grey
|
||||
*ngFor="let item of items"
|
||||
class="record"
|
||||
[style.transform]="item.active ? 'scale(1.5)' : 'none'"
|
||||
[class]="makeClass(item)"
|
||||
style="border-radius: 10px"
|
||||
[style]="styles"
|
||||
[style.color]="item.value == 4 ? 'red' : null"
|
||||
[style.background-color]="item.value == 4 ? 'white' : null"
|
||||
(click)="toggleActive(item, makeColorGrey)">
|
||||
{{ item.value }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<box-with-overridden-styles
|
||||
style="display:block"
|
||||
[style]="{'border-radius':'50px', 'border': '50px solid teal'}" [ngStyle]="{transform:'rotate(50deg)'}">
|
||||
</box-with-overridden-styles>
|
||||
`,
|
||||
standalone: false,
|
||||
})
|
||||
class AnimationWorldComponent {
|
||||
@HostBinding('class') classVal = 'border';
|
||||
|
||||
items: any[] = [
|
||||
{value: 1, active: false},
|
||||
{value: 2, active: false},
|
||||
{value: 3, active: false},
|
||||
{value: 4, active: false},
|
||||
{value: 5, active: false},
|
||||
{value: 6, active: false},
|
||||
{value: 7, active: false},
|
||||
{value: 8, active: false},
|
||||
{value: 9, active: false},
|
||||
];
|
||||
private _hostElement: HTMLElement;
|
||||
public styles: {[key: string]: any} | null = null;
|
||||
|
||||
constructor(
|
||||
element: ElementRef,
|
||||
private readonly cdr: ChangeDetectorRef,
|
||||
) {
|
||||
this._hostElement = element.nativeElement;
|
||||
}
|
||||
|
||||
makeClass(item: any) {
|
||||
return `record-${item.value}`;
|
||||
}
|
||||
|
||||
toggleActive(item: any, makeColorGrey: MakeColorGreyDirective) {
|
||||
item.active = !item.active;
|
||||
makeColorGrey.toggle();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AnimationWorldComponent, MakeColorGreyDirective, BoxWithOverriddenStylesComponent],
|
||||
imports: [BrowserModule],
|
||||
})
|
||||
class AnimationWorldModule {
|
||||
ngDoBootstrap(app: ApplicationRef) {
|
||||
app.bootstrap(AnimationWorldComponent);
|
||||
}
|
||||
}
|
||||
|
||||
platformBrowser().bootstrapModule(AnimationWorldModule, {ngZone: 'noop'});
|
||||
@@ -1,65 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "jasmine_node_test", "ng_module", "ts_library")
|
||||
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
|
||||
load("@npm//http-server:index.bzl", "http_server")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "animations",
|
||||
srcs = ["index.ts"],
|
||||
deps = [
|
||||
"//packages/animations",
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
"//packages/platform-browser/animations",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":animations",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(["*_spec.ts"]),
|
||||
deps = [
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/private/testing",
|
||||
"@npm//@bazel/runfiles",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
data = [
|
||||
":bundle.debug.min.js",
|
||||
":bundle.js",
|
||||
":bundle.min.js",
|
||||
":bundle.min.js.br",
|
||||
],
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
js_expected_symbol_test(
|
||||
name = "symbol_test",
|
||||
src = ":bundle.debug.min.js",
|
||||
golden = ":bundle.golden_symbols.json",
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "prodserver",
|
||||
data = [
|
||||
"index.html",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
)
|
||||
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Angular Animations Example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
|
||||
<app-root></app-root>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write('<script src="' +
|
||||
(document.location.search.endsWith('debug') ? '/bundle.debug.min.js' : '/bundle.min.js') +
|
||||
'"></' + 'script>');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {Component, NgModule, ɵNgModuleFactory as NgModuleFactory} from '../../../src/core';
|
||||
import {BrowserModule, platformBrowser} from '@angular/platform-browser';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'app-animations',
|
||||
template: `
|
||||
<div [@myAnimation]="exp"></div>
|
||||
`,
|
||||
animations: [
|
||||
trigger('myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])]),
|
||||
],
|
||||
standalone: false,
|
||||
})
|
||||
class AnimationsComponent {
|
||||
exp: any = false;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<app-animations></app-animations>
|
||||
`,
|
||||
standalone: false,
|
||||
})
|
||||
class RootComponent {}
|
||||
|
||||
@NgModule({
|
||||
declarations: [RootComponent, AnimationsComponent],
|
||||
imports: [BrowserModule, BrowserAnimationsModule],
|
||||
})
|
||||
class AnimationsExampleModule {
|
||||
ngDoBootstrap(app: any) {
|
||||
app.bootstrap(RootComponent);
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).waitForApp = platformBrowser().bootstrapModule(AnimationsExampleModule, {
|
||||
ngZone: 'noop',
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import '@angular/compiler';
|
||||
|
||||
import {runfiles} from '@bazel/runfiles';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const PACKAGE = 'angular/packages/core/test/bundling/animations';
|
||||
|
||||
describe('treeshaking with uglify', () => {
|
||||
let content: string;
|
||||
// We use the debug version as otherwise symbols/identifiers would be mangled (and the test would
|
||||
// always pass)
|
||||
const contentPath = runfiles.resolve(path.join(PACKAGE, 'bundle.debug.min.js'));
|
||||
beforeAll(() => {
|
||||
content = fs.readFileSync(contentPath, {encoding: 'utf-8'});
|
||||
});
|
||||
|
||||
it('should drop unused TypeScript helpers', () => {
|
||||
expect(content).not.toContain('__asyncGenerator');
|
||||
});
|
||||
|
||||
it('should not contain rxjs from commonjs distro', () => {
|
||||
expect(content).not.toContain('commonjsGlobal');
|
||||
expect(content).not.toContain('createCommonjsModule');
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "jasmine_node_test", "ng_module", "ts_library")
|
||||
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
|
||||
load("@npm//http-server:index.bzl", "http_server")
|
||||
load("//tools:defaults.bzl", "app_bundle", "jasmine_node_test", "ng_module", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@@ -50,12 +49,6 @@ jasmine_node_test(
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
js_expected_symbol_test(
|
||||
name = "symbol_test",
|
||||
src = ":bundle.debug.min.js",
|
||||
golden = ":bundle.golden_symbols.json",
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "devserver",
|
||||
data = [
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "jasmine_node_test", "ng_module", "ts_library")
|
||||
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
|
||||
load("@npm//http-server:index.bzl", "http_server")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "hello_world",
|
||||
srcs = ["index.ts"],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":hello_world",
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(["*_spec.ts"]),
|
||||
deps = [
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/core/testing",
|
||||
"//packages/private/testing",
|
||||
"@npm//@bazel/runfiles",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
data = [
|
||||
":bundle",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.js",
|
||||
":bundle.min.js.br",
|
||||
],
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
js_expected_symbol_test(
|
||||
name = "symbol_test",
|
||||
src = ":bundle.debug.min.js",
|
||||
golden = ":bundle.golden_symbols.json",
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "prodserver",
|
||||
data = [
|
||||
"index.html",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular Hello World Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
<hello-world></hello-world>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write('<script src="' +
|
||||
(document.location.search.endsWith('debug') ? '/bundle.debug.min.js' : '/bundle.min.js') +
|
||||
'"></' + 'script>');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
import {Component, NgModule} from '../../../src/core';
|
||||
import {platformBrowser} from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: 'Hello World!',
|
||||
standalone: false,
|
||||
})
|
||||
export class HelloWorldComponent {}
|
||||
|
||||
@NgModule({declarations: [HelloWorldComponent]})
|
||||
export class HelloWorldModule {}
|
||||
|
||||
platformBrowser().bootstrapModule(HelloWorldModule);
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import '@angular/compiler';
|
||||
|
||||
import {runfiles} from '@bazel/runfiles';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const PACKAGE = 'angular/packages/core/test/bundling/hello_world';
|
||||
|
||||
describe('treeshaking with uglify', () => {
|
||||
let content: string;
|
||||
const contentPath = runfiles.resolve(path.join(PACKAGE, 'bundle.debug.min.js'));
|
||||
beforeAll(() => {
|
||||
content = fs.readFileSync(contentPath, {encoding: 'utf-8'});
|
||||
});
|
||||
|
||||
it('should drop unused TypeScript helpers', () => {
|
||||
expect(content).not.toContain('__asyncGenerator');
|
||||
});
|
||||
|
||||
it('should not contain rxjs from commonjs distro', () => {
|
||||
expect(content).not.toContain('commonjsGlobal');
|
||||
expect(content).not.toContain('createCommonjsModule');
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "ng_module")
|
||||
load("@npm//http-server:index.bzl", "http_server")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "hello_world_i18n",
|
||||
srcs = [
|
||||
"index.ts",
|
||||
"translations.ts",
|
||||
],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
"//packages/localize",
|
||||
"//packages/localize/init",
|
||||
"//packages/platform-browser",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":hello_world_i18n",
|
||||
"//packages/core",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "prodserver",
|
||||
data = [
|
||||
"index.html",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
tags = [],
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular Hello World Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
<hello-world></hello-world>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write('<script src="' +
|
||||
(document.location.search.endsWith('debug') ? '/bundle.debug.min.js' : '/bundle.min.js') +
|
||||
'"></' + 'script>');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
import './translations';
|
||||
|
||||
import {Component, NgModule} from '../../../src/core';
|
||||
import {BrowserModule, platformBrowser} from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: `<div i18n i18n-title title="Hello Title!">Hello World!</div>`,
|
||||
standalone: false,
|
||||
})
|
||||
export class HelloWorld {}
|
||||
|
||||
@NgModule({
|
||||
declarations: [HelloWorld],
|
||||
imports: [BrowserModule],
|
||||
bootstrap: [HelloWorld],
|
||||
})
|
||||
export class Module {}
|
||||
|
||||
platformBrowser().bootstrapModule(Module, {ngZone: 'noop'});
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
// Make the `$localize()` global function available to the compiled templates, and the direct calls
|
||||
// below. This would normally be done inside the application `polyfills.ts` file.
|
||||
import '@angular/localize/init';
|
||||
import {computeMsgId} from '@angular/compiler';
|
||||
import {loadTranslations} from '@angular/localize';
|
||||
|
||||
const translations = {
|
||||
[computeMsgId('Hello World!')]: 'Bonjour Monde!',
|
||||
[computeMsgId('Hello Title!')]: 'Bonjour Titre!',
|
||||
};
|
||||
|
||||
loadTranslations(translations);
|
||||
@@ -1,49 +0,0 @@
|
||||
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
|
||||
load("//tools:defaults.bzl", "app_bundle", "jasmine_node_test", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_library(
|
||||
name = "injection",
|
||||
srcs = [
|
||||
"index.ts",
|
||||
"usage.ts",
|
||||
],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":injection",
|
||||
"//packages/core",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(["*_spec.ts"]),
|
||||
deps = [
|
||||
":injection",
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/core/testing",
|
||||
"//packages/private/testing",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
js_expected_symbol_test(
|
||||
name = "symbol_test",
|
||||
src = ":bundle.debug.min.js",
|
||||
golden = ":bundle.golden_symbols.json",
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {INJECTOR, ScopedService} from './usage';
|
||||
|
||||
INJECTOR.get(ScopedService).doSomething();
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import '@angular/compiler';
|
||||
import {INJECTOR, ScopedService} from './usage';
|
||||
|
||||
describe('functional test for injection system bundling', () => {
|
||||
it('should be able to inject the scoped service', () => {
|
||||
expect(INJECTOR.get(ScopedService) instanceof ScopedService).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ɵcreateInjector as createInjector,
|
||||
ɵɵdefineInjectable,
|
||||
ɵɵdefineInjector,
|
||||
} from '../../../src/core';
|
||||
|
||||
export class RootService {
|
||||
static ɵprov = ɵɵdefineInjectable({
|
||||
token: RootService,
|
||||
providedIn: 'root',
|
||||
factory: () => new RootService(),
|
||||
});
|
||||
}
|
||||
|
||||
export class ScopedService {
|
||||
static ɵprov = ɵɵdefineInjectable({
|
||||
token: ScopedService,
|
||||
providedIn: null,
|
||||
factory: () => new ScopedService(),
|
||||
});
|
||||
|
||||
doSomething(): void {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.log("Ensure this isn't tree-shaken.");
|
||||
}
|
||||
}
|
||||
|
||||
export class DefinedInjector {
|
||||
static ɵinj = ɵɵdefineInjector({
|
||||
providers: [ScopedService],
|
||||
});
|
||||
}
|
||||
|
||||
export const INJECTOR = createInjector(DefinedInjector);
|
||||
@@ -1,73 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "http_server", "jasmine_node_test", "ng_module", "ts_library")
|
||||
load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "todo",
|
||||
srcs = ["index.ts"],
|
||||
deps = [
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
"//packages/platform-browser-dynamic",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = "index.ts",
|
||||
deps = [
|
||||
":todo",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/platform-browser",
|
||||
"//packages/platform-browser-dynamic",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(["*_spec.ts"]),
|
||||
deps = [
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/platform-browser",
|
||||
"//packages/platform-browser-dynamic",
|
||||
"//packages/private/testing",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
data = [
|
||||
":bundle",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
js_expected_symbol_test(
|
||||
name = "symbol_test",
|
||||
src = ":bundle.debug.min.js",
|
||||
golden = ":bundle.golden_symbols.json",
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "server",
|
||||
srcs = [
|
||||
"base.css",
|
||||
"index.html",
|
||||
"todo.css",
|
||||
],
|
||||
deps = [
|
||||
":bundle.debug.min.js",
|
||||
":bundle.min.js.br",
|
||||
],
|
||||
)
|
||||
@@ -1,141 +0,0 @@
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
border: 0;
|
||||
border-top: 1px dashed #c5c5c5;
|
||||
border-bottom: 1px dashed #f7f7f7;
|
||||
}
|
||||
|
||||
.learn a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #b83f45;
|
||||
}
|
||||
|
||||
.learn a:hover {
|
||||
text-decoration: underline;
|
||||
color: #787e7e;
|
||||
}
|
||||
|
||||
.learn h3,
|
||||
.learn h4,
|
||||
.learn h5 {
|
||||
margin: 10px 0;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.learn h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.learn h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.learn h5 {
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.learn ul {
|
||||
padding: 0;
|
||||
margin: 0 0 30px 25px;
|
||||
}
|
||||
|
||||
.learn li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.learn p {
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 1.3;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#issue-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quote {
|
||||
border: none;
|
||||
margin: 20px 0 60px 0;
|
||||
}
|
||||
|
||||
.quote p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.quote p:before {
|
||||
content: '“';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.quote p:after {
|
||||
content: '”';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
bottom: -42px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.quote footer {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.quote footer img {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.quote footer a {
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.speech-bubble {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .04);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.speech-bubble:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 30px;
|
||||
border: 13px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
position: absolute;
|
||||
width: 272px;
|
||||
top: 8px;
|
||||
left: -300px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: rgba(255, 255, 255, .6);
|
||||
transition-property: left;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
@media (min-width: 899px) {
|
||||
.learn-bar {
|
||||
width: auto;
|
||||
padding-left: 300px;
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular Todo Example</title>
|
||||
<link rel="stylesheet" href="base.css" />
|
||||
<link rel="stylesheet" href="todo.css" />
|
||||
<style>
|
||||
.done {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
<todo-app></todo-app>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write(
|
||||
'<script src="' +
|
||||
(document.location.search.endsWith('debug')
|
||||
? '/bundle.debug.min.js'
|
||||
: '/bundle.min.js.br') +
|
||||
'"></' +
|
||||
'script>'
|
||||
);
|
||||
</script>
|
||||
<script>
|
||||
bootstrapApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,203 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component, Injectable, NgModule} from '../../../src/core';
|
||||
import {BrowserModule, platformBrowser} from '@angular/platform-browser';
|
||||
|
||||
class Todo {
|
||||
editing: boolean;
|
||||
|
||||
private _title!: string;
|
||||
get title() {
|
||||
return this._title;
|
||||
}
|
||||
set title(value: string) {
|
||||
this._title = value.trim();
|
||||
}
|
||||
|
||||
constructor(
|
||||
title: string,
|
||||
public completed: boolean = false,
|
||||
) {
|
||||
this.editing = false;
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
class TodoStore {
|
||||
todos: Array<Todo> = [
|
||||
new Todo('Demonstrate Components'),
|
||||
new Todo('Demonstrate Structural Directives', true),
|
||||
new Todo('Demonstrate NgModules'),
|
||||
new Todo('Demonstrate zoneless change detection'),
|
||||
new Todo('Demonstrate internationalization'),
|
||||
];
|
||||
|
||||
private getWithCompleted(completed: boolean) {
|
||||
return this.todos.filter((todo: Todo) => todo.completed === completed);
|
||||
}
|
||||
|
||||
allCompleted() {
|
||||
return this.todos.length === this.getCompleted().length;
|
||||
}
|
||||
|
||||
setAllTo(completed: boolean) {
|
||||
this.todos.forEach((t: Todo) => (t.completed = completed));
|
||||
}
|
||||
|
||||
removeCompleted() {
|
||||
this.todos = this.getWithCompleted(false);
|
||||
}
|
||||
|
||||
getRemaining() {
|
||||
return this.getWithCompleted(false);
|
||||
}
|
||||
|
||||
getCompleted() {
|
||||
return this.getWithCompleted(true);
|
||||
}
|
||||
|
||||
toggleCompletion(todo: Todo) {
|
||||
todo.completed = !todo.completed;
|
||||
}
|
||||
|
||||
remove(todo: Todo) {
|
||||
this.todos.splice(this.todos.indexOf(todo), 1);
|
||||
}
|
||||
|
||||
add(title: string) {
|
||||
this.todos.push(new Todo(title));
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'todo-app',
|
||||
// TODO(misko): make this work with `[(ngModel)]`
|
||||
styles: [
|
||||
`
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
font-weight:bold;
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
<section class="todoapp">
|
||||
<header class="header">
|
||||
<h1>todos</h1>
|
||||
<input class="new-todo" placeholder="What needs to be done?" autofocus=""
|
||||
[value]="newTodoText"
|
||||
(keyup)="$event.code == 'Enter' ? addTodo() : newTodoText = $any($event.target).value">
|
||||
</header>
|
||||
<section *ngIf="todoStore.todos.length > 0" class="main">
|
||||
<input *ngIf="todoStore.todos.length"
|
||||
#toggleall class="toggle-all" type="checkbox"
|
||||
[checked]="todoStore.allCompleted()"
|
||||
(click)="todoStore.setAllTo(toggleall.checked)">
|
||||
<ul class="todo-list">
|
||||
<li *ngFor="let todo of todoStore.todos"
|
||||
[class.completed]="todo.completed"
|
||||
[class.editing]="todo.editing">
|
||||
<div class="view">
|
||||
<input class="toggle" type="checkbox"
|
||||
(click)="toggleCompletion(todo)"
|
||||
[checked]="todo.completed">
|
||||
<label (dblclick)="editTodo(todo)">{{todo.title}}</label>
|
||||
<button class="destroy" (click)="remove(todo)"></button>
|
||||
</div>
|
||||
<input *ngIf="todo.editing"
|
||||
class="edit" #editedtodo
|
||||
[value]="todo.title"
|
||||
(blur)="stopEditing(todo, editedtodo.value)"
|
||||
(keyup)="todo.title = $any($event.target).value"
|
||||
(keyup)="$event.code == 'Enter' && updateEditingTodo(todo, editedtodo.value)"
|
||||
(keyup)="$event.code == 'Escape' && cancelEditingTodo(todo)">
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<footer *ngIf="todoStore.todos.length > 0" class="footer">
|
||||
<span class="todo-count">
|
||||
<strong>{{todoStore.getRemaining().length}}</strong>
|
||||
{{todoStore.getRemaining().length == 1 ? 'item' : 'items'}} left
|
||||
</span>
|
||||
<button *ngIf="todoStore.getCompleted().length > 0"
|
||||
class="clear-completed"
|
||||
(click)="removeCompleted()">
|
||||
Clear completed
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
`,
|
||||
standalone: false,
|
||||
})
|
||||
class ToDoAppComponent {
|
||||
newTodoText = '';
|
||||
|
||||
constructor(public todoStore: TodoStore) {
|
||||
(window as any).toDoAppComponent = this;
|
||||
}
|
||||
|
||||
stopEditing(todo: Todo, editedTitle: string) {
|
||||
todo.title = editedTitle;
|
||||
todo.editing = false;
|
||||
}
|
||||
|
||||
cancelEditingTodo(todo: Todo) {
|
||||
todo.editing = false;
|
||||
}
|
||||
|
||||
updateEditingTodo(todo: Todo, editedTitle: string) {
|
||||
editedTitle = editedTitle.trim();
|
||||
todo.editing = false;
|
||||
|
||||
if (editedTitle.length === 0) {
|
||||
return this.todoStore.remove(todo);
|
||||
}
|
||||
|
||||
todo.title = editedTitle;
|
||||
}
|
||||
|
||||
editTodo(todo: Todo) {
|
||||
todo.editing = true;
|
||||
}
|
||||
|
||||
removeCompleted() {
|
||||
this.todoStore.removeCompleted();
|
||||
}
|
||||
|
||||
toggleCompletion(todo: Todo) {
|
||||
this.todoStore.toggleCompletion(todo);
|
||||
}
|
||||
|
||||
remove(todo: Todo) {
|
||||
this.todoStore.remove(todo);
|
||||
}
|
||||
|
||||
addTodo() {
|
||||
if (this.newTodoText.trim().length) {
|
||||
this.todoStore.add(this.newTodoText);
|
||||
this.newTodoText = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({declarations: [ToDoAppComponent], imports: [CommonModule, BrowserModule]})
|
||||
class ToDoAppModule {
|
||||
ngDoBootstrap(app: any) {
|
||||
app.bootstrap(ToDoAppComponent);
|
||||
}
|
||||
}
|
||||
|
||||
function bootstrapApp() {
|
||||
return platformBrowser().bootstrapModule(ToDoAppModule, {ngZone: 'noop'});
|
||||
}
|
||||
|
||||
(window as any).bootstrapApp = bootstrapApp;
|
||||
@@ -1,363 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="checkbox"] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
label[for='toggle-all'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: -12px;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
border: none; /* Mobile Safari */
|
||||
}
|
||||
|
||||
.toggle-all:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 13px 17px 12px 17px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
white-space: pre-line;
|
||||
word-break: break-all;
|
||||
padding: 15px 60px 15px 15px;
|
||||
margin-left: 45px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a.selected,
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import '@angular/compiler';
|
||||
|
||||
import {withBody} from '@angular/private/testing';
|
||||
import * as path from 'path';
|
||||
|
||||
const PACKAGE = 'angular/packages/core/test/bundling/todo';
|
||||
const BUNDLES = ['bundle.js', 'bundle.debug.min.js', 'bundle.min.js'];
|
||||
|
||||
describe('functional test for todo', () => {
|
||||
BUNDLES.forEach((bundle) => {
|
||||
describe(bundle, () => {
|
||||
it(
|
||||
'should place styles on the elements within the component',
|
||||
withBody('<todo-app></todo-app>', async () => {
|
||||
// load the bundle
|
||||
await import(path.join(PACKAGE, bundle));
|
||||
// the bundle attaches the following fields to the `window` global.
|
||||
const {bootstrapApp} = window as any;
|
||||
|
||||
await bootstrapApp();
|
||||
|
||||
const styleContent = findStyleTextForSelector('.todo-list\\[_ngcontent-[a-z]+-\\w+\\]');
|
||||
expect(styleContent).toMatch(/font-weight:\s*bold;/);
|
||||
expect(styleContent).toMatch(/color:\s*#d9d9d9;/);
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function findStyleTextForSelector(selector: string): string {
|
||||
const styles = document.querySelectorAll('head style');
|
||||
const matchExp = new RegExp(`${selector}.+?\\\{([\\s\\S]+)\\\}`, 'm');
|
||||
for (let i = 0; i < styles.length; i++) {
|
||||
const styleElement = styles[i];
|
||||
const content = styleElement.textContent || '';
|
||||
const result = matchExp.exec(content);
|
||||
if (result && result.length > 1) {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`The CSS Style Rule ${selector} was not found`);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
load("//tools:defaults.bzl", "app_bundle", "http_server", "jasmine_node_test", "ng_module", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ng_module(
|
||||
name = "todo_i18n",
|
||||
srcs = [
|
||||
"index.ts",
|
||||
"translations.ts",
|
||||
],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
"//packages/localize",
|
||||
"//packages/localize/init",
|
||||
"//packages/platform-browser",
|
||||
],
|
||||
)
|
||||
|
||||
app_bundle(
|
||||
name = "bundle",
|
||||
entry_point = ":index.ts",
|
||||
deps = [
|
||||
":todo_i18n",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(["*_spec.ts"]),
|
||||
deps = [
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/localize",
|
||||
"//packages/localize/init",
|
||||
"//packages/private/testing",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
data = [
|
||||
":bundle",
|
||||
":bundle.debug.min.js",
|
||||
":bundle.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "server",
|
||||
srcs = [
|
||||
"base.css",
|
||||
"index.html",
|
||||
"todo.css",
|
||||
],
|
||||
deps = [
|
||||
":bundle.debug.min.js",
|
||||
":bundle.min.js",
|
||||
],
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
# Outstanding on the `Todo` app
|
||||
|
||||
## `Todo` app
|
||||
- [X] Clicking archive removes todo item.
|
||||
- [X] Update `Todo` app to match http://todomvc.com/.
|
||||
- [ ] Make it work with `[(ngModel)]`.
|
||||
- [ ] Make it work with `(keyup.Enter)`.
|
||||
|
||||
## Compiler
|
||||
- [X] Remove ` tslib_1.__decorate([core_1.Input(), tslib_1.__metadata("design:type", Object)], TodoComponent.prototype, "todo", void 0);` from generated output.
|
||||
- [ ] Allow compilation of `@angular/common` through ivy.
|
||||
|
||||
## Ivy Runtime
|
||||
- [X] Work on `ViewContainerRef` needs to cause change detection so that `todo` app renders correctly on first render.
|
||||
- [X] The todo input value box is not correctly rendering to checked for completed tasks.
|
||||
- [ ] `ViewContainerRef` must separate creation mode from update mode otherwise {{todo.done}} fails for `NgFor` because `todo` is not set during creation mode.
|
||||
- [ ] Injector should be optional
|
||||
|
||||
## Testing
|
||||
- [ ] Create a debug mode which would publish components into DOM for easier writing of tests.
|
||||
|
||||
# NOTES
|
||||
|
||||
## Killing hung `iblaze` server
|
||||
|
||||
At times the `iblaze run packages/core/test/bundling/todo:devserver` keeps running and holding onto
|
||||
ports even after `ctrl-c`. This command kills the outstanding processes.
|
||||
|
||||
```
|
||||
kill -9 $(ps aux | grep ibazel\\\|devserver | cut -c 17-23)
|
||||
```
|
||||
@@ -1,141 +0,0 @@
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
border: 0;
|
||||
border-top: 1px dashed #c5c5c5;
|
||||
border-bottom: 1px dashed #f7f7f7;
|
||||
}
|
||||
|
||||
.learn a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #b83f45;
|
||||
}
|
||||
|
||||
.learn a:hover {
|
||||
text-decoration: underline;
|
||||
color: #787e7e;
|
||||
}
|
||||
|
||||
.learn h3,
|
||||
.learn h4,
|
||||
.learn h5 {
|
||||
margin: 10px 0;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.learn h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.learn h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.learn h5 {
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.learn ul {
|
||||
padding: 0;
|
||||
margin: 0 0 30px 25px;
|
||||
}
|
||||
|
||||
.learn li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.learn p {
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 1.3;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#issue-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quote {
|
||||
border: none;
|
||||
margin: 20px 0 60px 0;
|
||||
}
|
||||
|
||||
.quote p {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.quote p:before {
|
||||
content: '“';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.quote p:after {
|
||||
content: '”';
|
||||
font-size: 50px;
|
||||
opacity: .15;
|
||||
position: absolute;
|
||||
bottom: -42px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.quote footer {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.quote footer img {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.quote footer a {
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.speech-bubble {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, .04);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.speech-bubble:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 30px;
|
||||
border: 13px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
position: absolute;
|
||||
width: 272px;
|
||||
top: 8px;
|
||||
left: -300px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: rgba(255, 255, 255, .6);
|
||||
transition-property: left;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
@media (min-width: 899px) {
|
||||
.learn-bar {
|
||||
width: auto;
|
||||
padding-left: 300px;
|
||||
}
|
||||
|
||||
.learn-bar > .learn {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Angular Todo Example</title>
|
||||
<link rel="stylesheet" href="base.css">
|
||||
<link rel="stylesheet" href="todo.css">
|
||||
<style>
|
||||
.done {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The Angular application will be bootstrapped into this element. -->
|
||||
<todo-app></todo-app>
|
||||
|
||||
<!--
|
||||
Script tag which bootstraps the application. Use `?debug` in URL to select
|
||||
the debug version of the script.
|
||||
|
||||
There are two scripts sources: `bundle.min.js` and `bundle.debug.min.js` You can
|
||||
switch between which bundle the browser loads to experiment with the application.
|
||||
|
||||
- `bundle.min.js`: Is what the site would serve to their users. It has gone
|
||||
through rollup, build-optimizer, and uglify with tree shaking.
|
||||
- `bundle.debug.min.js`: Is what the developer would like to see when debugging
|
||||
the application. It has also gone through full pipeline of esbuild, babel optimization,
|
||||
plugins from the devkit and terser, however mangling is disabled and the minified
|
||||
file is formatted using prettier (to ease debugging).
|
||||
-->
|
||||
<script>
|
||||
document.write('<script src="' +
|
||||
(document.location.search.endsWith('debug') ? 'bundle.debug.min.js' : 'bundle.min.js') +
|
||||
'"></' + 'script>');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,216 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Injectable,
|
||||
NgModule,
|
||||
ViewEncapsulation,
|
||||
} from '../../../src/core';
|
||||
import {loadTranslations} from '@angular/localize';
|
||||
import {BrowserModule, platformBrowser} from '@angular/platform-browser';
|
||||
|
||||
import {translations} from './translations';
|
||||
|
||||
class Todo {
|
||||
editing: boolean;
|
||||
|
||||
get title() {
|
||||
return this._title;
|
||||
}
|
||||
set title(value: string) {
|
||||
this._title = value.trim();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _title: string,
|
||||
public completed: boolean = false,
|
||||
) {
|
||||
this.editing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
class TodoStore {
|
||||
todos: Array<Todo> = [
|
||||
new Todo($localize`Demonstrate Components`),
|
||||
new Todo($localize`Demonstrate Structural Directives`, true),
|
||||
// Using a placeholder
|
||||
new Todo($localize`Demonstrate ${'NgModules'}:value:`),
|
||||
new Todo($localize`Demonstrate zoneless change detection`),
|
||||
new Todo($localize`Demonstrate internationalization`),
|
||||
];
|
||||
|
||||
private getWithCompleted(completed: boolean) {
|
||||
return this.todos.filter((todo: Todo) => todo.completed === completed);
|
||||
}
|
||||
|
||||
allCompleted() {
|
||||
return this.todos.length === this.getCompleted().length;
|
||||
}
|
||||
|
||||
setAllTo(completed: boolean) {
|
||||
this.todos.forEach((t: Todo) => (t.completed = completed));
|
||||
}
|
||||
|
||||
removeCompleted() {
|
||||
this.todos = this.getWithCompleted(false);
|
||||
}
|
||||
|
||||
getRemaining() {
|
||||
return this.getWithCompleted(false);
|
||||
}
|
||||
|
||||
getCompleted() {
|
||||
return this.getWithCompleted(true);
|
||||
}
|
||||
|
||||
toggleCompletion(todo: Todo) {
|
||||
todo.completed = !todo.completed;
|
||||
}
|
||||
|
||||
remove(todo: Todo) {
|
||||
this.todos.splice(this.todos.indexOf(todo), 1);
|
||||
}
|
||||
|
||||
add(title: string) {
|
||||
this.todos.push(new Todo(title));
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'todo-app',
|
||||
// TODO(misko): make this work with `[(ngModel)]`
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
template: `
|
||||
<section class="todoapp">
|
||||
<header class="header" i18n>
|
||||
<h1>todos</h1>
|
||||
<input class="new-todo" i18n-placeholder placeholder="What needs to be done?" autofocus=""
|
||||
[value]="newTodoText"
|
||||
(keyup)="$event.code == 'Enter' ? addTodo() : updateNewTodoValue($event)">
|
||||
</header>
|
||||
<section *ngIf="todoStore.todos.length > 0" class="main">
|
||||
<input *ngIf="todoStore.todos.length"
|
||||
#toggleall class="toggle-all" type="checkbox"
|
||||
[checked]="todoStore.allCompleted()"
|
||||
(click)="toggleAllTodos(toggleall.checked)">
|
||||
<ul class="todo-list">
|
||||
<li *ngFor="let todo of todoStore.todos"
|
||||
[class.completed]="todo.completed"
|
||||
[class.editing]="todo.editing">
|
||||
<div class="view">
|
||||
<input class="toggle" type="checkbox"
|
||||
(click)="toggleCompletion(todo)"
|
||||
[checked]="todo.completed">
|
||||
<label (dblclick)="editTodo(todo)">{{todo.title}}</label>
|
||||
<button class="destroy" (click)="remove(todo)"></button>
|
||||
</div>
|
||||
<input *ngIf="todo.editing"
|
||||
class="edit" #editedtodo
|
||||
[value]="todo.title"
|
||||
(blur)="updateEditedTodoValue(todo, editedtodo.value)"
|
||||
(keyup)="updateEditedTodoValue(todo, $any($event.target).value)"
|
||||
(keyup)="$event.code == 'Enter' && updateEditedTodoValue(todo, editedtodo.value)"
|
||||
(keyup)="$event.code == 'Escape' && cancelEditingTodo(todo)">
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<footer *ngIf="todoStore.todos.length > 0" class="footer">
|
||||
<span class="todo-count" i18n>
|
||||
<strong>{{todoStore.getRemaining().length}}</strong> {todoStore.getRemaining().length, plural, =1 {item left} other {items left}}
|
||||
</span>
|
||||
<button *ngIf="todoStore.getCompleted().length > 0" class="clear-completed" (click)="removeCompleted()" i18n>
|
||||
Clear completed
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
`,
|
||||
standalone: false,
|
||||
})
|
||||
class ToDoAppComponent {
|
||||
newTodoText = '';
|
||||
|
||||
constructor(
|
||||
public todoStore: TodoStore,
|
||||
private readonly cdr: ChangeDetectorRef,
|
||||
) {
|
||||
(window as any).todoAppComponent = this;
|
||||
}
|
||||
|
||||
cancelEditingTodo(todo: Todo) {
|
||||
todo.editing = false;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
finishUpdatingTodo(todo: Todo, editedTitle: string) {
|
||||
editedTitle = editedTitle.trim();
|
||||
|
||||
if (editedTitle.length === 0) {
|
||||
this.remove(todo);
|
||||
}
|
||||
|
||||
todo.title = editedTitle;
|
||||
this.cancelEditingTodo(todo);
|
||||
}
|
||||
|
||||
editTodo(todo: Todo) {
|
||||
todo.editing = true;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
removeCompleted() {
|
||||
this.todoStore.removeCompleted();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
toggleCompletion(todo: Todo) {
|
||||
this.todoStore.toggleCompletion(todo);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
remove(todo: Todo) {
|
||||
this.todoStore.remove(todo);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
addTodo() {
|
||||
if (this.newTodoText.trim().length) {
|
||||
this.todoStore.add(this.newTodoText);
|
||||
this.newTodoText = '';
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
toggleAllTodos(checked: boolean) {
|
||||
this.todoStore.setAllTo(checked);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
updateEditedTodoValue(todo: Todo, value: string) {
|
||||
todo.title = value;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
updateNewTodoValue(event: Event) {
|
||||
this.newTodoText = (event.target as HTMLInputElement).value;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [ToDoAppComponent],
|
||||
imports: [BrowserModule],
|
||||
bootstrap: [ToDoAppComponent],
|
||||
})
|
||||
class ToDoAppModule {}
|
||||
|
||||
loadTranslations(translations);
|
||||
|
||||
(window as any).appReady = platformBrowser().bootstrapModule(ToDoAppModule, {ngZone: 'noop'});
|
||||
@@ -1,369 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="checkbox"] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 80px;
|
||||
line-height: 80px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
label[for='toggle-all'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: -12px;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
border: none; /* Mobile Safari */
|
||||
}
|
||||
|
||||
.toggle-all:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 13px 17px 12px 17px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
white-space: pre-line;
|
||||
word-break: break-all;
|
||||
padding: 15px 60px 15px 15px;
|
||||
margin-left: 45px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a.selected,
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
import '@angular/localize/init';
|
||||
import '@angular/compiler';
|
||||
|
||||
import {clearTranslations} from '@angular/localize';
|
||||
import {withBody} from '@angular/private/testing';
|
||||
import * as path from 'path';
|
||||
|
||||
const PACKAGE = 'angular/packages/core/test/bundling/todo_i18n';
|
||||
const BUNDLES = ['bundle.js', 'bundle.debug.min.js', 'bundle.min.js'];
|
||||
|
||||
describe('functional test for todo i18n', () => {
|
||||
BUNDLES.forEach((bundle) => {
|
||||
describe(bundle, () => {
|
||||
it(
|
||||
'should render todo i18n',
|
||||
withBody('<todo-app></todo-app>', async () => {
|
||||
clearTranslations();
|
||||
// load the bundle
|
||||
await import(path.join(PACKAGE, bundle));
|
||||
// the bundle attaches the following fields to the `window` global.
|
||||
const {appReady} = window as any;
|
||||
await appReady;
|
||||
expect(document.body.textContent).toContain('liste de tâches');
|
||||
expect(document.body.textContent).toContain('Démontrer les components');
|
||||
expect(document.body.textContent).toContain('Démontrer NgModules');
|
||||
expect(document.body.textContent).toContain('4 tâches restantes');
|
||||
expect(document.querySelector('.new-todo')!.getAttribute('placeholder')).toEqual(
|
||||
`Qu'y a-t-il à faire ?`,
|
||||
);
|
||||
document.querySelector('button')!.click();
|
||||
expect(document.body.textContent).toContain('3 tâches restantes');
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
// Make the `$localize()` global function available to the compiled templates, and the direct calls
|
||||
// below. This would normally be done inside the application `polyfills.ts` file.
|
||||
import '@angular/localize/init';
|
||||
|
||||
import {computeMsgId} from '@angular/compiler';
|
||||
|
||||
export const translations = {
|
||||
[computeMsgId('What needs to be done?', '')]: `Qu'y a-t-il à faire ?`,
|
||||
[computeMsgId('{$START_HEADING_LEVEL1}todos{$CLOSE_HEADING_LEVEL1}{$TAG_INPUT}', '')]:
|
||||
'{$START_HEADING_LEVEL1}liste de tâches{$CLOSE_HEADING_LEVEL1}{$TAG_INPUT}',
|
||||
[computeMsgId('{VAR_PLURAL, plural, =1 {item left} other {items left}}', '')]:
|
||||
'{VAR_PLURAL, plural, =1 {tâche restante} other {tâches restantes}}',
|
||||
[computeMsgId('{$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG}{$ICU}', '')]:
|
||||
'{$START_TAG_STRONG}{$INTERPOLATION}{$CLOSE_TAG_STRONG} {$ICU}',
|
||||
[computeMsgId('Clear Completed', '')]: ' Effacer terminés ',
|
||||
[computeMsgId('Demonstrate Components', '')]: ' Démontrer les components',
|
||||
[computeMsgId('Demonstrate Structural Directives', '')]: 'Démontrer les directives structurelles',
|
||||
[computeMsgId('Demonstrate {$value}', '')]: 'Démontrer {$value}',
|
||||
[computeMsgId('Demonstrate zoneless change detection', '')]:
|
||||
'Démontrer la détection des changements sans zonejs',
|
||||
[computeMsgId('Demonstrate internationalization', '')]: `Démontrer l'internationalisation`,
|
||||
};
|
||||
Reference in New Issue
Block a user