UNPKG

regular-redux-undo

Version:

the plugin of regular-redux to archieve undo and redo

99 lines (81 loc) 2.47 kB
import {extend} from '../util'; const timelineActionTypes = ['ADD', 'UNDO', 'REDO', 'SEEK']; const track = (name, reducer, size = 1024) => { const initialState = { timeline: [], index: -1, size }; const handlers = {}; timelineActionTypes.forEach(type => { handlers[name + '_' + type] = track[type.toLowerCase()]; }); /** * 1. action.record : false 则不做记录 * 2. action.replace: true 证明需要替换上次记录 * 3. action.clean: true 证明需要清空记录 */ return (state = initialState, action) => { if (!state.timeline) { initialState.current = {}; state = initialState; } const handler = handlers[action.type]; if (handler) { return handler(state, action.payload, action.replace); } // 此处使用 state.current,给内层 reducer 暴露的是部分state,非全量 state // 返回新的 部分 state 数据 const newCurrentState = reducer(state.current, action); return add(state, newCurrentState, action.record !== false, action); }; }; // 将特定 state 加入 timeline const add = track.add = (state, data, recored, action) => { const current = state.current; if (data === current || data === undefined || data === null) return state; const nextState = { current: data }; if (recored) { if (action.clean) { state.timeline = []; } else if (action.replace) { state.timeline.pop(); } let nextTimeline = nextState.timeline = state.timeline.slice( state.index + 1 >= state.size ? 1 : 0, state.index + 1 ); nextState.index = nextTimeline.push(data) - 1; } return extend(nextState, state); }; /** * 搜索特定 index 的 timeline 数据,并替换当前 state * 实现 undo redo 功能 */ const seek = track.seek = (state, index, replace) => { const timeline = state.timeline; const maxIndex = timeline.length - 1; if (index < 0) { index = 0; } // Allow for -1 when timeline is empty. if (index > maxIndex) { index = maxIndex; return state; } if (replace) state.timeline = timeline.slice(0, index + 1); return index == state.index ? state : extend({ index: index, current: timeline[index] }, state); }; track.undo = function(state, steps, replace) { return seek(state, state.index - (steps || 1), replace); }; track.redo = function (state, steps) { return seek(state, state.index + (steps || 1)); }; export default track;