/* eslint-disable @typescript-eslint/no-unused-expressions */ /* eslint-disable consistent-return */ /* eslint-disable @typescript-eslint/no-unsafe-return */ const { join } = require('path'); module.paths.push(join(Editor.App.path, 'node_modules')); const Vue = require('vue/dist/vue.min.js'); const propUtils = require('../utils/prop'); const cssMediaWidth = 340; let layout = 'vertical'; exports.template = `
`; const excludeList = ['uuid', 'name', 'enabled', '_name', '_objFlags', '__scriptAsset', 'node', '_enabled', '__prefab', 'target', 'isAlignTop', 'isAlignBottom', 'isAlignLeft', 'isAlignRight', 'isAlignVerticalCenter', 'isAlignHorizontalCenter', 'isStretchWidth', 'isStretchHeight', 'top', 'editorTop', 'bottom', 'editorBottom', 'left', 'editorLeft', 'right', 'editorRight', 'horizontalCenter', 'editorHorizontalCenter', 'verticalCenter', 'editorVerticalCenter', 'isAbsoluteTop', 'isAbsoluteBottom', 'isAbsoluteLeft', 'isAbsoluteRight', 'isAbsoluteHorizontalCenter', 'isAbsoluteVerticalCenter', 'alignMode', 'alignFlags', '_alignFlags', '_target', '_left', '_right', '_top', '_bottom', '_horizontalCenter', '_verticalCenter', '_isAbsLeft', '_isAbsRight', '_isAbsTop', '_isAbsBottom', '_isAbsHorizontalCenter', '_isAbsVerticalCenter', '_originalWidth', '_originalHeight', '_alignMode', '_lockFlags']; // Used to determine if the value is locked const LockFlags = { top: 1 << 0, middle: 1 << 1, bottom: 1 << 2, left: 1 << 3, center: 1 << 4, right: 1 << 5, }; exports.$ = { app: '#app', }; exports.methods = { getObjectByKey(target, key) { let params = []; if (typeof key === 'string') { params = key.split('.'); } else if (key instanceof Array) { params = key; } if (params.length > 0) { const value = params.shift(); return this.getObjectByKey(target[value], params); } else { return target; } }, getDimensionHorizontal() { const { isAlignLeft, isAlignRight, isAlignHorizontalCenter, } = this.dump.value; let dimension = ''; if (isAlignLeft.value) { dimension = 'left'; } if (isAlignRight.value) { dimension = 'right'; } if (isAlignLeft.value && isAlignRight.value) { dimension = 'stretch'; } if (isAlignHorizontalCenter.value) { dimension = 'center'; } return dimension; }, getDimensionVertical() { const { isAlignTop, isAlignBottom, isAlignVerticalCenter, } = this.dump.value; let dimension = ''; if (isAlignTop.value) { dimension = 'top'; } if (isAlignBottom.value) { dimension = 'bottom'; } if (isAlignTop.value && isAlignBottom.value) { dimension = 'stretch'; } if (isAlignVerticalCenter.value) { dimension = 'middle'; } return dimension; }, isInvalid(key) { if (Array.isArray(this.dump.value[key].values)) { return this.dump.value[key].values.some((value) => value !== this.dump.value[key].value); } return false; }, update() { for (const key in uiElements) { const element = uiElements[key]; if (typeof element.update === 'function') { element.update.call(this); } } }, change(key, newValue) { this.dump.value[key].value = newValue; this.$refs.summitProp.dump = this.dump.value[key]; if ('values' in this.dump.value[key]) { this.dump.value[key].values.forEach((_, index) => { this.dump.value[key].values[index] = newValue; }); } this.$refs.summitProp.dispatch('change-dump'); }, snapshot() { // next tick snapshot setTimeout(() => { this.$refs.summitProp.dispatch('confirm-dump'); }); }, getUnit(type) { const data = this.dump.value; switch (type) { case 'editorTop': return data.isAbsoluteTop.value ? 'px' : '%'; case 'editorBottom': return data.isAbsoluteBottom.value ? 'px' : '%'; case 'editorLeft': return data.isAbsoluteLeft.value ? 'px' : '%'; case 'editorRight': return data.isAbsoluteRight.value ? 'px' : '%'; case 'editorHorizontalCenter': return data.isAbsoluteHorizontalCenter.value ? 'px' : '%'; case 'editorVerticalCenter': return data.isAbsoluteVerticalCenter.value ? 'px' : '%'; default: break; } }, changeUnit(type) { function update(dump, force) { if (force !== true && dump === this.dump) { return; } const value = dump.value; switch (type) { case 'editorTop': value.isAbsoluteTop.value = !value.isAbsoluteTop.value; if ('values' in value.isAbsoluteTop) { value.isAbsoluteTop.values.forEach((val, index) => { value.isAbsoluteTop.values[index] = value.isAbsoluteTop.value; }); } return { path: 'isAbsoluteTop', dump: value.isAbsoluteTop }; case 'editorBottom': value.isAbsoluteBottom.value = !value.isAbsoluteBottom.value; if ('values' in value.isAbsoluteBottom) { value.isAbsoluteBottom.values.forEach((val, index) => { value.isAbsoluteBottom.values[index] = value.isAbsoluteBottom.value; }); } return { path: 'isAbsoluteBottom', dump: value.isAbsoluteBottom }; case 'editorLeft': value.isAbsoluteLeft.value = !value.isAbsoluteLeft.value; if ('values' in value.isAbsoluteLeft) { value.isAbsoluteLeft.values.forEach((val, index) => { value.isAbsoluteLeft.values[index] = value.isAbsoluteLeft.value; }); } return { path: 'isAbsoluteLeft', dump: value.isAbsoluteLeft }; case 'editorRight': value.isAbsoluteRight.value = !value.isAbsoluteRight.value; if ('values' in value.isAbsoluteRight) { value.isAbsoluteRight.values.forEach((val, index) => { value.isAbsoluteRight.values[index] = value.isAbsoluteRight.value; }); } return { path: 'isAbsoluteRight', dump: value.isAbsoluteRight }; case 'editorHorizontalCenter': value.isAbsoluteHorizontalCenter.value = !value.isAbsoluteHorizontalCenter.value; if ('values' in value.isAbsoluteHorizontalCenter) { value.isAbsoluteHorizontalCenter.values.forEach((val, index) => { value.isAbsoluteHorizontalCenter.values[index] = value.isAbsoluteHorizontalCenter.value; }); } return { path: 'isAbsoluteHorizontalCenter', dump: value.isAbsoluteHorizontalCenter }; case 'editorVerticalCenter': value.isAbsoluteVerticalCenter.value = !value.isAbsoluteVerticalCenter.value; if ('values' in value.isAbsoluteVerticalCenter) { value.isAbsoluteVerticalCenter.values.forEach((val, index) => { value.isAbsoluteVerticalCenter.values[index] = value.isAbsoluteVerticalCenter.value; }); } return { path: 'isAbsoluteVerticalCenter', dump: value.isAbsoluteVerticalCenter }; default: break; } } const { dump } = update(this.dump, true); this.$refs.summitProp.dump = dump; this.$refs.summitProp.dispatch('change-dump'); this.snapshot(); }, select(event) { if (!event.path) { event.path = event.composedPath(); } // Handling through delegated events const button = event.path.find((element) => element && element.classList && element.classList.contains('button')); if (!button) { return; } const dimension = button.getAttribute('dimension'); let horizontal; let vertical; switch (dimension) { case 'horizontal': horizontal = { isAlignLeft: { value: false, }, isAlignRight: { value: false, }, isAlignHorizontalCenter: { value: false, }, }; break; case 'left': horizontal = { isAlignLeft: { value: true, }, isAlignRight: { value: false, }, isAlignHorizontalCenter: { value: false, }, }; break; case 'center': horizontal = { isAlignLeft: { value: false, }, isAlignRight: { value: false, }, isAlignHorizontalCenter: { value: true, }, }; break; case 'right': horizontal = { isAlignLeft: { value: false, }, isAlignRight: { value: true, }, isAlignHorizontalCenter: { value: false, }, }; break; case 'h-stretch': horizontal = { isAlignLeft: { value: true, }, isAlignRight: { value: true, }, isAlignHorizontalCenter: { value: false, }, }; break; case 'vertical': vertical = { isAlignTop: { value: false, }, isAlignVerticalCenter: { value: false, }, isAlignBottom: { value: false, }, }; break; case 'top': vertical = { isAlignTop: { value: true, }, isAlignVerticalCenter: { value: false, }, isAlignBottom: { value: false, }, }; break; case 'middle': vertical = { isAlignTop: { value: false, }, isAlignVerticalCenter: { value: true, }, isAlignBottom: { value: false, }, }; break; case 'bottom': vertical = { isAlignTop: { value: false, }, isAlignVerticalCenter: { value: false, }, isAlignBottom: { value: true, }, }; break; case 'v-stretch': vertical = { isAlignTop: { value: true, }, isAlignVerticalCenter: { value: false, }, isAlignBottom: { value: true, }, }; break; default: break; } const dump = this.dump; if (horizontal) { if (dump.value.isAlignLeft.value !== horizontal.isAlignLeft.value || !this.isHorizontalAlignValid) { dump.value.isAlignLeft.value = horizontal.isAlignLeft.value; this.$refs.summitProp.dump = dump.value.isAlignLeft; if ('values' in dump.value.isAlignLeft) { dump.value.isAlignLeft.values.forEach((val, index) => { dump.value.isAlignLeft.values[index] = dump.value.isAlignLeft.value; }); } this.$refs.summitProp.dispatch('change-dump'); } if (dump.value.isAlignRight.value !== horizontal.isAlignRight.value || !this.isHorizontalAlignValid) { dump.value.isAlignRight.value = horizontal.isAlignRight.value; this.$refs.summitProp.dump = dump.value.isAlignRight; if ('values' in dump.value.isAlignRight) { dump.value.isAlignRight.values.forEach((val, index) => { dump.value.isAlignRight.values[index] = dump.value.isAlignRight.value; }); } this.$refs.summitProp.dispatch('change-dump'); } if (dump.value.isAlignHorizontalCenter.value !== horizontal.isAlignHorizontalCenter.value || !this.isHorizontalAlignValid) { dump.value.isAlignHorizontalCenter.value = horizontal.isAlignHorizontalCenter.value; this.$refs.summitProp.dump = dump.value.isAlignHorizontalCenter; if ('values' in dump.value.isAlignHorizontalCenter) { dump.value.isAlignHorizontalCenter.values.forEach((val, index) => { dump.value.isAlignHorizontalCenter.values[index] = dump.value.isAlignHorizontalCenter.value; }); } this.$refs.summitProp.dispatch('change-dump'); } this.dimensionHorizontal = this.getDimensionHorizontal(); } if (vertical) { if (dump.value.isAlignTop.value !== vertical.isAlignTop.value || !this.isVerticalAlignValid) { dump.value.isAlignTop.value = vertical.isAlignTop.value; this.$refs.summitProp.dump = dump.value.isAlignTop; if ('values' in dump.value.isAlignTop) { dump.value.isAlignTop.values.forEach((val, index) => { dump.value.isAlignTop.values[index] = dump.value.isAlignTop.value; }); } this.$refs.summitProp.dispatch('change-dump'); } if (dump.value.isAlignVerticalCenter.value !== vertical.isAlignVerticalCenter.value || !this.isVerticalAlignValid) { dump.value.isAlignVerticalCenter.value = vertical.isAlignVerticalCenter.value; this.$refs.summitProp.dump = dump.value.isAlignVerticalCenter; if ('values' in dump.value.isAlignVerticalCenter) { dump.value.isAlignVerticalCenter.values.forEach((val, index) => { dump.value.isAlignVerticalCenter.values[index] = dump.value.isAlignVerticalCenter.value; }); } this.$refs.summitProp.dispatch('change-dump'); } if (dump.value.isAlignBottom.value !== vertical.isAlignBottom.value || !this.isVerticalAlignValid) { dump.value.isAlignBottom.value = vertical.isAlignBottom.value; this.$refs.summitProp.dump = dump.value.isAlignBottom; if ('values' in dump.value.isAlignBottom) { dump.value.isAlignBottom.values.forEach((val, index) => { dump.value.isAlignBottom.values[index] = dump.value.isAlignBottom.value; }); } this.$refs.summitProp.dispatch('change-dump'); } this.dimensionVertical = this.getDimensionVertical(); } this.snapshot(); }, toggleLock(direction) { const isLock = this.isLock(direction); let directions = [direction]; let lockValue = this.dump.value._lockFlags.value; const isStretchWidth = this.dump.value.isStretchWidth.value; const isStretchHeight = this.dump.value.isStretchHeight.value; const stretchWidth = ['left', 'right']; if (isStretchWidth && stretchWidth.includes(direction)) { directions = stretchWidth; } const stretchHeight = ['top', 'bottom']; if (isStretchHeight && stretchHeight.includes(direction)) { directions = stretchHeight; } directions.forEach((dir) => { const lockDirection = LockFlags[dir]; if (isLock) { lockValue &= ~lockDirection; } else { lockValue |= lockDirection; } }); // Submit data this.dump.value._lockFlags.value = lockValue; this.$refs.summitProp.dump = this.dump.value._lockFlags; if ('values' in this.dump.value._lockFlags) { this.dump.value._lockFlags.values.forEach((val, index) => { this.dump.value._lockFlags.values[index] = lockValue; }); } this.$refs.summitProp.dispatch('change-dump'); this.snapshot(); }, isLock(direction) { const lockValue = this.dump.value._lockFlags.value; const lockDirection = LockFlags[direction]; return lockValue & lockDirection; }, setLayout() { const rect = this.$this.getBoundingClientRect(); this.layout ??= layout; if (rect.width) { if (rect.width > cssMediaWidth) { layout = this.layout = 'horizontal'; } else { layout = this.layout = 'vertical'; } } }, }; const uiElements = { baseProps: { ready() { this.$baseProps = this.$el && this.$el.querySelectorAll('ui-prop:not(.customProp)'); }, update() { if (!this.$baseProps) { uiElements.baseProps.ready.call(this); } this.$baseProps.forEach((element) => { const key = element.getAttribute('dump-key'); const dump = this.getObjectByKey(this.dump.value, key); const isEmpty = element.getAttribute('empty'); if (!isEmpty) { const isShow = dump.visible; if (isShow) { element.render(dump); } element.style = isShow ? '' : 'display: none;'; } }); }, }, customProps: { update() { if (!this.$customProps) { this.$customProps = this.$el.querySelector('#customProps'); } propUtils.updateCustomPropElements(this.$customProps, excludeList, this.dump, (element, prop) => { element.className = 'customProp'; if (prop.dump.visible) { element.render(prop.dump); } element.hidden = !prop.dump.visible; }); }, }, }; const template = /* html*/`
top
right
bottom
left
Horizontal Alignment
NONE
Left
Center
Right
Vertical Alignment
NONE
Top
Middle
Bottom
`; const components = { 'widget-icon': { template: `
`, }, }; const computed = { isHorizontalAlignValid() { return !(this.isInvalid('isAlignLeft') || this.isInvalid('isAlignRight') || this.isInvalid('isAlignHorizontalCenter')); }, isVerticalAlignValid() { return !(this.isInvalid('isAlignTop') || this.isInvalid('isAlignBottom') || this.isInvalid('isAlignVerticalCenter')); }, }; exports.ready = function() { this.resizeObserver = new window.ResizeObserver((entries) => { window.requestAnimationFrame(() => { // avoid error: ResizeObserver loop limit exceeded if (!Array.isArray(entries) || !entries.length) { return; } this.setLayout(); }); }); this.resizeObserver.observe(this.$this); for (const key in uiElements) { const element = uiElements[key]; if (typeof element.ready === 'function') { element.ready.call(this); } } }; exports.update = function(dump) { this.dump = dump; this.dimensionHorizontal = this.getDimensionHorizontal(); this.dimensionVertical = this.getDimensionVertical(); this.setLayout(); if (!this.vm) { this.vm = new Vue({ el: this.$.app, data: this, template, components, computed, methods: exports.methods, }); } this.vm.update(); }; exports.close = function() { this.resizeObserver.unobserve(this.$this); };