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); + }); });