Use American English spelling throughout
This commit is contained in:
@@ -243,7 +243,7 @@ describe("updateEvent, per occurrence", () => {
|
||||
});
|
||||
|
||||
describe("isThisAndFutureRefusal", () => {
|
||||
it("recognises the refusal worth offering the series for", () => {
|
||||
it("recognizes the refusal worth offering the series for", () => {
|
||||
expect(isThisAndFutureRefusal(new CalendarSetError({
|
||||
type: "invalidProperties",
|
||||
description: "Occurrences of a this-and-future change cannot be modified individually.",
|
||||
|
||||
@@ -264,7 +264,7 @@ describe("importing a file bigger than the server will take at once", () => {
|
||||
* Re-importing the same file.
|
||||
*
|
||||
* The import kept the file's own UID from the day it was written, which is the
|
||||
* whole of what is needed to recognise an event that is already here -- and
|
||||
* whole of what is needed to recognize an event that is already here -- and
|
||||
* nothing looked. Importing an export twice left second copies of everything,
|
||||
* which the reporter's colleague hit during testing (#173, decided there:
|
||||
* "duplicate checks on UIDs if UID present in event"). Issue #222 made that a
|
||||
|
||||
@@ -35,7 +35,7 @@ describe("applyLang", () => {
|
||||
expect(document.documentElement.lang).toBe("en");
|
||||
});
|
||||
|
||||
it("serves every language whose catalogue is shipped", () => {
|
||||
it("serves every language whose catalog is shipped", () => {
|
||||
for (const l of UI_LANGUAGES) {
|
||||
applyLang({ ...DEFAULT_SETTINGS, uiLanguage: l.tag });
|
||||
expect(document.documentElement.lang).toBe(l.tag);
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("importing an LDIF address book", () => {
|
||||
const uids = Object.values(sets[0]!.create!).map((c) => c.uid as string);
|
||||
expect(new Set(uids).size).toBe(2);
|
||||
// Namespaced, so it is never mistaken for a UID a vCard author meant, and
|
||||
// stable, so importing the same file again recognises these.
|
||||
// stable, so importing the same file again recognizes these.
|
||||
expect(uids.every((u) => u.startsWith("urn:x-ihasmail:ldif:"))).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ describe("telling somebody what an LDIF re-import duplicated", () => {
|
||||
expect(r.alike).toBe(0);
|
||||
});
|
||||
|
||||
it("recognises a match on a second address", async () => {
|
||||
it("recognizes a match on a second address", async () => {
|
||||
server([card("c1", "Jane Doe", "[email protected]", "[email protected]")]);
|
||||
const r = await useContacts.getState().importLdif(entry("Jane Doe", "[email protected]"), "book1");
|
||||
expect(r.alike).toBe(1);
|
||||
|
||||
@@ -19,13 +19,13 @@ describe("isRecurring", () => {
|
||||
// and a base that is a different id. Neither makes it a series.
|
||||
expect(isRecurring(ev({ id: "eaaaaai", baseEventId: "i" }))).toBe(false);
|
||||
});
|
||||
it("recognises a series by its rule, under either name", () => {
|
||||
it("recognizes a series by its rule, under either name", () => {
|
||||
expect(isRecurring(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "weekly" }] }))).toBe(true);
|
||||
expect(isRecurring(ev({ excludedRecurrenceRules: [{ "@type": "RecurrenceRule", frequency: "monthly" }] }))).toBe(true);
|
||||
// Stalwart 0.16 keeps a single rule under the singular name.
|
||||
expect(isRecurring(ev({ recurrenceRule: { "@type": "RecurrenceRule", frequency: "weekly", count: 3 } }))).toBe(true);
|
||||
});
|
||||
it("recognises an occurrence, which arrives with no rule of its own", () => {
|
||||
it("recognizes an occurrence, which arrives with no rule of its own", () => {
|
||||
// A live 0.16.19 expands a weekly series into instances like this: an id
|
||||
// per occurrence, a recurrenceId, and no rule attached.
|
||||
expect(isRecurring(ev({ id: "iaaaaas", recurrenceId: "2030-03-11T10:00:00" }))).toBe(true);
|
||||
|
||||
@@ -73,7 +73,7 @@ describe("replying to a message somebody sent me", () => {
|
||||
expect(addrs(d.cc)).toEqual([BOB.email]);
|
||||
});
|
||||
|
||||
it("honours the sender's Reply-To, which is what it is for", async () => {
|
||||
it("honors the sender's Reply-To, which is what it is for", async () => {
|
||||
const d = await draftFor({ ...HERS, replyTo: [{ name: null, email: "[email protected]" }] } as Email, "reply");
|
||||
expect(addrs(d.to)).toEqual(["[email protected]"]);
|
||||
});
|
||||
@@ -105,7 +105,7 @@ describe("replying to a message I sent", () => {
|
||||
expect(addrs(d.cc)).toEqual([BOB.email]);
|
||||
});
|
||||
|
||||
it("recognises my address however the identity stored it", async () => {
|
||||
it("recognizes my address however the identity stored it", async () => {
|
||||
// A hand-typed identity address can carry whitespace, and comparing
|
||||
// strings rather than addresses made that enough to break the reply.
|
||||
const padded = [{ id: "i1", name: "John", email: " [email protected] " }] as unknown as Identity[];
|
||||
|
||||
@@ -111,7 +111,7 @@ describe("reconcile", () => {
|
||||
expect(useScheduled.getState().pending).toEqual({});
|
||||
});
|
||||
|
||||
it("returns a message cancelled elsewhere to Drafts, as a draft again", async () => {
|
||||
it("returns a message canceled elsewhere to Drafts, as a draft again", async () => {
|
||||
const s = server(["e1"], [{ id: "s1", emailId: "e1", sendAt: FUTURE, undoStatus: "canceled" }]);
|
||||
await useScheduled.getState().reconcile();
|
||||
expect(moved(s.updates[0]!.e1!)).toEqual({ into: DRAFTS, outOf: SCHED });
|
||||
@@ -156,7 +156,7 @@ describe("reconcile", () => {
|
||||
});
|
||||
|
||||
it("keeps a message whose live hold was moved earlier than the one it replaced", async () => {
|
||||
// Rescheduling to a sooner time leaves the cancelled submission holding the
|
||||
// Rescheduling to a sooner time leaves the canceled submission holding the
|
||||
// later sendAt. Going by timestamp alone would file a message back to
|
||||
// Drafts while the queue still has it.
|
||||
const s = server(
|
||||
|
||||
@@ -333,11 +333,11 @@ function forImport(event: Partial<CalendarEvent>): Partial<CalendarEvent> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The events a calendar already holds, for recognising a re-import.
|
||||
* The events a calendar already holds, for recognizing a re-import.
|
||||
*
|
||||
* A UID is what makes an event the same event across calendars, and the import
|
||||
* already keeps the file's own wherever there is one -- so the thing needed to
|
||||
* recognise a re-import was there all along and nothing looked at it. Asked for
|
||||
* recognize a re-import was there all along and nothing looked at it. Asked for
|
||||
* once per import rather than once per event: `CalendarEvent/query` does take a
|
||||
* `uid` filter, but a file of two thousand events would be two thousand
|
||||
* queries.
|
||||
@@ -618,7 +618,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
|
||||
for (const b of birthdaysInRange(Object.values(useContacts.getState().cards), start, end)) {
|
||||
birthdays.push({
|
||||
key: b.id,
|
||||
event: synthesiseBirthdayEvent(b),
|
||||
event: synthesizeBirthdayEvent(b),
|
||||
start: b.date,
|
||||
end: new Date(b.date.getTime() + DAY_MS),
|
||||
allDay: true,
|
||||
@@ -639,7 +639,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
|
||||
if (e.end <= start || e.start >= end) continue;
|
||||
birthdays.push({
|
||||
key: `${calId}:${e.uid}:${e.start.getTime()}`,
|
||||
event: synthesiseSubscriptionEvent(sub.id, e),
|
||||
event: synthesizeSubscriptionEvent(sub.id, e),
|
||||
start: e.start,
|
||||
end: e.end,
|
||||
allDay: e.allDay,
|
||||
@@ -821,7 +821,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
|
||||
*
|
||||
* The query deliberately omits `expandRecurrences`, so what comes back is the
|
||||
* stored event and `id` is a real id. Callers rely on that — `InviteCard`
|
||||
* removes a cancelled event by handing this straight to `destroyEvent` — so
|
||||
* removes a canceled event by handing this straight to `destroyEvent` — so
|
||||
* it is a property of this method, not an accident of the default.
|
||||
*/
|
||||
async findByUid(uid) {
|
||||
@@ -881,7 +881,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
|
||||
* the disagreement. Weighed on #279 and kept: an import is not the place to
|
||||
* start sending mail on somebody's behalf, and the alternative is a file
|
||||
* dropped into a calendar mailing a room full of people who never asked for
|
||||
* it. Whoever is organising can send the update from the event itself.
|
||||
* it. Whoever is organizing can send the update from the event itself.
|
||||
*/
|
||||
async importIcs(text, calendarId) {
|
||||
const accountId = get().accountId!;
|
||||
@@ -984,7 +984,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
|
||||
* flattened the rule would import somewhere else as an unmaintainable pile.
|
||||
*
|
||||
* Written in the browser, unlike the import, which hands the parsing to the
|
||||
* server. There is no `CalendarEvent/serialise` to hand this to -- the JMAP
|
||||
* server. There is no `CalendarEvent/serialize` to hand this to -- the JMAP
|
||||
* calendar drafts define parsing and nothing the other way -- so it is done
|
||||
* here from the objects the server already returns.
|
||||
*/
|
||||
@@ -1053,7 +1053,7 @@ function birthdayCalendar(): Calendar {
|
||||
}
|
||||
|
||||
/** A CalendarEvent shaped enough for the views, and for nothing else. */
|
||||
function synthesiseBirthdayEvent(b: Birthday): CalendarEvent {
|
||||
function synthesizeBirthdayEvent(b: Birthday): CalendarEvent {
|
||||
const local = `${b.date.getFullYear()}-${String(b.date.getMonth() + 1).padStart(2, "0")}-${String(b.date.getDate()).padStart(2, "0")}T00:00:00`;
|
||||
return {
|
||||
id: b.id,
|
||||
@@ -1088,7 +1088,7 @@ function subscriptionCalendar(sub: { id: string; name: string; color: string }):
|
||||
} as unknown as Calendar;
|
||||
}
|
||||
|
||||
function synthesiseSubscriptionEvent(subId: string, e: IcsEvent): CalendarEvent {
|
||||
function synthesizeSubscriptionEvent(subId: string, e: IcsEvent): CalendarEvent {
|
||||
const local = `${e.start.getFullYear()}-${String(e.start.getMonth() + 1).padStart(2, "0")}-${String(e.start.getDate()).padStart(2, "0")}T${String(e.start.getHours()).padStart(2, "0")}:${String(e.start.getMinutes()).padStart(2, "0")}:00`;
|
||||
return {
|
||||
id: `${subscriptionCalendarId(subId)}:${e.uid}`,
|
||||
|
||||
@@ -623,7 +623,7 @@ export const useCompose = create<ComposeState>((set, get) => ({
|
||||
});
|
||||
}
|
||||
};
|
||||
// A scheduled send is already delayed, and cancelling it is a server-side
|
||||
// A scheduled send is already delayed, and canceling it is a server-side
|
||||
// operation from the Scheduled folder -- holding it locally first would
|
||||
// only add a second, different kind of undo.
|
||||
if (delay <= 0 || scheduling) {
|
||||
|
||||
@@ -83,7 +83,7 @@ async function scanBook(accountId: Id, addressBookId: Id): Promise<{ byUid: Map<
|
||||
* confusion rather than duplication, and being told costs nothing.
|
||||
*
|
||||
* One key per address, so a person whose second address matches is still
|
||||
* recognised.
|
||||
* recognized.
|
||||
*/
|
||||
function likenessKeys(c: Partial<ContactCard>): string[] {
|
||||
const name = contactDisplayName(c as ContactCard).trim().toLowerCase();
|
||||
@@ -225,7 +225,7 @@ interface ContactsState {
|
||||
/**
|
||||
* Import an address book in LDIF, read against Mozilla's schema.
|
||||
*
|
||||
* Mozilla's schema has no UID, so a re-import is recognised by the entry's
|
||||
* Mozilla's schema has no UID, so a re-import is recognized by the entry's
|
||||
* `dn` instead -- the same update-rather-than-duplicate rule the vCard import
|
||||
* follows, on the only identity the file carries. `alike` is what is left
|
||||
* over: entries that were created and still look like somebody already here,
|
||||
|
||||
@@ -1331,7 +1331,7 @@ async function notifyNewMail(created: Id[], get: () => MailState) {
|
||||
onClick: () => {
|
||||
window.location.hash = "";
|
||||
// The one navigation that does not go through wouter -- it is
|
||||
// synthesising a popstate so the router picks the address up -- so
|
||||
// synthesizing a popstate so the router picks the address up -- so
|
||||
// it is also the one that has to add the mount prefix itself.
|
||||
window.history.pushState({}, "", withBase(`/mail/${inbox}/${e.threadId}`));
|
||||
window.dispatchEvent(new PopStateEvent("popstate"));
|
||||
|
||||
@@ -177,7 +177,7 @@ export const useScheduled = create<ScheduledState>((set, get) => ({
|
||||
* Nothing moves a message out of Scheduled when its hold expires -- the
|
||||
* server sends it and updates the submission, but the message stays where we
|
||||
* filed it. So on the way into the folder, settle up: what went out belongs
|
||||
* in Sent, what was cancelled elsewhere belongs back in Drafts.
|
||||
* in Sent, what was canceled elsewhere belongs back in Drafts.
|
||||
*/
|
||||
async reconcile() {
|
||||
const mail = useMail.getState();
|
||||
@@ -215,7 +215,7 @@ export const useScheduled = create<ScheduledState>((set, get) => ({
|
||||
pending[emailId] = s;
|
||||
continue;
|
||||
}
|
||||
// Cancelled goes back to Drafts; sent (or a submission the server no
|
||||
// Canceled goes back to Drafts; sent (or a submission the server no
|
||||
// longer knows about) goes to Sent, which is where it actually is.
|
||||
const toDrafts = s?.undoStatus === "canceled";
|
||||
const dest = toDrafts ? draftsId : sentId;
|
||||
|
||||
@@ -26,7 +26,7 @@ interface SessionState {
|
||||
logout(): Promise<void>;
|
||||
refresh(): Promise<void>;
|
||||
setAccount(id: Id): void;
|
||||
/** The account to read and write for a capability, honouring the account switcher. */
|
||||
/** The account to read and write for a capability, honoring the account switcher. */
|
||||
accountFor(cap: string): Id | null;
|
||||
/** The user's own account for a capability, whatever they are looking at. */
|
||||
ownAccountFor(cap: string): Id | null;
|
||||
|
||||
+10
-10
@@ -13,7 +13,7 @@ import { loadLanguage } from "@/lib/i18n";
|
||||
/**
|
||||
* "ihasmail" is a dark theme carrying the palette from ihasmail.org. It is a
|
||||
* theme rather than an accent because it changes the backgrounds, borders and
|
||||
* text as well as the highlight colour — an accent could not.
|
||||
* text as well as the highlight color — an accent could not.
|
||||
*/
|
||||
export type Theme = "system" | "light" | "dark" | "ihasmail";
|
||||
export type Density = "comfortable" | "cozy" | "compact";
|
||||
@@ -83,7 +83,7 @@ export interface Settings {
|
||||
* which is the half that stops an older device showing a theme nobody chose.
|
||||
*/
|
||||
theme: Theme;
|
||||
/** The colours. */
|
||||
/** The colors. */
|
||||
palette: PaletteId;
|
||||
/** Light, dark, or whatever the system says. */
|
||||
mode: Mode;
|
||||
@@ -131,7 +131,7 @@ export interface Settings {
|
||||
/** Let messages follow the app's light/dark theme instead of always sitting on white. */
|
||||
themeMessageBody: boolean;
|
||||
/**
|
||||
* Extend that to mail which brings colours of its own.
|
||||
* Extend that to mail which brings colors of its own.
|
||||
*
|
||||
* Only meaningful with `themeMessageBody` on. Off by default because it
|
||||
* cannot be done perfectly: see `markKeptSurfaces` in lib/html.ts for the
|
||||
@@ -225,8 +225,8 @@ export interface Settings {
|
||||
templates: Template[];
|
||||
labels: Label[];
|
||||
/**
|
||||
* Folder colours, by mailbox id. Local to this browser, like every other
|
||||
* colour here: JMAP has nowhere on a Mailbox to keep one.
|
||||
* Folder colors, by mailbox id. Local to this browser, like every other
|
||||
* color here: JMAP has nowhere on a Mailbox to keep one.
|
||||
*/
|
||||
folderColors: Record<string, string>;
|
||||
sidebarCollapsed: boolean;
|
||||
@@ -265,7 +265,7 @@ export interface Settings {
|
||||
* sidebar with their own CSS keeps what they had until they choose otherwise.
|
||||
*/
|
||||
sidebarWidth: number | null;
|
||||
/** Outlook-style colour categories for calendar events. */
|
||||
/** Outlook-style color categories for calendar events. */
|
||||
eventCategories: Array<{ name: string; color: string }>;
|
||||
/** Default sending identity per account (JMAP has no such flag). */
|
||||
defaultIdentityByAccount: Record<string, string>;
|
||||
@@ -645,7 +645,7 @@ export function applyLang(s: Settings = useSettings.getState().settings): void {
|
||||
const tag = resolveUiLanguage(s.uiLanguage);
|
||||
document.documentElement.lang = tag;
|
||||
/*
|
||||
* The catalogue is fetched, so it lands a beat after the attribute. That
|
||||
* The catalog is fetched, so it lands a beat after the attribute. That
|
||||
* order is deliberate: `lang` is what stops Chrome offering to translate,
|
||||
* and it should not wait on a network request to say something it already
|
||||
* knows. English needs no fetch at all and resolves immediately.
|
||||
@@ -663,7 +663,7 @@ export function applyTheme(s: Settings = useSettings.getState().settings): void
|
||||
/*
|
||||
* Two attributes, because they answer two questions. `data-theme` is the
|
||||
* mode, and every dark-only rule in the stylesheet keys off it without
|
||||
* knowing any palette exists; `data-palette` layers the colours on top. The
|
||||
* knowing any palette exists; `data-palette` layers the colors on top. The
|
||||
* accent variants out-specify both, which is what lets an accent still apply
|
||||
* over any palette.
|
||||
*/
|
||||
@@ -678,7 +678,7 @@ export function applyTheme(s: Settings = useSettings.getState().settings): void
|
||||
}
|
||||
|
||||
/**
|
||||
* The browser chrome colour, read from the palette's own background so it does
|
||||
* The browser chrome color, read from the palette's own background so it does
|
||||
* not have to be listed twice and cannot drift from it.
|
||||
*/
|
||||
function paletteThemeColor(palette: PaletteId, mode: "light" | "dark"): string {
|
||||
@@ -724,7 +724,7 @@ export function useEffectiveTheme(): "light" | "dark" {
|
||||
export const settings = () => useSettings.getState().settings;
|
||||
|
||||
/**
|
||||
* Primitive that changes whenever a date/time preference does, so memoised
|
||||
* Primitive that changes whenever a date/time preference does, so memoized
|
||||
* components that render dates re-render when the format is switched.
|
||||
*/
|
||||
export const dateTimeKey = (s: Settings): string => `${s.locale}|${s.dateFormat}|${s.timeFormat}`;
|
||||
|
||||
@@ -108,7 +108,7 @@ export const useSieve = create<SieveState>((set, get) => ({
|
||||
|
||||
async saveRules(rules) {
|
||||
const existing = get().scripts.find((s) => s.name === IHASMAIL_SCRIPT) ?? null;
|
||||
// The last line of defence. Writing rules replaces the whole script, so
|
||||
// The last line of defense. Writing rules replaces the whole script, so
|
||||
// doing it from a baseline we never managed to read deletes whatever was
|
||||
// there. Refusing is recoverable; overwriting is not.
|
||||
if (existing) {
|
||||
|
||||
Reference in New Issue
Block a user