builder block: allow to use the code editor on each item
This commit is contained in:
parent
bc148f0b6b
commit
8e947b0b77
|
@ -862,9 +862,16 @@ label.required::after {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
dialog {
|
||||
.builder-code-editor {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: none;
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
|
||||
textarea {
|
||||
font-family: Monospace;
|
||||
min-height: 50vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,64 +45,23 @@
|
|||
position="bottom"
|
||||
/>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm"
|
||||
v-on:click="openCodeEditor"
|
||||
>
|
||||
<i class="fas fa-code"></i>
|
||||
</button>
|
||||
<BuilderBlockCodeEditor
|
||||
ref="dialog"
|
||||
:value="value"
|
||||
:widgets="widgets"
|
||||
@update="codeUpdate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea :name="name" class="d-none">{{ toJson(value) }}</textarea>
|
||||
<dialog ref="dialog" class="modal-dialog modal-dialog-large">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Code editor</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
v-on:click="closeCodeEditor"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
class="form-control"
|
||||
rows="10"
|
||||
ref="codeEditor"
|
||||
v-model="nextValue"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
v-on:click="closeCodeEditor"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
v-on:click="checkAndSaveNextValue"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</Draggable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BuilderBlockItem from './BuilderBlockItem'
|
||||
import BuilderBlockCodeEditor from './BuilderBlockCodeEditor'
|
||||
import BuilderBlockCreate from './BuilderBlockCreate'
|
||||
import Routing from '../../../../../../../../../friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js'
|
||||
import Draggable from 'vuedraggable'
|
||||
|
@ -113,6 +72,12 @@ Routing.setRoutingData(routes)
|
|||
|
||||
export default {
|
||||
name: 'BuilderBlock',
|
||||
components: {
|
||||
BuilderBlockItem,
|
||||
BuilderBlockCreate,
|
||||
Draggable,
|
||||
BuilderBlockCodeEditor,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
|
@ -144,71 +109,8 @@ export default {
|
|||
triggerBuilderBlockEvent() {
|
||||
document.querySelector('body').dispatchEvent(new Event('builder_block.update'))
|
||||
},
|
||||
openCodeEditor() {
|
||||
this.nextValue = this.toJson(this.value)
|
||||
this.$refs.dialog.showModal()
|
||||
},
|
||||
closeCodeEditor() {
|
||||
this.$refs.codeEditor.classList.toggle('is-invalid', false)
|
||||
this.$refs.dialog.close()
|
||||
},
|
||||
isNextValueItemValueValid(item) {
|
||||
const hasId = typeof item.id === 'string'
|
||||
const hasWidget = typeof item.widget === 'string' && this.widgets[item.widget]
|
||||
const hasSettings = typeof item.settings === 'object'
|
||||
const hasChildren = Array.isArray(item.children)
|
||||
|
||||
if (!hasId || !hasWidget || !hasSettings || !hasChildren) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (let child of item.children) {
|
||||
if (!this.isNextValueItemValueValid(child)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
updateNextValueRecursiveIds(data) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach((value, key) => {
|
||||
data[key] = this.updateNextValueRecursiveIds(value)
|
||||
})
|
||||
} else {
|
||||
data.id = this.makeId()
|
||||
data.children = this.updateNextValueRecursiveIds(data.children)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
checkAndSaveNextValue() {
|
||||
this.$refs.codeEditor.classList.toggle('is-invalid', false)
|
||||
let hasError = false
|
||||
|
||||
try {
|
||||
let data = JSON.parse(this.nextValue)
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
hasError = true
|
||||
} else {
|
||||
for (let item of data) {
|
||||
if (!this.isNextValueItemValueValid(item)) {
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasError) {
|
||||
this.value = this.updateNextValueRecursiveIds(data)
|
||||
++this.blockKey
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
hasError = true
|
||||
}
|
||||
|
||||
return this.$refs.codeEditor.classList.toggle('is-invalid', hasError)
|
||||
codeUpdate(nextValue) {
|
||||
this.value = nextValue
|
||||
},
|
||||
removeBlock(key) {
|
||||
let newValue = []
|
||||
|
@ -259,22 +161,6 @@ export default {
|
|||
|
||||
return data
|
||||
},
|
||||
makeId() {
|
||||
let result = ''
|
||||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'
|
||||
const charactersLength = characters.length
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength))
|
||||
}
|
||||
|
||||
return `block-${result}`
|
||||
},
|
||||
},
|
||||
components: {
|
||||
BuilderBlockItem,
|
||||
BuilderBlockCreate,
|
||||
Draggable,
|
||||
},
|
||||
mounted() {
|
||||
const that = this
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm"
|
||||
v-on:click="open"
|
||||
>
|
||||
<i class="fas fa-code"></i>
|
||||
</button>
|
||||
<dialog ref="dialog" class="modal-dialog modal-dialog-large builder-code-editor">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Code editor</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
v-on:click="close"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
class="form-control"
|
||||
rows="10"
|
||||
ref="codeEditor"
|
||||
v-model="nextValue"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
v-on:click="close"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
v-on:click="checkAndSaveNextValue"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BuilderBlockCodeEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
widgets: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nextValue: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toJson(value) {
|
||||
return JSON.stringify(value, null, 2)
|
||||
},
|
||||
open() {
|
||||
this.nextValue = this.toJson(this.value)
|
||||
this.$refs.dialog.showModal()
|
||||
},
|
||||
close() {
|
||||
this.$refs.codeEditor.classList.toggle('is-invalid', false)
|
||||
this.$refs.dialog.close()
|
||||
},
|
||||
isNextValueItemValueValid(item) {
|
||||
const hasId = typeof item.id === 'string'
|
||||
const hasWidget = typeof item.widget === 'string' && this.widgets[item.widget]
|
||||
const hasSettings = typeof item.settings === 'object'
|
||||
const hasChildren = Array.isArray(item.children)
|
||||
|
||||
if (!hasId || !hasWidget || !hasSettings || !hasChildren) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (let child of item.children) {
|
||||
if (!this.isNextValueItemValueValid(child)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
updateNextValueRecursiveIds(data) {
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach((value, key) => {
|
||||
data[key] = this.updateNextValueRecursiveIds(value)
|
||||
})
|
||||
} else {
|
||||
data.id = this.makeId()
|
||||
data.children = this.updateNextValueRecursiveIds(data.children)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
checkAndSaveNextValue() {
|
||||
this.$refs.codeEditor.classList.toggle('is-invalid', false)
|
||||
let hasError = false
|
||||
|
||||
try {
|
||||
let data = JSON.parse(this.nextValue)
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
hasError = true
|
||||
} else {
|
||||
for (let item of data) {
|
||||
if (!this.isNextValueItemValueValid(item)) {
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasError) {
|
||||
this.$emit('update', this.updateNextValueRecursiveIds(data))
|
||||
this.close()
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
hasError = true
|
||||
}
|
||||
|
||||
return this.$refs.codeEditor.classList.toggle('is-invalid', hasError)
|
||||
},
|
||||
makeId() {
|
||||
let result = ''
|
||||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'
|
||||
const charactersLength = characters.length
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength))
|
||||
}
|
||||
|
||||
return `block-${result}`
|
||||
},
|
||||
},
|
||||
components: {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
created() {
|
||||
},
|
||||
updated() {
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -110,6 +110,7 @@
|
|||
</Draggable>
|
||||
|
||||
<div v-if="widget.isContainer" class="container">
|
||||
<div class="d-flex justify-content-between">
|
||||
<BuilderBlockCreate
|
||||
:container="item.children"
|
||||
:widgets="widgets"
|
||||
|
@ -117,17 +118,31 @@
|
|||
:allowedWidgets="widget.widgets"
|
||||
position="bottom"
|
||||
/>
|
||||
<BuilderBlockCodeEditor
|
||||
ref="dialog"
|
||||
:value="item.children"
|
||||
:widgets="widgets"
|
||||
@update="codeUpdate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BuilderBlockCreate from './BuilderBlockCreate'
|
||||
import BuilderBlockCodeEditor from './BuilderBlockCodeEditor'
|
||||
import BuilderBlockSetting from './BuilderBlockSetting'
|
||||
import Draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
name: 'BuilderBlockItem',
|
||||
components: {
|
||||
BuilderBlockCreate,
|
||||
BuilderBlockSetting,
|
||||
BuilderBlockCodeEditor,
|
||||
Draggable,
|
||||
},
|
||||
props: {
|
||||
widgets: {
|
||||
type: Object,
|
||||
|
@ -164,6 +179,9 @@ export default {
|
|||
removeMe() {
|
||||
this.$emit('remove-item')
|
||||
},
|
||||
codeUpdate(nextValue) {
|
||||
this.item.children = nextValue
|
||||
},
|
||||
removeBlock(key) {
|
||||
let children = []
|
||||
|
||||
|
@ -184,11 +202,6 @@ export default {
|
|||
++this.blockKey
|
||||
},
|
||||
},
|
||||
components: {
|
||||
BuilderBlockCreate,
|
||||
BuilderBlockSetting,
|
||||
Draggable,
|
||||
},
|
||||
mounted() {
|
||||
this.widget = this.widgets[this.item.widget]
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue