diff --git a/README.md b/README.md
index b79f4c7..4381e5c 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,6 @@ npm run lint
* Implement iframe based rendering (as more compatible alternative to OffscreenCanvas) for effects
* Implement action queue when drawing, only execute drawing on update() hook
-* Implement loaders on document load/save, image export and dropbox import
* Maintain cache for transformations and filters, rendered at the display destination size (invalidate on window resize)
* Drawing masks on a rotated layer that is panned (or mirrored) is broken
* Dragging of masks on rotated/mirror content is kinda broken
diff --git a/src/bitmappery.vue b/src/bitmappery.vue
index 70834a4..b440774 100644
--- a/src/bitmappery.vue
+++ b/src/bitmappery.vue
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Igor Zinken 2020 - https://www.igorski.nl
+ * Igor Zinken 2020-2021 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -56,13 +56,14 @@
@close="closeModal()"
/>
+
+
+
diff --git a/src/store/index.js b/src/store/index.js
index e539427..abb25a7 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
- * Igor Zinken 2020 - https://www.igorski.nl
+ * Igor Zinken 2020-2021 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -56,6 +56,7 @@ export default {
panMode: false, // whether drag interactions with the document will pan its viewport
dialog: null, // currently opened dialog
modal: null, // currently opened modal
+ loadingStates: [], // wether one or more long running operations are running
notifications: [], // notification message queue
dropboxConnected: false,
windowSize: {
@@ -66,6 +67,7 @@ export default {
getters: {
// eslint-disable-next-line no-unused-vars
t: state => ( key, optArgs ) => translate( key, optArgs ),
+ isLoading: state => state.loadingStates.length > 0,
},
mutations: {
setMenuOpened( state, value ) {
@@ -86,6 +88,17 @@ export default {
setPanMode( state, value ) {
state.panMode = value;
},
+ setLoading( state, key ) {
+ if ( !state.loadingStates.includes( key )) {
+ state.loadingStates.push( key );
+ }
+ },
+ unsetLoading( state, key ) {
+ const idx = state.loadingStates.indexOf( key );
+ if ( idx > -1 ) {
+ state.loadingStates.splice( idx, 1 );
+ }
+ },
/**
* open a dialog window showing given title and message.
* types can be info, error or confirm. When type is confirm, optional
diff --git a/tests/unit/store/store.spec.js b/tests/unit/store/store.spec.js
index 93b96ea..d1dd1ed 100644
--- a/tests/unit/store/store.spec.js
+++ b/tests/unit/store/store.spec.js
@@ -1,7 +1,7 @@
import store, { PROJECT_FILE_EXTENSION } from "@/store";
import { LAYER_IMAGE } from "@/definitions/layer-types";
-const { mutations, actions } = store;
+const { getters, mutations, actions } = store;
let mockUpdateFn;
jest.mock( "@/services/keyboard-service", () => ({
@@ -19,6 +19,15 @@ jest.mock( "@/utils/file-util", () => ({
}))
describe( "Vuex store", () => {
+ describe( "getters", () => {
+ it( "should know when there is currently a loading state active", () => {
+ const state = { loadingStates: [] };
+ expect( getters.isLoading( state )).toBe( false );
+ state.loadingStates.push( "foo" );
+ expect( getters.isLoading( state )).toBe( true );
+ });
+ });
+
describe( "mutations", () => {
it( "should be able to toggle the opened state of the menu", () => {
const state = { menuOpened: false };
@@ -57,6 +66,20 @@ describe( "Vuex store", () => {
expect( state.panMode ).toBe( true );
});
+ describe( "when toggling loading states", () => {
+ it( "should be able to register a new loading state", () => {
+ const state = { loadingStates: [ "foo" ] };
+ mutations.setLoading( state, "bar" );
+ expect( state.loadingStates ).toEqual([ "foo", "bar" ]);
+ });
+
+ it( "should be able to unregister an existing loading state", () => {
+ const state = { loadingStates: [ "foo", "bar" ] };
+ mutations.unsetLoading( state, "foo" );
+ expect( state.loadingStates ).toEqual([ "bar" ]);
+ });
+ });
+
describe( "when toggling dialog windows", () => {
it( "should be able to open a dialog window and apply its request parameters", () => {
const state = { dialog: null };