mirror of
https://github.com/visortelle/haskell-spotlight.git
synced 2024-09-11 03:55:54 +03:00
Fix bugs
This commit is contained in:
parent
32ecc65849
commit
c2fd1a0b27
@ -4,7 +4,7 @@
|
||||
"short_name": "Haskell Spotlight",
|
||||
"description": "Search on Hackage, Hoogle and more soon.",
|
||||
"homepage_url": "https://github.com/visortelle/hackage-ui",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"icons": { "192": "images/icon-192.png" },
|
||||
"content_scripts": [
|
||||
{
|
||||
@ -21,7 +21,7 @@
|
||||
"default_icon": {
|
||||
"128": "images/icon-192.png"
|
||||
},
|
||||
"default_title": "Haskell title",
|
||||
"default_title": "Haskell Spotlight",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"permissions": [
|
||||
|
@ -2,7 +2,7 @@ import * as lib from '@hackage-ui/react-lib';
|
||||
import styles from './Content.module.css';
|
||||
import * as s from './Content.module.css';
|
||||
import haskellLogo from '!!raw-loader!./haskell-monochrome.svg'
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { ReactText, Ref, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary'
|
||||
import * as k from '../popup/keybindings';
|
||||
import { applyStyles } from '../styles';
|
||||
@ -10,79 +10,94 @@ import { applyStyles } from '../styles';
|
||||
const Content = (props: { rootElement: HTMLElement }) => {
|
||||
const appContext = useContext(lib.appContext.AppContext);
|
||||
const stylesContainerRef = useRef(null);
|
||||
const contentRef = useRef(null);
|
||||
const [contentEl, setContentEl] = useState<HTMLDivElement>(null);
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
const [isShow, setIsShow] = useState(false);
|
||||
const [explode, setExplode] = useState(false);
|
||||
const [toggleKB, setToggleKB] = useState<k.KeyBinding | undefined>();
|
||||
const [showKB, setShowKB] = useState<k.KeyBinding | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const keybinding = await k.readKeyBinding('toggleSpotlight');
|
||||
setToggleKB(() => keybinding);
|
||||
})()
|
||||
}, []);
|
||||
|
||||
const toggleVisibility = useCallback((event: KeyboardEvent) => {
|
||||
const kb2: k.KeyBinding = {
|
||||
code: event.code,
|
||||
modifiers: {
|
||||
altKey: event.altKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
metaKey: event.metaKey,
|
||||
shiftKey: event.shiftKey
|
||||
}
|
||||
};
|
||||
|
||||
if (k.eqKeyBindings(toggleKB, kb2)) {
|
||||
event.preventDefault();
|
||||
setIsShow((isShow) => !isShow);
|
||||
const preventDefaultKeyBehavior = useCallback((event: KeyboardEvent | React.KeyboardEvent) => {
|
||||
if (!showKB) {
|
||||
return;
|
||||
}
|
||||
}, [isShow, setIsShow, toggleKB]);
|
||||
|
||||
// Prevent global page hotkeys when the search input is in focus.
|
||||
if (!isShow && k.eqKeyBindings(showKB, k.eventToKeyBinding(event))) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}, [isShow, showKB]);
|
||||
|
||||
const handleDocumentKeydown = useCallback((event: KeyboardEvent) => {
|
||||
if (!isShow && k.eqKeyBindings(showKB, k.eventToKeyBinding(event))) {
|
||||
setIsShow(() => true);
|
||||
}
|
||||
}, [isShow, setIsShow, showKB]);
|
||||
|
||||
// Prevent global page hotkeys when the spotlight popup is in focus.
|
||||
const handleKeyboardEvents = useCallback((event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
setIsShow(false);
|
||||
setIsShow(() => false);
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
}, []);
|
||||
if (isShow) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}, [setIsShow, isShow, showKB]);
|
||||
|
||||
const handleClickOutside = useCallback((event: MouseEvent) => {
|
||||
if (props.rootElement === event.target || props.rootElement.contains(event.target as Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsShow(false);
|
||||
setIsShow(() => false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!contentRef.current) {
|
||||
(async () => {
|
||||
const keybinding = await k.readKeyBinding('toggleSpotlight');
|
||||
setShowKB(() => keybinding);
|
||||
})()
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const cleanup = () => {
|
||||
document.removeEventListener('keydown', preventDefaultKeyBehavior);
|
||||
document.removeEventListener('keyup', preventDefaultKeyBehavior);
|
||||
}
|
||||
|
||||
if (!showKB) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', preventDefaultKeyBehavior);
|
||||
document.addEventListener('keyup', preventDefaultKeyBehavior);
|
||||
|
||||
return cleanup;
|
||||
}, [preventDefaultKeyBehavior, showKB]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!contentEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
contentRef.current.addEventListener('keyup', handleKeyboardEvents);
|
||||
contentRef.current.addEventListener('keydown', handleKeyboardEvents);
|
||||
contentRef.current.addEventListener('keypress', handleKeyboardEvents);
|
||||
contentEl.addEventListener('keyup', handleKeyboardEvents);
|
||||
contentEl.addEventListener('keydown', handleKeyboardEvents);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
contentRef?.current?.removeEventListener('keyup', handleKeyboardEvents)
|
||||
contentRef?.current?.removeEventListener('keydown', handleKeyboardEvents)
|
||||
contentRef?.current?.removeEventListener('keypress', handleKeyboardEvents)
|
||||
contentEl.removeEventListener('keyup', handleKeyboardEvents)
|
||||
contentEl.removeEventListener('keydown', handleKeyboardEvents)
|
||||
};
|
||||
});
|
||||
}, [contentEl]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keyup', toggleVisibility);
|
||||
document.addEventListener('keydown', handleDocumentKeydown);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keyup', toggleVisibility)
|
||||
document.removeEventListener('keydown', handleDocumentKeydown)
|
||||
};
|
||||
}, [toggleKB]);
|
||||
}, [showKB]);
|
||||
|
||||
useEffect(() => {
|
||||
let extraStyles = document.createElement('style');
|
||||
@ -93,7 +108,7 @@ const Content = (props: { rootElement: HTMLElement }) => {
|
||||
applyStyles(stylesContainerRef.current);
|
||||
styles.use({ target: stylesContainerRef.current });
|
||||
|
||||
setIsReady(true);
|
||||
setIsReady(() => true);
|
||||
}, [stylesContainerRef]);
|
||||
|
||||
return (
|
||||
@ -105,7 +120,7 @@ const Content = (props: { rootElement: HTMLElement }) => {
|
||||
<div>
|
||||
<div ref={stylesContainerRef}></div>
|
||||
{isReady && isShow && (
|
||||
<div ref={contentRef} className={s.content}>
|
||||
<div ref={setContentEl} className={s.content}>
|
||||
<div className={`${s.progressIndicator} ${Object.keys(appContext.tasks).length > 0 ? s.progressIndicatorRunning : ''}`}></div>
|
||||
<a href="https://github.com/visortelle/hackage-ui" target='__blank' className={s.logo} dangerouslySetInnerHTML={{ __html: haskellLogo }}></a>
|
||||
<div style={{ flex: 1 }}>
|
||||
|
@ -31,8 +31,6 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: var(--transition-short);
|
||||
background-color: #5e5086;
|
||||
animation: pulse-mono 800ms infinite ease;
|
||||
}
|
||||
|
||||
.kbdKeys:hover {
|
||||
@ -46,33 +44,9 @@
|
||||
|
||||
.kbdKeysAwaiting {
|
||||
background-color: #5e5086;
|
||||
animation: pulse 400ms infinite alternate ease;
|
||||
transition: var(--transition-short);
|
||||
}
|
||||
|
||||
.kbdKeysCalm {
|
||||
background-color: #aaa;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes pulse-mono {
|
||||
0% {
|
||||
background-color: #bbb;
|
||||
}
|
||||
100% {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
background-color: #5e5086;
|
||||
}
|
||||
100% {
|
||||
background-color: #453a62;
|
||||
}
|
||||
}
|
||||
|
||||
.kbdKey {
|
||||
margin: 4px;
|
||||
font-weight: bold;
|
||||
|
@ -6,6 +6,15 @@ import * as k from './keybindings';
|
||||
|
||||
export default () => {
|
||||
const [keyBinding, setKeyBinding] = useState<k.KeyBinding | undefined>();
|
||||
const [tmpKeyBinding, setTmpKeyBinding] = useState<k.KeyBinding>({
|
||||
code: undefined,
|
||||
modifiers: {
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
metaKey: false,
|
||||
shiftKey: false
|
||||
}
|
||||
});
|
||||
const [state, setState] = useState<'awaitingForNewKeyBinding' | 'awaitingForUserInput' | 'keyBindingUpdated'>('awaitingForNewKeyBinding');
|
||||
|
||||
useEffect(() => {
|
||||
@ -18,61 +27,66 @@ export default () => {
|
||||
})()
|
||||
}, []);
|
||||
|
||||
const handleKeyUp: KeyboardEventHandler = (event) => {
|
||||
const handleKeyUp: React.KeyboardEventHandler = (event): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const newKeyBinding = k.eventToKeyBinding(event);
|
||||
if (!newKeyBinding) {
|
||||
const isValidKb = k.validateKeyBinding(tmpKeyBinding);
|
||||
if (!isValidKb) {
|
||||
return;
|
||||
}
|
||||
|
||||
setKeyBinding(newKeyBinding);
|
||||
k.writeKeyBinding('toggleSpotlight', keyBinding).then(() => {
|
||||
setKeyBinding(tmpKeyBinding);
|
||||
k.writeKeyBinding('toggleSpotlight', tmpKeyBinding).then(() => {
|
||||
setState('keyBindingUpdated');
|
||||
});
|
||||
}
|
||||
|
||||
const handleKeyDown: KeyboardEventHandler = (event) => {
|
||||
const newKeyBinding = k.eventToKeyBinding(event, true);
|
||||
if (!newKeyBinding) {
|
||||
const handleKeyDown: React.KeyboardEventHandler = (event): void => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (state !== 'awaitingForUserInput') {
|
||||
return;
|
||||
}
|
||||
setKeyBinding(newKeyBinding);
|
||||
|
||||
const kb = k.eventToKeyBinding(event);
|
||||
setTmpKeyBinding(kb);
|
||||
}
|
||||
|
||||
const kb = state === 'awaitingForUserInput' ? tmpKeyBinding : keyBinding;
|
||||
return (
|
||||
<div className={s.popup}>
|
||||
<div
|
||||
className={s.popup}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<div className={s.header}>Haskell Spotlight</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', flex: '1 1' }}>
|
||||
<div style={{ fontSize: '14px', textAlign: 'center', padding: '0 18px' }}>
|
||||
{state === 'awaitingForNewKeyBinding' && <span>Click on the area bellow to change hot key.</span>}
|
||||
{state === 'awaitingForNewKeyBinding' && <span>Click on the area bellow to change hotkey.</span>}
|
||||
{state === 'awaitingForUserInput' && <span>Press key combination.</span>}
|
||||
{state === 'keyBindingUpdated' && <span>Hot key has been updated. Close the popup and try it on some web page. Try to refresh the page if nothing happens.</span>}
|
||||
{state === 'keyBindingUpdated' && <span><br /><strong style={{ fontSize: '32px', color: '#5e5086' }}>Refresh the page to apply new hotkey.</strong></span>}
|
||||
</div>
|
||||
|
||||
{keyBinding && (
|
||||
{kb && (
|
||||
<div
|
||||
className={`${s.kbdKeys} ${state === 'keyBindingUpdated' ? s.kbdKeysCalm : ''} ${state === 'awaitingForUserInput' ? s.kbdKeysAwaiting : ''}`}
|
||||
className={`${s.kbdKeys} ${state === 'awaitingForUserInput' ? s.kbdKeysAwaiting : ''}`}
|
||||
onClick={() => {
|
||||
if (state !== 'awaitingForUserInput') {
|
||||
if (state === 'awaitingForNewKeyBinding' || state === 'keyBindingUpdated') {
|
||||
setState('awaitingForUserInput')
|
||||
} else if (state === 'awaitingForUserInput') {
|
||||
if (k.validateKeybinding(keyBinding)) {
|
||||
setState('awaitingForNewKeyBinding');
|
||||
}
|
||||
setState('awaitingForNewKeyBinding');
|
||||
}
|
||||
}}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
tabIndex={0}
|
||||
>
|
||||
<KbdKey name={keyBinding.code} isActive={keyBinding.code !== undefined} />
|
||||
<KbdKey name={kb.code} isActive={kb.code !== undefined} />
|
||||
<div>
|
||||
<KbdKey name="Alt" isActive={keyBinding.modifiers.altKey} />
|
||||
<KbdKey name="Ctrl" isActive={keyBinding.modifiers.ctrlKey} />
|
||||
<KbdKey name="Meta" isActive={keyBinding.modifiers.metaKey} />
|
||||
<KbdKey name="Shift" isActive={keyBinding.modifiers.shiftKey} />
|
||||
<KbdKey name="Alt" isActive={kb.modifiers.altKey} />
|
||||
<KbdKey name="Ctrl" isActive={kb.modifiers.ctrlKey} />
|
||||
<KbdKey name="Meta" isActive={kb.modifiers.metaKey} />
|
||||
<KbdKey name="Shift" isActive={kb.modifiers.shiftKey} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -31,20 +31,24 @@ export const defaultKeyBindings: Record<KeyBindingId, KeyBinding> = {
|
||||
}
|
||||
}
|
||||
|
||||
export const eventToKeyBinding = (event: React.KeyboardEvent, ignoreValidation?: boolean): k.KeyBinding => {
|
||||
const noModifierSpecified = !(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
|
||||
export const isKeyModifier = (code: string) => {
|
||||
return code === 'AltLeft' ||
|
||||
code === 'AltRight' ||
|
||||
code === 'ControlLeft' ||
|
||||
code === 'ControlRight' ||
|
||||
code === 'MetaLeft' ||
|
||||
code === 'MetaRight' ||
|
||||
code === 'OSLeft' ||
|
||||
code === 'OSRight' ||
|
||||
code === 'ShiftLeft' ||
|
||||
code === 'ShiftRight'
|
||||
}
|
||||
|
||||
const keyIsModifier =
|
||||
event.key === 'Alt' ||
|
||||
event.key === 'Control' ||
|
||||
event.key === 'Meta' ||
|
||||
event.key === 'Shift';
|
||||
export const eventToKeyBinding = (event: KeyboardEvent | React.KeyboardEvent): KeyBinding => {
|
||||
const keyIsModifier = isKeyModifier(event.code);
|
||||
|
||||
if (!ignoreValidation && (noModifierSpecified || keyIsModifier)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
const kb = {
|
||||
code: keyIsModifier ? undefined : event.code,
|
||||
modifiers: {
|
||||
altKey: event.altKey,
|
||||
@ -53,6 +57,8 @@ export const eventToKeyBinding = (event: React.KeyboardEvent, ignoreValidation?:
|
||||
shiftKey: event.shiftKey,
|
||||
}
|
||||
};
|
||||
|
||||
return kb;
|
||||
}
|
||||
|
||||
export const eqKeyBindings = (kb1: KeyBinding, kb2: KeyBinding): boolean => {
|
||||
@ -66,7 +72,7 @@ export const eqKeyBindings = (kb1: KeyBinding, kb2: KeyBinding): boolean => {
|
||||
}
|
||||
|
||||
|
||||
export const resetKeyBinding = async (id: KeyBindingId): Promise<void> => {
|
||||
export const setDefaultKeybinding = async (id: KeyBindingId): Promise<void> => {
|
||||
const defaultKeyBinding = defaultKeyBindings[id];
|
||||
if (defaultKeyBinding) {
|
||||
console.log(`The keybinding ${id} is invalid. We'll reset it to default.`);
|
||||
@ -74,13 +80,13 @@ export const resetKeyBinding = async (id: KeyBindingId): Promise<void> => {
|
||||
}
|
||||
}
|
||||
|
||||
export const resetKeyBindings = async (): Promise<void> => {
|
||||
await Promise.all(Object.keys(defaultKeyBindings).map(id => resetKeyBinding(id)));
|
||||
export const setDefaultKeyBindings = async (): Promise<void> => {
|
||||
await Promise.all(Object.keys(defaultKeyBindings).map(id => setDefaultKeybinding(id as KeyBindingId)));
|
||||
}
|
||||
|
||||
// XXX - Very naive validation.
|
||||
export const validateKeybinding = (kb: KeyBinding): boolean => {
|
||||
const isValid =
|
||||
// XXX - Still quite naive validation.
|
||||
export const validateKeyBinding = (kb: KeyBinding): boolean => {
|
||||
const schemeIsValid =
|
||||
(typeof kb.code === 'string') &&
|
||||
(typeof kb.modifiers === 'object') &&
|
||||
(typeof kb.modifiers.altKey === 'boolean') &&
|
||||
@ -88,25 +94,48 @@ export const validateKeybinding = (kb: KeyBinding): boolean => {
|
||||
(typeof kb.modifiers.metaKey === 'boolean') &&
|
||||
(typeof kb.modifiers.shiftKey === 'boolean');
|
||||
|
||||
return isValid;
|
||||
if (!schemeIsValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const noModifierSpecified = !(kb.modifiers.altKey || kb.modifiers.ctrlKey || kb.modifiers.metaKey || kb.modifiers.shiftKey);
|
||||
if (noModifierSpecified) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const keyIsModifier = isKeyModifier(kb);
|
||||
if (keyIsModifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const readKeyBindingStr = async (storageKey: KeyBindingId): Promise<string | undefined> => (await browser.storage.local.get([storageKey]))[storageKey];
|
||||
|
||||
export const readKeyBinding = async (id: KeyBindingId): Promise<KeyBinding | undefined> => {
|
||||
const storageKey = kbToStorage(id);
|
||||
let keybinding: KeyBinding | undefined;
|
||||
const storageKey = kbToStorage(id) as KeyBindingId;
|
||||
|
||||
let serializedKb = await readKeyBindingStr(storageKey);
|
||||
let kb: KeyBinding;
|
||||
|
||||
try {
|
||||
keybinding = JSON.parse((await browser.storage.local.get(storageKey))[storageKey]);
|
||||
if (!validateKeybinding(keybinding)) {
|
||||
await resetKeyBindings();
|
||||
return (await readKeyBinding(id));
|
||||
if (!serializedKb) {
|
||||
await setDefaultKeyBindings();
|
||||
serializedKb = await readKeyBindingStr(storageKey);
|
||||
}
|
||||
|
||||
kb = JSON.parse(serializedKb);
|
||||
if (!validateKeyBinding(kb)) {
|
||||
await setDefaultKeyBindings();
|
||||
serializedKb = await readKeyBindingStr(storageKey);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await resetKeyBinding(id);
|
||||
} finally {
|
||||
return keybinding;
|
||||
await setDefaultKeyBindings();
|
||||
return await readKeyBinding(id);
|
||||
}
|
||||
|
||||
return kb;
|
||||
}
|
||||
|
||||
export const writeKeyBinding = async (id: KeyBindingId, kb: KeyBinding): Promise<void> => {
|
||||
|
@ -20,6 +20,8 @@ const HackageSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HackageSearch
|
||||
const [searchResults, setSearchResults] = useState<HackageSearchResults>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
|
||||
(async () => {
|
||||
if (!query) {
|
||||
return;
|
||||
@ -38,12 +40,18 @@ const HackageSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HackageSearch
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
)).data;
|
||||
} catch (err) {
|
||||
appContext.notifyError(`An error occurred while searching for packages`);
|
||||
console.log(err);
|
||||
if (!abortController.signal.aborted) {
|
||||
appContext.notifyError(`An error occurred while searching for packages`);
|
||||
console.log(err);
|
||||
}
|
||||
} finally {
|
||||
appContext.finishTask(taskId);
|
||||
}
|
||||
|
||||
if (abortController.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const searchResults: HackageSearchResults = resData;
|
||||
|
||||
if (searchResults.length > 0) {
|
||||
@ -53,9 +61,13 @@ const HackageSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HackageSearch
|
||||
setSearchResults(searchResults);
|
||||
})()
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
}
|
||||
|
||||
// XXX - don't add appContext to deps here as eslint suggests.
|
||||
// It may cause infinite recursive calls. Fix it if you know how.
|
||||
}, [query, appContext.tasks.length]);
|
||||
}, [query]);
|
||||
|
||||
const Link = asEmbeddedWidget ? ExtA : A;
|
||||
return (
|
||||
|
@ -64,6 +64,8 @@ const HoogleSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HoogleSearchRe
|
||||
}, [globalViewMode, setGlobalViewMode]);
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
|
||||
(async () => {
|
||||
if (!query) {
|
||||
return;
|
||||
@ -77,15 +79,24 @@ const HoogleSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HoogleSearchRe
|
||||
|
||||
resData = await (await axios.get(
|
||||
`${apiUrl}?mode=json&format=text&hoogle=${encodeURIComponent(query)}&start=1&count=1000`,
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
{
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
signal: abortController.signal
|
||||
}
|
||||
)).data;
|
||||
} catch (err) {
|
||||
appContext.notifyError('An error occured during searching on Hoogle');
|
||||
console.log(err);
|
||||
if (!abortController.signal.aborted) {
|
||||
appContext.notifyError('An error occured during searching on Hoogle');
|
||||
console.log(err);
|
||||
}
|
||||
} finally {
|
||||
appContext.finishTask(taskId);
|
||||
}
|
||||
|
||||
if (abortController.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const searchResults: HoogleSearchResults = groupBy(deduplicate(resData), 'item');
|
||||
|
||||
if (Object.keys(searchResults).length > 0) {
|
||||
@ -98,6 +109,10 @@ const HoogleSearchResults = ({ query, apiUrl, asEmbeddedWidget }: HoogleSearchRe
|
||||
setViewModes(zipObject(searchResultsKeys, searchResultsKeys.map(() => globalViewMode)));
|
||||
})();
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
}
|
||||
|
||||
// XXX - don't add appContext to deps here as eslint suggests.
|
||||
// It may cause infinite recursive calls. Fix it if you know how.
|
||||
}, [query]);
|
||||
|
Loading…
Reference in New Issue
Block a user