1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 16:58:06 +08:00

mac add aaa.right web.render

This commit is contained in:
shaoying 2018-10-22 09:16:31 +08:00
parent 76fc21dddf
commit 9c90712446
16 changed files with 1085 additions and 1687 deletions

View File

@ -1,14 +1,2 @@
~aaa
# login load var/login.txt
~file1
history load var/history.txt
source etc/local.shy source etc/local.shy
~shell1
alias import nfs
alias send send
alias open open
alias dial dial
alias pwd pwd

View File

@ -69,7 +69,9 @@ func (aaa *AAA) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
return time.Unix(int64(n), 0).Format("15:03:04") return time.Unix(int64(n), 0).Format("15:03:04")
}}, }},
} }
c.Configs = map[string]*ctx.Config{} c.Configs = map[string]*ctx.Config{
"right": &ctx.Config{Name: "right", Value: map[string]interface{}{}, Help: "用户权限"},
}
s := new(AAA) s := new(AAA)
s.Context = c s.Context = c
@ -153,6 +155,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
} }
return true return true
}, c) }, c)
if m.Results(0) { if m.Results(0) {
return return
} }
@ -173,18 +176,26 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
} }
return true return true
}, c) }, c)
if m.Results(0) { if m.Results(0) {
m.Append("sessid", m.Result(0))
return
}
if arg[0] == "" {
return return
} }
m.Start(fmt.Sprintf("user%d", m.Capi("nuser", 1)), "密码登录", "password", arg[0]) m.Start(fmt.Sprintf("user%d", m.Capi("nuser", 1)), "密码登录", "password", arg[0])
m.Cap("password", "password", aaa.Password(arg[1]), "密码登录") m.Cap("password", "password", aaa.Password(arg[1]), "密码登录")
m.Append("sessid", m.Cap("sessid"))
m.Echo(m.Cap("sessid")) m.Echo(m.Cap("sessid"))
return return
case 1: case 1:
m.Sess("login", nil)
m.Travel(func(m *ctx.Message, n int) bool { m.Travel(func(m *ctx.Message, n int) bool {
if n > 0 && m.Cap("sessid") == arg[0] { if n > 0 && m.Cap("sessid") == arg[0] {
if int64(m.Capi("expire_time")) > time.Now().Unix() { if int64(m.Capi("expire_time")) > time.Now().Unix() {
m.Sess("login", m.Target().Message())
m.Echo(m.Cap("stream")) m.Echo(m.Cap("stream"))
} else { } else {
m.Target().Close(m) m.Target().Close(m)
@ -205,6 +216,92 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
} }
} }
}}, }},
"right": &ctx.Command{Name: "right [user [check|owner|share group [order] [add|del]]]", Form: map[string]int{"from": 1}, Help: "权限管理", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Travel(func(m *ctx.Message, n int) bool {
if n == 0 {
return true
}
if len(arg) == 0 {
m.Add("append", "user", m.Cap("stream"))
m.Add("append", "right", m.Confv("right"))
return true
}
if m.Cap("stream") == arg[0] {
if len(arg) == 1 { //查看所有权
for k, v := range m.Confv("right").(map[string]interface{}) {
m.Add("append", "group", k)
m.Add("append", "right", v)
}
return true
}
if arg[1] == "check" { //权限检查
if from := m.Confv("right", []interface{}{"right", "role"}); from != nil && from.(string) == "root" {
m.Echo("root")
}
if len(arg) == 2 {
return false
}
if from := m.Confv("right", []interface{}{arg[2], "right", "role"}); from != nil && from.(string) == "owner" {
m.Echo("owner")
}
if len(arg) == 3 {
return false
}
if from := m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}); from != nil && from.(string) == "share" {
m.Echo("share")
}
return false
}
if len(arg) == 2 { //分配人事权
if m.Option("from") != "root" {
return false
}
switch arg[1] {
case "add":
m.Confv("right", []interface{}{"right", "role"}, "root")
m.Confv("right", []interface{}{"right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{"right", "role"}, "")
}
return true
}
if len(arg) == 3 { //查看使用权
for k, v := range m.Confv("right", arg[2]).(map[string]interface{}) {
m.Add("append", "order", k)
m.Add("append", "right", v)
}
return true
}
switch arg[1] {
case "owner": //分配所有权
if m.Cmd("right", m.Option("from"), "check").Result(0) == "" {
return false
}
switch arg[3] {
case "add":
m.Confv("right", []interface{}{arg[2], "right", "role"}, "owner")
m.Confv("right", []interface{}{arg[2], "right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{arg[2], "right", "role"}, "")
}
case "share": //分配使用权
if m.Cmd("right", m.Option("from"), "check", arg[2]).Result(0) == "" {
return false
}
switch arg[4] {
case "add":
m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "share")
m.Confv("right", []interface{}{arg[2], arg[3], "right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "")
}
}
return false
}
return true
}, c)
m.Table()
}},
"cert": &ctx.Command{Name: "cert [filename]", Help: "导出证书", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "cert": &ctx.Command{Name: "cert [filename]", Help: "导出证书", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if aaa, ok := m.Target().Server.(*AAA); m.Assert(ok) && aaa.certificate != nil { if aaa, ok := m.Target().Server.(*AAA); m.Assert(ok) && aaa.certificate != nil {
certificate := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: aaa.certificate.Raw})) certificate := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: aaa.certificate.Raw}))

View File

@ -1,20 +1,16 @@
package cli // {{{ package cli
// }}}
import ( // {{{
"contexts/ctx"
import (
"contexts/ctx"
"fmt" "fmt"
"os"
"os/exec"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"os"
"os/exec"
"time" "time"
) )
// }}}
type Frame struct { type Frame struct {
key string key string
run bool run bool
@ -22,7 +18,6 @@ type Frame struct {
index int index int
list []string list []string
} }
type CLI struct { type CLI struct {
alias map[string][]string alias map[string][]string
label map[string]string label map[string]string
@ -33,7 +28,7 @@ type CLI struct {
*ctx.Context *ctx.Context
} }
func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
c.Caches = map[string]*ctx.Cache{ c.Caches = map[string]*ctx.Cache{
"level": &ctx.Cache{Name: "level", Value: "0", Help: "嵌套层级"}, "level": &ctx.Cache{Name: "level", Value: "0", Help: "嵌套层级"},
"parse": &ctx.Cache{Name: "parse(true/false)", Value: "true", Help: "命令解析"}, "parse": &ctx.Cache{Name: "parse(true/false)", Value: "true", Help: "命令解析"},
@ -43,15 +38,15 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
} }
c.Configs = map[string]*ctx.Config{ c.Configs = map[string]*ctx.Config{
"ps_time": &ctx.Config{Name: "ps_time", Value: "[15:04:05]", Help: "当前时间", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { "ps_time": &ctx.Config{Name: "ps_time", Value: "[15:04:05]", Help: "当前时间", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{ if len(arg) > 0 {
return arg[0] return arg[0]
} }
return time.Now().Format(x.Value.(string)) return time.Now().Format(x.Value.(string))
// }}}
}}, }},
"ps_end": &ctx.Config{Name: "ps_end", Value: "> ", Help: "命令行提示符结尾"}, "ps_end": &ctx.Config{Name: "ps_end", Value: "> ", Help: "命令行提示符结尾"},
"prompt": &ctx.Config{Name: "prompt(ps_count/ps_time/ps_target/ps_end/...)", Value: "ps_count ps_time ps_target ps_end", Help: "命令行提示符, 以空格分隔, 依次显示缓存或配置信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { "prompt": &ctx.Config{Name: "prompt(ps_count/ps_time/ps_target/ps_end/...)", Value: "ps_count ps_time ps_target ps_end", Help: "命令行提示符, 以空格分隔, 依次显示缓存或配置信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{ if len(arg) > 0 {
return arg[0] return arg[0]
} }
@ -64,7 +59,7 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
} }
} }
return strings.Join(ps, "") return strings.Join(ps, "")
// }}}
}}, }},
} }
@ -83,15 +78,11 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
return s return s
} }
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
// }}}
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
cli.Message = m cli.Message = m
return cli return cli
} }
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
// }}}
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
cli.Message = m cli.Message = m
m.Sess("cli", m) m.Sess("cli", m)
yac := m.Sess("yac") yac := m.Sess("yac")
@ -178,9 +169,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
} }
return false return false
} }
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool {
// }}}
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
switch cli.Context { switch cli.Context {
case m.Target(): case m.Target():
case m.Source(): case m.Source():
@ -188,8 +177,6 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
return true return true
} }
// }}}
var Pulse *ctx.Message var Pulse *ctx.Message
var Index = &ctx.Context{Name: "cli", Help: "管理中心", var Index = &ctx.Context{Name: "cli", Help: "管理中心",
Caches: map[string]*ctx.Cache{ Caches: map[string]*ctx.Cache{
@ -199,11 +186,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"init.shy": &ctx.Config{Name: "init.shy", Value: "etc/init.shy", Help: "启动脚本"}, "init.shy": &ctx.Config{Name: "init.shy", Value: "etc/init.shy", Help: "启动脚本"},
"exit.shy": &ctx.Config{Name: "exit.shy", Value: "etc/exit.shy", Help: "启动脚本"}, "exit.shy": &ctx.Config{Name: "exit.shy", Value: "etc/exit.shy", Help: "启动脚本"},
"cli_name": &ctx.Config{Name: "cli_name", Value: "shell", Help: "模块命名", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { "cli_name": &ctx.Config{Name: "cli_name", Value: "shell", Help: "模块命名", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{ if len(arg) > 0 {
return arg[0] return arg[0]
} }
return fmt.Sprintf("%s%d", x.Value, m.Capi("nshell", 1)) return fmt.Sprintf("%s%d", x.Value, m.Capi("nshell", 1))
// }}}
}}, }},
"cli_help": &ctx.Config{Name: "cli_help", Value: "shell", Help: "模块文档"}, "cli_help": &ctx.Config{Name: "cli_help", Value: "shell", Help: "模块文档"},
"cmd_timeout": &ctx.Config{Name: "cmd_timeout", Value: "60s", Help: "系统命令超时"}, "cmd_timeout": &ctx.Config{Name: "cmd_timeout", Value: "60s", Help: "系统命令超时"},
@ -239,28 +226,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} }
}}, }},
"label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if cli.label == nil { if cli.label == nil {
cli.label = map[string]string{} cli.label = map[string]string{}
} }
cli.label[arg[1]] = m.Option("file_pos") cli.label[arg[1]] = m.Option("file_pos")
} // }}} }
}}, }},
"goto": &ctx.Command{Name: "goto label [exp] condition", Help: "向上跳转到指定位置, label: 跳转位置, condition: 跳转条件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "goto": &ctx.Command{Name: "goto label [exp] condition", Help: "向上跳转到指定位置, label: 跳转位置, condition: 跳转条件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if pos, ok := cli.label[arg[1]]; ok { if pos, ok := cli.label[arg[1]]; ok {
if !ctx.Right(arg[len(arg)-1]) { if !ctx.Right(arg[len(arg)-1]) {
return return
} }
m.Append("file_pos0", pos) m.Append("file_pos0", pos)
} }
} // }}} }
}}, }},
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, result: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "return": &ctx.Command{Name: "return result...", Help: "结束脚本, result: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Add("append", "return", arg[1:]) m.Add("append", "return", arg[1:])
}}, }},
"target": &ctx.Command{Name: "target module", Help: "设置当前模块, module: 模块全名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "target": &ctx.Command{Name: "target module", Help: "设置当前模块, module: 模块全名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if len(arg) == 0 { if len(arg) == 0 {
m.Echo("%s", m.Cap("ps_target")) m.Echo("%s", m.Cap("ps_target"))
return return
@ -269,13 +256,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
cli.target = msg.Target() cli.target = msg.Target()
m.Cap("ps_target", cli.target.Name) m.Cap("ps_target", cli.target.Name)
} }
} // }}} }
}}, }},
"alias": &ctx.Command{ "alias": &ctx.Command{
Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]", Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]",
Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
switch len(arg) { switch len(arg) {
case 0: case 0:
for k, v := range cli.alias { for k, v := range cli.alias {
@ -318,21 +305,21 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Log("info", "%s: %v", arg[0], cli.alias[arg[0]]) m.Log("info", "%s: %v", arg[0], cli.alias[arg[0]])
} }
} }
} // }}} }
}}, }},
"sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if d, e := time.ParseDuration(arg[0]); m.Assert(e) { // {{{ if d, e := time.ParseDuration(arg[0]); m.Assert(e) {
m.Log("info", "sleep %v", d) m.Log("info", "sleep %v", d)
time.Sleep(d) time.Sleep(d)
m.Log("info", "sleep %v done", d) m.Log("info", "sleep %v done", d)
} // }}} }
}}, }},
"time": &ctx.Command{ "time": &ctx.Command{
Name: "time [time_format format] [parse when] when [begin|end|yestoday|tommorow|monday|sunday|first|last|origin|last]", Name: "time [time_format format] [parse when] when [begin|end|yestoday|tommorow|monday|sunday|first|last|origin|last]",
Form: map[string]int{"time_format": 1, "parse": 1, "time_interval": 1}, Form: map[string]int{"time_format": 1, "parse": 1, "time_interval": 1},
Help: "查看时间, time_format: 输出或解析的时间格式, parse: 输入的时间字符串, when: 输入的时间戳, 其它是时间偏移", Help: "查看时间, time_format: 输出或解析的时间格式, parse: 输入的时间字符串, when: 输入的时间戳, 其它是时间偏移",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
t := time.Now() // {{{ t := time.Now()
if m.Options("parse") { if m.Options("parse") {
n, e := time.ParseInLocation(m.Confx("time_format"), m.Option("parse"), time.Local) n, e := time.ParseInLocation(m.Confx("time_format"), m.Option("parse"), time.Local)
m.Assert(e) m.Assert(e)
@ -341,7 +328,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
if len(arg) > 0 { if len(arg) > 0 {
if i, e := strconv.ParseInt(arg[0], 10, 64); e == nil { if i, e := strconv.ParseInt(arg[0], 10, 64); e == nil {
m.Option("time_format", m.Conf("time_format"))
t = time.Unix(int64(i/int64(m.Confi("time_unit"))), 0) t = time.Unix(int64(i/int64(m.Confi("time_unit"))), 0)
arg = arg[1:] arg = arg[1:]
} else if n, e := time.ParseInLocation(m.Confx("time_format"), arg[0], time.Local); e == nil { } else if n, e := time.ParseInLocation(m.Confx("time_format"), arg[0], time.Local); e == nil {
@ -405,7 +391,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else { } else {
m.Echo(t.Format(m.Confx("time_format"))) m.Echo(t.Format(m.Confx("time_format")))
} }
// }}}
}}, }},
"echo": &ctx.Command{Name: "echo arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "echo": &ctx.Command{Name: "echo arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Echo("%s", strings.Join(arg, "")) m.Echo("%s", strings.Join(arg, ""))
@ -415,7 +401,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Echo(arg[0][1 : len(arg[0])-1]) m.Echo(arg[0][1 : len(arg[0])-1])
}}, }},
"exe": &ctx.Command{Name: "exe $ ( cmd )", Help: "解析嵌套命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "exe": &ctx.Command{Name: "exe $ ( cmd )", Help: "解析嵌套命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
switch len(arg) { switch len(arg) {
case 1: case 1:
m.Echo(arg[0]) m.Echo(arg[0])
@ -438,7 +424,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} //}}} } //}}}
}}, }},
"val": &ctx.Command{Name: "val exp", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "val": &ctx.Command{Name: "val exp", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
result := "false" // {{{ result := "false"
switch len(arg) { switch len(arg) {
case 0: case 0:
result = "" result = ""
@ -567,7 +553,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} }
} }
m.Echo(result) m.Echo(result)
// }}}
}}, }},
"exp": &ctx.Command{Name: "exp word", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "exp": &ctx.Command{Name: "exp word", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if len(arg) > 0 && arg[0] == "{" { if len(arg) > 0 && arg[0] == "{" {
@ -585,7 +571,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
return return
} }
pre := map[string]int{ // {{{ pre := map[string]int{
"=": 1, "=": 1,
"+": 2, "-": 2, "+": 2, "-": 2,
"*": 3, "/": 3, "%": 3, "*": 3, "/": 3, "%": 3,
@ -609,10 +595,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} }
m.Echo("%s", num[0]) m.Echo("%s", num[0])
// }}}
}}, }},
"var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 { // {{{ if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 {
switch arg[2] { switch arg[2] {
case "=": case "=":
m.Cap(arg[1], arg[3]) m.Cap(arg[1], arg[3])
@ -621,28 +607,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} }
} }
m.Echo(m.Cap(arg[1])) m.Echo(m.Cap(arg[1]))
// }}}
}}, }},
"let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
switch arg[2] { // {{{ switch arg[2] {
case "=": case "=":
m.Cap(arg[1], arg[3]) m.Cap(arg[1], arg[3])
case "<-": case "<-":
m.Cap(arg[1], m.Cap("last_msg")) m.Cap(arg[1], m.Cap("last_msg"))
} }
m.Echo(m.Cap(arg[1])) m.Echo(m.Cap(arg[1]))
// }}}
}}, }},
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
run := m.Caps("parse") && ctx.Right(arg[1]) run := m.Caps("parse") && ctx.Right(arg[1])
cli.stack = append(cli.stack, &Frame{pos: m.Optioni("file_pos"), key: key, run: run}) cli.stack = append(cli.stack, &Frame{pos: m.Optioni("file_pos"), key: key, run: run})
m.Capi("level", 1) m.Capi("level", 1)
m.Caps("parse", run) m.Caps("parse", run)
} // }}} }
}}, }},
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if !m.Caps("parse") { if !m.Caps("parse") {
m.Caps("parse", true) m.Caps("parse", true)
} else { } else {
@ -653,10 +639,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Caps("parse", !frame.run) m.Caps("parse", !frame.run)
} }
} }
} // }}} }
}}, }},
"end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if frame := cli.stack[len(cli.stack)-1]; frame.key == "for" && frame.run { if frame := cli.stack[len(cli.stack)-1]; frame.key == "for" && frame.run {
m.Append("file_pos0", frame.pos) m.Append("file_pos0", frame.pos)
return return
@ -667,13 +653,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else { } else {
m.Caps("parse", true) m.Caps("parse", true)
} }
} // }}} }
}}, }},
"for": &ctx.Command{ "for": &ctx.Command{
Name: "for [[express ;] condition]|[index message meta value]", Name: "for [[express ;] condition]|[index message meta value]",
Help: "循环语句, express: 每次循环运行的表达式, condition: 循环条件, index: 索引消息, message: 消息编号, meta: value: ", Help: "循环语句, express: 每次循环运行的表达式, condition: 循环条件, index: 索引消息, message: 消息编号, meta: value: ",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
run := m.Caps("parse") run := m.Caps("parse")
defer func() { m.Caps("parse", run) }() defer func() { m.Caps("parse", run) }()
@ -726,10 +712,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} }
m.Cap(arg[3], arg[3], frame.list[0], "临时变量") m.Cap(arg[3], arg[3], frame.list[0], "临时变量")
} }
} // }}} }
}}, }},
"cmd": &ctx.Command{Name: "cmd word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "cmd": &ctx.Command{Name: "cmd word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
detail := []string{} detail := []string{}
if a, ok := cli.alias[arg[0]]; ok { if a, ok := cli.alias[arg[0]]; ok {
detail = append(detail, a...) detail = append(detail, a...)
@ -774,14 +760,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Capi("last_msg", 0, msg.Code()) m.Capi("last_msg", 0, msg.Code())
m.Capi("ps_count", 1) m.Capi("ps_count", 1)
} }
// }}}
}}, }},
"system": &ctx.Command{ "system": &ctx.Command{
Name: "system [cmd_combine true|false] [cmd_timeout time] word...", Name: "system [cmd_combine true|false] [cmd_timeout time] word...",
Help: "调用系统命令, cmd_combine: 非交互式命令, cmd_timeout: 命令超时, word: 命令", Help: "调用系统命令, cmd_combine: 非交互式命令, cmd_timeout: 命令超时, word: 命令",
Form: map[string]int{"cmd_combine": 1, "cmd_timeout": 1}, Form: map[string]int{"cmd_combine": 1, "cmd_timeout": 1},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
system := map[string]bool{"vi": true} // {{{ system := map[string]bool{"vi": true}
ui, ok := system[arg[0]] ui, ok := system[arg[0]]
if ui = ok && ui; m.Option("cmd_combine") != "" { if ui = ok && ui; m.Option("cmd_combine") != "" {
ui = !m.Options("cmd_combine") ui = !m.Options("cmd_combine")
@ -816,7 +802,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
case <-wait: case <-wait:
} }
} }
// }}}
}}, }},
"login": &ctx.Command{Name: "login username password", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "login": &ctx.Command{Name: "login username password", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Sess("aaa", false).Cmd("login", arg[0], arg[1]) m.Sess("aaa", false).Cmd("login", arg[0], arg[1])
@ -827,6 +813,27 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"tmux": &ctx.Command{Name: "tmux", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "tmux": &ctx.Command{Name: "tmux", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Copy(m.Spawn().Cmd("system", "tmux", arg), "result") m.Copy(m.Spawn().Cmd("system", "tmux", arg), "result")
}}, }},
"buffer": &ctx.Command{Name: "buffer", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
bufs := strings.Split(m.Spawn().Cmd("system", "tmux", "list-buffers").Result(0), "\n")
n := 3
if m.Option("limit") != "" {
n = m.Optioni("limit")
}
for i, b := range bufs {
if i >= n {
break
}
bs := strings.SplitN(b, ": ", 3)
if len(bs) > 1 {
m.Add("append", "buffer", bs[0][:len(bs[0])])
m.Add("append", "length", bs[1][:len(bs[1])-6])
m.Add("append", "string", bs[2][1:len(bs[2])-1])
}
}
m.Echo(m.Append("string"))
}},
}, },
Index: map[string]*ctx.Context{ Index: map[string]*ctx.Context{
"void": &ctx.Context{Caches: map[string]*ctx.Cache{"nshell": &ctx.Cache{}}}, "void": &ctx.Context{Caches: map[string]*ctx.Cache{"nshell": &ctx.Cache{}}},

View File

@ -709,7 +709,14 @@ func (m *Message) Search(key string, root ...bool) []*Message {
} }
func (m *Message) Sess(key string, arg ...interface{}) *Message { func (m *Message) Sess(key string, arg ...interface{}) *Message {
spawn := true spawn := true
if _, ok := m.Sessions[key]; !ok && len(arg) > 0 { if len(arg) > 0 {
switch v := arg[0].(type) {
case bool:
spawn, arg = v, arg[1:]
}
}
if len(arg) > 0 {
if m.Sessions == nil { if m.Sessions == nil {
m.Sessions = make(map[string]*Message) m.Sessions = make(map[string]*Message)
} }
@ -747,13 +754,9 @@ func (m *Message) Sess(key string, arg ...interface{}) *Message {
m.Sessions[key] = m.Search(value, root)[0] m.Sessions[key] = m.Search(value, root)[0]
} }
return m.Sessions[key] return m.Sessions[key]
} case nil:
} m.Sessions[key] = nil
return nil
if len(arg) > 0 {
switch v := arg[0].(type) {
case bool:
spawn = v
} }
} }
@ -1077,6 +1080,14 @@ func (m *Message) Sort(key string, arg ...string) *Message {
for j := i + 1; j < len(table); j++ { for j := i + 1; j < len(table); j++ {
result := false result := false
switch cmp { switch cmp {
case "str":
if table[i][key] > table[j][key] {
result = true
}
case "str_r":
if table[i][key] < table[j][key] {
result = true
}
case "int": case "int":
a, e := strconv.Atoi(table[i][key]) a, e := strconv.Atoi(table[i][key])
m.Assert(e) m.Assert(e)
@ -1093,14 +1104,6 @@ func (m *Message) Sort(key string, arg ...string) *Message {
if a < b { if a < b {
result = true result = true
} }
case "string":
if table[i][key] > table[j][key] {
result = true
}
case "string_r":
if table[i][key] < table[j][key] {
result = true
}
case "time": case "time":
ti, e := time.ParseInLocation(m.Confx("time_layout"), table[i][key], time.Local) ti, e := time.ParseInLocation(m.Confx("time_layout"), table[i][key], time.Local)
m.Assert(e) m.Assert(e)
@ -1964,16 +1967,18 @@ var CGI = template.FuncMap{
m.Assert(e) m.Assert(e)
index = i index = i
} }
if len(arg) == 2 { if len(arg) == 2 {
return m.Detail(index) return m.Detail(index)
} }
return m.Detail(index, arg[2]) return m.Detail(index, arg[2])
case map[string][]string: case map[string][]string:
return strings.Join(m["detail"], "") return strings.Join(m["detail"], "")
case []string: case []string:
return strings.Join(m, "") return strings.Join(m, "")
default: default:
return fmt.Sprintf("%v", arg[0]) return m
} }
return "" return ""
}, },
@ -2016,7 +2021,7 @@ var CGI = template.FuncMap{
case []string: case []string:
return strings.Join(m, "") return strings.Join(m, "")
default: default:
return fmt.Sprintf("%v", arg[0]) return m
} }
return "" return ""
}, },
@ -2040,16 +2045,18 @@ var CGI = template.FuncMap{
m.Assert(e) m.Assert(e)
index = i index = i
} }
if len(arg) == 2 { if len(arg) == 2 {
return m.Result(index) return m.Result(index)
} }
return m.Result(index, arg[2]) return m.Result(index, arg[2])
case map[string][]string: case map[string][]string:
return strings.Join(m["result"], "") return strings.Join(m["result"], "")
case []string: case []string:
return strings.Join(m, "") return strings.Join(m, "")
default: default:
return fmt.Sprintf("%v", arg[0]) return m
} }
return "" return ""
}, },
@ -2092,11 +2099,55 @@ var CGI = template.FuncMap{
case []string: case []string:
return strings.Join(m, "") return strings.Join(m, "")
default: default:
return fmt.Sprintf("%v", arg[0]) return m
} }
return "" return ""
}, },
"unscaped": func(str string) interface{} { "table": func(arg ...interface{}) []interface{} {
if len(arg) == 0 {
return []interface{}{}
}
switch m := arg[0].(type) {
case *Message:
if len(m.Meta["append"]) == 0 {
return []interface{}{}
}
if len(arg) == 1 {
data := []interface{}{}
nrow := len(m.Meta[m.Meta["append"][0]])
for i := 0; i < nrow; i++ {
line := map[string]string{}
for _, k := range m.Meta["append"] {
line[k] = m.Meta[k][i]
if len(m.Meta[k]) != i {
continue
}
}
data = append(data, line)
}
return data
}
case map[string][]string:
if len(arg) == 1 {
data := []interface{}{}
nrow := len(m[m["append"][0]])
for i := 0; i < nrow; i++ {
line := map[string]string{}
for _, k := range m["append"] {
line[k] = m[k][i]
}
data = append(data, line)
}
return data
}
}
return []interface{}{}
},
"unescape": func(str string) interface{} {
return template.HTML(str) return template.HTML(str)
}, },
@ -2978,7 +3029,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
"where_field": 1, "where_value": 1, "where_field": 1, "where_value": 1,
"sort_field": 1, "sort_order": 1, "sort_field": 1, "sort_order": 1,
"page_limit": 1, "page_offset": 1, "page_limit": 1, "page_offset": 1,
"select": 3, "format_field": 2,
"select": 3,
}, },
Hand: func(m *Message, c *Context, key string, arg ...string) { Hand: func(m *Message, c *Context, key string, arg ...string) {
offset, e := strconv.Atoi(m.Confx("page_offset")) offset, e := strconv.Atoi(m.Confx("page_offset"))
@ -3022,6 +3074,12 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
de.Decode(&save) de.Decode(&save)
} }
format_field := m.Option("format_field")
format_str := "%s"
if format_field != "" {
format_str = m.Meta["format_field"][1]
}
// sort_field := m.Option("sort_field") // sort_field := m.Option("sort_field")
// sort_order := m.Option("sort_order") // sort_order := m.Option("sort_order")
m.BackTrace(func(m *Message) bool { m.BackTrace(func(m *Message) bool {
@ -3113,7 +3171,11 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
m.Add("append", "index", "0") m.Add("append", "index", "0")
for k, v := range val { for k, v := range val {
if len(fields) == 0 || fields[k] { if len(fields) == 0 || fields[k] {
m.Add("append", k, v) if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v))
} else {
m.Add("append", k, v)
}
} }
} }
case []interface{}: case []interface{}:
@ -3134,7 +3196,11 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
m.Add("append", "index", i) m.Add("append", "index", i)
for k, v := range val { for k, v := range val {
if len(fields) == 0 || fields[k] { if len(fields) == 0 || fields[k] {
m.Add("append", k, v) if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v, v))
} else {
m.Add("append", k, v)
}
} }
} }
} }
@ -3142,11 +3208,18 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
case []string: case []string:
for i, v := range val { for i, v := range val {
m.Add("append", "index", i) m.Add("append", "index", i)
m.Add("append", "value", v) if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v, v))
} else {
m.Add("append", k, v)
}
} }
default: default:
m.Echo("%v", Trans(val)[0]) m.Echo("%v", Trans(val)[0])
} }
case 3:
m.Echo("%v", m.Confv(arg[0], strings.Split(arg[1], "."), arg[2]))
default: default:
m.Echo("%v", m.Confv(arg[0], arg[1:])) m.Echo("%v", m.Confv(arg[0], arg[1:]))
return false return false

View File

@ -68,8 +68,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) {
switch k { switch k {
case "filename": case "filename":
m.Add("append", "filename", "..") m.Add("append", "filename", "..")
case "dir": case "is_dir":
m.Add("append", "dir", "true") m.Add("append", "is_dir", "true")
case "size": case "size":
m.Add("append", "size", 0) m.Add("append", "size", 0)
case "line": case "line":
@ -130,8 +130,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) {
switch k { switch k {
case "filename": case "filename":
m.Add("append", "filename", filename) m.Add("append", "filename", filename)
case "dir": case "is_dir":
m.Add("append", "dir", f.IsDir()) m.Add("append", "is_dir", f.IsDir())
case "size": case "size":
m.Add("append", "size", f.Size()) m.Add("append", "size", f.Size())
case "line": case "line":
@ -803,11 +803,12 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
"buf_size": &ctx.Config{Name: "buf_size", Value: "1024", Help: "读取文件的缓存区的大小"}, "buf_size": &ctx.Config{Name: "buf_size", Value: "1024", Help: "读取文件的缓存区的大小"},
"qr_size": &ctx.Config{Name: "qr_size", Value: "256", Help: "生成二维码的图片的大小"}, "qr_size": &ctx.Config{Name: "qr_size", Value: "256", Help: "生成二维码的图片的大小"},
"dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"}, "dir_root": &ctx.Config{Name: "dir_root", Value: "usr", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_deep": &ctx.Config{Name: "dir_deep(yes/no)", Value: "yes", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"}, "dir_deep": &ctx.Config{Name: "dir_deep(yes/no)", Value: "yes", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_type": &ctx.Config{Name: "dir_type(file/dir)", Value: "file", Help: "dir命令输出的文件类型, file: 只输出普通文件, dir: 只输出目录文件, 否则输出所有文件"}, "dir_type": &ctx.Config{Name: "dir_type(file/dir)", Value: "file", Help: "dir命令输出的文件类型, file: 只输出普通文件, dir: 只输出目录文件, 否则输出所有文件"},
"dir_field": &ctx.Config{Name: "dir_field", Value: "filename line size time", Help: "表格排序字段"}, "dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"},
"dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_field": &ctx.Config{Name: "dir_field", Value: "filename is_dir line size time", Help: "表格排序字段"},
"sort_field": &ctx.Config{Name: "sort_field", Value: "line", Help: "表格排序字段"}, "sort_field": &ctx.Config{Name: "sort_field", Value: "line", Help: "表格排序字段"},
"sort_order": &ctx.Config{Name: "sort_order(int/int_r/string/string_r/time/time_r)", Value: "int", Help: "表格排序类型"}, "sort_order": &ctx.Config{Name: "sort_order(int/int_r/string/string_r/time/time_r)", Value: "int", Help: "表格排序类型"},
@ -1078,13 +1079,16 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
if len(arg) == 1 { if len(arg) == 1 {
var data interface{} var data interface{}
e := json.Unmarshal([]byte(arg[0]), &data) e := json.Unmarshal([]byte(arg[0]), &data)
if e != nil {
return
}
m.Assert(e) m.Assert(e)
buf, e := json.MarshalIndent(data, "", " ") buf, e := json.MarshalIndent(data, "", " ")
m.Assert(e) m.Assert(e)
m.Echo("'") // m.Echo("'")
m.Echo(string(buf)) m.Echo(string(buf))
m.Echo("'") // m.Echo("'")
return return
} }
@ -1122,10 +1126,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
"pwd": &ctx.Command{Name: "pwd", Help: "查看当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "pwd": &ctx.Command{Name: "pwd", Help: "查看当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Options("dir") { if m.Options("dir") {
m.Echo(m.Option("dir")) m.Echo(m.Option("dir"))
m.Add("append", "hi", "hello")
m.Add("append", "he", "hello")
m.Add("append", "hi", "world")
m.Add("append", "he", "world")
return return
} }
if len(arg) > 0 { if len(arg) > 0 {
@ -1134,20 +1134,31 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
wd, e := os.Getwd() wd, e := os.Getwd()
m.Assert(e) m.Assert(e)
m.Echo(wd) m.Echo(wd)
m.Append("hi", "hello")
}}, }},
"dir": &ctx.Command{ "dir": &ctx.Command{
Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type file|dir] [sort_field name] [sort_order type]", Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type both|file|dir] [sort_field name] [sort_order type]",
Help: "查看目录, dir: 目录名, dir_info: 显示统计信息, dir_name: 文件名类型, dir_type: 文件类型, sort_field: 排序字段, sort_order: 排序类型", Help: "查看目录, dir: 目录名, dir_info: 显示统计信息, dir_name: 文件名类型, dir_type: 文件类型, sort_field: 排序字段, sort_order: 排序类型",
Form: map[string]int{"dir_field": 1, "dir_deep": 1, "dir_info": 1, "dir_name": 1, "dir_type": 1, "sort_field": 1, "sort_order": 1}, Form: map[string]int{
"dir_root": 1,
"dir_deep": 1,
"dir_type": 1,
"dir_name": 1,
"dir_info": 1,
"dir_link": 1,
"dir_field": 1,
"sort_field": 1,
"sort_order": 1,
},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
d := "./" + m.Option("dir")
if len(arg) > 0 { if len(arg) > 0 {
d = arg[0] m.Option("dir", arg[0])
} }
m.Option("dir", path.Clean(m.Option("dir")))
d := path.Join(m.Confx("dir_root"), m.Option("dir"))
if s, e := os.Stat(d); m.Assert(e) && !s.IsDir() { if s, e := os.Stat(d); m.Assert(e) && !s.IsDir() {
d = path.Dir(d) d = path.Dir(d)
} }
fields := strings.Split(m.Confx("dir_field"), " ") fields := strings.Split(m.Confx("dir_field"), " ")
trip := 0 trip := 0
@ -1170,22 +1181,30 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
key := m.Meta["append"][i] key := m.Meta["append"][i]
switch key { switch key {
case "filename": case "filename":
v = maps[key]
if line > -1 && trip > 0 && trip <= len(v) { if line > -1 && trip > 0 && trip <= len(v) {
v = v[trip:] v = v[trip:]
m.Meta["filename"][line] = v if m.Options("dir_link") {
m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v)
} else {
m.Meta["filename"][line] = v
}
}
if line > -1 {
if m.Options("dir_link") {
m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v)
}
} }
case "dir":
continue
} }
m.Echo("%s\t", v)
} }
m.Echo("\n")
return true return true
}) })
if !m.Options("dir_link") {
m.Table()
}
for _, v := range info { for _, v := range info {
m.Echo("%s: %s\n", v, m.Option(v)) m.Echo("%s: %s\n", v, m.Option(v))
} }
}}, }},
"git": &ctx.Command{ "git": &ctx.Command{
Name: "git branch|status|diff|log|info arg... [dir path]...", Name: "git branch|status|diff|log|info arg... [dir path]...",

View File

@ -27,8 +27,8 @@ type MUX interface {
type WEB struct { type WEB struct {
*http.Client *http.Client
*http.ServeMux *http.ServeMux
*http.Server server *http.Server
*template.Template template *template.Template
*ctx.Context *ctx.Context
} }
@ -80,7 +80,9 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) {
m.TryCatch(m.Spawn(), true, func(msg *ctx.Message) { m.TryCatch(m.Spawn(), true, func(msg *ctx.Message) {
msg.Add("option", "method", r.Method).Add("option", "path", r.URL.Path) msg.Add("option", "method", r.Method).Add("option", "path", r.URL.Path)
msg.Option("remote_addr", r.RemoteAddr)
msg.Option("referer", r.Header.Get("Referer")) msg.Option("referer", r.Header.Get("Referer"))
msg.Option("accept", r.Header.Get("Accept"))
if r.ParseForm(); len(r.PostForm) > 0 { if r.ParseForm(); len(r.PostForm) > 0 {
for k, v := range r.PostForm { for k, v := range r.PostForm {
@ -101,11 +103,11 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) {
switch { switch {
case msg.Has("redirect"): case msg.Has("redirect"):
http.Redirect(w, r, msg.Append("redirect"), http.StatusFound) http.Redirect(w, r, msg.Append("redirect"), http.StatusTemporaryRedirect)
case msg.Has("directory"): case msg.Has("directory"):
http.ServeFile(w, r, msg.Append("directory")) http.ServeFile(w, r, msg.Append("directory"))
case msg.Has("template"): case msg.Has("componet"):
msg.Spawn().Cmd("/render", msg.Meta["template"]) msg.Spawn().Add("option", "componet_group", msg.Meta["componet"]).Cmd("/render")
case msg.Has("append"): case msg.Has("append"):
meta := map[string]interface{}{} meta := map[string]interface{}{}
if len(msg.Meta["result"]) > 0 { if len(msg.Meta["result"]) > 0 {
@ -208,16 +210,16 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool {
web.Caches["protocol"] = &ctx.Cache{Name: "protocol", Value: m.Confx("protocol", arg, 2), Help: "服务协议"} web.Caches["protocol"] = &ctx.Cache{Name: "protocol", Value: m.Confx("protocol", arg, 2), Help: "服务协议"}
web.Caches["address"] = &ctx.Cache{Name: "address", Value: m.Confx("address", arg, 1), Help: "服务地址"} web.Caches["address"] = &ctx.Cache{Name: "address", Value: m.Confx("address", arg, 1), Help: "服务地址"}
m.Log("info", "%d %s://%s", m.Capi("nserve", 1), m.Cap("protocol"), m.Cap("stream", m.Cap("address"))) m.Log("info", "%d %s://%s", m.Capi("nserve", 1), m.Cap("protocol"), m.Cap("stream", m.Cap("address")))
web.Server = &http.Server{Addr: m.Cap("address"), Handler: web} web.server = &http.Server{Addr: m.Cap("address"), Handler: web}
if m.Caps("master", true); m.Cap("protocol") == "https" { if m.Caps("master", true); m.Cap("protocol") == "https" {
web.Caches["cert"] = &ctx.Cache{Name: "cert", Value: m.Confx("cert", arg, 3), Help: "服务证书"} web.Caches["cert"] = &ctx.Cache{Name: "cert", Value: m.Confx("cert", arg, 3), Help: "服务证书"}
web.Caches["key"] = &ctx.Cache{Name: "key", Value: m.Confx("key", arg, 4), Help: "服务密钥"} web.Caches["key"] = &ctx.Cache{Name: "key", Value: m.Confx("key", arg, 4), Help: "服务密钥"}
m.Log("info", "cert [%s]", m.Cap("cert")) m.Log("info", "cert [%s]", m.Cap("cert"))
m.Log("info", "key [%s]", m.Cap("key")) m.Log("info", "key [%s]", m.Cap("key"))
web.Server.ListenAndServeTLS(m.Cap("cert"), m.Cap("key")) web.server.ListenAndServeTLS(m.Cap("cert"), m.Cap("key"))
} else { } else {
web.Server.ListenAndServe() web.server.ListenAndServe()
} }
return true return true
} }
@ -244,16 +246,192 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
"cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"},
"key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"},
"template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "路由数量"}, "web_site": &ctx.Config{Name: "web_site", Value: []interface{}{
"template_file": &ctx.Config{Name: "template_file", Value: "usr/template", Help: "路由数量"}, map[string]interface{}{"_name": "MDN", "site": "https://developer.mozilla.org"},
"template": &ctx.Config{Name: "template", Value: map[string]interface{}{ map[string]interface{}{"_name": "github", "site": "https://github.com"},
"index": []interface{}{ }, Help: "web_site"},
"template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "模板路径"},
"componet_context": &ctx.Config{Name: "component_context", Value: "nfs", Help: "默认模块"},
"componet_command": &ctx.Config{Name: "component_command", Value: "pwd", Help: "默认命令"},
"componet_group": &ctx.Config{Name: "component_group", Value: "index", Help: "默认组件"},
"componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
"login": []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "message", "title": "message", "template": "head", "name": "head", "help": "head",
"context": "nfs", "command": "pwd", "context": "", "command": "", "arguments": []interface{}{},
},
map[string]interface{}{
"template": "componet", "name": "login", "help": "login",
"context": "aaa", "command": "login", "arguments": []interface{}{"@username", "@password"},
"inputs": []interface{}{
map[string]interface{}{
"type": "text", "name": "username",
"label": "username", "value": "",
},
map[string]interface{}{
"type": "password", "name": "password",
"label": "password", "value": "",
},
map[string]interface{}{
"type": "button", "name": "string",
"label": "string", "value": "login",
},
},
"display_append": "",
"display_result": "",
"result_reload": "10",
},
map[string]interface{}{
"template": "tail", "name": "tail", "help": "tail",
"context": "", "command": "", "arguments": []interface{}{},
}, },
}, },
}, Help: "路由数量"}, "index": []interface{}{
map[string]interface{}{
"template": "head", "name": "head", "help": "head",
"context": "", "command": "", "arguments": []interface{}{},
},
map[string]interface{}{
"template": "clipboard", "name": "clipbaord", "help": "clipbaord",
"context": "", "command": "", "arguments": []interface{}{},
},
map[string]interface{}{
"template": "componet", "name": "message", "help": "message",
"context": "cli", "command": "buffer", "arguments": []interface{}{},
"inputs": []interface{}{
map[string]interface{}{
"type": "text", "name": "limit",
"label": "limit", "value": "3",
},
map[string]interface{}{
"type": "button", "name": "string",
"label": "string", "value": "refresh",
},
},
},
map[string]interface{}{
"template": "componet", "name": "time", "help": "time",
"context": "cli", "command": "time",
"arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{
"type": "text", "name": "time_format",
"label": "format", "value": "2006-01-02 15:04:05",
},
map[string]interface{}{
"type": "text", "name": "string",
"label": "string", "value": "",
},
map[string]interface{}{
"type": "button", "name": "button",
"label": "string", "value": "refresh",
},
},
},
map[string]interface{}{
"template": "componet", "name": "json", "help": "json",
"context": "nfs", "command": "json",
"arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{
"type": "text", "name": "string",
"label": "string", "value": "",
},
map[string]interface{}{
"type": "button", "name": "button",
"label": "string", "value": "refresh",
},
},
},
map[string]interface{}{
"template": "componet", "name": "dir", "help": "dir",
"context": "nfs", "command": "dir",
"arguments": []interface{}{"@dir",
"dir_deep", "no",
"dir_name", "name",
"dir_link", "<a class='download' data-type='%s'>%s<a>",
"dir_info", "",
},
"inputs": []interface{}{
map[string]interface{}{
"type": "text", "name": "dir",
"label": "dir", "value": "",
},
map[string]interface{}{
"type": "choice", "name": "dir_type",
"label": "dir_type", "value": "both",
"choice": []interface{}{
map[string]interface{}{
"name": "both", "value": "both",
},
map[string]interface{}{
"name": "file", "value": "file",
},
map[string]interface{}{
"name": "dir", "value": "dir",
},
},
},
map[string]interface{}{
"type": "choice", "name": "sort_field",
"label": "sort_field", "value": "time",
"choice": []interface{}{
map[string]interface{}{
"name": "filename", "value": "filename",
},
map[string]interface{}{
"name": "line", "value": "line",
},
map[string]interface{}{
"name": "size", "value": "size",
},
map[string]interface{}{
"name": "time", "value": "time",
},
},
},
map[string]interface{}{
"type": "choice", "name": "sort_order",
"label": "sort_order", "value": "time",
"choice": []interface{}{
map[string]interface{}{
"name": "str", "value": "str",
},
map[string]interface{}{
"name": "str_r", "value": "str_r",
},
map[string]interface{}{
"name": "int", "value": "int",
},
map[string]interface{}{
"name": "int_r", "value": "int_r",
},
map[string]interface{}{
"name": "time", "value": "time",
},
map[string]interface{}{
"name": "time_r", "value": "time_r",
},
},
},
},
},
map[string]interface{}{
"template": "componet", "name": "web_site", "help": "web_site",
"context": "web", "command": "config",
"arguments": []interface{}{
"web_site",
"format_field", "site", "<a href='%s'>%s<a>",
},
"display_result": "",
},
map[string]interface{}{
"template": "tail", "name": "tail", "help": "tail",
"context": "", "command": "", "arguments": []interface{}{},
},
},
}, Help: "组件列表"},
}, },
Commands: map[string]*ctx.Command{ Commands: map[string]*ctx.Command{
"client": &ctx.Command{Name: "client address [output [editor]]", Help: "添加浏览器配置, address: 默认地址, output: 输出路径, editor: 编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "client": &ctx.Command{Name: "client address [output [editor]]", Help: "添加浏览器配置, address: 默认地址, output: 输出路径, editor: 编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
@ -517,55 +695,248 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
} }
} }
}}, }},
"/demo": &ctx.Command{Name: "/demo template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "template": &ctx.Command{Name: "template [file [directory]]|[name [content]]", Help: "添加模板, content: 模板内容, directory: 模板目录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Append("template", "index")
}},
"template": &ctx.Command{Name: "template [file directory]|[name content]", Help: "添加模块, content: 模板内容, directory: 模板目录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { if web, ok := m.Target().Server.(*WEB); m.Assert(ok) {
if len(arg) == 0 { if len(arg) == 0 {
for _, v := range web.Template.Templates() { for _, v := range web.template.Templates() {
m.Add("append", "name", v.Name()) m.Add("append", "name", v.Name())
} }
m.Sort("name").Table() m.Sort("name").Table()
return return
} }
if web.Template == nil { if web.template == nil {
web.Template = template.New("render").Funcs(ctx.CGI) web.template = template.New("render").Funcs(ctx.CGI)
} }
dir := path.Join(m.Confx("template_dir", arg, 1), arg[0]) dir := path.Join(m.Confx("template_dir", arg, 1), arg[0])
if t, e := web.Template.ParseGlob(dir); e == nil { if t, e := web.template.ParseGlob(dir); e == nil {
web.Template = t web.template = t
} else { } else {
m.Log("info", "%s", e)
if len(arg) > 1 { if len(arg) > 1 {
web.Template = template.Must(web.Template.New(arg[0]).Parse(arg[1])) web.template = template.Must(web.template.New(arg[0]).Parse(arg[1]))
} else { } else {
buf := bytes.NewBuffer(make([]byte, 1024)) tmpl, e := web.template.Clone()
tmpl, e := web.Template.Clone()
m.Assert(e) m.Assert(e)
tmpl.Funcs(ctx.CGI)
buf := bytes.NewBuffer(make([]byte, 1024))
tmpl.ExecuteTemplate(buf, arg[0], m) tmpl.ExecuteTemplate(buf, arg[0], m)
m.Echo(string(buf.Bytes())) m.Echo(string(buf.Bytes()))
} }
} }
} }
}}, }},
"/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { "componet": &ctx.Command{Name: "componet [group [order [arg...]]]", Help: "添加组件, group: 组件分组, arg...: 组件参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { switch len(arg) {
w := m.Optionv("response").(http.ResponseWriter) case 0:
w.Header().Add("Content-Type", "text/html") for k, v := range m.Confv("componet").(map[string]interface{}) {
tmpl, e := web.Template.Clone() for i, val := range v.([]interface{}) {
m.Assert(e) value := val.(map[string]interface{})
m.Add("append", "group", k)
for _, v := range m.Confv("template", arg[0]).([]interface{}) { m.Add("append", "order", i)
//执行命令 m.Add("append", "name", value["name"])
val := v.(map[string]interface{}) m.Add("append", "help", value["help"])
if _, ok := val["command"]; ok { m.Add("append", "context", value["context"])
msg := m.Find(val["context"].(string)).Cmd(val["command"], val["argument"]) m.Add("append", "command", value["command"])
msg.Option("title", val["title"])
m.Assert(tmpl.ExecuteTemplate(w, val["name"].(string), msg))
} }
} }
m.Sort("group").Table()
case 1:
for i, val := range m.Confv("componet", arg[0]).([]interface{}) {
value := val.(map[string]interface{})
m.Add("append", "order", i)
m.Add("append", "name", value["name"])
m.Add("append", "help", value["help"])
m.Add("append", "context", value["context"])
m.Add("append", "command", value["command"])
}
m.Table()
case 2:
value := m.Confv("componet", []interface{}{arg[0], arg[1]}).(map[string]interface{})
for k, v := range value {
m.Add("append", k, v)
}
m.Table()
default:
if com, ok := m.Confv("componet", []interface{}{arg[0], arg[1]}).(map[string]interface{}); ok {
for i := 2; i < len(arg)-1; i += 2 {
com[arg[i]] = arg[i+1]
}
} else {
m.Confv("componet", []interface{}{arg[0], arg[1]}, map[string]interface{}{
"name": arg[2], "help": arg[3],
"context": m.Confx("componet_context", arg, 4),
"command": m.Confx("componet_command", arg, 5),
})
break
}
}
}},
"session": &ctx.Command{Name: "session", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
sessid := m.Option("sessid")
if sessid == "" && m.Options("username") && m.Options("password") {
sessid = m.Sess("aaa").Cmd("login", m.Option("username"), m.Option("password")).Result(0)
}
if sessid == "" && m.Options("remote_addr") {
sessid = m.Sess("aaa").Cmd("login", "ip", m.Option("remote_addr")).Result(0)
}
login := m.Sess("aaa").Cmd("login", sessid).Sess("login", false)
m.Appendv("login", login)
m.Echo(sessid)
}},
"/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*WEB); m.Assert(ok) {
accept_json := strings.HasPrefix(m.Option("accept"), "application/json")
list := []interface{}{}
// tmpl, e := web.template.Clone()
// m.Assert(e)
// tmpl.Funcs(ctx.CGI)
//
tmpl := template.New("render").Funcs(ctx.CGI)
tmpl.ParseGlob("/Users/shaoying/context/usr/template/common/base.tmpl")
w := m.Optionv("response").(http.ResponseWriter)
if accept_json {
w.Header().Add("Content-Type", "application/json")
} else {
w.Header().Add("Content-Type", "text/html")
}
if m.Option("componet_group") == "" {
m.Option("componet_group", m.Conf("componet_group"))
}
group := m.Option("componet_group")
right := false
if group == "login" {
right = true
}
login := m
login = nil
for count := 0; count == 0; {
order := -1
if m.Option("componet_order") != "" {
order = m.Optioni("componet_order")
}
if !right {
login = m.Spawn().Cmd("session").Appendv("login").(*ctx.Message)
}
if !right && login != nil {
if role := login.Confv("right", []interface{}{"right", "role"}); role != nil && role.(string) == "root" {
right = true
}
}
if !right && login != nil {
if role := login.Confv("right", []interface{}{group, "right", "role"}); role != nil && role.(string) == "owner" {
right = true
}
}
for i, v := range m.Confv("componet", group).([]interface{}) {
if order != -1 && i != order {
continue
}
val := v.(map[string]interface{})
order_right := right
if !order_right && login != nil {
if role := login.Confv("right", []interface{}{group, val["name"], "right", "role"}); role != nil && role.(string) == "share" {
order_right = true
}
}
if !order_right {
continue
}
msg := m.Find(val["context"].(string))
if msg == nil {
if !accept_json {
m.Assert(tmpl.ExecuteTemplate(w, val["template"].(string), m))
}
continue
}
count++
msg.Option("componet_order", i)
for k, v := range val {
if msg.Option(k) != "" {
continue
}
switch value := v.(type) {
case []string:
msg.Add("option", k, value)
case string:
msg.Add("option", k, value)
default:
msg.Put("option", k, value)
}
}
args := []string{}
if val["arguments"] != nil {
for _, v := range val["arguments"].([]interface{}) {
switch value := v.(type) {
case string:
if len(value) > 1 && value[0] == '$' {
args = append(args, msg.Cap(value[1:]))
} else if len(value) > 1 && value[0] == '@' {
args = append(args, msg.Confx(value[1:]))
} else {
args = append(args, value)
}
}
}
}
if val["inputs"] != nil {
for _, v := range val["inputs"].([]interface{}) {
value := v.(map[string]interface{})
if msg.Option(value["name"].(string)) == "" {
msg.Add("option", value["name"].(string), value["value"])
}
}
}
if msg.Cmd(val["command"], args); accept_json {
list = append(list, msg.Meta)
} else {
m.Assert(tmpl.ExecuteTemplate(w, val["template"].(string), msg))
}
if msg.Appends("sessid") {
http.SetCookie(w, &http.Cookie{Name: "sessid", Value: msg.Append("sessid")})
m.Append("page_redirect", fmt.Sprintf("/render?componet_group=%s&componet_order=%s",
m.Option("componet_group", m.Option("last_componet_group")),
m.Option("componet_order", m.Option("last_componet_order"))))
return
}
}
if count == 0 {
m.Option("last_componet_group", m.Option("componet_group"))
m.Option("last_componet_order", m.Option("componet_order"))
m.Option("componet_group", "login")
m.Option("componet_order", "-1")
group = m.Option("componet_group")
order = -1
right = true
}
}
if accept_json {
en := json.NewEncoder(w)
en.SetIndent("", " ")
en.Encode(list)
}
} }
}}, }},
}, },

View File

@ -1,59 +1,194 @@
function insert_child(parent, element, html, position) {
function update(event, module, details, key) { var elm = document.createElement(element)
if (event) { html && (elm.innerHTML = html)
window[key+"timer"] = !window[key+"timer"]; return parent.insertBefore(elm, position || parent.firstElementChild)
} }
if (!window[key+"timer"]) { function append_child(parent, element, html) {
return var elm = document.createElement(element)
} html && (elm.innerHTML = html)
console.log("update "+key) parent.append(elm)
setTimeout(function() { return elm
action(event, module, details, key); }
update(null, module, details, key); function insert_before(self, element, html) {
}, refresh_time); var elm = document.createElement(element)
html && (elm.innerHTML = html)
return self.parentElement.insertBefore(elm, self)
} }
function input(event, module, details, key) { function copy_to_clipboard(text) {
if (event.code == "Enter") { var clipboard = document.querySelector("#clipboard")
action(event, module, details, key); clipboard.value = text
} clipboard.select()
document.execCommand("copy")
clipboard.blur()
var clipstack = document.querySelector("#clipstack")
insert_child(clipstack, "option").value = clipboard.value
clipstack.childElementCount > 3 && clipstack.removeChild(clipstack.lastElementChild)
} }
function action(event, module, details, key) { function send_command(form, cb) {
var input = document.getElementsByClassName(key+"_input"); var data = {}
for (var i = 0; i < input.length; i++ ){ for (var key in form.dataset) {
if (input[i].value != "") { data[key] = form.dataset[key]
details.push(input[i].value) }
} for (var i = 0; i < form.length; i++) {
} data[form[i].name] = form[i].value
ctx.POST("", {module:module, details:details}, function(msg) { }
if (msg && msg.result) {
var result = document.getElementsByClassName(key+"_result")[0];
result.innerHTML = msg.result;
}
if (!msg || !msg.append || msg.append.length < 1) {
return
}
var append = document.getElementsByClassName(key+"_append")[0]; context.GET("", data, function(msg) {
if (append.rows.length == msg[msg.append[0]].length+1) { msg = msg[0]
return
}
append.innerHTML = '';
var tr = append.insertRow(0);
for (var i in msg.append) {
var th = tr.appendChild(document.createElement("th"));
th.appendChild(document.createTextNode(msg.append[i]));
}
for (var i = 0; i < msg[msg.append[0]].length; i++) { var result = document.querySelector("code.result."+data["componet_name"]+" pre")
var tr = append.insertRow(1); result && (result.innerHTML = (msg.result || []).join(""))
for (var j in msg.append) {
var td = tr.appendChild(document.createElement("td"));
td.appendChild(document.createTextNode(msg[msg.append[j]][i]));
}
}
var div = append.parent;
}) var append = document.querySelector("table.append."+data["componet_name"])
return false; append && (append.innerHTML = "")
if (append && msg.append) {
var tr = append_child(append, "tr")
for (var i in msg.append) {
append_child(tr, "th", msg.append[i])
}
var ncol = msg.append.length
var nrow = msg[msg.append[0]].length
for (var i = 0; i < nrow; i ++) {
var tr = append_child(append, "tr")
for (var k in msg.append) {
append_child(tr, "td", msg[msg.append[k]][i])
}
}
}
typeof(cb) == "function" && cb(msg)
})
}
function onaction(event, action) {
switch (action) {
case "command":
send_command(event.target.form)
break
case "input":
switch (event.key) {
case "Enter":
var form = event.target.form
for (var i = 0; i < form.length; i++) {
if (form[i] == event.target) {
continue
}
(i == form.length-1)? send_command(form): form[i+1].focus()
}
break
case "Escape":
event.target.value = ""
event.target.blur()
break
}
break
case "keymap":
switch (event.key) {
case "g":
document.querySelectorAll("form.option label.keymap").forEach(function(item) {
item.className = (item.className == "keymap show")? "keymap hide": "keymap show"
})
break
default:
if (inputs[event.key]) {
inputs[event.key].focus()
}
break
}
break
case "copy":
copy_to_clipboard(event.target.innerText)
break
}
}
var inputs = {}
var ninput = 0
var keymap = ['a', 'b', 'c']
function init_option() {
inputs = {}
ninput = 0
keymap =[]
for (var i = 97; i < 123; i++) {
if (i == 103) {
continue
}
keymap.push(String.fromCharCode(i))
}
document.querySelectorAll("form.option input").forEach(function(input) {
if (ninput < keymap.length && input.style.display != "none") {
input.title = "keymap: "+keymap[ninput]
input.dataset["keymap"] = keymap[ninput]
insert_before(input, "label", "("+keymap[ninput]+")").className = "keymap"
inputs[keymap[ninput++]] = input
}
})
}
function init_append(event) {
var append = document.querySelectorAll("table.append").forEach(function(item) {
item.onclick = function(event) {
if (event.target.tagName == "TD") {
copy_to_clipboard(event.target.innerText)
}
}
})
}
function init_result(event) {
var result = document.querySelectorAll("code.result pre").forEach(function(item) {
item.onclick = function(event) {
copy_to_clipboard(event.target.innerText)
}
})
}
function init_download(event) {
var option = document.querySelector("form.option.dir")
if (!option) {
return
}
option["dir"].value && send_command(option)
var append = document.querySelector("table.append.dir")
append.onclick = function(event) {
if (event.target.tagName == "A") {
if (event.target.dataset.type != "true") {
location.href = option["dir"].value+"/"+event.target.innerText
return
}
option["dir"].value = option["dir"].value+"/"+event.target.innerText
send_command(option, function(msg) {
option["dir"].value = msg.dir.join("")
})
} else if (event.target.tagName == "TD") {
copy_to_clipboard(event.target.innerText)
} else if (event.target.tagName == "TH") {
option["sort_field"].value = event.target.innerText
var sort_order = option["sort_order"]
switch (event.target.innerText) {
case "filename":
sort_order.value = (sort_order.value == "str")? "str_r": "str"
break
case "line":
case "size":
sort_order.value = (sort_order.value == "int")? "int_r": "int"
break
case "time":
sort_order.value = (sort_order.value == "time")? "time_r": "time"
break
}
send_command(option)
}
}
}
window.onload = function() {
init_option()
init_append()
init_result()
init_download()
} }

View File

@ -1,202 +1,47 @@
ctx = { context = {
Cookie: function(key, value) {//{{{ GET: function(url, form, cb) {
if (value == undefined) { form = form || {}
var pattern = new RegExp(key+"=([^;]*);?");
var result = pattern.exec(document.cookie);
if (result && result.length > 0) {
return result[1];
}
return "";
}
document.cookie = key+"="+value; var args = [];
return this.Cookie(key); for (var k in form) {
},//}}} if (form[k] instanceof Array) {
Search: function(key, value) {//{{{ for (i in form[k]) {
var args = {}; args.push(k+"="+encodeURIComponent(form[k][i]));
var search = location.search.split("?"); }
if (search.length > 1) { } else if (form[k] != undefined) {
var searchs = search[1].split("&"); args.push(k+"="+encodeURIComponent(form[k]));
for (var i = 0; i < searchs.length; i++) { }
var keys = searchs[i].split("=");
args[keys[0]] = decodeURIComponent(keys[1]);
}
}
if (typeof key == "object") {
for (var k in key) {
if (key[k] != undefined) {
args[k] = key[k];
}
}
} else if (value == undefined) {
return args[key] || "";
} else {
args[key] = value;
}
var arg = [];
for (var k in args) {
arg.push(k+"="+encodeURIComponent(args[k]));
}
location.search = arg.join("&");
},//}}}
GET: function(url, form, cb) {//{{{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
switch (xhr.status) {
case 200:
try {
var msg = JSON.parse(xhr.responseText||'{"result":[]}');
} catch (e) {
msg = {"result": [xhr.responseText]}
}
msg && console.log(msg)
msg.result && console.log(msg.result.join(""));
typeof cb == "function" && cb(msg)
}
break;
}
}
form = form || {}
form["dir"] = form["dir"] || this.Search("dir") || undefined
form["module"] = form["module"] || this.Search("module") || undefined
form["domain"] = form["domain"] || this.Search("domain") || undefined
var args = [];
for (k in form) {
if (form[k] instanceof Array) {
for (i in form[k]) {
args.push(k+"="+encodeURIComponent(form[k][i]));
}
} else if (form[k] != undefined) {
args.push(k+"="+encodeURIComponent(form[k]));
}
}
var arg = args.join("&");
if (arg) {
url += "?"+arg
} }
xhr.open("GET", url); var arg = args.join("&");
console.log("GET: "+url+"?"+arg); arg && (url += ((url.indexOf("?")>-1)? "&": "?") + arg)
xhr.send(); console.log("GET: "+url);
},//}}}
POST: function(url, form, cb) {//{{{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
switch (xhr.status) {
case 200:
try {
var msg = JSON.parse(xhr.responseText||'{"result":[]}');
} catch (e) {
msg = {"result": [xhr.responseText]}
}
msg && console.log(msg) var xhr = new XMLHttpRequest();
msg.result && console.log(msg.result.join("")); xhr.open("GET", url);
typeof cb == "function" && cb(msg) xhr.setRequestHeader("Accept", "application/json")
}
break;
}
}
xhr.open("POST", url); xhr.onreadystatechange = function() {
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); if (xhr.readyState != 4) {
return
}
if (xhr.status != 200) {
return
}
try {
var msg = JSON.parse(xhr.responseText||'{"result":[]}');
} catch (e) {
var msg = {"result": [xhr.responseText]}
}
form = form || {} console.log(msg)
form["dir"] = form["dir"] || this.Search("dir") || undefined msg.result && console.log(msg.result.join(""));
form["module"] = form["module"] || this.Search("module") || undefined if (msg.page_redirect) {
form["domain"] = form["domain"] || this.Search("domain") || undefined location.href = msg.page_redirect.join("")
}
var args = []; typeof cb == "function" && cb(msg)
for (k in form) { }
if (form[k] instanceof Array) { xhr.send();
for (i in form[k]) { },
args.push(k+"="+encodeURIComponent(form[k][i])); }
}
} else if (form[k] != undefined) {
args.push(k+"="+encodeURIComponent(form[k]));
}
}
var arg = args.join("&");
console.log("POST: "+url+"?"+arg);
xhr.send(arg);
},//}}}
Refresh: function() {//{{{
location.assign(location.href);
},//}}}
Cap: function(cap, cb) {//{{{
if (typeof cap == "function") {
cb = cap;
cap = undefined;
}
var args = {ccc:"cache"};
if (cap != undefined) {
args.name = cap;
}
this.POST("", args, function(msg) {
var value = msg.result.join("");
typeof cb == "function" && cb(value);
});
},//}}}
Conf: function(name, value, cb) {//{{{
if (typeof name == "function") {
value = name;
name = undefined;
}
if (typeof value == "function") {
cb = value;
value = undefined;
}
var args = {ccc:"config"};
if (name != undefined) {
args.name = name
}
if (value != undefined) {
args.value = value
}
this.POST("", args, function(msg) {
var value = msg.result.join("");
typeof cb == "function" && cb(value);
});
},//}}}
Cmd: function(cmd, value, cb) {//{{{
if (typeof cmd == "function") {
value = cmd;
cmd = undefined;
}
if (typeof value == "function") {
cb = value;
value = undefined;
}
var args = {ccc:"command"};
if (cmd != undefined) {
args.name = cmd
}
if (value != undefined) {
args.value = JSON.stringify(value)
}
this.POST("", args, cb);
},//}}}
Module: function(module, domain) {//{{{
this.Search({module:module, domain:domain})
},//}}}
};

View File

@ -1,211 +0,0 @@
function jumpto(url) {
if (url == "..") {
var ps = locaiton.href.split();
}
location.href=url;
}
function keyup(event) {
console.log(event);
if (typeof window.control == "function") {
control(event);
}
if (event.key == "z") {
var input = document.getElementsByClassName("query_input")[0];
if (!window.query_show) {
window.query_show = true;
var query = document.getElementsByClassName("query_menu")[0];
var input = query.getElementsByTagName("input")[0];
input.style.visibility = "visible";
input.style.width = "80px";
input.focus();
}
return true
}
return true
}
document.onkeyup = keyup;
function toggle(side) {
if (side == "left") {
window.left_list_hide = !window.left_list_hide;
var list = document.getElementsByClassName("list")[0];
var content = document.getElementsByClassName("content")[0];
if (left_list_hide) {
list.style.visibility = "hidden";
list.style.width="0px";
list.style.height="0px";
list.style["min-width"]="0px";
content.style.width="100%";
} else {
list.style.visibility = "visible";
list.style.width="15%";
list.style.height="100%";
list.style["min-width"]="180px";
content.style.width="85%";
}
}
}
function menu() {
var max = 0;
var min = 1000;
var list = [];
var hs = ["h2", "h3", "h4"];
for (var i = 0; i < hs.length; i++) {
var head = document.getElementsByTagName(hs[i]);
for (var j = 0; j < head.length; j++) {
head[j].id = "head"+head[j].offsetTop;
head[j].onclick = function(event) {}
list.push({"level": hs[i], "position": head[j].offsetTop, "title": head[j].innerText, "hash": head[j].id})
if (head[j].offsetTop > max) {
max = head[j].offsetTop;
}
if (head[j].offsetTop < min) {
min = head[j].offsetTop;
}
}
}
max = max - min;
var link = [];
var a = document.getElementsByTagName("a");
for (var i = 0; i < a.length; i++) {
link.push({href: a[i].href, title: a[i].innerText});
}
for (var i = 0; i < list.length-1; i++) {
for (var j = i+1; j < list.length; j++) {
if (list[j].position < list[i].position) {
var a = list[i];
list[i] = list[j];
list[j] = a;
}
}
}
var index = [-1, 0, 0]
for (var i = 0; i < list.length; i++) {
if (list[i].level == "h2") {
index[0]++;
index[1]=0;
index[2]=0;
} else if (list[i].level == "h3") {
index[1]++;
index[2]=0;
} else {
index[2]++;
}
list[i].index4 = index[2];
list[i].index3 = index[1];
list[i].index2 = index[0];
}
var m = document.getElementsByClassName("menu");
for (var i = 0; i < m.length; i++) {
for (var j = 0; j < list.length; j++) {
var text = list[j].index2+"."
if (list[j].level == "h3") {
text += list[j].index3
} else if (list[j].level == "h4") {
text += list[j].index3+"."+list[j].index4
}
text += " "
text += list[j].title;
var h = document.getElementById(list[j].hash)
h.innerText = text
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createElement("a"));
a.href = "#"+list[j].hash;
a.innerText = text+" ("+parseInt((list[j].position-min)/max*100)+"%)";
one.className = list[j].level;
}
}
var m = document.getElementsByClassName("link");
for (var i = 0; i < m.length; i++) {
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createTextNode("相关链接: "));
for (var j = 0; j < link.length; j++) {
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createTextNode(link[j].title+": "));
var a = one.appendChild(document.createElement("a"));
a.href = link[j].href
a.innerText = a.href
}
}
var m = document.getElementsByTagName("pre");
for (var i = 0; i < m.length; i++) {
var line = (m[i].clientHeight-10)/15
// if (line < 3) {
// continue
// }
console.log(m[i].clientHeight)
var nu = m[i].parentElement.insertBefore(document.createElement("div"), m[i]);
nu.className = "number1"
for (var j = 1; j <= line; j++) {
console.log(j)
var li = nu.appendChild(document.createElement("div"));
li.appendChild(document.createTextNode(""+j));
}
}
}
function query(event) {
if (event) {
if (event.code == "Enter") {
jumpto("/wiki/?query="+encodeURIComponent(event.target.value));
}
console.log("what")
return true
}
window.query_show = !window.query_show;
var query = document.getElementsByClassName("query_menu")[0];
var input = query.getElementsByTagName("input")[0];
if (window.query_show) {
input.style.visibility = "visible";
input.style.width = "80px";
} else {
input.style.visibility = "hidden";
input.style.width = "0px";
}
}
var tags_list = {};
ctx.GET("/wiki/define.json", undefined, function(msg){
tags_list = msg["define"];
})
function tags(event) {
console.log(event);
if (event.srcElement.tagName == "CODE") {
var tag = document.getSelection().toString();
console.log(tag);
if (tag && tag.length > 0 && tags_list[tag]) {
var position = tags_list[tag].position;
if (position.length == 1) {
jumpto("/wiki/src/"+position[0].file+"#hash_"+position[0].line);
} else {
jumpto("/wiki/?query="+encodeURIComponent(tag));
}
}
}
}
document.onmouseup = tags;
window.onload = function() {
toggle();
if (location.href.endsWith(".md")) {
menu();
}
}

View File

@ -1,145 +0,0 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{option .Meta "page_title"}}</title>
<style>
fieldset {
margin-top:8px;
}
legend {
font-size:16px;
font-weight:bold;
font-family:monospace;
}
th {
cursor:pointer;
background-color:lightgreen;
}
td {
padding-left: 10px;
padding-right: 20px;
}
pre {
color:white;
font-size:14px;
background-color:#272822;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
overflow:scroll;
}
.command {
font-size:14px;
font-family:monospace;
}
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
h4 {
margin:0px;
padding:0px;
}
</style>
<script src="/library/context.js"></script>
<script src="/library/base.js"></script>
</head>
<body>
{{end}}
{{define "code"}}
<pre><code>{{.}}</code></pre>
{{end}}
{{define "notice"}}
<fieldset class="notice"><legend>[notice]</legend>
{{template "code" result .Meta}}
</fieldset>
<style>
.notice {color:red}
</style>
{{end}}
{{define "detail"}}
{{$msg := .}}
{{$key := append . "title"|meta}}
<fieldset><legend><a onclick="return action(event, '{{option .Meta "module"}}', ['{{detail .Meta}}'], '{{$key}}')" href="/">{{option . "title"}}</a></legend>
{{range option . "ninput"|meta|list}}
<input type="text" class="{{$key}}_input" value="" onkeyup="return input(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
{{end}}
{{if option . "refresh"}}
<input type="button" class="{{$key}}_button" value="update" onclick="return update(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
<input type="button" class="{{$key}}_button" value="cancel" onclick="return update(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
{{end}}
<pre><code class="{{$key}}_result"></code></pre>
<div style="max-height:150px;overflow:auto">
<table class="{{$key}}_append"></table>
</div>
</fieldset>
<script>
var refresh_time = parseInt({{conf . "refresh_time"}});
{{if option . "auto_refresh"}}
update(true, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}');
{{end}}
</script>
{{end}}
{{define "result"}}
<fieldset><legend>{{option . "title"}}</legend>
{{template "code" result .Meta|unscaped}}
</fieldset>
{{end}}
{{define "append_link"}}
<a onclick="return jump('{{.}}')" href="{{.}}">{{.}}</a>
<script>
function jump(to) {
location.href = location.href + "/" +to;
return false
}
</script>
{{end}}
{{define "append"}}
<fieldset><legend>{{option . "title"}}</legend>
<table class="append">
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<tr>{{range append .}}<th><code onclick="sort_table('{{.}}')">{{.}}</code></th>{{end}}</tr>
{{range $row, $val := append . 0|append .}}
<tr>
{{range append $msg}}
{{$value := append $msg . $row}}
<td><code>
{{if eq . "filename"}}
{{template "append_link" $value}}
{{else}}
{{$value}}
{{end}}
</code></td>
{{end}}
</tr>
{{end}}
</table>
</fieldset>
<script>
var sort_field="";
function sort_table(field) {
sort_field = field;
console.log(sort_field);
}
</script>
{{end}}
{{define "main"}}
welcome to context world!
{{end}}
{{define "tail"}}
</body>
{{end}}

View File

@ -0,0 +1,138 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{option .Meta "page_title"}}</title>
<style>
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
fieldset {
margin-top:8px;
}
legend {
font-size:16px;
font-weight:bold;
font-family:monospace;
}
</style>
<style>
form.option div {
float:left;
}
form.option hr {
clear:both;
}
form.option label.keymap {
display:none;
color:red;
}
form.option label.keymap.show {
display:inline;
}
table.append th {
cursor:pointer;
background-color:lightgreen;
}
table.append th.order {
cursor:pointer;
background-color:red;
}
table.append td {
padding-left: 10px;
padding-right: 20px;
}
code.result pre {
color:white;
font-size:14px;
background-color:#272822;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
overflow:scroll;
}
</style>
</head>
<body onkeyup="return onaction(event, 'keymap')">
{{end}}
{{define "detail"}}{{detail .}}{{end}}
{{define "option"}}{{option .}}{{end}}
{{define "append"}}{{append .}}{{end}}
{{define "result"}}{{result .}}{{end}}
{{define "clipboard"}}
<fieldset><legend>clipboard</legend>
<datalist id="clipstack"></datalist>
<input id="clipboard">
</fieldset>
{{end}}
{{define "componet"}}
<fieldset><legend title="{{option .Meta "help"}}">{{option .Meta "context"}}.{{option .Meta "command"}}</legend>
<form class="option {{option .Meta "name"}}"
data-last_componet_group="{{option . "last_componet_group"|meta}}"
data-last_componet_order="{{option . "last_componet_order"|meta}}"
data-componet_group="{{option . "componet_group"|meta}}"
data-componet_order="{{option . "componet_order"|meta}}"
data-componet_name="{{option . "name"|meta}}"
data-componet_help="{{option . "help"|meta}}"
>
<input style="display:none"></input>
{{range $index, $input := option . "inputs"}}
<div>
{{$type := index $input "type"}}
{{if eq $type "button"}}
<input type="button" name="{{index $input "name"}}" value="{{index $input "value"}}" onclick="return onaction(event, 'command')">
{{else if eq $type "choice"}}
{{$default_value := index $input "value"}}
<label>{{index $input "label"}} : </label>
<select name="{{index $input "name"}}" onchange="return onaction(event, 'command')">
{{range $index, $value := index $input "choice"}}
{{$val := index $value "value"}}
{{if eq $default_value $val}}
<option value="{{index $value "value"}}" selected>{{index $value "name"}}</option>
{{else}}
<option value="{{index $value "value"}}">{{index $value "name"}}</option>
{{end}}
{{end}}
</select>
{{else}}
<label>{{index $input "label"}} : </label>
<input name="{{index $input "name"}}" value="{{index $input "value"}}" onkeyup="return onaction(event, 'input')" list="clipstack">
{{end}}
</div>
{{end}}
<hr/>
</form>
{{if index .Meta "display_append"}}
{{option .Meta "display_append"}}
{{else}}
<table class="append {{option .Meta "name"}}">
{{$msg := .}}
<tr>{{range $field := append .}}<th>{{$field}}</th>{{end}}</tr>
{{range $line := table .}}
<tr>{{range $field := append $msg}}<td>{{index $line $field|unescape}}</td>{{end}}</tr>
{{end}}
</table>
{{end}}
{{if index .Meta "display_result"}}
{{option .Meta "display_result"}}
{{else}}
<code class="result {{option .Meta "name"}}"><pre>{{result .Meta}}</pre></code>
{{end}}
</fieldset>
{{end}}
{{define "tail"}}
<script src="/library/context.js"></script>
<script src="/library/base.js"></script>
</body>
{{end}}

View File

@ -1,94 +0,0 @@
{{define "login"}}
<fieldset><legend>login</legend>
<form method="POST" action="/login">
<label>username:</label><input type="text" name="username" required autofocus>
<label>password:</label><input type="password" name="password" required>
<input type="submit">
</form>
</fieldset>
{{end}}
{{define "userinfo"}}
<fieldset><legend>userinfo</legend>
welcome <span class="username">{{option . "username"}}</span> to context world
<button onclick="return logout(event)">logout</button>
</fieldset>
<style>
.username {
color:red;
font-weight:bold;
}
</style>
<script>
function logout(event) {
ctx.Cookie("sessid", ";path=/");
ctx.Refresh();
return false;
}
</script>
{{end}}
{{define "share"}}
<fieldset><legend>share</legend>
<table>
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<tr>{{range append .}}<th><code onclick="sort_table('{{.}}')">{{.}}</code></th>{{end}}</tr>
{{range $row, $val := append . 0|append .}}
<tr>
{{range append $msg}}
{{$value := append $msg . $row}}
<td><code>
{{if eq . "to"}}
{{if eq $value ""}}
<input type="text" onkeyup="return share_input(event, '{{append $msg "template" $row}}', '{{append $msg "titles" $row}}', 'add')">
{{else}}
<code><a href="/" title="点击取消共享" onclick="return shareto('{{append $msg "template" $row}}', '{{append $msg "titles" $row}}', '{{$value}}','del')">{{$value}}</a></code>
{{end}}
{{else if eq . "value"}}
<code><a title="点击删除" href="/" onclick="deleteshare(event, '{{append $msg "friend" $row}}', '{{$value}}')">{{$value}}</a></code>
{{else}}
{{$value}}
{{end}}
</code></td>
{{end}}
</tr>
{{end}}
</table>
</fieldset>
<script>
function share_input(event, template, title, action) {
if (event.code == "Enter") {
shareto(template, title, event.target.value, action);
}
console.log(event.code)
console.log(event.key)
console.log(event)
}
function shareto(template, title, friend, action) {
ctx.POST("/share", {
module: "web",
template: template,
title: title,
friend: friend,
action: action,
share: ["command", "/index/"],
}, function(msg) {
ctx.Refresh();
})
return false
}
</script>
{{end}}
{{$msg := .}}
{{$meta := .Meta}}
{{template "head" $meta}}
{{if meta $meta.notice}}
{{template "notice" $meta}}
{{end}}
{{template "login" $meta}}
{{template "tail" $meta}}

View File

@ -1,9 +0,0 @@
{{$msg := .}}
{{$meta := .Meta}}
{{template "head" $meta}}
{{if meta $meta.message}}
{{template "message" $meta}}
{{end}}
{{template "main" $msg}}
{{template "tail" $meta}}

View File

@ -1,222 +0,0 @@
{{define "wiki_head"}}
{{end}}
{{define "wiki_menu"}}
{{end}}
{{define "wiki_list"}}
<style>
p {
text-indent:2em;
}
.container {
height:100%;
min-width:300px;
}
.head {
color:white;
font-size:20px;
font-weight:bold;
background-color:#222;
text-align:center;
vertical-align:middle;
padding:10px;
width:100%;
height:27px;
}
.title {
font-style:italic;
}
.toggle_menu {
cursor:pointer;
float:left;
}
.query_menu {
cursor:pointer;
margin-right:20px;
float:right;
}
.query_button {
cursor:pointer;
float:right;
margin-left:10px;
}
.query_input {
visibility:hidden;
width:0px;
position:absolute;
right:40px;
top:12px;
}
.list {
width:15%;
min-width:140px;
float:left;
max-height:1000px;
overflow:scroll;
}
.list_item {
padding-top:10px;
padding-left:30px;
min-height:30px;
margin-left:-30px;
}
.list_item:hover, .list_item:active {
background-color:green;
}
</style>
<div class="container">
<div class="head">
<div class="toggle_menu" onclick="toggle()"></div>
<div class="query_menu">
<input class="query_input" type="text" onkeyup="return query(event)">
<div class="query_button" onclick="return query()"> Q</div>
</div>
<div class="title" onclick="return jumpto('/wiki/')">shylinux</div>
</div>
<div class="list">
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<ul>
<li>
<div class="list_item" onclick="return jumpto('/wiki/{{option $msg "parent"|meta}}')">返回上一层</div>
</li>
{{range $row, $val := append . 0|append .}}
<li>
<div class="list_item" onclick="return jumpto('/wiki/{{option $msg "dir"|meta}}/{{append $msg "name" $row}}')">
{{append $msg "name" $row}}
</div>
</li>
{{end}}
</ul>
</div>
{{end}}
{{define "wiki_body"}}
<style>
.content {
width:85%;
height:100%;
float:left;
min-width:400px;
}
.toggle {
background-color:green;
width:2%;
height:100%;
float:left;
}
.toggle1 {
background-color:green;
width:2%;
height:100%;
float:right;
}
.texts {
max-width:800px;
width:94%;
float:left;
margin-left:2%;
}
.li_link {
font-size:18px;
}
.number {
float:left;
position:relative;
left:-6px;
top:18px;
text-align:right;
}
.number div {
margin:0px;
padding:0px;
height:16px;
}
.record {
margin: 10px 10px;
float:left;
}
.menu {
}
.menu a {
text-decoration:none;
}
.menu .h3 {
padding-left: 20px;
}
.menu .h4 {
padding-left: 40px;
}
.link {
margin-top:10px;
font-size: 14px;
}
.link div:first-child {
margin-left:-10px;
}
.link div {
padding-left:10px;
}
.number1 {
color:#271ace;
font-size:14px;
font-family:monospace;
background-color:#77b724;
padding:5px;
border:solid 2px green;
margin-left:0px;
float:left;
}
.number1 div {
text-align:right;
margin:0;
padding:0;
}
</style>
<div class="content">
<div class="toggle" title="点击,显示或隐藏目录" onclick="toggle('left')"></div>
<div class="toggle1" title="点击,显示或隐藏目录" onclick="toggle('right')"></div>
{{if option . "modify_time"|meta}}
<div class="record">上次修订时间: {{option . "modify_time"|meta}} 修订次数: {{option . "modify_count"|meta}}</div>
{{end}}
<div class="record">上次阅读时间: {{option . "last_record_time"|meta}} 总访问量: {{option . "record_count"|meta}}</div>
<div class="texts">
<div class="menu"></div>
<div class="link"></div>
<div class="number">
{{range option . "nline"|meta|list}}
<div id="hash_{{.}}" style="margin-top:-1px"><code>{{.}}</code></div>
{{end}}
</div>
{{$msg := .}}
{{if append . "name"}}
{{$l := append . "name"|len}}
{{if eq $l 1}}
<script>
location.replace("/wiki/{{option $msg "dir"|meta|unscaped}}/{{append . "name"|meta|unscaped}}");
</script>
{{else}}
<ul>
{{range $i, $v := append . "name"}}
<li class="li_link">
<div>
<code>{{option $msg "time" $i}}&nbsp;&nbsp;&nbsp;</code>
<a href="/wiki/{{option $msg "dir"|meta}}/{{$v}}{{option $msg "pend" $i}}">{{$v}}{{option $msg "pend" $i}}</a>
</div>
</li>
{{end}}
<ul>
{{end}}
{{else if append . "code"|meta}}
<p><pre><code>{{append . "code"|meta}}</code></pre><p>
{{else}}
<p>{{append . "body"|meta|unscaped}}</p>
{{end}}
</div>
</div>
</div>
<script src="/library/wiki.js"></script>
{{end}}

View File

@ -1,431 +0,0 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<style>
legend {
font-size:16px;
font-weight:bold;
}
th {
cursor:pointer;
background-color:lightgray;
}
.name {
padding-left:10px;
text-align:left;
}
.help {
padding-left:10px;
text-align:left;
}
.status {
padding-left:10px;
text-align:left;
}
.stream {
padding-left:10px;
text-align:left;
}
.result {
background-color:black;
color:white;
padding:10px;
margin:0px;
}
code {
font-size:14px;
}
</style>
</head>
<body>
{{end}}
{{define "cache"}}
{{$meta := .}}
<fieldset><legend>cache</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{$content := index $meta $key $i}}
<td class="{{$key}}">
<code>{{$content}}</code>
</td>
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<script>
function cache(event, key, value) {
console.log(event);
switch (event.type) {
case "keydown":
if (event.key != "Enter") {
return true;
}
value = event.target.value;
ctx.Cap(key, value);
}
}
</script>
{{end}}
{{define "config"}}
<fieldset><legend>config</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>{{$config := index $meta "key" $i}}
{{range $key := index $meta "append"}}
{{if eq $key "value"}}
<td class="{{$key}}">
<input type="text" value="{{index $meta $key $i}}" onkeydown="return Config(event, '{{$config}}')">
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<script>
function Config(event, name) {
if (event.type=="keydown" && event.key == "Enter") {
ctx.Conf(name, event.target.value, function(msg) {alert("ok")});
}
}
</script>
{{end}}
{{define "command2"}}
{{$meta := .}}
<fieldset><legend>command</legend>
<div>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
{{$command := index $meta "key" $i}}
<div>
<div>
<code>
{{$command}}: {{index $meta "help" $i}}<br/>
<a href="" onclick="return shell(event, '{{$command}}')">{{index $meta "name" $i}}</a>
</code>
</div>
<div id="argument_{{$command}}">
<button onclick="return Argument(event, 'add', '{{$command}}')">add</button>
<button onclick="return Argument(event, 'del', '{{$command}}')">del</button>
</div>
<pre class="result" hidden><code id="result_{{$command}}"></code></pre>
<table id="append_{{$command}}" hidden></table>
</div>
{{end}}
{{end}}
</div>
</fieldset>
<fieldset><legend><input id="direct" type="text" onkeydown="return shell(event)"></legend>
<pre class="result"><code id="result2"></code></pre>
</fieldset>
<script>
function show(msg, command) {
console.log(msg);
if (msg.result) {
var result = document.getElementById("result_"+command);
if (!result) {
var result = document.getElementById("result2");
}
result.innerHTML = msg.result.join("");
}
var append = document.getElementById("append_"+command);
append.innerHTML = "";
if (msg.append) {
append.hidden = false;
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var th = document.createElement("th");
th.innerHTML = msg.append[k];
tr.appendChild(th)
}
for (var i in msg[msg.append[0]]) {
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var td = document.createElement("td");
var pre = document.createElement("pre");
var code = document.createElement("code");
code.innerHTML = msg[msg.append[k]][i];
pre.appendChild(code)
td.appendChild(pre)
tr.appendChild(td);
}
}
}
}
function Argument(event, action, command) {
var argument = document.getElementById("argument_"+command);
switch (action) {
case "add":
var arg = document.createElement("input");
arg.type = "text";
argument.appendChild(arg);
break;
case "del":
var arg = argument.lastElementChild;
if (arg.type == "text") {
argument.removeChild(arg);
}
break;
}
}
function shell(event, command) {
console.log(event);
switch (event.type) {
case "keydown":
if (event.key != "Enter") {
return true;
}
command = event.target.value
// no break
case "click":
var detail = [];
var result = document.getElementById("result_"+command);
var append = document.getElementById("append_"+command);
if (!result) {
var result = document.getElementById("result2");
} else {
var div = document.getElementById("argument_"+command);
var input = div.getElementsByTagName("input");
for (var i in input) {
if (input[i].value) {
detail.push(input[i].value);
}
}
result = result.parentElement;
result.hidden = !result.hidden;
append.hidden = result.hidden;
}
if (!result.hidden) {
ctx.Cmd(command, detail, function(msg) {
show(msg, command);
if (!msg.result) {
}
});
}
return false;
}
return true;
}
function Direct(event, name, value) {
debugger;
console.log(event)
if (!name) {
name = event.currentTarget.value;
}
var direct = document.getElementById("direct");
direct.value = name;
ctx.Cmd(name, value, function(msg){
Result(msg, name);
});
return false;
}
</script>
{{end}}
{{define "command"}}
<fieldset><legend>command</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>{{$command := index $meta "key" $i}}
{{range $key := index $meta "append"}}
<td class="{{$key}}">
{{if eq $key "input"}}
<input type="text" name="{{$command}}" onkeydown="return Command(event, '{{$command}}')">
{{else if eq $key "key"}}
<code><a href="" onclick="return Direct(event, '{{$command}}')">{{index $meta $key $i}}</a></code>
{{else}}
<code>{{index $meta $key $i}}</code>
{{end}}
</td>
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<fieldset><legend><input id="direct" type="text" onkeydown="return Command(event)"></legend>
<table id="append"></table>
<pre class="result"><code id="result"></code></pre>
</fieldset>
<script>
function Result(msg) {
var result = document.getElementById("result");
result.innerHTML = msg.result.join("");
var append = document.getElementById("append");
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var th = document.createElement("th");
th.innerHTML = k;
}
}
function Command(event, name) {
if (event.keyCode == 13) {
var direct = document.getElementById("direct");
if (name) {
direct.value = name;
ctx.Cmd(name, event.currentTarget.value, Result);
} else {
ctx.Cmd(event.currentTarget.value, "", Result);
}
}
}
function Direct(event, name, value) {
console.log(event)
if (!name) {
name = event.currentTarget.value;
}
var direct = document.getElementById("direct");
direct.value = name;
ctx.Cmd(name, value, Result);
return false;
}
</script>
{{end}}
{{define "module"}}
<fieldset><legend><input type="text" id="module" value="{{index .current_module 0}}" onkeydown="return Change(event, 'dir')"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
<td class="{{$key}}">
<code><a href="" onclick="ctx.Search('dir', '{{index $meta "module" $i}}'); return false">{{index $meta $key $i}}</a></code>
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
{{end}}
{{define "domain"}}
<fieldset><legend><input type="text" id="domain" value="{{index . "current_domain" 0}}" onkeydown="return Change(event, 'dir')"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
<td class="{{$key}}">
<code><a href="" onclick="ctx.Search('domain', '{{index $meta "domain" $i}}'); return false">{{index $meta $key $i}}</a></code>
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
{{end}}
{{define "tail"}}
<script src="library/context.js"></script>
<script>
function Change(event, key) {
if (event.keyCode == 13) {
ctx.Search(key, event.target.value);
}
}
function list(what) {
ctx.Cookie("list", what);
ctx.Cookie("sort_order", ctx.Cookie("sort_order")*1 + 1);
location.assign(location.href);
}
</script>
</body>
{{end}}
{{define "main"}}
{{$msg := .}}
{{$meta := .Meta}}
{{$sess := $msg.Sessions}}
{{range .Meta.tmpl}}
{{if eq . "login"}}
{{template "login" $meta}}
{{else if eq . "userinfo"}}
{{template "userinfo" $msg}}
{{else if eq . "share"}}
{{template "share" $sess.share}}
{{else if eq . "cache"}}
{{template "cache" $sess.cache.Meta}}
{{else if eq . "config"}}
{{template "config" $sess.config.Meta}}
{{else if eq . "command"}}
{{template "command" $sess.command.Meta}}
{{template "command2" $sess.command.Meta}}
{{else if eq . "module"}}
{{template "module" $sess.module.Meta}}
{{else if eq . "domain"}}
{{template "domain" $sess.domain.Meta}}
{{end}}
{{end}}
{{end}}

View File

@ -1,163 +0,0 @@
{{define "list"}}
<fieldset><legend><input type="text" id="dir" value="{{meta .dir}}" onkeydown="return Change(event)"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>
{{$sort := meta .sort}}
{{$reverse := meta .reverse}}
{{range .append}}
{{if eq $sort .}}
<th class="{{.}} sort" onclick="list('{{.}}')">{{.}}</th>
{{else if eq $reverse .}}
<th class="{{.}} reverse" onclick="list('{{.}}')">{{.}}</th>
{{else if eq . "path"}}
{{else}}
<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>
{{end}}
{{end}}
</tr>
{{if .append}}
{{$meta := .}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
{{$type := index $meta "type" $i}}
<td class="{{$key}}">
<a {{if eq $type "file"}} download="{{index $meta $key $i}}" {{end}}
href="/upload?dir={{index $meta "path" $i}}"><code>{{index $meta $key $i}}</code></a>
</td>
{{else if eq $key "path"}}
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<style>
.time {
padding-right:20px;
}
.size {
text-align:right;
padding-right:20px;
}
.name {
padding-left:10px;
text-align:left;
}
.sort {
color:red;
}
.reverse {
color:green;
}
</style>
<script>
function Change(event) {
if (event.keyCode == 13) {
ctx.Search("dir", event.target.value);
}
}
function list(what) {
ctx.Cookie("list_order", ctx.Cookie("list_order")*1 + 1);
ctx.Cookie("list", what);
ctx.Refresh();
}
</script>
{{end}}
{{define "git"}}
<fieldset><legend>branch</legend>
<pre>{{index . "result"}}</pre>
</fieldset>
<fieldset><legend>status</legend>
<pre>{{index . "result"}}</pre>
</fieldset>
{{end}}
{{define "tmux"}}
{{$meta := .}}
{{range $index, $value := index $meta "append"}}
<fieldset><legend>{{$value}}</legend>
{{if eq $value "buffer"}}
<button onclick="copy_tmux_buffer('copy')">copy</button>
<button onclick="send_tmux_buffer('paste')">send</button>
<textarea rows="5" cols="60" name="tmux_buffer">{{meta . "buffer" 0}}</textarea>
<script>
var buffer = document.getElementsByName("tmux_buffer")[0];
function copy_tmux_buffer(action) {
buffer.select();
document.execCommand(action);
}
function send_tmux_buffer(action) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/paste?content="+encodeURIComponent(buffer.value));
xhr.send()
}
</script>
{{else}}
<pre>{{meta $meta $value}}</pre>
{{end}}
</fieldset>
{{end}}
{{end}}
{{define "upload"}}
<fieldset><legend>upload</legend>
<form method="POST" action="/create?dir={{option . "dir"|meta|unscaped}}" enctype="multipart/form-data">
<input type="file" name="file"><input type="submit">
</form>
</fieldset>
{{end}}
{{define "create"}}
<fieldset><legend>create</legend>
<form method="POST" action="/create?dir={{option . "dir"|meta|unscaped}}">
<table>
<tr><td>filename:</td><td><input type="text" name="filename" required><input type="submit"></td></tr>
<tr><td>content:</td><td><textarea rows="5" cols="60" name="content"></textarea></td></tr>
</table>
</form>
</fieldset>
{{end}}
{{define "main"}}
{{$msg := .}}
{{$meta := .Meta}}
{{$sess := .Sessions}}
{{range .Meta.tmpl}}
{{$tmpl := index $sess .}}
{{if eq . "login"}}
{{template "login" $meta}}
{{else if eq . "userinfo"}}
{{template "userinfo" $msg}}
{{else if eq . "share"}}
{{template "share" $sess.share}}
{{else if eq . "list"}}
{{template "list" $msg.Sessions.list.Meta}}
{{else if eq . "tmux"}}
{{template "tmux" $msg.Sessions.tmux.Meta}}
{{else if eq . "git"}}
{{if $msg.Sessions.git}}
{{template "git" $msg.Sessions.git.Meta}}
{{end}}
{{else if eq . "upload"}}
{{template "upload" $msg}}
{{else if eq . "create"}}
{{template "create" $msg}}
{{else}}
{{end}}
{{end}}
{{end}}