diff --git a/README.md b/README.md index 3caad727c3..c0567a03a9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # paranext-core -Electron client, extension host, and C# library for Paranext +Extensible Bible translation software
@@ -14,9 +14,17 @@ Electron client, extension host, and C# library for Paranext
+## Summary + +Platform.Bible is an extensible Bible translation software. Its functionality is provided almost completely by extensions in order to be very powerful and flexible, giving developers the freedom to create and to share their desired Bible translation experience. + +This repository contains the core Platform.Bible software (Electron client, extension host including "PAPI", and .NET library) and the extensions that come bundled with it. There are many other repositories containing additional Platform.Bible extensions. + ## Users -This software is not yet ready for users. We'll update here with where you can install it when its ready. +This software is not yet ready for users. We'll update here with where you can install it when it is ready. + +If you would still like to try Platform.Bible, you can [download early releases here on GitHub](https://github.com/paranext/paranext-core/releases). ### Linux Users @@ -28,6 +36,20 @@ sudo apt install libfuse2 Then simply [execute/run](https://github.com/AppImage/AppImageKit/wiki) the `.AppImage` file, which you can download from [Releases](https://github.com/paranext/paranext-core/releases). +### Mac Users + +If you download and run the ARM release of Platform.Bible from [a computer running Apple Silicon](https://support.apple.com/en-us/116943), you will likely encounter a warning from Apple's Gatekeeper stating that "Platform.Bible is damaged and can't be opened. You should move it to the Trash." or something very similar: + +![mac-arm-damaged-warning](doc-meta/mac-arm-damaged-warning.png) + +Unfortunately, this is the message Apple chose to display for ARM applications that are not signed (including Platform.Bible since we have not yet set up application code signing on Mac). + +If you trust Platform.Bible and would like to run it even though it is not code signed, you will need to run the following terminal command every time you install a new version of Platform.Bible: + +`xattr -c /Applications/Platform.Bible.app` + +[`xattr -c` clears all attributes on the provided file](https://ss64.com/mac/xattr.html). Running this command removes all attributes on the currently-installed Platform.Bible application file including the quarantine flag Gatekeeper puts on unsigned ARM applications downloaded from the internet. + ## Developer Install Set up pre-requisites for building: @@ -104,6 +126,8 @@ After you run `npm start` (or, in VSCode, launch `Debug Paranext Core`), you can Paranext Core extensions are found in the `extensions` folder. Please follow the instructions in `extensions/README.md` to develop extensions. +Please see the [Extension Template wiki](https://github.com/paranext/paranext-extension-template/wiki) for guides on developing extensions. + ## GitHub Pages **[Platform.Bible API Documentation](https://paranext.github.io/paranext-core/papi-dts)** @@ -140,7 +164,7 @@ npm run package cd ./release/app npm version 1.2.3 ``` -3. Create a new draft [GitHub **Release**](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository), ensure the following are included: +3. Create a new draft [GitHub **Release**](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository). Ensure the following are included: - a _Tag version_, e.g. `v1.2.3`, choose _Create new tag on publish_. - set the **Target** to the release branch. - a copy of the change log. Click **Generate release notes** as a starting point. diff --git a/doc-meta/mac-arm-damaged-warning.png b/doc-meta/mac-arm-damaged-warning.png new file mode 100644 index 0000000000..c5ce97f21f Binary files /dev/null and b/doc-meta/mac-arm-damaged-warning.png differ diff --git a/extensions/src/platform-scripture-editor/src/platform-scripture-editor.web-view.tsx b/extensions/src/platform-scripture-editor/src/platform-scripture-editor.web-view.tsx index e1355256c1..deab27cc4f 100644 --- a/extensions/src/platform-scripture-editor/src/platform-scripture-editor.web-view.tsx +++ b/extensions/src/platform-scripture-editor/src/platform-scripture-editor.web-view.tsx @@ -4,6 +4,8 @@ import { EditorRef, Marginal, MarginalRef, + getViewOptions, + DEFAULT_VIEW_MODE, } from '@biblionexus-foundation/platform-editor'; import { Usj } from '@biblionexus-foundation/scripture-utilities'; import { VerseRef } from '@sillsdev/scripture'; @@ -30,6 +32,18 @@ const defaultScrRef: ScriptureReference = { const usjDocumentDefault: Usj = { type: 'USJ', version: '0.2.1', content: [] }; +/** + * Check deep equality of two values such that two equal objects or arrays created in two different + * iframes successfully test as equal + * + * @param a + * @param b + * @returns + */ +function deepEqualAcrossIframes(a: unknown, b: unknown) { + return JSON.stringify(a) === JSON.stringify(b); +} + function scrollToScrRef(scrRef: ScriptureReference) { const verseElement = document.querySelector( `.editor-container span[data-marker="v"][data-number="${scrRef.verseNum}"]`, @@ -90,13 +104,35 @@ globalThis.webViewComponent = function PlatformScriptureEditor({ const debouncedSetUsj = useMemo(() => debounce((newUsj: Usj) => setUsj?.(newUsj), 300), [setUsj]); + // Editor's current usj state + const editorUsj = useRef(usj); + // TODO: remove debounce when issue #826 is done. - const onChange = useCallback(debouncedSetUsj, [debouncedSetUsj]); + const onChange = useCallback( + (newUsj: Usj) => { + // There is a bug where the editor's onChange runs when the state is externally set, so let's + // not run onChange if the change came externally (our tracked editorUsj.current editor state + // will already be up-to-date) + if (deepEqualAcrossIframes(newUsj, editorUsj.current)) return; + + editorUsj.current = newUsj; + debouncedSetUsj(newUsj); + }, + [debouncedSetUsj], + ); + // Update the editor if a change comes in useEffect(() => { - if (usj) editorRef.current?.setUsj(usj); + // Deep compare the old and current state of the usj to make sure we don't change the editor's + // state without a need. Note that it already does that internally using a different algorithm, + // but we need to compare in such a way that the same object across iframes works fine + if (usj && !deepEqualAcrossIframes(usj, editorUsj.current)) { + editorUsj.current = usj; + editorRef.current?.setUsj(usj); + } }, [usj]); + // On loading the first time, scroll the selected verse into view useEffect(() => { if (usj && !hasFirstRetrievedScripture.current) { hasFirstRetrievedScripture.current = true; @@ -143,7 +179,16 @@ globalThis.webViewComponent = function PlatformScriptureEditor({ }; }, [scrRef]); - const options: EditorOptions = { hasSpellCheck: false, isReadonly: isReadOnly }; + const options = useMemo( + () => ({ + // We need to provide view options to prevent a bug where the editor re-renders every key + // press and loses cursor position + view: getViewOptions(DEFAULT_VIEW_MODE), + hasSpellCheck: false, + isReadonly: isReadOnly, + }), + [isReadOnly], + ); return ( { // Get the object id for this web view provider name const webViewProviderObjectId = getWebViewProviderObjectId(webViewType); + await networkObjectStatusService.waitForNetworkObject( + { id: webViewProviderObjectId }, + // Wait up to 20 seconds for the web view provider to appear + 20000, + ); + const webViewProvider = await networkObjectService.get(webViewProviderObjectId); if (!webViewProvider) {