1
-
2
1
<template >
3
2
<!-- Get passed down to MyLayout.vue
4
3
& listen for custom events emitted from MyLayout.vue -->
5
- <router-view
6
- v-on:undo =" undoTrigger"
4
+ <router-view
5
+ v-on:undo =" undoTrigger"
7
6
v-on:redo =" redoTrigger"
8
7
v-bind:done-action =" doneAction"
9
8
v-bind:undone-action =" undoneAction"
10
9
/>
11
10
</template >
12
11
13
12
<script >
14
- import { defineComponent } from ' vue' ;
15
- const deepEqual = require (' lodash.isequal' )
16
- const cloneDeep = require (' lodash.clonedeep' )
17
- const throttle = require (' lodash.throttle' )
18
- import { defaultState } from ' ./store/state/index.js'
13
+ import { defineComponent } from " vue" ;
14
+ const deepEqual = require (" lodash.isequal" );
15
+ const cloneDeep = require (" lodash.clonedeep" );
16
+ const throttle = require (" lodash.throttle" );
17
+ import { defaultState } from " ./store/state/index.js" ;
19
18
20
19
// use this to make sure these actions don't count as things you "undo"
21
20
const ignoredActions = new Set ([
22
- ' setActiveComponent' ,
23
- ' setActiveLayer' ,
24
- ' upOneLayer' ,
25
- ' setActiveHTML' ,
26
- ' updateComponentNameInputValue'
27
- ])
21
+ " setActiveComponent" ,
22
+ " setActiveLayer" ,
23
+ " upOneLayer" ,
24
+ " setActiveHTML" ,
25
+ " updateComponentNameInputValue" ,
26
+ ]);
28
27
29
28
let redoMixin = {
30
- data () {
29
+ data () {
31
30
return {
32
31
doneAction: [],
33
32
undoneAction: [],
34
33
isTimetraveling: false ,
35
- initialState: {},
36
- }
34
+ initialState: {},
35
+ };
37
36
},
38
- created () {
37
+ created () {
39
38
this .$store .subscribeAction ((action , state ) => {
40
- // console.log("We are saving this action!", action)
41
- if (typeof action .payload === ' object' ) {
42
- // console.log("We saved the world with a deepclone!", action.payload === cloneDeep)
43
- action .payload = cloneDeep (action .payload )
39
+ if (typeof action .payload === " object" ) {
40
+ action .payload = cloneDeep (action .payload );
44
41
}
45
42
this .doneAction .push (action);
46
- // console.log(`From app.vue: ${action.payload}`)
47
- // console.log('this is the action we are logging',action)
48
- // console.log('this is in our redo queue', this.undoneAction[this.undoneAction.length-1])
49
- // console.log("Are these equal to each other?", action == this.undoneAction[this.undoneAction.length-1])
50
43
if (! this .isTimetraveling ) {
51
44
if (this .undoneAction [this .undoneAction .length - 1 ]) {
52
45
if (
@@ -57,115 +50,111 @@ let redoMixin = {
57
50
this .undoneAction [this .undoneAction .length - 1 ].payload
58
51
)
59
52
) {
60
- this .undoneAction .pop ()
53
+ this .undoneAction .pop ();
61
54
} else {
62
- this .undoneAction = []
55
+ this .undoneAction = [];
63
56
}
64
57
}
65
58
}
66
- })
59
+ });
67
60
},
68
61
// undo + redo function calling
69
62
// metaKey accounts for Command Key on Mac
70
- mounted () {
71
- const throttledUndo = throttle (this .undo , 300 )
72
- const throttledRedo = throttle (this .redo , 300 )
63
+ mounted () {
64
+ const throttledUndo = throttle (this .undo , 300 );
65
+ const throttledRedo = throttle (this .redo , 300 );
73
66
// undo function calling
74
- window .addEventListener (' keydown' , event => {
75
- if ((event .ctrlKey || event .metaKey ) && event .key === ' z ' ) {
76
- event .preventDefault ()
77
- throttledUndo ()
67
+ window .addEventListener (" keydown" , ( event ) => {
68
+ if ((event .ctrlKey || event .metaKey ) && event .key === " z " ) {
69
+ event .preventDefault ();
70
+ throttledUndo ();
78
71
}
79
- })
72
+ });
80
73
// redo function calling
81
- window .addEventListener (' keydown' , event => {
82
- if ((event .ctrlKey || event .metaKey ) && event .key === ' y ' ) {
83
- event .preventDefault ()
84
- throttledRedo ()
74
+ window .addEventListener (" keydown" , ( event ) => {
75
+ if ((event .ctrlKey || event .metaKey ) && event .key === " y " ) {
76
+ event .preventDefault ();
77
+ throttledRedo ();
85
78
}
86
- })
79
+ });
87
80
88
- this .initialState = defaultState (this .$store .state )
81
+ this .initialState = defaultState (this .$store .state );
89
82
},
90
83
91
84
methods: {
92
85
undo : function () {
93
86
if (this .doneAction .length === 0 ) {
94
- return
87
+ return ;
95
88
}
96
89
97
- this .isTimetraveling = true
98
- let undone = this .doneAction .pop ()
90
+ this .isTimetraveling = true ;
91
+ let undone = this .doneAction .pop ();
99
92
100
93
/* assuming we have have something to undo, we check if we are undoing an action that has no feedback
101
94
e.g.: changing active elements or active components or going up and down a layer since these can be obscured from immediate feedback.
102
95
these will feel bad to undo (imagine someone clicking around out of boredom and then deciding to undo
103
96
this will force them to have to undo the 30 highlights they just did instead of the last "Real" action)
104
97
if this happens we keep popping the doneAction queue and building up the redo queue. */
105
98
if (undone !== undefined ) {
106
- this .undoneAction .push (undone)
99
+ this .undoneAction .push (undone);
107
100
if (ignoredActions .has (undone .type )) {
108
- // console.log('We undid an ignored action!')
109
101
while (
110
102
this .doneAction [this .doneAction .length - 1 ] &&
111
103
ignoredActions .has (this .doneAction [this .doneAction .length - 1 ].type )
112
104
) {
113
- this .undoneAction .push (this .doneAction .pop ())
105
+ this .undoneAction .push (this .doneAction .pop ());
114
106
}
115
107
/* if we get here, that means we have undone all "useless" actions
116
108
so we have to do one more final pop and push, have to make sure it isn't null though */
117
- let finalPop = this .doneAction .pop ()
109
+ let finalPop = this .doneAction .pop ();
118
110
if (finalPop !== undefined ) {
119
- this .undoneAction .push (finalPop)
111
+ this .undoneAction .push (finalPop);
120
112
}
121
113
}
122
114
}
123
115
124
116
let payload = {
125
117
initialState: this .initialState ,
126
- store: this .$store
127
- }
128
- this .$store .commit (' EMPTY_STATE' , payload)
129
- this .doneAction .forEach (action => {
130
- // console.log('in the undo loop', this.$store)
131
- this .$store .dispatch (action .type , cloneDeep (action .payload ))
132
- this .doneAction .pop ()
133
- })
134
- this .isTimetraveling = false
118
+ store: this .$store ,
119
+ };
120
+ this .$store .commit (" EMPTY_STATE" , payload);
121
+ this .doneAction .forEach ((action ) => {
122
+ this .$store .dispatch (action .type , cloneDeep (action .payload ));
123
+ this .doneAction .pop ();
124
+ });
125
+ this .isTimetraveling = false ;
135
126
},
136
127
137
128
redo : function () {
138
- let action = this .undoneAction .pop ()
129
+ let action = this .undoneAction .pop ();
139
130
140
131
// we have to set timeTraveling to true to preserve the undoneAction array while we make changes
141
- this .isTimetraveling = true
132
+ this .isTimetraveling = true ;
142
133
if (action) {
143
- this .$store .dispatch (action .type , cloneDeep (action .payload ))
134
+ this .$store .dispatch (action .type , cloneDeep (action .payload ));
144
135
}
145
- this .isTimetraveling = false
136
+ this .isTimetraveling = false ;
146
137
if (action && ignoredActions .has (action .type )) {
147
- // console.log('in the redo loop')
148
- this .redo ()
138
+ this .redo ();
149
139
}
150
- },
140
+ },
151
141
152
142
// Undo triggered from MyLayout.vue
153
- undoTrigger : function () {
143
+ undoTrigger : function () {
154
144
const throttledUndo = throttle (this .undo , 300 );
155
145
throttledUndo ();
156
146
},
157
147
158
148
// Redo triggered from MyLayout.vue
159
- redoTrigger : function () {
149
+ redoTrigger : function () {
160
150
const throttledRedo = throttle (this .redo , 300 );
161
151
throttledRedo ();
162
- }
163
- }
164
- }
152
+ },
153
+ },
154
+ };
165
155
166
156
export default defineComponent ({
167
- name: ' App' ,
168
- mixins: [redoMixin]
169
- })
157
+ name: " App" ,
158
+ mixins: [redoMixin],
159
+ });
170
160
</script >
171
-
0 commit comments