From 37b8b834b612f636bb50ac15d0553bbdd0d0b33c Mon Sep 17 00:00:00 2001 From: HF Date: Fri, 19 Aug 2022 21:42:58 +0200 Subject: [PATCH] change types and notify popups about big window unloading --- src/client.js | 3 - src/components/Window.jsx | 4 +- src/core/popUps.js | 69 ++++++++++++------- src/fix.sh | 2 + src/store/README.md | 3 +- src/store/actions/index.js | 99 ++++++++++++++++++--------- src/store/actions/thunks.js | 4 +- src/store/actions/windows.js | 2 +- src/store/middleware/audio.js | 2 +- src/store/middleware/notifications.js | 2 +- src/store/middleware/parent.js | 32 ++++++--- src/store/middleware/popUps.js | 26 ++++--- src/store/middleware/promise.js | 13 ---- src/store/middleware/rendererHook.js | 6 +- src/store/reducers/canvas.js | 4 +- src/store/reducers/chat.js | 8 +-- src/store/reducers/chatRead.js | 10 +-- src/store/reducers/fetching.js | 2 +- src/store/reducers/gui.js | 22 +++--- src/store/reducers/windows.js | 6 +- src/store/sharedReducers.js | 2 +- src/store/store.js | 10 ++- src/store/storeWin.js | 8 +-- src/win.js | 6 +- 24 files changed, 198 insertions(+), 147 deletions(-) create mode 100755 src/fix.sh delete mode 100644 src/store/middleware/promise.js diff --git a/src/client.js b/src/client.js index 055ca0c..8c50d4e 100644 --- a/src/client.js +++ b/src/client.js @@ -108,9 +108,6 @@ function init() { window.addEventListener('resize', onWindowResize); onWindowResize(); - // listen ofr messages from popups - window.addEventListener('message', store.dispatch); - store.dispatch(initTimer()); store.dispatch(fetchMe()); diff --git a/src/components/Window.jsx b/src/components/Window.jsx index fd29552..0732c17 100644 --- a/src/components/Window.jsx +++ b/src/components/Window.jsx @@ -8,7 +8,7 @@ import React, { import { useSelector, useDispatch } from 'react-redux'; import { t } from 'ttag'; -import popUps from '../core/popUps'; +import { openPopUp } from '../core/popUps'; import { moveWindow, removeWindow, @@ -82,7 +82,7 @@ const Window = ({ id }) => { } = position; const popUp = useCallback((evt) => { - popUps.open(xPos, yPos, width, height); + openPopUp(xPos, yPos, width, height); close(evt); }, [xPos, yPos, width, height]); diff --git a/src/core/popUps.js b/src/core/popUps.js index b4b8431..4b66eb4 100644 --- a/src/core/popUps.js +++ b/src/core/popUps.js @@ -1,43 +1,31 @@ /* * keeping track of open popups */ +import { unload } from '../store/actions'; class PopUps { constructor() { this.wins = []; this.origin = window.location.origin; - this.closeAll = this.closeAll.bind(this); - window.addEventListener('beforeunload', this.closeAll); + window.addEventListener('beforeunload', () => { + this.dispatch(unload()); + }); } - open(xPos, yPos, width, height) { - let left; - let top; - try { - left = Math.round(window.top.screenX + xPos); - top = Math.round(window.top.screenY + yPos); - if (Number.isNaN(left) || Number.isNaN(top)) { - throw new Error('NaN'); - } - } catch { - left = 0; - top = 0; - } - try { - const newWindow = window.open( - './win', - 'lol', - `popup=yes,width=${width},height=${height},left=${left},top=${top},toolbar=no,status=no,directories=no,menubar=no`, - ); - this.wins.push(newWindow); - } catch { - // nothing, just don't bubble up + add(win) { + const pos = this.wins.indexOf(win); + if (pos === -1) { + this.wins.push(win); } } + remove(win) { + const pos = this.wins.indexOf(win); + if (~pos) this.wins.splice(pos, 1); + } + dispatch(msg) { const { wins } = this; - console.log('sending', msg); try { for (let i = 0; i < wins.length; i += 1) { const win = wins[i]; @@ -64,4 +52,35 @@ class PopUps { const popUps = new PopUps(); +export function openPopUp(xPos, yPos, width, height) { + let left; + let top; + try { + if (window.innerWidth <= 604) { + width = window.innerWidth; + height = window.innerHeight; + left = window.top.screenX; + top = window.top.screenY; + } else { + left = Math.round(window.top.screenX + xPos); + top = Math.round(window.top.screenY + yPos); + } + if (Number.isNaN(left) || Number.isNaN(top)) { + throw new Error('NaN'); + } + } catch { + left = 0; + top = 0; + } + try { + return window.open( + './win', + 'lol', + `popup=yes,width=${width},height=${height},left=${left},top=${top},toolbar=no,status=no,directories=no,menubar=no`, + ); + } catch { + return null; + } +} + export default popUps; diff --git a/src/fix.sh b/src/fix.sh new file mode 100755 index 0000000..dd63794 --- /dev/null +++ b/src/fix.sh @@ -0,0 +1,2 @@ +#!/bin/sh +grep -rli "$1" | xargs -i@ sed -i "s/${1}/s\/${1}/g" @ diff --git a/src/store/README.md b/src/store/README.md index 9c8aa62..392dad4 100644 --- a/src/store/README.md +++ b/src/store/README.md @@ -2,4 +2,5 @@ We use redux as a state manager of our application: https://redux.js.org/ -All actions that have a p/ prefix are shared between popups with the parent / popUp middlewares +All actions that have a s/ prefix are shared between popups with the parent / popUp middlewares +Actions that are one-way signals, like notifications for window open / closed are prefixed with t/ diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 875d87e..2546dfa 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -23,73 +23,73 @@ export function closeAlert() { export function toggleHistoricalView() { return { - type: 'TOGGLE_HISTORICAL_VIEW', + type: 's/TGL_HISTORICAL_VIEW', }; } export function toggleHiddenCanvases() { return { - type: 'TOGGLE_HIDDEN_CANVASES', + type: 's/TGL_HIDDEN_CANVASES', }; } export function toggleGrid() { return { - type: 'TOGGLE_GRID', + type: 's/TGL_GRID', }; } export function togglePixelNotify() { return { - type: 'TOGGLE_PXL_NOTIFY', + type: 's/TGL_PXL_NOTIFY', }; } export function toggleAutoZoomIn() { return { - type: 'TOGGLE_AUTO_ZOOM_IN', + type: 's/TGL_AUTO_ZOOM_IN', }; } export function toggleOnlineCanvas() { return { - type: 'TOGGLE_ONLINE_CANVAS', + type: 's/TGL_ONLINE_CANVAS', }; } export function toggleMute() { return { - type: 'TOGGLE_MUTE', + type: 's/TGL_MUTE', }; } export function toggleCompactPalette() { return { - type: 'TOGGLE_COMPACT_PALETTE', + type: 's/TGL_COMPACT_PALETTE', }; } export function toggleChatNotify() { return { - type: 'TOGGLE_CHAT_NOTIFY', + type: 's/TGL_CHAT_NOTIFY', }; } export function togglePotatoMode() { return { - type: 'TOGGLE_POTATO_MODE', + type: 's/TGL_POTATO_MODE', }; } export function toggleLightGrid() { return { - type: 'TOGGLE_LIGHT_GRID', + type: 's/TGL_LIGHT_GRID', }; } export function toggleOpenPalette() { return { - type: 'TOGGLE_OPEN_PALETTE', + type: 's/TGL_OPEN_PALETTE', }; } @@ -102,7 +102,7 @@ export function selectStyle(style) { export function toggleOpenMenu() { return { - type: 'TOGGLE_OPEN_MENU', + type: 's/TGL_OPEN_MENU', }; } @@ -296,7 +296,7 @@ export function receiveChatMessage( isRead, ) { return { - type: 'REC_CHAT_MESSAGE', + type: 's/REC_CHAT_MESSAGE', name, text, country, @@ -417,23 +417,9 @@ export function initTimer() { }; } -export function openChatChannel(cid) { - return { - type: 'OPEN_CHAT_CHANNEL', - cid, - }; -} - -export function closeChatChannel(cid) { - return { - type: 'CLOSE_CHAT_CHANNEL', - cid, - }; -} - export function addChatChannel(channel) { return { - type: 'ADD_CHAT_CHANNEL', + type: 's/ADD_CHAT_CHANNEL', channel, }; } @@ -463,21 +449,21 @@ export function blockingDm(blockDm) { export function removeChatChannel(cid) { return { - type: 'REMOVE_CHAT_CHANNEL', + type: 's/REMOVE_CHAT_CHANNEL', cid, }; } export function muteChatChannel(cid) { return { - type: 'MUTE_CHAT_CHANNEL', + type: 's/MUTE_CHAT_CHANNEL', cid, }; } export function unmuteChatChannel(cid) { return { - type: 'UNMUTE_CHAT_CHANNEL', + type: 'UNs/MUTE_CHAT_CHANNEL', cid, }; } @@ -503,8 +489,53 @@ export function selectHistoricalTime(date, time) { } export function urlChange() { - return (dispatch) => { - dispatch(reloadUrl()); + return reloadUrl(); +} + +export function unload() { + return { + type: 't/UNLOAD', }; } +export function load() { + return { + type: 't/LOAD', + }; +} + +export function propagateMe(state) { + const { + id, + name, + mailreg, + blockDm, + userlvl, + } = state.user; + const { canvases } = state.canvas; + const { + blocked, + channels, + } = state.chat; + const { + ranking, + dailyRanking, + totalPixels, + dailyTotalPixels, + } = state.ranks; + return { + type: 'REC_ME', + blockDm, + blocked, + canvases, + channels, + dailyRanking, + dailyTotalPixels, + id, + mailreg, + name, + ranking, + totalPixels, + userlvl, + }; +} diff --git a/src/store/actions/thunks.js b/src/store/actions/thunks.js index 317c7f9..1bcd317 100644 --- a/src/store/actions/thunks.js +++ b/src/store/actions/thunks.js @@ -30,7 +30,7 @@ function setApiFetching(fetching) { function setChatFetching(fetching) { return { - type: 'SET_CHAT_FETCHING', + type: 's/SET_CHAT_FETCHING', fetching, }; } @@ -40,7 +40,7 @@ function receiveChatHistory( history, ) { return { - type: 'REC_CHAT_HISTORY', + type: 's/REC_CHAT_HISTORY', cid, history, }; diff --git a/src/store/actions/windows.js b/src/store/actions/windows.js index 8fba0a9..54f2373 100644 --- a/src/store/actions/windows.js +++ b/src/store/actions/windows.js @@ -156,7 +156,7 @@ export function cloneWindow(windowId) { export function toggleMaximizeWindow(windowId) { return { - type: 'TOGGLE_MAXIMIZE_WIN', + type: 's/TGL_MAXIMIZE_WIN', windowId, }; } diff --git a/src/store/middleware/audio.js b/src/store/middleware/audio.js index fcd34de..c8db91e 100644 --- a/src/store/middleware/audio.js +++ b/src/store/middleware/audio.js @@ -207,7 +207,7 @@ export default (store) => (next) => (action) => { break; } - case 'REC_CHAT_MESSAGE': { + case 's/REC_CHAT_MESSAGE': { if (chatNotify) break; const { isPing, channel } = action; diff --git a/src/store/middleware/notifications.js b/src/store/middleware/notifications.js index 485dac7..3c646db 100644 --- a/src/store/middleware/notifications.js +++ b/src/store/middleware/notifications.js @@ -40,7 +40,7 @@ export default (store) => (next) => (action) => { break; } - case 'REC_CHAT_MESSAGE': { + case 's/REC_CHAT_MESSAGE': { const state = store.getState(); const { chatNotify } = state.gui; if (!chatNotify) break; diff --git a/src/store/middleware/parent.js b/src/store/middleware/parent.js index 6c36c27..a7e3037 100644 --- a/src/store/middleware/parent.js +++ b/src/store/middleware/parent.js @@ -1,31 +1,41 @@ /* * send and receive actions from parent window */ +import { load, unload } from '../actions'; -const BLACKLIST = [ - 'SET_HOVER', - 'UNSET_HOVER', - 'SET_SCALE', - 'SET_VIEW_COORDINATES', -]; const { origin } = window.location; +window.addEventListener('beforeunload', () => { + if (window.opener && !window.closed) { + window.opener.postMessage(unload(), origin); + } +}); + + export default () => (next) => (action) => { if (action instanceof MessageEvent) { if (action.origin !== origin) { return null; } + if (action.data.type === 't/UNLOAD') { + return null; + } + console.log('GOT', action.data); return next(action.data); } if (window.opener && !window.opener.closed - && !BLACKLIST.includes(action.type) + && action.type ) { - try { - window.opener.postMessage(action, origin); - } catch { - // nothing + if (action.type === 'HYDRATED') { + window.opener.postMessage(load(), origin); + } else if (action.type.startsWith('s/')) { + try { + window.opener.postMessage(action, origin); + } catch { + // nothing + } } } diff --git a/src/store/middleware/popUps.js b/src/store/middleware/popUps.js index f79dc74..171f2fb 100644 --- a/src/store/middleware/popUps.js +++ b/src/store/middleware/popUps.js @@ -1,26 +1,32 @@ /* * send and receive actions from popups */ +import { propagateMe } from '../actions'; import popUps from '../../core/popUps'; -const BLACKLIST = [ - 'SET_HOVER', - 'UNSET_HOVER', - 'SET_SCALE', - 'SET_VIEW_COORDINATES', -]; - -export default () => (next) => (action) => { +export default (store) => (next) => (action) => { if (action instanceof MessageEvent) { if (action.origin !== window.location.origin) { return null; } + if (action.data.type === 't/UNLOAD') { + console.log('popup closed'); + popUps.remove(action.source); + } else if (action.data.type === 't/LOAD') { + const state = store.getState(); + action.source.postMessage( + propagateMe(state), + window.location.origin, + ); + popUps.add(action.source); + console.log('popup added'); + } return next(action.data); } if (popUps.wins.length - && !BLACKLIST.includes(action.type) - && action.type.indexOf('WIN') === -1 + && action.type + && action.type.startsWith('s/') ) { popUps.dispatch(action); } diff --git a/src/store/middleware/promise.js b/src/store/middleware/promise.js deleted file mode 100644 index 5b1816a..0000000 --- a/src/store/middleware/promise.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * consume async function as action - */ - -function warn(error) { - // eslint-disable-next-line no-console - console.warn(error.message || error); - throw error; // To let the caller handle the rejection -} - -export default () => (next) => (action) => (typeof action.then === 'function' - ? Promise.resolve(action).then(next, warn) - : next(action)); diff --git a/src/store/middleware/rendererHook.js b/src/store/middleware/rendererHook.js index bcf8bb0..956d484 100644 --- a/src/store/middleware/rendererHook.js +++ b/src/store/middleware/rendererHook.js @@ -61,7 +61,7 @@ export default (store) => (next) => (action) => { break; } - case 'TOGGLE_HIDDEN_CANVASES': { + case 's/TGL_HIDDEN_CANVASES': { const renderer = getRenderer(); const { is3D } = state.canvas; if (is3D) { @@ -94,14 +94,14 @@ export default (store) => (next) => (action) => { break; } - case 'TOGGLE_GRID': + case 's/TGL_GRID': case 'ALLOW_SETTING_PXL': { const renderer = getRenderer(); renderer.forceNextSubrender = true; break; } - case 'TOGGLE_HISTORICAL_VIEW': + case 's/TGL_HISTORICAL_VIEW': case 'SET_SCALE': { const renderer = getRenderer(); renderer.updateScale(state, prevScale); diff --git a/src/store/reducers/canvas.js b/src/store/reducers/canvas.js index 4c81d81..3fab700 100644 --- a/src/store/reducers/canvas.js +++ b/src/store/reducers/canvas.js @@ -213,7 +213,7 @@ export default function canvasReducer( }; } - case 'TOGGLE_HISTORICAL_VIEW': { + case 's/TGL_HISTORICAL_VIEW': { const { scale, viewscale, @@ -226,7 +226,7 @@ export default function canvasReducer( }; } - case 'TOGGLE_HIDDEN_CANVASES': { + case 's/TGL_HIDDEN_CANVASES': { return { ...state, showHiddenCanvases: !state.showHiddenCanvases, diff --git a/src/store/reducers/chat.js b/src/store/reducers/chat.js index dca0bf4..4d570e3 100644 --- a/src/store/reducers/chat.js +++ b/src/store/reducers/chat.js @@ -105,7 +105,7 @@ export default function chat( }; } - case 'ADD_CHAT_CHANNEL': { + case 's/ADD_CHAT_CHANNEL': { const { channel } = action; const cid = Number(Object.keys(channel)[0]); if (state.channels[cid]) { @@ -120,7 +120,7 @@ export default function chat( }; } - case 'REMOVE_CHAT_CHANNEL': { + case 's/REMOVE_CHAT_CHANNEL': { const { cid } = action; if (!state.channels[cid]) { return state; @@ -136,7 +136,7 @@ export default function chat( }; } - case 'REC_CHAT_MESSAGE': { + case 's/REC_CHAT_MESSAGE': { const { name, text, country, channel, user, } = action; @@ -172,7 +172,7 @@ export default function chat( }; } - case 'REC_CHAT_HISTORY': { + case 's/REC_CHAT_HISTORY': { const { cid, history } = action; for (let i = 0; i < history.length; i += 1) { msgId += 1; diff --git a/src/store/reducers/chatRead.js b/src/store/reducers/chatRead.js index 9e29135..0742db8 100644 --- a/src/store/reducers/chatRead.js +++ b/src/store/reducers/chatRead.js @@ -45,7 +45,7 @@ export default function chatRead( }; } - case 'ADD_CHAT_CHANNEL': { + case 's/ADD_CHAT_CHANNEL': { const [cid] = Object.keys(action.channel); return { ...state, @@ -60,7 +60,7 @@ export default function chatRead( }; } - case 'REMOVE_CHAT_CHANNEL': { + case 's/REMOVE_CHAT_CHANNEL': { const { cid } = action; if (!state.readTs[cid]) { return state; @@ -76,7 +76,7 @@ export default function chatRead( }; } - case 'REC_CHAT_MESSAGE': { + case 's/REC_CHAT_MESSAGE': { const { channel: cid, isRead } = action; const readTs = isRead ? { @@ -131,7 +131,7 @@ export default function chatRead( }; } - case 'MUTE_CHAT_CHANNEL': { + case 's/MUTE_CHAT_CHANNEL': { const { cid } = action; return { ...state, @@ -142,7 +142,7 @@ export default function chatRead( }; } - case 'UNMUTE_CHAT_CHANNEL': { + case 'UNs/MUTE_CHAT_CHANNEL': { const { cid } = action; const mute = state.mute.filter((id) => (id !== cid)); return { diff --git a/src/store/reducers/fetching.js b/src/store/reducers/fetching.js index f12675c..88dad4b 100644 --- a/src/store/reducers/fetching.js +++ b/src/store/reducers/fetching.js @@ -14,7 +14,7 @@ export default function fetching( action, ) { switch (action.type) { - case 'SET_CHAT_FETCHING': { + case 's/SET_CHAT_FETCHING': { const { fetching: fetchingChat } = action; return { ...state, diff --git a/src/store/reducers/gui.js b/src/store/reducers/gui.js index 98e0752..30ec71a 100644 --- a/src/store/reducers/gui.js +++ b/src/store/reducers/gui.js @@ -22,63 +22,63 @@ export default function gui( action, ) { switch (action.type) { - case 'TOGGLE_GRID': { + case 's/TGL_GRID': { return { ...state, showGrid: !state.showGrid, }; } - case 'TOGGLE_PXL_NOTIFY': { + case 's/TGL_PXL_NOTIFY': { return { ...state, showPixelNotify: !state.showPixelNotify, }; } - case 'TOGGLE_AUTO_ZOOM_IN': { + case 's/TGL_AUTO_ZOOM_IN': { return { ...state, autoZoomIn: !state.autoZoomIn, }; } - case 'TOGGLE_ONLINE_CANVAS': { + case 's/TGL_ONLINE_CANVAS': { return { ...state, onlineCanvas: !state.onlineCanvas, }; } - case 'TOGGLE_POTATO_MODE': { + case 's/TGL_POTATO_MODE': { return { ...state, isPotato: !state.isPotato, }; } - case 'TOGGLE_LIGHT_GRID': { + case 's/TGL_LIGHT_GRID': { return { ...state, isLightGrid: !state.isLightGrid, }; } - case 'TOGGLE_COMPACT_PALETTE': { + case 's/TGL_COMPACT_PALETTE': { return { ...state, compactPalette: !state.compactPalette, }; } - case 'TOGGLE_OPEN_PALETTE': { + case 's/TGL_OPEN_PALETTE': { return { ...state, paletteOpen: !state.paletteOpen, }; } - case 'TOGGLE_OPEN_MENU': { + case 's/TGL_OPEN_MENU': { return { ...state, menuOpen: !state.menuOpen, @@ -109,13 +109,13 @@ export default function gui( }; } - case 'TOGGLE_MUTE': + case 's/TGL_MUTE': return { ...state, mute: !state.mute, }; - case 'TOGGLE_CHAT_NOTIFY': + case 's/TGL_CHAT_NOTIFY': return { ...state, chatNotify: !state.chatNotify, diff --git a/src/store/reducers/windows.js b/src/store/reducers/windows.js index 9879a30..1b22d21 100644 --- a/src/store/reducers/windows.js +++ b/src/store/reducers/windows.js @@ -183,9 +183,6 @@ export default function windows( state = initialState, action, ) { - if (action.type.startsWith('persist')) { - console.log(action); - } switch (action.type) { case 'OPEN_WIN': { /* @@ -412,7 +409,7 @@ export default function windows( }); } - case 'TOGGLE_MAXIMIZE_WIN': { + case 's/TGL_MAXIMIZE_WIN': { const { windowId, } = action; @@ -504,7 +501,6 @@ export default function windows( return state; } - console.log(action); const loadedState = { ...state, ...action.payload, diff --git a/src/store/sharedReducers.js b/src/store/sharedReducers.js index f30bdb8..f7c3701 100644 --- a/src/store/sharedReducers.js +++ b/src/store/sharedReducers.js @@ -14,7 +14,7 @@ import chatRead from './reducers/chatRead'; export const CURRENT_VERSION = 11; export const migrate = (state, version) => { - console.log('migrate', state, version); + // eslint-disable-next-line no-underscore-dangle if (!state || !state._persist || state._persist.version !== version) { console.log('Newer version run, resetting store.'); return Promise.resolve({}); diff --git a/src/store/store.js b/src/store/store.js index 02475fa..deac930 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -31,7 +31,6 @@ import audio from './middleware/audio'; import socketClientHook from './middleware/socketClientHook'; import rendererHook from './middleware/rendererHook'; import array from './middleware/array'; -import promise from './middleware/promise'; import notifications from './middleware/notifications'; import title from './middleware/title'; import popUps from './middleware/popUps'; @@ -58,7 +57,6 @@ const store = createStore( reducers, applyMiddleware( thunk, - promise, array, popUps, audio, @@ -70,9 +68,9 @@ const store = createStore( ), ); - -persistStore(store); - -window.lol = store; +export const persistor = persistStore(store, {}, () => { + window.addEventListener('message', store.dispatch); + store.dispatch({ type: 'HYDRATED' }); +}); export default store; diff --git a/src/store/storeWin.js b/src/store/storeWin.js index 02ae8b6..14896d7 100644 --- a/src/store/storeWin.js +++ b/src/store/storeWin.js @@ -20,7 +20,6 @@ import win from './reducers/win'; /* * middleware */ -import promise from './middleware/promise'; import parent from './middleware/parent'; const reducers = combineReducers({ @@ -33,12 +32,13 @@ const store = createStore( reducers, applyMiddleware( thunk, - promise, parent, ), ); - -export const persistor = persistStore(store); +export const persistor = persistStore(store, {}, () => { + window.addEventListener('message', store.dispatch); + store.dispatch({ type: 'HYDRATED' }); +}); export default store; diff --git a/src/win.js b/src/win.js index 7dc924c..72fbcc6 100644 --- a/src/win.js +++ b/src/win.js @@ -6,9 +6,13 @@ import store from './store/storeWin'; import renderAppWin from './components/AppWin'; +function init() { + // window.addEventListener('message', store.dispatch); +} +init(); + document.addEventListener('DOMContentLoaded', () => { // eslint-disable-next-line no-console console.log('hello'); renderAppWin(document.getElementById('app'), store); - window.addEventListener('message', store.dispatch); });