Skip to content

Commit

Permalink
Fixed editor selection issues on typing or changing verse, other mino…
Browse files Browse the repository at this point in the history
…r fixes and tweaks (#1008)
  • Loading branch information
tjcouch-sil authored Jul 17, 2024
2 parents 0dbea94 + dafad78 commit 35f1b7a
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# paranext-core

Electron client, extension host, and C# library for Paranext
Extensible Bible translation software

<div align="center">
<img src="doc-meta/doc-icon.png" />
Expand All @@ -14,9 +14,17 @@ Electron client, extension host, and C# library for Paranext

</div>

## 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

Expand All @@ -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:
Expand Down Expand Up @@ -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)**
Expand Down Expand Up @@ -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.
Expand Down
Binary file added doc-meta/mac-arm-damaged-warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<HTMLElement>(
`.editor-container span[data-marker="v"][data-number="${scrRef.verseNum}"]`,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -143,7 +179,16 @@ globalThis.webViewComponent = function PlatformScriptureEditor({
};
}, [scrRef]);

const options: EditorOptions = { hasSpellCheck: false, isReadonly: isReadOnly };
const options = useMemo<EditorOptions>(
() => ({
// 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 (
<Editor
Expand Down
7 changes: 7 additions & 0 deletions src/shared/services/web-view-provider.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import networkObjectService from '@shared/services/network-object.service';
import * as networkService from '@shared/services/network.service';
import logger from '@shared/services/logger.service';
import { isSerializable } from 'platform-bible-utils';
import networkObjectStatusService from '@shared/services/network-object-status.service';

/** Suffix on network objects that indicates that the network object is a data provider */
const WEB_VIEW_PROVIDER_LABEL = 'webViewProvider';
Expand Down Expand Up @@ -118,6 +119,12 @@ async function get(webViewType: string): Promise<WebViewProvider | undefined> {
// 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<WebViewProvider>(webViewProviderObjectId);

if (!webViewProvider) {
Expand Down

0 comments on commit 35f1b7a

Please sign in to comment.