Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions frontend/js/store/modules/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ACTIONS from '@/store/actions'
import { buildBlock, isBlockEmpty } from '@/utils/getFormData.js'

import api from '../api/blocks'
import { BLOCKS } from '../mutations'
import { BLOCKS, BROWSER, FORM, MEDIA_LIBRARY } from '../mutations'

const state = {
/**
Expand Down Expand Up @@ -107,7 +107,7 @@ const mutations = {
[BLOCKS.DUPLICATE_BLOCK] (state, { editorName, index, block, id }) {
const updated = state.blocks[editorName] || []

updated.splice(index, 0, { ...block, id, name: editorName })
updated.splice(index, 0, { ...JSON.parse(JSON.stringify(block)), id, name: editorName })

Vue.set(state.blocks, editorName, updated)
},
Expand Down Expand Up @@ -188,7 +188,81 @@ const actions = {
}
},
async [ACTIONS.DUPLICATE_BLOCK] ({ commit, state, rootState }, { editorName, futureIndex, block, id }) {
const clone = (v) => v == null ? v : JSON.parse(JSON.stringify(v))

const repeaters = (rootState.repeaters && rootState.repeaters.repeaters) || {}
const nestedBlocks = (rootState.blocks && rootState.blocks.blocks) || {}
const fields = (rootState.form && rootState.form.fields) || []
const mediaSelected = (rootState.mediaLibrary && rootState.mediaLibrary.selected) || {}
const browserSelected = (rootState.browser && rootState.browser.selected) || {}

const idMap = { [block.id]: id }
const queue = [block.id]
while (queue.length) {
const currentId = queue.shift()
const prefix = `blocks-${currentId}|`
;[repeaters, nestedBlocks].forEach(bucket => {
Object.keys(bucket).forEach(key => {
if (!key.startsWith(prefix)) return
;(bucket[key] || []).forEach(item => {
if (!item || item.id == null || idMap[item.id] != null) return
idMap[item.id] = setBlockID()
queue.push(item.id)
})
})
})
}

const rewrite = (str, before, after) => Object.keys(idMap).reduce(
(acc, oldId) => acc.split(`${before}${oldId}${after}`).join(`${before}${idMap[oldId]}${after}`), str
)
const inSubtree = (key) => Object.keys(idMap).some(oldId => key.startsWith(`blocks-${oldId}|`))

commit(BLOCKS.DUPLICATE_BLOCK, { editorName, index: futureIndex, block, id })

Object.keys(nestedBlocks).forEach(key => {
if (!inSubtree(key)) return
const newKey = rewrite(key, 'blocks-', '|')
const cloned = (nestedBlocks[key] || []).map(nested => {
if (!nested || nested.id == null || idMap[nested.id] == null) return null
return { ...clone(nested), id: idMap[nested.id], name: newKey }
}).filter(Boolean)
if (!cloned.length) return
const existing = state.blocks[newKey] || []
commit(BLOCKS.REORDER_BLOCKS, { editorName: newKey, value: [...existing, ...cloned] })
})

const clonedRepeaters = {}
Object.keys(repeaters).forEach(key => {
if (!inSubtree(key)) return
clonedRepeaters[rewrite(key, 'blocks-', '|')] = (repeaters[key] || []).map(item => {
const c = clone(item)
if (c && c.id != null && idMap[c.id] != null) c.id = idMap[c.id]
if (c) c.twillUi = { isNew: true }
return c
})
})
if (Object.keys(clonedRepeaters).length) commit(FORM.ADD_REPEATERS, { repeaters: clonedRepeaters })

const fieldCopies = []
const clonedMedias = {}
const clonedBrowsers = {}
Object.keys(idMap).forEach(oldId => {
const fp = `blocks[${oldId}]`
fields.forEach(f => {
if (typeof f.name !== 'string' || !f.name.startsWith(fp)) return
fieldCopies.push({ name: rewrite(f.name, 'blocks[', ']'), value: clone(f.value) })
})
Object.keys(mediaSelected).forEach(k => {
if (k.startsWith(fp)) clonedMedias[rewrite(k, 'blocks[', ']')] = clone(mediaSelected[k])
})
Object.keys(browserSelected).forEach(k => {
if (k.startsWith(fp)) clonedBrowsers[rewrite(k, 'blocks[', ']')] = clone(browserSelected[k])
})
})
if (fieldCopies.length) commit(FORM.ADD_FORM_FIELDS, fieldCopies)
if (Object.keys(clonedMedias).length) commit(MEDIA_LIBRARY.ADD_MEDIAS, { medias: clonedMedias })
if (Object.keys(clonedBrowsers).length) commit(BROWSER.ADD_BROWSERS, { browsers: clonedBrowsers })
},
async [ACTIONS.MOVE_BLOCK_TO_EDITOR] ({ commit, dispatch }, { editorName, index, block, futureIndex, id }) {
await dispatch(ACTIONS.DUPLICATE_BLOCK, {
Expand Down
15 changes: 0 additions & 15 deletions frontend/js/store/modules/browser.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import Vue from 'vue'

import ACTIONS from '@/store/actions'

import { BROWSER } from '../mutations'

const state = {
Expand Down Expand Up @@ -107,21 +105,8 @@ const mutations = {
}
}

const actions = {
async [ACTIONS.DUPLICATE_BLOCK] ({ commit, getters }, { block, id }) {
// copy browsers and update with the provided id
const browsers = { ...getters.browsersByBlockId(block.id) }
const browserIds = Object.keys(browsers)
const duplicates = {}
browserIds.forEach(browserId => (duplicates[browserId.replace(block.id, id)] = [...browsers[browserId]]))

commit(BROWSER.ADD_BROWSERS, { browsers: duplicates })
}
}

export default {
state,
getters,
mutations,
actions
}
8 changes: 1 addition & 7 deletions frontend/js/store/modules/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
* Save all the fields of the form. Submit the form. Display errors.
*/

import cloneDeep from 'lodash/cloneDeep'

import ACTIONS from '@/store/actions'
import { getFormData, getFormFields, getModalFormFields } from '@/utils/getFormData.js'

Expand Down Expand Up @@ -156,7 +154,7 @@ const mutations = {
fields.forEach(field => {
newFields.push({
name: field.name.replace(oldId, newId),
value: cloneDeep(field.value)
value: JSON.parse(JSON.stringify(field.value))
})
})
state.fields = [...state.fields, ...newFields]
Expand Down Expand Up @@ -356,10 +354,6 @@ const actions = {
commit(NOTIFICATION.SET_NOTIF, { message: 'Your submission could not be validated, please fix and retry', variant: 'error' })
}
})
},
async [ACTIONS.DUPLICATE_BLOCK] ({ commit, getters }, { block, id }) {
const fields = getters.fieldsByBlockId(block.id)
commit(FORM.DUPLICATE_BLOCK_FORM_FIELDS, { fields, oldId: block.id, newId: id })
}
}

Expand Down
15 changes: 0 additions & 15 deletions frontend/js/store/modules/media-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import cloneDeep from 'lodash/cloneDeep'
import Vue from 'vue'

import ACTIONS from '@/store/actions'

import { MEDIA_LIBRARY } from '../mutations'

const state = {
Expand Down Expand Up @@ -286,21 +284,8 @@ const mutations = {
}
}

const actions = {
async [ACTIONS.DUPLICATE_BLOCK] ({ commit, getters }, { block, id }) {
// copy medias and update with the provided id
const medias = { ...getters.mediasByBlockId(block.id) }
const mediaIds = Object.keys(medias)
const duplicates = {}
mediaIds.forEach(mediaId => (duplicates[mediaId.replace(block.id, id)] = [...medias[mediaId]]))

commit(MEDIA_LIBRARY.ADD_MEDIAS, { medias: duplicates })
}
}

export default {
state,
getters,
mutations,
actions
}
33 changes: 3 additions & 30 deletions frontend/js/store/modules/repeaters.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const mutations = {
state.repeaters[blockInfos.name].splice(blockInfos.index, 1)
},
[FORM.DUPLICATE_FORM_BLOCK] (state, blockInfos) {
const clone = Object.assign({}, state.repeaters[blockInfos.name][blockInfos.index])
const clone = JSON.parse(JSON.stringify(state.repeaters[blockInfos.name][blockInfos.index]))
clone.id = setBlockID()

// Metadata for rendering
Expand All @@ -122,7 +122,7 @@ const mutations = {
fields.forEach(field => {
fieldCopies.push({
name: field.name.replace(blockInfos.id, clone.id),
value: field.value
value: JSON.parse(JSON.stringify(field.value))
})
})
this.commit(FORM.ADD_FORM_FIELDS, fieldCopies)
Expand All @@ -139,7 +139,7 @@ const mutations = {

const actions = {
async [ACTIONS.DUPLICATE_REPEATER] ({ state, commit, getters }, { editorName, block, index, id }) {
const clone = Object.assign({}, state.repeaters[editorName][index])
const clone = JSON.parse(JSON.stringify(state.repeaters[editorName][index]))
clone.id = id

// Metadata for rendering
Expand All @@ -163,33 +163,6 @@ const actions = {

commit(FORM.ADD_FORM_FIELDS, fieldCopies)
commit(FORM.ADD_REPEATERS, { repeaters: duplicates })
},
async [ACTIONS.DUPLICATE_BLOCK] ({ commit, getters }, { block, id }) {
// copy repeaters and update with the provided id
const repeaters = { ...getters.repeatersByBlockId(block.id) }
const repeaterIds = Object.keys(repeaters)
const duplicates = {}
repeaterIds.forEach(repeaterId => (duplicates[repeaterId.replace(block.id, id)] = [...repeaters[repeaterId]]))

// copy fields and give them a new id
const fieldCopies = []
Object.keys(duplicates).forEach(duplicateId => {
duplicates[duplicateId].forEach((block, index) => {
const id = Date.now() + Math.floor(Math.random() * 1000)
const fields = [...getters.fieldsByBlockId(block.id)]
duplicates[duplicateId][index] = { ...duplicates[duplicateId][index], id }

fields.forEach(field => {
fieldCopies.push({
name: field.name.replace(block.id, id),
value: JSON.parse(JSON.stringify(field.value))
})
})
})
})

commit(FORM.ADD_REPEATERS, { repeaters: duplicates })
commit(FORM.ADD_FORM_FIELDS, fieldCopies)
}
}

Expand Down
Loading