@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
220 lines (171 loc) • 6.78 kB
JavaScript
import View from "../../../src/view/View.js";
import Signal from "../../../src/core/events/signal/Signal.js";
import dom from "../../../src/view/DOM.js";
import ObservedBoolean from "../../../src/core/model/ObservedBoolean.js";
import LabelView from "../../../src/view/common/LabelView.js";
import ButtonView from "../../../src/view/elements/button/ButtonView.js";
import EmptyView from "../../../src/view/elements/EmptyView.js";
import {downloadAsFile} from "../../../src/core/binary/downloadAsFile.js";
export async function obtainClipBoard() {
const navigator = globalThis.navigator;
if (navigator.clipboard === undefined) {
const queries = [{
name: "clipboard-read"
}, {
name: "clipboard-write"
}];
const permission_queries = queries.map(q => navigator.permissions.query(q));
const statuses = await Promise.all(permission_queries);
for (let i = 0; i < statuses.length; i++) {
const permissionStatus = statuses[i];
if (permissionStatus.state !== "granted") {
throw new Error(`Permission for query not granted (actual state = ${permissionStatus.state}). Query:${JSON.stringify(queries[i])}`)
}
}
}
return navigator.clipboard;
}
/**
*
* @param {string} text
* @param {string} [data_name]
* @returns {Promise<void>}
*/
export async function safeClipboardWriteText(text, data_name = "data") {
return obtainClipBoard().then(
() => {
const navigator = globalThis.navigator;
return navigator.clipboard.writeText(text);
},
() => {
// no clipboard available
console.log(`No clipboard available, downloading instead`);
downloadAsFile(text, `${data_name}.json`);
}
);
}
export async function safeClipboardReadText() {
return obtainClipBoard().then(() => {
const navigator = globalThis.navigator;
return navigator.clipboard.readText();
}, () => {
// clipboard not available
console.log(`No clipboard available, using a prompt instead`);
function clickElem(elem) {
// Thx user1601638 on Stack Overflow (6/6/2018 - https://stackoverflow.com/questions/13405129/javascript-create-and-save-file )
var eventMouse = document.createEvent("MouseEvents")
eventMouse.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
elem.dispatchEvent(eventMouse)
}
function openFile(func) {
const fileInput = document.createElement("input");
const readFile = function (e) {
var file = e.target.files[0];
if (!file) {
return;
}
var reader = new FileReader();
reader.onload = function (e) {
var contents = e.target.result;
fileInput.func(contents)
document.body.removeChild(fileInput)
}
reader.readAsText(file)
}
fileInput.type = 'file'
fileInput.style.display = 'none'
fileInput.onchange = readFile
fileInput.func = func
document.body.appendChild(fileInput)
clickElem(fileInput)
}
return new Promise((resolve, reject) => {
openFile(resolve);
});
});
}
/**
* @template T
*/
export class ComponentControlView extends View {
/**
* @template T
* @param {number} entity
* @param {T} component
* @param {EntityManager} entityManager
* @param {View} vController
* @param engine
* @constructor
*/
constructor(entity, component, entityManager, vController, engine) {
super();
this.signal = {
remove: new Signal()
};
const dRoot = dom('div');
dRoot.addClass('entity-editor-component-control-view');
this.el = dRoot.el;
const folded = this.folded = new ObservedBoolean(false);
const componentType = component.constructor;
const typeName = componentType.typeName;
const vComponentName = new LabelView(typeName);
const bFold = new ButtonView({
classList: ['fold-toggle'],
action() {
folded.invert();
}
});
const bRemove = new ButtonView({
classList: ['remove'],
action() {
self.signal.remove.dispatch();
}
});
const bCopy = new ButtonView({
classList: ['copy'],
async action() {
const json = component.toJSON();
const data = JSON.stringify({
type: typeName,
data: json
}, 3, 3);
safeClipboardWriteText(data, typeName).then(() => {
console.log(`${entity}:${typeName} dumped`);
});
}
});
bCopy.setClass('disabled', component.hasOwnProperty('toJSON') && typeof component.toJSON !== "function");
const bPaste = new ButtonView({
classList: ['paste'],
async action() {
safeClipboardReadText().then(text => {
const json = JSON.parse(text);
if (json.type !== typeName) {
throw new Error(`Component type(=${json.type}) in clipboard does not match current component type(=${typeName})`);
}
//get system
component.fromJSON(json.data, engine);
console.log(`${entity}:${typeName} pasted from clip`);
});
}
});
bPaste.setClass('disabled', component.hasOwnProperty('fromJSON') && typeof component.fromJSON !== "function");
const vTitleBar = new EmptyView();
dom(vTitleBar.el).addClass('title-bar');
vTitleBar.addChild(vComponentName);
vTitleBar.addChild(bCopy);
vTitleBar.addChild(bPaste);
vTitleBar.addChild(bFold);
vTitleBar.addChild(bRemove);
this.addChild(vTitleBar);
const self = this;
folded.process(function (v) {
dRoot.setClass('folded', v);
if (v) {
self.removeChild(vController);
} else {
self.addChild(vController);
}
});
}
}