Skip to content
Merged
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
17 changes: 16 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<b-btn variant="secondary" size="sm" v-b-modal="'uploadmodal'" class="mr-2" :title="$t('Load Screen')">
<i class="fas fa-upload mr-1"/>
</b-btn>
<button v-b-modal.preview-config type="button" class="btn btn-secondary btn-sm ml-1" :title="$t('Save Screen')"><i class="fas fa-save"/></button>
<button v-b-modal.preview-config type="button" @click="saveToLocalStorage()" class="btn btn-secondary btn-sm ml-1" :title="$t('Save Screen')"><i class="fas fa-save"/></button>
</b-col>
<b-modal
ref="uploadmodal"
Expand Down Expand Up @@ -320,8 +320,20 @@ export default {
config.builderBinding
);
});

this.loadFromLocalStorage();
},
methods: {
loadFromLocalStorage() {
const savedConfig = localStorage.getItem('savedConfig');
if (savedConfig) {
let config = JSON.parse(savedConfig);
this.$refs.builder.config = config;
}
},
saveToLocalStorage() {
localStorage.setItem('savedConfig', JSON.stringify(this.config));
},
editorDidMount(editor) {
editor.getAction('editor.action.formatDocument').run();
},
Expand All @@ -331,6 +343,9 @@ export default {
items.forEach(item => {
if (item.container) {
item.items.forEach(containerItems => {
if (!Array.isArray(containerItems)) {
containerItems = [containerItems];
}
validationErrors.push(...this.getValidationErrorsForItems(containerItems, page));
});
}
Expand Down
194 changes: 194 additions & 0 deletions src/components/editor/loop.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<template>
<div class="column-draggable">
<draggable
style="min-height: 80px;"
v-model="items"
:options="{group: {name: 'controls'}}"
>
<div class="control-item"
:class="{selected: selected === element, hasError: hasError(element)}"
v-for="(element,index) in items"
:key="index"
@click.stop="inspect(element)"
>
<div v-if="element.container" @click.stop="inspect(element)">
<div class="m-2 card border-0">
<div
v-if="selected === element"
class="card-header form-element-header d-flex align-items-center border rounded"
>
<i class="fas fa-arrows-alt-v mr-1 text-muted"/>
<i v-if="element.config.icon" :class="element.config.icon" class="mr-2 ml-1"/>
{{ element.config.name || $t('Variable Name') }}
<button
class="btn btn-sm btn-danger ml-auto"
@click="deleteItem(index)"
>
<i class="far fa-trash-alt text-light"/>
</button>
</div>

<component :class="elementCssClass(element)"
:validationErrors="validationErrors"
class="mb-3 mr-3 ml-3"
:selected="selected"
@inspect="inspect"
@update-state="$emit('update-state')"
v-model="element.items"
:config="element.config"
:is="element['editor-component']"
/>
</div>
</div>

<div v-else :id="element.config.name ? element.config.name : undefined">
<div class="m-2" :class="{ 'card' : selected === element }">
<div
v-if="selected === element"
class="card-header form-element-header d-flex align-items-center"
>
<i class="fas fa-arrows-alt-v mr-1 text-muted"/>
<i v-if="element.config.icon" :class="element.config.icon" class="mr-2 ml-1"/>
{{ element.config.name || $t('Variable Name') }}
<button
class="btn btn-sm btn-danger ml-auto"
@click="deleteItem(index)"
>
<i class="far fa-trash-alt text-light"/>
</button>
</div>

<component
class="p-3"
:class="[elementCssClass(element), { 'prevent-interaction': !element.config.interactive }]"
:tabindex="element.config.interactive ? 0 : -1"
v-bind="element.config"
:config="element.config"
@input="element.config.interactive ? element.config.content = $event : null"
:is="element['editor-component']"
/>
</div>
</div>
</div>
</draggable>
</div>
</template>

<script>
import draggable from 'vuedraggable';
import { HasColorProperty } from '@/mixins';
import * as renderer from '@/components/renderer';
import * as editor from '@/components/editor';
import {
FormInput,
FormSelectList,
FormTextArea,
FormCheckbox,
FormDatePicker,
FormHtmlEditor,
FormHtmlViewer,
} from '@processmaker/vue-form-elements';

const defaultColumnWidth = 1;

export default {
name: 'Loop',
mixins: [HasColorProperty],
props: ['value', 'name', 'config', 'selected', 'validationErrors'],
components: {
draggable,
FormInput,
FormSelectList,
FormCheckbox,
FormTextArea,
FormDatePicker,
FormHtmlEditor,
FormHtmlViewer,
...renderer,
...editor,
},
data() {
return {
items: [],
};
},
watch: {
value: {
handler() {
this.items = this.value;
},
immediate: true,
},
items() {
this.$emit('input', this.items);
},
},
methods: {
hasError(element) {
if (!this.validationErrors) { return false; }
return this.validationErrors.some(({ item }) => item === element);
},
inspect(element) {
this.$emit('inspect', element);
},
deleteItem(index) {
// Remove the item from the array in currentPage
this.items.splice(index, 1);
this.$emit('update-state');
},
},
};
</script>

<style lang="scss" scoped>
.hasError {
border: 1px solid red;
border-radius: 0.25rem;

.form-element-header {
border-bottom: 1px solid red;
color: red;
}
}

.column-draggable {
border: 1px dashed #000;
min-height: 80px;
content: "Drag Controls";
}

.selected .column-draggable {
border: none;
}

.control-item {
position: relative;

.delete {
position: absolute;
top: 0px;
right: 0px;
display: none;
}

&.selected,
&:hover {
.mask {
border: 1px solid red;
}

.delete {
display: inline-block;
}
}

.mask {
position: absolute;
top: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0);
width: 100%;
height: 100%;
}
}
</style>
115 changes: 115 additions & 0 deletions src/components/renderer/form-loop.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<template>
<div class="form-group">
<div v-for="loopIndex in times" :key="loopIndex">
<vue-form-renderer
@submit="submit"
:data="getMatrixValue(loopIndex)"
@update="setMatrixValue(loopIndex, $event)"
:config="rendererConfig"
:computed="null"
:custom-css="null"
:watchers="null"
/>
</div>
</div>
</template>

<script>
import Mustache from 'mustache';

export default {
name: 'FormLoop',
mixins: [],
props: ['value', 'name', 'config', 'transientData'],
data() {
return {
matrix: [],
items: [],
};
},
computed: {
rendererConfig() {
let items = this.items;
return [{
name: 'LoopItem',
items: items,
}];
},
times() {
if (!this.config) {
return [];
}

let times = this.config.times;

try {
times = Mustache.render(times, this.transientData);
} catch (error) { }

times = parseInt(times);

if (Number.isNaN(times)) {
return []
}

if (times > 100) {
times = 100;
}

return [...Array(times).keys()];
}
},
watch: {
transientData: {
handler() {
if (this.transientData && this.transientData[this.name]) {
this.matrix = this.transientData[this.name];
} else {
this.matrix = [];
}
this.setupMatrix();
},
immediate: true,
},
value: {
handler() {
this.items = this.value;
},
immediate: true,
},
matrix: {
handler() {
this.$parent.model[this.name] = this.matrix;
},
deep: true,
},
times() {
this.setupMatrix();
}
},
methods: {
setMatrixValue(i, v) {
this.$set(this.matrix, i, v);
},
getMatrixValue(i) {
let val = this.matrix[i];
if (!val) {
val = '';
}
return val;
},
setupMatrix() {
for (const i of this.times) {
if (typeof this.matrix[i] === 'undefined') {
this.$set(this.matrix, i, {});
} else {
}
}
},
submit() {
// Just bubble up
this.$emit('submit');
},
},
};
</script>
2 changes: 2 additions & 0 deletions src/components/vue-form-builder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ import undoRedoModule from '../undoRedoModule';
import accordions from './accordions';
import { keyNameProperty } from '../form-control-common-properties';
import VariableNameGenerator from '@/components/VariableNameGenerator';
import Loop from './editor/loop';

Vue.use(BootstrapVue);

Expand Down Expand Up @@ -330,6 +331,7 @@ export default {
mixins: [HasColorProperty],
components: {
draggable,
Loop,
FormInput,
FormSelectList,
FormCheckbox,
Expand Down
2 changes: 2 additions & 0 deletions src/components/vue-form-renderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import * as editor from './editor';
import * as renderer from './renderer';
import * as inspector from './inspector';
import FormMultiColumn from '@/components/renderer/form-multi-column';
import FormLoop from '@/components/renderer/form-loop';
import FormMaskedInput from '@/components/renderer/form-masked-input';
import CustomCSS from './custom-css';
import {
Expand Down Expand Up @@ -99,6 +100,7 @@ export default {
FormHtmlViewer,
FormMultiColumn,
CustomCSS,
FormLoop,
...editor,
...inspector,
...renderer,
Expand Down
Loading