UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

220 lines (171 loc) • 6.78 kB
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); } }); } }