feat: add `useSelf` to store system

This commit is contained in:
dntzhang 2019-09-22 19:07:10 +08:00
parent bfea4e33df
commit 91d8521b24
18 changed files with 2491 additions and 327 deletions

View File

@ -1,6 +1,6 @@
{
"props": {
"cname": 42,
"cname": 43,
"props": {
"$_dirty": "__d",
"$_disable": "__x",
@ -41,7 +41,8 @@
"$_customStyleElement": "N",
"$_customStyleContent": "O",
"$__hasChildren": "P",
"$__prevProps": "Q"
"$__prevProps": "Q",
"$_updateSelfPath": "R"
}
},
"vars": {

View File

@ -79,6 +79,8 @@ declare namespace Omi {
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
attrsToProps(): void;
setAttribute(name: string, value: any): void;
use(): any[];
useSelf(): any[];
}
interface ModelView<P, D> {
@ -105,6 +107,8 @@ declare namespace Omi {
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
attrsToProps(): void;
setAttribute(name: string, value: any): void;
use(): any[];
useSelf(): any[];
}
abstract class WeElement<P = {}, D = {}> {

View File

@ -1383,6 +1383,11 @@
} else {
this.constructor.use && (this.using = getUse(this.store.data, this.constructor.use));
}
if (this.useSelf) {
var _use = this.useSelf();
this._updateSelfPath = getPath(_use);
this.usingSelf = getUse(this.store.data, _use);
}
this.attrsToProps();
this.beforeInstall();
this.install();
@ -1575,142 +1580,147 @@
WeElement.is = 'WeElement';
function render(vnode, parent, store) {
parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (store) {
store.instances = [];
extendStoreUpate(store);
parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (store) {
store.instances = [];
extendStoreUpate(store);
store.data = new JSONPatcherProxy(store.data).observe(false, function (patch) {
var patchs = {};
if (patch.op === 'remove') {
// fix arr splice
var kv = getArrayPatch(patch.path, store);
patchs[kv.k] = kv.v;
store.data = new JSONPatcherProxy(store.data).observe(false, function (patch) {
var patchs = {};
if (patch.op === 'remove') {
// fix arr splice
var kv = getArrayPatch(patch.path, store);
patchs[kv.k] = kv.v;
update(patchs, store);
} else {
var key = fixPath(patch.path);
patchs[key] = patch.value;
update(patchs, store);
} else {
var key = fixPath(patch.path);
patchs[key] = patch.value;
update(patchs, store);
}
});
parent.store = store;
}
return diff(null, vnode, parent, false);
update(patchs, store);
}
});
parent.store = store;
}
return diff(null, vnode, parent, false);
}
function update(patch, store) {
store.update(patch);
store.update(patch);
}
function extendStoreUpate(store) {
store.update = function (patch) {
var _this = this;
store.update = function (patch) {
var _this = this;
var updateAll = matchGlobalData(this.globalData, patch);
var updateAll = matchGlobalData(this.globalData, patch);
if (Object.keys(patch).length > 0) {
this.instances.forEach(function (instance) {
if (updateAll || _this.updateAll || instance.constructor.updatePath && needUpdate(patch, instance.constructor.updatePath) || instance._updatePath && needUpdate(patch, instance._updatePath)) {
//update this.using
if (instance.constructor.use) {
instance.using = getUse(store.data, instance.constructor.use);
} else if (instance.use) {
instance.using = getUse(store.data, instance.use());
}
if (Object.keys(patch).length > 0) {
this.instances.forEach(function (instance) {
if (updateAll || _this.updateAll || instance.constructor.updatePath && needUpdate(patch, instance.constructor.updatePath) || instance._updatePath && needUpdate(patch, instance._updatePath)) {
//update this.using
if (instance.constructor.use) {
instance.using = getUse(store.data, instance.constructor.use);
} else if (instance.use) {
instance.using = getUse(store.data, instance.use());
}
instance.update();
}
});
this.onChange && this.onChange(patch);
}
};
instance.update();
}
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
_this.usingSelf = getUse(store.data, instance.useSelf());
instance.updateSelf();
}
});
this.onChange && this.onChange(patch);
}
};
}
function matchGlobalData(globalData, diffResult) {
if (!globalData) return false;
for (var keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true;
}
for (var i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true;
}
}
}
return false;
if (!globalData) return false;
for (var keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true;
}
for (var i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true;
}
}
}
return false;
}
function needUpdate(diffResult, updatePath) {
for (var keyA in diffResult) {
if (updatePath[keyA]) {
return true;
}
for (var keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true;
}
}
}
return false;
for (var keyA in diffResult) {
if (updatePath[keyA]) {
return true;
}
for (var keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true;
}
}
}
return false;
}
function includePath(pathA, pathB) {
if (pathA.indexOf(pathB) === 0) {
var next = pathA.substr(pathB.length, 1);
if (next === '[' || next === '.') {
return true;
}
}
return false;
if (pathA.indexOf(pathB) === 0) {
var next = pathA.substr(pathB.length, 1);
if (next === '[' || next === '.') {
return true;
}
}
return false;
}
function fixPath(path) {
var mpPath = '';
var arr = path.replace('/', '').split('/');
arr.forEach(function (item, index) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
});
return mpPath;
var mpPath = '';
var arr = path.replace('/', '').split('/');
arr.forEach(function (item, index) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
});
return mpPath;
}
function getArrayPatch(path, store) {
var arr = path.replace('/', '').split('/');
var current = store.data[arr[0]];
for (var i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]];
}
return { k: fixArrPath(path), v: current };
var arr = path.replace('/', '').split('/');
var current = store.data[arr[0]];
for (var i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]];
}
return { k: fixArrPath(path), v: current };
}
function fixArrPath(path) {
var mpPath = '';
var arr = path.replace('/', '').split('/');
var len = arr.length;
arr.forEach(function (item, index) {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
}
});
return mpPath;
var mpPath = '';
var arr = path.replace('/', '').split('/');
var len = arr.length;
arr.forEach(function (item, index) {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
}
});
return mpPath;
}
function tag(name, pure) {
@ -1885,7 +1895,7 @@
options.root.Omi = omi;
options.root.omi = omi;
options.root.Omi.version = '6.11.3';
options.root.Omi.version = '6.12.0';
if (typeof module != 'undefined') module.exports = omi;else self.Omi = omi;
}());

File diff suppressed because one or more lines are too long

View File

@ -1380,6 +1380,11 @@ var WeElement = function (_HTMLElement) {
} else {
this.constructor.use && (this.using = getUse(this.store.data, this.constructor.use));
}
if (this.useSelf) {
var _use = this.useSelf();
this._updateSelfPath = getPath(_use);
this.usingSelf = getUse(this.store.data, _use);
}
this.attrsToProps();
this.beforeInstall();
this.install();
@ -1572,142 +1577,147 @@ var WeElement = function (_HTMLElement) {
WeElement.is = 'WeElement';
function render(vnode, parent, store) {
parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (store) {
store.instances = [];
extendStoreUpate(store);
parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (store) {
store.instances = [];
extendStoreUpate(store);
store.data = new JSONPatcherProxy(store.data).observe(false, function (patch) {
var patchs = {};
if (patch.op === 'remove') {
// fix arr splice
var kv = getArrayPatch(patch.path, store);
patchs[kv.k] = kv.v;
store.data = new JSONPatcherProxy(store.data).observe(false, function (patch) {
var patchs = {};
if (patch.op === 'remove') {
// fix arr splice
var kv = getArrayPatch(patch.path, store);
patchs[kv.k] = kv.v;
update(patchs, store);
} else {
var key = fixPath(patch.path);
patchs[key] = patch.value;
update(patchs, store);
} else {
var key = fixPath(patch.path);
patchs[key] = patch.value;
update(patchs, store);
}
});
parent.store = store;
}
return diff(null, vnode, parent, false);
update(patchs, store);
}
});
parent.store = store;
}
return diff(null, vnode, parent, false);
}
function update(patch, store) {
store.update(patch);
store.update(patch);
}
function extendStoreUpate(store) {
store.update = function (patch) {
var _this = this;
store.update = function (patch) {
var _this = this;
var updateAll = matchGlobalData(this.globalData, patch);
var updateAll = matchGlobalData(this.globalData, patch);
if (Object.keys(patch).length > 0) {
this.instances.forEach(function (instance) {
if (updateAll || _this.updateAll || instance.constructor.updatePath && needUpdate(patch, instance.constructor.updatePath) || instance._updatePath && needUpdate(patch, instance._updatePath)) {
//update this.using
if (instance.constructor.use) {
instance.using = getUse(store.data, instance.constructor.use);
} else if (instance.use) {
instance.using = getUse(store.data, instance.use());
}
if (Object.keys(patch).length > 0) {
this.instances.forEach(function (instance) {
if (updateAll || _this.updateAll || instance.constructor.updatePath && needUpdate(patch, instance.constructor.updatePath) || instance._updatePath && needUpdate(patch, instance._updatePath)) {
//update this.using
if (instance.constructor.use) {
instance.using = getUse(store.data, instance.constructor.use);
} else if (instance.use) {
instance.using = getUse(store.data, instance.use());
}
instance.update();
}
});
this.onChange && this.onChange(patch);
}
};
instance.update();
}
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
_this.usingSelf = getUse(store.data, instance.useSelf());
instance.updateSelf();
}
});
this.onChange && this.onChange(patch);
}
};
}
function matchGlobalData(globalData, diffResult) {
if (!globalData) return false;
for (var keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true;
}
for (var i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true;
}
}
}
return false;
if (!globalData) return false;
for (var keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true;
}
for (var i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true;
}
}
}
return false;
}
function needUpdate(diffResult, updatePath) {
for (var keyA in diffResult) {
if (updatePath[keyA]) {
return true;
}
for (var keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true;
}
}
}
return false;
for (var keyA in diffResult) {
if (updatePath[keyA]) {
return true;
}
for (var keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true;
}
}
}
return false;
}
function includePath(pathA, pathB) {
if (pathA.indexOf(pathB) === 0) {
var next = pathA.substr(pathB.length, 1);
if (next === '[' || next === '.') {
return true;
}
}
return false;
if (pathA.indexOf(pathB) === 0) {
var next = pathA.substr(pathB.length, 1);
if (next === '[' || next === '.') {
return true;
}
}
return false;
}
function fixPath(path) {
var mpPath = '';
var arr = path.replace('/', '').split('/');
arr.forEach(function (item, index) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
});
return mpPath;
var mpPath = '';
var arr = path.replace('/', '').split('/');
arr.forEach(function (item, index) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
});
return mpPath;
}
function getArrayPatch(path, store) {
var arr = path.replace('/', '').split('/');
var current = store.data[arr[0]];
for (var i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]];
}
return { k: fixArrPath(path), v: current };
var arr = path.replace('/', '').split('/');
var current = store.data[arr[0]];
for (var i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]];
}
return { k: fixArrPath(path), v: current };
}
function fixArrPath(path) {
var mpPath = '';
var arr = path.replace('/', '').split('/');
var len = arr.length;
arr.forEach(function (item, index) {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
}
});
return mpPath;
var mpPath = '';
var arr = path.replace('/', '').split('/');
var len = arr.length;
arr.forEach(function (item, index) {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item;
} else {
mpPath += '[' + item + ']';
}
} else {
mpPath += item;
}
}
});
return mpPath;
}
function tag(name, pure) {
@ -1882,7 +1892,7 @@ var omi = {
options.root.Omi = omi;
options.root.omi = omi;
options.root.Omi.version = '6.11.3';
options.root.Omi.version = '6.12.0';
export default omi;
export { tag, WeElement, Component, render, h, h as createElement, options, define, observe, cloneElement, getHost, rpx, tick, nextTick, ModelView, defineElement, classNames, extractClass, createRef, html, htm, o, elements, $, extend$1 as extend, get, set, bind, unbind, JSONPatcherProxy as JSONProxy };

File diff suppressed because one or more lines are too long

View File

@ -547,6 +547,10 @@
if (instance.constructor.use) instance.using = getUse(store.data, instance.constructor.use); else if (instance.use) instance.using = getUse(store.data, instance.use());
instance.update();
}
if (instance.R && needUpdate(patch, instance.R)) {
_this.usingSelf = getUse(store.data, instance.useSelf());
instance.updateSelf();
}
});
this.onChange && this.onChange(patch);
}
@ -923,6 +927,11 @@
this.M = getPath(use);
this.using = getUse(this.store.data, use);
} else this.constructor.use && (this.using = getUse(this.store.data, this.constructor.use));
if (this.useSelf) {
var _use = this.useSelf();
this.R = getPath(_use);
this.usingSelf = getUse(this.store.data, _use);
}
this.attrsToProps();
this.beforeInstall();
this.install();
@ -1128,7 +1137,7 @@
};
options.root.Omi = omi;
options.root.omi = omi;
options.root.Omi.version = '6.11.3';
options.root.Omi.version = '6.12.0';
if ('undefined' != typeof module) module.exports = omi; else self.Omi = omi;
}();
//# sourceMappingURL=omi.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<meta charset="UTF-8" />
<title>Counter</title>
</head>
<body>
<script src="b.js"></script>
<a href="https://github.com/Tencent/omi" target="_blank" style="position: fixed; right: 0; top: 0; z-index: 3;">
<img src="//alloyteam.github.io/github.png" alt="">
</a>
</body>
</html>

View File

@ -0,0 +1,75 @@
import { render, WeElement, define } from '../../src/omi'
define('my-counter', class extends WeElement {
use(){
return [
{ count: 'count' }
]
}
add = () => this.store.add()
sub = () => this.store.sub()
addIfOdd = () => {
if (this.using.count % 2 !== 0) {
this.store.add()
}
}
addAsync = () => {
setTimeout(() => this.store.add(), 1000)
}
render() {
return (
<p>
Clicked: {this.using.count} times
<button onClick={this.add}>+</button>
<button onClick={this.sub}>-</button>
<button onClick={this.addIfOdd}>
Add if odd
</button>
<button onClick={this.addAsync}>
Add async
</button>
<div>{Math.random()}</div>
</p>
)
}
})
define('my-app', class extends WeElement {
useSelf(){
return ['msg']
}
render() {
return (
<div>
<span onClick={this.store.random}>{this.store.data.msg}</span>
<my-counter></my-counter>
</div>
)
}
})
render(<my-app />, 'body', new class Store{
data = {
msg: 'aaa',
count: 0
}
sub = ()=> {
this.data.count--
}
add = ()=> {
this.data.count++
}
random = ()=> {
console.log(this)
this.data.msg = Math.random()
}
})

View File

@ -79,6 +79,8 @@ declare namespace Omi {
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
attrsToProps(): void;
setAttribute(name: string, value: any): void;
use(): any[];
useSelf(): any[];
}
interface ModelView<P, D> {
@ -105,6 +107,8 @@ declare namespace Omi {
receiveProps?(props: RenderableProps<P>, oldProps:RenderableProps<P>): any;
attrsToProps(): void;
setAttribute(name: string, value: any): void;
use(): any[];
useSelf(): any[];
}
abstract class WeElement<P = {}, D = {}> {

View File

@ -62,7 +62,7 @@ const omi = {
options.root.Omi = omi
options.root.omi = omi
options.root.Omi.version = '6.11.3'
options.root.Omi.version = '6.12.0'
export default omi

View File

@ -3,146 +3,151 @@ import JSONProxy from './proxy'
import { getUse } from './util'
export function render(vnode, parent, store) {
parent = typeof parent === 'string' ? document.querySelector(parent) : parent
if (store) {
store.instances = []
extendStoreUpate(store)
parent = typeof parent === 'string' ? document.querySelector(parent) : parent
if (store) {
store.instances = []
extendStoreUpate(store)
store.data = new JSONProxy(store.data).observe(false, function(patch) {
store.data = new JSONProxy(store.data).observe(false, function (patch) {
const patchs = {}
if (patch.op === 'remove') {
// fix arr splice
const kv = getArrayPatch(patch.path, store)
patchs[kv.k] = kv.v
if (patch.op === 'remove') {
// fix arr splice
const kv = getArrayPatch(patch.path, store)
patchs[kv.k] = kv.v
update(patchs, store)
} else {
const key = fixPath(patch.path)
patchs[key] = patch.value
} else {
const key = fixPath(patch.path)
patchs[key] = patch.value
update(patchs, store)
}
})
parent.store = store
}
return diff(null, vnode, parent, false)
}
})
parent.store = store
}
return diff(null, vnode, parent, false)
}
function update(patch, store) {
store.update(patch)
store.update(patch)
}
function extendStoreUpate(store) {
store.update = function(patch) {
const updateAll = matchGlobalData(this.globalData, patch)
store.update = function (patch) {
const updateAll = matchGlobalData(this.globalData, patch)
if (Object.keys(patch).length > 0) {
this.instances.forEach(instance => {
if (
updateAll ||
this.updateAll ||
(instance.constructor.updatePath &&
needUpdate(patch, instance.constructor.updatePath)) ||(
instance._updatePath && needUpdate(patch, instance._updatePath))
) {
if (Object.keys(patch).length > 0) {
this.instances.forEach(instance => {
if (
updateAll ||
this.updateAll ||
(instance.constructor.updatePath &&
needUpdate(patch, instance.constructor.updatePath)) || (
instance._updatePath && needUpdate(patch, instance._updatePath))
) {
//update this.using
if(instance.constructor.use){
if (instance.constructor.use) {
instance.using = getUse(store.data, instance.constructor.use)
} else if(instance.use){
} else if (instance.use) {
instance.using = getUse(store.data, instance.use())
}
instance.update()
}
})
this.onChange && this.onChange(patch)
}
}
instance.update()
}
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
this.usingSelf = getUse(store.data, instance.useSelf())
instance.updateSelf()
}
})
this.onChange && this.onChange(patch)
}
}
}
export function matchGlobalData(globalData, diffResult) {
if (!globalData) return false
for (let keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true
}
for (let i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true
}
}
}
return false
if (!globalData) return false
for (let keyA in diffResult) {
if (globalData.indexOf(keyA) > -1) {
return true
}
for (let i = 0, len = globalData.length; i < len; i++) {
if (includePath(keyA, globalData[i])) {
return true
}
}
}
return false
}
export function needUpdate(diffResult, updatePath) {
for (let keyA in diffResult) {
if (updatePath[keyA]) {
return true
}
for (let keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true
}
}
}
return false
for (let keyA in diffResult) {
if (updatePath[keyA]) {
return true
}
for (let keyB in updatePath) {
if (includePath(keyA, keyB)) {
return true
}
}
}
return false
}
function includePath(pathA, pathB) {
if (pathA.indexOf(pathB) === 0) {
const next = pathA.substr(pathB.length, 1)
if (next === '[' || next === '.') {
return true
}
}
return false
if (pathA.indexOf(pathB) === 0) {
const next = pathA.substr(pathB.length, 1)
if (next === '[' || next === '.') {
return true
}
}
return false
}
export function fixPath(path) {
let mpPath = ''
const arr = path.replace('/', '').split('/')
arr.forEach((item, index) => {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item
} else {
mpPath += '[' + item + ']'
}
} else {
mpPath += item
}
})
return mpPath
let mpPath = ''
const arr = path.replace('/', '').split('/')
arr.forEach((item, index) => {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item
} else {
mpPath += '[' + item + ']'
}
} else {
mpPath += item
}
})
return mpPath
}
function getArrayPatch(path, store) {
const arr = path.replace('/', '').split('/')
let current = store.data[arr[0]]
for (let i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]]
}
const arr = path.replace('/', '').split('/')
let current = store.data[arr[0]]
for (let i = 1, len = arr.length; i < len - 1; i++) {
current = current[arr[i]]
}
return { k: fixArrPath(path), v: current }
}
function fixArrPath(path) {
let mpPath = ''
const arr = path.replace('/', '').split('/')
const len = arr.length
arr.forEach((item, index) => {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item
} else {
mpPath += '[' + item + ']'
}
} else {
mpPath += item
}
}
})
return mpPath
let mpPath = ''
const arr = path.replace('/', '').split('/')
const len = arr.length
arr.forEach((item, index) => {
if (index < len - 1) {
if (index) {
if (isNaN(Number(item))) {
mpPath += '.' + item
} else {
mpPath += '[' + item + ']'
}
} else {
mpPath += item
}
}
})
return mpPath
}

View File

@ -34,7 +34,12 @@ export default class WeElement extends HTMLElement {
this.using = getUse(this.store.data, use)
} else {
this.constructor.use && (this.using = getUse(this.store.data, this.constructor.use))
}
}
if(this.useSelf){
const use = this.useSelf()
this._updateSelfPath = getPath(use)
this.usingSelf = getUse(this.store.data, use)
}
this.attrsToProps()
this.beforeInstall()
this.install()