Skip to content

Commit

Permalink
Implement prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Sep 14, 2021
1 parent f81f452 commit 6661bca
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 8 deletions.
96 changes: 88 additions & 8 deletions src/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,109 @@ function getLocation(source) {
}

function createHistory(source) {
let promptHandlers = [];
let listeners = [];
let location = getLocation(source);
let action = POP;

const notifyPromptHandlers = () => {
for (let i = 0, l = promptHandlers.length; i < l; i++) {
const promptHandler = promptHandlers[i];
const result = promptHandler({ location, action });
if (result !== undefined) {
return result;
}
}
return undefined;
};
const promptIfNecessary = () => {
const message = notifyPromptHandlers();
return message !== undefined
? // eslint-disable-next-line no-alert
window.confirm(message)
: true;
};

const notifyListeners = (listenerFns = listeners) =>
listenerFns.forEach(listener => listener({ location, action }));

let popstateUnlisten;
const registerPopstateListener = () => {
if (popstateUnlisten === undefined) {
popstateUnlisten = addListener(source, "popstate", () => {
if (promptIfNecessary()) {
location = getLocation(source);
action = POP;
notifyListeners();
} else {
window.history.pushState(
location.state,
location.title,
location.href,
);
}
});
}
};
const removePopstateListener = () => {
if (popstateUnlisten !== undefined) {
popstateUnlisten();
popstateUnlisten = undefined;
}
};

let beforeUnloadUnlisten;
const registerBeforeUnloadListener = () => {
if (beforeUnloadUnlisten === undefined) {
beforeUnloadUnlisten = addListener(window, "beforeunload", e => {
const message = notifyPromptHandlers();
if (message !== undefined) {
e.preventDefault();
e.returnValue = message;
}
});
}
};
const removeBeforeUnloadListener = () => {
if (beforeUnloadUnlisten !== undefined) {
beforeUnloadUnlisten();
beforeUnloadUnlisten = undefined;
}
};

return {
get location() {
return location;
},
listen(listener) {
listeners.push(listener);
prompt(promptHandler) {
registerPopstateListener();
registerBeforeUnloadListener();

const popstateListener = () => {
location = getLocation(source);
action = POP;
notifyListeners([listener]);
promptHandlers.push(promptHandler);

return () => {
promptHandlers = promptHandlers.filter(fn => fn !== promptHandler);
if (promptHandlers.length === 0 && listeners.length === 0) {
removePopstateListener();
removeBeforeUnloadListener();
}
};
},
listen(listener) {
registerPopstateListener();
registerBeforeUnloadListener();

listeners.push(listener);

// Call listener when it is registered
notifyListeners([listener]);

const unlisten = addListener(source, "popstate", popstateListener);
return () => {
unlisten();
listeners = listeners.filter(fn => fn !== listener);
if (promptHandlers.length === 0 && listeners.length === 0) {
removePopstateListener();
removeBeforeUnloadListener();
}
};
},
/**
Expand All @@ -64,6 +140,10 @@ function createHistory(source) {
* stack, instead of pushing on a new one
*/
navigate(to, options) {
if (!promptIfNecessary()) {
return;
}

const { state = {}, replace = false } = options || {};
action = replace ? REPLACE : PUSH;
if (isNumber(to)) {
Expand Down
16 changes: 16 additions & 0 deletions test/testApp/src/Form.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script>
import { onMount } from "svelte";
import { useHistory } from "../../../src/hooks";

const history = useHistory();

let title = "";

onMount(() =>
history.prompt(() =>
title !== "" ? "This is the prompt that should be shown" : undefined,
),
);
</script>

<input name="title" bind:value={title} />
6 changes: 6 additions & 0 deletions test/testApp/src/Main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import LocationChange from "./LocationChange.svelte";
import Blog from "./Blog.svelte";
import Redirect from "./Redirect.svelte";
import Form from "./Form.svelte";

function appChange(state) {
window.appState = state;
Expand Down Expand Up @@ -101,6 +102,8 @@
use:link={customNavigate}
data-testid="action-link-custom-navigate"
href="/about"> ACTION LINK ABOUT CUSTOM NAVIGATE </a>

<Link to="form">FORM</Link>
</nav>
<br />
<main>
Expand Down Expand Up @@ -139,5 +142,8 @@
<Route path="redirect-target">
<div data-testid="redirect-target">REDIRECT-TARGET</div>
</Route>
<Route path="form">
<Form />
</Route>
</main>
</Router>

0 comments on commit 6661bca

Please sign in to comment.