Commit afc8d0df authored by 张晨辰's avatar 张晨辰

feat: delete scripts & events

parent c67c09a2
<template>
<div :style="customStyle" class="zero-custom-cmp zero-custom-node" v-html="selfText"></div>
<div :style="customStyle" class="zero-custom-cmp zero-custom-node">
<p class="custom-node-html" v-if="selfText">{{selfText}}</p>
<slot></slot>
</div>
</template>
<style>
<style lang="scss">
.zero-custom-cmp{
position: absolute;
box-sizing: border-box;
.custom-node-html{
position: absolute;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
}
</style>
......
......@@ -3,12 +3,12 @@
*/
import Vue from "vue";
import JSZip from "jszip";
import {projectApi} from "../../api";
import { projectApi } from "../../api";
import path from "path";
import generateUUID from "uuid/v4";
import {getCmpProps, flattenViews, getCmpByUUID} from '../../utils/common';
import {saveAs} from "../../utils";
import {template} from "../../template";
import { getCmpProps, flattenViews, getCmpByUUID } from '../../utils/common';
import { saveAs } from "../../utils";
import { template } from "../../template";
const defaultOptions = {
pageTitle: 'no title',
......@@ -52,14 +52,14 @@ export const projectStore = {
state.dirty = dirty;
},
updateProject(state, project) {
const {id, name, creator, data} = project;
const { id, name, creator, data } = project;
state.id = id;
state.name = name;
state.creator = creator;
const localData = state.data;
if (data) {
const {views, assets, dataMapping, processes, options,} = JSON.parse(data);
const { views, assets, dataMapping, processes, options, } = JSON.parse(data);
Vue.set(localData, 'options', options || getDefaultOptions());
Vue.set(localData, 'views', views || []);
......@@ -117,8 +117,17 @@ export const projectStore = {
state.stackIndex = 0; // 开始编辑的时候,重置操作栈的下标
let newView = _.merge(oldView, view);
// 如果是scripts和events的修改,直接覆盖 不merge
if (view.scripts) {
newView.scripts = _.cloneDeep(view.scripts)
}
if (view.events) {
newView.events = _.cloneDeep(view.events)
}
// 在操作栈中插入最新值
state.operateStack.unshift(_.cloneDeep(_.assign({uuid: newView.uuid}, view)));
state.operateStack.unshift(_.cloneDeep(_.assign({ uuid: newView.uuid }, view)));
// 操作栈最大200
if (state.operateStack.length > 200) {
state.operateStack.pop();
......@@ -126,35 +135,35 @@ export const projectStore = {
// 将数据更新至当前选中的节点上
_.forIn(view, (value, key) => {
if (key === 'properties') {
// if (key === 'properties') {
// horizonCenter和left\right
// verticalCenter和top\bottom
// 互斥,只要修改了一项,则把互斥项置空
if (value.horizonCenter) {
delete newView.properties.left;
delete newView.properties.right;
}
if (value.verticalCenter) {
delete newView.properties.top;
delete newView.properties.bottom;
}
if (value.left || value.right) {
delete newView.properties.horizonCenter;
}
if (value.top || value.bottom) {
delete newView.properties.verticalCenter;
}
// if (value.horizonCenter) {
// delete newView.properties.left;
// delete newView.properties.right;
// }
// if (value.verticalCenter) {
// delete newView.properties.top;
// delete newView.properties.bottom;
// }
// if (value.left || value.right) {
// delete newView.properties.horizonCenter;
// }
// if (value.top || value.bottom) {
// delete newView.properties.verticalCenter;
// }
// 如果left\right top\bottom组合同时存在
// 则根据数值,计算width height
if (newView.properties.left && newView.properties.right) {
}
if (newView.properties.top && newView.properties.bottom) {
// if (newView.properties.left && newView.properties.right) {
// //
// }
// if (newView.properties.top && newView.properties.bottom) {
}
// }
}
// }
Vue.set(state.activeComponent, key, newView[key]);
})
......@@ -223,7 +232,7 @@ export const projectStore = {
modifyProject(state) {
},
addNode(state, {node, name, type}) {
addNode(state, { node, name, type }) {
const child = {
name,
type,
......@@ -243,7 +252,7 @@ export const projectStore = {
importView(state, view) {
state.data.views.push(view);
},
deleteNode(state, {node, parentNode}) {
deleteNode(state, { node, parentNode }) {
const parentChildren = parentNode.children || parentNode;
const index = parentChildren.indexOf(node);
parentChildren.splice(index, 1);
......@@ -251,7 +260,7 @@ export const projectStore = {
importAssets(state, assets) {
state.data.assets.push(...assets);
},
addAsset(state, {url, file}) {
addAsset(state, { url, file }) {
const ext = path.extname(file.name);
state.data.assets.push({
name: path.basename(file.name, ext),
......@@ -261,7 +270,7 @@ export const projectStore = {
})
},
deleteAsset(state, uuid) {
const {assets} = state.data;
const { assets } = state.data;
for (let i = 0, li = assets.length; i < li; i++) {
const asset = state.data.assets[i];
if (asset.uuid === uuid) {
......@@ -295,7 +304,7 @@ export const projectStore = {
},
getters: {
project(state) {
const {id, name, creator, data} = state;
const { id, name, creator, data } = state;
return {
id, name, creator,
data: JSON.stringify(data),
......@@ -343,19 +352,35 @@ export const projectStore = {
// console.log('componentList', result);
return result;
},
/**
* 返回Array格式的views
*/
views: state => {
// 如果有选中的节点,则展示对应的视图组
// 否则展示第一个视图组
let _view = [];
if (state.activeViews) {
_view = state.data.views.filter(v => v.uuid === state.activeViews)
} else {
_view = state.data.views.length ? [].concat(state.data.views[0]) : [];
}
console.log('_view', _view);
return _view;
}
},
actions: {
saveToLocal({getters, commit}) {
const {project} = getters;
saveToLocal({ getters, commit }) {
const { project } = getters;
localStorage.setItem('project-' + project.id, JSON.stringify(project));
commit('setDirty', true);
},
localVersionExist({commit}, projectID) {
localVersionExist({ commit }, projectID) {
let json = localStorage.getItem('project-' + projectID);
return !!json;
},
loadFromLocal({commit}, projectID) {
loadFromLocal({ commit }, projectID) {
let json = localStorage.getItem('project-' + projectID);
if (json) {
const project = JSON.parse(json);
......@@ -363,11 +388,11 @@ export const projectStore = {
commit('setDirty', true);
}
},
deleteLocalVersion({state, commit}, projectID) {
deleteLocalVersion({ state, commit }, projectID) {
localStorage.removeItem('project-' + projectID);
commit('setDirty', false);
},
async loadFromRemote({commit, dispatch}, projectID) {
async loadFromRemote({ commit, dispatch }, projectID) {
const project = await projectApi.fetchOne(projectID);
if (project) {
dispatch('deleteLocalVersion', projectID);
......@@ -376,11 +401,11 @@ export const projectStore = {
throw new Error('Project does not exist')
}
},
async saveToRemote({state, dispatch, getters}) {
async saveToRemote({ state, dispatch, getters }) {
await projectApi.saveOne(getters.project);
dispatch('deleteLocalVersion', state.id);
},
async updateProject({commit}, projectID) {
async updateProject({ commit }, projectID) {
const project = await projectApi.getData(projectID);
commit('updateProject', project);
},
......@@ -409,14 +434,13 @@ export const projectStore = {
/**
* 修改属性
*/
modifyProperties({commit, state}, props) {
modifyProperties({ commit, state, getters }, props) {
// debugger;
// 如果当前修改的是“来源”属性,节点又没有高度宽度,则取图片的高度宽度
let _source = Object.keys(props).indexOf('source') > -1;
if (_source) {
if (props.source) {
let _props = state.activeComponent.properties;
if (!_props.width || !_props.height) {
let _url = props['source']; //_source.value;
let _url = props.source; //_source.value;
if (_url.indexOf('asset://') === 0) {
let uuid = _url.split('//')[1];
let asset = state.data.assets.find(a => a.uuid === uuid);
......@@ -435,6 +459,16 @@ export const projectStore = {
}
}
let finalProps = _.merge({}, _.cloneDeep(state.activeComponent.properties), props);
// 属性冲突&属性关联计算
// if (finalProps.left && finalProps.right) {
// left right 同时存在,计算其宽度
// }
commit('modifyActiveView', {
properties: props
})
......@@ -444,13 +478,13 @@ export const projectStore = {
* @param {*} param0
* @param {*} props
*/
modifyCopyProperties({commit}, props) {
modifyCopyProperties({ commit }, props) {
commit('modifyCopyProperties', props)
},
/**
* 修改当前选中的节点
*/
modifyActiveView({commit}, view) {
modifyActiveView({ commit }, view) {
commit('modifyActiveView', view)
},
......@@ -459,7 +493,7 @@ export const projectStore = {
* @param {*} param0
* @param {*} data
*/
addNodeScript({commit, state}, script) {
addNodeScript({ commit, state }, script) {
let _scripts = _.cloneDeep(state.activeComponent.scripts || []);
_scripts.push({
script: script,
......@@ -470,15 +504,15 @@ export const projectStore = {
})
},
exportView({state}, view) {
exportView({ state }, view) {
let zip = new JSZip();
zip.file('view.json', JSON.stringify(view));
zip.generateAsync({type: "blob"}).then(function (content) {
zip.generateAsync({ type: "blob" }).then(function (content) {
saveAs(content, `view-${view.name}.zrv`);
});
},
async packProject({state}) {
async packProject({ state }) {
const result = await projectApi.pack(state.id);
console.log(result)
return result;
......
......@@ -5,6 +5,11 @@
display: flex;
flex-direction: column-reverse;
&.pane-playground .content{
display: block;
width: 100%;
}
&:focus {
outline: none;
......@@ -28,10 +33,6 @@
flex: 1;
border-radius: 2px;
position: relative;
&.background{
display: block;
width: 100%;
}
}
.title-bar {
......
......@@ -26,6 +26,8 @@ export const componentsMap = [
// 属性的计算方法
const propsComputeRules = {
x: 'add',
y: 'add',
left: 'add',
top: 'add',
rotation: 'add',
......@@ -47,8 +49,8 @@ function invalidAttr(key, value) {
// 属性简称 对照表
const attrShortMapper = {
// x: 'left',
// y: 'top',
x: 'left',
y: 'top',
align: 'text-align',
size: 'font-size',
alpha: 'opacity',
......@@ -60,10 +62,12 @@ const attrShortMapper = {
// 编辑时想拖拽组件需要生成的css属性
// 只需要位置,不需要来源透明度等等
const operatProps = ['left', 'top','right', 'bottom', 'width', 'height', 'rotation'];
const operatProps = ['x', 'y', 'left', 'top', 'right', 'bottom', 'width', 'height', 'rotation'];
// 属性单位 对照表, 如果是数值的时候需要添加单位
const attrUnitMapper = {
x: 'px',
y: 'px',
left: 'px',
top: 'px',
right: 'px',
......@@ -139,22 +143,29 @@ export const flattenViews = function (views) {
* @param {*} props
* @param {*} parent
*/
function inheritProps(props, parent) {
function inheritProps(props, parent, onlyOpera) {
_.forIn(parent, (value, key) => {
let _pValue = parent[key];
if (_pValue === null || _pValue === undefined) {
return ;
return;
}
let rule = propsComputeRules[key];
// 加法
if (rule === 'add') {
if (props[key] === null || props[key] === undefined) {
props[key] = 0;
}
props[key] += _pValue;
}
// 乘法
if (rule === 'multi') {
if (props[key] === null || props[key] === undefined) {
props[key] = 1;
}
props[key] *= _pValue;
}
// 可见,特殊处理
// 节点和父节点的visible只要有一个是false,值就是false,否则为true
if (rule === 'visible') {
props[key] = !props[key] || !_pValue ? false : true;
}
......@@ -245,7 +256,7 @@ export const styles = {
if (propsMatrix.length) {
propsMatrix.forEach(prop => {
// 继承每个父节点的属性
inheritProps(cmpSelfProps, prop);
inheritProps(cmpSelfProps, prop, onlyOpera);
});
}
......
......@@ -3,26 +3,36 @@
export default {
node: {
groupName: '基础',
left: {
title: '左边距',
x: {
title: 'x坐标',
type: 'inputNumber',
value: undefined,
},
right: {
title: '右边距',
type: 'inputNumber',
value: undefined,
},
top: {
title: '上边距',
type: 'inputNumber',
value: undefined,
value: 0,
},
bottom: {
title: '下边距',
y: {
title: 'y坐标',
type: 'inputNumber',
value: undefined,
value: 0,
},
// left: {
// title: '左边距',
// type: 'inputNumber',
// value: undefined,
// },
// right: {
// title: '右边距',
// type: 'inputNumber',
// value: undefined,
// },
// top: {
// title: '上边距',
// type: 'inputNumber',
// value: undefined,
// },
// bottom: {
// title: '下边距',
// type: 'inputNumber',
// value: undefined,
// },
width: {
title: '宽度',
type: 'inputNumber',
......@@ -33,18 +43,18 @@ export default {
type: 'inputNumber',
value: 1
},
horizonCenter: {
title: '水平偏移',
type: 'inputNumber',
value: undefined,
desc: '相对于父元素中心点的水平偏移,0为正中心'
},
verticalCenter: {
title: '垂直偏移',
type: 'inputNumber',
value: undefined,
desc: '相对于父元素中心点的垂直偏移,0为正中心'
},
// horizonCenter: {
// title: '水平偏移',
// type: 'inputNumber',
// value: undefined,
// desc: '相对于父元素中心点的水平偏移,0为正中心'
// },
// verticalCenter: {
// title: '垂直偏移',
// type: 'inputNumber',
// value: undefined,
// desc: '相对于父元素中心点的垂直偏移,0为正中心'
// },
rotation: {
title: '旋转',
type: 'inputNumber',
......
......@@ -13,6 +13,8 @@
{{$t('Edit Behavior')}}
<i v-if="evn.behaviors && evn.behaviors.length" class="el-icon-check el-icon--right"></i>
</el-button>
<el-button icon="el-icon-delete" size="mini" v-if="evn.behaviors && evn.behaviors.length" @click="deleteBehavior(key)">
</el-button>
</div>
</el-form-item>
</div>
......@@ -81,8 +83,10 @@ export default {
once: v,
behaviors: _event.behaviors
};
let events = this.activeComponent.events;
this.$store.dispatch('modifyActiveView', {
events: event
events: _.merge({}, events, event)
});
}
},
......@@ -90,15 +94,28 @@ export default {
* 行为发生变化,同步数据
*/
handleBehaviorsChange(v) {
if (this.currentEvent/* && v && v.length*/) {
if (this.currentEvent /* && v && v.length*/) {
let event = {};
let currentEvent = this.eventsObj[this.currentEvent];
event[this.currentEvent] = Object.assign(currentEvent/*, { behaviors: v }*/);
event[this.currentEvent] = Object.assign(currentEvent /*, { behaviors: v }*/);
let events = this.activeComponent.events;
this.$store.dispatch('modifyActiveView', {
events: event
events: _.merge({}, events, event)
});
this.updateEventsObj();
}
},
/**
* 删除行为
*/
deleteBehavior(key) {
let _events = this.activeComponent.events || {};
delete _events[key];
this.$store.dispatch('modifyActiveView', {
events: _events
});
this.updateEventsObj();
}
},
watch: {
......
......@@ -35,6 +35,9 @@
<dynamic-component :component-value="getScriptValue(p, key, index)" :component-props="getScriptProps(p, index)" :component-type="getScriptType(p, index)" @onChange="v => handleScriptChange(index, key, v)"></dynamic-component>
</el-form-item>
</template>
<el-form-item label="">
<el-button @click="deleteNodeScript(index)">删除</el-button>
</el-form-item>
</el-collapse-item>
</template>
</el-collapse>
......@@ -54,9 +57,6 @@
</el-collapse>
</el-form>
</el-scrollbar>
<!-- <div class="script-config-dialog" v-show="scriptDialog">
<el-tree :data="scripts" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div> -->
</div>
</template>
......@@ -167,9 +167,9 @@ export default {
return getCmpProps(this.activeComponent.type);
},
scripts: function() {
console.log('scripts', this.$store.state.env.scripts);
return this.$store.state.env.scripts;
return _.filter(this.$store.state.env.scripts, s => {
return s !== null && s !== undefined;
});
}
},
watch: {
......@@ -243,7 +243,7 @@ export default {
*/
getPropValue(item, key) {
let _properties = this.activeComponentCopy.properties;
return (_properties[key] === undefined || _properties[key] === null) ? item.value : _properties[key];
return _properties[key] === undefined || _properties[key] === null ? item.value : _properties[key];
},
getScriptValue(item, key, index) {
let _script = this.activeComponent.scripts[index];
......@@ -287,6 +287,19 @@ export default {
getScriptOptions(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.props : {};
},
/**
* 删除节点脚本
*/
deleteNodeScript(index) {
let _scripts = _.cloneDeep(this.activeComponent.scripts);
_.remove(_scripts, (s, sindex) => {
return sindex === index;
});
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
});
}
}
};
......@@ -302,7 +315,7 @@ export default {
.el-divider__text {
background-color: #e9e9e9;
}
.zero-inspector-props-group{
.zero-inspector-props-group {
width: 100%;
max-height: 600px;
overflow-x: hidden;
......
<template>
<pane icon="el-icon-s-open" :title="$t('panes.Playground')">
<pane icon="el-icon-s-open" class="pane-playground" :title="$t('panes.Playground')">
<div class="zero-playground-body-center">
<div class="zero-playground-draw-panel">
<draw-panel></draw-panel>
......
......@@ -8,6 +8,7 @@
>
<wrap :component-data="item"/>
</div>
<!-- <views-tree :views="views"></views-tree> -->
<template v-if="!!this.activeComponentId">
<vue-draggable-resizable
:prevent-deactivation="true"
......@@ -33,12 +34,13 @@
<script>
import { mapState, mapGetters } from 'vuex';
import wrap from './wrap';
import viewsTree from './viewsTree';
import { styles } from '../../../utils/common';
import properties from '../../../utils/properties';
import VueDraggableResizable from 'vue-draggable-resizable';
export default {
components: { wrap, VueDraggableResizable },
components: { wrap, VueDraggableResizable, viewsTree },
methods: {
handleDeactivated() {
// this.$store.dispatch('changeEditaleStatus', false);
......@@ -51,8 +53,8 @@ export default {
if (_prop.x !== x || _prop.y !== y || _prop.width !== w || _prop.height !== h) {
this.$store.dispatch('modifyCopyProperties', {
left: x,
top: y,
x: x,
y: y,
width: w,
height: h
});
......@@ -68,8 +70,8 @@ export default {
if (_prop.x !== x || _prop.y !== y) {
this.$store.dispatch('modifyCopyProperties', {
left: x,
top: y
x: x,
y: y
});
// console.log('handleDragging', x, y);
}
......@@ -80,10 +82,10 @@ export default {
}
let _prop = this.activeComponent.properties;
if (_prop.left !== x || _prop.top !== y || _prop.width !== w || _prop.height !== h) {
if (_prop.x !== x || _prop.y !== y || _prop.width !== w || _prop.height !== h) {
this.$store.dispatch('modifyProperties', {
left: x,
top: y,
x: x,
y: y,
width: w,
height: h
});
......@@ -95,17 +97,17 @@ export default {
}
let _prop = this.activeComponent.properties;
if (_prop.left !== x || _prop.top !== y) {
if (_prop.x !== x || _prop.y !== y) {
this.$store.dispatch('modifyProperties', {
left: x,
top: y
x: x,
y: y
});
}
}
},
computed: {
...mapState(['project']),
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList', 'activeComponentId']),
...mapGetters(['activeComponent', 'activeComponentCopy', 'views', 'componentList', 'activeComponentId']),
active() {
return !!this.activeComponentId;
// return this.activeComponentId === (this.activeComponent || {}).uuid;
......@@ -118,8 +120,8 @@ export default {
const _node = properties.node;
// console.log('********', _props);
let result = {
x: _props.left || _node.left.value,
y: _props.top || _node.top.value,
x: _props.x || _node.x.value,
y: _props.y || _node.y.value,
w: _props.width || _node.width.value,
h: _props.height || _node.height.value
};
......
<template>
<div class="views-tree">
<custom-node v-for="view in views" :key="view.uuid" :custom-style="styleObject(view)" :properties="view.properties">
<template v-if="view.children">
<views-tree :views="view.children"></views-tree>
</template>
</custom-node>
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
import { styles } from '../../../utils/common';
import customNode from '../../../components/customElement/node/index.vue';
export default {
name: 'viewsTree',
props: {
views: {
type: Array,
default: []
}
},
components: {
'custom-node': customNode
},
computed: {
...mapState(['project']),
...mapGetters(['activeComponentCopy', 'componentList'])
},
methods: {
styleObject(view) {
let result = '';
if (view.uuid === this.activeComponentCopy.uuid) {
result = styles.getComponentStyle(this.activeComponentCopy, this.project, this.componentList);
} else {
result = styles.getComponentStyle(view, this.project, this.componentList);
}
return result;
}
}
};
</script>
<style>
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment