Merge pull request #19 from ueokande/content-and-background-redux-completely
Refactor: full redux on content and backgroundjh-changes
commit
d995ab0030
44 changed files with 360 additions and 404 deletions
@ -1,22 +0,0 @@ |
|||||||
import actions from '../actions'; |
|
||||||
|
|
||||||
const setItems = (groups) => { |
|
||||||
return { |
|
||||||
type: actions.COMPLETION_SET_ITEMS, |
|
||||||
groups, |
|
||||||
}; |
|
||||||
}; |
|
||||||
|
|
||||||
const selectNext = () => { |
|
||||||
return { |
|
||||||
type: actions.COMPLETION_SELECT_NEXT |
|
||||||
}; |
|
||||||
}; |
|
||||||
|
|
||||||
const selectPrev = () => { |
|
||||||
return { |
|
||||||
type: actions.COMPLETION_SELECT_PREV |
|
||||||
}; |
|
||||||
}; |
|
||||||
|
|
||||||
export { setItems, selectNext, selectPrev }; |
|
@ -1,30 +1,24 @@ |
|||||||
import * as consoleActions from '../actions/console'; |
import * as settingsActions from 'actions/setting'; |
||||||
import * as settingsActions from '../actions/setting'; |
import messages from 'content/messages'; |
||||||
import BackgroundComponent from '../components/background'; |
import BackgroundComponent from 'components/background'; |
||||||
import BackgroundInputComponent from '../components/background-input'; |
import BackgroundInputComponent from 'components/background-input'; |
||||||
import reducers from '../reducers'; |
import reducers from 'reducers'; |
||||||
import messages from '../content/messages'; |
import { createStore } from 'store'; |
||||||
import * as store from '../store'; |
|
||||||
|
|
||||||
const backgroundStore = store.createStore(reducers, (e, sender) => { |
const store = createStore(reducers, (e, sender) => { |
||||||
console.error('Vim-Vixen:', e); |
console.error('Vim-Vixen:', e); |
||||||
if (sender) { |
if (sender) { |
||||||
backgroundStore.dispatch(consoleActions.showError(e.message), sender); |
return browser.tabs.sendMessage(sender.tab.id, { |
||||||
|
type: messages.CONSOLE_SHOW_ERROR, |
||||||
|
text: e.message, |
||||||
|
}); |
||||||
} |
} |
||||||
}); |
}); |
||||||
const backgroundComponent = new BackgroundComponent(backgroundStore); |
const backgroundComponent = new BackgroundComponent(store); |
||||||
const backgroundInputComponent = new BackgroundInputComponent(backgroundStore); |
const backgroundInputComponent = new BackgroundInputComponent(store); |
||||||
backgroundStore.subscribe((sender) => { |
store.subscribe((sender) => { |
||||||
backgroundComponent.update(sender); |
backgroundComponent.update(sender); |
||||||
backgroundInputComponent.update(sender); |
backgroundInputComponent.update(sender); |
||||||
}); |
}); |
||||||
backgroundStore.subscribe((sender) => { |
|
||||||
if (sender) { |
|
||||||
return browser.tabs.sendMessage(sender.tab.id, { |
|
||||||
type: messages.STATE_UPDATE, |
|
||||||
state: backgroundStore.getState() |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
backgroundStore.dispatch(settingsActions.load()); |
store.dispatch(settingsActions.load()); |
||||||
|
@ -1,45 +1,34 @@ |
|||||||
import './console.scss'; |
import './console.scss'; |
||||||
import messages from '../content/messages'; |
import messages from 'content/messages'; |
||||||
import CompletionComponent from '../components/completion'; |
import CompletionComponent from 'components/completion'; |
||||||
import ConsoleComponent from '../components/console'; |
import ConsoleComponent from 'components/console'; |
||||||
import completionReducer from '../reducers/completion'; |
import reducers from 'reducers'; |
||||||
import * as store from '../store'; |
import { createStore } from 'store'; |
||||||
import * as completionActions from '../actions/completion'; |
import * as consoleActions from 'actions/console'; |
||||||
|
|
||||||
const completionStore = store.createStore(completionReducer); |
const store = createStore(reducers); |
||||||
let completionComponent = null; |
let completionComponent = null; |
||||||
let consoleComponent = null; |
let consoleComponent = null; |
||||||
let prevState = {}; |
|
||||||
|
|
||||||
window.addEventListener('load', () => { |
window.addEventListener('load', () => { |
||||||
let wrapper = document.querySelector('#vimvixen-console-completion'); |
let wrapper = document.querySelector('#vimvixen-console-completion'); |
||||||
completionComponent = new CompletionComponent(wrapper, completionStore); |
completionComponent = new CompletionComponent(wrapper, store); |
||||||
|
|
||||||
// TODO use root root store instead of completionStore
|
consoleComponent = new ConsoleComponent(document.body, store); |
||||||
consoleComponent = new ConsoleComponent(document.body, completionStore); |
|
||||||
}); |
}); |
||||||
|
|
||||||
completionStore.subscribe(() => { |
store.subscribe(() => { |
||||||
completionComponent.update(); |
completionComponent.update(); |
||||||
|
consoleComponent.update(); |
||||||
let state = completionStore.getState(); |
|
||||||
|
|
||||||
if (state.groupSelection >= 0) { |
|
||||||
let item = state.groups[state.groupSelection].items[state.itemSelection]; |
|
||||||
consoleComponent.setCommandValue(item.content); |
|
||||||
} else if (state.groups.length > 0 && |
|
||||||
JSON.stringify(prevState.groups) === JSON.stringify(state.groups)) { |
|
||||||
// Reset input only completion groups not changed (unselected an item in
|
|
||||||
// completion) in order to avoid to override previous input
|
|
||||||
consoleComponent.setCommandCompletionOrigin(); |
|
||||||
} |
|
||||||
prevState = state; |
|
||||||
}); |
}); |
||||||
|
|
||||||
browser.runtime.onMessage.addListener((action) => { |
browser.runtime.onMessage.addListener((action) => { |
||||||
if (action.type === messages.STATE_UPDATE) { |
switch (action.type) { |
||||||
let state = action.state.console; |
case messages.CONSOLE_SHOW_COMMAND: |
||||||
consoleComponent.update(state); |
return store.dispatch(consoleActions.showCommand(action.command)); |
||||||
completionStore.dispatch(completionActions.setItems(state.completions)); |
case messages.CONSOLE_SHOW_ERROR: |
||||||
|
return store.dispatch(consoleActions.showError(action.text)); |
||||||
|
case messages.CONSOLE_HIDE: |
||||||
|
return store.dispatch(consoleActions.hide(action.command)); |
||||||
} |
} |
||||||
}); |
}); |
||||||
|
@ -1,15 +1,15 @@ |
|||||||
import './settings.scss'; |
import './settings.scss'; |
||||||
import SettingComponent from '../components/setting'; |
import SettingComponent from 'components/setting'; |
||||||
import settingReducer from '../reducers/setting'; |
import settingReducer from 'reducers/setting'; |
||||||
import * as store from '../store'; |
import { createStore } from 'store'; |
||||||
|
|
||||||
const settingStore = store.createStore(settingReducer); |
const store = createStore(settingReducer); |
||||||
let settingComponent = null; |
let settingComponent = null; |
||||||
|
|
||||||
settingStore.subscribe(() => { |
store.subscribe(() => { |
||||||
settingComponent.update(); |
settingComponent.update(); |
||||||
}); |
}); |
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => { |
document.addEventListener('DOMContentLoaded', () => { |
||||||
settingComponent = new SettingComponent(document.body, settingStore); |
settingComponent = new SettingComponent(document.body, store); |
||||||
}); |
}); |
||||||
|
@ -1,68 +0,0 @@ |
|||||||
import actions from '../actions'; |
|
||||||
|
|
||||||
const defaultState = { |
|
||||||
groupSelection: -1, |
|
||||||
itemSelection: -1, |
|
||||||
groups: [], |
|
||||||
}; |
|
||||||
|
|
||||||
const nextSelection = (state) => { |
|
||||||
if (state.groupSelection < 0) { |
|
||||||
return [0, 0]; |
|
||||||
} |
|
||||||
|
|
||||||
let group = state.groups[state.groupSelection]; |
|
||||||
if (state.groupSelection + 1 >= state.groups.length && |
|
||||||
state.itemSelection + 1 >= group.items.length) { |
|
||||||
return [-1, -1]; |
|
||||||
} |
|
||||||
if (state.itemSelection + 1 >= group.items.length) { |
|
||||||
return [state.groupSelection + 1, 0]; |
|
||||||
} |
|
||||||
return [state.groupSelection, state.itemSelection + 1]; |
|
||||||
}; |
|
||||||
|
|
||||||
const prevSelection = (state) => { |
|
||||||
if (state.groupSelection < 0) { |
|
||||||
return [ |
|
||||||
state.groups.length - 1, |
|
||||||
state.groups[state.groups.length - 1].items.length - 1 |
|
||||||
]; |
|
||||||
} |
|
||||||
if (state.groupSelection === 0 && state.itemSelection === 0) { |
|
||||||
return [-1, -1]; |
|
||||||
} else if (state.itemSelection === 0) { |
|
||||||
return [ |
|
||||||
state.groupSelection - 1, |
|
||||||
state.groups[state.groupSelection - 1].items.length - 1 |
|
||||||
]; |
|
||||||
} |
|
||||||
return [state.groupSelection, state.itemSelection - 1]; |
|
||||||
}; |
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action = {}) { |
|
||||||
switch (action.type) { |
|
||||||
case actions.COMPLETION_SET_ITEMS: |
|
||||||
return Object.assign({}, state, { |
|
||||||
groups: action.groups, |
|
||||||
groupSelection: -1, |
|
||||||
itemSelection: -1, |
|
||||||
}); |
|
||||||
case actions.COMPLETION_SELECT_NEXT: { |
|
||||||
let next = nextSelection(state); |
|
||||||
return Object.assign({}, state, { |
|
||||||
groupSelection: next[0], |
|
||||||
itemSelection: next[1], |
|
||||||
}); |
|
||||||
} |
|
||||||
case actions.COMPLETION_SELECT_PREV: { |
|
||||||
let next = prevSelection(state); |
|
||||||
return Object.assign({}, state, { |
|
||||||
groupSelection: next[0], |
|
||||||
itemSelection: next[1], |
|
||||||
}); |
|
||||||
} |
|
||||||
default: |
|
||||||
return defaultState; |
|
||||||
} |
|
||||||
} |
|
@ -1,27 +0,0 @@ |
|||||||
import { expect } from "chai"; |
|
||||||
import actions from '../../src/actions'; |
|
||||||
import * as completionActions from '../../src/actions/completion'; |
|
||||||
|
|
||||||
describe("completion actions", () => { |
|
||||||
describe('setItems', () => { |
|
||||||
it('create COMPLETION_SET_ITEMS action', () => { |
|
||||||
let action = completionActions.setItems([1, 2, 3]); |
|
||||||
expect(action.type).to.equal(actions.COMPLETION_SET_ITEMS); |
|
||||||
expect(action.groups).to.deep.equal([1, 2, 3]); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('selectNext', () => { |
|
||||||
it('create COMPLETION_SELECT_NEXT action', () => { |
|
||||||
let action = completionActions.selectNext(); |
|
||||||
expect(action.type).to.equal(actions.COMPLETION_SELECT_NEXT); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
describe('selectPrev', () => { |
|
||||||
it('create COMPLETION_SELECT_PREV action', () => { |
|
||||||
let action = completionActions.selectPrev(); |
|
||||||
expect(action.type).to.equal(actions.COMPLETION_SELECT_PREV); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
@ -1,90 +0,0 @@ |
|||||||
import { expect } from "chai"; |
|
||||||
import actions from '../../src/actions'; |
|
||||||
import completionReducer from '../../src/reducers/completion'; |
|
||||||
|
|
||||||
describe("completion reducer", () => { |
|
||||||
it ('return the initial state', () => { |
|
||||||
let state = completionReducer(undefined, {}); |
|
||||||
expect(state).to.have.property('groupSelection', -1); |
|
||||||
expect(state).to.have.property('itemSelection', -1); |
|
||||||
expect(state).to.have.deep.property('groups', []); |
|
||||||
}); |
|
||||||
|
|
||||||
it ('return next state for COMPLETION_SET_ITEMS', () => { |
|
||||||
let state = { |
|
||||||
groupSelection: 0, |
|
||||||
itemSelection: 0, |
|
||||||
groups: [], |
|
||||||
} |
|
||||||
let action = { |
|
||||||
type: actions.COMPLETION_SET_ITEMS, |
|
||||||
groups: [{ |
|
||||||
name: 'Apple', |
|
||||||
items: [1, 2, 3] |
|
||||||
}, { |
|
||||||
name: 'Banana', |
|
||||||
items: [4, 5, 6] |
|
||||||
}] |
|
||||||
} |
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groups', action.groups); |
|
||||||
expect(state).to.have.property('groupSelection', -1); |
|
||||||
expect(state).to.have.property('itemSelection', -1); |
|
||||||
}); |
|
||||||
|
|
||||||
it ('return next state for COMPLETION_SELECT_NEXT', () => { |
|
||||||
let action = { type: actions.COMPLETION_SELECT_NEXT }; |
|
||||||
let state = { |
|
||||||
groupSelection: -1, |
|
||||||
itemSelection: -1, |
|
||||||
groups: [{ |
|
||||||
name: 'Apple', |
|
||||||
items: [1, 2] |
|
||||||
}, { |
|
||||||
name: 'Banana', |
|
||||||
items: [3] |
|
||||||
}] |
|
||||||
}; |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', 0); |
|
||||||
expect(state).to.have.property('itemSelection', 0); |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', 0); |
|
||||||
expect(state).to.have.property('itemSelection', 1); |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', -1); |
|
||||||
expect(state).to.have.property('itemSelection', -1); |
|
||||||
}); |
|
||||||
|
|
||||||
it ('return next state for COMPLETION_SELECT_PREV', () => { |
|
||||||
let action = { type: actions.COMPLETION_SELECT_PREV }; |
|
||||||
let state = { |
|
||||||
groupSelection: -1, |
|
||||||
itemSelection: -1, |
|
||||||
groups: [{ |
|
||||||
name: 'Apple', |
|
||||||
items: [1, 2] |
|
||||||
}, { |
|
||||||
name: 'Banana', |
|
||||||
items: [3] |
|
||||||
}] |
|
||||||
}; |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', 1); |
|
||||||
expect(state).to.have.property('itemSelection', 0); |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', 0); |
|
||||||
expect(state).to.have.property('itemSelection', 1); |
|
||||||
|
|
||||||
state = completionReducer(state, action); |
|
||||||
state = completionReducer(state, action); |
|
||||||
expect(state).to.have.property('groupSelection', -1); |
|
||||||
expect(state).to.have.property('itemSelection', -1); |
|
||||||
}); |
|
||||||
}); |
|
Reference in new issue