diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 9cc11336..45c164b1 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -172,7 +172,12 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Cmdy("ctx.config", "runtime", arg[0]) return } + m.Conf("runtime", arg[0], arg[1]) + if arg[0] == "node.route" && m.Confs("runtime", "work.serve") { + m.Conf("runtime", "work.route", arg[1]) + return + } m.Echo(arg[1]) } return @@ -664,6 +669,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } return }}, + "notice": &ctx.Command{Name: "notice", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + m.Cmd("cli.system", "osascript", "-e", fmt.Sprintf("display notification \"%s\"", kit.Select("", arg, 0))) + return + }}, "init": &ctx.Command{Name: "init", Help: "停止服务", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { m.Conf("runtime", "host.GOARCH", runtime.GOARCH) diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go index 08bfdf2e..1a7442d3 100644 --- a/src/contexts/nfs/nfs.go +++ b/src/contexts/nfs/nfs.go @@ -2,6 +2,7 @@ package nfs import ( "contexts/ctx" + "crypto/md5" "toolkit" "crypto/sha1" @@ -954,6 +955,15 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { nfs.Send(meta, v) } for _, k := range msg.Meta[body] { + if k == "binary" { + switch d := msg.Data[k].(type) { + case []byte: + nfs.Send("size", len(d)) + n, e := nfs.io.Write(d) + m.Log("info", "send %v %v", n, e) + } + continue + } for _, v := range msg.Meta[k] { nfs.Send(k, v) } @@ -1279,6 +1289,43 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", return }}, + "hash": &ctx.Command{Name: "hash filename", Help: "查找文件路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + dir, name := path.Split(arg[0]) + m.Append("dir", dir) + m.Append("name", name) + m.Append("type", strings.TrimPrefix(path.Ext(arg[0]), ".")) + if s, e := os.Stat(arg[0]); e == nil && !s.IsDir() { + m.Append("size", s.Size()) + if f, e := os.Open(arg[0]); e == nil { + defer f.Close() + md := md5.New() + io.Copy(md, f) + h := md.Sum(nil) + m.Echo(hex.EncodeToString(h[:])) + } + } + return + }}, + "copy": &ctx.Command{Name: "copy to from", Help: "查找文件路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + dir, _ := path.Split(arg[0]) + m.Assert(os.MkdirAll(dir, 0777)) + + to, e := os.Create(arg[0]) + m.Assert(e) + defer to.Close() + + for _, from := range arg[1:] { + f, e := os.Open(from) + m.Assert(e) + defer f.Close() + + n, e := io.Copy(to, f) + m.Assert(e) + m.Log("info", "copy %d from %s to %s", n, from, arg[0]) + } + m.Echo(arg[0]) + return + }}, "path": &ctx.Command{Name: "path filename", Help: "查找文件路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { return @@ -1294,12 +1341,18 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", }) return }}, + "load": &ctx.Command{Name: "load file [buf_size [pos]]", Help: "加载文件, buf_size: 加载大小, pos: 加载位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if p, f, e := open(m, arg[0]); e == nil { defer f.Close() pos := kit.Int(kit.Select("0", arg, 2)) size := kit.Int(m.Confx("buf_size", arg, 1)) + if size == -1 { + s, e := f.Stat() + m.Assert(e) + size = int(s.Size()) + } buf := make([]byte, size) if l, e := f.ReadAt(buf, int64(pos)); e == io.EOF || m.Assert(e) { diff --git a/src/contexts/ssh/ssh.go b/src/contexts/ssh/ssh.go index d4901563..628977d7 100644 --- a/src/contexts/ssh/ssh.go +++ b/src/contexts/ssh/ssh.go @@ -2,6 +2,10 @@ package ssh import ( "contexts/ctx" + "encoding/hex" + "io" + "os" + "path" "strings" "toolkit" ) @@ -35,18 +39,25 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", Configs: map[string]*ctx.Config{ "node": &ctx.Config{Name: "node", Value: map[string]interface{}{}, Help: "节点信息"}, "cert": &ctx.Config{Name: "cert", Value: map[string]interface{}{}, Help: "用户信息"}, + "file": &ctx.Config{Name: "file", Value: map[string]interface{}{}, Help: "用户信息"}, "trust": &ctx.Config{Name: "trust", Value: map[string]interface{}{"fresh": false, "user": true, "up": true}, Help: "可信节点"}, "timer": &ctx.Config{Name: "timer", Value: map[string]interface{}{"interval": "10s", "timer": ""}, Help: "断线重连"}, "componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{ "index": []interface{}{ map[string]interface{}{"componet_name": "pwd", "componet_help": "pwd", "componet_tmpl": "componet", - "componet_view": "FlashList", "componet_init": "initFlashList", - "componet_ctx": "nfs", "componet_cmd": "pwd", + "componet_view": "FlashList", "componet_init": "initFlashList.js", + "componet_ctx": "nfs", "componet_cmd": "pwd", "componet_args": []interface{}{"@text"}, "inputs": []interface{}{ + map[string]interface{}{"type": "button", "value": "当前", "click": "show"}, + map[string]interface{}{"type": "button", "value": "所有", "click": "show"}, + map[string]interface{}{"type": "text", "name": "text"}, + }, "display_result": "", "display_append": "", }, map[string]interface{}{"componet_name": "dir", "componet_help": "dir", "componet_tmpl": "componet", - "componet_view": "FlashList", "componet_init": "initFlashList", - "componet_ctx": "nfs", "componet_cmd": "dir", + "componet_view": "FlashList", "componet_init": "initFlashList.js", + "componet_ctx": "nfs", "componet_cmd": "dir", "componet_args": []interface{}{"@text"}, "inputs": []interface{}{ + map[string]interface{}{"type": "text", "name": "text"}, + }, "display_result": "", "display_append": "", }, }, @@ -89,6 +100,8 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", "node [create|check text|trust node]", "user [create|check text|share role node...|proxy node|trust node]", "work [create node name|check node name]", + "file [import]", + "tool ", }, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { m.Add("append", "key", "node.cert") @@ -204,6 +217,10 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", } switch arg[1] { + case "serve": // 注册节点 + m.Conf("runtime", "work.serve", true) + m.Conf("runtime", "work.route", m.Conf("runtime", "node.route")) + case "create": // 创建证书 user := m.Conf("runtime", "user.route") if user == "" { @@ -234,10 +251,75 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Echo("true") } } + case "tool": switch arg[1] { case "check": // 数字验签 - m.Cmdy("ssh.remote", arg[2], "check", arg[0]) + m.Cmdy("ssh.remote", arg[2], "check", arg[0], arg[3:]) + case "run": + m.Cmdy("ssh.remote", arg[2], "check", arg[0], "run", arg[3:]) + } + + case "file": + switch arg[1] { + case "import": + if msg := m.Cmd("nfs.hash", arg[2]); msg.Results(0) { + h := msg.Result(0) + m.Conf("file", kit.Hashs(h, msg.Append("name")), map[string]interface{}{ + "create_time": m.Time(), + "create_user": m.Option("username"), + "name": msg.Append("name"), + "type": msg.Append("type"), + "size": msg.Append("size"), + "hash": h, + }) + + m.Cmdy("nfs.copy", path.Join("var/file/hash", h[:2], h), arg[2]) + } + + case "fetch": + if m.Confs("file", arg[2]) { + m.Echo(arg[2]) + break + } + + msg := m.Cmd("ssh.remote", arg[3], "check", "file", arg[2]) + h := msg.Append("hash") + m.Conf("file", arg[2], map[string]interface{}{ + "create_time": m.Time(), + "create_user": m.Option("username"), + "name": msg.Append("name"), + "type": msg.Append("type"), + "size": msg.Append("size"), + "hash": h, + }) + + p := path.Join("var/file/hash", h[:2], h) + if m.Cmds("nfs.path", p) { + m.Echo(arg[2]) + break + } + m.Cmdy("nfs.copy", p) + f, e := os.Create(p) + m.Assert(e) + for i := 0; int64(i) < msg.Appendi("size"); i += 1024 { + msg := m.Cmd("ssh.remote", arg[3], "check", "file", arg[2], 1, 1024, i) + for _, d := range msg.Meta["data"] { + b, e := hex.DecodeString(d) + m.Assert(e) + _, e = f.Write(b) + m.Assert(e) + } + } + + default: + m.Confm("file", arg[1], func(file map[string]interface{}) { + m.Append("hash", file["hash"]) + m.Append("size", file["size"]) + m.Append("type", file["type"]) + m.Append("name", file["name"]) + }) + m.Table() } } return @@ -259,6 +341,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Echo(m.Cmdx("aaa.rsa", "sign", m.Conf("runtime", "user.key"), arg[2])) } } + case "work": // 工作验签 switch arg[1] { case "search": @@ -283,14 +366,69 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Echo(arg[1]) } } + case "tool": - m.Confm("componet", func(key string, index int, value map[string]interface{}) { - m.Add("append", "key", key) - m.Add("append", "index", index) - m.Add("append", "name", value["componet_name"]) - m.Add("append", "help", value["componet_help"]) - }) - m.Table() + if len(arg) == 1 { + m.Confm("componet", func(key string, index int, value map[string]interface{}) { + m.Add("append", "key", key) + m.Add("append", "index", index) + m.Add("append", "name", value["componet_name"]) + m.Add("append", "help", value["componet_help"]) + }) + m.Table() + break + } + switch arg[1] { + case "run": + tool := m.Confm("componet", []string{arg[2], arg[3]}) + msg := m.Find(kit.Format(tool["componet_ctx"])) + msg.Cmd(tool["componet_cmd"], arg[4:]).CopyTo(m) + + default: + m.Confm("componet", arg[1:], func(value map[string]interface{}) { + m.Add("append", "name", value["componet_name"]) + m.Add("append", "help", value["componet_help"]) + m.Add("append", "view", value["componet_view"]) + m.Add("append", "init", m.Cmdx("nfs.load", path.Join("usr/librarys/plugin", kit.Format(value["componet_init"])), -1)) + m.Add("append", "inputs", kit.Format(value["inputs"])) + }) + m.Table() + } + break + + case "file": + if len(arg) == 2 { + m.Confm("file", arg[1], func(file map[string]interface{}) { + m.Append("hash", file["hash"]) + m.Append("size", file["size"]) + m.Append("type", file["type"]) + m.Append("name", file["name"]) + }) + m.Table() + break + } + + h := m.Conf("file", []string{arg[1], "hash"}) + + if f, e := os.Open(path.Join("var/file/hash", h[:2], h)); e == nil { + defer f.Close() + + pos := kit.Int(kit.Select("0", arg, 4)) + size := kit.Int(kit.Select("1024", arg, 3)) + count := kit.Int(kit.Select("3", arg, 2)) + + buf := make([]byte, count*size) + + if l, e := f.ReadAt(buf, int64(pos)); e == io.EOF || m.Assert(e) { + for i := 0; i < count; i++ { + if l < (i+1)*size { + m.Add("append", "data", hex.EncodeToString(buf[i*size:l])) + break + } + m.Add("append", "data", hex.EncodeToString(buf[i*size:(i+1)*size])) + } + } + } } return }}, @@ -365,12 +503,6 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", m.Cmdm(arg) return }}, - "componet": &ctx.Command{Name: "componet", Help: "组件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - tool := m.Confm("componet", []string{arg[0], arg[1]}) - msg := m.Find(kit.Format(tool["componet_ctx"])) - msg.Cmd(tool["componet_cmd"]).CopyTo(m) - return - }}, "remote": &ctx.Command{Name: "remote auto|dial|listen args...", Help: "连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { // 设备证书 if !m.Confs("runtime", "node.cert") || !m.Confs("runtime", "node.key") { diff --git a/src/examples/chat/chat.go b/src/examples/chat/chat.go index 12d6bd87..554e6f15 100644 --- a/src/examples/chat/chat.go +++ b/src/examples/chat/chat.go @@ -284,12 +284,25 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心", m.Table() break } + if len(arg) == 3 { - m.Confm("flow", []string{arg[1], "tool", arg[2], "list"}, func(index int, value map[string]interface{}) { - m.Add("append", "node", value["node"]) - m.Add("append", "group", value["group"]) - m.Add("append", "index", value["index"]) - m.Add("append", "name", value["name"]) + m.Confm("flow", []string{arg[1], "tool", arg[2], "list"}, func(index int, tool map[string]interface{}) { + m.Add("append", "river", arg[1]) + m.Add("append", "storm", arg[2]) + m.Add("append", "action", index) + + m.Add("append", "node", tool["node"]) + m.Add("append", "group", tool["group"]) + m.Add("append", "index", tool["index"]) + + m.Option("username", "shy") + msg := m.Cmd("ssh.cert", "tool", "check", tool["node"], tool["group"], tool["index"]) + + m.Add("append", "name", msg.Append("name")) + m.Add("append", "help", msg.Append("help")) + m.Add("append", "view", msg.Append("view")) + m.Add("append", "init", msg.Append("init")) + m.Add("append", "inputs", msg.Append("inputs")) }) m.Table() break @@ -297,7 +310,7 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心", if tool := m.Confm("flow", []string{arg[1], "tool", arg[2], "list", arg[3]}); tool != nil { m.Option("username", "shy") - m.Cmdy("ssh.remote", tool["node"], "componet", tool["group"], tool["index"]) + m.Cmdy("ssh.cert", "tool", "run", tool["node"], tool["group"], tool["index"], arg[4:]) break } } diff --git a/usr/librarys/chat.js b/usr/librarys/chat.js index 8ce12146..50a4c3f7 100644 --- a/usr/librarys/chat.js +++ b/usr/librarys/chat.js @@ -1,9 +1,9 @@ var page = Page({ - conf: {border: 4, banner: 105}, - size: function(event, sizes) { - sizes = sizes || {} + conf: {border: 4, banner: 105, layout: {river:160, source:60, action:60, storm:160}}, + onlayout: function(event, sizes) { var width = document.body.offsetWidth var height = document.body.offsetHeight-page.conf.banner + sizes = sizes || {} sizes.river == undefined && (sizes.river = page.river.offsetWidth-page.conf.border) sizes.storm == undefined && (sizes.storm = page.storm.offsetWidth-page.conf.border) @@ -14,11 +14,16 @@ var page = Page({ sizes.action == undefined && (sizes.action = page.action.offsetHeight-page.conf.border) sizes.source == undefined && (sizes.source = page.source.offsetHeight-page.conf.border) sizes.target = height - sizes.action - sizes.source - 2*page.conf.border + if (sizes.action == -1) { + sizes.action = height + sizes.target = 0 + sizes.source = 0 + } page.target.Size(sizes.width, sizes.target) page.source.Size(sizes.width, sizes.source) page.action.Size(sizes.width, sizes.action) + kit.History.add("lay", sizes) }, - oncontrol: function(event, target, action) { switch (action) { case "control": @@ -36,6 +41,7 @@ var page = Page({ break } }, + initOcean: function(page, pane, form, output) { var table = kit.AppendChild(output, "table") var ui = kit.AppendChild(pane, [{view: ["create ocean"], list: [ @@ -152,7 +158,7 @@ var page = Page({ }}}]) pane.Size = function(width, height) { - pane.style.display = width==0? "none": "block" + pane.style.display = (width==0 || height==0)? "none": "block" pane.style.width = width+"px" pane.style.height = height+"px" ui.first.style.width = (width-7)+"px" @@ -178,20 +184,18 @@ var page = Page({ }, } pane.Show = function() { - output.Update(["storm", river, water], "text", ["node", "name"], "index", false, function(line, index) { - if (event.shiftKey) { - page.target.Send("field", JSON.stringify({ - componet_group: "index", - componet_name: "river", - cmds: ["storm", river, water, index], - input: [{type: "input", data: {name: "hi", value: line.cmd}}] - })) - return - } - form.Run(["storm", river, water, index], function(msg) { - msg.append && msg.append[0]? + output.Update(["storm", river, water], "plugin", ["node", "name"], "index", false, function(line, index, event, args, cbs) { + var cmds = ["storm", river, water, index].concat(args) + + event.shiftKey? page.target.Send("field", JSON.stringify({ + componet_group: "index", componet_name: "river", + cmds: cmds, input: [{type: "input", data: {name: "hi", value: line.cmd}}] + + })): form.Run(cmds, function(msg) { + event.ctrlKey && (msg.append && msg.append[0]? page.target.Send("table", JSON.stringify(ctx.Table(msg))): - page.target.Send("text", msg.result.join("")) + page.target.Send("text", msg.result.join(""))) + cbs(msg) }) }) } @@ -200,8 +204,20 @@ var page = Page({ var name = prompt("name") name && form.Run(["river", "tool", river, water, "add", name], pane.Show) }, + "恢复": function(event) { + page.onlayout(event, page.conf.layout) + }, + "放大": function(event) { + page.onlayout(event, {action:300}) + }, + "最宽": function(event) { + page.onlayout(event, {river:0, storm:0}) + }, + "最大": function(event) { + page.onlayout(event, {river:0, action: -1, storm:0}) + }, } - return {"button": ["添加"], "action": pane.Action} + return {"button": ["添加", "恢复", "放大", "最宽", "最大"], "action": pane.Action} }, initStorm: function(page, pane, form, output) { var river = "" @@ -291,10 +307,10 @@ var page = Page({ output.Append = function(type, line, key, which, cb) { var index = list.length type = line.type || type - var ui = kit.AppendChild(output, page.View(type, line, key, function(event) { + var ui = page.View(output, type, line, key, function(event, cmds, cbs) { output.Select(index), pane.which.set(line[which]) - typeof cb == "function" && cb(line, index, event) - })) + typeof cb == "function" && cb(line, index, event, cmds, cbs) + }) if (type == "table") { kit.OrderTable(ui.last) } @@ -334,6 +350,6 @@ var page = Page({ return conf }) - page.size(null, {river:160, source:60, action:60, storm:160}) + page.onlayout(null, page.conf.layout) }, }) diff --git a/usr/librarys/example.js b/usr/librarys/example.js index 40e228f8..e17ee6bf 100644 --- a/usr/librarys/example.js +++ b/usr/librarys/example.js @@ -1,9 +1,10 @@ function Page(page) { page.__proto__ = { + _id: 1, ID: function() { + return this._id++ + }, Sync: function(m) { - var meta = m - var data = "" - var list = [] + var meta = m, data = "", list = [] return { change: function(cb) { list.push(cb) @@ -31,19 +32,24 @@ function Page(page) { }, } }, - View: function(type, line, key, cb) { + View: function(parent, type, line, key, cb) { + var ui = {} + var result = [] switch (type) { case "icon": - return [{view: ["item", "div"], list: [{type: "img", data: {src: line[key[0]]}}, {}]}] + result = [{view: ["item", "div"], list: [{type: "img", data: {src: line[key[0]]}}, {}]}] + break case "text": switch (key.length) { case 0: - return [{view: ["item", "div", "null"], click: cb}] + result = [{view: ["item", "div", "null"], click: cb}] + break case 1: - return [{view: ["item", "div", line[key[0]]], click: cb}] + result = [{view: ["item", "div", line[key[0]]], click: cb}] + break default: - return [{view: ["item", "div", line[key[0]]+"("+line[key[1]]+")"], click: cb}] + result = [{view: ["item", "div", line[key[0]]+"("+line[key[1]]+")"], click: cb}] } break @@ -63,7 +69,7 @@ function Page(page) { list.push({view: ["", "tr"], list: line}) } var result = [{view: [""], list: [{view: ["", "table"], list: list}]}] - return result + break case "field": var data = JSON.parse(line.text) @@ -73,6 +79,7 @@ function Page(page) { } var result = [{view: ["", "fieldset"], list: [ + {text: ["", "legend"]}, {name: "form", view: ["", "form"], dataset: { componet_group: data.componet_group, componet_name: data.componet_name, @@ -81,12 +88,97 @@ function Page(page) { {name: "table", view: ["", "table"]}, {view: ["", "code"], list: [{name: "code", view: ["", "pre"]}]}, ]}] - return result + break + case "plugin": + var id = "plugin"+page.ID() + var input = [{type: "input", style: {"display": "none"}}] + JSON.parse(line.inputs || "[]").forEach(function(item, index, inputs) { + function run(event) { + var args = [] + ui.option.querySelectorAll("input").forEach(function(item, index){ + if (index==0) { + return + } + if (item.type == "text") { + args.push(item.value) + } + }) + ui.option.Run(event, args, function(msg) { + ui.option.ondaemon(msg) + }) + } + + item.type == "button"? item.onclick = function(event) { + var plugin = page[id]; + (plugin[item.click] || function() { + run(event) + })(item, index, inputs, event, ui.option) + + }: item.onkeyup = function(event) { + event.key == "Enter" && (index == inputs.length-1? run(event): event.target.nextSibling.focus()) + if (event.ctrlKey) { + switch (event.key) { + case "k": + kit.DelText(target, target.selectionStart) + break + case "u": + kit.DelText(target, 0, target.selectionEnd) + break + case "w": + var start = target.selectionStart-2 + var end = target.selectionEnd-1 + for (var i = start; i >= 0; i--) { + if (target.value[end] == " " && target.value[i] != " ") { + break + } + if (target.value[end] != " " && target.value[i] == " ") { + break + } + } + kit.DelText(target, i+1, end-i) + break + + case "c": + ui.output.innerHTML = "" + break + case "r": + ui.output.innerHTML = "" + case "j": + run(event) + break + case "l": + page.action.scrollTo(0, ui.option.parentNode.offsetTop) + break + case "m": + event.stopPropagation() + var uis = page.View(parent, type, line, key, cb) + page.action.scrollTo(0, uis.option.parentNode.offsetTop) + ui.option.querySelectorAll("input")[1].focus() + break + } + } + } + input.push({type: "input", data: item}) + }) + + var result = [{view: [line.view, "fieldset"], data: {id: id}, list: [ + {script: "Plugin("+id+","+line.init+")"}, + {text: [line.name, "legend"]}, + {name: "option", view: ["option", "form"], data: {Run: cb}, list: input}, + {name: "output", view: ["output", "div"]}, + ]}] + break } + + ui = kit.AppendChild(parent, result) + return ui }, reload: function() { location.reload() + }, + showToast: function(text) { + }, onscroll: function(event, target, action) { switch (action) { @@ -97,9 +189,6 @@ function Page(page) { break } }, - showToast: function(text) { - - }, initHeader: function(page, field, option, output) { return [{"text": ["shycontext", "div", "title"]}] @@ -138,7 +227,7 @@ function Page(page) { return false } pane.Size = function(width, height) { - pane.style.display = width==0? "none": "block" + pane.style.display = (width==0 || height==0)? "none": "block" pane.style.width = width+"px" pane.style.height = height+"px" } @@ -168,7 +257,9 @@ function Page(page) { window.onload = function() { page.init(page) - window.onresize = page.size + window.onresize = function(event) { + page.onlayout && page.onlayout(event) + } document.body.onkeydown = function(event) { page.onscroll && page.onscroll(event, document.body, "scroll") } @@ -178,3 +269,13 @@ function Page(page) { } return page } +function Plugin(field, plugin) { + var option = field.querySelector("form.option") + var output = field.querySelector("div.output") + + plugin.__proto__ = { + field: field, + } + plugin.init(page, page.action, field, option, output) + page[field.id] = plugin +} diff --git a/usr/librarys/toolkit.js b/usr/librarys/toolkit.js index 2efa929a..08c4214b 100644 --- a/usr/librarys/toolkit.js +++ b/usr/librarys/toolkit.js @@ -3,7 +3,7 @@ kit = toolkit = { isSpace: function(c) { return c == " " || c == "Enter" }, - History: {dir: [], pod: [], ctx: [], cmd: [], txt: [], key: [], + History: {dir: [], pod: [], ctx: [], cmd: [], txt: [], key: [], lay: [], add: function(type, data) { var list = this[type] || [] data && list.push({time: Date.now(), data: data}) @@ -240,6 +240,11 @@ kit = toolkit = { child.type = "code" child.list = [{"type": "pre" ,"data": {"innerText": child.code[0]}, "name": child.code[1]}] child.code.length > 2 && (child.data["className"] = child.code[2]) + + } else if (child.script) { + child.data.innerHTML = child.script + child.type = "script" + } else if (child.include) { child.data["src"] = child.include[0] child.data["type"] = "text/javascript" diff --git a/usr/wiki/自然/编程/终端工具链/context.md b/usr/wiki/自然/编程/终端工具链/context.md index 62a4a42e..20c35fc5 100644 --- a/usr/wiki/自然/编程/终端工具链/context.md +++ b/usr/wiki/自然/编程/终端工具链/context.md @@ -268,6 +268,15 @@ $ cat etc/local.shy chat模块提供了信息管理。 +访问:http://localhost:9094/chat + +启动服务节点 +boot.sh +``` +~cli + runtime work.route mac +``` + ### 所有目录 #### 一级目录