Compare commits
19 commits
Author | SHA1 | Date | |
---|---|---|---|
e719102dec | |||
90ea9df537 | |||
9c2af40b36 | |||
bf9908ded1 | |||
15a4048730 | |||
18e3b13fdc | |||
a63421b675 | |||
fe23109834 | |||
10e9a68989 | |||
5068141aff | |||
4bc4ca5a16 | |||
fd8f139bf4 | |||
f2822f219f | |||
3994dc115f | |||
82561bc25a | |||
ba87efcb7c | |||
3c7a00035f | |||
5e238ee0be | |||
da22b29313 |
18 changed files with 1289 additions and 731 deletions
147
README.md
147
README.md
|
@ -1,147 +0,0 @@
|
|||
# Stear
|
||||
|
||||
## Introduction
|
||||
A simple Framework. Its more a try to get a WindowManger and getting rid of self written HTML and CSS
|
||||
|
||||
## Getting started
|
||||
Download the stear Directory and add it to your Project.
|
||||
## Features
|
||||
### Create Stear Instance
|
||||
```javascript
|
||||
import { Stear, SWindow } from "./stear/main.js";
|
||||
var stear = new Stear(document.querySelector("#stear"));
|
||||
```
|
||||
### Addind Windows
|
||||
|
||||
```javascript
|
||||
stear.addElement("connect", new SWindow(connect));
|
||||
stear.addElement("start", new SWindow(start));
|
||||
```
|
||||
Windows don't necessarily have to be add this Way, but it is recommented.
|
||||
|
||||
An SWindow is an Extendion of the SFrame class. SWindow adds an DIV Element around the page content in Fullscreen.
|
||||
|
||||
### Calling Windows
|
||||
```javascript
|
||||
stear.call(stear.g("start"), {});
|
||||
```
|
||||
The first Argument must be an SFrame Instance. The secound Argument can be used to pass Data to the new Window.
|
||||
|
||||
An Window/Frame is could be build by extending SFrame or SWindow, but the recommanded way is to create an ES6 Module and passing it into the SWindow or SFrame class
|
||||
|
||||
### Creating a Window
|
||||
```javascript
|
||||
import { _ } from "./stear/main.js";
|
||||
import { fadein, fadeout, wait } from "./stear/utils.js";
|
||||
|
||||
|
||||
export const preRender = true;
|
||||
|
||||
export const render = ({}, {}) => {
|
||||
|
||||
return _({}, [
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
export const call = async (stear, { find, resolve, render, call }, args) => {
|
||||
|
||||
}
|
||||
```
|
||||
**preRender**: If actived render() will only be called once. If deactived you have to call the provided render() function in the call() function yourself.
|
||||
|
||||
**render**: A sync function returning your Page Content. (for Detail look deeper) The first Argument is not used right now. The scound one can contain Args passt in the render() function inside call().
|
||||
|
||||
**call**: When calling a Window this function will be called. The first Argument is the used Stear Instance. The secound Argument contains some SterungTools. The third Argument are the Arguments passt in the call request.
|
||||
|
||||
### Creating Page Content / class_ class
|
||||
```javascript
|
||||
_({
|
||||
find:"someString",
|
||||
type:"div",
|
||||
style:{
|
||||
color:"#fff",
|
||||
backgroundColor:"black",
|
||||
},
|
||||
//other Attributes
|
||||
},[
|
||||
//pass here other class_ Instances
|
||||
])
|
||||
```
|
||||
The function _(settings, childs) returns an class\_ Instance.
|
||||
|
||||
Attributes of the Settings Object while be applyed as HTML-Element Attribute.
|
||||
Exeptions are find, type and style (all can be empty):
|
||||
|
||||
**type**: The type Attribute determines the DOMElement Type. The Default is div.
|
||||
|
||||
**find**: The find Attribute is an identifier for the call() function. With find.someString you can get this Element. With find.someString._ you get the underlying DOMElement.
|
||||
|
||||
**style**: The content of the style Attribute will be applied as css style.
|
||||
|
||||
Other Methodes:
|
||||
```javascript
|
||||
var element = _({},[]);
|
||||
var newRenderedHTMLElement = element.render ;
|
||||
var HTMLElement = element._ ; //Same as line befor when Element was completly rendered
|
||||
element.childs = [
|
||||
//Overrides the secound Argument
|
||||
];
|
||||
element.settings = {
|
||||
//Overrides first Argument (when possible)
|
||||
}
|
||||
```
|
||||
|
||||
### Globel functions
|
||||
|
||||
#### Adding Global CSS the Oldway
|
||||
```javascript
|
||||
Stear.addGlobalStyleText(`
|
||||
.cssClass {
|
||||
color: #fff;
|
||||
background-color:black;
|
||||
}
|
||||
`);
|
||||
```
|
||||
#### Adding Global CSS the with JSON
|
||||
```javascript
|
||||
var name = ".cssClass";
|
||||
name = Stear.addGlobalStyleJSON({
|
||||
color: "#fff",
|
||||
backgroundColor: "black",
|
||||
},name);
|
||||
```
|
||||
The Function can add CSS like CSS can be added to Elements in Pages. When leaving name empty a cssClass will be added with a sortof random name.
|
||||
|
||||
#### Adding CSS Animations with JSON
|
||||
```javascript
|
||||
var KeyframeName = Stear.addAnimation({
|
||||
"0%":{
|
||||
transform: "scale(100%)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "scale(110%)",
|
||||
},
|
||||
"100%": {
|
||||
transform: "scale(100%)",
|
||||
}
|
||||
}/*,name*/);
|
||||
```
|
||||
|
||||
### Utils
|
||||
#### wait
|
||||
```javascript
|
||||
await wait(200);
|
||||
```
|
||||
Simpel Methode of Timedelay in an async fcuntion
|
||||
#### fadein
|
||||
```javascript
|
||||
await fadein(elems,ms,force);
|
||||
await fadeout(elems,ms,force);
|
||||
```
|
||||
**elems**: contains Element to Fade in or an Array of Elements
|
||||
**ms** Fade time
|
||||
**force** If set to true a alredy invisible/visible Element will be refaded out/in.
|
||||
### Extras
|
||||
|
||||
loading1.js: simple to use Loadinganimation
|
16
empty.js
16
empty.js
|
@ -1,16 +0,0 @@
|
|||
import { _ } from "./stear/main.js";
|
||||
import { fadein, fadeout, wait } from "./stear/utils.js";
|
||||
|
||||
|
||||
export const preRender = true;
|
||||
|
||||
export const render = ({}, {}) => {
|
||||
|
||||
return _({}, [
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
export const call = async (stear, { find, resolve, render, call }, { }) => {
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
import l1 from "../stear/extra/Elements/loading1.js";
|
||||
import showStatus from "../stear/extra/Pages/showStatus.js";
|
||||
import { _ } from "../stear/main.js";
|
||||
import { fadein, fadeout, wait } from "../stear/utils.js";
|
||||
|
||||
export const preRender = true;
|
||||
|
||||
export const render = ({},{}) =>
|
||||
_({find:"main"},[
|
||||
_({type:"p",find:"text",style:{
|
||||
position: "absolute",
|
||||
minWidth: "90%",
|
||||
textAlign: "center",
|
||||
top: "25%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%,-50%)",
|
||||
}}),
|
||||
_({style:{
|
||||
position: "absolute",
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
}}, l1())
|
||||
]);
|
||||
|
||||
export const call = async (stear, { find, resolve, render, call }, {name,id}) => {
|
||||
find.text._.innerText = "Connecting to: " + name + " (" + id + ")";
|
||||
await fadein(find.main._, 200, true);
|
||||
//do connection
|
||||
await wait(1000);
|
||||
if (Math.random() > 0.25){
|
||||
|
||||
call(showStatus, { text: "Connected" });
|
||||
|
||||
await fadeout(find.main._);
|
||||
return resolve(true);
|
||||
}else{
|
||||
|
||||
call(showStatus, { text: "Error while Connecting to: "+name, color:"red" });
|
||||
|
||||
await fadeout(find.main._);
|
||||
return resolve(false);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Stear</title>
|
||||
<style>
|
||||
html,body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#stear{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left:0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="stear"></div>
|
||||
|
||||
<script src="index.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,28 +0,0 @@
|
|||
import { Stear, SWindow } from "../stear/main.js";
|
||||
|
||||
import * as connect from "./connect.js";
|
||||
import * as start from "./start.js";
|
||||
|
||||
|
||||
var stear = new Stear(document.querySelector("#stear"));
|
||||
|
||||
stear.style({
|
||||
backgroundColor: "#dde",
|
||||
fontFamily: "Helvetica Neue",
|
||||
fontWeight: "lighter",
|
||||
fontSize: "0.9em",
|
||||
color: "#2a2a2a",
|
||||
});
|
||||
|
||||
stear.addElement("connect", new SWindow(connect));
|
||||
stear.addElement("start", new SWindow(start));
|
||||
|
||||
stear.call(stear.g("start"), {});
|
||||
|
||||
setTimeout(()=>{
|
||||
document.dispatchEvent(new Event("deviceready"));
|
||||
},10);
|
||||
|
||||
|
||||
|
||||
window.s = stear;
|
|
@ -1,41 +0,0 @@
|
|||
import { Stear, _ } from "../stear/main.js";
|
||||
import { fadein, fadeout, wait } from "../stear/utils.js";
|
||||
|
||||
export const preRender = true;
|
||||
|
||||
export const render = ({},{}) => {
|
||||
var wobel = Stear.addAnimation({
|
||||
"0%":{
|
||||
transform: "translate(-50%, -50%) scale(100%)"
|
||||
},
|
||||
"50%": {
|
||||
transform: "translate(-50%, -50%) scale(110%)"
|
||||
},
|
||||
"100%": {
|
||||
transform: "translate(-50%, -50%) scale(100%)"
|
||||
}
|
||||
});
|
||||
console.log(wobel)
|
||||
|
||||
return _({style:{zindex:1000},find:"main"}, [
|
||||
_({type:"img",src:"http://localhost:82/images/logo.png",style:{
|
||||
width: "80vw",
|
||||
maxWidth: "75vh",
|
||||
position: "absolute",
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
animation: `${wobel} 2s ease-in-out 0s infinite`,
|
||||
|
||||
}})
|
||||
]);
|
||||
}
|
||||
|
||||
export const call = (stear, { find, resolve, render, call }, args) => {
|
||||
document.addEventListener('deviceready', async ()=>{
|
||||
await wait(Math.max(1, 1000 - performance.now()));
|
||||
await fadeout(find.main._);
|
||||
call(stear.g("connect"),{id:"123-456",name:"Device"});
|
||||
resolve();
|
||||
}, false);
|
||||
}
|
64
extra/Pages/alert.js
Normal file
64
extra/Pages/alert.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { SFrame, _ } from "../../main.js";
|
||||
import { fadein, fadeout, subCancel } from "../../utils.js";
|
||||
|
||||
const call = async (stear, { find, resolve, render, call, event }, { text, titel = "" }) => {
|
||||
event.onloaded = () => {
|
||||
fadein(find.main, 200, true);
|
||||
find.btn._.focus();
|
||||
}
|
||||
event.onresolve = async () => await fadeout(find.main);
|
||||
|
||||
const cancel = subCancel(() => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
return _({
|
||||
find: "main",
|
||||
class: "stear_alert",
|
||||
style: {
|
||||
position: "fixed",
|
||||
left: "0",
|
||||
top: "0",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
backgroundColor: "rgba(0,0,0,0.5)"
|
||||
}
|
||||
}, _({
|
||||
style: {
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
padding: "1rem",
|
||||
paddingTop: "0",
|
||||
position: "absolute",
|
||||
backgroundColor: "#eee",
|
||||
minHeight: "4rem",
|
||||
minWidth: "8rem",
|
||||
borderRadius: "1rem",
|
||||
textAlign: "center"
|
||||
}
|
||||
}, [
|
||||
_({ type: "h2", style: { marginBottom: 0 } }, titel),
|
||||
_({ type: "p" }, text),
|
||||
_({
|
||||
type: "button",
|
||||
find: "btn",
|
||||
event: {
|
||||
click: () => {
|
||||
resolve(true);
|
||||
cancel();
|
||||
},
|
||||
input: (e) => {
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
style: {
|
||||
borderRadius: "0.5rem",
|
||||
}
|
||||
}, "OK"),
|
||||
]));
|
||||
}
|
||||
|
||||
export default new SFrame({
|
||||
preRender: true, call
|
||||
});
|
80
extra/Pages/prompt.js
Normal file
80
extra/Pages/prompt.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
import { SFrame, _ } from "../../main.js";
|
||||
import { fadein, fadeout, subCancel } from "../../utils.js";
|
||||
|
||||
const call = async (stear, { find, resolve, render, call, event }, { text, autoFill = "" }) => {
|
||||
event.onloaded = () => {
|
||||
fadein(find.main, 200, true);
|
||||
find.input._.focus();
|
||||
}
|
||||
event.onresolve = async () => await fadeout(find.main);
|
||||
|
||||
const cancel = subCancel(() => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
return _({
|
||||
find: "main",
|
||||
class: "stear_prompt",
|
||||
style: {
|
||||
position: "fixed",
|
||||
left: "0",
|
||||
top: "0",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
backgroundColor: "rgba(0,0,0,0.5)"
|
||||
}
|
||||
}, _({
|
||||
style: {
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
padding: "1rem",
|
||||
paddingTop: "0",
|
||||
position: "absolute",
|
||||
backgroundColor: "#eee",
|
||||
minHeight: "4rem",
|
||||
minWidth: "8rem",
|
||||
borderRadius: "1rem",
|
||||
textAlign: "center",
|
||||
display: "grid",
|
||||
gridGap: "0.5rem"
|
||||
}
|
||||
}, [
|
||||
_({ type: "p", style: { gridRow: "1", gridColumn: "1/3", marginBottom: "0" } }, text),
|
||||
_({
|
||||
type: "input",
|
||||
find: "input",
|
||||
attr: { type: "text" },
|
||||
event: {
|
||||
keydown: (e) => {
|
||||
if(e.code=="Enter")find.btn._.click();
|
||||
}
|
||||
},
|
||||
style: {
|
||||
height: "1rem",
|
||||
border: "2px solid",
|
||||
borderRadius: "0.5rem",
|
||||
gridRow: "2",
|
||||
padding:"0.5rem"
|
||||
}
|
||||
}, autoFill),
|
||||
_({
|
||||
type: "button",
|
||||
find: "btn",
|
||||
event: {
|
||||
click: () => {
|
||||
resolve(find.input._.value);
|
||||
cancel();
|
||||
}
|
||||
},
|
||||
style: {
|
||||
borderRadius: "0.5rem",
|
||||
gridRow: "2",
|
||||
}
|
||||
}, "OK"),
|
||||
]));
|
||||
};
|
||||
|
||||
export default new SFrame({
|
||||
preRender: true, call
|
||||
});
|
179
extra/Pages/showStatus.js
Normal file
179
extra/Pages/showStatus.js
Normal file
|
@ -0,0 +1,179 @@
|
|||
import { SFrame, Stear, _ } from "../../main.js";
|
||||
import { fadein, fadeout, wait } from "../../utils.js";
|
||||
|
||||
|
||||
Stear.addGlobalStyleJSON({
|
||||
position: "fixed",
|
||||
left: "50%",
|
||||
bottom: "1rem",
|
||||
transform: "translate(-50%, -50%)",
|
||||
textAlign: "center",
|
||||
border: `2px soild transparent`,
|
||||
borderRadius: "1rem",
|
||||
padding: "1rem",
|
||||
transition: "background-color 200ms",
|
||||
backgroundColor: "#212121",
|
||||
color:"#fafafa",
|
||||
webkitUserSelect: "none",
|
||||
|
||||
},".stear_status");
|
||||
|
||||
const statusList = [];
|
||||
var statusActive = false;
|
||||
|
||||
const call = async (stear, { find, resolve, render, close, call, event }, { text, color = "grey" }) => {
|
||||
statusList.push({ text, color, resolve });
|
||||
if (statusActive) return false;
|
||||
statusActive = true;;
|
||||
|
||||
event.onloaded = () => {
|
||||
fadein(find.main, 200, true);
|
||||
};
|
||||
event.onclose = async() => {
|
||||
await fadeout(find.main);
|
||||
};
|
||||
event.onBeforRerender = async() => {
|
||||
find.main.settings = { style: { backgroundColor: "#555" } };
|
||||
await wait(200);
|
||||
};
|
||||
event.onAfterRerender = async() => {
|
||||
find.main.settings = { style: { backgroundColor: "" } };
|
||||
};
|
||||
|
||||
var next = statusList.shift();
|
||||
|
||||
var timeoutId = setTimeout(nextMsg,3000);
|
||||
|
||||
var inProgress = false;
|
||||
|
||||
async function nextMsg(){
|
||||
if(inProgress)return;
|
||||
inProgress = true;
|
||||
if (timeoutId >= 0) clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
|
||||
next.resolve(null,false);
|
||||
next = statusList.shift();
|
||||
if(next == null){
|
||||
statusActive = false;
|
||||
close();
|
||||
return;
|
||||
}
|
||||
render(false);
|
||||
|
||||
timeoutId = setTimeout(nextMsg, 3000);
|
||||
inProgress = false;
|
||||
}
|
||||
|
||||
return (first = true)=>_({
|
||||
find: "main",
|
||||
class: "stear_status",
|
||||
style: {
|
||||
border: "2px solid " + next.color,
|
||||
backgroundColor: first ? "":"#555",
|
||||
userSelect:"none",
|
||||
cursor:"pointer"
|
||||
},
|
||||
event: { click: nextMsg }
|
||||
},next.text);
|
||||
}
|
||||
|
||||
/*const call = async (stear, { find, resolve, render, call, event }, { text, color="grey" }) => {
|
||||
|
||||
|
||||
async function loop(){
|
||||
last = next;
|
||||
next = statusList.shift();
|
||||
if (next == null) return finish();
|
||||
last.resolve(null, false);
|
||||
|
||||
find.main.settings = { style: { backgroundColor: "#555" } };
|
||||
await wait(200);
|
||||
find.main.settings = {
|
||||
style: {
|
||||
backgroundColor: "",
|
||||
border: "2px solid " + next.color
|
||||
}
|
||||
};
|
||||
find.main._.innerText = next.text;
|
||||
timeoutId = setTimeout(loop,3000);
|
||||
}
|
||||
var timeoutId = setTimeout(loop, 3000);
|
||||
find.main._.onclick = ()=>{
|
||||
if(timeoutId<0)return;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
loop();
|
||||
};
|
||||
|
||||
async function finish(){
|
||||
if (timeoutId >= 0)clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
statusActive = false;
|
||||
|
||||
await fadeout(find.main._);
|
||||
|
||||
last.resolve();
|
||||
}
|
||||
|
||||
}*/
|
||||
/*const call = async (stear, { find, resolve, render, call, event }, { text, color="grey" }) => {
|
||||
statusList.push({ text, color, resolve});
|
||||
if (statusActive) return false;
|
||||
statusActive = true;
|
||||
|
||||
var next = statusList.shift();
|
||||
var last;
|
||||
|
||||
find.main.settings = {style:{
|
||||
border: "2px solid " + next.color
|
||||
}};
|
||||
find.main._.innerText = next.text;
|
||||
|
||||
event.onloaded = () => fadein(find.main, 200, true);
|
||||
//find.main._.style.transition = "";
|
||||
|
||||
async function loop(){
|
||||
last = next;
|
||||
next = statusList.shift();
|
||||
if (next == null) return finish();
|
||||
last.resolve(null, false);
|
||||
|
||||
find.main.settings = { style: { backgroundColor: "#555" } };
|
||||
await wait(200);
|
||||
find.main.settings = {
|
||||
style: {
|
||||
backgroundColor: "",
|
||||
border: "2px solid " + next.color
|
||||
}
|
||||
};
|
||||
find.main._.innerText = next.text;
|
||||
timeoutId = setTimeout(loop,3000);
|
||||
}
|
||||
var timeoutId = setTimeout(loop, 3000);
|
||||
find.main._.onclick = ()=>{
|
||||
if(timeoutId<0)return;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
loop();
|
||||
};
|
||||
|
||||
async function finish(){
|
||||
if (timeoutId >= 0)clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
statusActive = false;
|
||||
|
||||
await fadeout(find.main._);
|
||||
|
||||
last.resolve();
|
||||
}
|
||||
|
||||
return _({
|
||||
find: "main",
|
||||
class: "stear_status",
|
||||
});
|
||||
}*/
|
||||
|
||||
export default new SFrame({
|
||||
preRender:true, call
|
||||
});
|
25
extra/Style/scrollBar1.js
Normal file
25
extra/Style/scrollBar1.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Stear } from "../../main.js";
|
||||
|
||||
export const scrollBarCss1 = ({ size = "5px", background = "transparent", thumbColor = "#33a", hoverColor ="#44f"}) => {
|
||||
return {
|
||||
"::-webkit-scrollbar":{
|
||||
width: size,
|
||||
height: size,
|
||||
},
|
||||
"::-webkit-scrollbar-track":{
|
||||
background: background,
|
||||
|
||||
},
|
||||
"::-webkit-scrollbar-thumb":{
|
||||
background: thumbColor,
|
||||
borderRadius: `calc(${size} / 2)`,
|
||||
},
|
||||
"::-webkit-scrollbar-thumb:hover":{
|
||||
background: hoverColor
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const applyScrollBarCss1 = ({ size = "5px", background = "transparent", thumbColor = "#33a", hoverColor = "#44f" } = {}) => {
|
||||
Object.entries(scrollBarCss1({ size, background, thumbColor, hoverColor })).forEach(([k,d])=>Stear.addGlobalStyleJSON(d,k));
|
||||
}
|
68
language.js
Normal file
68
language.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
export class LanguagePool {
|
||||
#pool = {};
|
||||
constructor() {
|
||||
|
||||
}
|
||||
addFile(elems, lang) {
|
||||
Object.entries(elems).forEach(([k, d]) => {
|
||||
if (typeof this.#pool[k] == "undefined") {
|
||||
this.#pool[k] = new LanguagePoolString();
|
||||
}
|
||||
this.#pool[k].set(d, lang);
|
||||
|
||||
});
|
||||
}
|
||||
set lang(lang) {
|
||||
Object.entries(this.#pool).forEach(([k, d]) => {
|
||||
d.lang = lang;
|
||||
})
|
||||
}
|
||||
get getFile() {
|
||||
var out = {};
|
||||
Object.entries(this.#pool).forEach(([k, d]) => {
|
||||
out[k] = d.get("default");
|
||||
});
|
||||
return out;
|
||||
}
|
||||
add(tag, defaultText = "") {
|
||||
let newS = typeof this.#pool[tag] == "undefined" ? new LanguagePoolString() : this.#pool[tag];
|
||||
this.#pool[tag] = newS;
|
||||
newS.set(defaultText, "default");
|
||||
return newS;
|
||||
}
|
||||
get(tag) {
|
||||
return this.#pool[tag];
|
||||
}
|
||||
}
|
||||
|
||||
export class LanguagePoolString {
|
||||
#value = {
|
||||
|
||||
};
|
||||
#lang = "en";
|
||||
constructor() { }
|
||||
|
||||
set(v, lang) {
|
||||
this.#value[lang] = v;
|
||||
}
|
||||
|
||||
get(lang) {
|
||||
return this.#value[lang];
|
||||
}
|
||||
|
||||
set lang(lang) {
|
||||
this.#lang = lang;
|
||||
}
|
||||
|
||||
r(...str) {
|
||||
var out = this.#value[this.#lang] == null ? this.#value.default : this.#value[this.#lang];
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
out = out.replace("{}", str[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
toString() {
|
||||
return this.#value[this.#lang] == null ? this.#value.default : this.#value[this.#lang];
|
||||
}
|
||||
}
|
770
main.js
Normal file
770
main.js
Normal file
|
@ -0,0 +1,770 @@
|
|||
import { LanguagePool, LanguagePoolString } from "./language.js"
|
||||
var counter = 0;
|
||||
|
||||
var globalStyle = document.createElement("style");
|
||||
document.head.appendChild(globalStyle);
|
||||
|
||||
String.prototype.map = Array.prototype.map;
|
||||
|
||||
function toCssAttr(txt) {
|
||||
return txt.map(d => (d.toUpperCase() === d && d !== d.toLowerCase()) ? "-" + d.toLowerCase() : d).join("");
|
||||
};
|
||||
|
||||
class callPromise extends Promise {
|
||||
#opts = {};
|
||||
constructor(cb) {
|
||||
super(cb);
|
||||
};
|
||||
set opts(opts) {
|
||||
this.#opts = opts;
|
||||
}
|
||||
get opts() {
|
||||
return this.#opts;
|
||||
}
|
||||
}
|
||||
|
||||
const pools = {
|
||||
|
||||
};
|
||||
|
||||
const stears = [];
|
||||
|
||||
/** Stear class */
|
||||
export class Stear {
|
||||
|
||||
elem;
|
||||
#childs = {};
|
||||
#frames = [];
|
||||
|
||||
/**
|
||||
* Creating a Stear class. It can be used to render "stear" in an Element.
|
||||
*
|
||||
* @param {HTMLElement} elem
|
||||
*/
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
elem.style.position = "relative";
|
||||
stears.push(this);
|
||||
}
|
||||
destroy() {
|
||||
let i = stears.indexOf(this);
|
||||
if (i == -1) return;
|
||||
stears.splice(i, 1);
|
||||
delete this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the Style of the render Element.
|
||||
*
|
||||
* @param {JSON} css
|
||||
*/
|
||||
style(css) {
|
||||
Object.entries(css).forEach(([k, d]) => {
|
||||
this.elem.style[k] = d;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* An Store for Frames
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {SFrame} elem
|
||||
*/
|
||||
addElement(id, elem) {
|
||||
if (!(elem instanceof SFrame)) throw new TypeError("Cannot add Element not extending from SFrame");
|
||||
this.#childs[id] = elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access an Element from the Frame Store
|
||||
*
|
||||
* @param {string} id
|
||||
* @returns {SFrame}
|
||||
*/
|
||||
getElement(id) {
|
||||
return this.g(id);
|
||||
}
|
||||
|
||||
g(id) {
|
||||
return this.#childs[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an Element gloabal.
|
||||
*
|
||||
* @param {SFrame} elem
|
||||
* @param {*} args
|
||||
* @param {number} layer
|
||||
* @returns {callPromise}
|
||||
*/
|
||||
async call(elem, args, layer = 1) {
|
||||
return await elem.call(this, args, this.#frames, layer);
|
||||
}
|
||||
|
||||
async callInParent(elem, args, layer, renderParent = this.elem) {
|
||||
return await elem.call(this, args, this.#frames, layer, renderParent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an Element in annother Element.
|
||||
*
|
||||
* @param {SFrame} elem
|
||||
* @param {*} args
|
||||
* @param {HTMLElement} renderParent
|
||||
* @param {number} layer
|
||||
* @returns {callPromise}
|
||||
*/
|
||||
include(elem, args, renderParent, layer = 1) {
|
||||
return elem.call(this, args, this.#frames, layer, renderParent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rernder everthing.
|
||||
*
|
||||
* @param {*} arg
|
||||
* @returns {Promise}
|
||||
*/
|
||||
rerenderGlobal(arg) {
|
||||
return new Promise((res, rej) => {
|
||||
if (this.#frames.length == 0) return void res();
|
||||
let running = this.#frames.length;
|
||||
for (let i = 0; i < this.#frames.length; i++) {
|
||||
const element = this.#frames[i];
|
||||
element.globalRenderRequest(arg)
|
||||
.then(() => {
|
||||
running--;
|
||||
if (running == 0) res();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw css Data.
|
||||
*
|
||||
* @param {string} text
|
||||
*/
|
||||
static addGlobalStyleText(text) {
|
||||
globalStyle.innerHTML += "\n" + text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a css Animation
|
||||
*
|
||||
* @param {object} steps - css like json Syntax
|
||||
* @param {string} name
|
||||
* @returns {string} name
|
||||
*/
|
||||
static addAnimation(steps, name = "stearAnimation_" + counter++) {
|
||||
Stear.addGlobalStyleText(`@keyframes ${name} {
|
||||
${Object.entries(steps).map(([k, d]) =>
|
||||
` ${k} {
|
||||
${Object.entries(d).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").join("\n")}
|
||||
}`).join("\n")
|
||||
}
|
||||
}`);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} json - css like json Syntax
|
||||
* @param {string} name - e.g. .classname
|
||||
* @returns {string} name
|
||||
*/
|
||||
static addGlobalStyleJSON(json, name = ".stearClass_" + counter++) {
|
||||
Stear.addGlobalStyleText(`
|
||||
${name} {
|
||||
${Object.entries(json).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").join("\n")}
|
||||
}
|
||||
`)
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add A Language Pool. E.g. for a subpage.
|
||||
*
|
||||
* @param {string} name
|
||||
* @returns {LanguagePool}
|
||||
*/
|
||||
static addLanguagePool(name) {
|
||||
if (typeof pools[name] == "undefined") {
|
||||
pools[name] = new LanguagePool();
|
||||
}
|
||||
return pools[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file containing translations.
|
||||
*
|
||||
* @param {JSON} data
|
||||
* @param {string} lang
|
||||
*/
|
||||
static addLanguageFile(data, lang) {
|
||||
Object.entries(data).forEach(([k, d]) => {
|
||||
if (typeof pools[k] == "undefined") pools[k] = new LanguagePool();
|
||||
pools[k].addFile(d, lang);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Used Language
|
||||
*/
|
||||
static set lang(lang) {
|
||||
Object.entries(pools).forEach(([k, d]) => {
|
||||
d.lang = lang;
|
||||
});
|
||||
stears.forEach(s => s.rerenderGlobal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Language File with defaults
|
||||
*/
|
||||
static get getLanguageFile() {
|
||||
var out = {};
|
||||
Object.entries(pools).forEach(([k, d]) => {
|
||||
out[k] = d.getFile;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//utils
|
||||
/**
|
||||
* Can be called to close a frame and return a response.
|
||||
* @async
|
||||
* @callback utilsResolveCallback
|
||||
* @param {*} returnValue
|
||||
* @param {boolean} close
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remove this Frame from Screen
|
||||
* @async
|
||||
* @callback utilsCloseCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rerender the local Content
|
||||
* @async
|
||||
* @callback utilsRenderCallback
|
||||
* @param {...*} args
|
||||
* @return {objectt} find
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open and run another frame with the ability to return data.
|
||||
* @async
|
||||
* @callback utilsCallCallback
|
||||
* @param {SFrame} elem
|
||||
* @param {*} [args={}]
|
||||
* @param {boolean} [global=true]
|
||||
* @return {callPromise}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Embet another Frame
|
||||
* @async
|
||||
* @callback utilsIncludeCallback
|
||||
* @param {SFrame} elem
|
||||
* @param {*} args
|
||||
* @return {includeFrame}
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//eventCallbacks
|
||||
/**
|
||||
* Called when Page is fully loaded.
|
||||
* @callback eventOnLoadedCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called and awaited bevor resolving.
|
||||
* @async
|
||||
* @callback eventOnResolveCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called and awaited bevor closing.
|
||||
* @async
|
||||
* @callback eventOnCloseCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called and awaited bevor rerendering.
|
||||
* @async
|
||||
* @callback eventOnBeforRerenderCallback
|
||||
* @param {...*} args - any given param
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called and awaited after rerendering.
|
||||
* @async
|
||||
* @callback eventOnAfterRerenderCallback
|
||||
* @param {...*} args - any given param
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called when included in another Frame and that Frame rerenders.
|
||||
* @callback eventOnParentRenderCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Will be called when included in another Frame and that Frame rerenders.
|
||||
* @callback eventOnGlobalRenderCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef callUtils
|
||||
* @type {Object}
|
||||
* @property {Object} find - find an element in local tree
|
||||
* @property {utilsResolveCallback} resolve - Return the Data
|
||||
* @property {utilsCloseCallback} close - Close the Frame
|
||||
* @property {utilsRenderCallback} render - Rerender the Frame
|
||||
* @property {utilsCallCallback} call - Use another Frame
|
||||
* @property {utilsIncludeCallback} include - Include another Frame
|
||||
* @property {Object} event - local Events
|
||||
* @property {eventOnLoadedCallback} event.onloaded
|
||||
* @property {eventOnResolveCallback} event.onresolve
|
||||
* @property {eventOnCloseCallback} event.close
|
||||
* @property {eventOnBeforRerenderCallback} event.onBeforRerender
|
||||
* @property {eventOnAfterRerenderCallback} event.onAfterRerender
|
||||
* @property {eventOnParentRenderCallback} event.onParentRender
|
||||
* @property {eventOnGlobalRenderCallback} event.onGlobalRenderRequest
|
||||
*/
|
||||
|
||||
/**
|
||||
* This callback will be called, when a frame should be opened.
|
||||
* @callback callCallback
|
||||
* @param {Stear} stear
|
||||
* @param {callUtils} utils - lots of utils for Frame manipulation
|
||||
* @param {*} args
|
||||
*/
|
||||
|
||||
/**
|
||||
* SFrame class
|
||||
*/
|
||||
export class SFrame {
|
||||
#preRender;
|
||||
#call;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} args
|
||||
* @param {callCallback} args.call
|
||||
* @param {boolean} [args.preRender]
|
||||
*/
|
||||
constructor({ call, preRender = true }) {
|
||||
this.#preRender = preRender;
|
||||
this.#call = call;
|
||||
}
|
||||
|
||||
call(stear, args, frames, layer = 1, renderParent = stear.elem) {
|
||||
let lastRender;
|
||||
let renderElem;
|
||||
|
||||
let event = { onloaded: () => { }, onclose: () => { }, onresolve: () => { }, onBeforRerender: () => { }, onAfterRerender: () => { }, onParentRender: () => { }, onGlobalRenderRequest: () => true };
|
||||
let find = {};
|
||||
|
||||
let resolved = false;
|
||||
|
||||
async function render(args) {
|
||||
if (!renderElem) return;
|
||||
//if (lastRender) if ([...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._);
|
||||
let now = renderElem;
|
||||
if (typeof now == "function") {
|
||||
if (lastRender) if ([...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._);
|
||||
now = await now();
|
||||
}
|
||||
if (!(now instanceof class_)) throw new Error("The Element to render is not an instance of class_");
|
||||
await now.build(args);
|
||||
|
||||
now.render
|
||||
if (!lastRender || ![...(renderParent.children)].includes(lastRender._)) renderParent.appendChild(now._);
|
||||
lastRender = now;
|
||||
|
||||
now._.style.zIndex = layer;
|
||||
|
||||
for (var member in find) delete find[member];
|
||||
Object.assign(find, now.find);
|
||||
return lastRender;
|
||||
}
|
||||
|
||||
const ppp = new callPromise(async (res, rej) => {
|
||||
const globalRegister = {
|
||||
globalRenderRequest: async (...args) => {
|
||||
const arg = await event.onGlobalRenderRequest(...args);
|
||||
if (arg === false) return;
|
||||
await options.render(arg);
|
||||
}
|
||||
}
|
||||
frames.push(globalRegister);
|
||||
const options = {
|
||||
find,
|
||||
render: async (...args) => {
|
||||
await event.onBeforRerender(...args);
|
||||
if (renderElem) await render(args);
|
||||
firstRender = true;
|
||||
await event.onAfterRerender(...args);
|
||||
return find;
|
||||
},
|
||||
resolve: async (r, close = true) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
await event.onresolve();
|
||||
if (close && lastRender && [...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._);
|
||||
let i = frames.indexOf(globalRegister);
|
||||
if (i > -1) frames.splice(i, 1);
|
||||
res(r);
|
||||
},
|
||||
call: (elem, args = {}, global = true) => {
|
||||
if (global) return stear.call(elem, args, layer + 1);
|
||||
else return stear.callInParent(elem, args, layer + 1, renderParent);
|
||||
},
|
||||
close: async () => {
|
||||
await event.onclose();
|
||||
if (lastRender && [...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._);
|
||||
},
|
||||
include: (frame, args = {}) => {
|
||||
let iFrame = new includeFrame(stear, frame, layer + 1, args);
|
||||
return iFrame;
|
||||
},
|
||||
event,
|
||||
};
|
||||
window.queueMicrotask(() => ppp.opts = options);
|
||||
let firstRender = false;
|
||||
renderElem = await this.#call(stear, options, args);
|
||||
if (!renderElem) {
|
||||
|
||||
} else {
|
||||
if (this.#preRender | firstRender) await render([]);
|
||||
event.onloaded();
|
||||
}
|
||||
});
|
||||
return ppp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Create a SWindow, a Fullscreen Frame. */
|
||||
export class SWindow extends SFrame {
|
||||
|
||||
#Frame;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} args
|
||||
* @param {callCallback} args.call
|
||||
* @param {boolean} [args.preRender]
|
||||
*/
|
||||
constructor({ call, preRender = true, backgroundColor = "transparent" }) {
|
||||
/*var Frame = _({
|
||||
style: {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "block",
|
||||
backgroundColor,
|
||||
//overflow:"scroll"
|
||||
},
|
||||
find:"main"
|
||||
}, []);*/
|
||||
super({
|
||||
call: async (...args) => _({
|
||||
style: {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "block",
|
||||
backgroundColor,
|
||||
//overflow:"scroll"
|
||||
},
|
||||
find: "main"
|
||||
}, await call(...args)),
|
||||
preRender
|
||||
});
|
||||
//this.#Frame = Frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef renderNodeSettings
|
||||
* @type {Object}
|
||||
* @property {string}[type]
|
||||
* @property {string}[find]
|
||||
* @property {Object}[event]
|
||||
* @property {Object}[attr]
|
||||
*/
|
||||
|
||||
/** Create a Render node, */
|
||||
export class class_ {
|
||||
#elem;
|
||||
#childs;
|
||||
#build;
|
||||
#find;
|
||||
#doBuild;
|
||||
|
||||
#dynamicState = 0;
|
||||
|
||||
#dynamicStyle = {};
|
||||
|
||||
/**
|
||||
* Generate a new Stear render Node.
|
||||
*
|
||||
* @param {renderNodeSettings} settings
|
||||
* @param {Array} childs
|
||||
* @param {boolean} doBuild
|
||||
*/
|
||||
constructor(settings, childs, doBuild = true) {
|
||||
const type = settings.type ?? "div";
|
||||
if((["circle", "ellipse", "line", "path", "polygon", "polyline", "rect","svg" ]).includes(type))
|
||||
this.#elem = document.createElementNS("http://www.w3.org/2000/svg",type);
|
||||
else this.#elem = document.createElement(type);
|
||||
this.#childs = childs;
|
||||
var keys = Object.keys(settings);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (key == "type") { } else if (key == "style") {
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
if (typeof d == "function") this.#dynamicStyle[k] = d;
|
||||
else this.#elem.style[k] = d;
|
||||
});
|
||||
} else if (key == "find") {
|
||||
this.#find = settings[key];
|
||||
} else if (key == "event") {
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
this.#elem.addEventListener(k, d);
|
||||
});
|
||||
} else if (key == "attr") {
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
this.#elem.setAttribute(k, d);
|
||||
});
|
||||
} else {
|
||||
this.#elem.setAttribute(key, settings[key]);
|
||||
}
|
||||
}
|
||||
this.#doBuild = doBuild;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} childs
|
||||
*/
|
||||
set childs(childs) {
|
||||
if (!this.#doBuild) return;
|
||||
this.#childs = Array.isArray(childs) ? childs : [childs];
|
||||
this.#dynamicState = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {renderNodeSettings} settings
|
||||
*/
|
||||
set settings(settings) {
|
||||
var keys = Object.keys(settings);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (key == "type") { } else if (key == "style") {
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
this.#elem.style[k] = d;
|
||||
});
|
||||
} else if (key == "find") {
|
||||
this.#find = settings[key];
|
||||
} else {
|
||||
this.#elem.setAttribute(key, settings[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateDynamicStyle(args) {
|
||||
for (const key in this.#dynamicStyle) {
|
||||
this.#elem.style[key] = await this.#dynamicStyle[key](args);
|
||||
}
|
||||
}
|
||||
|
||||
async #syncBuild(args) {
|
||||
for (let i = 0; i < this.#childs.length; i++) {
|
||||
let elem = this.#childs[i];
|
||||
|
||||
if (Array.isArray(elem)) {
|
||||
for (let j = 0; j < elem.length; j++) {
|
||||
if (elem[j] instanceof class_) await elem[j].build(args);
|
||||
}
|
||||
} else {
|
||||
if (elem instanceof class_) await elem.build(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Stear Structure
|
||||
*
|
||||
* @param {*} args
|
||||
*/
|
||||
async build(args) {
|
||||
if (!this.#doBuild) return;
|
||||
this.updateDynamicStyle(args);
|
||||
if (this.#dynamicState < 0) return void await this.#syncBuild(args);
|
||||
this.#build = [];
|
||||
for (let i = 0; i < this.#childs.length; i++) {
|
||||
let elem = this.#childs[i];
|
||||
|
||||
if (typeof elem == "function") {
|
||||
elem = (await elem(...args)) ?? [];
|
||||
this.#dynamicState = 2;
|
||||
}
|
||||
|
||||
if (Array.isArray(elem)) {
|
||||
for (let j = 0; j < elem.length; j++) {
|
||||
if (elem[j] instanceof class_) await elem[j].build(args);
|
||||
}
|
||||
this.#build.push(...elem);
|
||||
} else {
|
||||
if (elem instanceof class_) await elem.build(args);
|
||||
this.#build.push(elem);
|
||||
}
|
||||
}
|
||||
if (this.#dynamicState <= 0) this.#dynamicState = -1;
|
||||
}
|
||||
|
||||
#syncRender() {
|
||||
let out = [];
|
||||
for (let i = 0; i < this.#build.length; i++) {
|
||||
const elem = this.#build[i];
|
||||
if (typeof elem != "string" && !(elem instanceof LanguagePoolString)) {
|
||||
out[i] = elem.render;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genereate HTML Structure
|
||||
*
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
get render() {
|
||||
if (!this.#doBuild) return this.#elem;
|
||||
if (this.#dynamicState < -1) {
|
||||
this.#syncRender();
|
||||
return this.#elem;
|
||||
}
|
||||
let out = [];
|
||||
let needReplace = false;
|
||||
for (let i = 0; i < this.#build.length; i++) {
|
||||
const elem = this.#build[i];
|
||||
if (typeof elem == "string" || elem instanceof LanguagePoolString) {
|
||||
out[i] = document.createTextNode(String(elem));
|
||||
} else {
|
||||
out[i] = elem.render;
|
||||
}
|
||||
if (!needReplace && this.#elem.children[i] != out[i]) needReplace = true;
|
||||
}
|
||||
if (needReplace||out.length==0) this.#elem.replaceChildren(...out);
|
||||
if (this.#dynamicState < 0) this.#dynamicState = -2;
|
||||
return this.#elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
get _() {
|
||||
return this.#elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerender only this and child nodes.
|
||||
* @param {any[]} args Arguments, that should be given all render methodes
|
||||
*/
|
||||
async rerender(args = []) {
|
||||
await this.build(args);
|
||||
this.render;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns find Object
|
||||
*
|
||||
* @return {Object} find
|
||||
*/
|
||||
get find() {
|
||||
var out = {};
|
||||
if (this.#doBuild) {
|
||||
this.#build.forEach(d => {
|
||||
Object.assign(out, d.find);
|
||||
});
|
||||
}
|
||||
if (this.#find) out[this.#find] = this;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {renderNodeSettings} [settings]
|
||||
* @param {Array} [childs]
|
||||
* @returns {class_}
|
||||
*/
|
||||
export const _ = (settings = {}, childs = []) => new class_(settings, Array.isArray(childs) ? childs : [childs]);
|
||||
export const s = (type, settings, ...childs) => {
|
||||
settings = settings ?? {};
|
||||
settings.type = type;
|
||||
return new class_(settings, childs);
|
||||
}
|
||||
|
||||
/** includeFrame */
|
||||
class includeFrame {
|
||||
#elem;
|
||||
#call;
|
||||
/**
|
||||
* Call another Frame and generate an includeFrame.
|
||||
*
|
||||
* @param {Stear} stear
|
||||
* @param {SFrame} frame
|
||||
* @param {number} layer
|
||||
* @param {*} args
|
||||
*/
|
||||
constructor(stear, frame, layer, args = {}) {
|
||||
this.#elem = new class_({}, [], false);
|
||||
this.#call = stear.include(frame, args, this.#elem._, layer);
|
||||
this.#call.then(() => {
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {callUtils} utils from included Frame
|
||||
*/
|
||||
get opts() {
|
||||
return this.#call.opts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the included Frame.
|
||||
*/
|
||||
close() {
|
||||
if (this.#call) {
|
||||
this.#call.opts.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger onParentRender event
|
||||
*
|
||||
* @param {*} settings
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
render(settings = {}) {
|
||||
this.#elem.settings = settings;
|
||||
this.#call.opts.event.onParentRender();
|
||||
return this.#elem;
|
||||
}
|
||||
|
||||
};
|
|
@ -1,53 +0,0 @@
|
|||
import { SFrame, _ } from "../../main.js";
|
||||
import { fadein, fadeout } from "../../utils.js";
|
||||
|
||||
const preRender = false;
|
||||
|
||||
const render = ({ }, {titel,text,callback}) => {
|
||||
|
||||
return _({
|
||||
find:"main",
|
||||
class:"stear_alert",
|
||||
style: {
|
||||
position:"fixed",
|
||||
left: "0",
|
||||
top: "0",
|
||||
height:"100%",
|
||||
width:"100%",
|
||||
backgroundColor:"rgba(0,0,0,0.5)"
|
||||
}
|
||||
}, _({
|
||||
style:{
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
padding: "1rem",
|
||||
paddingTop: "0",
|
||||
position: "absolute",
|
||||
backgroundColor: "#eee",
|
||||
minHeight: "4rem",
|
||||
minWidth: "8rem",
|
||||
borderRadius: "1rem",
|
||||
textAlign: "center"
|
||||
}
|
||||
}, [
|
||||
_({ type: "h2", style: { marginBottom: 0 }}, titel),
|
||||
_({ type: "p"}, text),
|
||||
_({ type: "button", find:"btn", event: {click: callback}, style:{
|
||||
borderRadius:"0.5rem",
|
||||
}},"OK"),
|
||||
]));
|
||||
}
|
||||
|
||||
const call = async (stear, { find, resolve, render, call }, {text,titel=""}) => {
|
||||
render({titel,text,callback:()=>{
|
||||
resolve();
|
||||
fadeout(find.main._);
|
||||
}});
|
||||
await fadein (find.main._, 200, true);
|
||||
find.btn._.focus();
|
||||
}
|
||||
|
||||
export default new SFrame({
|
||||
preRender, render, call
|
||||
});
|
|
@ -1,87 +0,0 @@
|
|||
import { SFrame, Stear, _ } from "../../main.js";
|
||||
import { fadein, fadeout, wait } from "../../utils.js";
|
||||
|
||||
const preRender = true;
|
||||
|
||||
Stear.addGlobalStyleJSON({
|
||||
position: "fixed",
|
||||
left: "50%",
|
||||
bottom: "1rem",
|
||||
transform: "translate(-50%, -50%)",
|
||||
textAlign: "center",
|
||||
border: `2px soild transparent`,
|
||||
borderRadius: "1rem",
|
||||
padding: "1rem",
|
||||
transition: "background-color 200ms",
|
||||
backgroundColor: "#212121",
|
||||
color:"#fafafa",
|
||||
webkitUserSelect: "none",
|
||||
|
||||
},".stear_status");
|
||||
|
||||
const render = ({ }, { }) => {
|
||||
|
||||
return _({
|
||||
find:"main",
|
||||
class:"stear_status",
|
||||
});
|
||||
}
|
||||
|
||||
const statusList = [];
|
||||
var statusActive = false;
|
||||
|
||||
const call = async (stear, { find, resolve, render, call }, { text, color="grey" }) => {
|
||||
statusList.push({ text, color, resolve});
|
||||
if (statusActive) return;
|
||||
statusActive = true;
|
||||
|
||||
var next = statusList.shift();
|
||||
var last;
|
||||
|
||||
find.main.settings = {style:{
|
||||
border: "2px solid " + next.color
|
||||
}};
|
||||
find.main._.innerText = next.text;
|
||||
|
||||
await fadein(find.main._, 200, true);
|
||||
find.main._.style.transition = "";
|
||||
|
||||
async function loop(){
|
||||
last = next;
|
||||
next = statusList.shift();
|
||||
if (next == null) return finish();
|
||||
last.resolve(null, false);
|
||||
|
||||
find.main.settings = { style: { backgroundColor: "#555" } };
|
||||
await wait(200);
|
||||
find.main.settings = {
|
||||
style: {
|
||||
backgroundColor: "",
|
||||
border: "2px solid " + next.color
|
||||
}
|
||||
};
|
||||
find.main._.innerText = next.text;
|
||||
timeoutId = setTimeout(loop,3000);
|
||||
}
|
||||
var timeoutId = setTimeout(loop, 3000);
|
||||
find.main._.onclick = ()=>{
|
||||
if(timeoutId<0)return;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
loop();
|
||||
};
|
||||
|
||||
async function finish(){
|
||||
if (timeoutId >= 0)clearTimeout(timeoutId);
|
||||
timeoutId = -1;
|
||||
statusActive = false;
|
||||
|
||||
await fadeout(find.main._);
|
||||
|
||||
last.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export default new SFrame({
|
||||
preRender, render, call
|
||||
});
|
227
stear/main.js
227
stear/main.js
|
@ -1,227 +0,0 @@
|
|||
var counter = 0;
|
||||
|
||||
var globalStyle = document.createElement("style");
|
||||
document.head.appendChild(globalStyle);
|
||||
|
||||
String.prototype.map = Array.prototype.map;
|
||||
|
||||
function toCssAttr(txt){
|
||||
return txt.map(d => (d.toUpperCase() === d && d !== d.toLowerCase()) ? "-" + d.toLowerCase(): d ).join("");
|
||||
}
|
||||
|
||||
export class Stear{
|
||||
|
||||
elem;
|
||||
#childs = {};
|
||||
|
||||
constructor(elem){
|
||||
this.elem = elem;
|
||||
elem.style.position="relative";
|
||||
}
|
||||
|
||||
style(css){
|
||||
Object.entries(css).forEach(([k, d]) => {
|
||||
this.elem.style[k] = d;
|
||||
});
|
||||
}
|
||||
|
||||
addElement (id,elem){
|
||||
if(!(elem instanceof SFrame))throw new TypeError("Cannot add Element not extending from SFrame");
|
||||
this.#childs[id] = elem;
|
||||
}
|
||||
|
||||
getElement (id) {
|
||||
return this.g(id);
|
||||
}
|
||||
|
||||
g(id){
|
||||
return this.#childs[id];
|
||||
}
|
||||
|
||||
async call (elem, args, layer = 1){
|
||||
return await elem.call(this, args, layer);
|
||||
}
|
||||
|
||||
static addGlobalStyleText(text){
|
||||
globalStyle.innerHTML+="\n"+text;
|
||||
}
|
||||
|
||||
static addAnimation(steps, name = "stearAnimation_" + counter++){
|
||||
Stear.addGlobalStyleText(`@keyframes ${name} {
|
||||
${
|
||||
Object.entries(steps).map(([k,d])=>
|
||||
` ${k} {
|
||||
${Object.entries(d).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").join("\n")}
|
||||
}`).join("\n")
|
||||
}
|
||||
}`);
|
||||
|
||||
return name;
|
||||
}
|
||||
static addGlobalStyleJSON(json, name = ".stearClass_" + counter++){
|
||||
Stear.addGlobalStyleText(`
|
||||
${name} {
|
||||
${Object.entries(json).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").join("\n")}
|
||||
}
|
||||
`)
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
export class SFrame{
|
||||
#preRender;
|
||||
#render;
|
||||
#call;
|
||||
|
||||
#lastRender;
|
||||
constructor({ preRender, render, call }){
|
||||
this.#preRender = preRender;
|
||||
this.#render = render;
|
||||
this.#call = call;
|
||||
if(this.#preRender){
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
render(args={}){
|
||||
this.#lastRender = this.#render({}, args);
|
||||
this.#lastRender.render;
|
||||
return this.#lastRender;
|
||||
}
|
||||
|
||||
async call(stear, args, layer = 1){
|
||||
if(this.#preRender){
|
||||
stear.elem.appendChild(this.#lastRender._);
|
||||
this.#lastRender._.style.zIndex = layer;
|
||||
}
|
||||
var find = (this.#lastRender?.find) ?? {};
|
||||
return new Promise((res,rej)=>{
|
||||
this.#call(stear,{
|
||||
find,
|
||||
render: (args) => {
|
||||
this.render(args);
|
||||
for (var member in find) delete find[member];
|
||||
Object.assign(find, (this.#lastRender?.find) ?? {});
|
||||
if ([...(stear.elem.children)].indexOf(this.#lastRender._) >= 0) stear.elem.removeChild(this.#lastRender._);
|
||||
stear.elem.appendChild(this.#lastRender._);
|
||||
this.#lastRender._.style.zIndex = layer;
|
||||
return find;
|
||||
},
|
||||
resolve: (r,close=true)=>{
|
||||
if (close&&[...(stear.elem.children)].indexOf(this.#lastRender._) >= 0) stear.elem.removeChild(this.#lastRender._);
|
||||
res(r);
|
||||
},
|
||||
call: (elem, args)=>{
|
||||
return stear.call(elem,args,layer+1);
|
||||
}
|
||||
}, args);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class SWindow extends SFrame{
|
||||
|
||||
#Frame;
|
||||
|
||||
constructor({ preRender, render, call, backgroundColor = "transparent"}){
|
||||
var Frame = _({
|
||||
style: {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "block",
|
||||
backgroundColor,
|
||||
overflow:"scroll"
|
||||
},
|
||||
find:"main"
|
||||
}, []);
|
||||
super({
|
||||
preRender, render: (settings, args) => {
|
||||
Frame.childs = [render(settings, args)];
|
||||
return Frame;
|
||||
}, call
|
||||
});
|
||||
this.#Frame = Frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class class_ {
|
||||
#elem;
|
||||
#childs;
|
||||
#find;
|
||||
|
||||
constructor(settings,childs){
|
||||
this.#elem = document.createElement(settings.type ?? "div");
|
||||
this.#childs = childs;
|
||||
var keys = Object.keys(settings);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if(key == "type"){} else if (key == "style"){
|
||||
Object.entries(settings[key]).forEach(([k,d])=>{
|
||||
this.#elem.style[k] = d;
|
||||
});
|
||||
} else if (key == "find"){
|
||||
this.#find = settings[key];
|
||||
} else if (key == "event"){
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
this.#elem.addEventListener(k,d);
|
||||
});
|
||||
} else {
|
||||
this.#elem.setAttribute(key,settings[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set childs(childs){
|
||||
this.#childs = Array.isArray(childs) ? childs : [childs];
|
||||
}
|
||||
|
||||
set settings(settings){
|
||||
var keys = Object.keys(settings);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (key == "type") { } else if (key == "style") {
|
||||
Object.entries(settings[key]).forEach(([k, d]) => {
|
||||
this.#elem.style[k] = d;
|
||||
});
|
||||
} else if (key == "find") {
|
||||
this.#find = settings[key];
|
||||
} else {
|
||||
this.#elem.setAttribute(key, settings[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get render (){
|
||||
this.#elem.innerHTML = "";
|
||||
for (let i = 0; i < this.#childs.length; i++) {
|
||||
const elem = this.#childs[i];
|
||||
if(typeof elem == "string"){
|
||||
this.#elem.appendChild(document.createTextNode(elem));
|
||||
}else{
|
||||
this.#elem.appendChild(elem.render);
|
||||
}
|
||||
}
|
||||
return this.#elem;
|
||||
}
|
||||
|
||||
get _ (){
|
||||
return this.#elem;
|
||||
}
|
||||
|
||||
get find (){
|
||||
var out = {};
|
||||
this.#childs.forEach(d=>{
|
||||
Object.assign(out,d.find);
|
||||
});
|
||||
if (this.#find) out[this.#find]=this;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
export const _ = (settings = {}, childs = []) => new class_(settings, Array.isArray(childs) ? childs : [childs]);
|
||||
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
export const wait = (ms) => {
|
||||
return new Promise((res, rej) => {
|
||||
setTimeout(res, ms);
|
||||
});
|
||||
}
|
||||
|
||||
export const fadeout = async (elems, ms = 200, force = false) => {
|
||||
if (!Array.isArray(elems)) elems = [elems];
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.transition = `opacity ${ms}ms`;
|
||||
if(force){
|
||||
elems[i].style.opacity = "1";
|
||||
elems[i].style.display = "";
|
||||
}
|
||||
}
|
||||
await wait(10);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.opacity = "0";
|
||||
}
|
||||
await wait(ms);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
export const fadein = async (elems, ms = 200, force = false) => {
|
||||
if (!Array.isArray(elems)) elems = [elems];
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.transition = `opacity ${ms}ms`;
|
||||
elems[i].style.display = "";
|
||||
if (force) {
|
||||
elems[i].style.opacity = "0";
|
||||
}
|
||||
}
|
||||
await wait(10);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.opacity = "1";
|
||||
}
|
||||
await wait(ms);
|
||||
}
|
||||
|
||||
var bStack = [];
|
||||
export const subCancel = (callback) => {
|
||||
bStack.push(callback);
|
||||
return ()=>{
|
||||
var id;
|
||||
if ((id = bStack.indexOf(callback)) >= 0) {
|
||||
bStack.splice(id, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
if (bStack.length) {
|
||||
bStack.pop()();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("backbutton", back, false);
|
||||
document.addEventListener('keyup', (e)=>{
|
||||
if (e.code == "Escape")back();
|
||||
});
|
103
utils.js
Normal file
103
utils.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
import { class_ } from "./main.js";
|
||||
|
||||
/**
|
||||
* async wait/pause function
|
||||
*
|
||||
* @param {number} ms
|
||||
* @returns
|
||||
*/
|
||||
export const wait = (ms) => {
|
||||
return new Promise((res, rej) => {
|
||||
setTimeout(res, ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* fadeout an Element.
|
||||
*
|
||||
* @param {HTMLElement|class_} Selems Element ot fade
|
||||
* @param {number} [ms] Duration in ms
|
||||
* @param {boolean} [force]
|
||||
*/
|
||||
export const fadeout = async (Selems, ms = 200, force = false) => {
|
||||
var oldTrans = [];
|
||||
if (!Array.isArray(Selems)) Selems = [Selems];
|
||||
var elems = [];
|
||||
for (let i = 0; i < Selems.length; i++) {
|
||||
elems[i] = Selems[i] instanceof class_ ? Selems[i]._ : Selems[i];
|
||||
oldTrans[i] = elems[i].style.transition;
|
||||
elems[i].style.transition = `opacity ${ms}ms`;
|
||||
if(force){
|
||||
elems[i].style.opacity = "1";
|
||||
elems[i].style.display = "";
|
||||
}
|
||||
}
|
||||
await wait(10);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.opacity = "0";
|
||||
}
|
||||
await wait(ms);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.display = "none";
|
||||
elems[i].style.transition = oldTrans[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fadein an Element.
|
||||
*
|
||||
* @param {HTMLElement|class_} Selems Element to fade
|
||||
* @param {number} [ms] Duration in ms
|
||||
* @param {boolean} [force]
|
||||
* @param {string} [display] Set destroyed display style tag.
|
||||
*/
|
||||
export const fadein = async (Selems, ms = 200, force = false, display="") => {
|
||||
var oldTrans = [];
|
||||
if (!Array.isArray(Selems)) Selems = [Selems];
|
||||
var elems = [];
|
||||
for (let i = 0; i < Selems.length; i++) {
|
||||
elems[i] = (Selems[i] instanceof class_) ? Selems[i]._ : Selems[i];
|
||||
oldTrans[i] = elems[i].style.transition
|
||||
elems[i].style.transition = `opacity ${ms}ms`;
|
||||
elems[i].style.display = display;
|
||||
if (force) {
|
||||
elems[i].style.opacity = "0";
|
||||
}
|
||||
}
|
||||
await wait(10);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.opacity = "1";
|
||||
}
|
||||
await wait(ms+1);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].style.transition = oldTrans[i];
|
||||
}
|
||||
}
|
||||
|
||||
var bStack = [];
|
||||
/**
|
||||
* The callback will be triggered when the user intends to go back.
|
||||
*
|
||||
* @param {function} callback
|
||||
* @returns {function} cancle callback
|
||||
*/
|
||||
export const subCancel = (callback) => {
|
||||
bStack.push(callback);
|
||||
return ()=>{
|
||||
var id;
|
||||
if ((id = bStack.indexOf(callback)) >= 0) {
|
||||
bStack.splice(id, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
if (bStack.length) {
|
||||
bStack.pop()();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("backbutton", back, false);
|
||||
document.addEventListener('keyup', (e)=>{
|
||||
if (e.code == "Escape")back();
|
||||
});
|
Loading…
Reference in a new issue