package client import ( "apigo.cloud/git/apigo/plugin" webview "github.com/webview/webview_go" "os" "path/filepath" "sync" ) var binds = map[string]interface{}{} var bindsLock = sync.RWMutex{} func Bind(name string, fn interface{}) { bindsLock.Lock() binds[name] = fn bindsLock.Unlock() } func Unbind(name string) { bindsLock.Lock() delete(binds, name) bindsLock.Unlock() } type Webview struct { w webview.WebView isRunning bool isAsync bool } func (w *Webview) Run() { w.isRunning = true w.w.Run() if w.isRunning { w.isRunning = false w.w.Destroy() } } func (w *Webview) Close() { if w.isRunning { w.w.Terminate() } } func (w *Webview) SetHtml(html string) { w.w.SetHtml(html) } func (w *Webview) LoadURL(url string) { w.w.Navigate(url) } func (w *Webview) LoadFile(file string) { if filepath.IsAbs(file) { w.w.Navigate("file://" + file) } else { curPath, _ := os.Getwd() w.w.Navigate("file://" + filepath.Join(curPath, file)) } } func (w *Webview) Dispatch(f func()) { w.w.Dispatch(f) } func (w *Webview) SetTitle(title string) { w.w.SetTitle(title) } func (w *Webview) SetSize(width int, height int, sizeMode *string) { hint := "none" if sizeMode != nil { hint = *sizeMode } switch hint { case "none": w.w.SetSize(width, height, webview.HintNone) case "fixed": w.w.SetSize(width, height, webview.HintFixed) case "min": w.w.SetSize(width, height, webview.HintMin) case "max": w.w.SetSize(width, height, webview.HintMax) default: w.w.SetSize(width, height, webview.HintNone) } } func (w *Webview) Eval(code string) { w.w.Eval(code) } //func (w *Webview) Bind(name string, f interface{}) error { // fmt.Println(">>>>>>>>.bind", name, f) // return w.w.Bind(name, f) //} // //func (w *Webview) Unbind(name string) error { // return w.w.Unbind(name) //} func (w *Webview) binds() { tmpBinds := map[string]interface{}{} bindsLock.RLock() for k, v := range binds { tmpBinds[k] = v } bindsLock.RUnlock() for k, v := range tmpBinds { _ = w.w.Bind(k, v) } _ = w.w.Bind("__closeWindow", w.Close) _ = w.w.Bind("__setTitle", w.w.SetTitle) _ = w.w.Bind("__setSize", w.SetSize) _ = w.w.Bind("__eval", w.w.Eval) w.w.Init(dialogCode) w.w.Init(appCode) } func newWindow(title string, width int, height int, sizeMode *string, isDebug *bool) *Webview { isDebugV := false if isDebug != nil { isDebugV = *isDebug } w := &Webview{w: webview.New(isDebugV)} w.SetTitle(title) w.SetSize(width, height, sizeMode) w.binds() return w } const appCode = ` let app = { close: __closeWindow, setTitle: __setTitle, setSize: __setSize, eval: __eval, } ` const dialogCode = ` window._dialogTexts = {'zh':{'Close':'关闭','Cancel':'取消','Confirm':'确定'}} function _getDialogDefaultText(text) {return (window._dialogTexts[navigator.language] && window._dialogTexts[navigator.language][text]) || (window._dialogTexts[navigator.language.split('-')[0]] && window._dialogTexts[navigator.language.split('-')[0]][text]) || text} window.alert = function (msg, buttonText) {return showDialog(msg, [buttonText || _getDialogDefaultText('Close')])} window.confirm = function (msg, confirmButtonText, cancelButtonText) {return showDialog(msg, [cancelButtonText || _getDialogDefaultText('Cancel'), cancelButtonText || _getDialogDefaultText('Confirm')])} window.prompt = function (msg, defaultValue, confirmButtonText, cancelButtonText) {return showDialog(msg, [cancelButtonText || _getDialogDefaultText('Cancel'), cancelButtonText || _getDialogDefaultText('Confirm')], [{value:defaultValue||''}])} window.showDialog = function (msg, buttons, inputs) { if(!document.querySelector('#_dialogStyle')){ let sDom = document.createElement('style') sDom.id = '_dialogStyle' sDom.textContent = '._dialogMask {position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(128,128,128,0.7);display:flex;justify-content:center;align-items:center}\n' + '._dialogPanel {background:#eee;padding:16px;min-width:300px;max-width:80%;max-height:80%;margin:auto;border-radius:10px;display:flex;flex-flow:column;overflow:auto}\n' + '._dialogMessage {font-size:0.875rem;flex:1;overflow:auto;white-space:pre-wrap}\n' + '._dialogInputs {display:flex;flex-flow:column;margin-top:8px}\n' + '._dialogInputs input {flex:1;border:1px solid #aaa;border-radius:4px;min-height:28px;padding:0 8px}\n' + '._dialogLine {text-align:end;padding:4px 0}\n' + '._dialogButtons {text-align:end}\n' + '._dialogButtons button {background:none;border:none;color:#999;min-height:28px;cursor:pointer;font-size:1rem;margin-left:10px}\n' + '._dialogButtons button:hover {color:#999}\n' + '._dialogButtons button:last-child {color:#06f}' document.head.append(sDom) } return new Promise(resolve => { let a = ['
'] if (msg) a.push('
__MSG__
'.replace(/__MSG__/, msg)) if (inputs && inputs.length) { let a1 = ['
'] for (let i = 0; i < inputs.length; i++){ a1.push(''.replace(/__INPUT_INDEX__/, i + '').replace(/__INPUT_HINT__/, inputs[i].hint||'').replace(/__INPUT_VALUE__/, inputs[i].value||'')) } a1.push('
') a.push(a1.join('')) } a.push('

') let a2 = ['
'] for (let i = 0; i < buttons.length; i++) a2.push(''.replace(/__BUTTON_INDEX__/, i + '').replace(/__BUTTON_LABEL__/, buttons[i])) a2.push('
') a.push(a2.join('')) let dialogId = Math.ceil(Math.random() * 10000000000).toString(36) let w = document.createElement('div') w.id = '_dialogWindow' + dialogId w.className = '_dialogMask' window['_dialogAction' + dialogId] = function (index) { let isOK = index === buttons.length - 1 if (inputs && inputs.length) { if (isOK) { let inputValues = [] for (let i = 0; i < inputs.length; i++) inputValues.push(document.querySelector('#_dialogInput' + dialogId + '_' + i).value) resolve(inputs.length === 1 ? inputValues[0] : inputValues) } else { resolve(false) } } else { resolve(isOK ? true : index) } document.body.removeChild(document.querySelector('#_dialogWindow' + dialogId)) } w.innerHTML = a.join('').replace(/__ID__/g, dialogId) document.body.append(w) }) } ` func init() { plugin.Register(plugin.Plugin{ Id: "apigo.cloud/git/apigo/client", Name: "web client framework by github.com/webview/webview", Objects: map[string]interface{}{ "newApp": func(title string, width int, height int, sizeMode *string, isDebug *bool) *Webview { w := newWindow(title, width, height, sizeMode, isDebug) // svc 框架 //w.w.Init(``) return w }, "new": func(title string, width int, height int, sizeMode *string, isDebug *bool) *Webview { return newWindow(title, width, height, sizeMode, isDebug) }, }, }) }