diff --git a/client/src/components/content-block-form/ContentElement.vue b/client/src/components/content-block-form/ContentElement.vue
index 7b4659c4..d2deb10a 100644
--- a/client/src/components/content-block-form/ContentElement.vue
+++ b/client/src/components/content-block-form/ContentElement.vue
@@ -37,6 +37,18 @@
class="contents-form__trash-icon icon-button__icon"
/>
+
+ Up
+
+
+ Down
+
diff --git a/client/src/graphql/immutable-operations.js b/client/src/graphql/immutable-operations.js
index 44c9715e..9c758b1b 100644
--- a/client/src/graphql/immutable-operations.js
+++ b/client/src/graphql/immutable-operations.js
@@ -19,9 +19,26 @@ export const removeAtIndex = (arr, idx) => {
];
};
export const replaceAtIndex = (arr, idx, el) => {
+ //todo: check array index bounds, numbers
return [
...arr.slice(0, idx),
el,
...arr.slice(idx+1)
];
};
+export const swapElements = (arr, idx1, idx2)=>{
+ const maxLength = arr.length - 1;
+ if (idx1 < 0 || idx2 < 0 || idx1 > maxLength || idx2 > maxLength) {
+ return [...arr];
+ }
+ const [smaller, larger] = [idx1, idx2].sort(); // todo: check for numbers
+ const el1 = arr[smaller];
+ const el2 = arr[larger];
+ return [
+ ...arr.slice(0, smaller),
+ el2,
+ ...arr.slice(smaller+1, larger),
+ el1,
+ ...arr.slice(larger+1)
+ ];
+};
diff --git a/client/src/pages/createContentBlock.vue b/client/src/pages/createContentBlock.vue
index 4bf6cca6..0d9c97e2 100644
--- a/client/src/pages/createContentBlock.vue
+++ b/client/src/pages/createContentBlock.vue
@@ -45,6 +45,8 @@
class="create-content-block__segment"
@update="update(index, $event, outer)"
@remove="remove(outer, index)"
+ @up="up(outer, index)"
+ @down="down(outer, index)"
/>
value.type !== CHOOSER;
@@ -198,6 +202,25 @@
});
},
+ shift(outer, inner, distance) {
+ if (inner === undefined) {
+ this.contentBlock.contents = swapElements(this.contentBlock.contents, outer, outer + distance);
+ } else {
+ const {contents} = this.contentBlock;
+ const outerElement = contents[outer];
+ const newOuterElement = {
+ ...outerElement,
+ contents: swapElements(outerElement.contents, inner, inner + distance)
+ };
+ this.contentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
+ }
+ },
+ up(outer, inner){
+ this.shift(outer, inner, -1);
+ },
+ down(outer, inner){
+ this.shift(outer, inner, 1);
+ },
executeRemoval(outer, inner) {
if (inner === undefined) {
// not a list item container, just remove the element from the outer array
diff --git a/client/tests/unit/immutable-operations.spec.js b/client/tests/unit/immutable-operations.spec.js
index bde11030..d2e1773b 100644
--- a/client/tests/unit/immutable-operations.spec.js
+++ b/client/tests/unit/immutable-operations.spec.js
@@ -1,4 +1,4 @@
-import {removeAtIndex, replaceAtIndex, insertAtIndex, pushToArray } from '@/graphql/immutable-operations';
+import {removeAtIndex, replaceAtIndex, insertAtIndex, pushToArray, swapElements} from '@/graphql/immutable-operations';
describe('Cache operations', () => {
it('removes at index', () => {
const original = [1, 2, 3];
@@ -60,4 +60,41 @@ describe('Cache operations', () => {
expect(copy).toEqual([1, 2, 3, 5]);
});
+ it('swaps elements of array', () => {
+ const original = [1, 2, 3];
+ const copy = swapElements(original, 0, 2);
+ expect(original.length).toBe(3);
+ expect(original).toEqual([1, 2, 3]);
+ expect(copy.length).toBe(3);
+ expect(copy).toEqual([3, 2, 1]);
+
+ original.push(4);
+ expect(original.length).toBe(4);
+ expect(original).toEqual([1, 2, 3, 4]);
+ expect(copy.length).toBe(3);
+ expect(copy).toEqual([3, 2, 1]);
+ });
+
+ it('swaps neighbors', ()=>{
+ const original = [1, 2, 3, 4, 5];
+ const copy = swapElements(original, 3, 2);
+
+ expect(copy).toEqual([1, 2, 4, 3, 5]);
+ });
+
+ it('does nothing with wrong indices', ()=>{
+ const original = [1, 2, 3, 4, 5];
+ const copy1 = swapElements(original, -1, 2);
+ const copy2 = swapElements(original, 1, 99);
+ const copy3 = swapElements(original, 1, 5);
+
+ expect(copy1).toEqual([1, 2, 3, 4, 5]);
+ expect(copy2).toEqual([1, 2, 3, 4, 5]);
+ expect(copy3).toEqual([1, 2, 3, 4, 5]);
+ original.push(4);
+ expect(original.length).toBe(6);
+ expect(copy1.length).toBe(5);
+ expect(copy2.length).toBe(5);
+ expect(copy3.length).toBe(5);
+ });
});