Commit 8c099bb59d8a282bc1b16fca9fcce3f8bc542288

Authored by ly525
1 parent ffebb06b

feat(editor): support undo-redo && first version

front-end/h5/src/components/core/editor/canvas/edit.js
... ... @@ -45,6 +45,7 @@ export default {
45 45 'setEditingElement', // -> this.foo()
46 46 'setElementPosition', // -> this.foo()
47 47 'setElementShape', // -> this.foo()
  48 + 'recordElementRect', // -> this.foo()
48 49 'elementManager'
49 50 ]),
50 51 // TODO #!zh: 优化代码
... ... @@ -196,6 +197,12 @@ export default {
196 197 this.setElementPosition(pos)
197 198 }}
198 199 handleElementMoveProp={this.handleElementMove}
  200 + handleElementMouseUpProp={() => {
  201 + this.recordElementRect()
  202 + }}
  203 + handlePointMouseUpProp={() => {
  204 + this.recordElementRect()
  205 + }}
199 206 >
200 207 {h(element.name, data)}
201 208 </Shape>
... ...
front-end/h5/src/components/core/editor/index.js
1 1 import Vue from 'vue'
2 2 import { mapState, mapActions } from 'vuex'
3 3 // import Element from '../models/element'
  4 +import undoRedoHistory from '../../../store/plugins/undo-redo/History'
4 5  
5 6 import '../styles/index.scss'
6 7  
... ... @@ -79,6 +80,12 @@ export default {
79 80 defaultSelectedKeys={['2']}
80 81 style={{ lineHeight: '64px', float: 'right', background: 'transparent' }}
81 82 >
  83 + <a-menu-item key="4" class="transparent-bg">
  84 + <a-button-group>
  85 + <a-button class="transparent-bg" style={{ color: 'white' }} type="dashed" size="small" onClick={() => undoRedoHistory.undo()}><i class={['shortcut-icon', 'fa', `fa-mail-reply`]} aria-hidden='true'/> 撤销</a-button>
  86 + <a-button class="transparent-bg" style={{ color: 'white' }} type="dashed" size="small" onClick={() => undoRedoHistory.redo()}><i class={['shortcut-icon', 'fa', `fa-mail-forward`]} aria-hidden='true'/> 重做</a-button>
  87 + </a-button-group>
  88 + </a-menu-item>
82 89 <a-menu-item key="1" class="transparent-bg"><a-button type="primary" size="small">预览</a-button></a-menu-item>
83 90 <a-menu-item key="2" class="transparent-bg"><a-button size="small">保存</a-button></a-menu-item>
84 91 <a-menu-item key="3" class="transparent-bg"><a-button size="small">发布</a-button></a-menu-item>
... ...
front-end/h5/src/components/core/support/shape.js
... ... @@ -13,7 +13,7 @@ const directionKey = {
13 13 const points = ['lt', 'rt', 'lb', 'rb', 'l', 'r', 't', 'b']
14 14  
15 15 export default {
16   - props: ['defaultPosition', 'active', 'handleMousedownProp', 'handleElementMoveProp', 'handlePointMoveProp'],
  16 + props: ['defaultPosition', 'active', 'handleMousedownProp', 'handleElementMoveProp', 'handlePointMoveProp', 'handleElementMouseUpProp', 'handlePointMouseUpProp'],
17 17 computed: {
18 18 position () {
19 19 return { ...this.defaultPosition }
... ...
front-end/h5/src/store/index.js
1 1 import Vue from 'vue'
2 2 import Vuex from 'vuex'
  3 +import undoRedoPlugin from './plugins/undo-redo/index'
3 4 import editor from './modules/editor'
4 5 import user from './modules/user'
5 6 import visible from './modules/visible'
... ... @@ -24,5 +25,6 @@ export default new Vuex.Store({
24 25 visible,
25 26 loading,
26 27 element
27   - }
  28 + },
  29 + plugins: [undoRedoPlugin]
28 30 })
... ...
front-end/h5/src/store/modules/element.js
... ... @@ -22,6 +22,9 @@ const actions = {
22 22 setElementShape ({ commit }, payload) {
23 23 commit('setElementCommonStyle', payload)
24 24 },
  25 + recordElementRect ({ commit }, payload = {}) {
  26 + commit('recordRect', payload)
  27 + },
25 28 elementManager ({ commit }, payload) {
26 29 commit('elementManager', payload)
27 30 }
... ... @@ -58,6 +61,9 @@ const mutations = {
58 61 break
59 62 default:
60 63 }
  64 + },
  65 + recordRect (state, { type, value }) {
  66 +
61 67 }
62 68 }
63 69  
... ...
front-end/h5/src/store/plugins/undo-redo/History.js 0 → 100644
  1 +import { cloneDeep } from 'lodash'
  2 +
  3 +class UndoRedoHistory {
  4 + store;
  5 + history = [];
  6 + currentIndex = -1;
  7 +
  8 + get canUndo () {
  9 + return this.currentIndex > 0
  10 + }
  11 +
  12 + get canRedo () {
  13 + return this.history.length > this.currentIndex + 1
  14 + }
  15 +
  16 + init (store) {
  17 + this.store = store
  18 + }
  19 +
  20 + addState (state) {
  21 + // may be we have to remove redo steps
  22 + if (this.currentIndex + 1 < this.history.length) {
  23 + this.history.splice(this.currentIndex + 1)
  24 + }
  25 + this.history.push(state)
  26 + this.currentIndex++
  27 + }
  28 +
  29 + undo () {
  30 + if (!this.canUndo) return
  31 + const prevState = this.history[this.currentIndex - 1]
  32 + // take a copy of the history state
  33 + // because it would be changed during store mutations
  34 + // what would corrupt the undo-redo-history
  35 + // (same on redo)
  36 + this.store.replaceState(cloneDeep(prevState))
  37 + this.currentIndex--
  38 + }
  39 +
  40 + redo () {
  41 + if (!this.canRedo) return
  42 + const nextState = this.history[this.currentIndex + 1]
  43 + this.store.replaceState(cloneDeep(nextState))
  44 + this.currentIndex++
  45 + }
  46 +}
  47 +
  48 +const undoRedoHistory = new UndoRedoHistory()
  49 +
  50 +export default undoRedoHistory
... ...
front-end/h5/src/store/plugins/undo-redo/index.js 0 → 100644
  1 +
  2 +import { cloneDeep } from 'lodash'
  3 +import undoRedoHistory from './History'
  4 +const unRecordHistoryMutationTypes = ['element/setElementCommonStyle']
  5 +
  6 +const undoRedoPlugin = (store) => {
  7 + // initialize and save the starting stage
  8 + undoRedoHistory.init(store)
  9 + let firstState = cloneDeep(store.state)
  10 + undoRedoHistory.addState(firstState)
  11 +
  12 + store.subscribe((mutation, state) => {
  13 + const { type } = mutation
  14 + if (unRecordHistoryMutationTypes.includes(type)) return
  15 + // is called AFTER every mutation
  16 + undoRedoHistory.addState(cloneDeep(state))
  17 + })
  18 +}
  19 +
  20 +export default undoRedoPlugin
... ...