Skip to content

Commit

Permalink
add a way to get the tab url
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian-ubs committed Nov 27, 2024
1 parent 10a7cf2 commit d0facbc
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 18 deletions.
6 changes: 5 additions & 1 deletion src/website-viewer/contributions/localizedStrings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
"%websiteViewerMenu_openOTNWebsiteViewer%": "Open Translators Notes (SIL)",
"%websiteViewerMenu_openMarbleWebsiteViewer%": "Marble (UBS)",
"%websiteViewerMenu_openWiBiLexWebsiteViewer%": "WiBiLex (German Bible Society)",
"%websiteViewerMenu_openYouVersionVerseView%": "YouVersion verse view"
"%websiteViewerMenu_openYouVersionVerseView%": "YouVersion verse view",
"%websiteViewerMenu_website%": "Website",
"%websiteViewerMenu_showUrl%": "Show website url",
"%websiteViewerMenu_showUrl_tooltip%": "Show the url that was used to load this tab. It might not be the current url in case you navigated inside the website.",
"%websiteViewerMenu_clickLink%": "Click this link to open the url in the web browser of your operating system. You may close this window afterwards. This url display will not update until you reopen it from the menu of a website viewer tab."
}
}
}
30 changes: 29 additions & 1 deletion src/website-viewer/contributions/menus.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,33 @@
"groups": {},
"items": []
},
"webViewMenus": {}
"webViewMenus": {
"website-viewer.webView": {
"topMenu": {
"columns": {
"website-viewer.website": {
"label": "%websiteViewerMenu_website%",
"order": 4711,
"isExtensible": true
}
},
"groups": {
"website-viewer.website": { "column": "website-viewer.website", "order": 3 }
},
"items": [
{
"label": "%websiteViewerMenu_showUrl%",
"tooltip": "%websiteViewerMenu_showUrl_tooltip%",
"group": "website-viewer.website",
"order": 1,
"command": "websiteViewer.showUrl"
}
]
},
"contextMenu": {
"groups": {},
"items": []
}
}
}
}
19 changes: 19 additions & 0 deletions src/website-viewer/src/link.web-view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { WebViewProps } from '@papi/core';
import { useLocalizedStrings } from '@papi/frontend/react';
import { LocalizeKey } from 'platform-bible-utils';

// misusing the title to pass around the url, because I cannot come up with an easy way to get it in
global.webViewComponent = function LinkWebView({ title }: WebViewProps) {
const descriptionTextL10nKey = '%websiteViewerMenu_clickLink%';
const localizedStringKeys: LocalizeKey[] = [descriptionTextL10nKey];
const [{ [descriptionTextL10nKey]: descriptionTextLocalized }] =
useLocalizedStrings(localizedStringKeys);
return (
<div>
<p>{descriptionTextLocalized}</p>
<a href={title} target="_blank" rel="noreferrer">
{title}
</a>
</div>
);
};
82 changes: 72 additions & 10 deletions src/website-viewer/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SATISFY_TS_OPTIONS,
WebsiteViewerOptions,
} from './websiteViewerOptions';
import linkWebView from './link.web-view?inline';

interface BasicWebsiteViewerOptions extends GetWebViewOptions {
openWebsiteCommand: keyof CommandHandlers;
Expand All @@ -32,7 +33,12 @@ interface ScrollGroupInfo {
scrRef: ScriptureReference;
}

const WEBSITE_VIEWER_WEBVIEW_TYPE = 'websiteViewer.webView';
interface LinkWebViewOptions extends GetWebViewOptions {
url: string;
}

const WEBSITE_VIEWER_WEBVIEW_TYPE = 'website-viewer.webView';
const LINK_WEB_VIEW_TYPE = 'website-viewer.link.webView';
const USER_DATA_KEY = 'webViewTypeById_';
const SCR_REF_TO_TRIGGER_UPDATE = {
bookNum: -1,
Expand Down Expand Up @@ -111,7 +117,7 @@ const websiteViewerWebViewProvider: IWebViewProvider = {

const options: WebsiteViewerOptions = websiteOptions.get(command) || SATISFY_TS_OPTIONS;

const url = await options.getUrl(currentScriptureReference, userLanguageCode);
const url = options.getUrl(currentScriptureReference, userLanguageCode);
logger.log(`website-viewer is opening url ${url}, options: ${JSON.stringify(options)}`);

const titleFormatString = await papi.localization.getLocalizedString({
Expand All @@ -130,7 +136,7 @@ const websiteViewerWebViewProvider: IWebViewProvider = {
},
};

export async function getCurrentScriptureReference(
async function getCurrentScriptureReference(
scrollGroupRef: ScrollGroupScrRef | undefined,
): Promise<ScriptureReference> {
if (scrollGroupRef === undefined) return papi.scrollGroups.getScrRef();
Expand All @@ -140,7 +146,28 @@ export async function getCurrentScriptureReference(
return Promise.resolve(scrollGroupRef);
}

function registerCommandHandlers() {
/** Simple web view provider that provides link web views when papi requests them */
const linkWebViewProvider: IWebViewProvider = {
async getWebView(
savedWebView: SavedWebViewDefinition,
getWebViewOptions: LinkWebViewOptions,
): Promise<WebViewDefinition | undefined> {
if (savedWebView.webViewType !== LINK_WEB_VIEW_TYPE)
throw new Error(
`${LINK_WEB_VIEW_TYPE} provider received request to provide a ${savedWebView.webViewType} web view`,
);

return {
...savedWebView,
content: linkWebView,
// work around to pass in the url, because the title can be accessed from within the web view
title: getWebViewOptions.url,
allowPopups: true,
};
},
};

function registerOpenWebsiteCommandHandlers() {
websiteOptions = getWebsiteOptions();

return Array.from(websiteOptions.entries()).map(([command, options]) => {
Expand Down Expand Up @@ -199,14 +226,25 @@ async function getUserLanguageCode(): Promise<string> {
return 'NOT_YET_IMPLEMENTED';
}

function getUrlForWebView(webViewId: string): string {
const command = commandByWebViewId.get(webViewId) || SATISFY_TS_KEY;
const options: WebsiteViewerOptions = websiteOptions.get(command) || SATISFY_TS_OPTIONS;
const currentScrollGroupInfo = scrollGroupInfoByWebViewId.get(webViewId);
const currentScriptureReference = currentScrollGroupInfo
? currentScrollGroupInfo.scrRef
: SCR_REF_TO_TRIGGER_UPDATE; // this should not happen
if (!currentScrollGroupInfo) {
logger.warn('website-viewer: scroll group could not be found, copied url might be unexpected');
}
return options.getUrl(currentScriptureReference, userLanguageCode);
}

export async function activate(context: ExecutionActivationContext): Promise<void> {
logger.info('website-viewer is activating!');

executionToken = context.executionToken;
userLanguageCode = await getUserLanguageCode();

const commandPromises = registerCommandHandlers();

// When the scripture reference changes, re-render the last webview of type "websiteViewerWebViewType"
// This is not fired in case of "no scroll group", this is handled inside the scroll group change code
papi.scrollGroups.onDidUpdateScrRef((scrollGroupUpdateInfo: ScrollGroupUpdateInfo) => {
Expand Down Expand Up @@ -266,19 +304,43 @@ export async function activate(context: ExecutionActivationContext): Promise<voi

// clean up webviews from the map, so that no unexpected empty tabs appear on changing ref after closing tabs
papi.webViews.onDidCloseWebView((closeWebViewEvent: CloseWebViewEvent) => {
if (commandByWebViewId.has(closeWebViewEvent.webView.id)) {
commandByWebViewId.delete(closeWebViewEvent.webView.id);
scrollGroupInfoByWebViewId.delete(closeWebViewEvent.webView.id);
const webViewId = closeWebViewEvent.webView.id;
if (commandByWebViewId.has(webViewId)) {
commandByWebViewId.delete(webViewId);
scrollGroupInfoByWebViewId.delete(webViewId);

const userDataKey = `${USER_DATA_KEY}${webViewId}`;
papi.storage.deleteUserData(executionToken, userDataKey);
}
});

const openUrlWebViewPromise = papi.commands.registerCommand(
'websiteViewer.showUrl',
async (webViewId) => {
const url = getUrlForWebView(webViewId);
const options: LinkWebViewOptions = { url, existingId: '?' }; // only open 1 instance at a time
return papi.webViews.openWebView(LINK_WEB_VIEW_TYPE, undefined, options);
},
);

const linkWebViewProviderPromise = papi.webViewProviders.registerWebViewProvider(
LINK_WEB_VIEW_TYPE,
linkWebViewProvider,
);

const commandPromises = registerOpenWebsiteCommandHandlers();

const websiteViewerWebViewProviderPromise = papi.webViewProviders.registerWebViewProvider(
WEBSITE_VIEWER_WEBVIEW_TYPE,
websiteViewerWebViewProvider,
);

// Await the registration promises at the end so we don't hold everything else up
context.registrations.add(await websiteViewerWebViewProviderPromise);
context.registrations.add(
await websiteViewerWebViewProviderPromise,
await openUrlWebViewPromise,
await linkWebViewProviderPromise,
);
Promise.all(commandPromises)
.then((arr) => context.registrations.add(...arr))
.catch((e) => logger.error('Error loading command promises', e));
Expand Down
13 changes: 13 additions & 0 deletions src/website-viewer/src/types/website-viewer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ declare module 'papi-shared-types' {
*/
'websiteViewer.openYouVersionVerse': () => Promise<string | undefined>;

/**
* Opens a new webview with a link to the url with which Platform opened the website. Clicking
* that link will open the url in the default browser of the OS
*
* Note: this command is intended to work from the web view menu
*
* @param webViewId The web view id of the current web view to look up the type and get the url,
* provided by the web view menu
* @returns From return value of openWebView: Promise that resolves to the id of the link web
* view or undefined if the provider did not create a link web view
*/
'websiteViewer.showUrl': (webViewId: string) => Promise<string | undefined>;

/**
* Dummy to use in strictly typed Maps
*
Expand Down
12 changes: 6 additions & 6 deletions src/website-viewer/src/websiteViewerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { formatScrRef, ScriptureReference } from 'platform-bible-utils';

export interface WebsiteViewerOptions {
getUrl: (scrRef: ScriptureReference, langCode: string) => string;
// TODO: could be improved by passing in another parameter with the selected text of the active tab
// (e.g. for a lexicon or Marble to scroll to / highlight a word)
// for demo purpose this text could for now come from a setting, where users can copy it into
// alternatively an input on the main toolbar - if extensions can do a thing like adding controls to the main toolbar
websiteName: string;
watchRefChange?: RefChange;
}
Expand All @@ -14,10 +18,6 @@ export const SATISFY_TS_KEY: keyof CommandHandlers = 'dummy.dummy';
export const SATISFY_TS_OPTIONS: WebsiteViewerOptions = {
getUrl: () => '',
websiteName: '',
// TODO: could be improved by passing in the selected tab of the active tab
// (e.g. for a lexicon or Marble to scroll to / highlight a word)
// for demo purpose this text could for now come from a setting, where users can copy it into
// alternatively an input on the main toolbar - if extensions can do a thing like adding controls to the main toolbar
};

export enum RefChange {
Expand Down Expand Up @@ -126,7 +126,7 @@ export function getWebsiteOptions(): Map<keyof CommandHandlers, WebsiteViewerOpt
websiteName: 'GBS WiBiLex',
};

const youVersionVerseViewOtions: WebsiteViewerOptions = {
const youVersionVerseViewOptions: WebsiteViewerOptions = {
getUrl: (scrRef: ScriptureReference) => {
const verseRef = new VerseRef(scrRef.bookNum, scrRef.chapterNum, scrRef.verseNum, undefined);
return `https://www.bible.com/en-GB/bible/1/${verseRef.book}.${scrRef.chapterNum}.${scrRef.verseNum}`;
Expand All @@ -143,6 +143,6 @@ export function getWebsiteOptions(): Map<keyof CommandHandlers, WebsiteViewerOpt
['websiteViewer.openOTN', otnOptions],
['websiteViewer.openMarble', marbleOptions],
['websiteViewer.openWiBiLex', wiBiLexOptions],
['websiteViewer.openYouVersionVerse', youVersionVerseViewOtions],
['websiteViewer.openYouVersionVerse', youVersionVerseViewOptions],
]);
}

0 comments on commit d0facbc

Please sign in to comment.