als-component
Advanced tools
Comparing version 0.1.0 to 0.2.0
128
component.js
class Component { | ||
static get state() { | ||
let state = {} | ||
Object.keys(Component).forEach(methodName => { | ||
if(Object.keys(Component[methodName].state).length > 0) | ||
state[methodName] = Component[methodName].state | ||
}) | ||
return state | ||
} | ||
constructor(componentName,fn,data={}) { | ||
this.componentName = componentName | ||
this.fn = fn | ||
this.data = data | ||
Component[componentName] = this | ||
} | ||
static import(Obj) { | ||
Object.keys(Obj).forEach(name => { | ||
let obj = Obj[name] | ||
let fn = new Function("return " + obj.fn)(); | ||
new Component(name,fn,obj.state,obj.hooks) | ||
}); | ||
} | ||
static export() { | ||
let exceptions = ['state','import','export','convert','script'] | ||
let components = [] | ||
Object.keys(Component).forEach(methodName => { | ||
if(!exceptions.includes(methodName)) { | ||
let hooks = {} | ||
Object.keys(Component[methodName].hooks).forEach(hookActionName => { | ||
hooks[hookActionName] = [] | ||
Component[methodName].hooks[hookActionName].forEach(fn => { | ||
hooks[hookActionName].push(fn.toString()) | ||
}) | ||
}) | ||
components.push({ | ||
name:Component[methodName].name, | ||
fn:Component[methodName].fn.toString(), | ||
state:Component[methodName].state, | ||
hooks, | ||
}) | ||
} | ||
}) | ||
return components | ||
} | ||
static convert(obj,ret="{") { | ||
function check(v) { | ||
if(typeof v === "function") v = v.toString() | ||
else if (typeof v === "object") v = Component.convert(v) | ||
else if (typeof v == "boolean" || Number.isInteger(v)) v=v | ||
else v = `"${v}"` | ||
return v | ||
} | ||
if(obj instanceof Array) { | ||
ret="[" | ||
obj.forEach(v => { | ||
ret += check(v)+',' | ||
}); | ||
ret += "\n]" | ||
} else { | ||
for (let k in obj) { | ||
let v = obj[k]; | ||
ret += `\n ${k}: ${check(v)},`; | ||
} | ||
ret += "\n}"; | ||
} | ||
return ret | ||
} | ||
static script() { | ||
return `Component.import(${Component.convert(Component)})` | ||
} | ||
constructor(name,component,state = {},hooks={}) { | ||
this.init = true | ||
this.fn = component | ||
this.name = name | ||
this.state = state | ||
this.hooks = hooks | ||
this.components = {} | ||
this.actions = {} | ||
this.addToState() | ||
this.hooks = hooks | ||
if(this.hooks.update == undefined) this.hooks.update = [] | ||
if(this.hooks.remove == undefined) this.hooks.remove = [] | ||
if(this.hooks.add == undefined) this.hooks.add = [] | ||
Component[name] = this | ||
} | ||
addToState() { | ||
Object.keys(this.state).forEach(varName => { | ||
Component.state[varName] = this.state[varName] | ||
}) | ||
} | ||
update(id='',state=this.state) { | ||
this.setState(id,state,element => { | ||
element.outerHTML = this.fn(state) | ||
},this.hooks.update) | ||
} | ||
remove(id='',state=this.state) { | ||
this.setState(id,state,element => { | ||
element.remove() | ||
},this.hooks.remove) | ||
} | ||
add(id='',state=this.state,place) { | ||
this.setState(id,state,element => { | ||
element.insertAdjacentHTML(place,this.fn(state)) | ||
},this.hooks.add) | ||
} | ||
addBefore(id,state=this.state) {this.add(id,state,'beforebegin')} | ||
addAfter(id,state=this.state) {this.add(id,state,'afterend')} | ||
setState(id='',state=this.state,fn,hooks) { | ||
let query = `[component=${this.name}]${id}` | ||
hooks.forEach(hook => {hook(state,this.init)}); | ||
let elements = [...document.querySelectorAll(query)] | ||
elements.forEach(element => {fn(element)}); | ||
this.init = false | ||
} | ||
update(id=this.componentName,data=this.data) { | ||
document.getElementById(id).outerHTML = this.fn(id,data) | ||
} | ||
} | ||
try {module.exports = Component} catch{} |
{ | ||
"name": "als-component", | ||
"version": "0.1.0", | ||
"description": "Managing elements and states.", | ||
"main": "component.js", | ||
"version": "0.2.0", | ||
"description": "Managing components and states.", | ||
"main": "export.js", | ||
"scripts": { | ||
@@ -7,0 +7,0 @@ "test": "echo \"Error: no test specified\" && exit 1" |
175
readme.md
@@ -1,89 +0,130 @@ | ||
# als-component **being tested not for use** | ||
# Als-component | ||
To show html colored code inside string in js, use es6-string-html plugin in vsCode and /*html*/`html code`. | ||
## Frontend | ||
There are two files: | ||
1. component.js - for frontend usage | ||
2. export.js - for node.js usage | ||
To show colored html code inside string, use ``es6-string-html`` plugin for Vscode. | ||
Example: | ||
## Component.js | ||
```html | ||
<!-- Add Component class --> | ||
<script src="/component.js"></script> | ||
<!-- Add Initial element with component name and input for changing state --> | ||
<input id="input" type="text" oninput="test.state.name=this.value; test.update()"> | ||
<div component="test"></div> | ||
<div component="some" id="some"></div> | ||
<input type="text" oninput="Some.update('some',{test:'Hello again'})"> | ||
<script src="/node_moduls/als-component/component.js"></script> | ||
<script> | ||
let test = new Component( | ||
'test', // component name | ||
function() { //function for generating component's html | ||
return /*html*/`<div component="test"> | ||
Hello ${this.state.name} | ||
</div>` | ||
}, | ||
{name:'Alex'}, // initial state | ||
{update:[ // hooks object with update hook | ||
function(state,init) { | ||
if(init) document.getElementById('input').value = state.name | ||
} | ||
]} | ||
) | ||
// find element [component=test] and update it | ||
test.update() | ||
</script> | ||
let componentName = 'some' | ||
let data = {test:'hello world'} | ||
let fn = (id,data) => /*html*/`<div component="some" id="some">${data.test}</div>` | ||
let Some = new Component(componentName,fn,data) | ||
<script> | ||
``` | ||
## Todo application | ||
### Syntax: | ||
**data.js** | ||
```javascript | ||
let component = new Component(name,component,state = {},hooks={update:[],remove:[],add:[]}) | ||
component.fn // component function | ||
component.state // component state | ||
component.hooks // component hooks | ||
let data = [ | ||
{"userId": 1,"id": 1,"title": "delectus aut autem","completed": false}, | ||
{"userId": 1,"id": 2,"title": "quis ut nam facilis et officia qui","completed": false}, | ||
{"userId": 1,"id": 3,"title": "fugiat veniam minus","completed": false} | ||
] | ||
try {module.exports = data} catch{} | ||
``` | ||
Exceptions for component name: state,import,export,convert,script. | ||
**todo.js** | ||
```javascript | ||
function todo(id) { | ||
let Todos = Component.todos | ||
let index = Todos.data.findIndex(todo => todo.id === id); | ||
let todo = Todos.data[index] | ||
return /*html*/` | ||
<div component="todo" id="${id}"> | ||
<span onclick="Todos.data[${index}].completed = !Todos.data[${index}].completed; Todo.update(${id})" | ||
style="color:${todo.completed ? 'green' : 'blue'}"> | ||
${todo.title} | ||
</span> | ||
<button onclick="Todos.data.splice(${index}, 1); Todos.update()">x</button> | ||
</div> | ||
` | ||
} | ||
try {module.exports = todo} catch{} | ||
``` | ||
### Component inside component | ||
**todos.js** | ||
```javascript | ||
function todos(id,data) { | ||
return /*html*/` | ||
<div component="todos" id="todos"> | ||
${data.map(el => Component.todo.fn(el.id)).join('')} | ||
</div> | ||
` | ||
} | ||
try {module.exports = todos} catch{} | ||
``` | ||
**addnew.js** | ||
```javascript | ||
function addNew(title) { | ||
let ids = data.map(obj => obj.id) | ||
let id = Math.max(...ids) +1 | ||
data.push({id,title,completed:false}) | ||
Todos.update() | ||
} | ||
try {module.exports = addNew} catch{} | ||
``` | ||
## Frontend usage | ||
```html | ||
<ul component="todos"></ul> | ||
<script> | ||
let todos = [{id:1,name:'do something'},{id:2,name:'do else'}] | ||
<script src="/node_moduls/als-component/component.js"></script> | ||
<div> | ||
Add new | ||
<input type="text" onchange="addNew(this.value)"> | ||
</div> | ||
// todo component | ||
let todoComponent = new Component('todo',function({name,id}) { | ||
return /*html*/`<li component="todo" id="${id}">${name}</li>` | ||
}) | ||
<div component="todos" id="todos"></div> | ||
// todos component | ||
let todosComponent = new Component('todos',function() { | ||
return /*html*/` | ||
<ul component="todos"> | ||
${this.state.todos.map(todo => todoComponent.fn(todo)).join('')} | ||
</ul>` | ||
},{todos}) | ||
<script src="data.js"></script> | ||
<script src="todo.js"></script> | ||
<script src="todos.js"></script> | ||
todosComponent.update() | ||
<script> | ||
let Todo = new Component('todo',todo) | ||
let Todos = new Component('todos',todos,data) | ||
Todos.update() | ||
</script> | ||
``` | ||
### Actions | ||
remove,apdate, add, addBefore, addAfter | ||
## Express usage | ||
### Hooks | ||
remove,apdate, add | ||
init | ||
**server.js** | ||
```javascript | ||
const express = require('express') | ||
let app = express() | ||
app.use(require('als-component').mw) | ||
app.get('/',(req,res) => { | ||
let data = require('./data') | ||
let data = require('./todo') | ||
let data = require('./todos') | ||
let data = require('./addnew') | ||
res.fns.push(addNew) | ||
res.component('todo',todo) | ||
res.component('todos',todos,data,true) | ||
#### component.state | ||
#### Component.state - Combine states | ||
## Node.js | ||
#### import | ||
#### export | ||
return res.end(/*html*/` | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Todos</title> | ||
</head> | ||
<body> | ||
<div> | ||
Add new | ||
<input type="text" onchange="Component.addNew(this.value)"> | ||
</div> | ||
<div component="todos" id="todos"></div> | ||
${res.exportComponents()} | ||
</body> | ||
</html>`) | ||
}) | ||
app.listen(3000) | ||
``` |
4
131
4962
39