Commit e3ee0cb1 by Иван Кубота

Split components.

Clone objects tree with cloning reactive subscriptions. WeakMap shim
parent 31813a8d
......@@ -5,7 +5,45 @@ const emptyFn = ()=>void 0;
const falseFn = ()=>false;
const REFLECTION = true;
const WEAKMAP = typeof WeakMap === 'function';
if(typeof Object.assign === 'undefined'){
Object.assign = function(a,...x) {
let i, _i = x.length, o, key;
for(i = 0; i< _i; i++){
o = x[i];
for(key in o){
a[key] = o[key];
}
}
return a;
};
}
const rand = ()=>Math.random().toString(36).substr(2);
const WeakMapShim = function() {
this._id = '__'+rand();
this.store = {};
this.damaged = [];
};
WeakMapShim.prototype = {
get: function(a) {
return this.store[a[this._id]];
},
has: function(a) {
return a.hasOwnProperty(this._id) && this.store.hasOwnProperty(a[this._id]);
},
set: function(a,b) {
let key = rand();
a[this._id] = key;
this.store[key] = b;
this.damaged.push(a);
},
clear: function() {
this.damaged.forEach((item)=>delete item[this._id]);
this.damaged = [];
this.store = {};
}
};
export const Reactivity = function(args) {
this.args = args;
};
......@@ -88,6 +126,9 @@ export const R = function() {
const args = [];
const reactivity = new Reactivity(args);
if(REFLECTION){
reactivity._deps = [];
}
for(let i = 0, _i = arguments.length === 1 ? arguments.length : arguments.length - 1; i < _i; i++){
const obj = arguments[i];
if(typeof obj === 'function'){
......@@ -98,6 +139,9 @@ export const R = function() {
reactivity.emit();
};
args[i] = objResolved.value;
if(REFLECTION){
reactivity._deps[i] = objResolved;
}
})
} else {
......@@ -106,19 +150,16 @@ export const R = function() {
reactivity.emit();
};
args[i] = obj.value;
if(REFLECTION){
reactivity._deps[i] = obj;
}
}
}
if(arguments.length === 1){
reactivity.fn = byPass;
if(REFLECTION){
reactivity._deps = [].slice.call( arguments );
}
}else{
reactivity.fn = arguments[arguments.length-1];
if(REFLECTION){
reactivity._deps = [].slice.call( arguments, 0, arguments.length - 1 );
}
}
return reactivity;
......@@ -151,6 +192,9 @@ ReactiveContent.prototype = {
}else{
throw new Error('Fix it. My parent does not contain me (ReactiveChild)');
}
},
clone: function(parent) {
return new ReactiveContent(parent, this.reactivity);
}
};
......@@ -267,7 +311,7 @@ Reactive.prototype = {
beforeSetKey: function (key, val, lastVal) {
return val;
},
_getReflectiveState: function() {
_getReflectiveState: function(cloningWorld) {
const cloningState = {};
clone(this.state, cloningState, function(val) {
if(val instanceof Component){
......@@ -279,7 +323,12 @@ Reactive.prototype = {
clone(this._rState, cloningState, function(val) {
if(val instanceof Reactivity){
var args = val._deps.map((dep)=>dep.obj.sub(dep.key)).concat(val.fn);
var args = val._deps.map(function(dep){
if(!cloningWorld.has(dep.obj)){
cloningWorld.set(dep.obj, new dep.obj._ctor(dep.obj.nodeName));
}
return cloningWorld.get(dep.obj).sub(dep.key);
}).concat(val.fn);
console.log(val, args)
return R.apply(this, args);
......@@ -532,16 +581,47 @@ Object.assign(Component.prototype, {
this.set(this.def);
this._inited = true;
},
clone: function() {
const clone = new this._ctor(this.nodeName);
clone: function(cloningWorld) {
if(cloningWorld === void 0){
if(WEAKMAP){
cloningWorld = new WeakMap();
}else{
cloningWorld = new WeakMapShim();
}
}
// CLONE OBJECT
let clone;
if(cloningWorld.has(this)){
clone = cloningWorld.get(this);
}else{
clone = new this._ctor(this.nodeName);
cloningWorld.set(this, clone);
}
clone.init();
// CLONE STRUCTURE
this.children.forEach(function(child) {
if(child instanceof ReactiveContent){
clone.addChild(child.reactivity);
}else{
clone.addChild(child.clone(cloningWorld));
}
});
//TaskManager.add(function() {
// CLONE STATE
clone._inited = false;
if(REFLECTION){
clone.set( this._getReflectiveState() );
clone.set( this._getReflectiveState(cloningWorld) );
}else{
clone.set(this.state);
}
clone._inited = true;
//});
return clone;
},
renderTo: function (where) {
......
import {Component, h, PropSettersInterface, EventHandler} from '../F';
interface ButtonProps {
onClick: EventHandler<MouseEvent>
}
class Button extends Component<ButtonProps> {
button: Component = null;
def = {
import {Component, h} from '../F';
export const Button = Component.extend('Button', {
button: null,
def: {
type: 'Button',
disabled: false
};
setters: PropSettersInterface<Button> = {
},
setters: {
value: (_,val:string)=>_.button.el.innerText = val,
disabled: (_,val:boolean)=>_.button.set({disabled: val})
};
},
render(){
//@ts-ignore
this.button = <button/>;
return this.button;
}
}
export {Button};
\ No newline at end of file
});
\ No newline at end of file
import { h, R } from "../F";
import { UIComponent } from './UIComponent';
let gg = 0;
export const Slider = UIComponent.extend('Slider', {
def: {
from: 0,
to: 100,
step: 1,
value: 0,
sliderWidth: 10,
background: 'red',
mover: <div
style={{
cursor: 'pointer',
width: 10,
height: 10,
/*R(but.sub('text'), (v1)=>{
if(gg<30){
console.log( v1 );
gg++;
}
return (v1-0)%20
})*/
border: '3px solid #fff',
position: 'absolute',
boxSizing: 'border-box'
}}
/>
},
recalc: function() {
if(this.state.value<this.state.from){
return this.set({value: this.state.from});
}
if(this.state.value>this.state.to){
return this.set({value: this.state.to});
}
var delta = this.state.to - this.state.from;
this.state.mover.set({
style: {
left: (this.state.value-this.state.from)/delta*(this.state.width-this.state.sliderWidth)
}
});
},
setters: {
'from,to,step,value,width': (_)=>{
_.later('recalc', _.recalc);
},
mover: function(_, val, lastVal) {
let sliderRect;
const moveFn = (e)=>{
const newRawVal = Math.max(0, Math.min(1,(e.clientX-sliderRect.left)/(sliderRect.width))),
delta = this.state.to - this.state.from,
newRangedVal = newRawVal*delta+this.state.from,
step = this.state.step,
newRoundedVal = Math.round(newRangedVal/step)*step;
this.set({value: newRoundedVal});
};
//this.state.mover = ;
val.on('mousedown', (e)=>{
console.log('down');
sliderRect = this.getBoundingClientRect();
this.doc.on('mousemove', moveFn);
this.doc.once('mouseup', ()=>{
this.doc.un('mousemove', moveFn);
});
this.set({width: sliderRect.width});
e.preventDefault();
});
}
},
render(){
return <div class="slider" style={{background: R(this.sub('background')), position: 'relative', height: 10}}>
{R(this.sub('mover'))}<div/>
</div>;
}
});
\ No newline at end of file
import { Component } from "../F";
export const UIComponent = Component.extend('UIComponent', {
def: {
disabled: false,
hidden: false,
label: {
position: 'top',
text: 'Label'
},
selected: false,
active: false,
empty: false,
placeholder: '',
style: {
size: 'normal',
margin: {top: '16px'}
}
},
setters: {
hidden: (_, val) => _.el.style.display = val === false ? 'block' : 'none',
style: (_, val)=>{
}
}
});
\ No newline at end of file
import {Button} from './cmp/Button';
import {h, R, Component} from './F';
let i, btn, item;
import {UIComponent} from "./cmp/UIComponent";
import {Slider} from "./cmp/Slider";
class Item extends Component {
checkbox = null;
checkbox2 = null;
const Item = Component.extend('Item', {
checkbox: null,
checkbox2: null,
render(){
let checkbox3;
......@@ -21,33 +23,10 @@ class Item extends Component {
{<input type="checkbox" id="c4" checked={R(checkbox3.sub('checked'))}/>}<br/><br/><br/><br/>
</div>;
}
}
});
let but = <i text={2}>1</i>;
const UIComponent = Component.extend('UIComponent', {
def: {
disabled: false,
hidden: false,
label: {
position: 'top',
text: 'Label'
},
selected: false,
active: false,
empty: false,
placeholder: '',
style: {
size: 'normal',
margin: {top: '16px'}
}
},
setters: {
hidden: (_, val) => _.el.style.display = val === false ? 'block' : 'none',
style: (_, val)=>{
}
}
});
const Check = UIComponent.extend('Check', {
setters: {
......@@ -70,84 +49,7 @@ const Check = UIComponent.extend('Check', {
}
});
let gg = 0;
const Slider = UIComponent.extend('Slider', {
def: {
from: 0,
to: 100,
step: 1,
value: 0,
sliderWidth: 10,
background: 'red',
mover: <div
style={{
cursor: 'pointer',
width: 10,
height: R(but.sub('text'), (v1)=>{
if(gg<30){
console.log( v1 );
gg++;
}
return (v1-0)%20
}),
border: '3px solid #fff',
position: 'absolute',
boxSizing: 'border-box'
}}
/>
},
recalc: function() {
if(this.state.value<this.state.from){
return this.set({value: this.state.from});
}
if(this.state.value>this.state.to){
return this.set({value: this.state.to});
}
var delta = this.state.to - this.state.from;
this.state.mover.set({
style: {
left: (this.state.value-this.state.from)/delta*(this.state.width-this.state.sliderWidth)
}
});
},
setters: {
'from,to,step,value,width': (_)=>{
_.later('recalc', _.recalc);
},
mover: function(_, val, lastVal) {
let sliderRect;
const moveFn = (e)=>{
const newRawVal = Math.max(0, Math.min(1,(e.clientX-sliderRect.left)/(sliderRect.width))),
delta = this.state.to - this.state.from,
newRangedVal = newRawVal*delta+this.state.from,
step = this.state.step,
newRoundedVal = Math.round(newRangedVal/step)*step;
this.set({value: newRoundedVal});
};
//this.state.mover = ;
val.on('mousedown', (e)=>{
console.log('down');
sliderRect = this.getBoundingClientRect();
this.doc.on('mousemove', moveFn);
this.doc.once('mouseup', ()=>{
this.doc.un('mousemove', moveFn);
});
this.set({width: sliderRect.width});
e.preventDefault();
});
}
},
render(){
return <div class="slider" style={{background: R(this.sub('background')), position: 'relative', height: 10}}>
{R(this.sub('mover'))}<div/>
</div>;
}
});
//
......@@ -157,7 +59,14 @@ let slider1 = <Slider from={-10} to={100} step={1}/>;
let RS, GS, BS;
let fr, tt;
var D = <div className='wrapper'>
let SSS;
let D = <div>
<div>
{SSS = <Slider from={0} to={255} step={1} value={10}/>}<span text={R(SSS.sub('value'))}/>
</div>
</div>;
D = <div className='wrapper'>
<div text="text of div"/><div>text in div</div>
<Check value={true} label={{text: 'Ti pidor'}} hidden={R(()=>chhh.sub('value'))}/>
{chhh}
......@@ -195,7 +104,7 @@ var D = <div className='wrapper'>
(b)=>'rgba('+[0,0,b,1]+')'
)}/>}
<div style={{
width: 300,
height: 300,
padding: '30px',
position: 'relative',
......@@ -236,7 +145,17 @@ var D = <div className='wrapper'>
`)}/>
</div>;
//D.mount(document.body);
//
document.getElementById('b1').addEventListener('click', function() {
D.mount(document.getElementById('d1'));
});
document.getElementById('b2').addEventListener('click', function() {
var G = D.clone();
G.mount(document.getElementById('d2'));
});
setTimeout(function() {
document.getElementById('b2').click();
}, 30000);
window.D = D;
let counter = 0;
setInterval(()=>{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment