@schukai/monster 3.96.2 → 3.97.0
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/CHANGELOG.md +23 -94
- package/package.json +1 -1
- package/source/components/accessibility/locale-picker.mjs +598 -0
- package/source/components/accessibility/style/locale-picker.css +1 -0
- package/source/components/accessibility/style/locale-picker.pcss +26 -0
- package/source/components/accessibility/stylesheet/locale-picker.mjs +31 -0
- package/source/components/content/stylesheet/copy.mjs +2 -2
- package/source/components/datatable/datasource/rest.mjs +33 -10
- package/source/components/datatable/filter.mjs +164 -63
- package/source/components/datatable/stylesheet/change-button.mjs +2 -2
- package/source/components/datatable/stylesheet/column-bar.mjs +2 -2
- package/source/components/datatable/stylesheet/dataset.mjs +2 -2
- package/source/components/datatable/stylesheet/datasource.mjs +1 -1
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/datatable/stylesheet/embedded-pagination.mjs +2 -2
- package/source/components/datatable/stylesheet/filter-button.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-date-range.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-range.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-select.mjs +2 -2
- package/source/components/datatable/stylesheet/filter.mjs +2 -2
- package/source/components/datatable/stylesheet/pagination.mjs +1 -1
- package/source/components/datatable/stylesheet/save-button.mjs +2 -2
- package/source/components/datatable/stylesheet/status.mjs +1 -1
- package/source/components/form/form.mjs +4 -2
- package/source/components/form/stylesheet/action-button.mjs +1 -1
- package/source/components/form/stylesheet/api-bar.mjs +1 -1
- package/source/components/form/stylesheet/api-button.mjs +1 -1
- package/source/components/form/stylesheet/button-bar.mjs +1 -1
- package/source/components/form/stylesheet/button.mjs +1 -1
- package/source/components/form/stylesheet/confirm-button.mjs +1 -1
- package/source/components/form/stylesheet/context-error.mjs +1 -1
- package/source/components/form/stylesheet/context-help.mjs +1 -1
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/form.mjs +1 -1
- package/source/components/form/stylesheet/input-group.mjs +1 -1
- package/source/components/form/stylesheet/message-state-button.mjs +1 -1
- package/source/components/form/stylesheet/password.mjs +1 -1
- package/source/components/form/stylesheet/popper-button.mjs +1 -1
- package/source/components/form/stylesheet/select.mjs +1 -1
- package/source/components/form/stylesheet/state-button.mjs +1 -1
- package/source/components/form/stylesheet/toggle-switch.mjs +1 -1
- package/source/components/form/stylesheet/tree-select.mjs +1 -1
- package/source/components/host/stylesheet/call-button.mjs +2 -2
- package/source/components/host/stylesheet/config-manager.mjs +1 -1
- package/source/components/host/stylesheet/host.mjs +2 -2
- package/source/components/host/stylesheet/overlay.mjs +2 -2
- package/source/components/host/stylesheet/toggle-button.mjs +2 -2
- package/source/components/host/stylesheet/viewer.mjs +2 -2
- package/source/components/layout/stylesheet/collapse.mjs +2 -2
- package/source/components/layout/stylesheet/details.mjs +2 -2
- package/source/components/layout/stylesheet/iframe.mjs +1 -1
- package/source/components/layout/stylesheet/panel.mjs +2 -2
- package/source/components/layout/stylesheet/popper.mjs +1 -1
- package/source/components/layout/stylesheet/slider.mjs +2 -2
- package/source/components/layout/stylesheet/split-panel.mjs +1 -1
- package/source/components/layout/stylesheet/tabs.mjs +2 -2
- package/source/components/layout/stylesheet/width-toggle.mjs +1 -1
- package/source/components/navigation/stylesheet/table-of-content.mjs +2 -2
- package/source/components/notify/stylesheet/message.mjs +2 -2
- package/source/components/notify/stylesheet/notify.mjs +1 -1
- package/source/components/state/stylesheet/log.mjs +1 -1
- package/source/components/state/stylesheet/state.mjs +1 -1
- package/source/components/style/property.css +1 -0
- package/source/components/style/theme.css +4 -4
- package/source/components/stylesheet/badge.mjs +1 -1
- package/source/components/stylesheet/border.mjs +1 -1
- package/source/components/stylesheet/button.mjs +1 -1
- package/source/components/stylesheet/card.mjs +1 -1
- package/source/components/stylesheet/color.mjs +1 -1
- package/source/components/stylesheet/common.mjs +1 -1
- package/source/components/stylesheet/control.mjs +1 -1
- package/source/components/stylesheet/data-grid.mjs +1 -1
- package/source/components/stylesheet/display.mjs +1 -1
- package/source/components/stylesheet/floating-ui.mjs +1 -1
- package/source/components/stylesheet/form.mjs +1 -1
- package/source/components/stylesheet/host.mjs +1 -1
- package/source/components/stylesheet/icons.mjs +1 -1
- package/source/components/stylesheet/link.mjs +1 -1
- package/source/components/stylesheet/mixin/badge.mjs +1 -1
- package/source/components/stylesheet/mixin/button.mjs +1 -1
- package/source/components/stylesheet/mixin/hover.mjs +1 -1
- package/source/components/stylesheet/mixin/icon.mjs +1 -1
- package/source/components/stylesheet/mixin/media.mjs +1 -1
- package/source/components/stylesheet/mixin/property.mjs +1 -1
- package/source/components/stylesheet/mixin/skeleton.mjs +1 -1
- package/source/components/stylesheet/mixin/spinner.mjs +1 -1
- package/source/components/stylesheet/mixin/typography.mjs +1 -1
- package/source/components/stylesheet/normalize.mjs +1 -1
- package/source/components/stylesheet/popper.mjs +1 -1
- package/source/components/stylesheet/property.mjs +2 -2
- package/source/components/stylesheet/ripple.mjs +1 -1
- package/source/components/stylesheet/skeleton.mjs +1 -1
- package/source/components/stylesheet/space.mjs +1 -1
- package/source/components/stylesheet/spinner.mjs +1 -1
- package/source/components/stylesheet/table.mjs +1 -1
- package/source/components/stylesheet/theme.mjs +1 -1
- package/source/components/stylesheet/typography.mjs +1 -1
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
- package/source/constants.mjs +14 -1
- package/source/data/extend.mjs +2 -1
- package/source/data/transformer.mjs +2 -0
- package/source/dom/customelement.mjs +7 -3
- package/source/dom/updater.mjs +5 -1
- package/source/i18n/locale.mjs +151 -151
- package/source/i18n/map/languages.mjs +104 -0
- package/source/i18n/util.mjs +139 -0
- package/source/monster.mjs +1 -1
- package/source/text/formatter.mjs +5 -3
- package/source/types/is.mjs +13 -0
- package/source/types/proxyobserver.mjs +7 -2
- package/source/types/version.mjs +1 -1
- package/source/util/clone.mjs +9 -14
- package/test/cases/data/pathfinder.mjs +18 -0
- package/test/cases/i18n/util.mjs +295 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/text/formatter.mjs +21 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +115 -75
@@ -18,7 +18,7 @@ import { Observer } from "./observer.mjs";
|
|
18
18
|
import { ObserverList } from "./observerlist.mjs";
|
19
19
|
import { validateObject } from "./validate.mjs";
|
20
20
|
import { extend } from "../data/extend.mjs";
|
21
|
-
import { instanceSymbol } from "../constants.mjs";
|
21
|
+
import { instanceSymbol, proxyInstanceMarker } from "../constants.mjs";
|
22
22
|
import { clone } from "../util/clone.mjs";
|
23
23
|
export { ProxyObserver };
|
24
24
|
|
@@ -74,7 +74,7 @@ class ProxyObserver extends Base {
|
|
74
74
|
/**
|
75
75
|
* @since 1.24.0
|
76
76
|
* @param {Object} obj
|
77
|
-
* @return {
|
77
|
+
* @return {ProxyObserver}
|
78
78
|
*/
|
79
79
|
setSubject(obj) {
|
80
80
|
let i;
|
@@ -152,6 +152,11 @@ function getHandler() {
|
|
152
152
|
const handler = {
|
153
153
|
// https://262.ecma-international.org/9.0/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
|
154
154
|
get: function (target, key, receiver) {
|
155
|
+
// this is an internal hack to identify proxy
|
156
|
+
if (key === proxyInstanceMarker) {
|
157
|
+
return proxyInstanceMarker;
|
158
|
+
}
|
159
|
+
|
155
160
|
const value = Reflect.get(target, key, receiver);
|
156
161
|
|
157
162
|
if (typeof key === "symbol") {
|
package/source/types/version.mjs
CHANGED
package/source/util/clone.mjs
CHANGED
@@ -13,7 +13,13 @@
|
|
13
13
|
*/
|
14
14
|
|
15
15
|
import { getGlobal } from "../types/global.mjs";
|
16
|
-
import {
|
16
|
+
import {
|
17
|
+
isArray,
|
18
|
+
isFunction,
|
19
|
+
isObject,
|
20
|
+
isPrimitive,
|
21
|
+
isProxy,
|
22
|
+
} from "../types/is.mjs";
|
17
23
|
import { typeOf } from "../types/typeof.mjs";
|
18
24
|
import { validateObject } from "../types/validate.mjs";
|
19
25
|
|
@@ -71,8 +77,7 @@ function clone(obj) {
|
|
71
77
|
|
72
78
|
/** Do not clone DOM nodes */
|
73
79
|
if (typeof Element !== "undefined" && obj instanceof Element) return obj;
|
74
|
-
if (typeof
|
75
|
-
return obj;
|
80
|
+
if (typeof Document !== "undefined" && obj instanceof Document) return obj;
|
76
81
|
if (
|
77
82
|
typeof DocumentFragment !== "undefined" &&
|
78
83
|
obj instanceof DocumentFragment
|
@@ -81,21 +86,11 @@ function clone(obj) {
|
|
81
86
|
|
82
87
|
/** Do not clone global objects */
|
83
88
|
if (obj === getGlobal()) return obj;
|
84
|
-
if (typeof globalContext !== "undefined" && obj === globalContext)
|
85
|
-
return obj;
|
86
89
|
if (typeof window !== "undefined" && obj === window) return obj;
|
87
90
|
if (typeof document !== "undefined" && obj === document) return obj;
|
88
91
|
if (typeof navigator !== "undefined" && obj === navigator) return obj;
|
89
92
|
if (typeof JSON !== "undefined" && obj === JSON) return obj;
|
90
|
-
|
91
|
-
// Handle Proxy-Object
|
92
|
-
try {
|
93
|
-
// try/catch because possible: TypeError: Function has non-object prototype 'undefined' in instanceof check
|
94
|
-
if (obj instanceof Proxy) {
|
95
|
-
return obj;
|
96
|
-
}
|
97
|
-
} catch (e) {}
|
98
|
-
|
93
|
+
if (isProxy(obj)) return obj; // Handle Proxy-Object
|
99
94
|
return cloneObject(obj);
|
100
95
|
}
|
101
96
|
|
@@ -22,6 +22,24 @@ describe('Pathfinder', function () {
|
|
22
22
|
return r;
|
23
23
|
}
|
24
24
|
|
25
|
+
describe("value is not an integer issue #274", function () {
|
26
|
+
it("should not be fail with", function () {
|
27
|
+
|
28
|
+
const pf = new Pathfinder({
|
29
|
+
data: {}
|
30
|
+
});
|
31
|
+
|
32
|
+
try {
|
33
|
+
pf.setVia("data.age", 10);
|
34
|
+
} catch (e) {
|
35
|
+
expect(e).to.be.null;
|
36
|
+
}
|
37
|
+
|
38
|
+
expect(pf.getVia("data.age")).to.be.equal(10);
|
39
|
+
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
25
43
|
|
26
44
|
describe('with Wildcard and Iterations', function () {
|
27
45
|
let pf, obj;
|
@@ -0,0 +1,295 @@
|
|
1
|
+
import {getGlobal} from "../../../source/types/global.mjs";
|
2
|
+
|
3
|
+
import * as chai from 'chai';
|
4
|
+
import {chaiDom} from "../../util/chai-dom.mjs";
|
5
|
+
import {initJSDOM} from "../../util/jsdom.mjs";
|
6
|
+
|
7
|
+
let expect = chai.expect;
|
8
|
+
chai.use(chaiDom);
|
9
|
+
|
10
|
+
describe('LocalPicker', function () {
|
11
|
+
|
12
|
+
let LocalPicker, documentLanguage, linkTags, originalLanguages, getPreferredLanguage;
|
13
|
+
|
14
|
+
before(function (done) {
|
15
|
+
initJSDOM().then(() => {
|
16
|
+
|
17
|
+
documentLanguage = document.documentElement.lang;
|
18
|
+
linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
|
19
|
+
linkTags.forEach(item => item.remove());
|
20
|
+
|
21
|
+
import("element-internals-polyfill").catch(e => done(e));
|
22
|
+
|
23
|
+
import("../../../source/i18n/util.mjs").then((m) => {
|
24
|
+
|
25
|
+
LocalPicker = m['LocalPicker'];
|
26
|
+
getPreferredLanguage = m['detectUserLanguagePreference'];
|
27
|
+
|
28
|
+
originalLanguages = navigator.languages;
|
29
|
+
|
30
|
+
done()
|
31
|
+
}).catch(e => done(e))
|
32
|
+
|
33
|
+
|
34
|
+
});
|
35
|
+
})
|
36
|
+
|
37
|
+
after(function () {
|
38
|
+
document.documentElement.lang = documentLanguage;
|
39
|
+
|
40
|
+
linkTags.forEach(item => {
|
41
|
+
const link = document.createElement('link');
|
42
|
+
link.setAttribute('rel', 'alternate');
|
43
|
+
link.setAttribute('hreflang', item.hreflang);
|
44
|
+
link.setAttribute('href', item.href);
|
45
|
+
|
46
|
+
// check if already exits
|
47
|
+
if (!document.querySelector(`link[hreflang="${item.hreflang}"]`)) {
|
48
|
+
document.querySelector('head').appendChild(link);
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
|
53
|
+
Object.defineProperty(navigator, 'languages', {
|
54
|
+
value: originalLanguages,
|
55
|
+
writable: true
|
56
|
+
});
|
57
|
+
|
58
|
+
|
59
|
+
})
|
60
|
+
|
61
|
+
// Hilfsfunktion zum Setup eines JSDOM-Dokuments mit <html> und ggf. link-Tags
|
62
|
+
function setupDOM({htmlLang = '', linkHreflangs = [], navLang = ""}) {
|
63
|
+
|
64
|
+
linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
|
65
|
+
linkTags.forEach(item => item.remove());
|
66
|
+
|
67
|
+
// Links hinzufügen
|
68
|
+
const head = window.document.querySelector('head');
|
69
|
+
linkHreflangs.forEach(item => {
|
70
|
+
const link = window.document.createElement('link');
|
71
|
+
link.setAttribute('rel', 'alternate');
|
72
|
+
link.setAttribute('hreflang', item.hreflang);
|
73
|
+
link.setAttribute('href', item.href);
|
74
|
+
head.appendChild(link);
|
75
|
+
});
|
76
|
+
|
77
|
+
window.document.documentElement.lang = htmlLang;
|
78
|
+
|
79
|
+
|
80
|
+
Object.defineProperty(navigator, 'language', {
|
81
|
+
value: navLang[0] || "",
|
82
|
+
writable: true
|
83
|
+
});
|
84
|
+
|
85
|
+
Object.defineProperty(navigator, 'languages', {
|
86
|
+
value: navLang,
|
87
|
+
writable: true
|
88
|
+
});
|
89
|
+
}
|
90
|
+
|
91
|
+
describe('getPreferredLanguage()', () => {
|
92
|
+
|
93
|
+
// 1) No document language, no navigator.languages => "No language information available."
|
94
|
+
it('should return "No language information available." when no current and no user preferences', () => {
|
95
|
+
setupDOM({htmlLang: '', linkHreflangs: [], navLang: []});
|
96
|
+
|
97
|
+
const result = getPreferredLanguage();
|
98
|
+
expect(result).to.have.property('message').that.not.empty;
|
99
|
+
});
|
100
|
+
|
101
|
+
// 2) Document lang is set, but no <link> tags => "No <link> tags with hreflang available."
|
102
|
+
it('should return "No <link> tags with hreflang available." when there are no link tags', () => {
|
103
|
+
setupDOM({htmlLang: 'en', linkHreflangs: []});
|
104
|
+
window.navigator.languages = [];
|
105
|
+
|
106
|
+
const result = getPreferredLanguage();
|
107
|
+
expect(result).to.have.property('current', 'en');
|
108
|
+
expect(result).to.have.property('message').that.equals('No <link> tags with hreflang available.');
|
109
|
+
});
|
110
|
+
|
111
|
+
// 3) Document lang 'en', no user preferences, but link tags exist => "None of the preferred languages are available."
|
112
|
+
it('should return "None of the preferred languages are available." when there are link tags but no matching user preferences', () => {
|
113
|
+
setupDOM({
|
114
|
+
htmlLang: 'en',
|
115
|
+
linkHreflangs: [
|
116
|
+
{hreflang: 'de', href: 'http://example.com/de'},
|
117
|
+
{hreflang: 'fr', href: 'http://example.com/fr'}
|
118
|
+
],
|
119
|
+
navLang: []
|
120
|
+
});
|
121
|
+
|
122
|
+
const result = getPreferredLanguage();
|
123
|
+
expect(result).to.have.property('current', 'en');
|
124
|
+
expect(result).to.have.property('message').that.equals('No available languages match the user\'s preferences.');
|
125
|
+
expect(result.available).to.be.an('array').that.has.lengthOf(2);
|
126
|
+
});
|
127
|
+
|
128
|
+
// 4) Document lang 'en', user prefers ['en'], link tags with 'en' and 'de' => best match is 'en'
|
129
|
+
it('should return best match = "en" when user prefers en', () => {
|
130
|
+
setupDOM({
|
131
|
+
htmlLang: 'en',
|
132
|
+
linkHreflangs: [
|
133
|
+
{hreflang: 'en', href: 'http://example.com/en'},
|
134
|
+
{hreflang: 'de', href: 'http://example.com/de'}
|
135
|
+
]
|
136
|
+
});
|
137
|
+
window.navigator.languages = ['en'];
|
138
|
+
|
139
|
+
const result = getPreferredLanguage();
|
140
|
+
expect(result).to.have.property('current', 'en');
|
141
|
+
console.log(JSON.stringify(result.preferred));
|
142
|
+
expect(result.preferred).to.have.property('full', "en");
|
143
|
+
expect(result.preferred).to.have.property('base', "en");
|
144
|
+
expect(result.preferred).to.have.property('label', "English");
|
145
|
+
expect(result.preferred).to.have.property('href', "http://example.com/en");
|
146
|
+
});
|
147
|
+
|
148
|
+
// 5) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
|
149
|
+
it('should return best match = "de-DE" when user prefers de-DE', () => {
|
150
|
+
setupDOM({
|
151
|
+
htmlLang: 'de-DE',
|
152
|
+
linkHreflangs: [
|
153
|
+
{hreflang: 'de-DE', href: 'http://example.com/de-DE'},
|
154
|
+
{hreflang: 'en-US', href: 'http://example.com/en-US'}
|
155
|
+
]
|
156
|
+
});
|
157
|
+
window.navigator.languages = ['de-DE'];
|
158
|
+
|
159
|
+
const result = getPreferredLanguage();
|
160
|
+
expect(result).to.have.property('current', 'de-DE');
|
161
|
+
|
162
|
+
expect(result.preferred).to.have.property('full', "de-DE");
|
163
|
+
expect(result.preferred).to.have.property('base', "de");
|
164
|
+
expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
|
165
|
+
expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
|
166
|
+
|
167
|
+
});
|
168
|
+
|
169
|
+
|
170
|
+
// 5x) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
|
171
|
+
it('should return best match = "de-DE" when user prefers de-DE', () => {
|
172
|
+
setupDOM({
|
173
|
+
htmlLang: 'en',
|
174
|
+
linkHreflangs: [
|
175
|
+
{hreflang: 'de', href: 'http://example.com/de-DE'},
|
176
|
+
{hreflang: 'en', href: 'http://example.com/en-US'}
|
177
|
+
]
|
178
|
+
});
|
179
|
+
window.navigator.languages = ['de-DE'];
|
180
|
+
|
181
|
+
const result = getPreferredLanguage();
|
182
|
+
expect(result).to.have.property('current', 'en');
|
183
|
+
|
184
|
+
expect(result.preferred).to.have.property('full', "de");
|
185
|
+
expect(result.preferred).to.have.property('base', "de");
|
186
|
+
expect(result.preferred).to.have.property('label', "Deutsch");
|
187
|
+
expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
|
188
|
+
|
189
|
+
});
|
190
|
+
|
191
|
+
// 6) Document lang 'de-DE', user prefers ['en-US', 'en'], link tags with 'en-US' & 'en-GB' => best match = 'en-US'
|
192
|
+
it('should return best match = "en-US" for user preferences [en-US, en]', () => {
|
193
|
+
setupDOM({
|
194
|
+
htmlLang: 'de-DE',
|
195
|
+
linkHreflangs: [
|
196
|
+
{hreflang: 'en-US', href: 'http://example.com/en-US'},
|
197
|
+
{hreflang: 'en-GB', href: 'http://example.com/en-GB'}
|
198
|
+
]
|
199
|
+
});
|
200
|
+
window.navigator.languages = ['en-US', 'en'];
|
201
|
+
|
202
|
+
const result = getPreferredLanguage();
|
203
|
+
expect(result).to.have.property('current', 'de-DE');
|
204
|
+
expect(result.preferred).to.have.property('full', "en-US");
|
205
|
+
expect(result.preferred).to.have.property('base', "en");
|
206
|
+
expect(result.preferred).to.have.property('label', "English (United States)");
|
207
|
+
expect(result.preferred).to.have.property('href', "http://example.com/en-US");
|
208
|
+
|
209
|
+
});
|
210
|
+
|
211
|
+
// 7) Document lang 'de-DE', user prefers ['de','en'], link tags with 'de-DE' & 'en-US' => best match = 'de-DE' (baseLang = 'de')
|
212
|
+
it('should return best match = "de-DE" when user preferences include its base language "de"', () => {
|
213
|
+
setupDOM({
|
214
|
+
htmlLang: 'de-DE',
|
215
|
+
linkHreflangs: [
|
216
|
+
{hreflang: 'de-DE', href: 'http://example.com/de-DE'},
|
217
|
+
{hreflang: 'en-US', href: 'http://example.com/en-US'}
|
218
|
+
]
|
219
|
+
});
|
220
|
+
window.navigator.languages = ['de', 'en'];
|
221
|
+
|
222
|
+
const result = getPreferredLanguage();
|
223
|
+
expect(result).to.have.property('current', 'de-DE');
|
224
|
+
|
225
|
+
expect(result.preferred).to.have.property('full', "de-DE");
|
226
|
+
expect(result.preferred).to.have.property('base', "de");
|
227
|
+
expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
|
228
|
+
expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
|
229
|
+
|
230
|
+
});
|
231
|
+
|
232
|
+
// 8) Multiple link tags share the same weight => the first in the sorted array should be returned
|
233
|
+
it('should return the first item when multiple link tags have the same weight', () => {
|
234
|
+
setupDOM({
|
235
|
+
htmlLang: 'en',
|
236
|
+
linkHreflangs: [
|
237
|
+
{hreflang: 'fr', href: 'http://example.com/fr'},
|
238
|
+
{hreflang: 'es', href: 'http://example.com/es'}
|
239
|
+
]
|
240
|
+
});
|
241
|
+
// Neither "fr" nor "es" is in the user preferences => both have weight = 1
|
242
|
+
window.navigator.languages = ['de'];
|
243
|
+
|
244
|
+
const result = getPreferredLanguage();
|
245
|
+
// Both 'fr' and 'es' have weight 1. After sorting, 'fr' appears first (as it was added first).
|
246
|
+
expect(result.available[0].fullLang).to.equal('fr');
|
247
|
+
expect(result.available[1].fullLang).to.equal('es');
|
248
|
+
expect(result.offerable).to.be.undefined;
|
249
|
+
expect(result).to.have.property('message', 'No available languages match the user\'s preferences.');
|
250
|
+
});
|
251
|
+
|
252
|
+
// 9) Check that bestURL is returned if a best match is found
|
253
|
+
it('should include bestURL when a best match is found', () => {
|
254
|
+
setupDOM({
|
255
|
+
htmlLang: 'fr',
|
256
|
+
linkHreflangs: [
|
257
|
+
{hreflang: 'fr-FR', href: 'http://example.com/fr-FR'},
|
258
|
+
{hreflang: 'de-DE', href: 'http://example.com/de-DE'}
|
259
|
+
]
|
260
|
+
});
|
261
|
+
window.navigator.languages = ['fr-FR', 'de-DE'];
|
262
|
+
|
263
|
+
const result = getPreferredLanguage();
|
264
|
+
|
265
|
+
expect(result.preferred).to.have.property('full', "fr-FR");
|
266
|
+
expect(result.preferred).to.have.property('base', "fr");
|
267
|
+
expect(result.preferred).to.have.property('label', "Français (France)");
|
268
|
+
expect(result.preferred).to.have.property('href', "http://example.com/fr-FR");
|
269
|
+
|
270
|
+
});
|
271
|
+
|
272
|
+
// 10) Check presence of availableLanguages array, ensuring it has weight info
|
273
|
+
it('should return availableLanguages with weight for each link', () => {
|
274
|
+
setupDOM({
|
275
|
+
htmlLang: 'en-GB',
|
276
|
+
linkHreflangs: [
|
277
|
+
{hreflang: 'en-GB', href: 'http://example.com/en-GB'},
|
278
|
+
{hreflang: 'en-US', href: 'http://example.com/en-US'}
|
279
|
+
]
|
280
|
+
});
|
281
|
+
window.navigator.languages = ['en-GB', 'en', 'en-US'];
|
282
|
+
|
283
|
+
const result = getPreferredLanguage();
|
284
|
+
expect(result.available).to.be.an('array').with.lengthOf(2);
|
285
|
+
result.available.forEach(item => {
|
286
|
+
expect(item).to.have.property('weight');
|
287
|
+
expect(item).to.have.property('fullLang');
|
288
|
+
expect(item).to.have.property('baseLang');
|
289
|
+
expect(item).to.have.property('href');
|
290
|
+
});
|
291
|
+
});
|
292
|
+
|
293
|
+
});
|
294
|
+
|
295
|
+
})
|
package/test/cases/monster.mjs
CHANGED
@@ -4,7 +4,27 @@ import {Formatter} from "../../../source/text/formatter.mjs";
|
|
4
4
|
|
5
5
|
describe('Formatter', function () {
|
6
6
|
|
7
|
-
// https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/
|
7
|
+
// https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/275
|
8
|
+
describe('change empty handling', function () {
|
9
|
+
|
10
|
+
it('modification 1', function () {
|
11
|
+
|
12
|
+
const formatter = new Formatter({
|
13
|
+
|
14
|
+
a: null,
|
15
|
+
b: undefined,
|
16
|
+
c : 0
|
17
|
+
|
18
|
+
|
19
|
+
})
|
20
|
+
|
21
|
+
expect(formatter.format("${a | tostring}")).to.be.equal('null');
|
22
|
+
expect(formatter.format("${b | tostring}")).to.be.equal('undefined');
|
23
|
+
expect(formatter.format("${c | tostring}")).to.be.equal('0');
|
24
|
+
})
|
25
|
+
})
|
26
|
+
|
27
|
+
// https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/47
|
8
28
|
describe('examples', function () {
|
9
29
|
|
10
30
|
it('rfc example should run', function () {
|
package/test/web/test.html
CHANGED
@@ -9,8 +9,8 @@
|
|
9
9
|
</head>
|
10
10
|
<body>
|
11
11
|
<div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
|
12
|
-
<h1 style='margin-bottom: 0.1em;'>Monster 3.96.
|
13
|
-
<div id="lastupdate" style='font-size:0.7em'>last update
|
12
|
+
<h1 style='margin-bottom: 0.1em;'>Monster 3.96.2</h1>
|
13
|
+
<div id="lastupdate" style='font-size:0.7em'>last update Fr 3. Jan 15:17:06 CET 2025</div>
|
14
14
|
</div>
|
15
15
|
<div id="mocha-errors"
|
16
16
|
style="color: red;font-weight: bold;display: flex;align-items: center;justify-content: center;flex-direction: column;margin:20px;"></div>
|