├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── build.bat ├── build_linux.sh ├── build_mips.sh ├── build_sqlite3.go ├── cache.go ├── checkType.go ├── go.mod ├── go.sum ├── js ├── db │ ├── redis.js │ ├── sql.js │ └── sqlite3.js ├── ejs │ ├── ejs.js │ ├── ejs.min.js │ ├── functions.ejs │ ├── functions.js │ ├── list.ejs │ ├── list.js │ ├── list_redis.js │ ├── sql.ejs │ └── sql.js ├── file │ └── test1.js ├── http │ ├── body.js │ ├── cookie.js │ ├── download.js │ ├── header.js │ ├── http.js │ ├── request.js │ ├── session.js │ └── upload.js ├── image │ ├── font.js │ ├── image.js │ ├── test1.js │ └── test2.js ├── index.js ├── others │ ├── cache.js │ ├── os.js │ ├── require.js │ ├── return.js │ └── types.js └── utils.js ├── lib ├── db │ ├── db.go │ ├── redis │ │ ├── conn.go │ │ └── redis.go │ ├── result.go │ ├── rows.go │ ├── sql.go │ ├── stmt.go │ └── tx.go ├── error.go ├── file.go ├── fmt.go ├── image │ ├── image.go │ ├── lib │ │ ├── fonts.go │ │ └── img.go │ ├── png │ │ └── png.go │ └── rgba.go ├── io.go ├── net │ ├── http │ │ ├── cookie.go │ │ ├── header.go │ │ ├── http.go │ │ ├── multipartFile.go │ │ ├── request.go │ │ └── response.go │ └── url │ │ ├── url.go │ │ └── values.go ├── os.go ├── path │ └── filepath.go ├── strings.go ├── time.go ├── types.go └── utils.go ├── main.go ├── nodejs ├── console │ ├── module.go │ └── module_test.go ├── eventloop │ ├── eventloop.go │ └── eventloop_test.go ├── require │ ├── module.go │ ├── module_test.go │ └── testdata │ │ └── m.js └── util │ ├── module.go │ └── module_test.go ├── public ├── css │ └── index.css ├── index.html ├── jquery-easyui │ ├── jquery.easyui.min.js │ └── themes │ │ ├── default │ │ ├── accordion.css │ │ ├── calendar.css │ │ ├── combo.css │ │ ├── combobox.css │ │ ├── datagrid.css │ │ ├── datalist.css │ │ ├── datebox.css │ │ ├── dialog.css │ │ ├── easyui.css │ │ ├── filebox.css │ │ ├── images │ │ │ ├── accordion_arrows.png │ │ │ ├── blank.gif │ │ │ ├── calendar_arrows.png │ │ │ ├── combo_arrow.png │ │ │ ├── datagrid_icons.png │ │ │ ├── datebox_arrow.png │ │ │ ├── layout_arrows.png │ │ │ ├── linkbutton_bg.png │ │ │ ├── loading.gif │ │ │ ├── menu_arrows.png │ │ │ ├── messager_icons.png │ │ │ ├── pagination_icons.png │ │ │ ├── panel_tools.png │ │ │ ├── passwordbox_close.png │ │ │ ├── passwordbox_open.png │ │ │ ├── searchbox_button.png │ │ │ ├── slider_handle.png │ │ │ ├── spinner_arrows.png │ │ │ ├── tabs_icons.png │ │ │ ├── tagbox_icons.png │ │ │ ├── tree_icons.png │ │ │ └── validatebox_warning.png │ │ ├── layout.css │ │ ├── linkbutton.css │ │ ├── menu.css │ │ ├── menubutton.css │ │ ├── messager.css │ │ ├── numberbox.css │ │ ├── pagination.css │ │ ├── panel.css │ │ ├── passwordbox.css │ │ ├── progressbar.css │ │ ├── propertygrid.css │ │ ├── searchbox.css │ │ ├── slider.css │ │ ├── spinner.css │ │ ├── splitbutton.css │ │ ├── switchbutton.css │ │ ├── tabs.css │ │ ├── tagbox.css │ │ ├── textbox.css │ │ ├── tooltip.css │ │ ├── tree.css │ │ ├── validatebox.css │ │ └── window.css │ │ ├── icon.css │ │ └── icons │ │ ├── back.png │ │ ├── blank.gif │ │ ├── cancel.png │ │ ├── clear.png │ │ ├── cut.png │ │ ├── edit_add.png │ │ ├── edit_remove.png │ │ ├── filesave.png │ │ ├── filter.png │ │ ├── help.png │ │ ├── large_chart.png │ │ ├── large_clipart.png │ │ ├── large_picture.png │ │ ├── large_shapes.png │ │ ├── large_smartart.png │ │ ├── lock.png │ │ ├── man.png │ │ ├── mini_add.png │ │ ├── mini_edit.png │ │ ├── mini_refresh.png │ │ ├── more.png │ │ ├── no.png │ │ ├── ok.png │ │ ├── pencil.png │ │ ├── print.png │ │ ├── redo.png │ │ ├── reload.png │ │ ├── search.png │ │ ├── sum.png │ │ ├── tip.png │ │ └── undo.png └── js │ └── jquery.js ├── session.go └── test └── sql.go /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=golang 2 | *.css linguist-language=golang 3 | *.html linguist-language=golang -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.db 3 | go-server-js 4 | *.json 5 | test/ 6 | debug 7 | .vscode/ 8 | vendor/ 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 996.icu 2 | 3 | # a js server 4 | 一种新的javascript写服务端程序的方案,没有回调,完全不同于node.js 5 | 6 | 这可能是最简单的服务器方案了,因为它不需要任何配置,只有一个文件,运行它就有了完整的服务器、数据库和缓存系统,并且可以运行在go语言支持的所有平台上,例如:路由器上,相对于其它语言开发的服务器软件而言是非常有优势的,我曾经在路由器上配置过php服务器,花了好几个小时的时间,并且无法及时更新到新版本。这不像pc机那么容易的。 7 | 8 | 优点: 9 | 1. 免安装,无需配置任何环境,自带sqlite数据库和一个简易的缓存系统 10 | 2. go语言开发,无限扩展功能,可以自由定制 11 | 3. 跨平台,支持linux、windows、mac,支持x86/arm/mips等指令集的cpu(运行在安卓手机、树莓派、路由器、国产龙芯。。。) 12 | 4. 完全不同于node.js,没有回调,程序更易维护和编写,推荐使用typescript 13 | 14 | 缺点: 15 | 1. 由于每次js都是从磁盘读取再执行,因此性能不高,和node.js完全不是一个级别的,目前能完全满足小应用的需求,在这里能找到一份测试报告:https://github.com/zengming00/go-server-js-testShop 16 | 2. api目前不够完善,我只是需要什么就往上面加什么,你也可以 17 | 3. 目前没有文档支持,没空写,哈哈 18 | 4. 没有debug功能,调试不方便,这是个很严重的问题,目前没有办法 19 | 20 | 写node一年了,感觉node的异步优势很少用到,坑爹的回调让人非常痛苦,虽然说有async/await但仍然会时不时接触到,用async/await其实还是在写同步的代码,所谓的异步并发优势只能很少数场合能用到,有的时候甚至是得不偿失的。 21 | 22 | 在不了解node之前,在我的想象中以为node是像php那样写的,学过之后发现完全不是这样的,我曾经去找过类似这种东西,但是没找到,也许是我的方法不对,网上有个fibjs,那不是我想要的。并且,我是在发布go-server-js之后才听说的 23 | 24 | 所以我决定自己做一个,为此我曾经注册了serverjs.cn域名,我尝试过用c语言来写,C语言门槛太高了只做了一个能够连上redis的东西,还得靠cgi模式来提供服务,最终放弃了,后来接触了go语言,于是有了实现它的可能,最早是用的otto,后来才用的goja。 25 | 26 | 从开始到完成0.0.2版本应该花了一个多月吧,基本上都是在学go语言和尝试一些功能细节,最后还花时间将我一年前写的一个nodejs写的商城用我自创的go-server-js技术重写了一遍( 项目地址:https://github.com/zengming00/go-server-js-testShop ),并且和go-server-js 0.0.2捆绑发布。 27 | 28 | 再后来,为了验证go-server-js写的项目能不能够方便的移植到原生go语言项目,我又把这个商城用go语言写了一遍( 项目地址:https://github.com/zengming00/go-testShop ),得益于当时选择照抄go语言的编程风格,只需要将go-server-js封装好的一些功能实现,js代码到go语言代码的转换是很方便的 29 | 30 | # 下载试用 (download),下载后运行go-server-js,打开 http://127.0.0.1:8080/ 就是一个商城 31 | https://github.com/zengming00/go-server-js/releases 32 | 33 | ## 入门之helloworld 34 | 整个服务器就是go-server-js这个文件,不需要任何其它东西,运行它会在当前目录下生成一个config.json,这个是用来修改一些服务器配置的,比如端口号之类的。 35 | 36 | 在当前目录下创建test.js内容为 37 | 38 | ```js 39 | response.write('helloworld'); 40 | ``` 41 | 运行go-server-js然后在浏览器打开 http://127.0.0.1:8080/test.js 就可以看到helloworld了,修改文件后不需要重启服务器 42 | 更多的教程不如直接看附带的商城源码,一些api与go语言是完全一样的,因此为后期移植到原生go语言提供了极大便利 43 | 44 | # 用go-server-js写的项目 45 | 一个商城:https://github.com/zengming00/go-server-js-testShop 46 | 47 | wooyun本地镜像:https://github.com/zengming00/go-server-js-wooyun 48 | 49 | # 用go-server-js写的项目移植为go语言代码,两种等效代码对比 50 | 51 | https://github.com/zengming00/go-testShop 52 | 53 | ![两种等效代码对比](https://github.com/zengming00/go-testShop/raw/master/public/uploads/1.png) 54 | 55 | 56 | ## 获取源码 57 | ``` 58 | go get -v github.com/zengming00/go-server-js 59 | ``` 60 | 61 | 默认不会编译sqlite,在windows下编译sqlite需要安装 TDM-GCC 或 mingw64 并 set CGO_ENABLED = 1 62 | 63 | 如果要编译sqlite,在windows下运行build.bat,在linux下运行build_linux.sh 64 | 65 | 66 | ## 内部实现功能时需要注意的地方 67 | ```go 68 | // 在go语言中如果是返回一个error,要经过转换才能给js使用 69 | err := db.Close() 70 | if err != nil { 71 | return runtime.ToValue(lib.NewError(runtime, err)) 72 | } 73 | return nil 74 | 75 | // 如果类型无法处理,应该用这种方式抛出 76 | panic(runtime.NewTypeError("p0 is not a string type:%T", args[0])) 77 | 78 | // 如果有多个返回值,应该返回一个对象供js使用 79 | tx, err := db.Begin() 80 | if err != nil { 81 | return lib.MakeErrorValue(runtime, err) 82 | } 83 | return lib.MakeReturnValue(runtime, NewTx(runtime, tx)) 84 | 85 | // 动态参数 86 | args := lib.GetAllArgs(&call) 87 | err := rows.Scan(args...) 88 | 89 | // go语言原生类型的传递 90 | p0 := GetNativeType(runtime, &call, 0) 91 | if err, ok := p0.(error); ok { 92 | return runtime.ToValue(os.IsNotExist(err)) 93 | } 94 | panic(runtime.NewTypeError("p0 is not error type:%T", p0)) 95 | 96 | // 注意函数签名的不同 97 | func(call goja.FunctionCall) goja.Value {} 98 | func(call goja.ConstructorCall) *Object {} 99 | ``` 100 | 101 | # docker 102 | ```Dockerfile 103 | FROM scratch 104 | COPY . / 105 | EXPOSE 8080 106 | CMD [ "/go-server-js" ] 107 | ``` 108 | ```sh 109 | $ docker pull zengming00/go-server-js 110 | $ docker run -d --rm -p 80:8080 zengming00/go-server-js 111 | ``` 112 | 113 | # docker 编译 mips 环境 114 | docker pull zengming00/golang-mips 115 | 116 | 117 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | go build -tags=sqlite3 -v -------------------------------------------------------------------------------- /build_linux.sh: -------------------------------------------------------------------------------- 1 | go build -tags=sqlite3 -v -ldflags "-linkmode external -extldflags -static" 2 | -------------------------------------------------------------------------------- /build_mips.sh: -------------------------------------------------------------------------------- 1 | export CGO_ENABLED=1 2 | export GOOS=linux 3 | export GOARCH=mips 4 | export CC=mips-linux-gnu-gcc 5 | export CXX=mips-linux-gnu-g++ 6 | 7 | go env 8 | go build -tags=sqlite3 -v -ldflags "-linkmode external -extldflags -static" 9 | -------------------------------------------------------------------------------- /build_sqlite3.go: -------------------------------------------------------------------------------- 1 | // +build sqlite3 2 | 3 | package main 4 | 5 | import _ "github.com/mattn/go-sqlite3" 6 | 7 | // go-sqlite3在win32下的问题 8 | // https://github.com/mattn/go-sqlite3/issues/358 9 | // 需要安装 TDM-GCC 并 set CGO_ENABLED = 1 10 | 11 | // 编译mips 12 | // apt-get install gcc-arm-linux-gnu 13 | // apt-get install g++-arm-linux-gnu 14 | // CGO_ENABLED=1 GOOS=linux GOARCH=mips CC=mips-linux-gnu-gcc CXX=mips-linux-gnu-g++ go build -v -ldflags "-linkmode external -extldflags -static" 15 | 16 | // 要将sqlite3编译进去,执行 17 | // go build -tags=sqlite3 -a -v 18 | -------------------------------------------------------------------------------- /cache.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/dop251/goja" 8 | ) 9 | 10 | type CacheMgr struct { 11 | mu sync.RWMutex 12 | gcIntervalSec int64 13 | items map[string]*CacheItem 14 | } 15 | 16 | type CacheItem struct { 17 | value interface{} 18 | expireTimeSec int64 19 | } 20 | 21 | func NewCacheMgr(gcIntervalSec int64) *CacheMgr { 22 | mgr := &CacheMgr{ 23 | gcIntervalSec: gcIntervalSec, 24 | items: make(map[string]*CacheItem), 25 | } 26 | go mgr.gc() 27 | return mgr 28 | } 29 | 30 | func (mgr *CacheMgr) gc() { 31 | for { 32 | <-time.After(time.Duration(mgr.gcIntervalSec) * time.Second) 33 | mgr.mu.Lock() 34 | for key := range mgr.items { 35 | mgr.isExpired(key) 36 | } 37 | mgr.mu.Unlock() 38 | } 39 | } 40 | 41 | func (mgr *CacheMgr) isExpired(key string) bool { 42 | if item, ok := mgr.items[key]; ok { 43 | if item.expireTimeSec <= 0 { 44 | return false 45 | } 46 | if item.expireTimeSec < time.Now().Unix() { 47 | delete(mgr.items, key) 48 | return true 49 | } 50 | return false 51 | } 52 | return true 53 | } 54 | 55 | func (mgr *CacheMgr) Add(key string, v int64, expireSec int64) int64 { 56 | mgr.mu.Lock() 57 | defer mgr.mu.Unlock() 58 | 59 | expireTimeSec := int64(-1) 60 | if expireSec > 0 { 61 | expireTimeSec = time.Now().Unix() + expireSec 62 | } 63 | 64 | if item, ok := mgr.items[key]; ok { 65 | if oldVal, ok := item.value.(int64); ok { 66 | item.expireTimeSec = expireTimeSec 67 | item.value = oldVal + v 68 | return oldVal 69 | } 70 | } 71 | mgr.items[key] = &CacheItem{ 72 | value: v, 73 | expireTimeSec: expireTimeSec, 74 | } 75 | return 0 76 | } 77 | 78 | func (mgr *CacheMgr) Set(key string, value interface{}, expireSec int64) { 79 | mgr.mu.Lock() 80 | defer mgr.mu.Unlock() 81 | 82 | expireTimeSec := int64(-1) 83 | if expireSec > 0 { 84 | expireTimeSec = time.Now().Unix() + expireSec 85 | } 86 | mgr.items[key] = &CacheItem{ 87 | value: value, 88 | expireTimeSec: expireTimeSec, 89 | } 90 | } 91 | 92 | func (mgr *CacheMgr) Get(key string) (interface{}, bool) { 93 | mgr.mu.RLock() 94 | defer mgr.mu.RUnlock() 95 | if !mgr.isExpired(key) { 96 | if v, ok := mgr.items[key]; ok { 97 | return v.value, true 98 | } 99 | } 100 | return nil, false 101 | } 102 | 103 | func (mgr *CacheMgr) Del(key string) { 104 | mgr.mu.Lock() 105 | defer mgr.mu.Unlock() 106 | delete(mgr.items, key) 107 | } 108 | 109 | func (mgr *CacheMgr) Flush() { 110 | mgr.mu.Lock() 111 | defer mgr.mu.Unlock() 112 | mgr.items = make(map[string]*CacheItem) 113 | } 114 | 115 | /////////////////////////////////////////////////////////////////////////// 116 | 117 | func NewCache(runtime *goja.Runtime, cacheMgr *CacheMgr) *goja.Object { 118 | o := runtime.NewObject() 119 | o.Set("set", func(call goja.FunctionCall) goja.Value { 120 | key := call.Argument(0).String() 121 | value := call.Argument(1).Export() 122 | expireSec := call.Argument(2).ToInteger() 123 | if IsValidType(value) { 124 | cacheMgr.Set(key, value, expireSec) 125 | return nil 126 | } 127 | panic(runtime.NewTypeError("value type %T is not permitted", value)) 128 | }) 129 | 130 | o.Set("get", func(call goja.FunctionCall) goja.Value { 131 | key := call.Argument(0).String() 132 | if value, ok := cacheMgr.Get(key); ok { 133 | return runtime.ToValue(value) 134 | } 135 | return goja.Null() 136 | }) 137 | 138 | o.Set("del", func(call goja.FunctionCall) goja.Value { 139 | key := call.Argument(0).String() 140 | cacheMgr.Del(key) 141 | return nil 142 | }) 143 | 144 | o.Set("flush", func(call goja.FunctionCall) goja.Value { 145 | cacheMgr.Flush() 146 | return nil 147 | }) 148 | 149 | o.Set("add", func(call goja.FunctionCall) goja.Value { 150 | key := call.Argument(0).String() 151 | value := call.Argument(1).ToInteger() 152 | expireSec := call.Argument(2).ToInteger() 153 | oldValue := cacheMgr.Add(key, value, expireSec) 154 | return runtime.ToValue(oldValue) 155 | }) 156 | 157 | o.Set("sub", func(call goja.FunctionCall) goja.Value { 158 | key := call.Argument(0).String() 159 | value := call.Argument(1).ToInteger() 160 | expireSec := call.Argument(2).ToInteger() 161 | oldValue := cacheMgr.Add(key, -value, expireSec) 162 | return runtime.ToValue(oldValue) 163 | }) 164 | 165 | return o 166 | } 167 | -------------------------------------------------------------------------------- /checkType.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | var validType = []reflect.Kind{ 8 | reflect.Bool, 9 | reflect.Int, 10 | reflect.Int8, 11 | reflect.Int16, 12 | reflect.Int32, 13 | reflect.Int64, 14 | reflect.Uint, 15 | reflect.Uint8, 16 | reflect.Uint16, 17 | reflect.Uint32, 18 | reflect.Uint64, 19 | reflect.Float32, 20 | reflect.Float64, 21 | reflect.Complex64, 22 | reflect.Complex128, 23 | reflect.String, 24 | } 25 | 26 | func IsValidType(val interface{}) bool { 27 | if val == nil { 28 | return true 29 | } 30 | k := reflect.TypeOf(val).Kind() 31 | for _, v := range validType { 32 | if v == k { 33 | return true 34 | } 35 | } 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/zengming00/go-server-js 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dlclark/regexp2 v1.1.6 7 | github.com/dop251/goja v0.0.0-20180113122955-eab79f83e840 8 | github.com/garyburd/redigo v1.4.0 9 | github.com/go-sql-driver/mysql v1.3.0 10 | github.com/mattn/go-sqlite3 v1.6.0 11 | golang.org/x/text v0.0.0-20171227012246-e19ae1496984 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg= 2 | github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 3 | github.com/dop251/goja v0.0.0-20180113122955-eab79f83e840 h1:c8hPp5t1uP4cfZ+HhsoVbbarv1rQrrjRTbQhf3IDFpY= 4 | github.com/dop251/goja v0.0.0-20180113122955-eab79f83e840/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= 5 | github.com/garyburd/redigo v1.4.0 h1:PlMIyh8f7og1DRVAZiU1I6VR8R5vFbWch3ddfv1ICvY= 6 | github.com/garyburd/redigo v1.4.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= 7 | github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE= 8 | github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 9 | github.com/mattn/go-sqlite3 v1.6.0 h1:TDwTWbeII+88Qy55nWlof0DclgAtI4LqGujkYMzmQII= 10 | github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 11 | golang.org/x/text v0.0.0-20171227012246-e19ae1496984 h1:ulYJn/BqO4fMRe1xAQzWjokgjsQLPpb21GltxXHI3fQ= 12 | golang.org/x/text v0.0.0-20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 13 | -------------------------------------------------------------------------------- /js/db/redis.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis') 2 | var utils = require('utils') 3 | 4 | var r = redis.dial('tcp', ':6379') 5 | if (r.err) { 6 | throw r.err; 7 | } 8 | var conn = r.value; 9 | r = conn.do('get', 'str') 10 | if (r.err) { 11 | throw r.err; 12 | } 13 | r = redis.string(r.value) 14 | if (r.err) { 15 | conn.do('set', 'str', 'helloworld', 'ex', '3') 16 | console.log(">>>>>>> set value") 17 | throw r.err; 18 | } else { 19 | log(r.value) 20 | } 21 | 22 | r = conn.do('keys', '*') 23 | if (r.err) { 24 | throw r.err; 25 | } 26 | if (Array.isArray(r.value)) { 27 | r.value.forEach(function (item) { 28 | println(utils.toString(item)) 29 | }); 30 | } 31 | r = conn.close() 32 | if (r) { 33 | throw r; 34 | } 35 | 36 | log(r) 37 | 38 | function log(data) { 39 | console.log("log:", data) 40 | console.log("log:", JSON.stringify(data, null, 2)) 41 | } 42 | 43 | function println(data) { 44 | utils.print(data); 45 | utils.print("\r\n"); 46 | response.write(data + "\r\n"); 47 | } -------------------------------------------------------------------------------- /js/db/sql.js: -------------------------------------------------------------------------------- 1 | var sql = require('sql') 2 | var url = require('url') 3 | var utils = require('utils') 4 | var types = require('types') 5 | 6 | try { 7 | // var db = sql.new("mysql", "root:root@/test2?parseTime=true&loc=" + url.queryEscape("Asia/Shanghai")) 8 | var reUse = true; 9 | var r = sql.open("mysql", "root:root@/test2", reUse); 10 | if (r.err) { 11 | throw r.err; 12 | } 13 | var db = r.value; 14 | if (!r.isReUse) { 15 | db.setMaxOpenConns(100); 16 | } 17 | var stat = db.stats(); 18 | response.write(JSON.stringify(stat, null, 2)) 19 | r = db.query("select * from users") 20 | if (r.err) { 21 | throw r.err; 22 | } 23 | var rows = r.value; 24 | while (rows.next()) { 25 | var data = getData(rows) 26 | utils.print(JSON.stringify(data, null, 2)) 27 | utils.print("\r\n") 28 | } 29 | var err = rows.err() 30 | if (err) { 31 | throw err; 32 | } 33 | err = rows.close(); 34 | if (err) { 35 | throw err; 36 | } 37 | // err = db.close(); 38 | // if (err) { 39 | // throw err; 40 | // } 41 | } catch (e) { 42 | console.log("ee: %j", e) 43 | throw e; 44 | } 45 | 46 | function getData(rows) { 47 | var arr = [ 48 | types.newString(), 49 | types.newString(), 50 | types.newString(), 51 | types.newString(), 52 | types.newString(), 53 | types.newString(), 54 | types.newString(), 55 | types.newString(), 56 | ]; 57 | var err = rows.scan.apply(rows, arr) 58 | if (err) { 59 | throw err; 60 | } 61 | response.write(JSON.stringify(arr, null, 2)) 62 | return { 63 | // id: types.intValue(arr[0]), 64 | a: types.stringValue(arr[1]), 65 | } 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /js/ejs/functions.ejs: -------------------------------------------------------------------------------- 1 |

Users

2 | 3 | <% function user(user) { %> 4 |
  • <%= user.name %> is a <%= user.age %> year old <%= user.species %>.
  • 5 | <% } %> 6 | 7 | 10 |

    ejs version: <%= version %>

    11 | -------------------------------------------------------------------------------- /js/ejs/functions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Believe it or not, you can declare and use functions in EJS templates too. 3 | */ 4 | 5 | var ejs = require("./js/ejs/ejs.js"); 6 | var file = require("file"); 7 | var utils = require("utils"); 8 | 9 | function fileLoader(filePath) { 10 | var r = file.read(filePath); 11 | if(r.err){ 12 | throw r.err 13 | } 14 | return utils.toString(r.data); 15 | } 16 | 17 | ejs.fileLoader = fileLoader; 18 | 19 | var data = { 20 | users: [ 21 | { name: 'Tobi', age: 2, species: 'zengming' }, 22 | { name: 'Loki', age: 2, species: 'ferret' }, 23 | { name: 'Jane', age: 6, species: new Date().toString() }, 24 | ], 25 | version: ejs.VERSION, 26 | }; 27 | 28 | var path = './js/ejs/functions.ejs'; 29 | var content = fileLoader(path); 30 | var func = ejs.compile(content, { filename: path }); 31 | var ret = func(data); 32 | response.write(ret) 33 | 34 | -------------------------------------------------------------------------------- /js/ejs/list.ejs: -------------------------------------------------------------------------------- 1 | <% if (names.length) { %> 2 | 8 | <% } %> 9 | -------------------------------------------------------------------------------- /js/ejs/list.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This example demonstrates how to use Array.prototype.forEach() in an EJS 3 | * template. 4 | */ 5 | 6 | // var ejs = require("./js/ejs/ejs.js"); 7 | var ejs = require("./js/ejs/ejs.min.js"); 8 | var file = require("file"); 9 | var utils = require("utils"); 10 | var myUtils = require('./js/utils.js'); 11 | 12 | 13 | ejs.fileLoader = myUtils.fileLoader; 14 | 15 | var data = { 16 | names: ['foo', 'bar', '"baz'] 17 | }; 18 | 19 | 20 | ejs.renderFile('./js/ejs/list.ejs', data, function (err, html) { 21 | if (err) { 22 | console.log(err); 23 | return 24 | } 25 | response.header().set('Content-Type', 'text/html; charset=utf-8'); 26 | response.write(html); 27 | }); 28 | -------------------------------------------------------------------------------- /js/ejs/list_redis.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This example demonstrates how to use Array.prototype.forEach() in an EJS 3 | * template. 4 | */ 5 | 6 | // var ejs = require("./js/ejs/ejs.js"); 7 | var ejs = require("./js/ejs/ejs.min.js"); 8 | var file = require("file"); 9 | var utils = require("utils"); 10 | var redis = require('redis') 11 | 12 | function fileLoader(filePath) { 13 | return utils.toString(file.read(filePath)); 14 | } 15 | 16 | 17 | var data = { 18 | names: [ejs.VERSION], 19 | }; 20 | 21 | var conn = redis.dial('tcp', ':6379') 22 | var v = conn.do('keys', '*') 23 | if (Array.isArray(v)) { 24 | v.forEach(function (item) { 25 | var str = utils.toString(item); 26 | data.names.push(str); 27 | }); 28 | } 29 | conn.close() 30 | 31 | var path = './js/ejs/list.ejs'; 32 | var content = fileLoader(path); 33 | ejs.compile(content, { filename: path })(data); 34 | -------------------------------------------------------------------------------- /js/ejs/sql.ejs: -------------------------------------------------------------------------------- 1 | <% if (datas.length) { %> 2 | 3 | <% datas.forEach(function (item) { %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | <% }) %> 13 |
    <%= item.id %><%= item.firstname %><%= item.lastname %><%= item.phone %><%= item.email %><%= item.created_at.Time ? item.created_at.Time : item.created_at %>
    14 | <% } %> 15 | -------------------------------------------------------------------------------- /js/ejs/sql.js: -------------------------------------------------------------------------------- 1 | var sql = require('sql') 2 | var url = require('url') 3 | var file = require('file'); 4 | var utils = require('utils') 5 | var ejs = require('./js/ejs/ejs.min.js'); 6 | var myUtils = require('./js/utils.js'); 7 | 8 | 9 | 10 | // var db = sql.new("mysql", "root:root@/test2?parseTime=true&loc=" + url.queryEscape("Asia/Shanghai")) 11 | // var db = sql.new("mysql", "root:root@/test2") 12 | var r = sql.open("sqlite3", "./js/db/test.db") 13 | if (r.err) { 14 | throw r.err; 15 | } 16 | 17 | var db = r.value; 18 | r = db.query("select * from users") 19 | if (r.err) { 20 | throw r.err; 21 | } 22 | 23 | var rows = r.value; 24 | var rowDatas = []; 25 | while (rows.next()) { 26 | var data = rows.getData(); 27 | rowDatas.push(data); 28 | } 29 | 30 | var err = rows.err() 31 | if (err) { 32 | throw err; 33 | } 34 | db.close() 35 | log(rowDatas) 36 | var path = './js/ejs/sql.ejs'; 37 | var content = myUtils.fileLoader(path); 38 | var func = ejs.compile(content, { filename: path }); 39 | var html = func({ datas: rowDatas }); 40 | response.write(html) 41 | 42 | function log(data) { 43 | console.log("log:", data) 44 | console.log("log:", JSON.stringify(data, null, 2)) 45 | } 46 | -------------------------------------------------------------------------------- /js/file/test1.js: -------------------------------------------------------------------------------- 1 | var os = require('os') 2 | 3 | var r = os.create('te.txt') 4 | if(r.err){ 5 | throw r.err 6 | } 7 | 8 | var file = r.file 9 | file.writeString("helloworld go-serverjs") 10 | file.close() 11 | -------------------------------------------------------------------------------- /js/http/body.js: -------------------------------------------------------------------------------- 1 | var utils = require('utils') 2 | 3 | function log(d) { 4 | console.log("%j", d); 5 | var r = response.write(d); 6 | if (r.err) { 7 | throw r.err; 8 | } 9 | response.write('\r\n'); 10 | } 11 | 12 | var r = request.getRawBody() 13 | if (r.err) { 14 | throw r.err; 15 | } 16 | 17 | var value = utils.toString(r.value) 18 | log(value) 19 | var obj = JSON.parse(value) 20 | log(obj.a) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /js/http/cookie.js: -------------------------------------------------------------------------------- 1 | 2 | var Name = 'test' 3 | var Value = 'testval' 4 | var Path = '/' 5 | var MaxAge = 10 6 | var HttpOnly = true 7 | 8 | 9 | // response.setCookie(Name, Value, Path, MaxAge, HttpOnly) 10 | response.setCookie(Name, Value, Path, MaxAge) 11 | // response.setCookie(Name, Value, Path) 12 | 13 | 14 | var cks = request.cookies() 15 | var str = JSON.stringify(cks, null, 2) 16 | log(str) 17 | 18 | var r = request.cookie('test') 19 | if (r.err) { 20 | throw r.err; 21 | } 22 | var cookie = r.value 23 | log(cookie.name) 24 | log(cookie.value) 25 | 26 | 27 | function log(d) { 28 | console.log("%j", d); 29 | response.write(d); 30 | response.write('\r\n'); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /js/http/download.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/js/http/download.js -------------------------------------------------------------------------------- /js/http/header.js: -------------------------------------------------------------------------------- 1 | var utils = require('utils') 2 | 3 | function log(d) { 4 | console.log("%j", d); 5 | response.write(d); 6 | response.write('\r\n'); 7 | } 8 | 9 | log("getHeader('content-type'): " + request.header.get('content-type')) // application/x-www-form-urlencoded 10 | log("headers:" + JSON.stringify(request.headers, null, 2)) 11 | log("headers:" + JSON.stringify(request.headers['Haha'], null, 2)) 12 | var r = request.header.getRaw() 13 | log(utils.toString(r)) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /js/http/http.js: -------------------------------------------------------------------------------- 1 | var http = require("http") 2 | var file = require("file") 3 | var utils = require("utils") 4 | var url = require('url') 5 | 6 | var obj = { 7 | ticket: '99c936b0-9c35-11e7-be48-43b6cddd43aa' 8 | }; 9 | 10 | var header = { 11 | "Content-Type": "application/json", 12 | "x-api-version": "1", 13 | }; 14 | 15 | var method = "POST" 16 | var url = "http://esee.rabbitpre.com/api/rabuser/login" 17 | var body = JSON.stringify(obj) 18 | var data = http.request(method, url, header, body, 3000) 19 | 20 | data.body = utils.toString(data.body); 21 | console.log("data:", JSON.stringify(data, null, 2)) 22 | console.log("Set-Cookie:", data.header['Set-Cookie'][0]) 23 | 24 | obj = JSON.parse(data.body) 25 | var avatar = obj.result.avatar 26 | console.log("avatar:", avatar) 27 | try { 28 | data = http.request("GET", avatar, {}, '', 3000) 29 | file.write("./a.jpg", data.body) 30 | } catch (e) { 31 | console.log("err:", e) 32 | throw e; 33 | } 34 | console.log('done.'); 35 | 36 | -------------------------------------------------------------------------------- /js/http/request.js: -------------------------------------------------------------------------------- 1 | 2 | function log(d) { 3 | console.log("%j", d); 4 | response.write(d); 5 | response.write('\r\n'); 6 | } 7 | 8 | // http://localhost:8080/js/http/request.js?a=b&c=d&c=22#aa 9 | 10 | log("method: " + request.method) // POST 11 | log("uri: " + request.uri) // /js/http/request.js?a=b&c=d 12 | log("host: " + request.host) // localhost:8080 13 | log("userAgent: " + request.userAgent()) // PostmanRuntime/7.1.1 14 | log("remoteAddr: " + request.remoteAddr) // [::1]:63716 15 | 16 | // 若调用 parseForm() 则body参数必需以'application/x-www-form-urlencoded'方式传递 17 | // 不调用,则可以由'application/x-www-form-urlencoded'和'multipart/form-data'传递 18 | // request.parseForm() 19 | log("test=" + request.formValue('test')) // from body test=1111 : 1111 20 | 21 | log("a=" + request.formValue('a')) // b 22 | log("c=" + request.formValue('c')) // d 23 | 24 | var values = request.form.gets('c') 25 | log(JSON.stringify(values)) // ["d","22"] -------------------------------------------------------------------------------- /js/http/session.js: -------------------------------------------------------------------------------- 1 | // session.start() // 可选操作,如果没有调用,在set和get时会自动调用 2 | // session.end() 3 | session.set('aa', 'helloworld') 4 | console.log(session.get('aa')) -------------------------------------------------------------------------------- /js/http/upload.js: -------------------------------------------------------------------------------- 1 | var io = require('io') 2 | var os = require('os') 3 | 4 | if (request.method === 'POST') { 5 | var err = request.parseMultipartForm(1024 * 1024) 6 | if (err) { 7 | throw err 8 | } 9 | var haha = request.formValue('haha') 10 | console.log('haha:', haha) 11 | var o = request.formFile('file') 12 | if (o.err) { 13 | throw o.err 14 | } 15 | console.log(o.name) 16 | var r = os.openFile(o.name, os.O_CREATE|os.O_WRONLY, 0666) 17 | var file = r.value 18 | io.copy(file, o.file) 19 | o.file.close() 20 | file.close() 21 | response.write(JSON.stringify(o.header, null, 2)) 22 | 23 | } else { 24 | response.write("hello /") 25 | } -------------------------------------------------------------------------------- /js/image/image.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var image = require('image'); 4 | 5 | var Image = (function () { 6 | function Image(w, h) { 7 | this.w = w; 8 | this.h = h; 9 | 10 | var rect = image.rect(0, 0, this.w, this.h) 11 | this.img = image.newRGBA(rect) 12 | } 13 | Image.prototype.drawPoint = function (x, y, rgba) { 14 | if (x >= this.w || y >= this.h || x < 0 || y < 0) { 15 | return; 16 | } 17 | if (!(rgba instanceof Object)) { 18 | rgba = { 19 | b: rgba & 0xFF, // 蓝 20 | g: (rgba >> 8) & 0xFF, // 绿 21 | r: (rgba >> 16) & 0xFF, // 红 22 | a: 255, 23 | } 24 | } 25 | this.img.setRGBA(x, y, rgba.r, rgba.g, rgba.b, rgba.a); 26 | }; 27 | Image.prototype.drawLineH = function (x1, x2, y, rgba) { 28 | if (x1 > x2) { 29 | var tmp = x2; 30 | x2 = x1; 31 | x1 = tmp; 32 | } 33 | for (; x1 <= x2; x1++) { 34 | this.drawPoint(x1, y, rgba); 35 | } 36 | }; 37 | Image.prototype.drawLineV = function (y1, y2, x, rgba) { 38 | if (y1 > y2) { 39 | var tmp = y2; 40 | y2 = y1; 41 | y1 = tmp; 42 | } 43 | for (; y1 <= y2; y1++) { 44 | this.drawPoint(x, y1, rgba); 45 | } 46 | }; 47 | Image.prototype.drawLine = function (x1, y1, x2, y2, rgba) { 48 | var x, y, dx, dy, s1, s2, p, temp, interchange, i; 49 | x = x1; 50 | y = y1; 51 | dx = x2 > x1 ? (x2 - x1) : (x1 - x2); 52 | dy = y2 > y1 ? (y2 - y1) : (y1 - y2); 53 | s1 = x2 > x1 ? 1 : -1; 54 | s2 = y2 > y1 ? 1 : -1; 55 | if (dy > dx) { 56 | temp = dx; 57 | dx = dy; 58 | dy = temp; 59 | interchange = true; 60 | } 61 | else { 62 | interchange = false; 63 | } 64 | p = (dy << 1) - dx; 65 | for (i = 0; i <= dx; i++) { 66 | this.drawPoint(x, y, rgba); 67 | if (p >= 0) { 68 | if (interchange) { 69 | x = x + s1; 70 | } 71 | else { 72 | y = y + s2; 73 | } 74 | p = p - (dx << 1); 75 | } 76 | if (interchange) { 77 | y = y + s2; 78 | } 79 | else { 80 | x = x + s1; 81 | } 82 | p = p + (dy << 1); 83 | } 84 | }; 85 | Image.prototype.drawRect = function (x1, y1, x2, y2, rgba) { 86 | this.drawLineH(x1, x2, y1, rgba); 87 | this.drawLineH(x1, x2, y2, rgba); 88 | this.drawLineV(y1, y2, x1, rgba); 89 | this.drawLineV(y1, y2, x2, rgba); 90 | }; 91 | Image.prototype.fillRect = function (x1, y1, x2, y2, rgba) { 92 | var x; 93 | if (x1 > x2) { 94 | var tmp = x2; 95 | x2 = x1; 96 | x1 = tmp; 97 | } 98 | if (y1 > y2) { 99 | var tmp = y2; 100 | y2 = y1; 101 | y1 = tmp; 102 | } 103 | for (; y1 <= y2; y1++) { 104 | for (x = x1; x <= x2; x++) { 105 | this.drawPoint(x, y1, rgba); 106 | } 107 | } 108 | }; 109 | Image.prototype.drawCircle = function (x, y, r, rgba) { 110 | var a, b, c; 111 | a = 0; 112 | b = r; 113 | // c = 1.25 - r; 114 | c = 3 - 2 * r; 115 | while (a < b) { 116 | this.drawPoint(x + a, y + b, rgba); 117 | this.drawPoint(x - a, y + b, rgba); 118 | this.drawPoint(x + a, y - b, rgba); 119 | this.drawPoint(x - a, y - b, rgba); 120 | this.drawPoint(x + b, y + a, rgba); 121 | this.drawPoint(x - b, y + a, rgba); 122 | this.drawPoint(x + b, y - a, rgba); 123 | this.drawPoint(x - b, y - a, rgba); 124 | if (c < 0) { 125 | c = c + 4 * a + 6; 126 | } 127 | else { 128 | c = c + 4 * (a - b) + 10; 129 | b -= 1; 130 | } 131 | a = a + 1; 132 | } 133 | if (a === b) { 134 | this.drawPoint(x + a, y + b, rgba); 135 | this.drawPoint(x - a, y + b, rgba); 136 | this.drawPoint(x + a, y - b, rgba); 137 | this.drawPoint(x - a, y + b, rgba); 138 | this.drawPoint(x + b, y + a, rgba); 139 | this.drawPoint(x - b, y + a, rgba); 140 | this.drawPoint(x + b, y - a, rgba); 141 | this.drawPoint(x - b, y - a, rgba); 142 | } 143 | }; 144 | Image.prototype.drawChar = function (ch, x, y, font, rgba) { 145 | var index = font.fonts.indexOf(ch); 146 | if (index < 0) { 147 | return; 148 | } 149 | var fontData = font.data[index]; 150 | var y0 = y; 151 | var x0 = x; 152 | for (var _i = 0, fontData_1 = fontData; _i < fontData_1.length; _i++) { 153 | var data = fontData_1[_i]; 154 | x0 = x; 155 | for (var b = data; b > 0; b <<= 1) { 156 | if (b & 0x80) { 157 | this.drawPoint(x0, y0, rgba); 158 | } 159 | x0++; 160 | } 161 | y0++; 162 | if ((y0 - y) >= font.h) { 163 | y0 = y; 164 | x += 8; 165 | } 166 | } 167 | }; 168 | Image.prototype.drawString = function (str, x, y, font, rgba) { 169 | for (var _i = 0, str_1 = str; _i < str_1.length; _i++) { 170 | var c = str_1[_i]; 171 | this.drawChar(c, x, y, font, rgba); 172 | x += font.w; 173 | } 174 | }; 175 | return Image; 176 | }()); 177 | exports.Image = Image; 178 | -------------------------------------------------------------------------------- /js/image/test1.js: -------------------------------------------------------------------------------- 1 | var os = require('os') 2 | var png = require('png') 3 | var font = require('./js/image/font.js') 4 | var image = require('./js/image/image.js') 5 | 6 | 7 | 8 | function writeToFile(img) { 9 | var r = os.create('image.png') 10 | if (r.err) { 11 | console.log(r.err) 12 | return 13 | } 14 | var file = r.file 15 | 16 | var err = png.encode(file, img) 17 | if (err) { 18 | console.log(err) 19 | return 20 | } 21 | var err = file.close() 22 | if (err) { 23 | console.log(err) 24 | return 25 | } 26 | console.log("done.") 27 | } 28 | 29 | function writeToResponse(img) { 30 | var err = png.encode(response, img) 31 | if (err) { 32 | console.log(err) 33 | return 34 | } 35 | } 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | var cnfonts = { 45 | w: 16, 46 | h: 16, 47 | fonts: '中国', 48 | data: [ 49 | [0x01, 0x01, 0x01, 0x01, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x08, 0x08, 0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00], 50 | [0x00, 0x7F, 0x40, 0x40, 0x5F, 0x41, 0x41, 0x4F, 0x41, 0x41, 0x41, 0x5F, 0x40, 0x40, 0x7F, 0x40, 0x00, 0xFC, 0x04, 0x04, 0xF4, 0x04, 0x04, 0xE4, 0x04, 0x44, 0x24, 0xF4, 0x04, 0x04, 0xFC, 0x04], 51 | ], 52 | }; 53 | // 测试字库 54 | function makeImg2() { 55 | var img = new image.Image(300, 140); 56 | img.drawString('helloworld', 20, 10, font.font8x16, { r: 255, g: 0, b: 0, a: 255 }); 57 | img.drawString('helloworld', 20, 25, font.font12x24, { r: 0, g: 255, b: 0, a: 255 }); 58 | img.drawString('helloworld', 20, 50, font.font16x32, { r: 0, g: 0, b: 255, a: 255 }); 59 | img.drawString('中国', 20, 85, cnfonts, { r: 255, g: 255, b: 0, a: 255 }); 60 | return img; 61 | } 62 | // 仿PHP的rand函数 63 | function rand(min, max) { 64 | return Math.random() * (max - min + 1) + min | 0; 65 | } 66 | // 制造验证码图片 67 | function makeCapcha() { 68 | var img = new image.Image(100, 40); 69 | img.drawCircle(rand(0, 100), rand(0, 40), rand(10, 40), rand(0, 0xffffff)); 70 | // 边框 71 | img.drawRect(0, 0, img.w - 1, img.h - 1, rand(0, 0xffffff)); 72 | img.fillRect(rand(0, 100), rand(0, 40), rand(10, 35), rand(10, 35), rand(0, 0xffffff)); 73 | img.drawLine(rand(0, 100), rand(0, 40), rand(0, 100), rand(0, 40), rand(0, 0xffffff)); 74 | // return img; 75 | // 画曲线 76 | var w = img.w / 2; 77 | var h = img.h; 78 | var color = rand(0, 0xffffff); 79 | var y1 = rand(-5, 5); // Y轴位置调整 80 | var w2 = rand(10, 15); // 数值越小频率越高 81 | var h3 = rand(4, 6); // 数值越小幅度越大 82 | var bl = rand(1, 5); 83 | for (var i_1 = -w; i_1 < w; i_1 += 0.1) { 84 | var y_1 = Math.floor(h / h3 * Math.sin(i_1 / w2) + h / 2 + y1); 85 | var x_1 = Math.floor(i_1 + w); 86 | for (var j = 0; j < bl; j++) { 87 | img.drawPoint(x_1, y_1 + j, color); 88 | } 89 | } 90 | var p = 'ABCDEFGHKMNPQRSTUVWXYZ3456789'; 91 | var str = ''; 92 | for (var i_2 = 0; i_2 < 5; i_2++) { 93 | str += p.charAt(Math.random() * p.length | 0); 94 | } 95 | var fonts = [font.font8x16, font.font12x24, font.font16x32]; 96 | var x = 15, y = 8; // tslint:disable-line 97 | for (var _i = 0, str_1 = str; _i < str_1.length; _i++) { 98 | var ch = str_1[_i]; 99 | var f = fonts[Math.random() * fonts.length | 0]; 100 | y = 8 + rand(-10, 10); 101 | img.drawChar(ch, x, y, f, rand(0, 0xffffff)); 102 | x += f.w + rand(2, 8); 103 | } 104 | return img; 105 | } 106 | 107 | // 测试生成验证码的效率 108 | // var start = Date.now(); 109 | // var i = 0; 110 | // while ((Date.now() - start) < 1000) { 111 | // makeCapcha(); 112 | // // makeImg2(); 113 | // i++; 114 | // } 115 | // console.log('1秒钟生成:' + i); 116 | 117 | 118 | // writeToResponse(makeImg2().img) 119 | writeToResponse(makeCapcha().img) -------------------------------------------------------------------------------- /js/image/test2.js: -------------------------------------------------------------------------------- 1 | var os = require('os') 2 | var png = require('png') 3 | var image = require('image') 4 | 5 | 6 | function writeToFile(img) { 7 | var r = os.create('image.png') 8 | if (r.err) { 9 | console.log(r.err) 10 | return 11 | } 12 | var file = r.file 13 | 14 | var err = png.encode(file, img) 15 | if (err) { 16 | console.log(err) 17 | return 18 | } 19 | var err = file.close() 20 | if (err) { 21 | console.log(err) 22 | return 23 | } 24 | console.log("done.") 25 | } 26 | 27 | function writeToResponse(img) { 28 | var err = png.encode(response, img) 29 | if (err) { 30 | console.log(err) 31 | return 32 | } 33 | } 34 | 35 | // var start = Date.now(); 36 | // var i = 0; 37 | // while ((Date.now() - start) < 1000) { 38 | // image.makeCapcha() 39 | // i++; 40 | // } 41 | // console.log('1秒钟生成:' + i); 42 | 43 | writeToResponse(image.makeCapcha()) 44 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | 2 | var header = response.header() 3 | header.set('location', '/public') 4 | 5 | response.writeHeader(302) 6 | 7 | -------------------------------------------------------------------------------- /js/others/cache.js: -------------------------------------------------------------------------------- 1 | cache.set("a", 1234) 2 | cache.set("b", "bbbb") 3 | 4 | get("a") 5 | get("b") 6 | cache.del("b") 7 | get("b") 8 | 9 | var r = cache.get("c") 10 | if (!r.ok) { 11 | console.log("set c") 12 | cache.set("c", Date.now(), 10) 13 | } else { 14 | console.log("get c:", r.value) 15 | } 16 | 17 | function get(key) { 18 | var r = cache.get(key) 19 | if (r.ok) { 20 | console.log(key + ":" + r.value) 21 | } else { 22 | console.log(key + " not exists") 23 | } 24 | } 25 | 26 | get('i') 27 | console.log('oldv:', cache.add("i", 3, 10)) 28 | get('i') 29 | console.log('oldv:', cache.sub("i", 2, 10)) 30 | get('i') 31 | 32 | console.log("--------------------------------------") -------------------------------------------------------------------------------- /js/others/os.js: -------------------------------------------------------------------------------- 1 | var os = require('os') 2 | 3 | console.log('args', os.args) 4 | 5 | function getwd() { 6 | var wd = os.getwd() 7 | if (wd.err) { 8 | throw err; 9 | } 10 | console.log('wd:', wd.value) 11 | } 12 | 13 | getwd() 14 | os.chdir("d:/") 15 | getwd() 16 | 17 | console.log('tmpdir:', os.tempDir()) 18 | console.log('path:', os.getEnv('path')) 19 | 20 | var r = os.hostname() 21 | if (r.err) { 22 | throw err; 23 | } 24 | console.log('hostname:', r.value) 25 | 26 | var r = os.mkdir("est", 0666) 27 | if (r) { 28 | throw r; 29 | } 30 | r = os.remove('est') 31 | if (r) { 32 | throw r; 33 | } 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /js/others/require.js: -------------------------------------------------------------------------------- 1 | var fmt = require('fmt') 2 | var os = require('os') 3 | var utils = require('utils') 4 | var file = require('file') 5 | 6 | var r = cache.get("a") 7 | 8 | if (!r.ok) { 9 | console.log('set a') 10 | cache.set("a", 11.9, 10) 11 | } 12 | 13 | fmt.printf("%s %d %T \n", 'hello', 123, { a: true }) 14 | 15 | var list = require_list() 16 | var str = JSON.stringify(list, null, 2) 17 | 18 | console.log('require_list:', str) 19 | 20 | 21 | 22 | var fs = require_get('fs') 23 | if (!fs) { 24 | var myExports = { 25 | foo: function () { 26 | console.log('foooooo'); 27 | }, 28 | readFileSync: function (name) { 29 | var r = file.read(name); 30 | if (r.err) { 31 | throw r.err 32 | } 33 | return utils.toString(r.value); 34 | }, 35 | existsSync: function (name) { 36 | var r = os.stat(name) 37 | return !r.err; 38 | } 39 | } 40 | var myModule = { 41 | exports: myExports, 42 | a: true, 43 | b: 1234, 44 | c: 'asdf', 45 | d: [1, 4, 6] 46 | }; 47 | require_set('fs', myModule); 48 | } 49 | var fs = require('fs'); 50 | fs.foo(); 51 | var name = './test/a.js'; 52 | var r = fs.existsSync('asdf') 53 | console.log('existsSync:', r) 54 | var r = fs.readFileSync(name); 55 | console.log(r.toString()) 56 | 57 | -------------------------------------------------------------------------------- /js/others/return.js: -------------------------------------------------------------------------------- 1 | var types = require('types'); 2 | 3 | var a = types.retNil(); 4 | // console.log('a:', a === null) // false 5 | console.log('a:', a === undefined) // ture 6 | 7 | var b = types.retNull(); 8 | // console.log(b === null) // true 9 | console.log(b === undefined) // false 10 | 11 | var c = types.retUndefined() 12 | // console.log(c === null) // false 13 | console.log(c === undefined) // true 14 | console.log('=a:', c === a) // true 15 | console.log('=b:', c === b) // true -------------------------------------------------------------------------------- /js/others/types.js: -------------------------------------------------------------------------------- 1 | var types = require('types') 2 | console.log(types.err()) 3 | console.log("%j", types.err()) 4 | console.log(JSON.stringify(types.err())) 5 | console.log(types.err2()) -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | var file = require('file'); 2 | 3 | exports.log = function (data) { 4 | console.log("log: %j", data); 5 | console.log("log json: ", JSON.stringify(data, null, 2)); 6 | } 7 | 8 | exports.fileLoader = function (filePath) { 9 | var r = file.read(filePath); 10 | if (r.err) { 11 | throw err; 12 | } 13 | return utils.toString(r.value); 14 | } 15 | 16 | exports.toInt = function (v, def) { 17 | def = def || 0; 18 | v = parseInt(v); 19 | return isNaN(v) ? def : v; 20 | } -------------------------------------------------------------------------------- /lib/db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewDB(runtime *goja.Runtime, db *sql.DB) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("query", func(call goja.FunctionCall) goja.Value { 13 | args := lib.GetAllArgs(&call) 14 | if query, ok := args[0].(string); ok { 15 | var rows *sql.Rows 16 | var err error 17 | if len(args) == 1 { 18 | rows, err = db.Query(query) 19 | } else { 20 | rows, err = db.Query(query, args[1:]...) 21 | } 22 | if err != nil { 23 | return lib.MakeErrorValue(runtime, err) 24 | } 25 | return lib.MakeReturnValue(runtime, NewRows(runtime, rows)) 26 | } 27 | panic(runtime.NewTypeError("p0 is not a string type:%T", args[0])) 28 | }) 29 | 30 | o.Set("close", func(call goja.FunctionCall) goja.Value { 31 | err := db.Close() 32 | if err != nil { 33 | return runtime.ToValue(lib.NewError(runtime, err)) 34 | } 35 | return nil 36 | }) 37 | 38 | o.Set("exec", func(call goja.FunctionCall) goja.Value { 39 | args := lib.GetAllArgs(&call) 40 | 41 | if query, ok := args[0].(string); ok { 42 | var result sql.Result 43 | var err error 44 | if len(args) == 1 { 45 | result, err = db.Exec(query) 46 | } else { 47 | result, err = db.Exec(query, args[1:]...) 48 | } 49 | if err != nil { 50 | return lib.MakeErrorValue(runtime, err) 51 | } 52 | return lib.MakeReturnValue(runtime, NewResult(runtime, result)) 53 | } 54 | panic(runtime.NewTypeError("p0 is not a string type:%T", args[0])) 55 | }) 56 | 57 | o.Set("prepare", func(call goja.FunctionCall) goja.Value { 58 | query := call.Argument(0).String() 59 | stmt, err := db.Prepare(query) 60 | if err != nil { 61 | return lib.MakeErrorValue(runtime, err) 62 | } 63 | return lib.MakeReturnValue(runtime, NewStmt(runtime, stmt)) 64 | }) 65 | 66 | o.Set("stats", func(call goja.FunctionCall) goja.Value { 67 | st := db.Stats() 68 | o := runtime.NewObject() 69 | o.Set("openConnections", st.OpenConnections) 70 | return o 71 | }) 72 | 73 | o.Set("begin", func(call goja.FunctionCall) goja.Value { 74 | tx, err := db.Begin() 75 | if err != nil { 76 | return lib.MakeErrorValue(runtime, err) 77 | } 78 | return lib.MakeReturnValue(runtime, NewTx(runtime, tx)) 79 | }) 80 | 81 | o.Set("setMaxOpenConns", func(call goja.FunctionCall) goja.Value { 82 | n := call.Argument(0).ToInteger() 83 | db.SetMaxOpenConns(int(n)) 84 | return nil 85 | }) 86 | 87 | o.Set("setMaxIdleConns", func(call goja.FunctionCall) goja.Value { 88 | n := call.Argument(0).ToInteger() 89 | db.SetMaxIdleConns(int(n)) 90 | return nil 91 | }) 92 | return o 93 | } 94 | -------------------------------------------------------------------------------- /lib/db/redis/conn.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "github.com/dop251/goja" 5 | "github.com/garyburd/redigo/redis" 6 | "github.com/zengming00/go-server-js/lib" 7 | ) 8 | 9 | func NewConn(runtime *goja.Runtime, conn redis.Conn) *goja.Object { 10 | o := runtime.NewObject() 11 | o.Set("do", func(call goja.FunctionCall) goja.Value { 12 | commandName := call.Argument(0).String() 13 | args := lib.GetAllArgs(&call) 14 | reply, err := conn.Do(commandName, args[1:]...) 15 | if err != nil { 16 | return lib.MakeErrorValue(runtime, err) 17 | } 18 | return lib.MakeReturnValue(runtime, reply) 19 | }) 20 | 21 | o.Set("close", func(call goja.FunctionCall) goja.Value { 22 | err := conn.Close() 23 | if err != nil { 24 | return lib.MakeErrorValue(runtime, err) 25 | } 26 | return nil 27 | }) 28 | return o 29 | } 30 | -------------------------------------------------------------------------------- /lib/db/redis/redis.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "github.com/dop251/goja" 5 | "github.com/garyburd/redigo/redis" 6 | "github.com/zengming00/go-server-js/lib" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func init() { 11 | require.RegisterNativeModule("redis", func(runtime *goja.Runtime, module *goja.Object) { 12 | o := module.Get("exports").(*goja.Object) 13 | o.Set("dial", func(call goja.FunctionCall) goja.Value { 14 | network := call.Argument(0).String() 15 | address := call.Argument(1).String() 16 | conn, err := redis.Dial(network, address) 17 | if err != nil { 18 | return lib.MakeErrorValue(runtime, err) 19 | } 20 | return lib.MakeReturnValue(runtime, NewConn(runtime, conn)) 21 | }) 22 | 23 | o.Set("string", func(call goja.FunctionCall) goja.Value { 24 | repl := call.Argument(0).Export() 25 | str, err := redis.String(repl, nil) 26 | if err != nil { 27 | return lib.MakeErrorValue(runtime, err) 28 | } 29 | return lib.MakeReturnValue(runtime, str) 30 | }) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /lib/db/result.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewResult(runtime *goja.Runtime, result sql.Result) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("lastInsertId", func(call goja.FunctionCall) goja.Value { 13 | id, err := result.LastInsertId() 14 | if err != nil { 15 | return lib.MakeErrorValue(runtime, err) 16 | } 17 | return lib.MakeReturnValue(runtime, id) 18 | }) 19 | 20 | o.Set("rowsAffected", func(call goja.FunctionCall) goja.Value { 21 | rows, err := result.RowsAffected() 22 | if err != nil { 23 | return lib.MakeErrorValue(runtime, err) 24 | } 25 | return lib.MakeReturnValue(runtime, rows) 26 | }) 27 | return o 28 | } 29 | -------------------------------------------------------------------------------- /lib/db/rows.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | "reflect" 6 | 7 | "github.com/dop251/goja" 8 | "github.com/go-sql-driver/mysql" 9 | "github.com/zengming00/go-server-js/lib" 10 | ) 11 | 12 | func NewRows(runtime *goja.Runtime, rows *sql.Rows) *goja.Object { 13 | o := runtime.NewObject() 14 | o.Set("err", func(call goja.FunctionCall) goja.Value { 15 | err := rows.Err() 16 | if err != nil { 17 | return runtime.ToValue(lib.NewError(runtime, err)) 18 | } 19 | return nil 20 | }) 21 | 22 | o.Set("getData", func(call goja.FunctionCall) goja.Value { 23 | rows := rows 24 | cols, err := rows.Columns() 25 | if err != nil { 26 | panic(runtime.NewGoError(err)) 27 | } 28 | ct, err := rows.ColumnTypes() 29 | if err != nil { 30 | panic(runtime.NewGoError(err)) 31 | } 32 | 33 | arr := make([]interface{}, len(ct)) 34 | for i, v := range ct { 35 | t := v.ScanType() 36 | arr[i] = reflect.New(t).Interface() 37 | } 38 | 39 | err = rows.Scan(arr...) 40 | if err != nil { 41 | panic(runtime.NewGoError(err)) 42 | } 43 | 44 | m := make(map[string]interface{}) 45 | for i, col := range cols { 46 | switch vv := arr[i].(type) { 47 | case *int64: 48 | m[col] = *vv 49 | case *int32: 50 | m[col] = *vv 51 | case *sql.NullString: 52 | m[col] = *vv 53 | case *sql.NullBool: 54 | m[col] = *vv 55 | case *sql.NullFloat64: 56 | m[col] = *vv 57 | case *sql.NullInt64: 58 | m[col] = *vv 59 | case *sql.RawBytes: 60 | m[col] = string(*vv) 61 | case *mysql.NullTime: 62 | m[col] = *vv 63 | case *string: 64 | m[col] = *vv 65 | default: 66 | panic(runtime.NewTypeError("unknown type %T", vv)) 67 | } 68 | } 69 | return runtime.ToValue(m) 70 | }) 71 | 72 | o.Set("scan", func(call goja.FunctionCall) goja.Value { 73 | args := lib.GetAllArgs(&call) 74 | err := rows.Scan(args...) 75 | if err != nil { 76 | return runtime.ToValue(lib.NewError(runtime, err)) 77 | } 78 | return nil 79 | }) 80 | 81 | o.Set("next", func(call goja.FunctionCall) goja.Value { 82 | r := rows.Next() 83 | return runtime.ToValue(r) 84 | }) 85 | 86 | o.Set("close", func(call goja.FunctionCall) goja.Value { 87 | err := rows.Close() 88 | if err != nil { 89 | return runtime.ToValue(lib.NewError(runtime, err)) 90 | } 91 | return nil 92 | }) 93 | return o 94 | } 95 | -------------------------------------------------------------------------------- /lib/db/sql.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | var reUseDb *sql.DB 12 | 13 | func init() { 14 | require.RegisterNativeModule("sql", func(runtime *goja.Runtime, module *goja.Object) { 15 | o := module.Get("exports").(*goja.Object) 16 | o.Set("open", func(call goja.FunctionCall) goja.Value { 17 | driverName := call.Argument(0).String() 18 | dataSourceName := call.Argument(1).String() 19 | reUse := call.Argument(2).ToBoolean() 20 | 21 | if reUse && reUseDb != nil { 22 | return runtime.ToValue(map[string]interface{}{ 23 | "value": NewDB(runtime, reUseDb), 24 | "isReUse": true, 25 | }) 26 | } 27 | db, err := sql.Open(driverName, dataSourceName) 28 | if err != nil { 29 | return lib.MakeErrorValue(runtime, err) 30 | } 31 | if reUse && reUseDb == nil { 32 | reUseDb = db 33 | } 34 | return lib.MakeReturnValue(runtime, NewDB(runtime, db)) 35 | }) 36 | 37 | o.Set("drivers", func(call goja.FunctionCall) goja.Value { 38 | arr := sql.Drivers() 39 | return runtime.ToValue(arr) 40 | }) 41 | 42 | o.Set("newNullString", func(call goja.FunctionCall) goja.Value { 43 | return runtime.ToValue(new(sql.NullString)) 44 | }) 45 | 46 | o.Set("nullStringValue", func(call goja.FunctionCall) goja.Value { 47 | v := call.Argument(0).Export() 48 | if vv, ok := v.(*sql.NullString); ok { 49 | return runtime.ToValue(map[string]interface{}{ 50 | "value": vv.String, 51 | "valid": vv.Valid, 52 | }) 53 | } 54 | panic(runtime.NewTypeError("p0 is not sql.NullString type:%T", v)) 55 | }) 56 | 57 | o.Set("newNullBool", func(call goja.FunctionCall) goja.Value { 58 | return runtime.ToValue(new(sql.NullBool)) 59 | }) 60 | 61 | o.Set("nullBoolValue", func(call goja.FunctionCall) goja.Value { 62 | v := call.Argument(0).Export() 63 | if vv, ok := v.(*sql.NullBool); ok { 64 | return runtime.ToValue(map[string]interface{}{ 65 | "value": vv.Bool, 66 | "valid": vv.Valid, 67 | }) 68 | } 69 | panic(runtime.NewTypeError("p0 is not sql.NullBool type:%T", v)) 70 | }) 71 | 72 | o.Set("newNullFloat64", func(call goja.FunctionCall) goja.Value { 73 | return runtime.ToValue(new(sql.NullFloat64)) 74 | }) 75 | 76 | o.Set("nullFloat64Value", func(call goja.FunctionCall) goja.Value { 77 | v := call.Argument(0).Export() 78 | if vv, ok := v.(*sql.NullFloat64); ok { 79 | return runtime.ToValue(map[string]interface{}{ 80 | "value": vv.Float64, 81 | "valid": vv.Valid, 82 | }) 83 | } 84 | panic(runtime.NewTypeError("p0 is not sql.NullFloat64 type:%T", v)) 85 | }) 86 | 87 | o.Set("newNullInt64", func(call goja.FunctionCall) goja.Value { 88 | return runtime.ToValue(new(sql.NullInt64)) 89 | }) 90 | 91 | o.Set("nullInt64Value", func(call goja.FunctionCall) goja.Value { 92 | v := call.Argument(0).Export() 93 | if vv, ok := v.(*sql.NullInt64); ok { 94 | return runtime.ToValue(map[string]interface{}{ 95 | "value": vv.Int64, 96 | "valid": vv.Valid, 97 | }) 98 | } 99 | panic(runtime.NewTypeError("p0 is not sql.NullInt64 type:%T", v)) 100 | }) 101 | 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /lib/db/stmt.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewStmt(runtime *goja.Runtime, stmt *sql.Stmt) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("exec", func(call goja.FunctionCall) goja.Value { 13 | args := lib.GetAllArgs(&call) 14 | result, err := stmt.Exec(args...) 15 | if err != nil { 16 | return lib.MakeErrorValue(runtime, err) 17 | } 18 | return lib.MakeReturnValue(runtime, NewResult(runtime, result)) 19 | }) 20 | return o 21 | } 22 | -------------------------------------------------------------------------------- /lib/db/tx.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewTx(runtime *goja.Runtime, tx *sql.Tx) *goja.Object { 11 | // todo 12 | o := runtime.NewObject() 13 | o.Set("commit", func(call goja.FunctionCall) goja.Value { 14 | err := tx.Commit() 15 | if err != nil { 16 | return lib.MakeErrorValue(runtime, err) 17 | } 18 | return nil 19 | }) 20 | return o 21 | } 22 | -------------------------------------------------------------------------------- /lib/error.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func NewError(runtime *goja.Runtime, err error) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("error", func(call goja.FunctionCall) goja.Value { 13 | return runtime.ToValue(err.Error()) 14 | }) 15 | 16 | o.Set("nativeType", err) 17 | 18 | return o 19 | } 20 | 21 | func init() { 22 | require.RegisterNativeModule("error", func(runtime *goja.Runtime, module *goja.Object) { 23 | o := module.Get("exports").(*goja.Object) 24 | o.Set("new", func(call goja.FunctionCall) goja.Value { 25 | text := call.Argument(0).String() 26 | err := errors.New(text) 27 | return NewError(runtime, err) 28 | }) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /lib/file.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | 7 | "github.com/dop251/goja" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func NewFile(runtime *goja.Runtime, file *os.File) *goja.Object { 12 | o := runtime.NewObject() 13 | o.Set("writeString", func(call goja.FunctionCall) goja.Value { 14 | s := call.Argument(0).String() 15 | n, err := file.WriteString(s) 16 | if err != nil { 17 | return MakeErrorValue(runtime, err) 18 | } 19 | return MakeReturnValue(runtime, n) 20 | }) 21 | 22 | o.Set("close", func(call goja.FunctionCall) goja.Value { 23 | err := file.Close() 24 | if err != nil { 25 | return MakeErrorValue(runtime, err) 26 | } 27 | return nil 28 | }) 29 | 30 | o.Set("nativeType", file) 31 | 32 | return o 33 | } 34 | 35 | func init() { 36 | require.RegisterNativeModule("file", func(runtime *goja.Runtime, module *goja.Object) { 37 | o := module.Get("exports").(*goja.Object) 38 | o.Set("write", func(call goja.FunctionCall) goja.Value { 39 | filename := call.Argument(0).String() 40 | data := call.Argument(1).Export() 41 | if bts, ok := data.([]byte); ok { 42 | err := ioutil.WriteFile(filename, bts, 0666) 43 | if err != nil { 44 | return MakeErrorValue(runtime, err) 45 | } 46 | return nil 47 | } 48 | panic(runtime.NewTypeError("p1 is not []byte type:%T", data)) 49 | }) 50 | 51 | o.Set("read", func(call goja.FunctionCall) goja.Value { 52 | filename := call.Argument(0).String() 53 | data, err := ioutil.ReadFile(filename) 54 | if err != nil { 55 | return MakeErrorValue(runtime, err) 56 | } 57 | return MakeReturnValue(runtime, data) 58 | }) 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /lib/fmt.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func init() { 11 | require.RegisterNativeModule("fmt", func(runtime *goja.Runtime, module *goja.Object) { 12 | o := module.Get("exports").(*goja.Object) 13 | o.Set("sprintf", func(call goja.FunctionCall) goja.Value { 14 | format := call.Argument(0).String() 15 | args := GetAllArgs(&call) 16 | str := fmt.Sprintf(format, args[1:]...) 17 | return runtime.ToValue(str) 18 | }) 19 | 20 | o.Set("printf", func(call goja.FunctionCall) goja.Value { 21 | format := call.Argument(0).String() 22 | args := GetAllArgs(&call) 23 | n, err := fmt.Printf(format, args[1:]...) 24 | if err != nil { 25 | return MakeErrorValue(runtime, err) 26 | } 27 | return MakeReturnValue(runtime, n) 28 | }) 29 | 30 | o.Set("println", func(call goja.FunctionCall) goja.Value { 31 | args := GetAllArgs(&call) 32 | n, err := fmt.Println(args...) 33 | if err != nil { 34 | return MakeErrorValue(runtime, err) 35 | } 36 | return MakeReturnValue(runtime, n) 37 | }) 38 | 39 | o.Set("print", func(call goja.FunctionCall) goja.Value { 40 | args := GetAllArgs(&call) 41 | n, err := fmt.Print(args...) 42 | if err != nil { 43 | return MakeErrorValue(runtime, err) 44 | } 45 | return MakeReturnValue(runtime, n) 46 | }) 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /lib/image/image.go: -------------------------------------------------------------------------------- 1 | package image 2 | 3 | import ( 4 | "image" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib/image/lib" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func init() { 12 | require.RegisterNativeModule("image", func(runtime *goja.Runtime, module *goja.Object) { 13 | o := module.Get("exports").(*goja.Object) 14 | o.Set("rect", func(call goja.FunctionCall) goja.Value { 15 | x0 := int(call.Argument(0).ToInteger()) 16 | y0 := int(call.Argument(1).ToInteger()) 17 | x1 := int(call.Argument(2).ToInteger()) 18 | y1 := int(call.Argument(3).ToInteger()) 19 | // TODO 20 | rect := image.Rect(x0, y0, x1, y1) 21 | return runtime.ToValue(rect) 22 | }) 23 | 24 | o.Set("newRGBA", func(call goja.FunctionCall) goja.Value { 25 | r := call.Argument(0).Export() 26 | if rect, ok := r.(image.Rectangle); ok { 27 | rgba := image.NewRGBA(rect) 28 | return runtime.ToValue(NewRGBA(runtime, rgba)) 29 | } 30 | panic(runtime.NewTypeError("p0 is not a image.Rectangle type:%T", r)) 31 | }) 32 | 33 | o.Set("makeCapcha", func(call goja.FunctionCall) goja.Value { 34 | rgba := lib.MakeCapcha() 35 | return runtime.ToValue(NewRGBA(runtime, rgba)) 36 | }) 37 | 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /lib/image/lib/img.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "image" 5 | "time" 6 | 7 | "image/color" 8 | "math" 9 | mrand "math/rand" 10 | "unicode/utf8" 11 | ) 12 | 13 | func rand(min, max int) int { 14 | return mrand.Intn(max + 1) 15 | } 16 | 17 | func randColor() color.Color { 18 | return &color.RGBA{ 19 | R: uint8(rand(0, 255)), 20 | G: uint8(rand(0, 255)), 21 | B: uint8(rand(0, 255)), 22 | A: 255, 23 | } 24 | } 25 | 26 | func MakeCapcha() *image.RGBA { 27 | mrand.Seed(time.Now().UnixNano()) 28 | const imgw = 100 29 | const imgh = 40 30 | img := image.NewRGBA(image.Rect(0, 0, imgw, imgh)) 31 | DrawCircle(img, rand(0, 100), rand(0, 40), rand(10, 40), randColor()) 32 | // 边框 33 | DrawRect(img, 0, 0, imgw-1, imgh-1, randColor()) 34 | FillRect(img, rand(0, 100), rand(0, 40), rand(10, 35), rand(10, 35), randColor()) 35 | DrawLine(img, rand(0, 100), rand(0, 40), rand(0, 100), rand(0, 40), randColor()) 36 | // return img; 37 | // 画曲线 38 | var w = float64(imgw / 2) 39 | var h = float64(imgh) 40 | var color = randColor() 41 | var y1 = float64(rand(-5, 5)) 42 | var w2 = float64(rand(10, 15)) 43 | var h3 = float64(rand(4, 6)) 44 | var bl = rand(1, 5) 45 | for i1 := -w; i1 < w; i1 += 0.1 { 46 | var y1 = math.Floor(h/h3*math.Sin(i1/w2) + h/2 + y1) 47 | var x1 = math.Floor(i1 + w) 48 | for j := 0; j < bl; j++ { 49 | img.Set(int(x1), int(y1+float64(j)), color) 50 | } 51 | } 52 | var p = "ABCDEFGHKMNPQRSTUVWXYZ3456789" 53 | var plegn = utf8.RuneCountInString(p) 54 | var str = "" 55 | for i2 := 0; i2 < 5; i2++ { 56 | str += string(charAt(p, mrand.Intn(plegn))) 57 | } 58 | fonts := []*Font{Font8x16, Font12x24, Font16x32} 59 | x := 15 60 | y := 8 61 | arr := []rune(str) 62 | for i := 0; i < len(arr); i++ { 63 | var ch = arr[i] 64 | var f = fonts[mrand.Intn(len(fonts))] 65 | y = 8 + rand(-10, 10) 66 | DrawChar(img, ch, x, y, f, randColor()) 67 | x += f.w + rand(2, 8) 68 | } 69 | return img 70 | } 71 | 72 | type DrawPoint interface { 73 | Set(x, y int, c color.Color) 74 | } 75 | 76 | func charAt(str string, i int) rune { 77 | arr := []rune(str) 78 | return arr[i] 79 | } 80 | 81 | func indexRune(str string, r rune) int { 82 | finded := false 83 | n := -1 84 | for _, v := range str { 85 | n++ 86 | if v == r { 87 | finded = true 88 | break 89 | } 90 | } 91 | if finded { 92 | return n 93 | } 94 | return -1 95 | } 96 | 97 | func DrawLineH(img DrawPoint, x1, x2, y int, color color.Color) { 98 | if x1 > x2 { 99 | var tmp = x2 100 | x2 = x1 101 | x1 = tmp 102 | } 103 | for ; x1 <= x2; x1++ { 104 | img.Set(x1, y, color) 105 | } 106 | } 107 | 108 | func DrawLineV(img DrawPoint, y1, y2, x int, color color.Color) { 109 | if y1 > y2 { 110 | var tmp = y2 111 | y2 = y1 112 | y1 = tmp 113 | } 114 | for ; y1 <= y2; y1++ { 115 | img.Set(x, y1, color) 116 | } 117 | } 118 | 119 | func DrawLine(img DrawPoint, x1, y1, x2, y2 int, color color.Color) { 120 | var x, y, dx, dy, s1, s2, p, temp, i int 121 | var interchange bool 122 | x = x1 123 | y = y1 124 | 125 | if x2 > x1 { 126 | dx = x2 - x1 127 | } else { 128 | dx = x1 - x2 129 | } 130 | if y2 > y1 { 131 | dy = y2 - y1 132 | } else { 133 | dy = y1 - y2 134 | } 135 | if x2 > x1 { 136 | s1 = 1 137 | } else { 138 | s1 = -1 139 | } 140 | if y2 > y1 { 141 | s2 = 1 142 | } else { 143 | s2 = -1 144 | } 145 | if dy > dx { 146 | temp = dx 147 | dx = dy 148 | dy = temp 149 | interchange = true 150 | } else { 151 | interchange = false 152 | } 153 | p = (dy << 1) - dx 154 | for i = 0; i <= dx; i++ { 155 | img.Set(x, y, color) 156 | if p >= 0 { 157 | if interchange { 158 | x = x + s1 159 | } else { 160 | y = y + s2 161 | } 162 | p = p - (dx << 1) 163 | } 164 | if interchange { 165 | y = y + s2 166 | } else { 167 | x = x + s1 168 | } 169 | p = p + (dy << 1) 170 | } 171 | } 172 | 173 | func DrawRect(img DrawPoint, x1, y1, x2, y2 int, color color.Color) { 174 | DrawLineH(img, x1, x2, y1, color) 175 | DrawLineH(img, x1, x2, y2, color) 176 | DrawLineV(img, y1, y2, x1, color) 177 | DrawLineV(img, y1, y2, x2, color) 178 | } 179 | 180 | func FillRect(img DrawPoint, x1, y1, x2, y2 int, color color.Color) { 181 | var x int 182 | if x1 > x2 { 183 | var tmp = x2 184 | x2 = x1 185 | x1 = tmp 186 | } 187 | if y1 > y2 { 188 | var tmp = y2 189 | y2 = y1 190 | y1 = tmp 191 | } 192 | for ; y1 <= y2; y1++ { 193 | for x = x1; x <= x2; x++ { 194 | img.Set(x, y1, color) 195 | } 196 | } 197 | } 198 | 199 | func DrawCircle(img DrawPoint, x, y, r int, color color.Color) { 200 | var a, b, c int 201 | a = 0 202 | b = r 203 | // c = 1.25 - r; 204 | c = 3 - 2*r 205 | for a < b { 206 | img.Set(x+a, y+b, color) 207 | img.Set(x-a, y+b, color) 208 | img.Set(x+a, y-b, color) 209 | img.Set(x-a, y-b, color) 210 | img.Set(x+b, y+a, color) 211 | img.Set(x-b, y+a, color) 212 | img.Set(x+b, y-a, color) 213 | img.Set(x-b, y-a, color) 214 | if c < 0 { 215 | c = c + 4*a + 6 216 | } else { 217 | c = c + 4*(a-b) + 10 218 | b-- 219 | } 220 | a = a + 1 221 | } 222 | if a == b { 223 | img.Set(x+a, y+b, color) 224 | img.Set(x-a, y+b, color) 225 | img.Set(x+a, y-b, color) 226 | img.Set(x-a, y+b, color) 227 | img.Set(x+b, y+a, color) 228 | img.Set(x-b, y+a, color) 229 | img.Set(x+b, y-a, color) 230 | img.Set(x-b, y-a, color) 231 | } 232 | } 233 | 234 | func DrawChar(img DrawPoint, ch rune, x int, y int, font *Font, color color.Color) { 235 | var index = indexRune(font.fonts, ch) 236 | if index < 0 { 237 | return 238 | } 239 | var fontData = font.data[index] 240 | var y0 = y 241 | var x0 = x 242 | for i := 0; i < len(fontData); i++ { 243 | var data = fontData[i] 244 | x0 = x 245 | for b := data; b > 0; b <<= 1 { 246 | if b&0x80 != 0 { 247 | img.Set(x0, y0, color) 248 | } 249 | x0++ 250 | } 251 | y0++ 252 | if (y0 - y) >= font.h { 253 | y0 = y 254 | x += 8 255 | } 256 | } 257 | } 258 | 259 | func DrawString(img DrawPoint, str string, x int, y int, font *Font, color color.Color) { 260 | for _, v := range str { 261 | DrawChar(img, rune(v), x, y, font, color) 262 | x += font.w 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /lib/image/png/png.go: -------------------------------------------------------------------------------- 1 | package png 2 | 3 | import ( 4 | "image" 5 | "image/png" 6 | "io" 7 | 8 | "github.com/dop251/goja" 9 | "github.com/zengming00/go-server-js/lib" 10 | "github.com/zengming00/go-server-js/nodejs/require" 11 | ) 12 | 13 | func init() { 14 | require.RegisterNativeModule("image/png", func(runtime *goja.Runtime, module *goja.Object) { 15 | o := module.Get("exports").(*goja.Object) 16 | o.Set("encode", func(call goja.FunctionCall) goja.Value { 17 | p0 := lib.GetNativeType(runtime, &call, 0) 18 | p1 := lib.GetNativeType(runtime, &call, 1) 19 | 20 | w, ok := p0.(io.Writer) 21 | if !ok { 22 | panic(runtime.NewTypeError("p0 is not io.Writer type:%T", p0)) 23 | } 24 | 25 | m, ok := p1.(image.Image) 26 | if !ok { 27 | panic(runtime.NewTypeError("p1 is not image.Image type:%T", p1)) 28 | } 29 | err := png.Encode(w, m) 30 | if err != nil { 31 | return lib.MakeErrorValue(runtime, err) 32 | } 33 | return nil 34 | }) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /lib/image/rgba.go: -------------------------------------------------------------------------------- 1 | package image 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | 7 | "github.com/dop251/goja" 8 | ) 9 | 10 | type _rgba struct { 11 | runtime *goja.Runtime 12 | rgba *image.RGBA 13 | } 14 | 15 | func (This *_rgba) drawLineH(call goja.FunctionCall) goja.Value { 16 | return nil 17 | } 18 | 19 | func (This *_rgba) drawLineV(call goja.FunctionCall) goja.Value { 20 | return nil 21 | } 22 | 23 | func (This *_rgba) drawLine(call goja.FunctionCall) goja.Value { 24 | return nil 25 | } 26 | 27 | func (This *_rgba) drawRect(call goja.FunctionCall) goja.Value { 28 | return nil 29 | } 30 | 31 | func (This *_rgba) fillRect(call goja.FunctionCall) goja.Value { 32 | return nil 33 | } 34 | 35 | func (This *_rgba) drawCircle(call goja.FunctionCall) goja.Value { 36 | return nil 37 | } 38 | 39 | func (This *_rgba) drawChar(call goja.FunctionCall) goja.Value { 40 | return nil 41 | } 42 | 43 | func (This *_rgba) drawString(call goja.FunctionCall) goja.Value { 44 | return nil 45 | } 46 | 47 | func NewRGBA(runtime *goja.Runtime, rgba *image.RGBA) *goja.Object { 48 | o := runtime.NewObject() 49 | o.Set("nativeType", rgba) 50 | 51 | o.Set("setRGBA", func(call goja.FunctionCall) goja.Value { 52 | x := int(call.Argument(0).ToInteger()) 53 | y := int(call.Argument(1).ToInteger()) 54 | rgba.SetRGBA(x, y, color.RGBA{ 55 | R: uint8(call.Argument(2).ToInteger()), 56 | G: uint8(call.Argument(3).ToInteger()), 57 | B: uint8(call.Argument(4).ToInteger()), 58 | A: uint8(call.Argument(5).ToInteger()), 59 | }) 60 | return nil 61 | }) 62 | return o 63 | } 64 | -------------------------------------------------------------------------------- /lib/io.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func init() { 11 | require.RegisterNativeModule("io", func(runtime *goja.Runtime, module *goja.Object) { 12 | o := module.Get("exports").(*goja.Object) 13 | o.Set("copy", func(call goja.FunctionCall) goja.Value { 14 | p0 := GetNativeType(runtime, &call, 0) 15 | dst, ok := p0.(io.Writer) 16 | if !ok { 17 | panic(runtime.NewTypeError("p0 is not io.Writer type:%T", p0)) 18 | } 19 | 20 | p1 := GetNativeType(runtime, &call, 1) 21 | src, ok := p1.(io.Reader) 22 | if !ok { 23 | panic(runtime.NewTypeError("p1 is not io.Reader type:%T", p1)) 24 | } 25 | 26 | written, err := io.Copy(dst, src) 27 | if err != nil { 28 | return MakeErrorValue(runtime, err) 29 | } 30 | return MakeReturnValue(runtime, written) 31 | }) 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /lib/net/http/cookie.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewCookie(runtime *goja.Runtime, cookie *http.Cookie) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("string", func(call goja.FunctionCall) goja.Value { 13 | return runtime.ToValue(cookie.String()) 14 | }) 15 | o.Set("getDomain", func(call goja.FunctionCall) goja.Value { 16 | return runtime.ToValue(cookie.Domain) 17 | }) 18 | o.Set("getExpires", func(call goja.FunctionCall) goja.Value { 19 | return lib.NewTime(runtime, &cookie.Expires) 20 | }) 21 | o.Set("getHttpOnly", func(call goja.FunctionCall) goja.Value { 22 | return runtime.ToValue(cookie.HttpOnly) 23 | }) 24 | o.Set("getMaxAge", func(call goja.FunctionCall) goja.Value { 25 | return runtime.ToValue(cookie.MaxAge) 26 | }) 27 | o.Set("getName", func(call goja.FunctionCall) goja.Value { 28 | return runtime.ToValue(cookie.Name) 29 | }) 30 | o.Set("getPath", func(call goja.FunctionCall) goja.Value { 31 | return runtime.ToValue(cookie.Path) 32 | }) 33 | o.Set("getRaw", func(call goja.FunctionCall) goja.Value { 34 | return runtime.ToValue(cookie.Raw) 35 | }) 36 | o.Set("getRawExpires", func(call goja.FunctionCall) goja.Value { 37 | return runtime.ToValue(cookie.RawExpires) 38 | }) 39 | o.Set("getSecure", func(call goja.FunctionCall) goja.Value { 40 | return runtime.ToValue(cookie.Secure) 41 | }) 42 | o.Set("getUnparsed", func(call goja.FunctionCall) goja.Value { 43 | return runtime.ToValue(cookie.Unparsed) 44 | }) 45 | o.Set("getValue", func(call goja.FunctionCall) goja.Value { 46 | return runtime.ToValue(cookie.Value) 47 | }) 48 | return o 49 | } 50 | -------------------------------------------------------------------------------- /lib/net/http/header.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | 7 | "github.com/dop251/goja" 8 | ) 9 | 10 | func NewHeader(runtime *goja.Runtime, header http.Header) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("add", func(call goja.FunctionCall) goja.Value { 13 | key := call.Argument(0).String() 14 | value := call.Argument(1).String() 15 | header.Add(key, value) 16 | return nil 17 | }) 18 | 19 | o.Set("del", func(call goja.FunctionCall) goja.Value { 20 | key := call.Argument(0).String() 21 | header.Del(key) 22 | return nil 23 | }) 24 | 25 | o.Set("get", func(call goja.FunctionCall) goja.Value { 26 | key := call.Argument(0).String() 27 | value := header.Get(key) 28 | return runtime.ToValue(value) 29 | }) 30 | 31 | o.Set("gets", func(call goja.FunctionCall) goja.Value { 32 | key := call.Argument(0).String() 33 | value := header[key] 34 | return runtime.ToValue(value) 35 | }) 36 | 37 | o.Set("set", func(call goja.FunctionCall) goja.Value { 38 | key := call.Argument(0).String() 39 | value := call.Argument(1).String() 40 | header.Set(key, value) 41 | return nil 42 | }) 43 | 44 | o.Set("getRaw", func(call goja.FunctionCall) goja.Value { 45 | byteBuf := &bytes.Buffer{} 46 | header.Write(byteBuf) 47 | return runtime.ToValue(byteBuf.Bytes()) 48 | }) 49 | return o 50 | } 51 | -------------------------------------------------------------------------------- /lib/net/http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | "strings" 7 | "time" 8 | 9 | "github.com/dop251/goja" 10 | "github.com/zengming00/go-server-js/nodejs/require" 11 | ) 12 | 13 | func init() { 14 | require.RegisterNativeModule("http", func(runtime *goja.Runtime, module *goja.Object) { 15 | o := module.Get("exports").(*goja.Object) 16 | o.Set("request", func(call goja.FunctionCall) goja.Value { 17 | method := call.Argument(0).String() 18 | url := call.Argument(1).String() 19 | headers := call.Argument(2).Export().(map[string]interface{}) 20 | body := call.Argument(3).String() 21 | timeout := call.Argument(4).ToInteger() 22 | 23 | req, err := http.NewRequest(method, url, strings.NewReader(body)) 24 | if err != nil { 25 | panic(runtime.NewGoError(err)) 26 | } 27 | 28 | for k, v := range headers { 29 | if str, ok := v.(string); ok { 30 | req.Header.Set(k, str) 31 | } else { 32 | panic(runtime.NewTypeError("header[" + k + "] is not string")) 33 | } 34 | } 35 | 36 | client := &http.Client{} 37 | client.Timeout = time.Duration(timeout) * time.Millisecond 38 | res, err := client.Do(req) 39 | if err != nil { 40 | panic(runtime.NewGoError(err)) 41 | } 42 | defer res.Body.Close() 43 | datas, err := ioutil.ReadAll(res.Body) 44 | if err != nil { 45 | panic(runtime.NewGoError(err)) 46 | } 47 | 48 | headerObj := runtime.NewObject() 49 | for k, v := range res.Header { 50 | headerObj.Set(k, v) 51 | } 52 | return runtime.ToValue(map[string]interface{}{ 53 | "body": datas, 54 | "header": headerObj, 55 | }) 56 | }) 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /lib/net/http/multipartFile.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "mime/multipart" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewMultipartFile(runtime *goja.Runtime, file multipart.File) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("nativeType", file) 13 | 14 | o.Set("read", func(call goja.FunctionCall) goja.Value { 15 | p0 := call.Argument(0).Export() 16 | if buf, ok := p0.([]byte); ok { 17 | n, err := file.Read(buf) 18 | if err != nil { 19 | return lib.MakeErrorValue(runtime, err) 20 | } 21 | return lib.MakeReturnValue(runtime, n) 22 | } 23 | panic(runtime.NewTypeError("p0 is not []byte type:%T", p0)) 24 | }) 25 | 26 | o.Set("readAt", func(call goja.FunctionCall) goja.Value { 27 | p0 := call.Argument(0).Export() 28 | off := call.Argument(1).ToInteger() 29 | if buf, ok := p0.([]byte); ok { 30 | n, err := file.ReadAt(buf, off) 31 | if err != nil { 32 | return lib.MakeErrorValue(runtime, err) 33 | } 34 | return lib.MakeReturnValue(runtime, n) 35 | } 36 | panic(runtime.NewTypeError("p0 is not []byte type:%T", p0)) 37 | }) 38 | 39 | o.Set("seek", func(call goja.FunctionCall) goja.Value { 40 | offset := call.Argument(0).ToInteger() 41 | whence := call.Argument(1).ToInteger() 42 | v, err := file.Seek(offset, int(whence)) 43 | if err != nil { 44 | return lib.MakeErrorValue(runtime, err) 45 | } 46 | return lib.MakeReturnValue(runtime, v) 47 | }) 48 | 49 | o.Set("close", func(call goja.FunctionCall) goja.Value { 50 | err := file.Close() 51 | if err != nil { 52 | return runtime.ToValue(lib.NewError(runtime, err)) 53 | } 54 | return nil 55 | }) 56 | 57 | return o 58 | } 59 | -------------------------------------------------------------------------------- /lib/net/http/request.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | 7 | "github.com/dop251/goja" 8 | "github.com/zengming00/go-server-js/lib" 9 | "github.com/zengming00/go-server-js/lib/net/url" 10 | ) 11 | 12 | func NewRequest(runtime *goja.Runtime, r *http.Request) *goja.Object { 13 | o := runtime.NewObject() 14 | 15 | o.Set("isMissingFile", func(call goja.FunctionCall) goja.Value { 16 | p0 := lib.GetNativeType(runtime, &call, 0) 17 | if err, ok := p0.(error); ok { 18 | return runtime.ToValue(err == http.ErrMissingFile) 19 | } 20 | panic(runtime.NewTypeError("p0 is not error type:%T", p0)) 21 | }) 22 | 23 | o.Set("getContentLength", func(call goja.FunctionCall) goja.Value { 24 | return runtime.ToValue(r.ContentLength) 25 | }) 26 | 27 | o.Set("getMethod", func(call goja.FunctionCall) goja.Value { 28 | return runtime.ToValue(r.Method) 29 | }) 30 | 31 | o.Set("getHost", func(call goja.FunctionCall) goja.Value { 32 | return runtime.ToValue(r.Host) 33 | }) 34 | 35 | o.Set("getBody", func(call goja.FunctionCall) goja.Value { 36 | //todo 37 | return runtime.ToValue(r.Body) 38 | }) 39 | 40 | o.Set("getHeader", func(call goja.FunctionCall) goja.Value { 41 | return NewHeader(runtime, r.Header) 42 | }) 43 | 44 | o.Set("getHeaders", func(call goja.FunctionCall) goja.Value { 45 | return runtime.ToValue(map[string][]string(r.Header)) 46 | }) 47 | 48 | o.Set("getUri", func(call goja.FunctionCall) goja.Value { 49 | return runtime.ToValue(r.RequestURI) 50 | }) 51 | 52 | o.Set("getUrl", func(call goja.FunctionCall) goja.Value { 53 | return url.NewURL(runtime, r.URL) 54 | }) 55 | 56 | o.Set("getRemoteAddr", func(call goja.FunctionCall) goja.Value { 57 | return runtime.ToValue(r.RemoteAddr) 58 | }) 59 | 60 | o.Set("getForm", func(call goja.FunctionCall) goja.Value { 61 | return url.NewValues(runtime, r.Form) 62 | }) 63 | 64 | o.Set("formValue", func(call goja.FunctionCall) goja.Value { 65 | key := call.Argument(0).String() 66 | value := r.FormValue(key) 67 | return runtime.ToValue(value) 68 | }) 69 | 70 | o.Set("formFile", func(call goja.FunctionCall) goja.Value { 71 | key := call.Argument(0).String() 72 | file, fileHeader, err := r.FormFile(key) 73 | if err != nil { 74 | return lib.MakeErrorValue(runtime, err) 75 | } 76 | return runtime.ToValue(map[string]interface{}{ 77 | "file": NewMultipartFile(runtime, file), 78 | "name": fileHeader.Filename, 79 | "header": map[string][]string(fileHeader.Header), 80 | }) 81 | }) 82 | 83 | o.Set("userAgent", func(call goja.FunctionCall) goja.Value { 84 | value := r.UserAgent() 85 | return runtime.ToValue(value) 86 | }) 87 | 88 | o.Set("parseForm", func(call goja.FunctionCall) goja.Value { 89 | err := r.ParseForm() 90 | if err != nil { 91 | return lib.MakeErrorValue(runtime, err) 92 | } 93 | return nil 94 | }) 95 | 96 | o.Set("parseMultipartForm", func(call goja.FunctionCall) goja.Value { 97 | maxMemory := call.Argument(0).ToInteger() 98 | err := r.ParseMultipartForm(maxMemory) 99 | if err != nil { 100 | return lib.MakeErrorValue(runtime, err) 101 | } 102 | return nil 103 | }) 104 | 105 | o.Set("cookie", func(call goja.FunctionCall) goja.Value { 106 | name := call.Argument(0).String() 107 | c, err := r.Cookie(name) 108 | if err != nil { 109 | return lib.MakeErrorValue(runtime, err) 110 | } 111 | return lib.MakeReturnValue(runtime, NewCookie(runtime, c)) 112 | }) 113 | 114 | o.Set("cookies", func(call goja.FunctionCall) goja.Value { 115 | cks := r.Cookies() 116 | arr := make([]*goja.Object, len(cks)) 117 | for i, v := range cks { 118 | arr[i] = NewCookie(runtime, v) 119 | } 120 | return runtime.ToValue(arr) 121 | }) 122 | 123 | o.Set("getRawBody", func(call goja.FunctionCall) goja.Value { 124 | bts, err := ioutil.ReadAll(r.Body) 125 | if err != nil { 126 | return lib.MakeErrorValue(runtime, err) 127 | } 128 | return lib.MakeReturnValue(runtime, bts) 129 | }) 130 | 131 | return o 132 | } 133 | -------------------------------------------------------------------------------- /lib/net/http/response.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | ) 9 | 10 | func NewResponse(runtime *goja.Runtime, w http.ResponseWriter) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("header", func(call goja.FunctionCall) goja.Value { 13 | return NewHeader(runtime, w.Header()) 14 | }) 15 | 16 | o.Set("write", func(call goja.FunctionCall) goja.Value { 17 | p0 := call.Argument(0).Export() 18 | 19 | var data []byte 20 | switch t := p0.(type) { 21 | case []interface{}: 22 | data = make([]byte, len(t)) 23 | for i, v := range t { 24 | if val, ok := v.(int64); ok { 25 | if val >= 0 && val <= 255 { 26 | data[i] = byte(val) 27 | continue 28 | } 29 | } 30 | panic(runtime.NewTypeError("can not convert to byte `data[%d]:%T`", i, v)) 31 | } 32 | case []byte: 33 | data = t 34 | case string: 35 | data = []byte(t) 36 | default: 37 | panic(runtime.NewTypeError("data is not a []byte or string type:%T", t)) 38 | } 39 | 40 | n, err := w.Write(data) 41 | if err != nil { 42 | return lib.MakeErrorValue(runtime, err) 43 | } 44 | return lib.MakeReturnValue(runtime, n) 45 | }) 46 | 47 | o.Set("writeHeader", func(call goja.FunctionCall) goja.Value { 48 | n := call.Argument(0).ToInteger() 49 | w.WriteHeader(int(n)) 50 | return nil 51 | }) 52 | 53 | o.Set("setCookie", func(call goja.FunctionCall) goja.Value { 54 | cookie := &http.Cookie{} 55 | cookie.Name = call.Argument(0).String() 56 | cookie.Value = call.Argument(1).String() 57 | cookie.Path = call.Argument(2).String() 58 | cookie.MaxAge = int(call.Argument(3).ToInteger()) 59 | cookie.HttpOnly = call.Argument(4).ToBoolean() 60 | http.SetCookie(w, cookie) 61 | return nil 62 | }) 63 | 64 | o.Set("nativeType", w) 65 | 66 | return o 67 | } 68 | -------------------------------------------------------------------------------- /lib/net/url/url.go: -------------------------------------------------------------------------------- 1 | package url 2 | 3 | import ( 4 | "net/url" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func NewURL(runtime *goja.Runtime, u *url.URL) *goja.Object { 12 | // TODO 13 | o := runtime.NewObject() 14 | o.Set("getForceQuery", func(call goja.FunctionCall) goja.Value { 15 | return runtime.ToValue(u.ForceQuery) 16 | }) 17 | 18 | o.Set("getFragment", func(call goja.FunctionCall) goja.Value { 19 | return runtime.ToValue(u.Fragment) 20 | }) 21 | 22 | o.Set("getHost", func(call goja.FunctionCall) goja.Value { 23 | return runtime.ToValue(u.Host) 24 | }) 25 | 26 | o.Set("getOpaque", func(call goja.FunctionCall) goja.Value { 27 | return runtime.ToValue(u.Opaque) 28 | }) 29 | 30 | o.Set("getPath", func(call goja.FunctionCall) goja.Value { 31 | return runtime.ToValue(u.Path) 32 | }) 33 | 34 | o.Set("getRawPath", func(call goja.FunctionCall) goja.Value { 35 | return runtime.ToValue(u.RawPath) 36 | }) 37 | 38 | o.Set("getRawQuery", func(call goja.FunctionCall) goja.Value { 39 | return runtime.ToValue(u.RawQuery) 40 | }) 41 | 42 | o.Set("getScheme", func(call goja.FunctionCall) goja.Value { 43 | return runtime.ToValue(u.Scheme) 44 | }) 45 | 46 | o.Set("getPort", func(call goja.FunctionCall) goja.Value { 47 | return runtime.ToValue(u.Port()) 48 | }) 49 | 50 | return o 51 | } 52 | 53 | func init() { 54 | require.RegisterNativeModule("url", func(runtime *goja.Runtime, module *goja.Object) { 55 | o := module.Get("exports").(*goja.Object) 56 | o.Set("parse", func(call goja.FunctionCall) goja.Value { 57 | rawurl := call.Argument(0).String() 58 | u, err := url.Parse(rawurl) 59 | if err != nil { 60 | return lib.MakeErrorValue(runtime, err) 61 | } 62 | return lib.MakeReturnValue(runtime, NewURL(runtime, u)) 63 | }) 64 | 65 | o.Set("queryEscape", func(call goja.FunctionCall) goja.Value { 66 | str := url.QueryEscape(call.Argument(0).String()) 67 | return runtime.ToValue(str) 68 | }) 69 | 70 | o.Set("queryUnescape", func(call goja.FunctionCall) goja.Value { 71 | str, err := url.QueryUnescape(call.Argument(0).String()) 72 | if err != nil { 73 | return lib.MakeErrorValue(runtime, err) 74 | } 75 | return lib.MakeReturnValue(runtime, str) 76 | }) 77 | 78 | o.Set("parseRequestURI", func(call goja.FunctionCall) goja.Value { 79 | rawurl := call.Argument(0).String() 80 | mUrl, err := url.ParseRequestURI(rawurl) 81 | if err != nil { 82 | return lib.MakeErrorValue(runtime, err) 83 | } 84 | return lib.MakeReturnValue(runtime, NewURL(runtime, mUrl)) 85 | }) 86 | 87 | o.Set("parseQuery", func(call goja.FunctionCall) goja.Value { 88 | query := call.Argument(0).String() 89 | values, err := url.ParseQuery(query) 90 | if err != nil { 91 | return lib.MakeErrorValue(runtime, err) 92 | } 93 | return lib.MakeReturnValue(runtime, NewValues(runtime, values)) 94 | }) 95 | 96 | o.Set("newValues", func(call goja.FunctionCall) goja.Value { 97 | return NewValues(runtime, make(url.Values)) 98 | }) 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /lib/net/url/values.go: -------------------------------------------------------------------------------- 1 | package url 2 | 3 | import ( 4 | "net/url" 5 | 6 | "github.com/dop251/goja" 7 | ) 8 | 9 | func NewValues(runtime *goja.Runtime, values url.Values) *goja.Object { 10 | o := runtime.NewObject() 11 | o.Set("del", func(call goja.FunctionCall) goja.Value { 12 | key := call.Argument(0).String() 13 | values.Del(key) 14 | return nil 15 | }) 16 | 17 | o.Set("add", func(call goja.FunctionCall) goja.Value { 18 | key := call.Argument(0).String() 19 | value := call.Argument(1).String() 20 | values.Add(key, value) 21 | return nil 22 | }) 23 | 24 | o.Set("encode", func(call goja.FunctionCall) goja.Value { 25 | str := values.Encode() 26 | return runtime.ToValue(str) 27 | }) 28 | 29 | o.Set("get", func(call goja.FunctionCall) goja.Value { 30 | key := call.Argument(0).String() 31 | str := values.Get(key) 32 | return runtime.ToValue(str) 33 | }) 34 | 35 | o.Set("gets", func(call goja.FunctionCall) goja.Value { 36 | key := call.Argument(0).String() 37 | values := values[key] 38 | return runtime.ToValue(values) 39 | }) 40 | 41 | o.Set("getAll", func(call goja.FunctionCall) goja.Value { 42 | return runtime.ToValue(map[string][]string(values)) 43 | }) 44 | 45 | o.Set("set", func(call goja.FunctionCall) goja.Value { 46 | key := call.Argument(0).String() 47 | value := call.Argument(1).String() 48 | values.Set(key, value) 49 | return nil 50 | }) 51 | return o 52 | } 53 | -------------------------------------------------------------------------------- /lib/os.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func init() { 11 | require.RegisterNativeModule("os", func(runtime *goja.Runtime, module *goja.Object) { 12 | o := module.Get("exports").(*goja.Object) 13 | o.Set("O_CREATE", os.O_CREATE) 14 | o.Set("O_WRONLY", os.O_WRONLY) 15 | o.Set("O_RDONLY", os.O_RDONLY) 16 | o.Set("O_RDWR", os.O_RDWR) 17 | o.Set("O_APPEND", os.O_APPEND) 18 | o.Set("O_EXCL", os.O_EXCL) 19 | o.Set("O_SYNC", os.O_SYNC) 20 | o.Set("O_TRUNC", os.O_TRUNC) 21 | 22 | o.Set("args", os.Args) 23 | 24 | o.Set("tempDir", func(call goja.FunctionCall) goja.Value { 25 | value := os.TempDir() 26 | return runtime.ToValue(value) 27 | }) 28 | 29 | o.Set("hostname", func(call goja.FunctionCall) goja.Value { 30 | name, err := os.Hostname() 31 | if err != nil { 32 | return MakeErrorValue(runtime, err) 33 | } 34 | return MakeReturnValue(runtime, name) 35 | }) 36 | 37 | o.Set("getEnv", func(call goja.FunctionCall) goja.Value { 38 | key := call.Argument(0).String() 39 | value := os.Getenv(key) 40 | return runtime.ToValue(value) 41 | }) 42 | 43 | o.Set("remove", func(call goja.FunctionCall) goja.Value { 44 | name := call.Argument(0).String() 45 | err := os.Remove(name) 46 | if err != nil { 47 | return runtime.ToValue(NewError(runtime, err)) 48 | } 49 | return nil 50 | }) 51 | 52 | o.Set("removeAll", func(call goja.FunctionCall) goja.Value { 53 | path := call.Argument(0).String() 54 | err := os.RemoveAll(path) 55 | if err != nil { 56 | return runtime.ToValue(NewError(runtime, err)) 57 | } 58 | return nil 59 | }) 60 | 61 | o.Set("mkdir", func(call goja.FunctionCall) goja.Value { 62 | name := call.Argument(0).String() 63 | perm := call.Argument(1).ToInteger() 64 | err := os.Mkdir(name, os.FileMode(perm)) 65 | if err != nil { 66 | return runtime.ToValue(NewError(runtime, err)) 67 | } 68 | return nil 69 | }) 70 | 71 | o.Set("mkdirAll", func(call goja.FunctionCall) goja.Value { 72 | path := call.Argument(0).String() 73 | perm := call.Argument(1).ToInteger() 74 | err := os.MkdirAll(path, os.FileMode(perm)) 75 | if err != nil { 76 | return runtime.ToValue(NewError(runtime, err)) 77 | } 78 | return nil 79 | }) 80 | 81 | o.Set("getwd", func(call goja.FunctionCall) goja.Value { 82 | dir, err := os.Getwd() 83 | if err != nil { 84 | return MakeErrorValue(runtime, err) 85 | } 86 | return MakeReturnValue(runtime, dir) 87 | }) 88 | 89 | o.Set("chdir", func(call goja.FunctionCall) goja.Value { 90 | dir := call.Argument(0).String() 91 | err := os.Chdir(dir) 92 | if err != nil { 93 | return runtime.ToValue(NewError(runtime, err)) 94 | } 95 | return nil 96 | }) 97 | 98 | o.Set("openFile", func(call goja.FunctionCall) goja.Value { 99 | name := call.Argument(0).String() 100 | flag := call.Argument(1).ToInteger() 101 | perm := call.Argument(2).ToInteger() 102 | 103 | file, err := os.OpenFile(name, int(flag), os.FileMode(perm)) 104 | if err != nil { 105 | return MakeErrorValue(runtime, err) 106 | } 107 | return MakeReturnValue(runtime, NewFile(runtime, file)) 108 | }) 109 | 110 | o.Set("create", func(call goja.FunctionCall) goja.Value { 111 | name := call.Argument(0).String() 112 | file, err := os.Create(name) 113 | if err != nil { 114 | return MakeErrorValue(runtime, err) 115 | } 116 | return MakeReturnValue(runtime, NewFile(runtime, file)) 117 | }) 118 | 119 | o.Set("open", func(call goja.FunctionCall) goja.Value { 120 | name := call.Argument(0).String() 121 | file, err := os.Open(name) 122 | if err != nil { 123 | return MakeErrorValue(runtime, err) 124 | } 125 | return MakeReturnValue(runtime, NewFile(runtime, file)) 126 | }) 127 | 128 | o.Set("stat", func(call goja.FunctionCall) goja.Value { 129 | name := call.Argument(0).String() 130 | fileInfo, err := os.Stat(name) 131 | if err != nil { 132 | return MakeErrorValue(runtime, err) 133 | } 134 | // todo 135 | return MakeReturnValue(runtime, fileInfo) 136 | }) 137 | 138 | o.Set("isExist", func(call goja.FunctionCall) goja.Value { 139 | p0 := GetNativeType(runtime, &call, 0) 140 | if err, ok := p0.(error); ok { 141 | return runtime.ToValue(os.IsExist(err)) 142 | } 143 | panic(runtime.NewTypeError("p0 is not error type:%T", p0)) 144 | }) 145 | 146 | o.Set("isNotExist", func(call goja.FunctionCall) goja.Value { 147 | p0 := GetNativeType(runtime, &call, 0) 148 | if err, ok := p0.(error); ok { 149 | return runtime.ToValue(os.IsNotExist(err)) 150 | } 151 | panic(runtime.NewTypeError("p0 is not error type:%T", p0)) 152 | }) 153 | }) 154 | } 155 | -------------------------------------------------------------------------------- /lib/path/filepath.go: -------------------------------------------------------------------------------- 1 | package path 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/lib" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func init() { 12 | require.RegisterNativeModule("path/filepath", func(runtime *goja.Runtime, module *goja.Object) { 13 | o := module.Get("exports").(*goja.Object) 14 | o.Set("abs", func(call goja.FunctionCall) goja.Value { 15 | path := call.Argument(0).String() 16 | str, err := filepath.Abs(path) 17 | if err != nil { 18 | return lib.MakeErrorValue(runtime, err) 19 | } 20 | return lib.MakeReturnValue(runtime, str) 21 | }) 22 | 23 | o.Set("join", func(call goja.FunctionCall) goja.Value { 24 | arr := lib.GetAllArgs_string(runtime, &call) 25 | str := filepath.Join(arr...) 26 | return runtime.ToValue(str) 27 | }) 28 | 29 | o.Set("ext", func(call goja.FunctionCall) goja.Value { 30 | path := call.Argument(0).String() 31 | str := filepath.Ext(path) 32 | return runtime.ToValue(str) 33 | }) 34 | 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /lib/strings.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func init() { 11 | require.RegisterNativeModule("strings", func(runtime *goja.Runtime, module *goja.Object) { 12 | o := module.Get("exports").(*goja.Object) 13 | o.Set("hasPrefix", func(call goja.FunctionCall) goja.Value { 14 | s := call.Argument(0).String() 15 | prefix := call.Argument(1).String() 16 | return runtime.ToValue(strings.HasPrefix(s, prefix)) 17 | }) 18 | 19 | o.Set("hasSuffix", func(call goja.FunctionCall) goja.Value { 20 | s := call.Argument(0).String() 21 | suffix := call.Argument(1).String() 22 | return runtime.ToValue(strings.HasSuffix(s, suffix)) 23 | }) 24 | 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /lib/time.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func NewTime(runtime *goja.Runtime, t *time.Time) *goja.Object { 11 | o := runtime.NewObject() 12 | o.Set("string", func(call goja.FunctionCall) goja.Value { 13 | str := t.String() 14 | return runtime.ToValue(str) 15 | }) 16 | 17 | return o 18 | } 19 | 20 | func init() { 21 | require.RegisterNativeModule("time", func(runtime *goja.Runtime, module *goja.Object) { 22 | o := module.Get("exports").(*goja.Object) 23 | o.Set("sleep", func(call goja.FunctionCall) goja.Value { 24 | d := call.Argument(0).ToInteger() 25 | <-time.After(time.Duration(d) * time.Millisecond) 26 | return nil 27 | }) 28 | 29 | o.Set("nowString", func(call goja.FunctionCall) goja.Value { 30 | const DATE_TIME_FORMAT = "2006-01-02 15:04:05" 31 | cst := time.FixedZone("CST", 28800) 32 | str := time.Now().In(cst).Format(DATE_TIME_FORMAT) 33 | return runtime.ToValue(str) 34 | }) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /lib/types.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/dop251/goja" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func init() { 12 | require.RegisterNativeModule("types", func(runtime *goja.Runtime, module *goja.Object) { 13 | o := module.Get("exports").(*goja.Object) 14 | 15 | o.Set("newInt", func(call goja.FunctionCall) goja.Value { 16 | return runtime.ToValue(new(int)) 17 | }) 18 | 19 | o.Set("intValue", func(call goja.FunctionCall) goja.Value { 20 | v := call.Argument(0).Export() 21 | if vv, ok := v.(*int); ok { 22 | return runtime.ToValue(*vv) 23 | } 24 | panic(runtime.NewTypeError("p0 is not int type:%T", v)) 25 | }) 26 | 27 | o.Set("newBool", func(call goja.FunctionCall) goja.Value { 28 | return runtime.ToValue(new(bool)) 29 | }) 30 | 31 | o.Set("boolValue", func(call goja.FunctionCall) goja.Value { 32 | v := call.Argument(0).Export() 33 | if vv, ok := v.(*bool); ok { 34 | return runtime.ToValue(*vv) 35 | } 36 | panic(runtime.NewTypeError("p0 is not bool type:%T", v)) 37 | }) 38 | 39 | o.Set("newString", func(call goja.FunctionCall) goja.Value { 40 | return runtime.ToValue(new(string)) 41 | }) 42 | 43 | o.Set("stringValue", func(call goja.FunctionCall) goja.Value { 44 | v := call.Argument(0).Export() 45 | if vv, ok := v.(*string); ok { 46 | return runtime.ToValue(*vv) 47 | } 48 | panic(runtime.NewTypeError("p0 is not string type:%T", v)) 49 | }) 50 | 51 | o.Set("makeByteSlice", func(call goja.FunctionCall) goja.Value { 52 | mLen := call.Argument(0).ToInteger() 53 | mCap := mLen 54 | if len(call.Arguments) != 1 { 55 | mCap = call.Argument(1).ToInteger() 56 | } 57 | v := make([]byte, mLen, mCap) 58 | return runtime.ToValue(v) 59 | }) 60 | 61 | o.Set("test", func(call goja.FunctionCall) goja.Value { 62 | v := call.Argument(0).Export() 63 | fmt.Printf("%T %[1]v\n", v) 64 | return nil 65 | }) 66 | 67 | o.Set("err", func(call goja.FunctionCall) goja.Value { 68 | return MakeErrorValue(runtime, errors.New("terr")) 69 | }) 70 | 71 | o.Set("retNil", func(call goja.FunctionCall) goja.Value { 72 | // nil 和 goja.Undefined() 效果相同,在js中都是undefined 73 | return nil 74 | }) 75 | 76 | o.Set("retUndefined", func(call goja.FunctionCall) goja.Value { 77 | return goja.Undefined() 78 | }) 79 | 80 | o.Set("retNull", func(call goja.FunctionCall) goja.Value { 81 | // 在js中是null 82 | return goja.Null() 83 | }) 84 | 85 | }) 86 | } 87 | -------------------------------------------------------------------------------- /lib/utils.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/sha1" 6 | "encoding/base64" 7 | "encoding/hex" 8 | "fmt" 9 | 10 | "github.com/dop251/goja" 11 | "github.com/zengming00/go-server-js/nodejs/require" 12 | ) 13 | 14 | func GetNativeType(runtime *goja.Runtime, call *goja.FunctionCall, idx int) interface{} { 15 | return call.Argument(idx).ToObject(runtime).Get("nativeType").Export() 16 | } 17 | 18 | func GetGoType(runtime *goja.Runtime, call *goja.FunctionCall, idx int) goja.Value { 19 | p := call.Argument(idx).ToObject(runtime) 20 | protoFunc, ok := goja.AssertFunction(p.Get("getGoType")) 21 | if !ok { 22 | panic(runtime.NewTypeError("p%d not have getGoType() function", idx)) 23 | } 24 | obj, err := protoFunc(p) 25 | if err != nil { 26 | panic(runtime.NewGoError(err)) 27 | } 28 | return obj 29 | } 30 | 31 | func GetAllArgs(call *goja.FunctionCall) []interface{} { 32 | args := make([]interface{}, len(call.Arguments)) 33 | for i, v := range call.Arguments { 34 | args[i] = v.Export() 35 | } 36 | return args 37 | } 38 | 39 | func GetAllArgs_string(runtime *goja.Runtime, call *goja.FunctionCall) []string { 40 | args := make([]string, len(call.Arguments)) 41 | for i, v := range call.Arguments { 42 | vv := v.Export() 43 | if s, ok := vv.(string); ok { 44 | args[i] = s 45 | } else { 46 | panic(runtime.NewTypeError("arg[%d] is not a string type:%T", i, v)) 47 | } 48 | } 49 | return args 50 | } 51 | 52 | func MakeReturnValue(runtime *goja.Runtime, value interface{}) goja.Value { 53 | return runtime.ToValue(map[string]interface{}{ 54 | "value": value, 55 | }) 56 | } 57 | 58 | func MakeErrorValue(runtime *goja.Runtime, err error) goja.Value { 59 | return runtime.ToValue(map[string]interface{}{ 60 | "err": NewError(runtime, err), 61 | }) 62 | } 63 | 64 | func init() { 65 | require.RegisterNativeModule("utils", func(runtime *goja.Runtime, module *goja.Object) { 66 | o := module.Get("exports").(*goja.Object) 67 | o.Set("print", func(call goja.FunctionCall) goja.Value { 68 | fmt.Print(call.Argument(0).String()) 69 | return nil 70 | }) 71 | 72 | o.Set("panic", func(call goja.FunctionCall) goja.Value { 73 | panic(call.Argument(0).String()) 74 | }) 75 | 76 | o.Set("toString", func(call goja.FunctionCall) goja.Value { 77 | data := call.Argument(0).Export() 78 | if bts, ok := data.([]byte); ok { 79 | return runtime.ToValue(string(bts)) 80 | } 81 | panic(runtime.NewTypeError("p0 is not []byte type:%T", data)) 82 | }) 83 | 84 | o.Set("toBase64", func(call goja.FunctionCall) goja.Value { 85 | p0 := call.Argument(0).Export() 86 | var str string 87 | switch data := p0.(type) { 88 | case []byte: 89 | str = base64.StdEncoding.EncodeToString(data) 90 | case string: 91 | str = base64.StdEncoding.EncodeToString([]byte(data)) 92 | default: 93 | panic(runtime.NewTypeError("p0 is not []byte or string type:%T", p0)) 94 | } 95 | return runtime.ToValue(str) 96 | }) 97 | 98 | o.Set("md5", func(call goja.FunctionCall) goja.Value { 99 | p0 := call.Argument(0).Export() 100 | var r []byte 101 | switch data := p0.(type) { 102 | case []byte: 103 | tmp := md5.Sum(data) 104 | r = tmp[:] 105 | case string: 106 | tmp := md5.Sum([]byte(data)) 107 | r = tmp[:] 108 | default: 109 | panic(runtime.NewTypeError("p0 is not []byte or string type:%T", p0)) 110 | } 111 | return runtime.ToValue(hex.EncodeToString(r)) 112 | }) 113 | 114 | o.Set("sha1", func(call goja.FunctionCall) goja.Value { 115 | p0 := call.Argument(0).Export() 116 | var r []byte 117 | switch data := p0.(type) { 118 | case []byte: 119 | tmp := sha1.Sum(data) 120 | r = tmp[:] 121 | case string: 122 | tmp := sha1.Sum([]byte(data)) 123 | r = tmp[:] 124 | default: 125 | panic(runtime.NewTypeError("p0 is not []byte or string type:%T", p0)) 126 | } 127 | return runtime.ToValue(hex.EncodeToString(r)) 128 | }) 129 | }) 130 | } 131 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "math/rand" 10 | "net/http" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "time" 15 | 16 | _ "github.com/zengming00/go-server-js/lib" 17 | _ "github.com/zengming00/go-server-js/lib/db" 18 | _ "github.com/zengming00/go-server-js/lib/db/redis" 19 | _ "github.com/zengming00/go-server-js/lib/image" 20 | _ "github.com/zengming00/go-server-js/lib/image/png" 21 | mhttp "github.com/zengming00/go-server-js/lib/net/http" 22 | _ "github.com/zengming00/go-server-js/lib/net/url" 23 | _ "github.com/zengming00/go-server-js/lib/path" 24 | 25 | _ "net/http/pprof" 26 | 27 | "github.com/dop251/goja" 28 | _ "github.com/go-sql-driver/mysql" 29 | "github.com/zengming00/go-server-js/nodejs/console" 30 | "github.com/zengming00/go-server-js/nodejs/require" 31 | ) 32 | 33 | var configFile = flag.String("config", "config.json", "set the config.json") 34 | 35 | var _cwd string 36 | var _sessionMgr *SessionMgr 37 | var _cacheMgr *CacheMgr 38 | 39 | type _server struct { 40 | config *config 41 | writeResultValue bool 42 | } 43 | 44 | type config struct { 45 | IndexFile string 46 | Port string 47 | WorkDir *string 48 | SessionMaxLifeTimeSec int64 49 | CacheGcIntervalSec int64 50 | ScriptTimeoutSec int 51 | } 52 | 53 | func (This *_server) handler(w http.ResponseWriter, r *http.Request) { 54 | u := r.URL 55 | file := u.Path 56 | if file == "/" { 57 | file = This.config.IndexFile 58 | } 59 | file = filepath.Join(_cwd, file) 60 | 61 | if strings.HasPrefix(file, _cwd) { 62 | ext := filepath.Ext(file) 63 | if ext == ".js" { 64 | runtime := goja.New() 65 | registry := new(require.Registry) 66 | runtime.Set("response", mhttp.NewResponse(runtime, w)) 67 | runtime.Set("request", mhttp.NewRequest(runtime, r)) 68 | runtime.Set("cache", NewCache(runtime, _cacheMgr)) 69 | runtime.Set("session", NewSession(runtime, _sessionMgr, w, r)) 70 | 71 | normalEndCh := make(chan bool) 72 | 73 | go func() { 74 | ret, err := runFile(file, runtime, registry) 75 | if err != nil { 76 | switch err := err.(type) { 77 | case *goja.Exception: 78 | w.WriteHeader(http.StatusInternalServerError) 79 | fmt.Println("*goja.Exception:", err.String()) 80 | if v := err.Value().ToObject(runtime).Get("nativeType"); v != nil { 81 | fmt.Printf("%T:%[1]v\n", v.Export()) 82 | } 83 | case *goja.InterruptedError: 84 | fmt.Println("*goja.InterruptedError:", err.String()) 85 | default: 86 | fmt.Println("default err:", err) 87 | } 88 | normalEndCh <- false 89 | return 90 | } 91 | 92 | // if goja.IsNull(*ret) || goja.IsUndefined(*ret) { 93 | // w.WriteHeader(http.StatusOK) 94 | // return 95 | // } 96 | if This.writeResultValue { 97 | // w.Header().Set("Content-Type", "text/html; charset=utf-8") 98 | w.Write([]byte((ret).String())) 99 | } 100 | normalEndCh <- true 101 | }() 102 | 103 | if This.config.ScriptTimeoutSec > 0 { 104 | timeoutCh := time.After(time.Duration(This.config.ScriptTimeoutSec) * time.Second) 105 | select { 106 | case <-timeoutCh: 107 | runtime.Interrupt("run code timeout, halt") 108 | w.WriteHeader(http.StatusInternalServerError) 109 | case <-normalEndCh: 110 | } 111 | } else { 112 | <-normalEndCh 113 | } 114 | return 115 | } 116 | } 117 | w.WriteHeader(http.StatusNotFound) 118 | } 119 | 120 | func server() { 121 | var err error 122 | s := &_server{ 123 | config: &config{ 124 | IndexFile: "/index.js", 125 | Port: "8080", 126 | SessionMaxLifeTimeSec: 60 * 15, 127 | CacheGcIntervalSec: 60, 128 | ScriptTimeoutSec: -1, 129 | }, 130 | } 131 | 132 | initConfig(*configFile, s.config) 133 | 134 | if s.config.WorkDir != nil { 135 | err := os.Chdir(*s.config.WorkDir) 136 | if err != nil { 137 | panic(err) 138 | } 139 | } 140 | 141 | _cwd, err = os.Getwd() 142 | if err != nil { 143 | panic(err) 144 | } 145 | 146 | _sessionMgr = NewSessionMgr("sid", s.config.SessionMaxLifeTimeSec) 147 | log.Printf("SessionMaxLifeTimeSec: %d\r\n", s.config.SessionMaxLifeTimeSec) 148 | 149 | _cacheMgr = NewCacheMgr(s.config.CacheGcIntervalSec) 150 | log.Printf("CacheGcIntervalSec: %d\r\n", s.config.CacheGcIntervalSec) 151 | log.Printf("ScriptTimeoutSec: %d\r\n", s.config.ScriptTimeoutSec) 152 | 153 | http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("./public")))) 154 | // http.Handle("/public", s.fileServer) 155 | http.HandleFunc("/", s.handler) 156 | 157 | log.Println("server running on " + s.config.Port) 158 | err = http.ListenAndServe(":"+s.config.Port, nil) 159 | if err != nil { 160 | panic(err) 161 | } 162 | } 163 | 164 | func main() { 165 | flag.Parse() 166 | // debug.SetGCPercent(1) 167 | rand.Seed(time.Now().UnixNano()) 168 | 169 | if len(os.Args) == 2 { 170 | filename := os.Args[1] 171 | start := time.Now() 172 | 173 | registry := new(require.Registry) 174 | runtime := goja.New() 175 | r, err := runFile(filename, runtime, registry) 176 | if err != nil { 177 | switch err := err.(type) { 178 | case *goja.Exception: 179 | fmt.Println("*goja.Exception:", err.String()) 180 | case *goja.InterruptedError: 181 | fmt.Println("*goja.InterruptedError:", err.String()) 182 | default: 183 | fmt.Println("default:", err) 184 | } 185 | os.Exit(64) 186 | } 187 | fmt.Println("result:", r) 188 | fmt.Printf("done (%s)", time.Since(start)) 189 | return 190 | } 191 | server() 192 | } 193 | 194 | func runFile(filename string, runtime *goja.Runtime, registry *require.Registry) (goja.Value, error) { 195 | src, err := ioutil.ReadFile(filename) 196 | if err != nil { 197 | return nil, err 198 | } 199 | registry.Enable(runtime) 200 | console.Enable(runtime) 201 | 202 | // (function(){ ... })() 用来允许直接在文件顶层return 203 | prg, err := goja.Compile(filename, "(function(){"+string(src)+"\n})()", false) 204 | if err != nil { 205 | return nil, err 206 | } 207 | 208 | result, err := runtime.RunProgram(prg) 209 | if err != nil { 210 | return nil, err 211 | } 212 | return result, nil 213 | } 214 | 215 | func initConfig(path string, v interface{}) { 216 | _, err := os.Stat(path) 217 | if err != nil { 218 | if os.IsNotExist(err) { 219 | bts, err := json.MarshalIndent(v, "", " ") 220 | if err != nil { 221 | panic(err) 222 | } 223 | err = ioutil.WriteFile(path, bts, 0666) 224 | if err != nil { 225 | panic(err) 226 | } 227 | return 228 | } 229 | panic(err) 230 | } 231 | file, err := os.Open(path) 232 | if err != nil { 233 | panic(err) 234 | } 235 | defer file.Close() 236 | dec := json.NewDecoder(file) 237 | err = dec.Decode(v) 238 | if err != nil { 239 | panic(err) 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /nodejs/console/module.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | _ "github.com/zengming00/go-server-js/nodejs/util" 9 | ) 10 | 11 | type Console struct { 12 | runtime *goja.Runtime 13 | util *goja.Object 14 | } 15 | 16 | func (c *Console) log(call goja.FunctionCall) goja.Value { 17 | if format, ok := goja.AssertFunction(c.util.Get("format")); ok { 18 | ret, err := format(c.util, call.Arguments...) 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | log.Print(ret.String()) 24 | } else { 25 | panic(c.runtime.NewTypeError("util.format is not a function")) 26 | } 27 | 28 | return nil 29 | } 30 | 31 | func Require(runtime *goja.Runtime, module *goja.Object) { 32 | c := &Console{ 33 | runtime: runtime, 34 | } 35 | 36 | c.util = require.Require(runtime, "util").(*goja.Object) 37 | 38 | o := module.Get("exports").(*goja.Object) 39 | o.Set("log", c.log) 40 | o.Set("error", c.log) 41 | o.Set("warn", c.log) 42 | 43 | } 44 | 45 | func Enable(runtime *goja.Runtime) { 46 | runtime.Set("console", require.Require(runtime, "console")) 47 | } 48 | 49 | func init() { 50 | require.RegisterNativeModule("console", Require) 51 | } 52 | -------------------------------------------------------------------------------- /nodejs/console/module_test.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/dop251/goja" 7 | "github.com/zengming00/go-server-js/nodejs/require" 8 | ) 9 | 10 | func TestConsole(t *testing.T) { 11 | vm := goja.New() 12 | 13 | new(require.Registry).Enable(vm) 14 | Enable(vm) 15 | 16 | if c := vm.Get("console"); c == nil { 17 | t.Fatal("console not found") 18 | } 19 | 20 | if _, err := vm.RunString("console.log('')"); err != nil { 21 | t.Fatal("console.log() error", err) 22 | } 23 | 24 | if _, err := vm.RunString("console.error('')"); err != nil { 25 | t.Fatal("console.error() error", err) 26 | } 27 | 28 | if _, err := vm.RunString("console.warn('')"); err != nil { 29 | t.Fatal("console.warn() error", err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nodejs/eventloop/eventloop.go: -------------------------------------------------------------------------------- 1 | package eventloop 2 | 3 | import ( 4 | "github.com/dop251/goja" 5 | "github.com/zengming00/go-server-js/nodejs/console" 6 | "github.com/zengming00/go-server-js/nodejs/require" 7 | "time" 8 | ) 9 | 10 | type job struct { 11 | goja.Callable 12 | args []goja.Value 13 | cancelled bool 14 | } 15 | 16 | type timer struct { 17 | job 18 | timer *time.Timer 19 | } 20 | 21 | type interval struct { 22 | job 23 | ticker *time.Ticker 24 | stopChan chan int 25 | } 26 | 27 | type EventLoop struct { 28 | vm *goja.Runtime 29 | jobChan chan func() 30 | jobCount int32 31 | running bool 32 | } 33 | 34 | func NewEventLoop() *EventLoop { 35 | vm := goja.New() 36 | 37 | loop := &EventLoop{ 38 | vm: vm, 39 | jobChan: make(chan func()), 40 | } 41 | 42 | new(require.Registry).Enable(vm) 43 | console.Enable(vm) 44 | vm.Set("setTimeout", loop.setTimeout) 45 | vm.Set("setInterval", loop.setInterval) 46 | vm.Set("clearTimeout", loop.clearTimeout) 47 | vm.Set("clearInterval", loop.clearInterval) 48 | 49 | return loop 50 | } 51 | 52 | func (loop *EventLoop) schedule(call goja.FunctionCall, repeating bool) goja.Value { 53 | if fn, ok := goja.AssertFunction(call.Argument(0)); ok { 54 | delay := call.Argument(1).ToInteger() 55 | var args []goja.Value 56 | if len(call.Arguments) > 2 { 57 | args = call.Arguments[2:] 58 | } 59 | if repeating { 60 | return loop.vm.ToValue(loop.addInterval(fn, time.Duration(delay)*time.Millisecond, args)) 61 | } else { 62 | return loop.vm.ToValue(loop.addTimeout(fn, time.Duration(delay)*time.Millisecond, args)) 63 | } 64 | } 65 | return nil 66 | } 67 | 68 | func (loop *EventLoop) setTimeout(call goja.FunctionCall) goja.Value { 69 | return loop.schedule(call, false) 70 | } 71 | 72 | func (loop *EventLoop) setInterval(call goja.FunctionCall) goja.Value { 73 | return loop.schedule(call, true) 74 | } 75 | 76 | // Run calls the specified function, starts the event loop and waits until there are no more delayed jobs to run 77 | // after which it stops the loop and returns. 78 | // The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside 79 | // of the function. 80 | func (loop *EventLoop) Run(fn func(*goja.Runtime)) { 81 | fn(loop.vm) 82 | loop.run(false) 83 | } 84 | 85 | // Start the event loop in the background. The loop continues to run until Stop() is called. 86 | func (loop *EventLoop) Start() { 87 | go loop.run(true) 88 | } 89 | 90 | // Stop the loop that was started with Start(). After this function returns there will be no more jobs executed 91 | // by the loop. It is possible to call Start() or Run() again after this to resume the execution. 92 | func (loop *EventLoop) Stop() { 93 | ch := make(chan int) 94 | 95 | loop.jobChan <- func() { 96 | loop.running = false 97 | ch <- 1 98 | } 99 | 100 | <-ch 101 | } 102 | 103 | // RunOnLoop schedules to run the specified function in the context of the loop as soon as possible. 104 | // The order of the runs is preserved (i.e. the functions will be called in the same order as calls to RunOnLoop()) 105 | // The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside 106 | // of the function. 107 | func (loop *EventLoop) RunOnLoop(fn func(*goja.Runtime)) { 108 | loop.jobChan <- func() { 109 | fn(loop.vm) 110 | } 111 | } 112 | 113 | func (loop *EventLoop) run(inBackground bool) { 114 | loop.running = true 115 | for job := range loop.jobChan { 116 | job() 117 | if !loop.running || !inBackground && loop.jobCount <= 0 { 118 | break 119 | } 120 | } 121 | } 122 | 123 | func (loop *EventLoop) addTimeout(f goja.Callable, timeout time.Duration, args []goja.Value) *timer { 124 | t := &timer{ 125 | job: job{Callable: f, args: args}, 126 | } 127 | 128 | t.timer = time.AfterFunc(timeout, func() { 129 | loop.jobChan <- func() { 130 | loop.doTimeout(t) 131 | } 132 | }) 133 | 134 | loop.jobCount++ 135 | return t 136 | } 137 | 138 | func (loop *EventLoop) addInterval(f goja.Callable, timeout time.Duration, args []goja.Value) *interval { 139 | i := &interval{ 140 | job: job{Callable: f, args: args}, 141 | ticker: time.NewTicker(timeout), 142 | stopChan: make(chan int), 143 | } 144 | 145 | go i.run(loop) 146 | loop.jobCount++ 147 | return i 148 | } 149 | 150 | func (loop *EventLoop) doTimeout(t *timer) { 151 | if !t.cancelled { 152 | t.Callable(nil, t.args...) 153 | t.cancelled = true 154 | loop.jobCount-- 155 | } 156 | } 157 | 158 | func (loop *EventLoop) doInterval(i *interval) { 159 | if !i.cancelled { 160 | i.Callable(nil, i.args...) 161 | } 162 | } 163 | 164 | func (loop *EventLoop) clearTimeout(t *timer) { 165 | if !t.cancelled { 166 | t.timer.Stop() 167 | t.cancelled = true 168 | loop.jobCount-- 169 | } 170 | } 171 | 172 | func (loop *EventLoop) clearInterval(i *interval) { 173 | if !i.cancelled { 174 | i.cancelled = true 175 | i.stopChan <- 1 176 | loop.jobCount-- 177 | } 178 | } 179 | 180 | func (i *interval) run(loop *EventLoop) { 181 | for { 182 | select { 183 | case <-i.stopChan: 184 | i.ticker.Stop() 185 | break 186 | case <-i.ticker.C: 187 | loop.jobChan <- func() { 188 | loop.doInterval(i) 189 | } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /nodejs/eventloop/eventloop_test.go: -------------------------------------------------------------------------------- 1 | package eventloop 2 | 3 | import ( 4 | "github.com/dop251/goja" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestRun(t *testing.T) { 10 | const SCRIPT = ` 11 | setTimeout(function() { 12 | console.log("ok"); 13 | }, 1000); 14 | console.log("Started"); 15 | ` 16 | 17 | loop := NewEventLoop() 18 | prg, err := goja.Compile("main.js", SCRIPT, false) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | loop.Run(func(vm *goja.Runtime) { 23 | vm.RunProgram(prg) 24 | }) 25 | } 26 | 27 | func TestStart(t *testing.T) { 28 | const SCRIPT = ` 29 | setTimeout(function() { 30 | console.log("ok"); 31 | }, 1000); 32 | console.log("Started"); 33 | ` 34 | 35 | prg, err := goja.Compile("main.js", SCRIPT, false) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | 40 | loop := NewEventLoop() 41 | loop.Start() 42 | 43 | loop.RunOnLoop(func(vm *goja.Runtime) { 44 | vm.RunProgram(prg) 45 | }) 46 | 47 | time.Sleep(2 * time.Second) 48 | loop.Stop() 49 | } 50 | 51 | func TestInterval(t *testing.T) { 52 | const SCRIPT = ` 53 | var count = 0; 54 | var t = setInterval(function() { 55 | console.log("tick"); 56 | if (++count > 2) { 57 | clearInterval(t); 58 | } 59 | }, 1000); 60 | console.log("Started"); 61 | ` 62 | 63 | loop := NewEventLoop() 64 | prg, err := goja.Compile("main.js", SCRIPT, false) 65 | if err != nil { 66 | t.Fatal(err) 67 | } 68 | loop.Run(func(vm *goja.Runtime) { 69 | vm.RunProgram(prg) 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /nodejs/require/module.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | import ( 4 | js "github.com/dop251/goja" 5 | 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "path/filepath" 10 | "sync" 11 | ) 12 | 13 | type ModuleLoader func(*js.Runtime, *js.Object) 14 | type SourceLoader func(path string) ([]byte, error) 15 | 16 | var ( 17 | InvalidModuleError = errors.New("Invalid module") 18 | IllegalModuleNameError = errors.New("Illegal module name") 19 | ) 20 | 21 | var native map[string]ModuleLoader 22 | 23 | // Registry contains a cache of compiled modules which can be used by multiple Runtimes 24 | type Registry struct { 25 | sync.Mutex 26 | compiled map[string]*js.Program 27 | 28 | srcLoader SourceLoader 29 | } 30 | 31 | type RequireModule struct { 32 | r *Registry 33 | runtime *js.Runtime 34 | modules map[string]*js.Object 35 | } 36 | 37 | func NewRegistryWithLoader(srcLoader SourceLoader) *Registry { 38 | return &Registry{ 39 | srcLoader: srcLoader, 40 | } 41 | } 42 | 43 | // Enable adds the require() function to the specified runtime. 44 | func (r *Registry) Enable(runtime *js.Runtime) *RequireModule { 45 | rrt := &RequireModule{ 46 | r: r, 47 | runtime: runtime, 48 | modules: make(map[string]*js.Object), 49 | } 50 | 51 | runtime.Set("require", rrt.require) 52 | runtime.Set("require_list", rrt.list) 53 | runtime.Set("require_set", rrt.set) 54 | runtime.Set("require_get", rrt.get) 55 | return rrt 56 | } 57 | 58 | func (r *Registry) getCompiledSource(p string) (prg *js.Program, err error) { 59 | r.Lock() 60 | defer r.Unlock() 61 | 62 | prg = r.compiled[p] 63 | if prg == nil { 64 | srcLoader := r.srcLoader 65 | if srcLoader == nil { 66 | srcLoader = ioutil.ReadFile 67 | } 68 | if s, err1 := srcLoader(p); err1 == nil { 69 | source := "(function(module, exports) {" + string(s) + "\n})" 70 | prg, err = js.Compile(p, source, false) 71 | if err == nil { 72 | if r.compiled == nil { 73 | r.compiled = make(map[string]*js.Program) 74 | } 75 | r.compiled[p] = prg 76 | } 77 | } else { 78 | err = err1 79 | } 80 | } 81 | return 82 | } 83 | 84 | func (r *RequireModule) loadModule(path string, jsModule *js.Object) error { 85 | 86 | if ldr, exists := native[path]; exists { 87 | ldr(r.runtime, jsModule) 88 | return nil 89 | } 90 | 91 | prg, err := r.r.getCompiledSource(path) 92 | 93 | if err != nil { 94 | return err 95 | } 96 | 97 | f, err := r.runtime.RunProgram(prg) 98 | if err != nil { 99 | return err 100 | } 101 | 102 | if call, ok := js.AssertFunction(f); ok { 103 | jsExports := jsModule.Get("exports") 104 | 105 | // Run the module source, with "jsModule" as the "module" variable, "jsExports" as "this"(Nodejs capable). 106 | _, err = call(jsExports, jsModule, jsExports) 107 | if err != nil { 108 | return err 109 | } 110 | } else { 111 | return InvalidModuleError 112 | } 113 | 114 | return nil 115 | } 116 | 117 | func (r *RequireModule) list(call js.FunctionCall) js.Value { 118 | return r.runtime.ToValue(r.modules) 119 | } 120 | 121 | func (r *RequireModule) set(call js.FunctionCall) js.Value { 122 | key := call.Argument(0).String() 123 | value := call.Argument(1).ToObject(r.runtime) 124 | r.modules[key] = value 125 | return nil 126 | } 127 | 128 | func (r *RequireModule) get(call js.FunctionCall) js.Value { 129 | key := call.Argument(0).String() 130 | if v, ok := r.modules[key]; ok { 131 | return r.runtime.ToValue(v) 132 | } 133 | return nil 134 | } 135 | 136 | func (r *RequireModule) require(call js.FunctionCall) js.Value { 137 | ret, err := r.Require(call.Argument(0).String()) 138 | if err != nil { 139 | panic(r.runtime.NewGoError(err)) 140 | } 141 | return ret 142 | } 143 | 144 | func filepathClean(p string) string { 145 | return filepath.Clean(p) 146 | } 147 | 148 | // Require can be used to import modules from Go source (similar to JS require() function). 149 | func (r *RequireModule) Require(p string) (ret js.Value, err error) { 150 | p = filepathClean(p) 151 | if p == "" { 152 | err = IllegalModuleNameError 153 | return 154 | } 155 | module := r.modules[p] 156 | if module == nil { 157 | module = r.runtime.NewObject() 158 | module.Set("exports", r.runtime.NewObject()) 159 | r.modules[p] = module 160 | err = r.loadModule(p, module) 161 | if err != nil { 162 | delete(r.modules, p) 163 | err = fmt.Errorf("Could not load module '%s': %v", p, err) 164 | return 165 | } 166 | } 167 | ret = module.Get("exports") 168 | return 169 | } 170 | 171 | func Require(runtime *js.Runtime, name string) js.Value { 172 | if r, ok := js.AssertFunction(runtime.Get("require")); ok { 173 | mod, err := r(js.Undefined(), runtime.ToValue(name)) 174 | if err != nil { 175 | panic(err) 176 | } 177 | return mod 178 | } 179 | panic(runtime.NewTypeError("Please enable require for this runtime using new(require.Require).Enable(runtime)")) 180 | } 181 | 182 | func RegisterNativeModule(name string, loader ModuleLoader) { 183 | if native == nil { 184 | native = make(map[string]ModuleLoader) 185 | } 186 | name = filepathClean(name) 187 | native[name] = loader 188 | } 189 | -------------------------------------------------------------------------------- /nodejs/require/module_test.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | js "github.com/dop251/goja" 8 | ) 9 | 10 | func TestRequireNativeModule(t *testing.T) { 11 | const SCRIPT = ` 12 | var m = require("test/m"); 13 | m.test(); 14 | ` 15 | 16 | vm := js.New() 17 | 18 | registry := new(Registry) 19 | registry.Enable(vm) 20 | 21 | RegisterNativeModule("test/m", func(runtime *js.Runtime, module *js.Object) { 22 | o := module.Get("exports").(*js.Object) 23 | o.Set("test", func(call js.FunctionCall) js.Value { 24 | return runtime.ToValue("passed") 25 | }) 26 | }) 27 | 28 | v, err := vm.RunString(SCRIPT) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | if !v.StrictEquals(vm.ToValue("passed")) { 34 | t.Fatalf("Unexpected result: %v", v) 35 | } 36 | } 37 | 38 | func TestRequire(t *testing.T) { 39 | const SCRIPT = ` 40 | var m = require("./testdata/m.js"); 41 | m.test(); 42 | ` 43 | 44 | vm := js.New() 45 | 46 | registry := new(Registry) 47 | registry.Enable(vm) 48 | 49 | v, err := vm.RunString(SCRIPT) 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | 54 | if !v.StrictEquals(vm.ToValue("passed")) { 55 | t.Fatalf("Unexpected result: %v", v) 56 | } 57 | } 58 | 59 | func TestSourceLoader(t *testing.T) { 60 | const SCRIPT = ` 61 | var m = require("m.js"); 62 | m.test(); 63 | ` 64 | 65 | const MODULE = ` 66 | function test() { 67 | return "passed1"; 68 | } 69 | 70 | exports.test = test; 71 | ` 72 | 73 | vm := js.New() 74 | 75 | registry := NewRegistryWithLoader(func(name string) ([]byte, error) { 76 | if name == "m.js" { 77 | return []byte(MODULE), nil 78 | } 79 | return nil, errors.New("Module does not exist") 80 | }) 81 | registry.Enable(vm) 82 | 83 | v, err := vm.RunString(SCRIPT) 84 | if err != nil { 85 | t.Fatal(err) 86 | } 87 | 88 | if !v.StrictEquals(vm.ToValue("passed1")) { 89 | t.Fatalf("Unexpected result: %v", v) 90 | } 91 | } 92 | 93 | func TestStrictModule(t *testing.T) { 94 | const SCRIPT = ` 95 | var m = require("m.js"); 96 | m.test(); 97 | ` 98 | 99 | const MODULE = ` 100 | "use strict"; 101 | 102 | function test() { 103 | var a = "passed1"; 104 | eval("var a = 'not passed'"); 105 | return a; 106 | } 107 | 108 | exports.test = test; 109 | ` 110 | 111 | vm := js.New() 112 | 113 | registry := NewRegistryWithLoader(func(name string) ([]byte, error) { 114 | if name == "m.js" { 115 | return []byte(MODULE), nil 116 | } 117 | return nil, errors.New("Module does not exist") 118 | }) 119 | registry.Enable(vm) 120 | 121 | v, err := vm.RunString(SCRIPT) 122 | if err != nil { 123 | t.Fatal(err) 124 | } 125 | 126 | if !v.StrictEquals(vm.ToValue("passed1")) { 127 | t.Fatalf("Unexpected result: %v", v) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /nodejs/require/testdata/m.js: -------------------------------------------------------------------------------- 1 | function test() { 2 | return "passed"; 3 | } 4 | 5 | module.exports = { 6 | test: test 7 | } 8 | -------------------------------------------------------------------------------- /nodejs/util/module.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "github.com/dop251/goja" 6 | "github.com/zengming00/go-server-js/nodejs/require" 7 | ) 8 | 9 | type Util struct { 10 | runtime *goja.Runtime 11 | } 12 | 13 | func (u *Util) format(f rune, val goja.Value, w *bytes.Buffer) bool { 14 | switch f { 15 | case 's': 16 | w.WriteString(val.String()) 17 | case 'd': 18 | w.WriteString(val.ToNumber().String()) 19 | case 'j': 20 | if json, ok := u.runtime.Get("JSON").(*goja.Object); ok { 21 | if stringify, ok := goja.AssertFunction(json.Get("stringify")); ok { 22 | res, err := stringify(json, val) 23 | if err != nil { 24 | panic(err) 25 | } 26 | w.WriteString(res.String()) 27 | } 28 | } 29 | case '%': 30 | w.WriteByte('%') 31 | return false 32 | default: 33 | w.WriteByte('%') 34 | w.WriteRune(f) 35 | return false 36 | } 37 | return true 38 | } 39 | 40 | func (u *Util) Format(b *bytes.Buffer, f string, args ...goja.Value) { 41 | pct := false 42 | argNum := 0 43 | for _, chr := range f { 44 | if pct { 45 | if argNum < len(args) { 46 | if u.format(chr, args[argNum], b) { 47 | argNum++ 48 | } 49 | } else { 50 | b.WriteByte('%') 51 | b.WriteRune(chr) 52 | } 53 | pct = false 54 | } else { 55 | if chr == '%' { 56 | pct = true 57 | } else { 58 | b.WriteRune(chr) 59 | } 60 | } 61 | } 62 | 63 | for _, arg := range args[argNum:] { 64 | b.WriteByte(' ') 65 | b.WriteString(arg.String()) 66 | } 67 | } 68 | 69 | func (u *Util) js_format(call goja.FunctionCall) goja.Value { 70 | var b bytes.Buffer 71 | var fmt string 72 | 73 | if arg := call.Argument(0); !goja.IsUndefined(arg) { 74 | fmt = arg.String() 75 | } 76 | 77 | var args []goja.Value 78 | if len(call.Arguments) > 0 { 79 | args = call.Arguments[1:] 80 | } 81 | u.Format(&b, fmt, args...) 82 | 83 | return u.runtime.ToValue(b.String()) 84 | } 85 | 86 | func Require(runtime *goja.Runtime, module *goja.Object) { 87 | u := &Util{ 88 | runtime: runtime, 89 | } 90 | obj := module.Get("exports").(*goja.Object) 91 | obj.Set("format", u.js_format) 92 | } 93 | 94 | func New(runtime *goja.Runtime) *Util { 95 | return &Util{ 96 | runtime: runtime, 97 | } 98 | } 99 | 100 | func init() { 101 | require.RegisterNativeModule("util", Require) 102 | } 103 | -------------------------------------------------------------------------------- /nodejs/util/module_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/dop251/goja" 8 | "github.com/zengming00/go-server-js/nodejs/require" 9 | ) 10 | 11 | func TestUtil_Format(t *testing.T) { 12 | vm := goja.New() 13 | util := New(vm) 14 | 15 | var b bytes.Buffer 16 | util.Format(&b, "Test: %% %д %s %d, %j", vm.ToValue("string"), vm.ToValue(42), vm.NewObject()) 17 | 18 | if res := b.String(); res != "Test: % %д string 42, {}" { 19 | t.Fatalf("Unexpected result: '%s'", res) 20 | } 21 | } 22 | 23 | func TestUtil_Format_NoArgs(t *testing.T) { 24 | vm := goja.New() 25 | util := New(vm) 26 | 27 | var b bytes.Buffer 28 | util.Format(&b, "Test: %s %d, %j") 29 | 30 | if res := b.String(); res != "Test: %s %d, %j" { 31 | t.Fatalf("Unexpected result: '%s'", res) 32 | } 33 | } 34 | 35 | func TestUtil_Format_LessArgs(t *testing.T) { 36 | vm := goja.New() 37 | util := New(vm) 38 | 39 | var b bytes.Buffer 40 | util.Format(&b, "Test: %s %d, %j", vm.ToValue("string"), vm.ToValue(42)) 41 | 42 | if res := b.String(); res != "Test: string 42, %j" { 43 | t.Fatalf("Unexpected result: '%s'", res) 44 | } 45 | } 46 | 47 | func TestUtil_Format_MoreArgs(t *testing.T) { 48 | vm := goja.New() 49 | util := New(vm) 50 | 51 | var b bytes.Buffer 52 | util.Format(&b, "Test: %s %d, %j", vm.ToValue("string"), vm.ToValue(42), vm.NewObject(), vm.ToValue(42.42)) 53 | 54 | if res := b.String(); res != "Test: string 42, {} 42.42" { 55 | t.Fatalf("Unexpected result: '%s'", res) 56 | } 57 | } 58 | 59 | func TestJSNoArgs(t *testing.T) { 60 | vm := goja.New() 61 | new(require.Registry).Enable(vm) 62 | 63 | if util, ok := require.Require(vm, "util").(*goja.Object); ok { 64 | if format, ok := goja.AssertFunction(util.Get("format")); ok { 65 | res, err := format(util) 66 | if err != nil { 67 | t.Fatal(err) 68 | } 69 | if v := res.Export(); v != "" { 70 | t.Fatalf("Unexpected result: %v", v) 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: verdana, helvetica, arial, sans-serif; 3 | padding: 20px; 4 | font-size: 12px; 5 | margin: 0; 6 | } 7 | 8 | h2 { 9 | font-size: 18px; 10 | font-weight: bold; 11 | margin: 0; 12 | margin-bottom: 15px; 13 | } 14 | 15 | .demo-info { 16 | padding: 0 0 12px 0; 17 | } 18 | 19 | .demo-tip { 20 | display: none; 21 | } 22 | 23 | #fm { 24 | margin: 0; 25 | padding: 10px 30px; 26 | } 27 | 28 | .ftitle { 29 | font-size: 14px; 30 | font-weight: bold; 31 | color: #666; 32 | padding: 5px 0; 33 | margin-bottom: 10px; 34 | border-bottom: 1px solid #ccc; 35 | } 36 | 37 | .fitem { 38 | margin-bottom: 5px; 39 | } 40 | 41 | .fitem label { 42 | display: inline-block; 43 | width: 80px; 44 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | jQuery EasyUI CRUD Demo 9 | 10 | 11 | 12 | 13 | 14 | 95 | 96 | 97 | 98 |

    go-server-js Basic CRUD Application

    99 |
    100 |
     
    101 |
    Click the buttons on datagrid toolbar to do crud actions.
    102 |

    103 | 还可以测试: 104 | ejs模板引擎(先在下面添加数据) 105 | 图像处理 106 | redis(本机6379且没有密码) 107 |

    108 |
    109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
    First NameLast NamePhoneEmail
    121 |
    122 | New User 123 | Edit User 124 | Remove User 125 |
    126 | 127 |
    128 |
    User Information
    129 |
    130 |
    131 | 132 | 133 |
    134 |
    135 | 136 | 137 |
    138 |
    139 | 140 | 141 |
    142 |
    143 | 144 | 145 |
    146 |
    147 |
    148 |
    149 | Save 150 | Cancel 151 |
    152 | 153 | 154 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/accordion.css: -------------------------------------------------------------------------------- 1 | .accordion { 2 | overflow: hidden; 3 | border-width: 1px; 4 | border-style: solid; 5 | } 6 | .accordion .accordion-header { 7 | border-width: 0 0 1px; 8 | cursor: pointer; 9 | } 10 | .accordion .accordion-body { 11 | border-width: 0 0 1px; 12 | } 13 | .accordion-noborder { 14 | border-width: 0; 15 | } 16 | .accordion-noborder .accordion-header { 17 | border-width: 0 0 1px; 18 | } 19 | .accordion-noborder .accordion-body { 20 | border-width: 0 0 1px; 21 | } 22 | .accordion-collapse { 23 | background: url('images/accordion_arrows.png') no-repeat 0 0; 24 | } 25 | .accordion-expand { 26 | background: url('images/accordion_arrows.png') no-repeat -16px 0; 27 | } 28 | .accordion { 29 | background: #ffffff; 30 | border-color: #95B8E7; 31 | } 32 | .accordion .accordion-header { 33 | background: #E0ECFF; 34 | filter: none; 35 | } 36 | .accordion .accordion-header-selected { 37 | background: #ffe48d; 38 | } 39 | .accordion .accordion-header-selected .panel-title { 40 | color: #000000; 41 | } 42 | .accordion .panel-last > .accordion-header { 43 | border-bottom-color: #E0ECFF; 44 | } 45 | .accordion .panel-last > .accordion-body { 46 | border-bottom-color: #ffffff; 47 | } 48 | .accordion .panel-last > .accordion-header-selected, 49 | .accordion .panel-last > .accordion-header-border { 50 | border-bottom-color: #95B8E7; 51 | } 52 | .accordion> .panel-hleft { 53 | float: left; 54 | } 55 | .accordion> .panel-hleft>.panel-header { 56 | border-width: 0 1px 0 0; 57 | } 58 | .accordion> .panel-hleft> .panel-body { 59 | border-width: 0 1px 0 0; 60 | } 61 | .accordion> .panel-hleft.panel-last > .accordion-header { 62 | border-right-color: #E0ECFF; 63 | } 64 | .accordion> .panel-hleft.panel-last > .accordion-body { 65 | border-right-color: #ffffff; 66 | } 67 | .accordion> .panel-hleft.panel-last > .accordion-header-selected, 68 | .accordion> .panel-hleft.panel-last > .accordion-header-border { 69 | border-right-color: #95B8E7; 70 | } 71 | .accordion> .panel-hright { 72 | float: right; 73 | } 74 | .accordion> .panel-hright>.panel-header { 75 | border-width: 0 0 0 1px; 76 | } 77 | .accordion> .panel-hright> .panel-body { 78 | border-width: 0 0 0 1px; 79 | } 80 | .accordion> .panel-hright.panel-last > .accordion-header { 81 | border-left-color: #E0ECFF; 82 | } 83 | .accordion> .panel-hright.panel-last > .accordion-body { 84 | border-left-color: #ffffff; 85 | } 86 | .accordion> .panel-hright.panel-last > .accordion-header-selected, 87 | .accordion> .panel-hright.panel-last > .accordion-header-border { 88 | border-left-color: #95B8E7; 89 | } 90 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/calendar.css: -------------------------------------------------------------------------------- 1 | .calendar { 2 | border-width: 1px; 3 | border-style: solid; 4 | padding: 1px; 5 | overflow: hidden; 6 | } 7 | .calendar table { 8 | table-layout: fixed; 9 | border-collapse: separate; 10 | font-size: 12px; 11 | width: 100%; 12 | height: 100%; 13 | } 14 | .calendar table td, 15 | .calendar table th { 16 | font-size: 12px; 17 | } 18 | .calendar-noborder { 19 | border: 0; 20 | } 21 | .calendar-header { 22 | position: relative; 23 | height: 22px; 24 | } 25 | .calendar-title { 26 | text-align: center; 27 | height: 22px; 28 | } 29 | .calendar-title span { 30 | position: relative; 31 | display: inline-block; 32 | top: 2px; 33 | padding: 0 3px; 34 | height: 18px; 35 | line-height: 18px; 36 | font-size: 12px; 37 | cursor: pointer; 38 | -moz-border-radius: 5px 5px 5px 5px; 39 | -webkit-border-radius: 5px 5px 5px 5px; 40 | border-radius: 5px 5px 5px 5px; 41 | } 42 | .calendar-prevmonth, 43 | .calendar-nextmonth, 44 | .calendar-prevyear, 45 | .calendar-nextyear { 46 | position: absolute; 47 | top: 50%; 48 | margin-top: -7px; 49 | width: 14px; 50 | height: 14px; 51 | cursor: pointer; 52 | font-size: 1px; 53 | -moz-border-radius: 5px 5px 5px 5px; 54 | -webkit-border-radius: 5px 5px 5px 5px; 55 | border-radius: 5px 5px 5px 5px; 56 | } 57 | .calendar-prevmonth { 58 | left: 20px; 59 | background: url('images/calendar_arrows.png') no-repeat -18px -2px; 60 | } 61 | .calendar-nextmonth { 62 | right: 20px; 63 | background: url('images/calendar_arrows.png') no-repeat -34px -2px; 64 | } 65 | .calendar-prevyear { 66 | left: 3px; 67 | background: url('images/calendar_arrows.png') no-repeat -1px -2px; 68 | } 69 | .calendar-nextyear { 70 | right: 3px; 71 | background: url('images/calendar_arrows.png') no-repeat -49px -2px; 72 | } 73 | .calendar-body { 74 | position: relative; 75 | } 76 | .calendar-body th, 77 | .calendar-body td { 78 | text-align: center; 79 | } 80 | .calendar-day { 81 | border: 0; 82 | padding: 1px; 83 | cursor: pointer; 84 | -moz-border-radius: 5px 5px 5px 5px; 85 | -webkit-border-radius: 5px 5px 5px 5px; 86 | border-radius: 5px 5px 5px 5px; 87 | } 88 | .calendar-other-month { 89 | opacity: 0.3; 90 | filter: alpha(opacity=30); 91 | } 92 | .calendar-disabled { 93 | opacity: 0.6; 94 | filter: alpha(opacity=60); 95 | cursor: default; 96 | } 97 | .calendar-menu { 98 | position: absolute; 99 | top: 0; 100 | left: 0; 101 | width: 180px; 102 | height: 150px; 103 | padding: 5px; 104 | font-size: 12px; 105 | display: none; 106 | overflow: hidden; 107 | } 108 | .calendar-menu-year-inner { 109 | text-align: center; 110 | padding-bottom: 5px; 111 | } 112 | .calendar-menu-year { 113 | width: 50px; 114 | text-align: center; 115 | border-width: 1px; 116 | border-style: solid; 117 | outline-style: none; 118 | resize: none; 119 | margin: 0; 120 | padding: 2px; 121 | font-weight: bold; 122 | font-size: 12px; 123 | -moz-border-radius: 5px 5px 5px 5px; 124 | -webkit-border-radius: 5px 5px 5px 5px; 125 | border-radius: 5px 5px 5px 5px; 126 | } 127 | .calendar-menu-prev, 128 | .calendar-menu-next { 129 | display: inline-block; 130 | width: 21px; 131 | height: 21px; 132 | vertical-align: top; 133 | cursor: pointer; 134 | -moz-border-radius: 5px 5px 5px 5px; 135 | -webkit-border-radius: 5px 5px 5px 5px; 136 | border-radius: 5px 5px 5px 5px; 137 | } 138 | .calendar-menu-prev { 139 | margin-right: 10px; 140 | background: url('images/calendar_arrows.png') no-repeat 2px 2px; 141 | } 142 | .calendar-menu-next { 143 | margin-left: 10px; 144 | background: url('images/calendar_arrows.png') no-repeat -45px 2px; 145 | } 146 | .calendar-menu-month { 147 | text-align: center; 148 | cursor: pointer; 149 | font-weight: bold; 150 | -moz-border-radius: 5px 5px 5px 5px; 151 | -webkit-border-radius: 5px 5px 5px 5px; 152 | border-radius: 5px 5px 5px 5px; 153 | } 154 | .calendar-body th, 155 | .calendar-menu-month { 156 | color: #4d4d4d; 157 | } 158 | .calendar-day { 159 | color: #000000; 160 | } 161 | .calendar-sunday { 162 | color: #CC2222; 163 | } 164 | .calendar-saturday { 165 | color: #00ee00; 166 | } 167 | .calendar-today { 168 | color: #0000ff; 169 | } 170 | .calendar-menu-year { 171 | border-color: #95B8E7; 172 | } 173 | .calendar { 174 | border-color: #95B8E7; 175 | } 176 | .calendar-header { 177 | background: #E0ECFF; 178 | } 179 | .calendar-body, 180 | .calendar-menu { 181 | background: #ffffff; 182 | } 183 | .calendar-body th { 184 | background: #F4F4F4; 185 | padding: 2px 0; 186 | } 187 | .calendar-hover, 188 | .calendar-nav-hover, 189 | .calendar-menu-hover { 190 | background-color: #eaf2ff; 191 | color: #000000; 192 | } 193 | .calendar-hover { 194 | border: 1px solid #b7d2ff; 195 | padding: 0; 196 | } 197 | .calendar-selected { 198 | background-color: #ffe48d; 199 | color: #000000; 200 | border: 1px solid #ffab3f; 201 | padding: 0; 202 | } 203 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/combo.css: -------------------------------------------------------------------------------- 1 | .combo-arrow { 2 | width: 18px; 3 | height: 20px; 4 | overflow: hidden; 5 | display: inline-block; 6 | vertical-align: top; 7 | cursor: pointer; 8 | opacity: 0.6; 9 | filter: alpha(opacity=60); 10 | } 11 | .combo-arrow-hover { 12 | opacity: 1.0; 13 | filter: alpha(opacity=100); 14 | } 15 | .combo-panel { 16 | overflow: auto; 17 | } 18 | .combo-arrow { 19 | background: url('images/combo_arrow.png') no-repeat center center; 20 | } 21 | .combo-panel { 22 | background-color: #ffffff; 23 | } 24 | .combo-arrow { 25 | background-color: #E0ECFF; 26 | } 27 | .combo-arrow-hover { 28 | background-color: #eaf2ff; 29 | } 30 | .combo-arrow:hover { 31 | background-color: #eaf2ff; 32 | } 33 | .combo .textbox-icon-disabled:hover { 34 | cursor: default; 35 | } 36 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/combobox.css: -------------------------------------------------------------------------------- 1 | .combobox-item, 2 | .combobox-group, 3 | .combobox-stick { 4 | font-size: 12px; 5 | padding: 3px; 6 | } 7 | .combobox-item-disabled { 8 | opacity: 0.5; 9 | filter: alpha(opacity=50); 10 | } 11 | .combobox-gitem { 12 | padding-left: 10px; 13 | } 14 | .combobox-group, 15 | .combobox-stick { 16 | font-weight: bold; 17 | } 18 | .combobox-stick { 19 | position: absolute; 20 | top: 1px; 21 | left: 1px; 22 | right: 1px; 23 | background: inherit; 24 | } 25 | .combobox-item-hover { 26 | background-color: #eaf2ff; 27 | color: #000000; 28 | } 29 | .combobox-item-selected { 30 | background-color: #ffe48d; 31 | color: #000000; 32 | } 33 | .combobox-icon { 34 | display: inline-block; 35 | width: 16px; 36 | height: 16px; 37 | vertical-align: middle; 38 | margin-right: 2px; 39 | } 40 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/datalist.css: -------------------------------------------------------------------------------- 1 | .datalist .datagrid-header { 2 | border-width: 0; 3 | } 4 | .datalist .datagrid-group, 5 | .m-list .m-list-group { 6 | height: 25px; 7 | line-height: 25px; 8 | font-weight: bold; 9 | overflow: hidden; 10 | background-color: #efefef; 11 | border-style: solid; 12 | border-width: 0 0 1px 0; 13 | border-color: #ccc; 14 | } 15 | .datalist .datagrid-group-expander { 16 | display: none; 17 | } 18 | .datalist .datagrid-group-title { 19 | padding: 0 4px; 20 | } 21 | .datalist .datagrid-btable { 22 | width: 100%; 23 | table-layout: fixed; 24 | } 25 | .datalist .datagrid-row td { 26 | border-style: solid; 27 | border-left-color: transparent; 28 | border-right-color: transparent; 29 | border-bottom-width: 0; 30 | } 31 | .datalist-lines .datagrid-row td { 32 | border-bottom-width: 1px; 33 | } 34 | .datalist .datagrid-cell, 35 | .m-list li { 36 | width: auto; 37 | height: auto; 38 | padding: 2px 4px; 39 | line-height: 18px; 40 | position: relative; 41 | white-space: nowrap; 42 | text-overflow: ellipsis; 43 | overflow: hidden; 44 | } 45 | .datalist-link, 46 | .m-list li>a { 47 | display: block; 48 | position: relative; 49 | cursor: pointer; 50 | color: #000000; 51 | text-decoration: none; 52 | overflow: hidden; 53 | margin: -2px -4px; 54 | padding: 2px 4px; 55 | padding-right: 16px; 56 | line-height: 18px; 57 | white-space: nowrap; 58 | text-overflow: ellipsis; 59 | overflow: hidden; 60 | } 61 | .datalist-link::after, 62 | .m-list li>a::after { 63 | position: absolute; 64 | display: block; 65 | width: 8px; 66 | height: 8px; 67 | content: ''; 68 | right: 6px; 69 | top: 50%; 70 | margin-top: -4px; 71 | border-style: solid; 72 | border-width: 1px 1px 0 0; 73 | -ms-transform: rotate(45deg); 74 | -moz-transform: rotate(45deg); 75 | -webkit-transform: rotate(45deg); 76 | -o-transform: rotate(45deg); 77 | transform: rotate(45deg); 78 | } 79 | .m-list { 80 | margin: 0; 81 | padding: 0; 82 | list-style: none; 83 | } 84 | .m-list li { 85 | border-style: solid; 86 | border-width: 0 0 1px 0; 87 | border-color: #ccc; 88 | } 89 | .m-list li>a:hover { 90 | background: #eaf2ff; 91 | color: #000000; 92 | } 93 | .m-list .m-list-group { 94 | padding: 0 4px; 95 | } 96 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/datebox.css: -------------------------------------------------------------------------------- 1 | .datebox-calendar-inner { 2 | height: 180px; 3 | } 4 | .datebox-button { 5 | padding: 0 5px; 6 | text-align: center; 7 | } 8 | .datebox-button a { 9 | line-height: 22px; 10 | font-size: 12px; 11 | font-weight: bold; 12 | text-decoration: none; 13 | opacity: 0.6; 14 | filter: alpha(opacity=60); 15 | } 16 | .datebox-button a:hover { 17 | opacity: 1.0; 18 | filter: alpha(opacity=100); 19 | } 20 | .datebox-current, 21 | .datebox-close { 22 | float: left; 23 | } 24 | .datebox-close { 25 | float: right; 26 | } 27 | .datebox .combo-arrow { 28 | background-image: url('images/datebox_arrow.png'); 29 | background-position: center center; 30 | } 31 | .datebox-button { 32 | background-color: #F4F4F4; 33 | } 34 | .datebox-button a { 35 | color: #444; 36 | } 37 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/dialog.css: -------------------------------------------------------------------------------- 1 | .dialog-content { 2 | overflow: auto; 3 | } 4 | .dialog-toolbar { 5 | position: relative; 6 | padding: 2px 5px; 7 | } 8 | .dialog-tool-separator { 9 | float: left; 10 | height: 24px; 11 | border-left: 1px solid #ccc; 12 | border-right: 1px solid #fff; 13 | margin: 2px 1px; 14 | } 15 | .dialog-button { 16 | position: relative; 17 | top: -1px; 18 | padding: 5px; 19 | text-align: right; 20 | } 21 | .dialog-button .l-btn { 22 | margin-left: 5px; 23 | } 24 | .dialog-toolbar, 25 | .dialog-button { 26 | background: #F4F4F4; 27 | border-width: 1px; 28 | border-style: solid; 29 | } 30 | .dialog-toolbar { 31 | border-color: #95B8E7 #95B8E7 #dddddd #95B8E7; 32 | } 33 | .dialog-button { 34 | border-color: #dddddd #95B8E7 #95B8E7 #95B8E7; 35 | } 36 | .window-thinborder .dialog-toolbar { 37 | border-left: transparent; 38 | border-right: transparent; 39 | border-top-color: #F4F4F4; 40 | } 41 | .window-thinborder .dialog-button { 42 | top: 0px; 43 | padding: 5px 8px 8px 8px; 44 | border-left: transparent; 45 | border-right: transparent; 46 | border-bottom: transparent; 47 | } 48 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/filebox.css: -------------------------------------------------------------------------------- 1 | .filebox .textbox-value { 2 | vertical-align: top; 3 | position: absolute; 4 | top: 0; 5 | left: -5000px; 6 | } 7 | .filebox-label { 8 | display: inline-block; 9 | position: absolute; 10 | width: 100%; 11 | height: 100%; 12 | cursor: pointer; 13 | left: 0; 14 | top: 0; 15 | z-index: 10; 16 | background: url('images/blank.gif') no-repeat; 17 | } 18 | .l-btn-disabled .filebox-label { 19 | cursor: default; 20 | } 21 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/accordion_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/accordion_arrows.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/blank.gif -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/calendar_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/calendar_arrows.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/combo_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/combo_arrow.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/datagrid_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/datagrid_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/datebox_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/datebox_arrow.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/layout_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/layout_arrows.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/linkbutton_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/linkbutton_bg.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/loading.gif -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/menu_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/menu_arrows.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/messager_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/messager_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/pagination_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/pagination_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/panel_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/panel_tools.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/passwordbox_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/passwordbox_close.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/passwordbox_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/passwordbox_open.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/searchbox_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/searchbox_button.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/slider_handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/slider_handle.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/spinner_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/spinner_arrows.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/tabs_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/tabs_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/tagbox_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/tagbox_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/tree_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/tree_icons.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/images/validatebox_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/images/validatebox_warning.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/layout.css: -------------------------------------------------------------------------------- 1 | .layout { 2 | position: relative; 3 | overflow: hidden; 4 | margin: 0; 5 | padding: 0; 6 | z-index: 0; 7 | } 8 | .layout-panel { 9 | position: absolute; 10 | overflow: hidden; 11 | } 12 | .layout-body { 13 | min-width: 1px; 14 | min-height: 1px; 15 | } 16 | .layout-panel-east, 17 | .layout-panel-west { 18 | z-index: 2; 19 | } 20 | .layout-panel-north, 21 | .layout-panel-south { 22 | z-index: 3; 23 | } 24 | .layout-expand { 25 | position: absolute; 26 | padding: 0px; 27 | font-size: 1px; 28 | cursor: pointer; 29 | z-index: 1; 30 | } 31 | .layout-expand .panel-header, 32 | .layout-expand .panel-body { 33 | background: transparent; 34 | filter: none; 35 | overflow: hidden; 36 | } 37 | .layout-expand .panel-header { 38 | border-bottom-width: 0px; 39 | } 40 | .layout-expand .panel-body { 41 | position: relative; 42 | } 43 | .layout-expand .panel-body .panel-icon { 44 | margin-top: 0; 45 | top: 0; 46 | left: 50%; 47 | margin-left: -8px; 48 | } 49 | .layout-expand-west .panel-header .panel-icon, 50 | .layout-expand-east .panel-header .panel-icon { 51 | display: none; 52 | } 53 | .layout-expand-title { 54 | position: absolute; 55 | top: 0; 56 | left: 21px; 57 | white-space: nowrap; 58 | word-wrap: normal; 59 | -webkit-transform: rotate(90deg); 60 | -webkit-transform-origin: 0 0; 61 | -moz-transform: rotate(90deg); 62 | -moz-transform-origin: 0 0; 63 | -o-transform: rotate(90deg); 64 | -o-transform-origin: 0 0; 65 | transform: rotate(90deg); 66 | transform-origin: 0 0; 67 | } 68 | .layout-expand-title-up { 69 | position: absolute; 70 | top: 0; 71 | left: 0; 72 | text-align: right; 73 | padding-left: 5px; 74 | white-space: nowrap; 75 | word-wrap: normal; 76 | -webkit-transform: rotate(-90deg); 77 | -webkit-transform-origin: 0 0; 78 | -moz-transform: rotate(-90deg); 79 | -moz-transform-origin: 0 0; 80 | -o-transform: rotate(-90deg); 81 | -o-transform-origin: 0 0; 82 | transform: rotate(-90deg); 83 | transform-origin: 0 0; 84 | } 85 | .layout-expand-with-icon { 86 | top: 18px; 87 | } 88 | .layout-expand .panel-body-noheader .layout-expand-title, 89 | .layout-expand .panel-body-noheader .panel-icon { 90 | top: 5px; 91 | } 92 | .layout-expand .panel-body-noheader .layout-expand-with-icon { 93 | top: 23px; 94 | } 95 | .layout-split-proxy-h, 96 | .layout-split-proxy-v { 97 | position: absolute; 98 | font-size: 1px; 99 | display: none; 100 | z-index: 5; 101 | } 102 | .layout-split-proxy-h { 103 | width: 5px; 104 | cursor: e-resize; 105 | } 106 | .layout-split-proxy-v { 107 | height: 5px; 108 | cursor: n-resize; 109 | } 110 | .layout-mask { 111 | position: absolute; 112 | background: #fafafa; 113 | filter: alpha(opacity=10); 114 | opacity: 0.10; 115 | z-index: 4; 116 | } 117 | .layout-button-up { 118 | background: url('images/layout_arrows.png') no-repeat -16px -16px; 119 | } 120 | .layout-button-down { 121 | background: url('images/layout_arrows.png') no-repeat -16px 0; 122 | } 123 | .layout-button-left { 124 | background: url('images/layout_arrows.png') no-repeat 0 0; 125 | } 126 | .layout-button-right { 127 | background: url('images/layout_arrows.png') no-repeat 0 -16px; 128 | } 129 | .layout-split-proxy-h, 130 | .layout-split-proxy-v { 131 | background-color: #aac5e7; 132 | } 133 | .layout-split-north { 134 | border-bottom: 5px solid #E6EEF8; 135 | } 136 | .layout-split-south { 137 | border-top: 5px solid #E6EEF8; 138 | } 139 | .layout-split-east { 140 | border-left: 5px solid #E6EEF8; 141 | } 142 | .layout-split-west { 143 | border-right: 5px solid #E6EEF8; 144 | } 145 | .layout-expand { 146 | background-color: #E0ECFF; 147 | } 148 | .layout-expand-over { 149 | background-color: #E0ECFF; 150 | } 151 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/linkbutton.css: -------------------------------------------------------------------------------- 1 | .l-btn { 2 | text-decoration: none; 3 | display: inline-block; 4 | overflow: hidden; 5 | margin: 0; 6 | padding: 0; 7 | cursor: pointer; 8 | outline: none; 9 | text-align: center; 10 | vertical-align: middle; 11 | line-height: normal; 12 | } 13 | .l-btn-plain { 14 | border-width: 0; 15 | padding: 1px; 16 | } 17 | .l-btn-left { 18 | display: inline-block; 19 | position: relative; 20 | overflow: hidden; 21 | margin: 0; 22 | padding: 0; 23 | vertical-align: top; 24 | } 25 | .l-btn-text { 26 | display: inline-block; 27 | vertical-align: top; 28 | width: auto; 29 | line-height: 24px; 30 | font-size: 12px; 31 | padding: 0; 32 | margin: 0 4px; 33 | } 34 | .l-btn-icon { 35 | display: inline-block; 36 | width: 16px; 37 | height: 16px; 38 | line-height: 16px; 39 | position: absolute; 40 | top: 50%; 41 | margin-top: -8px; 42 | font-size: 1px; 43 | } 44 | .l-btn span span .l-btn-empty { 45 | display: inline-block; 46 | margin: 0; 47 | width: 16px; 48 | height: 24px; 49 | font-size: 1px; 50 | vertical-align: top; 51 | } 52 | .l-btn span .l-btn-icon-left { 53 | padding: 0 0 0 20px; 54 | background-position: left center; 55 | } 56 | .l-btn span .l-btn-icon-right { 57 | padding: 0 20px 0 0; 58 | background-position: right center; 59 | } 60 | .l-btn-icon-left .l-btn-text { 61 | margin: 0 4px 0 24px; 62 | } 63 | .l-btn-icon-left .l-btn-icon { 64 | left: 4px; 65 | } 66 | .l-btn-icon-right .l-btn-text { 67 | margin: 0 24px 0 4px; 68 | } 69 | .l-btn-icon-right .l-btn-icon { 70 | right: 4px; 71 | } 72 | .l-btn-icon-top .l-btn-text { 73 | margin: 20px 4px 0 4px; 74 | } 75 | .l-btn-icon-top .l-btn-icon { 76 | top: 4px; 77 | left: 50%; 78 | margin: 0 0 0 -8px; 79 | } 80 | .l-btn-icon-bottom .l-btn-text { 81 | margin: 0 4px 20px 4px; 82 | } 83 | .l-btn-icon-bottom .l-btn-icon { 84 | top: auto; 85 | bottom: 4px; 86 | left: 50%; 87 | margin: 0 0 0 -8px; 88 | } 89 | .l-btn-left .l-btn-empty { 90 | margin: 0 4px; 91 | width: 16px; 92 | } 93 | .l-btn-plain:hover { 94 | padding: 0; 95 | } 96 | .l-btn-focus { 97 | outline: #0000FF dotted thin; 98 | } 99 | .l-btn-large .l-btn-text { 100 | line-height: 40px; 101 | } 102 | .l-btn-large .l-btn-icon { 103 | width: 32px; 104 | height: 32px; 105 | line-height: 32px; 106 | margin-top: -16px; 107 | } 108 | .l-btn-large .l-btn-icon-left .l-btn-text { 109 | margin-left: 40px; 110 | } 111 | .l-btn-large .l-btn-icon-right .l-btn-text { 112 | margin-right: 40px; 113 | } 114 | .l-btn-large .l-btn-icon-top .l-btn-text { 115 | margin-top: 36px; 116 | line-height: 24px; 117 | min-width: 32px; 118 | } 119 | .l-btn-large .l-btn-icon-top .l-btn-icon { 120 | margin: 0 0 0 -16px; 121 | } 122 | .l-btn-large .l-btn-icon-bottom .l-btn-text { 123 | margin-bottom: 36px; 124 | line-height: 24px; 125 | min-width: 32px; 126 | } 127 | .l-btn-large .l-btn-icon-bottom .l-btn-icon { 128 | margin: 0 0 0 -16px; 129 | } 130 | .l-btn-large .l-btn-left .l-btn-empty { 131 | margin: 0 4px; 132 | width: 32px; 133 | } 134 | .l-btn { 135 | color: #444; 136 | background: #fafafa; 137 | background-repeat: repeat-x; 138 | border: 1px solid #bbb; 139 | background: -webkit-linear-gradient(top,#ffffff 0,#eeeeee 100%); 140 | background: -moz-linear-gradient(top,#ffffff 0,#eeeeee 100%); 141 | background: -o-linear-gradient(top,#ffffff 0,#eeeeee 100%); 142 | background: linear-gradient(to bottom,#ffffff 0,#eeeeee 100%); 143 | background-repeat: repeat-x; 144 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff,endColorstr=#eeeeee,GradientType=0); 145 | -moz-border-radius: 5px 5px 5px 5px; 146 | -webkit-border-radius: 5px 5px 5px 5px; 147 | border-radius: 5px 5px 5px 5px; 148 | } 149 | .l-btn:hover { 150 | background: #eaf2ff; 151 | color: #000000; 152 | border: 1px solid #b7d2ff; 153 | filter: none; 154 | } 155 | .l-btn-plain { 156 | background: transparent; 157 | border-width: 0; 158 | filter: none; 159 | } 160 | .l-btn-outline { 161 | border-width: 1px; 162 | border-color: #b7d2ff; 163 | padding: 0; 164 | } 165 | .l-btn-plain:hover { 166 | background: #eaf2ff; 167 | color: #000000; 168 | border: 1px solid #b7d2ff; 169 | -moz-border-radius: 5px 5px 5px 5px; 170 | -webkit-border-radius: 5px 5px 5px 5px; 171 | border-radius: 5px 5px 5px 5px; 172 | } 173 | .l-btn-disabled, 174 | .l-btn-disabled:hover { 175 | opacity: 0.5; 176 | cursor: default; 177 | background: #fafafa; 178 | color: #444; 179 | background: -webkit-linear-gradient(top,#ffffff 0,#eeeeee 100%); 180 | background: -moz-linear-gradient(top,#ffffff 0,#eeeeee 100%); 181 | background: -o-linear-gradient(top,#ffffff 0,#eeeeee 100%); 182 | background: linear-gradient(to bottom,#ffffff 0,#eeeeee 100%); 183 | background-repeat: repeat-x; 184 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff,endColorstr=#eeeeee,GradientType=0); 185 | } 186 | .l-btn-disabled .l-btn-text, 187 | .l-btn-disabled .l-btn-icon { 188 | filter: alpha(opacity=50); 189 | } 190 | .l-btn-plain-disabled, 191 | .l-btn-plain-disabled:hover { 192 | background: transparent; 193 | filter: alpha(opacity=50); 194 | } 195 | .l-btn-selected, 196 | .l-btn-selected:hover { 197 | background: #ddd; 198 | filter: none; 199 | } 200 | .l-btn-plain-selected, 201 | .l-btn-plain-selected:hover { 202 | background: #ddd; 203 | } 204 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/menu.css: -------------------------------------------------------------------------------- 1 | .menu { 2 | position: absolute; 3 | margin: 0; 4 | padding: 2px; 5 | border-width: 1px; 6 | border-style: solid; 7 | overflow: hidden; 8 | } 9 | .menu-inline { 10 | position: relative; 11 | } 12 | .menu-item { 13 | position: relative; 14 | margin: 0; 15 | padding: 0; 16 | overflow: hidden; 17 | white-space: nowrap; 18 | cursor: pointer; 19 | border-width: 1px; 20 | border-style: solid; 21 | } 22 | .menu-text { 23 | height: 20px; 24 | line-height: 20px; 25 | float: left; 26 | padding-left: 28px; 27 | } 28 | .menu-icon { 29 | position: absolute; 30 | width: 16px; 31 | height: 16px; 32 | left: 2px; 33 | top: 50%; 34 | margin-top: -8px; 35 | } 36 | .menu-rightarrow { 37 | position: absolute; 38 | width: 16px; 39 | height: 16px; 40 | right: 0; 41 | top: 50%; 42 | margin-top: -8px; 43 | } 44 | .menu-line { 45 | position: absolute; 46 | left: 26px; 47 | top: 0; 48 | height: 2000px; 49 | font-size: 1px; 50 | } 51 | .menu-sep { 52 | margin: 3px 0px 3px 25px; 53 | font-size: 1px; 54 | } 55 | .menu-noline .menu-line { 56 | display: none; 57 | } 58 | .menu-noline .menu-sep { 59 | margin-left: 0; 60 | margin-right: 0; 61 | } 62 | .menu-active { 63 | -moz-border-radius: 5px 5px 5px 5px; 64 | -webkit-border-radius: 5px 5px 5px 5px; 65 | border-radius: 5px 5px 5px 5px; 66 | } 67 | .menu-item-disabled { 68 | opacity: 0.5; 69 | filter: alpha(opacity=50); 70 | cursor: default; 71 | } 72 | .menu-text, 73 | .menu-text span { 74 | font-size: 12px; 75 | } 76 | .menu-shadow { 77 | position: absolute; 78 | -moz-border-radius: 5px 5px 5px 5px; 79 | -webkit-border-radius: 5px 5px 5px 5px; 80 | border-radius: 5px 5px 5px 5px; 81 | background: #ccc; 82 | -moz-box-shadow: 2px 2px 3px #cccccc; 83 | -webkit-box-shadow: 2px 2px 3px #cccccc; 84 | box-shadow: 2px 2px 3px #cccccc; 85 | filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=2,MakeShadow=false,ShadowOpacity=0.2); 86 | } 87 | .menu-rightarrow { 88 | background: url('images/menu_arrows.png') no-repeat -32px center; 89 | } 90 | .menu-line { 91 | border-left: 1px solid #ccc; 92 | border-right: 1px solid #fff; 93 | } 94 | .menu-sep { 95 | border-top: 1px solid #ccc; 96 | border-bottom: 1px solid #fff; 97 | } 98 | .menu { 99 | background-color: #fafafa; 100 | border-color: #ddd; 101 | color: #444; 102 | } 103 | .menu-content { 104 | background: #ffffff; 105 | } 106 | .menu-item { 107 | border-color: transparent; 108 | _border-color: #fafafa; 109 | } 110 | .menu-active { 111 | border-color: #b7d2ff; 112 | color: #000000; 113 | background: #eaf2ff; 114 | } 115 | .menu-active-disabled { 116 | border-color: transparent; 117 | background: transparent; 118 | color: #444; 119 | } 120 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/menubutton.css: -------------------------------------------------------------------------------- 1 | .m-btn-downarrow, 2 | .s-btn-downarrow { 3 | display: inline-block; 4 | position: absolute; 5 | width: 16px; 6 | height: 16px; 7 | font-size: 1px; 8 | right: 0; 9 | top: 50%; 10 | margin-top: -8px; 11 | } 12 | .m-btn-active, 13 | .s-btn-active { 14 | background: #eaf2ff; 15 | color: #000000; 16 | border: 1px solid #b7d2ff; 17 | filter: none; 18 | } 19 | .m-btn-plain-active, 20 | .s-btn-plain-active { 21 | background: transparent; 22 | padding: 0; 23 | border-width: 1px; 24 | border-style: solid; 25 | -moz-border-radius: 5px 5px 5px 5px; 26 | -webkit-border-radius: 5px 5px 5px 5px; 27 | border-radius: 5px 5px 5px 5px; 28 | } 29 | .m-btn .l-btn-left .l-btn-text { 30 | margin-right: 20px; 31 | } 32 | .m-btn .l-btn-icon-right .l-btn-text { 33 | margin-right: 40px; 34 | } 35 | .m-btn .l-btn-icon-right .l-btn-icon { 36 | right: 20px; 37 | } 38 | .m-btn .l-btn-icon-top .l-btn-text { 39 | margin-right: 4px; 40 | margin-bottom: 14px; 41 | } 42 | .m-btn .l-btn-icon-bottom .l-btn-text { 43 | margin-right: 4px; 44 | margin-bottom: 34px; 45 | } 46 | .m-btn .l-btn-icon-bottom .l-btn-icon { 47 | top: auto; 48 | bottom: 20px; 49 | } 50 | .m-btn .l-btn-icon-top .m-btn-downarrow, 51 | .m-btn .l-btn-icon-bottom .m-btn-downarrow { 52 | top: auto; 53 | bottom: 0px; 54 | left: 50%; 55 | margin-left: -8px; 56 | } 57 | .m-btn-line { 58 | display: inline-block; 59 | position: absolute; 60 | font-size: 1px; 61 | display: none; 62 | } 63 | .m-btn .l-btn-left .m-btn-line { 64 | right: 0; 65 | width: 16px; 66 | height: 500px; 67 | border-style: solid; 68 | border-color: #aac5e7; 69 | border-width: 0 0 0 1px; 70 | } 71 | .m-btn .l-btn-icon-top .m-btn-line, 72 | .m-btn .l-btn-icon-bottom .m-btn-line { 73 | left: 0; 74 | bottom: 0; 75 | width: 500px; 76 | height: 16px; 77 | border-width: 1px 0 0 0; 78 | } 79 | .m-btn-large .l-btn-icon-right .l-btn-text { 80 | margin-right: 56px; 81 | } 82 | .m-btn-large .l-btn-icon-bottom .l-btn-text { 83 | margin-bottom: 50px; 84 | } 85 | .m-btn-downarrow, 86 | .s-btn-downarrow { 87 | background: url('images/menu_arrows.png') no-repeat 0 center; 88 | } 89 | .m-btn-plain-active, 90 | .s-btn-plain-active { 91 | border-color: #b7d2ff; 92 | background-color: #eaf2ff; 93 | color: #000000; 94 | } 95 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/messager.css: -------------------------------------------------------------------------------- 1 | .messager-body { 2 | padding: 10px 10px 30px 10px; 3 | overflow: auto; 4 | } 5 | .messager-button { 6 | text-align: center; 7 | padding: 5px; 8 | } 9 | .messager-button .l-btn { 10 | width: 70px; 11 | } 12 | .messager-icon { 13 | float: left; 14 | width: 32px; 15 | height: 32px; 16 | margin: 0 10px 10px 0; 17 | } 18 | .messager-error { 19 | background: url('images/messager_icons.png') no-repeat scroll -64px 0; 20 | } 21 | .messager-info { 22 | background: url('images/messager_icons.png') no-repeat scroll 0 0; 23 | } 24 | .messager-question { 25 | background: url('images/messager_icons.png') no-repeat scroll -32px 0; 26 | } 27 | .messager-warning { 28 | background: url('images/messager_icons.png') no-repeat scroll -96px 0; 29 | } 30 | .messager-progress { 31 | padding: 10px; 32 | } 33 | .messager-p-msg { 34 | margin-bottom: 5px; 35 | } 36 | .messager-body .messager-input { 37 | width: 100%; 38 | padding: 4px 0; 39 | outline-style: none; 40 | border: 1px solid #95B8E7; 41 | } 42 | .window-thinborder .messager-button { 43 | padding-bottom: 8px; 44 | } 45 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/numberbox.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/default/numberbox.css -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/pagination.css: -------------------------------------------------------------------------------- 1 | .pagination { 2 | zoom: 1; 3 | } 4 | .pagination table { 5 | float: left; 6 | height: 30px; 7 | } 8 | .pagination td { 9 | border: 0; 10 | } 11 | .pagination-btn-separator { 12 | float: left; 13 | height: 24px; 14 | border-left: 1px solid #ccc; 15 | border-right: 1px solid #fff; 16 | margin: 3px 1px; 17 | } 18 | .pagination .pagination-num { 19 | border-width: 1px; 20 | border-style: solid; 21 | margin: 0 2px; 22 | padding: 2px; 23 | width: 2em; 24 | height: auto; 25 | } 26 | .pagination-page-list { 27 | margin: 0px 6px; 28 | padding: 1px 2px; 29 | width: auto; 30 | height: auto; 31 | border-width: 1px; 32 | border-style: solid; 33 | } 34 | .pagination-info { 35 | float: right; 36 | margin: 0 6px; 37 | padding: 0; 38 | height: 30px; 39 | line-height: 30px; 40 | font-size: 12px; 41 | } 42 | .pagination span { 43 | font-size: 12px; 44 | } 45 | .pagination-link .l-btn-text { 46 | width: 24px; 47 | text-align: center; 48 | margin: 0; 49 | } 50 | .pagination-first { 51 | background: url('images/pagination_icons.png') no-repeat 0 center; 52 | } 53 | .pagination-prev { 54 | background: url('images/pagination_icons.png') no-repeat -16px center; 55 | } 56 | .pagination-next { 57 | background: url('images/pagination_icons.png') no-repeat -32px center; 58 | } 59 | .pagination-last { 60 | background: url('images/pagination_icons.png') no-repeat -48px center; 61 | } 62 | .pagination-load { 63 | background: url('images/pagination_icons.png') no-repeat -64px center; 64 | } 65 | .pagination-loading { 66 | background: url('images/loading.gif') no-repeat center center; 67 | } 68 | .pagination-page-list, 69 | .pagination .pagination-num { 70 | border-color: #95B8E7; 71 | } 72 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/passwordbox.css: -------------------------------------------------------------------------------- 1 | .passwordbox-open { 2 | background: url('images/passwordbox_open.png') no-repeat center center; 3 | } 4 | .passwordbox-close { 5 | background: url('images/passwordbox_close.png') no-repeat center center; 6 | } 7 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/progressbar.css: -------------------------------------------------------------------------------- 1 | .progressbar { 2 | border-width: 1px; 3 | border-style: solid; 4 | -moz-border-radius: 5px 5px 5px 5px; 5 | -webkit-border-radius: 5px 5px 5px 5px; 6 | border-radius: 5px 5px 5px 5px; 7 | overflow: hidden; 8 | position: relative; 9 | } 10 | .progressbar-text { 11 | text-align: center; 12 | position: absolute; 13 | } 14 | .progressbar-value { 15 | position: relative; 16 | overflow: hidden; 17 | width: 0; 18 | -moz-border-radius: 5px 0 0 5px; 19 | -webkit-border-radius: 5px 0 0 5px; 20 | border-radius: 5px 0 0 5px; 21 | } 22 | .progressbar { 23 | border-color: #95B8E7; 24 | } 25 | .progressbar-text { 26 | color: #000000; 27 | font-size: 12px; 28 | } 29 | .progressbar-value .progressbar-text { 30 | background-color: #ffe48d; 31 | color: #000000; 32 | } 33 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/propertygrid.css: -------------------------------------------------------------------------------- 1 | .propertygrid .datagrid-view1 .datagrid-body td { 2 | padding-bottom: 1px; 3 | border-width: 0 1px 0 0; 4 | } 5 | .propertygrid .datagrid-group { 6 | height: 21px; 7 | overflow: hidden; 8 | border-width: 0 0 1px 0; 9 | border-style: solid; 10 | } 11 | .propertygrid .datagrid-group span { 12 | font-weight: bold; 13 | } 14 | .propertygrid .datagrid-view1 .datagrid-body td { 15 | border-color: #dddddd; 16 | } 17 | .propertygrid .datagrid-view1 .datagrid-group { 18 | border-color: #E0ECFF; 19 | } 20 | .propertygrid .datagrid-view2 .datagrid-group { 21 | border-color: #dddddd; 22 | } 23 | .propertygrid .datagrid-group, 24 | .propertygrid .datagrid-view1 .datagrid-body, 25 | .propertygrid .datagrid-view1 .datagrid-row-over, 26 | .propertygrid .datagrid-view1 .datagrid-row-selected { 27 | background: #E0ECFF; 28 | } 29 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/searchbox.css: -------------------------------------------------------------------------------- 1 | .searchbox-button { 2 | width: 18px; 3 | height: 20px; 4 | overflow: hidden; 5 | display: inline-block; 6 | vertical-align: top; 7 | cursor: pointer; 8 | opacity: 0.6; 9 | filter: alpha(opacity=60); 10 | } 11 | .searchbox-button-hover { 12 | opacity: 1.0; 13 | filter: alpha(opacity=100); 14 | } 15 | .searchbox .l-btn-plain { 16 | border: 0; 17 | padding: 0; 18 | vertical-align: top; 19 | opacity: 0.6; 20 | filter: alpha(opacity=60); 21 | -moz-border-radius: 0 0 0 0; 22 | -webkit-border-radius: 0 0 0 0; 23 | border-radius: 0 0 0 0; 24 | } 25 | .searchbox .l-btn-plain:hover { 26 | border: 0; 27 | padding: 0; 28 | opacity: 1.0; 29 | filter: alpha(opacity=100); 30 | -moz-border-radius: 0 0 0 0; 31 | -webkit-border-radius: 0 0 0 0; 32 | border-radius: 0 0 0 0; 33 | } 34 | .searchbox a.m-btn-plain-active { 35 | -moz-border-radius: 0 0 0 0; 36 | -webkit-border-radius: 0 0 0 0; 37 | border-radius: 0 0 0 0; 38 | } 39 | .searchbox .m-btn-active { 40 | border-width: 0 1px 0 0; 41 | -moz-border-radius: 0 0 0 0; 42 | -webkit-border-radius: 0 0 0 0; 43 | border-radius: 0 0 0 0; 44 | } 45 | .searchbox .textbox-button-right { 46 | border-width: 0 0 0 1px; 47 | } 48 | .searchbox .textbox-button-left { 49 | border-width: 0 1px 0 0; 50 | } 51 | .searchbox-button { 52 | background: url('images/searchbox_button.png') no-repeat center center; 53 | } 54 | .searchbox .l-btn-plain { 55 | background: #E0ECFF; 56 | } 57 | .searchbox .l-btn-plain-disabled, 58 | .searchbox .l-btn-plain-disabled:hover { 59 | opacity: 0.5; 60 | filter: alpha(opacity=50); 61 | } 62 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/slider.css: -------------------------------------------------------------------------------- 1 | .slider-disabled { 2 | opacity: 0.5; 3 | filter: alpha(opacity=50); 4 | } 5 | .slider-h { 6 | height: 22px; 7 | } 8 | .slider-v { 9 | width: 22px; 10 | } 11 | .slider-inner { 12 | position: relative; 13 | height: 6px; 14 | top: 7px; 15 | border-width: 1px; 16 | border-style: solid; 17 | border-radius: 5px; 18 | } 19 | .slider-handle { 20 | position: absolute; 21 | display: block; 22 | outline: none; 23 | width: 20px; 24 | height: 20px; 25 | top: 50%; 26 | margin-top: -10px; 27 | margin-left: -10px; 28 | } 29 | .slider-tip { 30 | position: absolute; 31 | display: inline-block; 32 | line-height: 12px; 33 | font-size: 12px; 34 | white-space: nowrap; 35 | top: -22px; 36 | } 37 | .slider-rule { 38 | position: relative; 39 | top: 15px; 40 | } 41 | .slider-rule span { 42 | position: absolute; 43 | display: inline-block; 44 | font-size: 0; 45 | height: 5px; 46 | border-width: 0 0 0 1px; 47 | border-style: solid; 48 | } 49 | .slider-rulelabel { 50 | position: relative; 51 | top: 20px; 52 | } 53 | .slider-rulelabel span { 54 | position: absolute; 55 | display: inline-block; 56 | font-size: 12px; 57 | } 58 | .slider-v .slider-inner { 59 | width: 6px; 60 | left: 7px; 61 | top: 0; 62 | float: left; 63 | } 64 | .slider-v .slider-handle { 65 | left: 50%; 66 | margin-top: -10px; 67 | } 68 | .slider-v .slider-tip { 69 | left: -10px; 70 | margin-top: -6px; 71 | } 72 | .slider-v .slider-rule { 73 | float: left; 74 | top: 0; 75 | left: 16px; 76 | } 77 | .slider-v .slider-rule span { 78 | width: 5px; 79 | height: 'auto'; 80 | border-left: 0; 81 | border-width: 1px 0 0 0; 82 | border-style: solid; 83 | } 84 | .slider-v .slider-rulelabel { 85 | float: left; 86 | top: 0; 87 | left: 23px; 88 | } 89 | .slider-handle { 90 | background: url('images/slider_handle.png') no-repeat; 91 | } 92 | .slider-inner { 93 | border-color: #95B8E7; 94 | background: #E0ECFF; 95 | } 96 | .slider-rule span { 97 | border-color: #95B8E7; 98 | } 99 | .slider-rulelabel span { 100 | color: #000000; 101 | } 102 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/spinner.css: -------------------------------------------------------------------------------- 1 | .spinner-arrow { 2 | background-color: #E0ECFF; 3 | display: inline-block; 4 | overflow: hidden; 5 | vertical-align: top; 6 | margin: 0; 7 | padding: 0; 8 | opacity: 1.0; 9 | filter: alpha(opacity=100); 10 | width: 18px; 11 | } 12 | .spinner-arrow-up, 13 | .spinner-arrow-down { 14 | opacity: 0.6; 15 | filter: alpha(opacity=60); 16 | display: block; 17 | font-size: 1px; 18 | width: 18px; 19 | height: 10px; 20 | width: 100%; 21 | height: 50%; 22 | color: #444; 23 | outline-style: none; 24 | } 25 | .spinner-arrow-hover { 26 | background-color: #eaf2ff; 27 | opacity: 1.0; 28 | filter: alpha(opacity=100); 29 | } 30 | .spinner-arrow-up:hover, 31 | .spinner-arrow-down:hover { 32 | opacity: 1.0; 33 | filter: alpha(opacity=100); 34 | background-color: #eaf2ff; 35 | } 36 | .textbox-icon-disabled .spinner-arrow-up:hover, 37 | .textbox-icon-disabled .spinner-arrow-down:hover { 38 | opacity: 0.6; 39 | filter: alpha(opacity=60); 40 | background-color: #E0ECFF; 41 | cursor: default; 42 | } 43 | .spinner .textbox-icon-disabled { 44 | opacity: 0.6; 45 | filter: alpha(opacity=60); 46 | } 47 | .spinner-arrow-up { 48 | background: url('images/spinner_arrows.png') no-repeat 1px center; 49 | } 50 | .spinner-arrow-down { 51 | background: url('images/spinner_arrows.png') no-repeat -15px center; 52 | } 53 | .spinner-button-up { 54 | background: url('images/spinner_arrows.png') no-repeat -32px center; 55 | } 56 | .spinner-button-down { 57 | background: url('images/spinner_arrows.png') no-repeat -48px center; 58 | } 59 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/splitbutton.css: -------------------------------------------------------------------------------- 1 | .s-btn:hover .m-btn-line, 2 | .s-btn-active .m-btn-line, 3 | .s-btn-plain-active .m-btn-line { 4 | display: inline-block; 5 | } 6 | .l-btn:hover .s-btn-downarrow, 7 | .s-btn-active .s-btn-downarrow, 8 | .s-btn-plain-active .s-btn-downarrow { 9 | border-style: solid; 10 | border-color: #aac5e7; 11 | border-width: 0 0 0 1px; 12 | } 13 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/switchbutton.css: -------------------------------------------------------------------------------- 1 | .switchbutton { 2 | text-decoration: none; 3 | display: inline-block; 4 | overflow: hidden; 5 | vertical-align: middle; 6 | margin: 0; 7 | padding: 0; 8 | cursor: pointer; 9 | background: #bbb; 10 | border: 1px solid #bbb; 11 | -moz-border-radius: 5px 5px 5px 5px; 12 | -webkit-border-radius: 5px 5px 5px 5px; 13 | border-radius: 5px 5px 5px 5px; 14 | } 15 | .switchbutton-inner { 16 | display: inline-block; 17 | overflow: hidden; 18 | position: relative; 19 | top: -1px; 20 | left: -1px; 21 | } 22 | .switchbutton-on, 23 | .switchbutton-off, 24 | .switchbutton-handle { 25 | display: inline-block; 26 | text-align: center; 27 | height: 100%; 28 | float: left; 29 | font-size: 12px; 30 | -moz-border-radius: 5px 5px 5px 5px; 31 | -webkit-border-radius: 5px 5px 5px 5px; 32 | border-radius: 5px 5px 5px 5px; 33 | } 34 | .switchbutton-on { 35 | background: #ffe48d; 36 | color: #000000; 37 | } 38 | .switchbutton-off { 39 | background-color: #ffffff; 40 | color: #000000; 41 | } 42 | .switchbutton-on, 43 | .switchbutton-reversed .switchbutton-off { 44 | -moz-border-radius: 5px 0 0 5px; 45 | -webkit-border-radius: 5px 0 0 5px; 46 | border-radius: 5px 0 0 5px; 47 | } 48 | .switchbutton-off, 49 | .switchbutton-reversed .switchbutton-on { 50 | -moz-border-radius: 0 5px 5px 0; 51 | -webkit-border-radius: 0 5px 5px 0; 52 | border-radius: 0 5px 5px 0; 53 | } 54 | .switchbutton-handle { 55 | position: absolute; 56 | top: 0; 57 | left: 50%; 58 | background-color: #ffffff; 59 | color: #000000; 60 | border: 1px solid #bbb; 61 | -moz-box-shadow: 0 0 3px 0 #bbb; 62 | -webkit-box-shadow: 0 0 3px 0 #bbb; 63 | box-shadow: 0 0 3px 0 #bbb; 64 | } 65 | .switchbutton-value { 66 | position: absolute; 67 | top: 0; 68 | left: -5000px; 69 | } 70 | .switchbutton-disabled { 71 | opacity: 0.5; 72 | filter: alpha(opacity=50); 73 | } 74 | .switchbutton-disabled, 75 | .switchbutton-readonly { 76 | cursor: default; 77 | } 78 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/tagbox.css: -------------------------------------------------------------------------------- 1 | .tagbox { 2 | cursor: text; 3 | } 4 | .tagbox .textbox-text { 5 | float: left; 6 | } 7 | .tagbox-label { 8 | position: relative; 9 | display: block; 10 | margin: 4px 0 0 4px; 11 | padding: 0 20px 0 4px; 12 | float: left; 13 | vertical-align: top; 14 | text-decoration: none; 15 | -moz-border-radius: 5px 5px 5px 5px; 16 | -webkit-border-radius: 5px 5px 5px 5px; 17 | border-radius: 5px 5px 5px 5px; 18 | background: #eaf2ff; 19 | color: #000000; 20 | } 21 | .tagbox-remove { 22 | background: url('images/tagbox_icons.png') no-repeat -16px center; 23 | position: absolute; 24 | display: block; 25 | width: 16px; 26 | height: 16px; 27 | right: 2px; 28 | top: 50%; 29 | margin-top: -8px; 30 | opacity: 0.6; 31 | filter: alpha(opacity=60); 32 | } 33 | .tagbox-remove:hover { 34 | opacity: 1; 35 | filter: alpha(opacity=100); 36 | } 37 | .textbox-disabled .tagbox-label { 38 | cursor: default; 39 | } 40 | .textbox-disabled .tagbox-remove:hover { 41 | cursor: default; 42 | opacity: 0.6; 43 | filter: alpha(opacity=60); 44 | } 45 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/textbox.css: -------------------------------------------------------------------------------- 1 | .textbox { 2 | position: relative; 3 | border: 1px solid #95B8E7; 4 | background-color: #fff; 5 | vertical-align: middle; 6 | display: inline-block; 7 | overflow: hidden; 8 | white-space: nowrap; 9 | margin: 0; 10 | padding: 0; 11 | -moz-border-radius: 5px 5px 5px 5px; 12 | -webkit-border-radius: 5px 5px 5px 5px; 13 | border-radius: 5px 5px 5px 5px; 14 | } 15 | .textbox .textbox-text { 16 | font-size: 12px; 17 | border: 0; 18 | margin: 0; 19 | padding: 4px; 20 | white-space: normal; 21 | vertical-align: top; 22 | outline-style: none; 23 | resize: none; 24 | -moz-border-radius: 5px 5px 5px 5px; 25 | -webkit-border-radius: 5px 5px 5px 5px; 26 | border-radius: 5px 5px 5px 5px; 27 | } 28 | .textbox .textbox-text::-ms-clear, 29 | .textbox .textbox-text::-ms-reveal { 30 | display: none; 31 | } 32 | .textbox textarea.textbox-text { 33 | white-space: pre-wrap; 34 | } 35 | .textbox .textbox-prompt { 36 | font-size: 12px; 37 | color: #aaa; 38 | } 39 | .textbox .textbox-bgicon { 40 | background-position: 3px center; 41 | padding-left: 21px; 42 | } 43 | .textbox .textbox-button, 44 | .textbox .textbox-button:hover { 45 | position: absolute; 46 | top: 0; 47 | padding: 0; 48 | vertical-align: top; 49 | -moz-border-radius: 0 0 0 0; 50 | -webkit-border-radius: 0 0 0 0; 51 | border-radius: 0 0 0 0; 52 | } 53 | .textbox .textbox-button-right, 54 | .textbox .textbox-button-right:hover { 55 | right: 0; 56 | border-width: 0 0 0 1px; 57 | } 58 | .textbox .textbox-button-left, 59 | .textbox .textbox-button-left:hover { 60 | left: 0; 61 | border-width: 0 1px 0 0; 62 | } 63 | .textbox .textbox-button-top, 64 | .textbox .textbox-button-top:hover { 65 | left: 0; 66 | border-width: 0 0 1px 0; 67 | } 68 | .textbox .textbox-button-bottom, 69 | .textbox .textbox-button-bottom:hover { 70 | top: auto; 71 | bottom: 0; 72 | left: 0; 73 | border-width: 1px 0 0 0; 74 | } 75 | .textbox-addon { 76 | position: absolute; 77 | top: 0; 78 | } 79 | .textbox-label { 80 | display: inline-block; 81 | width: 80px; 82 | height: 22px; 83 | line-height: 22px; 84 | vertical-align: middle; 85 | overflow: hidden; 86 | text-overflow: ellipsis; 87 | white-space: nowrap; 88 | margin: 0; 89 | padding-right: 5px; 90 | } 91 | .textbox-label-after { 92 | padding-left: 5px; 93 | padding-right: 0; 94 | } 95 | .textbox-label-top { 96 | display: block; 97 | width: auto; 98 | padding: 0; 99 | } 100 | .textbox-disabled, 101 | .textbox-label-disabled { 102 | opacity: 0.6; 103 | filter: alpha(opacity=60); 104 | } 105 | .textbox-icon { 106 | display: inline-block; 107 | width: 18px; 108 | height: 20px; 109 | overflow: hidden; 110 | vertical-align: top; 111 | background-position: center center; 112 | cursor: pointer; 113 | opacity: 0.6; 114 | filter: alpha(opacity=60); 115 | text-decoration: none; 116 | outline-style: none; 117 | } 118 | .textbox-icon-disabled, 119 | .textbox-icon-readonly { 120 | cursor: default; 121 | } 122 | .textbox-icon:hover { 123 | opacity: 1.0; 124 | filter: alpha(opacity=100); 125 | } 126 | .textbox-icon-disabled:hover { 127 | opacity: 0.6; 128 | filter: alpha(opacity=60); 129 | } 130 | .textbox-focused { 131 | border-color: #6b9cde; 132 | -moz-box-shadow: 0 0 3px 0 #95B8E7; 133 | -webkit-box-shadow: 0 0 3px 0 #95B8E7; 134 | box-shadow: 0 0 3px 0 #95B8E7; 135 | } 136 | .textbox-invalid { 137 | border-color: #ffa8a8; 138 | background-color: #fff3f3; 139 | } 140 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/tooltip.css: -------------------------------------------------------------------------------- 1 | .tooltip { 2 | position: absolute; 3 | display: none; 4 | z-index: 9900000; 5 | outline: none; 6 | opacity: 1; 7 | filter: alpha(opacity=100); 8 | padding: 5px; 9 | border-width: 1px; 10 | border-style: solid; 11 | border-radius: 5px; 12 | -moz-border-radius: 5px 5px 5px 5px; 13 | -webkit-border-radius: 5px 5px 5px 5px; 14 | border-radius: 5px 5px 5px 5px; 15 | } 16 | .tooltip-content { 17 | font-size: 12px; 18 | } 19 | .tooltip-arrow-outer, 20 | .tooltip-arrow { 21 | position: absolute; 22 | width: 0; 23 | height: 0; 24 | line-height: 0; 25 | font-size: 0; 26 | border-style: solid; 27 | border-width: 6px; 28 | border-color: transparent; 29 | _border-color: tomato; 30 | _filter: chroma(color=tomato); 31 | } 32 | .tooltip-arrow { 33 | display: none \9; 34 | } 35 | .tooltip-right .tooltip-arrow-outer { 36 | left: 0; 37 | top: 50%; 38 | margin: -6px 0 0 -13px; 39 | } 40 | .tooltip-right .tooltip-arrow { 41 | left: 0; 42 | top: 50%; 43 | margin: -6px 0 0 -12px; 44 | } 45 | .tooltip-left .tooltip-arrow-outer { 46 | right: 0; 47 | top: 50%; 48 | margin: -6px -13px 0 0; 49 | } 50 | .tooltip-left .tooltip-arrow { 51 | right: 0; 52 | top: 50%; 53 | margin: -6px -12px 0 0; 54 | } 55 | .tooltip-top .tooltip-arrow-outer { 56 | bottom: 0; 57 | left: 50%; 58 | margin: 0 0 -13px -6px; 59 | } 60 | .tooltip-top .tooltip-arrow { 61 | bottom: 0; 62 | left: 50%; 63 | margin: 0 0 -12px -6px; 64 | } 65 | .tooltip-bottom .tooltip-arrow-outer { 66 | top: 0; 67 | left: 50%; 68 | margin: -13px 0 0 -6px; 69 | } 70 | .tooltip-bottom .tooltip-arrow { 71 | top: 0; 72 | left: 50%; 73 | margin: -12px 0 0 -6px; 74 | } 75 | .tooltip { 76 | background-color: #ffffff; 77 | border-color: #95B8E7; 78 | color: #000000; 79 | } 80 | .tooltip-right .tooltip-arrow-outer { 81 | border-right-color: #95B8E7; 82 | } 83 | .tooltip-right .tooltip-arrow { 84 | border-right-color: #ffffff; 85 | } 86 | .tooltip-left .tooltip-arrow-outer { 87 | border-left-color: #95B8E7; 88 | } 89 | .tooltip-left .tooltip-arrow { 90 | border-left-color: #ffffff; 91 | } 92 | .tooltip-top .tooltip-arrow-outer { 93 | border-top-color: #95B8E7; 94 | } 95 | .tooltip-top .tooltip-arrow { 96 | border-top-color: #ffffff; 97 | } 98 | .tooltip-bottom .tooltip-arrow-outer { 99 | border-bottom-color: #95B8E7; 100 | } 101 | .tooltip-bottom .tooltip-arrow { 102 | border-bottom-color: #ffffff; 103 | } 104 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/tree.css: -------------------------------------------------------------------------------- 1 | .tree { 2 | margin: 0; 3 | padding: 0; 4 | list-style-type: none; 5 | } 6 | .tree li { 7 | white-space: nowrap; 8 | } 9 | .tree li ul { 10 | list-style-type: none; 11 | margin: 0; 12 | padding: 0; 13 | } 14 | .tree-node { 15 | height: 18px; 16 | white-space: nowrap; 17 | cursor: pointer; 18 | } 19 | .tree-hit { 20 | cursor: pointer; 21 | } 22 | .tree-expanded, 23 | .tree-collapsed, 24 | .tree-folder, 25 | .tree-file, 26 | .tree-checkbox, 27 | .tree-indent { 28 | display: inline-block; 29 | width: 16px; 30 | height: 18px; 31 | vertical-align: top; 32 | overflow: hidden; 33 | } 34 | .tree-expanded { 35 | background: url('images/tree_icons.png') no-repeat -18px 0px; 36 | } 37 | .tree-expanded-hover { 38 | background: url('images/tree_icons.png') no-repeat -50px 0px; 39 | } 40 | .tree-collapsed { 41 | background: url('images/tree_icons.png') no-repeat 0px 0px; 42 | } 43 | .tree-collapsed-hover { 44 | background: url('images/tree_icons.png') no-repeat -32px 0px; 45 | } 46 | .tree-lines .tree-expanded, 47 | .tree-lines .tree-root-first .tree-expanded { 48 | background: url('images/tree_icons.png') no-repeat -144px 0; 49 | } 50 | .tree-lines .tree-collapsed, 51 | .tree-lines .tree-root-first .tree-collapsed { 52 | background: url('images/tree_icons.png') no-repeat -128px 0; 53 | } 54 | .tree-lines .tree-node-last .tree-expanded, 55 | .tree-lines .tree-root-one .tree-expanded { 56 | background: url('images/tree_icons.png') no-repeat -80px 0; 57 | } 58 | .tree-lines .tree-node-last .tree-collapsed, 59 | .tree-lines .tree-root-one .tree-collapsed { 60 | background: url('images/tree_icons.png') no-repeat -64px 0; 61 | } 62 | .tree-line { 63 | background: url('images/tree_icons.png') no-repeat -176px 0; 64 | } 65 | .tree-join { 66 | background: url('images/tree_icons.png') no-repeat -192px 0; 67 | } 68 | .tree-joinbottom { 69 | background: url('images/tree_icons.png') no-repeat -160px 0; 70 | } 71 | .tree-folder { 72 | background: url('images/tree_icons.png') no-repeat -208px 0; 73 | } 74 | .tree-folder-open { 75 | background: url('images/tree_icons.png') no-repeat -224px 0; 76 | } 77 | .tree-file { 78 | background: url('images/tree_icons.png') no-repeat -240px 0; 79 | } 80 | .tree-loading { 81 | background: url('images/loading.gif') no-repeat center center; 82 | } 83 | .tree-checkbox0 { 84 | background: url('images/tree_icons.png') no-repeat -208px -18px; 85 | } 86 | .tree-checkbox1 { 87 | background: url('images/tree_icons.png') no-repeat -224px -18px; 88 | } 89 | .tree-checkbox2 { 90 | background: url('images/tree_icons.png') no-repeat -240px -18px; 91 | } 92 | .tree-title { 93 | font-size: 12px; 94 | display: inline-block; 95 | text-decoration: none; 96 | vertical-align: top; 97 | white-space: nowrap; 98 | padding: 0 2px; 99 | height: 18px; 100 | line-height: 18px; 101 | } 102 | .tree-node-proxy { 103 | font-size: 12px; 104 | line-height: 20px; 105 | padding: 0 2px 0 20px; 106 | border-width: 1px; 107 | border-style: solid; 108 | z-index: 9900000; 109 | } 110 | .tree-dnd-icon { 111 | display: inline-block; 112 | position: absolute; 113 | width: 16px; 114 | height: 18px; 115 | left: 2px; 116 | top: 50%; 117 | margin-top: -9px; 118 | } 119 | .tree-dnd-yes { 120 | background: url('images/tree_icons.png') no-repeat -256px 0; 121 | } 122 | .tree-dnd-no { 123 | background: url('images/tree_icons.png') no-repeat -256px -18px; 124 | } 125 | .tree-node-top { 126 | border-top: 1px dotted red; 127 | } 128 | .tree-node-bottom { 129 | border-bottom: 1px dotted red; 130 | } 131 | .tree-node-append .tree-title { 132 | border: 1px dotted red; 133 | } 134 | .tree-editor { 135 | border: 1px solid #95B8E7; 136 | font-size: 12px; 137 | line-height: 16px; 138 | padding: 0 4px; 139 | margin: 0; 140 | width: 80px; 141 | outline-style: none; 142 | vertical-align: top; 143 | position: absolute; 144 | top: 0; 145 | } 146 | .tree-node-proxy { 147 | background-color: #ffffff; 148 | color: #000000; 149 | border-color: #95B8E7; 150 | } 151 | .tree-node-hover { 152 | background: #eaf2ff; 153 | color: #000000; 154 | } 155 | .tree-node-selected { 156 | background: #ffe48d; 157 | color: #000000; 158 | } 159 | .tree-node-hidden { 160 | display: none; 161 | } 162 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/validatebox.css: -------------------------------------------------------------------------------- 1 | .validatebox-invalid { 2 | border-color: #ffa8a8; 3 | background-color: #fff3f3; 4 | color: #000; 5 | } 6 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/default/window.css: -------------------------------------------------------------------------------- 1 | .window { 2 | overflow: hidden; 3 | padding: 5px; 4 | border-width: 1px; 5 | border-style: solid; 6 | } 7 | .window .window-header { 8 | background: transparent; 9 | padding: 0px 0px 6px 0px; 10 | } 11 | .window .window-body { 12 | border-width: 1px; 13 | border-style: solid; 14 | border-top-width: 0px; 15 | } 16 | .window .window-body-noheader { 17 | border-top-width: 1px; 18 | } 19 | .window .panel-body-nobottom { 20 | border-bottom-width: 0; 21 | } 22 | .window .window-header .panel-icon, 23 | .window .window-header .panel-tool { 24 | top: 50%; 25 | margin-top: -11px; 26 | } 27 | .window .window-header .panel-icon { 28 | left: 1px; 29 | } 30 | .window .window-header .panel-tool { 31 | right: 1px; 32 | } 33 | .window .window-header .panel-with-icon { 34 | padding-left: 18px; 35 | } 36 | .window-proxy { 37 | position: absolute; 38 | overflow: hidden; 39 | } 40 | .window-proxy-mask { 41 | position: absolute; 42 | filter: alpha(opacity=5); 43 | opacity: 0.05; 44 | } 45 | .window-mask { 46 | position: absolute; 47 | left: 0; 48 | top: 0; 49 | width: 100%; 50 | height: 100%; 51 | filter: alpha(opacity=40); 52 | opacity: 0.40; 53 | font-size: 1px; 54 | overflow: hidden; 55 | } 56 | .window, 57 | .window-shadow { 58 | position: absolute; 59 | -moz-border-radius: 5px 5px 5px 5px; 60 | -webkit-border-radius: 5px 5px 5px 5px; 61 | border-radius: 5px 5px 5px 5px; 62 | } 63 | .window-shadow { 64 | background: #ccc; 65 | -moz-box-shadow: 2px 2px 3px #cccccc; 66 | -webkit-box-shadow: 2px 2px 3px #cccccc; 67 | box-shadow: 2px 2px 3px #cccccc; 68 | filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=2,MakeShadow=false,ShadowOpacity=0.2); 69 | } 70 | .window, 71 | .window .window-body { 72 | border-color: #95B8E7; 73 | } 74 | .window { 75 | background-color: #E0ECFF; 76 | background: -webkit-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%); 77 | background: -moz-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%); 78 | background: -o-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%); 79 | background: linear-gradient(to bottom,#EFF5FF 0,#E0ECFF 20%); 80 | background-repeat: repeat-x; 81 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#EFF5FF,endColorstr=#E0ECFF,GradientType=0); 82 | } 83 | .window-proxy { 84 | border: 1px dashed #95B8E7; 85 | } 86 | .window-proxy-mask, 87 | .window-mask { 88 | background: #ccc; 89 | } 90 | .window .panel-footer { 91 | border: 1px solid #95B8E7; 92 | position: relative; 93 | top: -1px; 94 | } 95 | .window-thinborder { 96 | padding: 0; 97 | } 98 | .window-thinborder .window-header { 99 | padding: 5px 5px 6px 5px; 100 | } 101 | .window-thinborder .window-body { 102 | border-width: 0px; 103 | } 104 | .window-thinborder .window-header .panel-icon, 105 | .window-thinborder .window-header .panel-tool { 106 | margin-top: -9px; 107 | margin-left: 5px; 108 | margin-right: 5px; 109 | } 110 | .window-noborder { 111 | border: 0; 112 | } 113 | .window.panel-hleft .window-header { 114 | padding: 0 6px 0 0; 115 | } 116 | .window.panel-hright .window-header { 117 | padding: 0 0 0 6px; 118 | } 119 | .window.panel-hleft>.panel-header .panel-title { 120 | top: auto; 121 | left: 16px; 122 | } 123 | .window.panel-hright>.panel-header .panel-title { 124 | top: auto; 125 | right: 16px; 126 | } 127 | .window.panel-hleft>.panel-header .panel-title-up, 128 | .window.panel-hright>.panel-header .panel-title-up { 129 | bottom: 0; 130 | } 131 | .window.panel-hleft .window-body { 132 | border-width: 1px 1px 1px 0; 133 | } 134 | .window.panel-hright .window-body { 135 | border-width: 1px 0 1px 1px; 136 | } 137 | .window.panel-hleft .window-header .panel-icon { 138 | top: 1px; 139 | margin-top: 0; 140 | left: 0; 141 | } 142 | .window.panel-hright .window-header .panel-icon { 143 | top: 1px; 144 | margin-top: 0; 145 | left: auto; 146 | right: 1px; 147 | } 148 | .window.panel-hleft .window-header .panel-tool, 149 | .window.panel-hright .window-header .panel-tool { 150 | margin-top: 0; 151 | top: auto; 152 | bottom: 1px; 153 | right: auto; 154 | margin-right: 0; 155 | left: 50%; 156 | margin-left: -11px; 157 | } 158 | .window.panel-hright .window-header .panel-tool { 159 | left: auto; 160 | right: 1px; 161 | } 162 | .window-thinborder.panel-hleft .window-header { 163 | padding: 5px 6px 5px 5px; 164 | } 165 | .window-thinborder.panel-hright .window-header { 166 | padding: 5px 5px 5px 6px; 167 | } 168 | .window-thinborder.panel-hleft>.panel-header .panel-title { 169 | left: 21px; 170 | } 171 | .window-thinborder.panel-hleft>.panel-header .panel-title-up, 172 | .window-thinborder.panel-hright>.panel-header .panel-title-up { 173 | bottom: 5px; 174 | } 175 | .window-thinborder.panel-hleft .window-header .panel-icon, 176 | .window-thinborder.panel-hright .window-header .panel-icon { 177 | margin-top: 5px; 178 | } 179 | .window-thinborder.panel-hleft .window-header .panel-tool, 180 | .window-thinborder.panel-hright .window-header .panel-tool { 181 | left: 16px; 182 | bottom: 5px; 183 | } 184 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icon.css: -------------------------------------------------------------------------------- 1 | .icon-blank{ 2 | background:url('icons/blank.gif') no-repeat center center; 3 | } 4 | .icon-add{ 5 | background:url('icons/edit_add.png') no-repeat center center; 6 | } 7 | .icon-edit{ 8 | background:url('icons/pencil.png') no-repeat center center; 9 | } 10 | .icon-clear{ 11 | background:url('icons/clear.png') no-repeat center center; 12 | } 13 | .icon-remove{ 14 | background:url('icons/edit_remove.png') no-repeat center center; 15 | } 16 | .icon-save{ 17 | background:url('icons/filesave.png') no-repeat center center; 18 | } 19 | .icon-cut{ 20 | background:url('icons/cut.png') no-repeat center center; 21 | } 22 | .icon-ok{ 23 | background:url('icons/ok.png') no-repeat center center; 24 | } 25 | .icon-no{ 26 | background:url('icons/no.png') no-repeat center center; 27 | } 28 | .icon-cancel{ 29 | background:url('icons/cancel.png') no-repeat center center; 30 | } 31 | .icon-reload{ 32 | background:url('icons/reload.png') no-repeat center center; 33 | } 34 | .icon-search{ 35 | background:url('icons/search.png') no-repeat center center; 36 | } 37 | .icon-print{ 38 | background:url('icons/print.png') no-repeat center center; 39 | } 40 | .icon-help{ 41 | background:url('icons/help.png') no-repeat center center; 42 | } 43 | .icon-undo{ 44 | background:url('icons/undo.png') no-repeat center center; 45 | } 46 | .icon-redo{ 47 | background:url('icons/redo.png') no-repeat center center; 48 | } 49 | .icon-back{ 50 | background:url('icons/back.png') no-repeat center center; 51 | } 52 | .icon-sum{ 53 | background:url('icons/sum.png') no-repeat center center; 54 | } 55 | .icon-tip{ 56 | background:url('icons/tip.png') no-repeat center center; 57 | } 58 | .icon-filter{ 59 | background:url('icons/filter.png') no-repeat center center; 60 | } 61 | .icon-man{ 62 | background:url('icons/man.png') no-repeat center center; 63 | } 64 | .icon-lock{ 65 | background:url('icons/lock.png') no-repeat center center; 66 | } 67 | .icon-more{ 68 | background:url('icons/more.png') no-repeat center center; 69 | } 70 | 71 | 72 | .icon-mini-add{ 73 | background:url('icons/mini_add.png') no-repeat center center; 74 | } 75 | .icon-mini-edit{ 76 | background:url('icons/mini_edit.png') no-repeat center center; 77 | } 78 | .icon-mini-refresh{ 79 | background:url('icons/mini_refresh.png') no-repeat center center; 80 | } 81 | 82 | .icon-large-picture{ 83 | background:url('icons/large_picture.png') no-repeat center center; 84 | } 85 | .icon-large-clipart{ 86 | background:url('icons/large_clipart.png') no-repeat center center; 87 | } 88 | .icon-large-shapes{ 89 | background:url('icons/large_shapes.png') no-repeat center center; 90 | } 91 | .icon-large-smartart{ 92 | background:url('icons/large_smartart.png') no-repeat center center; 93 | } 94 | .icon-large-chart{ 95 | background:url('icons/large_chart.png') no-repeat center center; 96 | } 97 | -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/back.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/blank.gif -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/cancel.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/clear.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/cut.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/edit_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/edit_add.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/edit_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/edit_remove.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/filesave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/filesave.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/filter.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/help.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/large_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/large_chart.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/large_clipart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/large_clipart.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/large_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/large_picture.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/large_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/large_shapes.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/large_smartart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/large_smartart.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/lock.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/man.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/mini_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/mini_add.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/mini_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/mini_edit.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/mini_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/mini_refresh.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/more.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/no.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/ok.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/pencil.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/print.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/redo.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/reload.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/search.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/sum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/sum.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/tip.png -------------------------------------------------------------------------------- /public/jquery-easyui/themes/icons/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengming00/go-server-js/3d4e2189093eb28d6efc54a64e830b4571c1d3d4/public/jquery-easyui/themes/icons/undo.png -------------------------------------------------------------------------------- /session.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "io" 7 | "net/http" 8 | "net/url" 9 | "strconv" 10 | "sync" 11 | "time" 12 | 13 | "github.com/dop251/goja" 14 | ) 15 | 16 | type Session struct { 17 | mLastTimeAccessed time.Time 18 | mValues map[string]interface{} 19 | } 20 | 21 | type SessionMgr struct { 22 | mCookieName string // 客户端cookie名称 23 | mLock sync.RWMutex // 互斥(保证线程安全) 24 | mMaxLifeTimeSec int64 // 垃圾回收时间(秒) 25 | 26 | mSessions map[string]*Session 27 | } 28 | 29 | func NewSessionMgr(cookieName string, maxLifeTimeSec int64) *SessionMgr { 30 | mgr := &SessionMgr{mCookieName: cookieName, mMaxLifeTimeSec: maxLifeTimeSec, mSessions: make(map[string]*Session)} 31 | go mgr.GC() 32 | return mgr 33 | } 34 | 35 | func (mgr *SessionMgr) StartSession(w http.ResponseWriter, r *http.Request) string { 36 | mgr.mLock.Lock() 37 | defer mgr.mLock.Unlock() 38 | 39 | var sessionID string 40 | cookie, err := r.Cookie(mgr.mCookieName) 41 | if err == nil { 42 | if session, ok := mgr.mSessions[cookie.Value]; ok { 43 | session.mLastTimeAccessed = time.Now() 44 | sessionID = cookie.Value 45 | } 46 | } 47 | 48 | if sessionID == "" { 49 | sessionID = url.QueryEscape(mgr.NewSessionID()) 50 | session := &Session{mLastTimeAccessed: time.Now(), mValues: make(map[string]interface{})} 51 | mgr.mSessions[sessionID] = session 52 | } 53 | 54 | cookie = &http.Cookie{Name: mgr.mCookieName, Value: sessionID, Path: "/", HttpOnly: true, MaxAge: int(mgr.mMaxLifeTimeSec)} 55 | http.SetCookie(w, cookie) 56 | return sessionID 57 | } 58 | 59 | func (mgr *SessionMgr) EndSession(w http.ResponseWriter, r *http.Request) { 60 | cookie, err := r.Cookie(mgr.mCookieName) 61 | if err != nil || cookie.Value == "" { 62 | return 63 | } 64 | mgr.mLock.Lock() 65 | defer mgr.mLock.Unlock() 66 | 67 | delete(mgr.mSessions, cookie.Value) 68 | 69 | // 让浏览器cookie立刻过期 70 | cookie = &http.Cookie{Name: mgr.mCookieName, Path: "/", HttpOnly: true, MaxAge: -1} 71 | http.SetCookie(w, cookie) 72 | } 73 | 74 | func (mgr *SessionMgr) EndSessionByID(sessionID string) { 75 | mgr.mLock.Lock() 76 | defer mgr.mLock.Unlock() 77 | 78 | delete(mgr.mSessions, sessionID) 79 | } 80 | 81 | func (mgr *SessionMgr) SetSessionVal(sessionID string, key string, value interface{}) { 82 | mgr.mLock.Lock() 83 | defer mgr.mLock.Unlock() 84 | 85 | if session, ok := mgr.mSessions[sessionID]; ok { 86 | session.mValues[key] = value 87 | } 88 | } 89 | 90 | func (mgr *SessionMgr) GetSessionVal(sessionID string, key string) (interface{}, bool) { 91 | mgr.mLock.RLock() 92 | defer mgr.mLock.RUnlock() 93 | 94 | if session, ok := mgr.mSessions[sessionID]; ok { 95 | value, ok := session.mValues[key] 96 | return value, ok 97 | } 98 | return nil, false 99 | } 100 | 101 | func (mgr *SessionMgr) GetSessionIDList() []string { 102 | mgr.mLock.RLock() 103 | defer mgr.mLock.RUnlock() 104 | 105 | sessionIDList := make([]string, len(mgr.mSessions)) 106 | i := 0 107 | for k := range mgr.mSessions { 108 | sessionIDList[i] = k 109 | i++ 110 | } 111 | return sessionIDList 112 | } 113 | 114 | func (mgr *SessionMgr) GC() { 115 | for { 116 | <-time.After(time.Duration(mgr.mMaxLifeTimeSec) * time.Second) 117 | mgr.mLock.Lock() 118 | for sessionID, session := range mgr.mSessions { 119 | if session.mLastTimeAccessed.Unix()+mgr.mMaxLifeTimeSec < time.Now().Unix() { 120 | delete(mgr.mSessions, sessionID) 121 | } 122 | } 123 | mgr.mLock.Unlock() 124 | } 125 | } 126 | 127 | func (mgr *SessionMgr) NewSessionID() string { 128 | // todo 为了更加安全,sessionID应该考虑加上验证 129 | b := make([]byte, 32) 130 | if _, err := io.ReadFull(rand.Reader, b); err != nil { 131 | nano := time.Now().UnixNano() 132 | return strconv.FormatInt(nano, 10) 133 | } 134 | return base64.URLEncoding.EncodeToString(b) 135 | } 136 | 137 | ///////////////////////////////////////////////////////////////////////////////// 138 | 139 | type _session struct { 140 | runtime *goja.Runtime 141 | sessionMgr *SessionMgr 142 | sessionID *string 143 | w http.ResponseWriter 144 | r *http.Request 145 | } 146 | 147 | func (This *_session) start(call goja.FunctionCall) goja.Value { 148 | sessionID := This.sessionMgr.StartSession(This.w, This.r) 149 | This.sessionID = &sessionID 150 | return nil 151 | } 152 | 153 | func (This *_session) end(call goja.FunctionCall) goja.Value { 154 | This.sessionMgr.EndSession(This.w, This.r) 155 | This.sessionID = nil 156 | return nil 157 | } 158 | 159 | func (This *_session) get(call goja.FunctionCall) goja.Value { 160 | if This.sessionID == nil { 161 | This.start(call) 162 | } 163 | key := call.Argument(0).String() 164 | if value, ok := This.sessionMgr.GetSessionVal(*This.sessionID, key); ok { 165 | return This.runtime.ToValue(value) 166 | } 167 | return goja.Null() 168 | } 169 | 170 | func (This *_session) set(call goja.FunctionCall) goja.Value { 171 | if This.sessionID == nil { 172 | This.start(call) 173 | } 174 | key := call.Argument(0).String() 175 | value := call.Argument(1).Export() 176 | if IsValidType(value) { 177 | This.sessionMgr.SetSessionVal(*This.sessionID, key, value) 178 | return nil 179 | } 180 | panic(This.runtime.NewTypeError("value type %T is not permitted", value)) 181 | } 182 | 183 | func NewSession(runtime *goja.Runtime, sessionMgr *SessionMgr, w http.ResponseWriter, r *http.Request) *goja.Object { 184 | This := &_session{ 185 | runtime: runtime, 186 | sessionMgr: sessionMgr, 187 | w: w, 188 | r: r, 189 | } 190 | 191 | o := runtime.NewObject() 192 | o.Set("start", This.start) 193 | o.Set("end", This.end) 194 | o.Set("get", This.get) 195 | o.Set("set", This.set) 196 | return o 197 | } 198 | -------------------------------------------------------------------------------- /test/sql.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/go-sql-driver/mysql" 10 | ) 11 | 12 | func handErr(err error) { 13 | if err != nil { 14 | panic(err) 15 | } 16 | } 17 | 18 | func main() { 19 | // db, err := sql.Open("mysql", "root:root@/test?parseTime=true&loc="+url.QueryEscape("Asia/Shanghai")) 20 | db, err := sql.Open("mysql", "root:root@/test2") 21 | handErr(err) 22 | rows, err := db.Query("select * from users") 23 | handErr(err) 24 | defer rows.Close() 25 | 26 | cols, err := rows.Columns() 27 | handErr(err) 28 | ct, err := rows.ColumnTypes() 29 | handErr(err) 30 | 31 | arr := make([]interface{}, len(ct)) 32 | for i, v := range ct { 33 | t := v.ScanType() 34 | v := reflect.New(t).Interface() 35 | arr[i] = v 36 | fmt.Println(cols[i], t) 37 | } 38 | 39 | for rows.Next() { 40 | err = rows.Scan(arr...) 41 | handErr(err) 42 | 43 | m := make(map[string]interface{}) 44 | for i, col := range cols { 45 | if col == "template_info" || col == "state" { 46 | m[col] = "" 47 | continue 48 | } 49 | v := arr[i] 50 | switch vv := v.(type) { 51 | case *int32: 52 | m[col] = *vv 53 | case *sql.NullString: 54 | m[col] = *vv 55 | case *sql.NullBool: 56 | m[col] = *vv 57 | case *sql.NullFloat64: 58 | m[col] = *vv 59 | case *sql.NullInt64: 60 | m[col] = *vv 61 | case *sql.RawBytes: 62 | m[col] = string(*vv) 63 | case *mysql.NullTime: 64 | m[col] = *vv 65 | default: 66 | m[col] = vv 67 | panic("unknow type") 68 | } 69 | } 70 | 71 | if bts, err := json.MarshalIndent(m, "", " "); err != nil { 72 | panic(err) 73 | } else { 74 | fmt.Println(string(bts)) 75 | } 76 | } 77 | err = rows.Err() 78 | handErr(err) 79 | } 80 | --------------------------------------------------------------------------------