Skip to content

Commit 6b868ca

Browse files
committed
fix: correct errorMsg reference in addScalarTransposition
1 parent d802b44 commit 6b868ca

File tree

13 files changed

+1604
-19
lines changed

13 files changed

+1604
-19
lines changed

css/darkmode.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,20 @@ body.dark {
6161
background-color: rgba(255, 255, 255, 0.855);
6262
border-radius: 3px;
6363
padding: 2px;
64+
}
65+
66+
/* Window table colors for dark mode */
67+
.dark .windowFrame td {
68+
background-color: #022363 !important;
69+
color: #eeeeee !important;
70+
}
71+
72+
.dark .windowFrame td.headcol {
73+
background-color: #363636 !important;
74+
color: #ffffff !important;
75+
}
76+
77+
/* Ensure bold text in cells is also light colored */
78+
.dark .windowFrame td b {
79+
color: #ffffff !important;
6480
}

index.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,11 @@
714714
link.addEventListener("click", function (e) {
715715
e.preventDefault(); // prevent default <a> behavior
716716
const selectedLang = this.id; // ID corresponds to language code
717-
localStorage.setItem("languagePreference", selectedLang);
718-
location.reload(); // automatically reload
717+
const currentLang = localStorage.getItem("languagePreference");
718+
if (currentLang !== selectedLang) {
719+
localStorage.setItem("languagePreference", selectedLang);
720+
location.reload(); // automatically reload
721+
}
719722
});
720723
});
721724
}

js/__tests__/turtle.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,4 @@ describe("Turtle", () => {
249249
expect(turtle.butNotThese).toEqual({});
250250
});
251251
});
252-
});
252+
});

js/turtle-singer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ class Singer {
377377
tur.singer.keySignature,
378378
tur.singer.movable,
379379
null,
380-
activity.logo.errorMsg,
380+
activity.errorMsg,
381381
logo.synth.inTemperament
382382
);
383383
}

js/turtleactions/VolumeActions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ function setupVolumeActions(activity) {
9797
);
9898
tur.singer.crescendoInitialVolume[synth].pop();
9999
}
100+
101+
tur.singer.inCrescendo.pop();
100102
};
101103

102104
activity.logo.setTurtleListener(turtle, listenerName, __listener);

js/utils/__tests__/utils.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,62 @@ describe("Utility Functions (logic-only)", () => {
669669
it("returns undefined for non-string input", () => {
670670
expect(resolveObject(123)).toBeUndefined();
671671
});
672+
it("returns undefined for empty string", () => {
673+
expect(resolveObject("")).toBeUndefined();
674+
});
675+
it("returns undefined for boolean input", () => {
676+
expect(resolveObject(true)).toBeUndefined();
677+
});
678+
it("returns undefined for object input", () => {
679+
expect(resolveObject({})).toBeUndefined();
680+
});
681+
it("returns undefined when null encountered in path", () => {
682+
global.TestNull = { A: null };
683+
expect(resolveObject("TestNull.A.B")).toBeUndefined();
684+
delete global.TestNull;
685+
});
686+
it("returns undefined and warns if an error occurs during resolution", () => {
687+
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
688+
689+
const originalSplit = String.prototype.split;
690+
String.prototype.split = () => {
691+
throw new Error("forced error");
692+
};
693+
expect(resolveObject("Any.Path")).toBeUndefined();
694+
expect(warnSpy).toHaveBeenCalled();
695+
String.prototype.split = originalSplit;
696+
warnSpy.mockRestore();
697+
});
698+
});
699+
describe("delayExecution()", () => {
700+
beforeEach(() => {
701+
jest.useFakeTimers();
702+
});
703+
afterEach(() => {
704+
jest.useRealTimers();
705+
});
706+
it("resolves after the specified duration", async () => {
707+
const promise = delayExecution(1000);
708+
jest.advanceTimersByTime(1000);
709+
await expect(promise).resolves.toBe(true);
710+
});
711+
it("does not resolve before duration", async () => {
712+
const promise = delayExecution(1000);
713+
714+
let resolved = false;
715+
promise.then(() => {
716+
resolved = true;
717+
});
718+
jest.advanceTimersByTime(500);
719+
await Promise.resolve();
720+
expect(resolved).toBe(false);
721+
jest.advanceTimersByTime(500);
722+
});
723+
it("resolves immediately when duration is 0", async () => {
724+
const promise = delayExecution(0);
725+
jest.advanceTimersByTime(0);
726+
await expect(promise).resolves.toBe(true);
727+
});
672728
});
673729
describe("importMembers()", () => {
674730
class DummyModel {

0 commit comments

Comments
 (0)