forked from platypush/platypush
[#341] Added UI for while
loops in procedure editor.
This commit is contained in:
parent
ab07fc0fa3
commit
dfbbea93fd
4 changed files with 141 additions and 39 deletions
|
@ -29,7 +29,7 @@
|
||||||
v-on="componentsData[index].on"
|
v-on="componentsData[index].on"
|
||||||
:collapsed="collapsedBlocks[index]"
|
:collapsed="collapsedBlocks[index]"
|
||||||
:dragging="isDragging"
|
:dragging="isDragging"
|
||||||
v-else-if="fors[index]" />
|
v-else-if="loops[index]" />
|
||||||
|
|
||||||
<BreakTile :active="isDragging"
|
<BreakTile :active="isDragging"
|
||||||
:readOnly="readOnly"
|
:readOnly="readOnly"
|
||||||
|
@ -86,8 +86,12 @@
|
||||||
<AddTile icon="fas fa-question" title="Add Else" @click="$emit('add-else')" />
|
<AddTile icon="fas fa-question" title="Add Else" @click="$emit('add-else')" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row item action add-for-container" v-if="visibleAddButtons.loop">
|
<div class="row item action add-for-container" v-if="visibleAddButtons.for">
|
||||||
<AddTile icon="fas fa-arrow-rotate-left" title="Add Loop" @click="addLoop" />
|
<AddTile icon="fas fa-arrow-rotate-left" title="Add For Loop" @click="addForLoop" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row item action add-while-container" v-if="visibleAddButtons.while">
|
||||||
|
<AddTile icon="fas fa-arrow-rotate-left" title="Add While Loop" @click="addWhileLoop" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row item action add-break-container" v-if="visibleAddButtons.break">
|
<div class="row item action add-break-container" v-if="visibleAddButtons.break">
|
||||||
|
@ -265,9 +269,15 @@ export default {
|
||||||
data.props.indent = this.indent + 1
|
data.props.indent = this.indent + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const loop = this.getFor(action)
|
const forLoop = this.getFor(action)
|
||||||
if (loop) {
|
if (forLoop) {
|
||||||
data.props.async = loop.async
|
data.props.async = forLoop.async
|
||||||
|
data.props.type = 'for'
|
||||||
|
}
|
||||||
|
|
||||||
|
const whileLoop = this.getWhile(action)
|
||||||
|
if (whileLoop) {
|
||||||
|
data.props.type = 'while'
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -338,6 +348,23 @@ export default {
|
||||||
}, {}) || {}
|
}, {}) || {}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
whiles() {
|
||||||
|
return this.newValue?.reduce?.((acc, action, index) => {
|
||||||
|
if (this.getWhile(action)) {
|
||||||
|
acc[index] = action
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, {}) || {}
|
||||||
|
},
|
||||||
|
|
||||||
|
loops() {
|
||||||
|
return [...Object.keys(this.fors), ...Object.keys(this.whiles)].reduce((acc, index) => {
|
||||||
|
acc[index] = this.newValue[index]
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
|
||||||
hasChanges() {
|
hasChanges() {
|
||||||
return this.newStringValue !== this.stringValue
|
return this.newStringValue !== this.stringValue
|
||||||
},
|
},
|
||||||
|
@ -389,14 +416,17 @@ export default {
|
||||||
|
|
||||||
showAddButtons() {
|
showAddButtons() {
|
||||||
return (
|
return (
|
||||||
this.newValue.length === 0 || !this.collapseAddButtons
|
(this.indent === 0 && this.newValue.length === 0) || !this.collapseAddButtons
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
showAddButtonsExpander() {
|
showAddButtonsExpander() {
|
||||||
return (
|
return (
|
||||||
!this.readOnly &&
|
!this.readOnly &&
|
||||||
this.newValue?.length > 0 &&
|
(
|
||||||
|
this.newValue?.length > 0 ||
|
||||||
|
this.indent > 0
|
||||||
|
) &&
|
||||||
Object.entries(this.visibleAddButtons).filter(
|
Object.entries(this.visibleAddButtons).filter(
|
||||||
([key, value]) => value && key != 'action'
|
([key, value]) => value && key != 'action'
|
||||||
).length > 1
|
).length > 1
|
||||||
|
@ -431,6 +461,7 @@ export default {
|
||||||
this.conditions[index] ||
|
this.conditions[index] ||
|
||||||
this.elses[index] ||
|
this.elses[index] ||
|
||||||
this.fors[index] ||
|
this.fors[index] ||
|
||||||
|
this.whiles[index] ||
|
||||||
this.isAction(action) ||
|
this.isAction(action) ||
|
||||||
this.isReturn(action) ||
|
this.isReturn(action) ||
|
||||||
this.isBreak(action) ||
|
this.isBreak(action) ||
|
||||||
|
@ -448,7 +479,8 @@ export default {
|
||||||
action: this.allowAddButtons,
|
action: this.allowAddButtons,
|
||||||
return: this.allowAddButtons,
|
return: this.allowAddButtons,
|
||||||
condition: this.allowAddButtons,
|
condition: this.allowAddButtons,
|
||||||
loop: this.allowAddButtons,
|
for: this.allowAddButtons,
|
||||||
|
while: this.allowAddButtons,
|
||||||
else: (
|
else: (
|
||||||
this.allowAddButtons &&
|
this.allowAddButtons &&
|
||||||
this.parent &&
|
this.parent &&
|
||||||
|
@ -663,11 +695,16 @@ export default {
|
||||||
this.selectLastExprEditor()
|
this.selectLastExprEditor()
|
||||||
},
|
},
|
||||||
|
|
||||||
addLoop() {
|
addForLoop() {
|
||||||
this.newValue.push({ 'for _ in ${range(10)}': [] })
|
this.newValue.push({ 'for _ in ${range(10)}': [] })
|
||||||
this.selectLastExprEditor()
|
this.selectLastExprEditor()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addWhileLoop() {
|
||||||
|
this.newValue.push({ 'while ${True}': [] })
|
||||||
|
this.selectLastExprEditor()
|
||||||
|
},
|
||||||
|
|
||||||
addBreak() {
|
addBreak() {
|
||||||
this.newValue.push('break')
|
this.newValue.push('break')
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #after>
|
<template #after>
|
||||||
<EndBlockTile value="end for"
|
<EndBlockTile :value="`end ${type}`"
|
||||||
icon="fas fa-arrow-rotate-right"
|
icon="fas fa-arrow-rotate-right"
|
||||||
:active="active"
|
:active="active"
|
||||||
:spacer-bottom="spacerBottom"
|
:spacer-bottom="spacerBottom"
|
||||||
|
@ -64,6 +64,11 @@ export default {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
active: {
|
active: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -117,8 +122,36 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
changeHandler() {
|
||||||
|
if (this.type === 'for') {
|
||||||
|
return this.onForChange
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type === 'while') {
|
||||||
|
return this.onWhileChange
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {}
|
||||||
|
},
|
||||||
|
|
||||||
|
isDragging() {
|
||||||
|
return this.dragging_ || this.dragging
|
||||||
|
},
|
||||||
|
|
||||||
|
key() {
|
||||||
|
return this.getKey(this.value)
|
||||||
|
},
|
||||||
|
|
||||||
loop() {
|
loop() {
|
||||||
|
if (this.type === 'for') {
|
||||||
return this.getFor(this.key)
|
return this.getFor(this.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type === 'while') {
|
||||||
|
return {condition: this.getWhile(this.key)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
},
|
},
|
||||||
|
|
||||||
loopTileConf() {
|
loopTileConf() {
|
||||||
|
@ -129,10 +162,11 @@ export default {
|
||||||
readOnly: this.readOnly,
|
readOnly: this.readOnly,
|
||||||
spacerBottom: this.spacerBottom,
|
spacerBottom: this.spacerBottom,
|
||||||
spacerTop: this.spacerTop,
|
spacerTop: this.spacerTop,
|
||||||
|
type: this.type,
|
||||||
},
|
},
|
||||||
|
|
||||||
on: {
|
on: {
|
||||||
change: this.onLoopChange,
|
change: this.changeHandler,
|
||||||
delete: (event) => this.$emit('delete', event),
|
delete: (event) => this.$emit('delete', event),
|
||||||
drag: this.onDragStart,
|
drag: this.onDragStart,
|
||||||
dragend: this.onDragEnd,
|
dragend: this.onDragEnd,
|
||||||
|
@ -144,14 +178,6 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
isDragging() {
|
|
||||||
return this.dragging_ || this.dragging
|
|
||||||
},
|
|
||||||
|
|
||||||
key() {
|
|
||||||
return this.getKey(this.value)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -163,7 +189,7 @@ export default {
|
||||||
this.$emit('input', { [this.key]: value })
|
this.$emit('input', { [this.key]: value })
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoopChange(loop) {
|
onForChange(loop) {
|
||||||
const iterable = loop?.iterable?.trim()
|
const iterable = loop?.iterable?.trim()
|
||||||
const iterator = loop?.iterator?.trim()
|
const iterator = loop?.iterator?.trim()
|
||||||
const async_ = loop?.async || false
|
const async_ = loop?.async || false
|
||||||
|
@ -177,6 +203,16 @@ export default {
|
||||||
this.$emit('input', { [loop]: this.value[this.key] })
|
this.$emit('input', { [loop]: this.value[this.key] })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onWhileChange(condition) {
|
||||||
|
condition = condition?.trim()
|
||||||
|
if (!this.key || this.readOnly || !condition?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const loop = `while \${${condition}}`
|
||||||
|
this.$emit('input', { [loop]: this.value[this.key] })
|
||||||
|
},
|
||||||
|
|
||||||
onDragStart(event) {
|
onDragStart(event) {
|
||||||
if (this.readOnly) {
|
if (this.readOnly) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,12 +17,17 @@
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fas fa-arrow-rotate-left" />
|
<i class="fas fa-arrow-rotate-left" />
|
||||||
</span>
|
</span>
|
||||||
<span class="name">
|
<span class="name" v-if="type === 'for'">
|
||||||
<span class="keyword">for<span v-if="async">k</span></span>
|
<span class="keyword">for<span v-if="async">k</span></span>
|
||||||
<span class="code" v-text="iterator" />
|
<span class="code" v-text="iterator" />
|
||||||
<span class="keyword"> in </span> [
|
<span class="keyword"> in </span> [
|
||||||
<span class="code" v-text="iterable" /> ]
|
<span class="code" v-text="iterable" /> ]
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span class="name" v-else-if="type === 'while'">
|
||||||
|
<span class="keyword">while</span> [
|
||||||
|
<span class="code" v-text="condition" /> ]
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Tile>
|
</Tile>
|
||||||
|
|
||||||
|
@ -33,17 +38,23 @@
|
||||||
<LoopEditor :iterator="iterator"
|
<LoopEditor :iterator="iterator"
|
||||||
:iterable="iterable"
|
:iterable="iterable"
|
||||||
:async="async"
|
:async="async"
|
||||||
ref="loopEditor"
|
|
||||||
@change="onLoopChange"
|
@change="onLoopChange"
|
||||||
v-if="showLoopEditor">
|
v-if="showLoopEditor && type === 'for'">
|
||||||
Loop
|
Loop
|
||||||
</LoopEditor>
|
</LoopEditor>
|
||||||
|
|
||||||
|
<ExpressionEditor :value="condition"
|
||||||
|
@input.prevent.stop="onConditionChange"
|
||||||
|
v-else-if="showLoopEditor && type === 'while'">
|
||||||
|
Loop Condition
|
||||||
|
</ExpressionEditor>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ExpressionEditor from "./ExpressionEditor"
|
||||||
import ListItem from "./ListItem"
|
import ListItem from "./ListItem"
|
||||||
import LoopEditor from "./LoopEditor"
|
import LoopEditor from "./LoopEditor"
|
||||||
import Modal from "@/components/Modal"
|
import Modal from "@/components/Modal"
|
||||||
|
@ -64,6 +75,7 @@ export default {
|
||||||
],
|
],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
ExpressionEditor,
|
||||||
LoopEditor,
|
LoopEditor,
|
||||||
ListItem,
|
ListItem,
|
||||||
Modal,
|
Modal,
|
||||||
|
@ -71,16 +83,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
iterator: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
iterable: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
active: {
|
active: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -91,9 +93,16 @@ export default {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
isElse: {
|
condition: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: false,
|
},
|
||||||
|
|
||||||
|
iterator: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
iterable: {
|
||||||
|
type: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
readOnly: {
|
readOnly: {
|
||||||
|
@ -110,6 +119,11 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -154,6 +168,21 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
onConditionChange(event) {
|
||||||
|
this.showLoopEditor = false
|
||||||
|
if (this.readOnly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const condition = event.target.value?.trim()
|
||||||
|
if (!condition?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event.target.value = condition
|
||||||
|
this.$emit('change', condition)
|
||||||
|
},
|
||||||
|
|
||||||
onLoopChange(event) {
|
onLoopChange(event) {
|
||||||
this.showLoopEditor = false
|
this.showLoopEditor = false
|
||||||
if (this.readOnly) {
|
if (this.readOnly) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
isActionsBlock(value) {
|
isActionsBlock(value) {
|
||||||
return this.getCondition(value) || this.isElse(value) || this.getFor(value)
|
return this.getCondition(value) || this.isElse(value) || this.getFor(value) || this.getWhile(value)
|
||||||
},
|
},
|
||||||
|
|
||||||
isBreak(value) {
|
isBreak(value) {
|
||||||
|
|
Loading…
Reference in a new issue