From 3f2fe567f909f27282f2a61349c6f0da4ea520b0 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Tue, 24 Sep 2019 11:53:12 +0900 Subject: [PATCH 1/4] feat: deselect image when image is removed --- src/scripts/main.tsx | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/scripts/main.tsx b/src/scripts/main.tsx index 6cb6192..71b0783 100644 --- a/src/scripts/main.tsx +++ b/src/scripts/main.tsx @@ -2,9 +2,13 @@ import * as React from 'react'; import ReactDom from 'react-dom'; import { Provider } from 'react-redux'; import { store } from './store'; -import { selectImageAction } from './actions'; +import { selectImageAction, deselectImageAction } from './actions'; import App from './components/App'; +function handleClickAddedImage(e: Event) { + store.dispatch(selectImageAction(e.target as HTMLImageElement)); +} + window.onload = (_e: Event): void => { const noteBody = document.getElementById('note-body'); const rootApp = document.createElement('div'); @@ -19,15 +23,31 @@ window.onload = (_e: Event): void => { const noteBodyObserver = new MutationObserver((records) => { records.forEach((record) => { - const addImages = Array.from(record.addedNodes) - .map((node) => node.firstChild) - .filter((node) => node.nodeName === 'IMG'); + if (record.addedNodes.length > 0) { + const addImages = Array.from(record.addedNodes) + .map((node) => node.firstChild) + .filter((node) => node.nodeName === 'IMG'); + + addImages.forEach((image) => { + image.addEventListener('click', handleClickAddedImage); + }); + } + + if (record.removedNodes.length > 0) { + // 削除された Image へのイベントを削除 + const removedImages = Array.from(record.removedNodes) + .map((node) => node.firstChild) + .filter((node) => node.nodeName === 'IMG'); + + removedImages.forEach((image, i, self) => { + image.removeEventListener('click', handleClickAddedImage); - addImages.forEach((image) => { - image.addEventListener('click', (e) => { - store.dispatch(selectImageAction(e.target as HTMLImageElement)); + // 最後に画像の選択を解除 + if (i + 1 === self.length) { + store.dispatch(deselectImageAction()); + } }); - }); + } }); }); From a2da15e378cbb62001274f71134d6aa2691ff063 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Tue, 24 Sep 2019 12:48:54 +0900 Subject: [PATCH 2/4] refactor: separate file observers --- src/scripts/main.tsx | 36 +----------------------------------- src/scripts/observers.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 35 deletions(-) create mode 100644 src/scripts/observers.ts diff --git a/src/scripts/main.tsx b/src/scripts/main.tsx index 71b0783..e008bec 100644 --- a/src/scripts/main.tsx +++ b/src/scripts/main.tsx @@ -2,12 +2,8 @@ import * as React from 'react'; import ReactDom from 'react-dom'; import { Provider } from 'react-redux'; import { store } from './store'; -import { selectImageAction, deselectImageAction } from './actions'; import App from './components/App'; - -function handleClickAddedImage(e: Event) { - store.dispatch(selectImageAction(e.target as HTMLImageElement)); -} +import { noteBodyObserver } from './observers'; window.onload = (_e: Event): void => { const noteBody = document.getElementById('note-body'); @@ -21,35 +17,5 @@ window.onload = (_e: Event): void => { rootApp, ); - const noteBodyObserver = new MutationObserver((records) => { - records.forEach((record) => { - if (record.addedNodes.length > 0) { - const addImages = Array.from(record.addedNodes) - .map((node) => node.firstChild) - .filter((node) => node.nodeName === 'IMG'); - - addImages.forEach((image) => { - image.addEventListener('click', handleClickAddedImage); - }); - } - - if (record.removedNodes.length > 0) { - // 削除された Image へのイベントを削除 - const removedImages = Array.from(record.removedNodes) - .map((node) => node.firstChild) - .filter((node) => node.nodeName === 'IMG'); - - removedImages.forEach((image, i, self) => { - image.removeEventListener('click', handleClickAddedImage); - - // 最後に画像の選択を解除 - if (i + 1 === self.length) { - store.dispatch(deselectImageAction()); - } - }); - } - }); - }); - noteBodyObserver.observe(noteBody, { childList: true }); }; diff --git a/src/scripts/observers.ts b/src/scripts/observers.ts new file mode 100644 index 0000000..0ccab28 --- /dev/null +++ b/src/scripts/observers.ts @@ -0,0 +1,33 @@ +import { store } from './store'; +import { selectImageAction, deselectImageAction } from './actions'; + +function handleClickAddedImage(e: Event) { + store.dispatch(selectImageAction(e.target as HTMLImageElement)); +} + +export const noteBodyObserver = new MutationObserver((records) => { + records.forEach((record) => { + if (record.addedNodes.length > 0) { + const addImages = Array.from(record.addedNodes) + .map((node) => node.firstChild) + .filter((node) => node.nodeName === 'IMG'); + + addImages.forEach((image) => { + image.addEventListener('click', handleClickAddedImage); + }); + } + + if (record.removedNodes.length > 0) { + // 削除された Image へのイベントを削除 + const removedImages = Array.from(record.removedNodes) + .map((node) => node.firstChild) + .filter((node) => node.nodeName === 'IMG'); + + removedImages.forEach((image, i, self) => { + image.removeEventListener('click', handleClickAddedImage); + }); + + store.dispatch(deselectImageAction()); + } + }); +}); From 76f38c77a98c4b02d43072ca8b576d25497f47ba Mon Sep 17 00:00:00 2001 From: masuP9 Date: Tue, 24 Sep 2019 13:23:57 +0900 Subject: [PATCH 3/4] feat: reposition when image style change --- src/scripts/actions.ts | 11 ++++++++++- src/scripts/observers.ts | 22 ++++++++++++++++++---- src/scripts/reducer.ts | 18 +++++++++++++++--- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/scripts/actions.ts b/src/scripts/actions.ts index 8e76eb6..5de0f4d 100644 --- a/src/scripts/actions.ts +++ b/src/scripts/actions.ts @@ -17,4 +17,13 @@ export function deselectImageAction(): DeselectImageAction { return { type: DESELECT_IMAGE }; } -export type ActionTypes = SelectImageAction | DeselectImageAction; +export const CHANGE_SIZE_IMAGE = 'CHANGE_SIZE_IMAGE'; +export type ChangeSizeImageAction = { + type: typeof CHANGE_SIZE_IMAGE; +}; + +export function changeSizeImageAction(): ChangeSizeImageAction { + return { type: CHANGE_SIZE_IMAGE }; +} + +export type ActionTypes = SelectImageAction | DeselectImageAction | ChangeSizeImageAction; diff --git a/src/scripts/observers.ts b/src/scripts/observers.ts index 0ccab28..40be1f5 100644 --- a/src/scripts/observers.ts +++ b/src/scripts/observers.ts @@ -1,5 +1,18 @@ import { store } from './store'; -import { selectImageAction, deselectImageAction } from './actions'; +import { selectImageAction, deselectImageAction, changeSizeImageAction } from './actions'; + +export const imageObserver = new MutationObserver((records) => { + records.forEach((record) => { + const { type, target, oldValue, attributeName } = record; + if ( + type === 'attributes' && + target.nodeName === 'IMG' && + oldValue !== (target as HTMLImageElement).getAttribute(attributeName) + ) { + store.dispatch(changeSizeImageAction()); + } + }); +}); function handleClickAddedImage(e: Event) { store.dispatch(selectImageAction(e.target as HTMLImageElement)); @@ -14,6 +27,7 @@ export const noteBodyObserver = new MutationObserver((records) => { addImages.forEach((image) => { image.addEventListener('click', handleClickAddedImage); + imageObserver.observe(image, { attributeFilter: ['style'] }); }); } @@ -27,7 +41,7 @@ export const noteBodyObserver = new MutationObserver((records) => { image.removeEventListener('click', handleClickAddedImage); }); - store.dispatch(deselectImageAction()); - } - }); + store.dispatch(deselectImageAction()); + } + }); }); diff --git a/src/scripts/reducer.ts b/src/scripts/reducer.ts index 9fc66af..e6e48e4 100644 --- a/src/scripts/reducer.ts +++ b/src/scripts/reducer.ts @@ -1,5 +1,5 @@ import { combineReducers } from 'redux'; -import { DESELECT_IMAGE, SELECT_IMAGE, ActionTypes } from './actions'; +import { DESELECT_IMAGE, SELECT_IMAGE, ActionTypes, CHANGE_SIZE_IMAGE } from './actions'; export type Position = { left: number; @@ -23,7 +23,7 @@ type Action = ActionTypes; export function imageReducer(state = initialState, action: Action) { switch (action.type) { - case SELECT_IMAGE: + case SELECT_IMAGE: { const imageRect = action.payload.getBoundingClientRect(); return { ...state, @@ -33,8 +33,20 @@ export function imageReducer(state = initialState, action: Action) { top: imageRect.top, }, }; - case DESELECT_IMAGE: + } + case DESELECT_IMAGE: { return { ...state, selectedImage: null }; + } + case CHANGE_SIZE_IMAGE: { + const imageRect = state.selectedImage.getBoundingClientRect(); + return { + ...state, + position: { + left: imageRect.right + 12, + top: imageRect.top, + }, + }; + } default: return state; } From 709051eaeb67f9510a52a1939499edca347831d1 Mon Sep 17 00:00:00 2001 From: masuP9 Date: Tue, 24 Sep 2019 13:24:28 +0900 Subject: [PATCH 4/4] feat: deselect image when add nodes too --- src/scripts/observers.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scripts/observers.ts b/src/scripts/observers.ts index 40be1f5..32385e0 100644 --- a/src/scripts/observers.ts +++ b/src/scripts/observers.ts @@ -29,6 +29,8 @@ export const noteBodyObserver = new MutationObserver((records) => { image.addEventListener('click', handleClickAddedImage); imageObserver.observe(image, { attributeFilter: ['style'] }); }); + + store.dispatch(deselectImageAction()); } if (record.removedNodes.length > 0) {