From d44705ab3d72b940f801c52ee27b695cccdf4ae9 Mon Sep 17 00:00:00 2001 From: "Thomas M. Edwards" Date: Wed, 24 Jul 2024 04:34:16 -0500 Subject: [PATCH 1/7] feat: update SugarCube to v2.37.1 --- public/story-formats/sugarcube-2.37.0/format.js | 1 - .../{sugarcube-2.37.0 => sugarcube-2.37.1}/LICENSE | 0 public/story-formats/sugarcube-2.37.1/format.js | 1 + .../{sugarcube-2.37.0 => sugarcube-2.37.1}/icon.svg | 0 src/store/story-formats/defaults.ts | 4 ++-- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 public/story-formats/sugarcube-2.37.0/format.js rename public/story-formats/{sugarcube-2.37.0 => sugarcube-2.37.1}/LICENSE (100%) create mode 100644 public/story-formats/sugarcube-2.37.1/format.js rename public/story-formats/{sugarcube-2.37.0 => sugarcube-2.37.1}/icon.svg (100%) diff --git a/public/story-formats/sugarcube-2.37.0/format.js b/public/story-formats/sugarcube-2.37.0/format.js deleted file mode 100644 index dc6605fc5..000000000 --- a/public/story-formats/sugarcube-2.37.0/format.js +++ /dev/null @@ -1 +0,0 @@ -window.storyFormat({"name":"SugarCube","version":"2.37.0","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file diff --git a/public/story-formats/sugarcube-2.37.0/LICENSE b/public/story-formats/sugarcube-2.37.1/LICENSE similarity index 100% rename from public/story-formats/sugarcube-2.37.0/LICENSE rename to public/story-formats/sugarcube-2.37.1/LICENSE diff --git a/public/story-formats/sugarcube-2.37.1/format.js b/public/story-formats/sugarcube-2.37.1/format.js new file mode 100644 index 000000000..0b03c96e5 --- /dev/null +++ b/public/story-formats/sugarcube-2.37.1/format.js @@ -0,0 +1 @@ +window.storyFormat({"name":"SugarCube","version":"2.37.1","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file diff --git a/public/story-formats/sugarcube-2.37.0/icon.svg b/public/story-formats/sugarcube-2.37.1/icon.svg similarity index 100% rename from public/story-formats/sugarcube-2.37.0/icon.svg rename to public/story-formats/sugarcube-2.37.1/icon.svg diff --git a/src/store/story-formats/defaults.ts b/src/store/story-formats/defaults.ts index 36b8ca771..ea9a12a06 100644 --- a/src/store/story-formats/defaults.ts +++ b/src/store/story-formats/defaults.ts @@ -47,7 +47,7 @@ export const builtins = () => [ }, { name: 'SugarCube', - url: 'story-formats/sugarcube-2.37.0/format.js', - version: '2.37.0' + url: 'story-formats/sugarcube-2.37.1/format.js', + version: '2.37.1' } ]; From 46ee30937882d452a13343331846bf3a8a70179b Mon Sep 17 00:00:00 2001 From: "Thomas M. Edwards" Date: Wed, 24 Jul 2024 15:46:01 -0500 Subject: [PATCH 2/7] feat: update SugarCube to v2.37.2 --- .../{sugarcube-2.37.1 => sugarcube-2.37.2}/LICENSE | 0 .../{sugarcube-2.37.1 => sugarcube-2.37.2}/format.js | 2 +- .../{sugarcube-2.37.1 => sugarcube-2.37.2}/icon.svg | 0 src/store/story-formats/defaults.ts | 4 ++-- 4 files changed, 3 insertions(+), 3 deletions(-) rename public/story-formats/{sugarcube-2.37.1 => sugarcube-2.37.2}/LICENSE (100%) rename public/story-formats/{sugarcube-2.37.1 => sugarcube-2.37.2}/format.js (76%) rename public/story-formats/{sugarcube-2.37.1 => sugarcube-2.37.2}/icon.svg (100%) diff --git a/public/story-formats/sugarcube-2.37.1/LICENSE b/public/story-formats/sugarcube-2.37.2/LICENSE similarity index 100% rename from public/story-formats/sugarcube-2.37.1/LICENSE rename to public/story-formats/sugarcube-2.37.2/LICENSE diff --git a/public/story-formats/sugarcube-2.37.1/format.js b/public/story-formats/sugarcube-2.37.2/format.js similarity index 76% rename from public/story-formats/sugarcube-2.37.1/format.js rename to public/story-formats/sugarcube-2.37.2/format.js index 0b03c96e5..e50a94b81 100644 --- a/public/story-formats/sugarcube-2.37.1/format.js +++ b/public/story-formats/sugarcube-2.37.2/format.js @@ -1 +1 @@ -window.storyFormat({"name":"SugarCube","version":"2.37.1","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file +window.storyFormat({"name":"SugarCube","version":"2.37.2","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file diff --git a/public/story-formats/sugarcube-2.37.1/icon.svg b/public/story-formats/sugarcube-2.37.2/icon.svg similarity index 100% rename from public/story-formats/sugarcube-2.37.1/icon.svg rename to public/story-formats/sugarcube-2.37.2/icon.svg diff --git a/src/store/story-formats/defaults.ts b/src/store/story-formats/defaults.ts index ea9a12a06..b4fa739b0 100644 --- a/src/store/story-formats/defaults.ts +++ b/src/store/story-formats/defaults.ts @@ -47,7 +47,7 @@ export const builtins = () => [ }, { name: 'SugarCube', - url: 'story-formats/sugarcube-2.37.1/format.js', - version: '2.37.1' + url: 'story-formats/sugarcube-2.37.2/format.js', + version: '2.37.2' } ]; From b2f8717bde8f0ef16ca78d9b99b6139c3bd05321 Mon Sep 17 00:00:00 2001 From: "Thomas M. Edwards" Date: Fri, 26 Jul 2024 19:51:24 -0500 Subject: [PATCH 3/7] feat: update SugarCube to v2.37.3 --- .../{sugarcube-2.37.2 => sugarcube-2.37.3}/LICENSE | 0 .../{sugarcube-2.37.2 => sugarcube-2.37.3}/format.js | 2 +- .../{sugarcube-2.37.2 => sugarcube-2.37.3}/icon.svg | 0 src/store/story-formats/defaults.ts | 4 ++-- 4 files changed, 3 insertions(+), 3 deletions(-) rename public/story-formats/{sugarcube-2.37.2 => sugarcube-2.37.3}/LICENSE (100%) rename public/story-formats/{sugarcube-2.37.2 => sugarcube-2.37.3}/format.js (50%) rename public/story-formats/{sugarcube-2.37.2 => sugarcube-2.37.3}/icon.svg (100%) diff --git a/public/story-formats/sugarcube-2.37.2/LICENSE b/public/story-formats/sugarcube-2.37.3/LICENSE similarity index 100% rename from public/story-formats/sugarcube-2.37.2/LICENSE rename to public/story-formats/sugarcube-2.37.3/LICENSE diff --git a/public/story-formats/sugarcube-2.37.2/format.js b/public/story-formats/sugarcube-2.37.3/format.js similarity index 50% rename from public/story-formats/sugarcube-2.37.2/format.js rename to public/story-formats/sugarcube-2.37.3/format.js index e50a94b81..985a19cc0 100644 --- a/public/story-formats/sugarcube-2.37.2/format.js +++ b/public/story-formats/sugarcube-2.37.3/format.js @@ -1 +1 @@ -window.storyFormat({"name":"SugarCube","version":"2.37.2","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file +window.storyFormat({"name":"SugarCube","version":"2.37.3","description":"A full featured, highly customizable story format. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t
\n\t\t

Browser lacks capabilities required to play.

Upgrade or switch to another browser.

\n\t\t
Loading…
\n\t
\n\t{{STORY_DATA}}\n\t\n\n\n"}); \ No newline at end of file diff --git a/public/story-formats/sugarcube-2.37.2/icon.svg b/public/story-formats/sugarcube-2.37.3/icon.svg similarity index 100% rename from public/story-formats/sugarcube-2.37.2/icon.svg rename to public/story-formats/sugarcube-2.37.3/icon.svg diff --git a/src/store/story-formats/defaults.ts b/src/store/story-formats/defaults.ts index b4fa739b0..db12231f0 100644 --- a/src/store/story-formats/defaults.ts +++ b/src/store/story-formats/defaults.ts @@ -47,7 +47,7 @@ export const builtins = () => [ }, { name: 'SugarCube', - url: 'story-formats/sugarcube-2.37.2/format.js', - version: '2.37.2' + url: 'story-formats/sugarcube-2.37.3/format.js', + version: '2.37.3' } ]; From c36420398c248ff2cb4b51caa0b6f5e205a0ac85 Mon Sep 17 00:00:00 2001 From: Chris Klimas Date: Sat, 27 Jul 2024 14:16:40 -0400 Subject: [PATCH 4/7] Use library to create UUIDs Needed because we still have users using http://twinery.org/2/, where window.crypto isn't available. --- package-lock.json | 24 +++++++++++++++++-- package.json | 1 + src/setupTests.ts | 5 ---- .../electron-ipc/story-formats/load.ts | 3 ++- .../persistence/local-storage/prefs/save.ts | 3 ++- .../local-storage/story-formats/save.ts | 7 +++--- .../stories/action-creators/create-story.ts | 3 ++- .../action-creators/duplicate-story.ts | 7 +++--- src/store/stories/reducer/create-passage.ts | 3 ++- src/store/stories/reducer/create-story.ts | 5 ++-- .../stories/reducer/repair/repair-passage.ts | 20 +++++++++------- .../stories/reducer/repair/repair-story.ts | 12 ++++++---- src/store/story-formats/reducer.ts | 13 +++++----- .../story-formats/story-formats-context.tsx | 3 ++- src/util/import.ts | 13 ++++------ src/util/twee.ts | 7 +++--- 16 files changed, 77 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4cda09d2e..69b2061b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "Twine", - "version": "2.9.0", + "version": "2.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Twine", - "version": "2.9.0", + "version": "2.9.1", "license": "GPL-3.0", "dependencies": { + "@lukeed/uuid": "^2.0.1", "@popperjs/core": "^2.9.1", "@tabler/icons": "^1.119.0", "@testing-library/dom": "^9.3.1", @@ -3512,6 +3513,25 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@lukeed/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==", + "dependencies": { + "@lukeed/csprng": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@malept/cross-spawn-promise": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", diff --git a/package.json b/package.json index 6bff33f30..68887425e 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "npm": ">=8" }, "dependencies": { + "@lukeed/uuid": "^2.0.1", "@popperjs/core": "^2.9.1", "@tabler/icons": "^1.119.0", "@testing-library/dom": "^9.3.1", diff --git a/src/setupTests.ts b/src/setupTests.ts index 1bd66d08b..3ce6234af 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -1,7 +1,6 @@ import {toHaveNoViolations} from 'jest-axe'; import {configure} from '@testing-library/dom'; import '@testing-library/jest-dom'; -import {faker} from '@faker-js/faker'; import 'jest-canvas-mock'; // Always mock these files so that Jest doesn't see import.meta. @@ -51,9 +50,5 @@ afterEach(() => delete (window as any).matchMedia); } }; -// ... and jsdom doesn't implement the crypto module, which we use to generate UUIDs. - -(window as any).crypto.randomUUID = () => faker.string.uuid(); - window.Element.prototype.releasePointerCapture = () => {}; window.Element.prototype.setPointerCapture = () => {}; diff --git a/src/store/persistence/electron-ipc/story-formats/load.ts b/src/store/persistence/electron-ipc/story-formats/load.ts index fd5a8c303..7118149ce 100644 --- a/src/store/persistence/electron-ipc/story-formats/load.ts +++ b/src/store/persistence/electron-ipc/story-formats/load.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {TwineElectronWindow} from '../../../../electron/shared'; import {StoryFormatsState} from '../../../story-formats/story-formats.types'; @@ -15,7 +16,7 @@ export async function load(): Promise { } return storyFormats.map(data => ({ - id: window.crypto.randomUUID(), + id: uuid(), loadState: 'unloaded', name: data.name, selected: false, diff --git a/src/store/persistence/local-storage/prefs/save.ts b/src/store/persistence/local-storage/prefs/save.ts index 9b3e67df9..915c9b15e 100644 --- a/src/store/persistence/local-storage/prefs/save.ts +++ b/src/store/persistence/local-storage/prefs/save.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {PrefsState} from '../../../prefs'; export function save(state: PrefsState) { @@ -17,7 +18,7 @@ export function save(state: PrefsState) { const ids: string[] = []; for (const name in state) { - const id = window.crypto.randomUUID(); + const id = uuid(); ids.push(id); window.localStorage.setItem( diff --git a/src/store/persistence/local-storage/story-formats/save.ts b/src/store/persistence/local-storage/story-formats/save.ts index 027b96d25..401442793 100644 --- a/src/store/persistence/local-storage/story-formats/save.ts +++ b/src/store/persistence/local-storage/story-formats/save.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {StoryFormatsState} from '../../../story-formats/story-formats.types'; export function save(state: StoryFormatsState) { @@ -17,8 +18,8 @@ export function save(state: StoryFormatsState) { const ids: string[] = []; - state.forEach(format => { - const id = window.crypto.randomUUID(); + for (const format of state) { + const id = uuid(); // We have to remove the `properties` property if it exists, as that is // dynamically added when loading. @@ -34,7 +35,7 @@ export function save(state: StoryFormatsState) { selected: undefined }) ); - }); + } window.localStorage.setItem('twine-storyformats', ids.join(',')); } diff --git a/src/store/stories/action-creators/create-story.ts b/src/store/stories/action-creators/create-story.ts index db20e70fe..93faafa37 100644 --- a/src/store/stories/action-creators/create-story.ts +++ b/src/store/stories/action-creators/create-story.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {Thunk} from 'react-hook-thunk-reducer'; import {PrefsState} from '../../prefs'; import {StoriesAction, StoriesState, Story} from '../stories.types'; @@ -10,7 +11,7 @@ export function createStory( prefs: PrefsState, props: Partial> & Pick ): Thunk { - const id = window.crypto.randomUUID(); + const id = uuid(); if (props.name.trim() === '') { throw new Error('Story name cannot be empty'); diff --git a/src/store/stories/action-creators/duplicate-story.ts b/src/store/stories/action-creators/duplicate-story.ts index e31cf282c..ca305c6e0 100644 --- a/src/store/stories/action-creators/duplicate-story.ts +++ b/src/store/stories/action-creators/duplicate-story.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {CreateStoryAction, Story} from '../stories.types'; import {unusedName} from '../../../util/unused-name'; @@ -8,21 +9,21 @@ export function duplicateStory( story: Story, stories: Story[] ): CreateStoryAction { - const id = window.crypto.randomUUID(); + const id = uuid(); return { type: 'createStory', props: { ...story, id, - ifid: window.crypto.randomUUID(), + ifid: uuid(), name: unusedName( story.name, stories.map(story => story.name) ), passages: story.passages.map(passage => ({ ...passage, - id: window.crypto.randomUUID(), + id: uuid(), story: id })) } diff --git a/src/store/stories/reducer/create-passage.ts b/src/store/stories/reducer/create-passage.ts index 28c456faa..f56072b11 100644 --- a/src/store/stories/reducer/create-passage.ts +++ b/src/store/stories/reducer/create-passage.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {passageDefaults} from '../defaults'; import {Passage, Story, StoriesState} from '../stories.types'; @@ -34,7 +35,7 @@ export function createPassage( const newPassage: Passage = { ...passageDefaults(), - id: window.crypto.randomUUID(), + id: uuid(), ...passageProps, story: story.id }; diff --git a/src/store/stories/reducer/create-story.ts b/src/store/stories/reducer/create-story.ts index 16ab3df9c..3942770c1 100644 --- a/src/store/stories/reducer/create-story.ts +++ b/src/store/stories/reducer/create-story.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {passageDefaults, storyDefaults} from '../defaults'; import {Story, StoriesState} from '../stories.types'; @@ -20,9 +21,9 @@ export function createStory(state: StoriesState, storyProps: Partial) { } const story: Story = { - id: window.crypto.randomUUID(), + id: uuid(), ...storyDefaults(), - ifid: window.crypto.randomUUID().toUpperCase(), + ifid: uuid().toUpperCase(), lastUpdate: new Date(), passages: [], tags: [], diff --git a/src/store/stories/reducer/repair/repair-passage.ts b/src/store/stories/reducer/repair/repair-passage.ts index a04a89e3f..ef1b5f47d 100644 --- a/src/store/stories/reducer/repair/repair-passage.ts +++ b/src/store/stories/reducer/repair/repair-passage.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {passageDefaults} from '../../defaults'; import {Passage, Story} from '../../stories.types'; @@ -25,15 +26,16 @@ export function repairPassage(passage: Passage, parentStory: Story): Passage { // Give the passage an ID if it has none. if (typeof passage.id !== 'string' || passage.id === '') { - const newId = window.crypto.randomUUID(); + const newId = uuid(); logRepair(passage, 'id', newId, 'was undefined or empty string'); - repairs.id = window.crypto.randomUUID(); + repairs.id = newId; } // Apply default properties to the passage. - Object.entries(passageDefs).forEach(([key, value]) => { + for (const key in passageDefs) { + const value = passageDefs[key as keyof typeof passageDefs]; const defKey = key as keyof typeof passageDefs; if ( @@ -43,11 +45,11 @@ export function repairPassage(passage: Passage, parentStory: Story): Passage { logRepair(passage, defKey, passageDefs[defKey]); (repairs[defKey] as Passage[typeof defKey]) = passageDefs[defKey]; } - }); + } // Make passage coordinates 0 or greater. - ['left', 'top'].forEach(pos => { + for (const pos of ['left', 'top']) { const posKey = pos as keyof Passage; if ( @@ -57,11 +59,11 @@ export function repairPassage(passage: Passage, parentStory: Story): Passage { logRepair(passage, posKey, 0, 'was negative'); (repairs[posKey] as Passage[typeof posKey]) = 0; } - }); + } // Make passage dimensions 5 or greater. - ['height', 'width'].forEach(dim => { + for (const dim of ['height', 'width']) { const dimKey = dim as keyof Passage; if ( @@ -71,7 +73,7 @@ export function repairPassage(passage: Passage, parentStory: Story): Passage { logRepair(passage, dimKey, 0, 'was less than 5'); (repairs[dimKey] as Passage[typeof dimKey]) = 5; } - }); + } // Repair story property if it doesn't point to the parent story. @@ -91,7 +93,7 @@ export function repairPassage(passage: Passage, parentStory: Story): Passage { return otherPassage.id === passage.id; }) ) { - const newId = window.crypto.randomUUID(); + const newId = uuid(); logRepair( passage, diff --git a/src/store/stories/reducer/repair/repair-story.ts b/src/store/stories/reducer/repair/repair-story.ts index 6b1a479b2..665b3f773 100644 --- a/src/store/stories/reducer/repair/repair-story.ts +++ b/src/store/stories/reducer/repair/repair-story.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {satisfies} from 'semver'; import {Story} from '../../stories.types'; import {storyDefaults} from '../../defaults'; @@ -33,7 +34,7 @@ export function repairStory( // Give the story an ID if it has none. if (typeof story.id !== 'string' || story.id === '') { - const newId = window.crypto.randomUUID(); + const newId = uuid(); logRepair(story, 'id', newId, 'was bad type or empty string'); repairs.id = newId; @@ -42,7 +43,7 @@ export function repairStory( // Give the story an IFID if it has none. if (typeof story.ifid !== 'string' || story.id === '') { - const newIfid = window.crypto.randomUUID(); + const newIfid = uuid(); logRepair(story, 'ifid', newIfid, 'was bad type or empty string'); repairs.ifid = newIfid; @@ -50,8 +51,9 @@ export function repairStory( // Apply default properties to the story. - Object.entries(storyDefs).forEach(([key, value]) => { + for (const key in storyDefs) { const defKey = key as keyof typeof storyDefs; + const value = storyDefs[defKey]; if ( (typeof value === 'number' && !Number.isFinite(story[defKey])) || @@ -60,7 +62,7 @@ export function repairStory( logRepair(story, defKey, storyDefs[defKey]); (repairs[defKey] as Story[typeof defKey]) = storyDefs[defKey]; } - }); + } if ( typeof story.storyFormat !== 'string' || @@ -144,7 +146,7 @@ export function repairStory( return otherStory.id === story.id; }) ) { - const newId = window.crypto.randomUUID(); + const newId = uuid(); logRepair(story, 'id', newId, "conflicted with another story's ID"); repairs.id = newId; diff --git a/src/store/story-formats/reducer.ts b/src/store/story-formats/reducer.ts index 40e6bf516..a051242db 100644 --- a/src/store/story-formats/reducer.ts +++ b/src/store/story-formats/reducer.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import {builtins} from './defaults'; import { StoryFormat, @@ -37,7 +38,7 @@ export const reducer: React.Reducer = ( // Add any builtins not present. - builtinFormats.forEach(builtinFormat => { + for (const builtinFormat of builtinFormats) { if ( !result.some( f => @@ -50,13 +51,14 @@ export const reducer: React.Reducer = ( ); result.push({ ...builtinFormat, - id: window.crypto.randomUUID(), + id: uuid(), loadState: 'unloaded', selected: false, userAdded: false }); } - }); + } + return result; } @@ -71,10 +73,7 @@ export const reducer: React.Reducer = ( return state; } - return [ - ...state, - {...action.props, id: window.crypto.randomUUID(), loadState: 'unloaded'} - ]; + return [...state, {...action.props, id: uuid(), loadState: 'unloaded'}]; case 'delete': return state.filter(f => f.id !== action.id); diff --git a/src/store/story-formats/story-formats-context.tsx b/src/store/story-formats/story-formats-context.tsx index fa9ed23a1..b1cec7b57 100644 --- a/src/store/story-formats/story-formats-context.tsx +++ b/src/store/story-formats/story-formats-context.tsx @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import * as React from 'react'; import useThunkReducer from 'react-hook-thunk-reducer'; import {usePersistence} from '../persistence/use-persistence'; @@ -13,7 +14,7 @@ import {reducer} from './reducer'; const defaultBuiltins: StoryFormat[] = builtins().map(f => ({ ...f, - id: window.crypto.randomUUID(), + id: uuid(), loadState: 'unloaded', selected: false, userAdded: false diff --git a/src/util/import.ts b/src/util/import.ts index b52664e9d..a3ee4f749 100644 --- a/src/util/import.ts +++ b/src/util/import.ts @@ -5,6 +5,7 @@ // affects startup time in the Twine desktop app. This module moves data from // the filesystem into local storage, and the app can't begin until it's done. +import {v4 as uuid} from '@lukeed/uuid'; import defaults from 'lodash/defaults'; import {passageDefaults, storyDefaults, Passage, Story} from '../store/stories'; @@ -69,8 +70,8 @@ function domToObject(storyEl: Element): ImportedStory { const startPassagePid = storyEl.getAttribute('startnode'); let startPassageId: string | undefined = undefined; const story: ImportedStory = { - ifid: storyEl.getAttribute('ifid') ?? window.crypto.randomUUID(), - id: window.crypto.randomUUID(), + ifid: storyEl.getAttribute('ifid') ?? uuid().toUpperCase(), + id: uuid(), lastUpdate: undefined, name: storyEl.getAttribute('name') ?? undefined, storyFormat: storyEl.getAttribute('format') ?? undefined, @@ -95,7 +96,7 @@ function domToObject(storyEl: Element): ImportedStory { return {...result, [tagName]: el.getAttribute('color')}; }, {}), passages: query(storyEl, selectors.passageData).map(passageEl => { - const id = window.crypto.randomUUID(); + const id = uuid(); const position = parseDimensions(passageEl.getAttribute('position')); const size = parseDimensions(passageEl.getAttribute('size')); @@ -140,11 +141,7 @@ export function importStories( // Merge in defaults. We can't use object spreads here because undefined // values would override defaults. - const story: Story = defaults( - importedStory, - {id: window.crypto.randomUUID()}, - storyDefaults() - ); + const story: Story = defaults(importedStory, {id: uuid()}, storyDefaults()); // Override the last update as requested. diff --git a/src/util/twee.ts b/src/util/twee.ts index 631eb10d8..8b16407b0 100644 --- a/src/util/twee.ts +++ b/src/util/twee.ts @@ -1,3 +1,4 @@ +import {v4 as uuid} from '@lukeed/uuid'; import sortBy from 'lodash/sortBy'; import {Passage, passageDefaults, Story, storyDefaults} from '../store/stories'; import {unusedName} from './unused-name'; @@ -73,7 +74,7 @@ export function passageFromTwee(source: string): Omit { const passage: Omit = { ...passageDefaults(), - id: window.crypto.randomUUID(), + id: uuid(), name: unescapeForTweeHeader( rawName .replace(/^(\\\s)+/g, match => ' '.repeat(match.length / 2)) @@ -134,12 +135,12 @@ export function passageFromTwee(source: string): Omit { * Converts a story from Twee source. */ export function storyFromTwee(source: string) { - const id = window.crypto.randomUUID(); + const id = uuid(); const story: Story = { ...storyDefaults(), id, - ifid: window.crypto.randomUUID(), + ifid: uuid().toUpperCase(), lastUpdate: new Date(), passages: source .split(/^::/m) From 99e2b6f809a3ed0293b4f010a2a11836070fbf9f Mon Sep 17 00:00:00 2001 From: Chris Klimas Date: Sat, 27 Jul 2024 16:59:28 -0400 Subject: [PATCH 5/7] Improve layout of prefs dialog --- src/dialogs/app-prefs.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dialogs/app-prefs.css b/src/dialogs/app-prefs.css index 4032d63b5..c28363284 100644 --- a/src/dialogs/app-prefs.css +++ b/src/dialogs/app-prefs.css @@ -11,6 +11,19 @@ margin: 0; } +.app-prefs-dialog .text-select > label { + width: 100%; +} + +.app-prefs-dialog .text-select .text-select-control { + display: flex; + flex-grow: 1; +} + +.app-prefs-dialog .text-select select { + flex-grow: 1; +} + .app-prefs-dialog .text-input, .app-prefs-dialog input[type='text'] { width: 100%; From 911d18bc4994f1648137da4cacb66fced9086f6f Mon Sep 17 00:00:00 2001 From: Chris Klimas Date: Sun, 28 Jul 2024 14:30:29 -0400 Subject: [PATCH 6/7] Add Chapbook 2.2.0 --- public/story-formats/chapbook-2.1.0/format.js | 1 - public/story-formats/chapbook-2.2.0/format.js | 1 + .../story-formats/{chapbook-2.1.0 => chapbook-2.2.0}/logo.svg | 0 src/store/story-formats/defaults.ts | 4 ++-- 4 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 public/story-formats/chapbook-2.1.0/format.js create mode 100644 public/story-formats/chapbook-2.2.0/format.js rename public/story-formats/{chapbook-2.1.0 => chapbook-2.2.0}/logo.svg (100%) diff --git a/public/story-formats/chapbook-2.1.0/format.js b/public/story-formats/chapbook-2.1.0/format.js deleted file mode 100644 index dd09ea851..000000000 --- a/public/story-formats/chapbook-2.1.0/format.js +++ /dev/null @@ -1 +0,0 @@ -window.storyFormat({"source":"{{STORY_NAME}}
{{STORY_DATA}}","author":"Chris Klimas","description":"A Twine story format emphasizing ease of authoring, multimedia, and playability on many different types of devices. Visit the guide for more information.","hydrate":"(function(l){\"use strict\";function r(){return{startState(){return{inVarsSection:!1}},token(e,t){if(t.hasVarsSection===void 0){for(let n=1,o=e.lookAhead(1);o&&t.hasVarsSection===void 0;o=e.lookAhead(++n))o===\"--\"&&(t.hasVarsSection=!0,t.inVarsSection=!0);t.hasVarsSection===void 0&&(t.hasVarsSection=!1)}return t.hasVarsSection&&t.inVarsSection&&e.sol()?e.match(/^--$/)?(t.inVarsSection=!1,e.skipToEnd(),\"punctuation\"):e.skipTo(\":\")?(e.next(),\"def\"):(e.skipToEnd(),\"text\"):e.sol()&&e.match(/^\\[[^[].*\\]$/)||e.match(/^\\{.+?\\}/)?\"keyword\":e.match(/^\\[\\[[^\\]]+?\\]\\]/)?\"link\":(e.eatWhile(/[^[{]/)||e.skipToEnd(),\"text\")}}}function c(e){return Object.keys(e).reduce((t,n)=>({...t,[n]:o=>{o.replaceSelection(e[n]),o.focus()}}),{})}function d(e){return Object.keys(e).reduce((t,n)=>({...t,[n]:o=>{const{matcher:i,wrapper:v}=e[n];o.replaceSelections(o.getSelections().map(s=>i.test(s)?s.replace(i,\"$1\"):v(s)),\"around\"),o.focus()}}),{})}const b={...d({boldText:{matcher:/^(?:__|\\*\\*)(.+)(?:__|\\*\\*)$/,wrapper:e=>`**${e}**`},italicText:{matcher:/^(?:_|\\*)(.+)(?:_|\\*)$/,wrapper:e=>`*${e}*`},monospacedText:{matcher:/^`(.+)`$/,wrapper:e=>\"`\"+e+\"`\"},smallCapsText:{matcher:/^~~(.+)~~$/,wrapper:e=>`~~${e}~~`}}),...c({insertAfter:`\n[after 1 second]\nText\n\n[continued]`,insertAppend:`\n[append]\n`,insertBlockquote:`\n
Text
\n`,insertContinue:`\n[continued]\n`,insertBulletedList:`\n- Item\n- Item\n`,insertCss:`\n[CSS]\n.page article {\n color: green;\n}\n\n[continued]\n`,insertCyclingLink:\"{cycling link for: 'variable name', choices: ['choice', 'choice']}\",insertDropdownMenu:\"{dropdown menu for: 'variable name', choices: ['choice', 'choice']}\",insertEmbedAmbientSound:\"{ambient sound: 'sound name'}\",insertEmbedSoundEffect:\"{sound effect: 'sound name'}\",insertEmbedPassage:\"{embed passage: 'Passage name'}\",insertEmbedYouTubeVideo:\"{embed YouTube video: 'URL'}\",insertImageFlickr:\"{embed Flickr image: 'Flickr embed code'}\",insertImageUrl:\"{embed image: 'URL to image'}\",insertImageUnsplash:\"{embed Unsplash image: }\",insertForkList:`\n> Link\n> Link\n`,insertIf:`\n[if condition]\nText\n\n[continue]\n`,insertIfElse:`\n[if condition]\nText\n\n[else]Text\n\n[continued]\n`,insertJs:`\n[JavaScript]\nwrite('Hello from JavaScript');\n\n[continued]\n`,insertNote:`\n[note]\nNote to self\n\n[continued]\n`,insertNumberedList:`\n1. Item\n2. Item\n`,insertPassageLink:\"{link to: 'Passage name', label: 'Label text'}\",insertRestartLink:\"{restart link, label: 'Label text'}\",insertRevealPassageLink:\"{reveal link: 'Label text', passage: 'Passage name'}\",insertRevealTextLink:\"{restart link: 'Label text', text: 'Displayed text'}\",insertSectionBreak:`\n***\n`,insertTextInput:\"{text input for: 'variable name'}\",insertUnless:`\n[unless condition]\nText\n\n[continued]\n`})},m=`\n \n \n \n\n\n\n`,p=`\n \n \n \n \n \n\n\n\n`,u=`\n \n \n \n \n \n\n\n\n`,h=`\n \n \n \n \n \n \n \n \n \n\n\n\n`,k=`\n \n \n \n \n\n\n\n`;function a(e,t){return`data:image/svg+xml;base64,${window.btoa(e.replace(/currentColor/g,t))}`}function g(e,{foregroundColor:t}){const n=e.getDoc().somethingSelected();return[{type:\"menu\",icon:a(p,t),label:\"Style\",items:[{type:\"button\",iconOnly:!0,label:\"Bold\",command:\"boldText\",disabled:!n},{type:\"button\",label:\"Italic\",command:\"italicText\",disabled:!n},{type:\"button\",label:\"Monospaced Text\",command:\"monospacedText\",disabled:!n},{type:\"button\",label:\"Small Caps\",command:\"smallCapsText\",disabled:!n},{type:\"separator\"},{type:\"button\",label:\"Blockquote\",command:\"insertBlockquote\",disabled:n},{type:\"button\",label:\"Bulleted List\",command:\"insertBulletedList\",disabled:n},{type:\"button\",label:\"Fork List\",command:\"insertForkList\",disabled:n},{type:\"button\",label:\"Numbered List\",command:\"insertNumberedList\",disabled:n},{type:\"button\",label:\"Section Break\",command:\"insertSectionBreak\",disabled:n}]},{type:\"menu\",icon:a(k,t),label:\"Link\",disabled:n,items:[{type:\"button\",label:\"Passage Link\",command:\"insertPassageLink\"},{type:\"button\",label:\"Restart Link\",command:\"insertRestartLink\"},{type:\"button\",label:\"Reveal Passage Link\",command:\"insertRevealPassageLink\"},{type:\"button\",label:\"Reveal Text Link\",command:\"insertRevealTextLink\"}]},{type:\"menu\",icon:a(m,t),label:\"Modifiers\",disabled:n,items:[{type:\"button\",label:\"If\",command:\"insertIf\"},{type:\"button\",label:\"If and Else\",command:\"insertIfElse\"},{type:\"button\",label:\"Unless\",command:\"insertUnless\"},{type:\"button\",label:\"Continue\",command:\"insertContinue\"},{type:\"separator\"},{type:\"button\",label:\"After Delay\",command:\"insertAfter\"},{type:\"button\",label:\"Append Text\",command:\"insertAppend\"},{type:\"button\",label:\"Note\",command:\"insertNote\"},{type:\"separator\"},{type:\"button\",label:\"JavaScript\",command:\"insertJs\"},{type:\"button\",label:\"CSS\",command:\"insertCss\"}]},{type:\"menu\",icon:a(u,t),label:\"Embed\",disabled:n,items:[{type:\"button\",label:\"Embed Passage\",command:\"insertEmbedPassage\"},{type:\"button\",label:\"Embed Image from Flickr\",command:\"insertImageFlickr\"},{type:\"button\",label:\"Embed Image from URL\",command:\"insertImageUrl\"},{type:\"button\",label:\"Embed Image from Unsplash\",command:\"insertImageUnsplash\"},{type:\"button\",label:\"Embed Ambient Sound\",command:\"insertEmbedAmbientSound\"},{type:\"button\",label:\"Embed Sound Effect\",command:\"insertEmbedSoundEffect\"},{type:\"button\",label:\"Embed YouTube Video\",command:\"insertEmbedYouTubeVideo\"}]},{type:\"menu\",icon:a(h,t),label:\"Input\",disabled:n,items:[{type:\"button\",label:\"Cycling Link\",command:\"insertCyclingLink\"},{type:\"button\",label:\"Dropdown Menu\",command:\"insertDropdownMenu\"},{type:\"button\",label:\"Text Input\",command:\"insertTextInput\"}]}]}function f(e){const t=[/\\{embed\\s+passage\\s*:\\s*['\"](.+?)['\"]\\s*}/g,/\\{link\\s+to\\s*:\\s*['\"](.+?)['\"]\\s*\\}/g,/\\{reveal\\s+link.+passage\\s*:\\s*['\"](.+?)['\"].*\\}/g],n=[];for(const o of t){let i;for(;i=o.exec(e);)n.push(i[1])}return n}l.editorExtensions={twine:{\"^2.4.0-beta2\":{codeMirror:{commands:b,mode:r,toolbar:g},references:{parsePassageText:f}}}}})(this);\n","image":"logo.svg","name":"Chapbook","proofing":false,"version":"2.1.0"}) \ No newline at end of file diff --git a/public/story-formats/chapbook-2.2.0/format.js b/public/story-formats/chapbook-2.2.0/format.js new file mode 100644 index 000000000..36527eac5 --- /dev/null +++ b/public/story-formats/chapbook-2.2.0/format.js @@ -0,0 +1 @@ +window.storyFormat({"source":"{{STORY_NAME}}
{{STORY_DATA}}","author":"Chris Klimas","description":"A Twine story format emphasizing ease of authoring, multimedia, and playability on many different types of devices. Visit the guide for more information.","hydrate":"(function(l){\"use strict\";function r(){return{startState(){return{inVarsSection:!1}},token(e,t){if(t.hasVarsSection===void 0){for(let n=1,o=e.lookAhead(1);o&&t.hasVarsSection===void 0;o=e.lookAhead(++n))o===\"--\"&&(t.hasVarsSection=!0,t.inVarsSection=!0);t.hasVarsSection===void 0&&(t.hasVarsSection=!1)}return t.hasVarsSection&&t.inVarsSection&&e.sol()?e.match(/^--$/)?(t.inVarsSection=!1,e.skipToEnd(),\"punctuation\"):e.skipTo(\":\")?(e.next(),\"def\"):(e.skipToEnd(),\"text\"):e.sol()&&e.match(/^\\[[^[].*\\]$/)||e.match(/^\\{.+?\\}/)?\"keyword\":e.match(/^\\[\\[[^\\]]+?\\]\\]/)?\"link\":(e.eatWhile(/[^[{]/)||e.skipToEnd(),\"text\")}}}function c(e){return Object.keys(e).reduce((t,n)=>({...t,[n]:o=>{o.replaceSelection(e[n]),o.focus()}}),{})}function d(e){return Object.keys(e).reduce((t,n)=>({...t,[n]:o=>{const{matcher:i,wrapper:v}=e[n];o.replaceSelections(o.getSelections().map(s=>i.test(s)?s.replace(i,\"$1\"):v(s)),\"around\"),o.focus()}}),{})}const b={...d({boldText:{matcher:/^(?:__|\\*\\*)(.+)(?:__|\\*\\*)$/,wrapper:e=>`**${e}**`},italicText:{matcher:/^(?:_|\\*)(.+)(?:_|\\*)$/,wrapper:e=>`*${e}*`},monospacedText:{matcher:/^`(.+)`$/,wrapper:e=>\"`\"+e+\"`\"},smallCapsText:{matcher:/^~~(.+)~~$/,wrapper:e=>`~~${e}~~`}}),...c({insertAfter:`\n[after 1 second]\nText\n\n[continued]`,insertAppend:`\n[append]\n`,insertBlockquote:`\n
Text
\n`,insertContinue:`\n[continued]\n`,insertBulletedList:`\n- Item\n- Item\n`,insertCss:`\n[CSS]\n.page article {\n color: green;\n}\n\n[continued]\n`,insertCyclingLink:\"{cycling link for: 'variable name', choices: ['choice', 'choice']}\",insertDropdownMenu:\"{dropdown menu for: 'variable name', choices: ['choice', 'choice']}\",insertEmbedAmbientSound:\"{ambient sound: 'sound name'}\",insertEmbedSoundEffect:\"{sound effect: 'sound name'}\",insertEmbedPassage:\"{embed passage: 'Passage name'}\",insertEmbedYouTubeVideo:\"{embed YouTube video: 'URL'}\",insertImageFlickr:\"{embed Flickr image: 'Flickr embed code'}\",insertImageUrl:\"{embed image: 'URL to image'}\",insertImageUnsplash:\"{embed Unsplash image: }\",insertForkList:`\n> Link\n> Link\n`,insertIf:`\n[if condition]\nText\n\n[continue]\n`,insertIfElse:`\n[if condition]\nText\n\n[else]Text\n\n[continued]\n`,insertJs:`\n[JavaScript]\nwrite('Hello from JavaScript');\n\n[continued]\n`,insertNote:`\n[note]\nNote to self\n\n[continued]\n`,insertNumberedList:`\n1. Item\n2. Item\n`,insertPassageLink:\"{link to: 'Passage name', label: 'Label text'}\",insertRestartLink:\"{restart link, label: 'Label text'}\",insertRevealPassageLink:\"{reveal link: 'Label text', passage: 'Passage name'}\",insertRevealTextLink:\"{restart link: 'Label text', text: 'Displayed text'}\",insertSectionBreak:`\n***\n`,insertTextInput:\"{text input for: 'variable name'}\",insertUnless:`\n[unless condition]\nText\n\n[continued]\n`})},m=`\n \n \n \n\n\n\n`,p=`\n \n \n \n \n \n\n\n\n`,u=`\n \n \n \n \n \n\n\n\n`,h=`\n \n \n \n \n \n \n \n \n \n\n\n\n`,k=`\n \n \n \n \n\n\n\n`;function a(e,t){return`data:image/svg+xml;base64,${window.btoa(e.replace(/currentColor/g,t))}`}function g(e,{foregroundColor:t}){const n=e.getDoc().somethingSelected();return[{type:\"menu\",icon:a(p,t),label:\"Style\",items:[{type:\"button\",iconOnly:!0,label:\"Bold\",command:\"boldText\",disabled:!n},{type:\"button\",label:\"Italic\",command:\"italicText\",disabled:!n},{type:\"button\",label:\"Monospaced Text\",command:\"monospacedText\",disabled:!n},{type:\"button\",label:\"Small Caps\",command:\"smallCapsText\",disabled:!n},{type:\"separator\"},{type:\"button\",label:\"Blockquote\",command:\"insertBlockquote\",disabled:n},{type:\"button\",label:\"Bulleted List\",command:\"insertBulletedList\",disabled:n},{type:\"button\",label:\"Fork List\",command:\"insertForkList\",disabled:n},{type:\"button\",label:\"Numbered List\",command:\"insertNumberedList\",disabled:n},{type:\"button\",label:\"Section Break\",command:\"insertSectionBreak\",disabled:n}]},{type:\"menu\",icon:a(k,t),label:\"Link\",disabled:n,items:[{type:\"button\",label:\"Passage Link\",command:\"insertPassageLink\"},{type:\"button\",label:\"Restart Link\",command:\"insertRestartLink\"},{type:\"button\",label:\"Reveal Passage Link\",command:\"insertRevealPassageLink\"},{type:\"button\",label:\"Reveal Text Link\",command:\"insertRevealTextLink\"}]},{type:\"menu\",icon:a(m,t),label:\"Modifiers\",disabled:n,items:[{type:\"button\",label:\"If\",command:\"insertIf\"},{type:\"button\",label:\"If and Else\",command:\"insertIfElse\"},{type:\"button\",label:\"Unless\",command:\"insertUnless\"},{type:\"button\",label:\"Continue\",command:\"insertContinue\"},{type:\"separator\"},{type:\"button\",label:\"After Delay\",command:\"insertAfter\"},{type:\"button\",label:\"Append Text\",command:\"insertAppend\"},{type:\"button\",label:\"Note\",command:\"insertNote\"},{type:\"separator\"},{type:\"button\",label:\"JavaScript\",command:\"insertJs\"},{type:\"button\",label:\"CSS\",command:\"insertCss\"}]},{type:\"menu\",icon:a(u,t),label:\"Embed\",disabled:n,items:[{type:\"button\",label:\"Embed Passage\",command:\"insertEmbedPassage\"},{type:\"button\",label:\"Embed Image from Flickr\",command:\"insertImageFlickr\"},{type:\"button\",label:\"Embed Image from URL\",command:\"insertImageUrl\"},{type:\"button\",label:\"Embed Image from Unsplash\",command:\"insertImageUnsplash\"},{type:\"button\",label:\"Embed Ambient Sound\",command:\"insertEmbedAmbientSound\"},{type:\"button\",label:\"Embed Sound Effect\",command:\"insertEmbedSoundEffect\"},{type:\"button\",label:\"Embed YouTube Video\",command:\"insertEmbedYouTubeVideo\"}]},{type:\"menu\",icon:a(h,t),label:\"Input\",disabled:n,items:[{type:\"button\",label:\"Cycling Link\",command:\"insertCyclingLink\"},{type:\"button\",label:\"Dropdown Menu\",command:\"insertDropdownMenu\"},{type:\"button\",label:\"Text Input\",command:\"insertTextInput\"}]}]}function f(e){const t=[/\\{embed\\s+passage\\s*:\\s*['\"](.+?)['\"]\\s*}/g,/\\{link\\s+to\\s*:\\s*['\"](.+?)['\"]\\s*\\}/g,/\\{reveal\\s+link.+passage\\s*:\\s*['\"](.+?)['\"].*\\}/g],n=[];for(const o of t){let i;for(;i=o.exec(e);)n.push(i[1])}return n}l.editorExtensions={twine:{\"^2.4.0-beta2\":{codeMirror:{commands:b,mode:r,toolbar:g},references:{parsePassageText:f}}}}})(this);\n","image":"logo.svg","name":"Chapbook","proofing":false,"version":"2.2.0"}) \ No newline at end of file diff --git a/public/story-formats/chapbook-2.1.0/logo.svg b/public/story-formats/chapbook-2.2.0/logo.svg similarity index 100% rename from public/story-formats/chapbook-2.1.0/logo.svg rename to public/story-formats/chapbook-2.2.0/logo.svg diff --git a/src/store/story-formats/defaults.ts b/src/store/story-formats/defaults.ts index db12231f0..a3aa03b2b 100644 --- a/src/store/story-formats/defaults.ts +++ b/src/store/story-formats/defaults.ts @@ -6,8 +6,8 @@ export const builtins = () => [ }, { name: 'Chapbook', - url: 'story-formats/chapbook-2.1.0/format.js', - version: '2.1.0' + url: 'story-formats/chapbook-2.2.0/format.js', + version: '2.2.0' }, { name: 'Harlowe', From ceff39b03d8aec37016e1bef7deb4d9b50a1536c Mon Sep 17 00:00:00 2001 From: Chris Klimas Date: Sun, 28 Jul 2024 14:37:55 -0400 Subject: [PATCH 7/7] 2.9.2 release --- docs/en/src/release-notes/2-9.md | 18 +++++++++++++++++- package.json | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/en/src/release-notes/2-9.md b/docs/en/src/release-notes/2-9.md index 04e40b023..d109a93c4 100644 --- a/docs/en/src/release-notes/2-9.md +++ b/docs/en/src/release-notes/2-9.md @@ -1,12 +1,28 @@ # 2.9 versions +## 2.9.2 + +Release Date: July 28, 2024 + +## Bugs Fixed + +- Browser Twine works in HTTP (e.g. nonsecure) contexts again. 2.9.1 introduced + a change that broke this. +- The layout of the preferences dialog is a little nicer. + +## Story Format Updates + +- Chapbook has been updated to version [2.2.0](https://klembot.github.io/chapbook/guide/references/version-history.html#220-28-july-2024). +- SugarCube has been updated to version [2.37.3](http://www.motoslave.net/sugarcube/2/releases.php). + ## 2.9.1 Release Date: July 21, 2024 ## Bugs Fixed -- Importing a story in browser Twine that replaces an existing one no longer creates duplicate stories. +- Importing a story in browser Twine that replaces an existing one no longer + creates duplicate stories. ## Behind the Scenes diff --git a/package.json b/package.json index 68887425e..c9d5a54fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Twine", - "version": "2.9.1", + "version": "2.9.2", "description": "a GUI for creating nonlinear stories", "author": "Chris Klimas ", "license": "GPL-3.0",