769 lines
24 KiB
Vue

<template>
<div @mousedown="changeEditorFocus()" v-if="forceRefresh" @mouseup="drag && fileDragDrop($event)" ref="openFilesView"
class="ddei-core-panel-openfilesview">
<div v-show="this.editor?.leftWidth == 0 " class="ddei-core-panel-openfilesview-expandbox"
@click="expandToolBox">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-expand4"></use>
</svg>
</div>
<div class="ddei-core-panel-openfilesview-item" v-if="!editor?.files"></div>
<div
:class="item.active == 1 ? 'ddei-core-panel-openfilesview-item ddei-core-panel-openfilesview-item--selected' : 'ddei-core-panel-openfilesview-item'"
@click="changeFile(item)" @mousedown="drag && fileDragStart(index, $event)"
@mousemove="drag && fileDragOver($event)" v-for="(item, i) in editor?.files"
v-show="i >= openIndex && ((i - openIndex + 1) * unitFileWidth + 120) <= width" :title="item.name">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-file"></use>
</svg>
<span class="textcontent">
<div class="text" @dblclick="rename && startChangeFileName(item, $event)">{{ item.name }}</div>
<div class="dirty" v-show="item.state != 0"></div>
</span>
<svg @click.prevent.stop="closeFile(item, $event)" v-if="close" class="icon close" aria-hidden="true">
<use xlink:href="#icon-close"></use>
</svg>
</div>
<svg class="icon addfile" aria-hidden="true" v-if="create && (!max || editor?.files?.length < max)"
@click="newFile">
<use xlink:href="#icon-add"></use>
</svg>
<div style="flex:1 1 1px"></div>
<div class="ddei-core-panel-openfilesview-movebox" v-show="editor?.files?.length > maxOpenSize"
@click="moveItem(-1)">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-left"></use>
</svg>
</div>
<div class="ddei-core-panel-openfilesview-movebox" v-show="editor?.files?.length > maxOpenSize"
@click="moveItem(1)">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-right"></use>
</svg>
</div>
</div>
</template>
<script lang="ts">
import {DDeiUtil} from "ddei-framework";
import {DDeiEditor} from "ddei-framework";
import {DDeiActiveType} from "ddei-framework";
import {DDeiEditorState} from "ddei-framework";
import {DDeiFileState} from "ddei-framework";
import {DDeiFile} from "ddei-framework";
import {DDeiEditorUtil} from "ddei-framework";
import {DDeiStoreLocal} from "ddei-framework";
import {DDeiEnumBusCommandType} from "ddei-framework";
import {DDeiEditorEnumBusCommandType} from "ddei-framework";
import {DDeiStage} from "ddei-framework";
import {DDeiSheet} from "ddei-framework";
export default {
name: "ddei-core-panel-openfilesview",
extends: null,
mixins: [],
props: {
//外部传入的插件扩展参数
options: {
type: Object,
default: null
},
//是否允许展开收折
expand: {
type: Boolean,
default: false
},
create: {
type: Boolean,
default: true
},
close: {
type: Boolean,
default: true
},
rename: {
type: Boolean,
default: true
},
drag: {
type: Boolean,
default: true
},
max:{
type: Number,
default: 0
},
beforeCloseFile:{
type: Function,
default: null
}
, editor: {
type: DDeiEditor,
default: null,
}
},
data() {
return {
//当前打开的页的开始下标
openIndex: 0,
//最大可以打开的数量
maxOpenSize: 1,
// tempFile: null,
unitFileWidth: 160,
// user: null,
forceRefresh:true
};
},
computed: {},
watch: {},
created() {
// 监听文件列表大小变化
this.$watch("editor.files.length", function (newVal, oldVal) {
//打开新文件
setTimeout(() => {
let activeIndex = -1;
for (let i = 0; i < this.editor.files.length; i++) {
if (this.editor.files[i].active == DDeiActiveType.ACTIVE) {
activeIndex = i;
this.editor.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["toolbox", "property"]
});
this.editor.bus.executeAll();
break;
}
}
this.openIndex = activeIndex + 1 - this.maxOpenSize;
if (this.openIndex < 0) {
this.openIndex = 0;
}
}, 10);
});
},
mounted() {
// 创建 ResizeObserver 实例
const resizeObserver = new ResizeObserver(entries => {
// entries 是一个 ResizeObserverEntry 对象数组,包含目标元素的大小信息
for (const entry of entries) {
// 获取宽度和高度
let { width, height } = entry.contentRect;
if(width == 0 || height == 0){
width = this.$refs.openFilesView.clientWidth
height = this.$refs.openFilesView.clientHeight
}
if (width != 0 && height != 0) {
//获取单个tab大小
let fileEles = this.$refs.openFilesView.getElementsByClassName("ddei-core-panel-openfilesview-item")
let fileWidth = 0;
if (fileEles.length > 0) {
fileWidth = fileEles[0].clientWidth
}
if (!fileWidth) {
fileWidth = 160
}
this.unitFileWidth = fileWidth
let size = parseInt((width - 120) / fileWidth);
if (size > this.maxOpenSize && this.openIndex > 0) {
this.openIndex--;
}
this.maxOpenSize = size;
this.width = width
}
}
});
// 开始监听目标元素的大小变化
resizeObserver.observe(this.$refs.openFilesView);
this.refreshData();
},
methods: {
//强制刷新当前以及下层组件
forceRefreshParts(parts) {
if (!parts || parts == 'openfiles' || parts.indexOf('openfiles') != -1) {
this.forceRefresh = false
this.$nextTick(() => {
this.forceRefresh = true;
if (this.refreshData) {
this.refreshData();
}
});
}
},
refreshData() {
this.editor.openFilesViewer = this;
// let userCookie = Cookies.get("user");
// if (userCookie) {
// this.user = JSON.parse(userCookie)
// }
},
/**
* 新建文件
* @param evt
*/
newFile(evt) {
if (this.editor?.ddInstance) {
let rsState = DDeiEditorUtil.invokeCallbackFunc("EVENT_ADD_FILE_BEFORE", "ADD_FILE", null, this.editor.ddInstance, null)
if (rsState != -1) {
let ddInstance = this.editor.ddInstance;
let fileText = this.editor.i18n('ddei.file')
let newText = this.editor.i18n('ddei.new')
let pageText = this.editor.i18n('ddei.page')
let file = DDeiFile.loadFromJSON(
{
name: newText + fileText + "_NEW",
path: "/" + newText + fileText + "_NEW",
sheets: [
new DDeiSheet({
name: pageText + "-1",
desc: pageText + "-1",
stage: DDeiStage.initByJSON({ id: "stage_1" }, { currentDdInstance :ddInstance}),
active: DDeiActiveType.ACTIVE,
}),
],
currentSheetIndex: 0,
state: DDeiFileState.NEW,
active: DDeiActiveType.ACTIVE,
},
{ currentDdInstance: ddInstance }
);
file.local = 1
//添加文件
if (this.editor.currentFileIndex != -1) {
this.editor.files[this.editor.currentFileIndex].active =
DDeiActiveType.NONE;
}
this.editor.addFile(file);
this.editor.currentFileIndex = this.editor.files.length - 1;
let sheets = file?.sheets;
if (file && sheets && ddInstance) {
ddInstance.stage.destroyRender()
let stage = sheets[0].stage;
stage.ddInstance = ddInstance;
//刷新页面
ddInstance.stage = stage;
//记录文件初始日志
file.initHistroy();
//设置视窗位置到中央
if (!stage.wpv) {
//缺省定位在画布中心点位置
stage.wpv = {
x: -(stage.width - ddInstance.render.canvas.width / ddInstance.render.ratio) / 2,
y: -(stage.height - ddInstance.render.canvas.height / ddInstance.render.ratio) / 2,
z: 0,
};
}
//加载场景渲染器
stage.initRender();
ddInstance.bus.push(DDeiEditorEnumBusCommandType.ClearTemplateUI);
ddInstance.bus.push(DDeiEnumBusCommandType.RefreshShape);
ddInstance.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["bottommenu", "topmenu"],
});
this.editor.changeState(DDeiEditorState.DESIGNING);
ddInstance?.bus?.executeAll();
}
DDeiEditorUtil.invokeCallbackFunc("EVENT_ADD_FILE_AFTER", "ADD_FILE", null, this.editor.ddInstance, null)
if (this.editor.files.length == 0) {
ddInstance.disabled = true
} else {
ddInstance.disabled = false
}
}
}
},
/**
* 修改文件标题
*/
startChangeFileName(file, evt) {
let ele = evt.target;
let domPos = DDeiUtil.getDomAbsPosition(ele);
let editor = DDeiEditor.ACTIVE_INSTANCE;
let editorEle = document.getElementById(editor.id);
let editorDomPos = DDeiUtil.getDomAbsPosition(editorEle);
let input = document.getElementById(editor.id+"_change_file_name_input");
if (!input) {
input = document.createElement("input");
input.setAttribute("id", editor.id +"_change_file_name_input");
input.style.position = "absolute";
input.style.fontSize = "16px"
editorEle.appendChild(input);
input.onblur = function () {
//设置属性值
if (input.value) {
let editor = DDeiEditor.ACTIVE_INSTANCE;
let file = editor?.files[editor?.currentFileIndex];
if (input.value != file.name) {
file.name = input.value;
if (file.path) {
if (file.path.indexOf("/") != -1) {
file.path = file.path.substring(0, file.path.lastIndexOf("/")) + "/" + file.name
} else {
file.path = file.name;
}
}
editor.editorViewer?.changeFileModifyDirty();
editor.bus.push(DDeiEditorEnumBusCommandType.AddFileHistroy);
editor.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["openfiles"],
});
editor.bus.executeAll();
editor.changeState(DDeiEditorState.DESIGNING);
}
input.style.display = "none";
input.style.left = "0px";
input.style.top = "0px";
input.value = "";
}
};
input.onkeydown = function (e) {
//回车
if (e.keyCode == 13) {
let editor = DDeiEditor.ACTIVE_INSTANCE;
let file = editor?.files[editor?.currentFileIndex];
if (input.value != file.name) {
file.name = input.value;
if (file.path){
if (file.path.indexOf("/") != -1){
file.path = file.path.substring(0, file.path.lastIndexOf("/"))+"/"+file.name
}else{
file.path = file.name;
}
}
editor.editorViewer?.changeFileModifyDirty();
editor.bus.push(DDeiEditorEnumBusCommandType.AddFileHistroy);
editor.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["openfiles"],
});
editor.bus.executeAll();
editor.changeState(DDeiEditorState.DESIGNING);
}
input.style.display = "none";
input.style.left = "0px";
input.style.top = "0px";
input.value = "";
} else if (e.keyCode == 27) {
let editor = DDeiEditor.ACTIVE_INSTANCE;
input.style.display = "none";
input.style.left = "0px";
input.style.top = "0px";
input.value = "";
editor.changeState(DDeiEditorState.DESIGNING);
}
};
}
input.style.width = ele.offsetWidth + "px";
input.style.height = ele.offsetHeight - 3 + "px";
input.style.left = domPos.left - editorDomPos.left + "px";
input.style.top = (domPos.top + 2 - editorDomPos.top) + "px";
input.style.border = "none";
input.style.outline = "none";
input.style.borderBottom = "1px solid #1F72FF";
input.style.borderRadius = "1px";
input.value = file.name;
input.style.display = "block";
input.selectionStart = 0; // 选中开始位置
input.selectionEnd = input.value.length; // 获取输入框里的长度。
input.style.background = "var(--background)";
input.style.color = "var(--text)";
input.focus();
//修改编辑器状态为快捷编辑中
this.editor.bus.push(DDeiEditorEnumBusCommandType.ClearTemplateUI);
this.editor.bus.executeAll();
if (this.editor.state != DDeiEditorState.PROPERTY_EDITING && this.editor.state != DDeiEditorState.QUICK_EDITING) {
this.editor.changeState(DDeiEditorState.PROPERTY_EDITING);
}
},
/**
* file开始拖拽移动
*/
fileDragStart(fileEle, evt) {
this.dragFileEle = evt.currentTarget;
},
/**
* 拖拽元素移动
*/
fileDragOver(e) {
if (this.dragFileEle) {
if (e.currentTarget.className.indexOf("ddei-core-panel-openfilesview-item") != -1) {
let parentDiv = this.dragFileEle.parentElement;
let sourceIndex = -1;
let targetIndex = -1;
let children = parentDiv.children;
for (let i = 1; i < children.length - 4; i++) {
children[i].style.borderLeft = "";
children[i].style.borderRight = "";
if (children[i] == this.dragFileEle) {
sourceIndex = i;
} else if (e.currentTarget == children[i]) {
targetIndex = i;
}
}
if (sourceIndex != -1 && targetIndex != -1) {
this.sourceFileIndex = sourceIndex - 1;
if (targetIndex == children.length - 5) {
let pos = DDeiUtil.getDomAbsPosition(children[targetIndex]);
let halfPos = pos.left + children[targetIndex].offsetWidth / 2;
if (
halfPos <= e.clientX &&
e.clientX <= pos.left + children[targetIndex].offsetWidth
) {
this.changeFileIndex = targetIndex;
children[targetIndex].style.borderRight = "2px solid #1F72FF";
} else {
this.changeFileIndex = targetIndex - 1;
children[targetIndex].style.borderLeft = "2px solid #1F72FF";
}
} else {
this.changeFileIndex = targetIndex - 1;
children[targetIndex].style.borderLeft = "2px solid #1F72FF";
}
}
e.preventDefault();
}
}
},
/**
* 拖拽元素放开
*/
fileDragDrop(e) {
if (
(this.sourceFileIndex || this.sourceFileIndex == 0) &&
(this.changeFileIndex || this.changeFileIndex == 0)
) {
//修改file位置
let files = this.editor.files;
let sourceFile = this.editor.files[this.sourceFileIndex];
let currentFile = this.editor.files[this.editor.currentFileIndex];
files[this.sourceFileIndex] = null;
files.splice(this.changeFileIndex, 0, sourceFile);
for (let j = files.length; j >= 0; j--) {
if (files[j] == null) {
files.splice(j, 1);
}
}
for (let j = files.length; j >= 0; j--) {
if (currentFile == files[j]) {
this.editor.currentFileIndex = j;
}
}
let parentDiv = this.dragFileEle.parentElement;
let children = parentDiv.children;
for (let i = 1; i < children.length - 4; i++) {
children[i].style.borderLeft = "";
children[i].style.borderRight = "";
}
//刷新
this.editor.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["openfiles"],
});
this.editor.bus.executeAll();
}
this.dragFileEle = null;
this.sourceFileIndex = null;
this.changeFileIndex = null;
},
/**
* 变更实例
* @param instance
*/
changeFile(file) {
let ddInstance = this.editor?.ddInstance;
if (!file) {
ddInstance.bus.push(DDeiEnumBusCommandType.RefreshShape);
ddInstance.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {});
ddInstance.bus.executeAll();
}else{
if (this.editor.files.indexOf(file) != this.editor.currentFileIndex){
let rsState = DDeiEditorUtil.invokeCallbackFunc("EVENT_CHANGE_FILE_BEFORE", "CHANGE_FILE", null, ddInstance, null)
if (rsState != -1) {
this.editor.changeFile(this.editor.files.indexOf(file))
DDeiEditorUtil.invokeCallbackFunc("EVENT_CHANGE_FILE_AFTER", "CHANGE_FILE", null, ddInstance, null)
ddInstance.bus.push(DDeiEnumBusCommandType.RefreshShape);
ddInstance.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {});
ddInstance.bus.executeAll();
}
}
}
if (this.editor.files.length == 0) {
ddInstance.disabled = true
} else {
ddInstance.disabled = false
}
},
// /**
// * 放弃并关闭确认弹框
// */
// abortAndCloseFileConfirmDialog() {
// this.tempFile.state = DDeiFileState.NONE;
// this.closeFile(this.tempFile);
// },
// /**
// * 保存
// * @param evt
// */
// saveAndCloseFileConfirmDialog() {
// if (this.tempFile) {
// //获取json信息
// let file = this.tempFile;
// if (file) {
// let json = file.toJSON();
// if (json) {
// //执行保存
// let storeIns = new DDeiStoreLocal();
// json.state = DDeiFileState.NONE;
// storeIns.save(file.id, json).then((data) => {
// //回写ID
// file.id = data;
// file.state = DDeiFileState.NONE;
// this.closeFile(this.tempFile);
// });
// }
// }
// }
// },
/**
* 关闭文件
* @param instance
*/
closeFile(file, evt) {
//如果文件为脏状态,询问是否保存,放弃,或取消
let canClose = true;
if (this.beforeCloseFile){
canClose = this.beforeCloseFile(file)
}
if(canClose){
let ddInstance = this.editor.ddInstance;
let rsState = DDeiEditorUtil.invokeCallbackFunc("EVENT_CLOSE_FILE_BEFORE", "CLOSE_FILE", null, ddInstance, evt)
if (rsState != -1) {
// if (
// file.state == DDeiFileState.NEW ||
// file.state == DDeiFileState.MODIFY
// ) {
// DDeiEditorUtil.showDialog(this.editor, "ddei-core-dialog-closefile", {
// msg: '是否保存对"' + file.name + '"的更改?',
// callback: {
// abort: this.abortAndCloseFileConfirmDialog,
// ok: this.saveAndCloseFileConfirmDialog,
// },
// background: "white",
// opacity: "1%",
// event: -1
// })
// this.tempFile = file;
// } else {
//刷新画布
let index = this.editor.files.indexOf(file);
this.editor.removeFile(file);
if (index < this.editor.currentFileIndex) {
this.editor.currentFileIndex--;
} else if (index == this.editor.currentFileIndex) {
if (index > 0) {
this.changeFile(
this.editor.files[this.editor.currentFileIndex - 1]
);
} else if (this.editor.files.length > 0) {
this.changeFile(this.editor.files[0]);
}
}
if (this.editor.files.length == 0) {
this.changeFile(null);
this.editor.currentFileIndex = -1;
}
if (index > this.openIndex) {
this.openIndex--;
if (this.openIndex < 0) {
this.openIndex = 0;
}
}
DDeiEditorUtil.invokeCallbackFunc("EVENT_CLOSE_FILE_AFTER", "CLOSE_FILE", null, ddInstance, evt)
ddInstance.bus.push(DDeiEnumBusCommandType.RefreshShape);
ddInstance.bus.push(DDeiEditorEnumBusCommandType.RefreshEditorParts, {
parts: ["bottommenu", "topmenu"],
});
this.editor.changeState(DDeiEditorState.DESIGNING);
ddInstance?.bus?.executeAll();
}
}
// }
},
/**
* 在存在显示隐藏的情况下移动tab
*/
moveItem(index: number = 0) {
if (index != 0) {
this.openIndex += index;
if (this.openIndex > this.editor.files.length - this.maxOpenSize) {
this.openIndex = this.editor.files.length - this.maxOpenSize;
} else if (this.openIndex < 0) {
this.openIndex = 0;
}
}
},
/**
* 展开工具栏
*/
expandToolBox() {
this.editor.leftWidth = window.leftWidth;
//重新设置画布大小
this.editor.middleWidth -= window.leftWidth;
delete window.leftWidth
this.editor.changeState(DDeiEditorState.DESIGNING);
},
/**
* 焦点进入当前区域
*/
changeEditorFocus() {
this.editor.changeState(DDeiEditorState.DESIGNING);
this.editor.bus.push(DDeiEditorEnumBusCommandType.ClearTemplateUI);
this.editor.bus.executeAll();
},
},
};
</script>
<style lang="less" scoped>
.icon{
color:var(--icon);
}
.ddei-core-panel-openfilesview {
flex: 0 0 30.5px;
background: var(--panel-background);
border-top: 1px solid var(--panel-border);
border-bottom: 1px solid var(--panel-border);
display: flex;
user-select: none;
align-items: center;
&-expandbox {
flex: 0 0 28px;
display: flex;
justify-content: center;
align-items: center;
height:100%;
&:hover {
background: var(--panel-hover);
cursor: pointer;
}
.icon{
font-size:18px;
}
}
.addfile {
margin: 0px 10px;
font-size: 24px;
}
&-movebox {
flex: 0 0 25px;
display: flex;
justify-content: center;
align-items: center;
&:hover {
background: var(--panel-hover);
cursor: pointer;
}
img {
filter: brightness(60%);
margin-top: 4px;
}
}
&-item {
height: 100%;
flex: 0 0 195px;
display: flex;
justify-content: center;
align-items: center;
background-color: var(--panel-background);
border-right: 1px solid var(--panel-hover);//#B3B4B4;
.icon {
font-size: 16px;
flex: 0 0 42px;
text-align: center;
}
.close {
font-size: 18px;
flex: 0 0 24px;
margin-left: -5px;
}
.textcontent {
font-size: 15px;
flex: 0 0 130px;
width: 130px;
display: flex;
justify-content: center;
align-items: center;
.text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: var(--panel-title);
flex: 1;
font-size: 16px;
font-weight: 400;
}
}
span .dirty {
color: red;
width: 10px;
flex: 0 0 10px;
font-size: 18px;
text-align: right;
}
&:hover {
background: var(--panel-hover);
}
&--selected {
background: var(--panel-selected);
.textcontent .text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
flex: 1;
color: var(--panel-title);
}
}
}
}
</style>