change types and notify popups about big window unloading

This commit is contained in:
HF 2022-08-19 21:42:58 +02:00
parent cd9177cc1b
commit 37b8b834b6
24 changed files with 198 additions and 147 deletions

View File

@ -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());

View File

@ -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]);

View File

@ -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;

2
src/fix.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
grep -rli "$1" | xargs -i@ sed -i "s/${1}/s\/${1}/g" @

View File

@ -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/

View File

@ -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,
};
}

View File

@ -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,
};

View File

@ -156,7 +156,7 @@ export function cloneWindow(windowId) {
export function toggleMaximizeWindow(windowId) {
return {
type: 'TOGGLE_MAXIMIZE_WIN',
type: 's/TGL_MAXIMIZE_WIN',
windowId,
};
}

View File

@ -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;

View File

@ -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;

View File

@ -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
}
}
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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({});

View File

@ -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;

View File

@ -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;

View File

@ -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);
});