@angular-wave/angular.ts 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/directive/controller/controller.js +4 -4
- package/src/directive/repeat/repeat.js +0 -6
- package/src/directive/setter/setter.html +18 -0
- package/src/directive/setter/setter.js +60 -0
- package/src/directive/setter/setter.spec.js +76 -0
- package/src/directive/setter/setter.test.js +11 -0
- package/src/public.js +2 -0
- package/src/services/http/http.spec.js +2 -4
- package/types/directive/controller/controller.d.ts +2 -2
- package/types/directive/setter/setter.d.ts +7 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@angular-wave/angular.ts",
|
|
3
3
|
"description": "A modern, optimized and typesafe version of AngularJS",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.6.
|
|
5
|
+
"version": "0.6.2",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/angular-ts.esm.js",
|
|
8
8
|
"browser": "dist/angular-ts.umd.js",
|
|
@@ -280,12 +280,6 @@ export const ngRepeatDirective = [
|
|
|
280
280
|
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
|
281
281
|
// by a directive with templateUrl when its template arrives.
|
|
282
282
|
block.clone = clone;
|
|
283
|
-
$animate.enter(clone, null, previousNode);
|
|
284
|
-
previousNode = clone;
|
|
285
|
-
// Note: We only need the first/last node of the cloned nodes.
|
|
286
|
-
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
|
287
|
-
// by a directive with templateUrl when its template arrives.
|
|
288
|
-
block.clone = clone;
|
|
289
283
|
nextBlockMap[block.id] = block;
|
|
290
284
|
updateScope(
|
|
291
285
|
block.scope,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>AngularTS Test Runner</title>
|
|
6
|
+
|
|
7
|
+
<link rel="shortcut icon" type="image/png" href="/images/favicon.ico" />
|
|
8
|
+
<link rel="stylesheet" href="/jasmine/jasmine-5.1.2/jasmine.css" />
|
|
9
|
+
<script src="/jasmine/jasmine-5.1.2/jasmine.js"></script>
|
|
10
|
+
<script src="/jasmine/jasmine-5.1.2/jasmine-html.js"></script>
|
|
11
|
+
<script src="/jasmine/jasmine-5.1.2/boot0.js"></script>
|
|
12
|
+
<script src="/jasmine/jasmine-5.1.2/boot1.js"></script>
|
|
13
|
+
<script type="module" src="/src/directive/setter/setter.spec.js"></script>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="dummy"></div>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
ngSetterDirective.$inject = ["$parse"];
|
|
2
|
+
/**
|
|
3
|
+
* @returns {import('../../types.js').Directive}
|
|
4
|
+
*/
|
|
5
|
+
export function ngSetterDirective($parse) {
|
|
6
|
+
return {
|
|
7
|
+
restrict: "A",
|
|
8
|
+
link(scope, element, attrs) {
|
|
9
|
+
const modelExpression = attrs.ngSetter;
|
|
10
|
+
|
|
11
|
+
if (!modelExpression) {
|
|
12
|
+
console.warn("ngSetter: Model expression is not provided.");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const assignModel = $parse(modelExpression).assign;
|
|
17
|
+
|
|
18
|
+
if (!assignModel) {
|
|
19
|
+
console.warn("ngSetter: Invalid model expression.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const updateModel = (value) => {
|
|
24
|
+
assignModel(scope, value);
|
|
25
|
+
scope.$digest();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const observer = new MutationObserver((mutationsList) => {
|
|
29
|
+
let contentChanged = false;
|
|
30
|
+
for (const mutation of mutationsList) {
|
|
31
|
+
if (
|
|
32
|
+
mutation.type === "childList" ||
|
|
33
|
+
mutation.type === "characterData"
|
|
34
|
+
) {
|
|
35
|
+
contentChanged = true;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (contentChanged) {
|
|
41
|
+
updateModel(element[0].innerHTML);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (element && element[0]) {
|
|
46
|
+
observer.observe(element[0], {
|
|
47
|
+
childList: true,
|
|
48
|
+
subtree: true,
|
|
49
|
+
characterData: true,
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
console.warn("ngSetter: Element is not a valid DOM node.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
scope.$on("$destroy", () => observer.disconnect());
|
|
57
|
+
updateModel(element.html());
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Angular } from "../../loader.js";
|
|
2
|
+
import { wait } from "../../shared/test-utils.js";
|
|
3
|
+
|
|
4
|
+
describe("setter", () => {
|
|
5
|
+
let $compile, $rootScope, $parse, observerSpy;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
window.angular = new Angular();
|
|
9
|
+
angular.module("myModule", ["ng"]);
|
|
10
|
+
angular
|
|
11
|
+
.bootstrap(document.getElementById("dummy"), ["myModule"])
|
|
12
|
+
.invoke((_$compile_, _$rootScope_, _$parse_) => {
|
|
13
|
+
$compile = _$compile_;
|
|
14
|
+
$rootScope = _$rootScope_;
|
|
15
|
+
$parse = _$parse_;
|
|
16
|
+
});
|
|
17
|
+
observerSpy = jasmine.createSpyObj("MutationObserver", [
|
|
18
|
+
"observe",
|
|
19
|
+
"disconnect",
|
|
20
|
+
]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should update the scope model when the element content changes", async () => {
|
|
24
|
+
$rootScope.testModel = "";
|
|
25
|
+
const element = $compile('<div ng-setter="testModel"></div>')($rootScope);
|
|
26
|
+
$rootScope.$digest();
|
|
27
|
+
|
|
28
|
+
element.html("New content");
|
|
29
|
+
await wait();
|
|
30
|
+
$rootScope.$digest();
|
|
31
|
+
|
|
32
|
+
expect($rootScope.testModel).toBe("New content");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should handle initial content in the element", () => {
|
|
36
|
+
$rootScope.testModel = "";
|
|
37
|
+
const element = $compile(
|
|
38
|
+
'<div ng-setter="testModel">Initial content</div>',
|
|
39
|
+
)($rootScope);
|
|
40
|
+
$rootScope.$digest();
|
|
41
|
+
|
|
42
|
+
expect($rootScope.testModel).toBe("Initial content");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should warn if no model expression is provided", () => {
|
|
46
|
+
spyOn(console, "warn");
|
|
47
|
+
|
|
48
|
+
$compile("<div ng-setter></div>")($rootScope);
|
|
49
|
+
$rootScope.$digest();
|
|
50
|
+
|
|
51
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
52
|
+
"ngSetter: Model expression is not provided.",
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should clean up the MutationObserver on scope destruction", async () => {
|
|
57
|
+
spyOn(window, "MutationObserver").and.returnValue(observerSpy);
|
|
58
|
+
const element = $compile('<div ng-setter="testModel"></div>')($rootScope);
|
|
59
|
+
const isolateScope = element.isolateScope();
|
|
60
|
+
|
|
61
|
+
$rootScope.$destroy();
|
|
62
|
+
await wait();
|
|
63
|
+
expect(observerSpy.disconnect).toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should gracefully handle invalid DOM elements", () => {
|
|
67
|
+
spyOn(console, "warn");
|
|
68
|
+
|
|
69
|
+
const element = $compile("<div></div>")($rootScope);
|
|
70
|
+
$rootScope.$digest();
|
|
71
|
+
|
|
72
|
+
expect(console.warn).not.toHaveBeenCalledWith(
|
|
73
|
+
"ngSetter: Element is not a valid DOM node.",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { test, expect } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
const TEST_URL = "src/directive/setter/setter.html";
|
|
4
|
+
|
|
5
|
+
test("unit tests contain no errors", async ({ page }) => {
|
|
6
|
+
await page.goto(TEST_URL);
|
|
7
|
+
await page.content();
|
|
8
|
+
await expect(page.locator(".jasmine-overall-result")).toHaveText(
|
|
9
|
+
/0 failures/,
|
|
10
|
+
);
|
|
11
|
+
});
|
package/src/public.js
CHANGED
|
@@ -131,6 +131,7 @@ import {
|
|
|
131
131
|
ngView,
|
|
132
132
|
} from "./router/directives/view-directive.js";
|
|
133
133
|
import { ngChannelDirective } from "./directive/channel/channel.js";
|
|
134
|
+
import { ngSetterDirective } from "./directive/setter/setter.js";
|
|
134
135
|
|
|
135
136
|
/**
|
|
136
137
|
* @type {string} `version` from `package.json`, injected by Rollup plugin
|
|
@@ -185,6 +186,7 @@ export function publishExternalAPI(angular) {
|
|
|
185
186
|
ngNonBindable: ngNonBindableDirective,
|
|
186
187
|
ngRef: ngRefDirective,
|
|
187
188
|
ngRepeat: ngRepeatDirective,
|
|
189
|
+
ngSetter: ngSetterDirective,
|
|
188
190
|
ngShow: ngShowDirective,
|
|
189
191
|
ngStyle: ngStyleDirective,
|
|
190
192
|
ngSwitch: ngSwitchDirective,
|
|
@@ -84,7 +84,7 @@ describe("$http", function () {
|
|
|
84
84
|
expect(response.config.method).toBe("GET");
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
it("sets
|
|
87
|
+
it("sets default headers on request", async function () {
|
|
88
88
|
await $http({
|
|
89
89
|
url: "/mock/hello",
|
|
90
90
|
headers: {
|
|
@@ -96,9 +96,7 @@ describe("$http", function () {
|
|
|
96
96
|
});
|
|
97
97
|
expect(response).toBeDefined();
|
|
98
98
|
|
|
99
|
-
expect(response.config.headers.Accept).toBe(
|
|
100
|
-
"application/json, text/plain, */*",
|
|
101
|
-
);
|
|
99
|
+
expect(response.config.headers.Accept).toBe("text/plain");
|
|
102
100
|
expect(response.config.headers["Cache-Control"]).toBe("no-cache");
|
|
103
101
|
});
|
|
104
102
|
|