--- title: WebBuilder Examples description: The WebBuilder Module Examples. type: example audience: ai-agent, developer version: "10" keywords: webbuilder, example, wd-files, ai-training --- # admin/about/get-new-version.xwl Title: get-new-version Description: Get new version ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.send(Wb.submit({ url: 'https://www.geejing.com/get-version', timeout: 8000 }));\n}\nmain();", "remark": "Get new version" }, "_icon": "module" } # admin/about.xwl Title: About Description: View about WebBuilder ```json { "title": "@about", "icon": "info", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('wb/modules/sys/portal/home/util.mjs');\n let lic = Util.getLicensee();\n\n Wb.set({\n version: Wb.getConfig('sys.app.version'),\n type: Wb.getConfig('sys.app.type'),\n date: Wb.getConfig('sys.app.date').dateText,\n serverCode: Config.serverCode,\n lic: (lic ? ('Authorized to ' + lic) : 'Unlicensed')\n });\n}\nmain();", "remark": "View about WebBuilder", "obfuscate": "true" }, "_icon": "module", "_expanded": true, "tags": "", "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "html": "\n", "autoScroll": "true" }, "events": { "ready": "let el = this.el, mainDiv, teamDiv, updateLink, newVersion;\n\nif (Str.lang == 'zh-cn')\n mainDiv = el.query('[cid=lang-zh-cn]');\nelse\n mainDiv = el.query('[cid=lang-en]');\nmainDiv.setStyle('display', 'block');\nteamDiv = mainDiv.query('[cid=team-list]')\nteamDiv.addEventListener('animationend', f => {\n teamDiv.parentNode.cls = 'w-scroll-true';\n}, {\n once: true\n});\nteamDiv.className = 'w-vscroll';\nnew Wb.Button({\n el: mainDiv.query('[cid=buy]'), icon: 'cart', text: Str.buy, type: 'primary', owner: this, handler() {\n window.open('https://www.geejing.com/buy');\n }\n});\nnewVersion = mainDiv.query('[cid=newVersion]');\nWb.ajax({\n url: xpath + '/get-new-version', mask: false, showError: false,\n failure(resp) {\n newVersion.textContent = Str.unableDetectNew;\n },\n success(resp) {\n if (parseFloat(resp) != _$version$_) {\n newVersion.textContent = '';\n updateLink = newVersion.addTag('a');\n updateLink.href = 'https://www.geejing.com/download';\n updateLink.target = '_blank';\n updateLink.textContent = Str.foundNewVersion.format(resp);\n updateLink.highlight();\n } else {\n newVersion.textContent = Str.alreadyLatestVersion;\n }\n }\n});" }, "_expanded": true } ] } # admin/blocked-ip/set-actions.xwl Title: set-actions Description: Set block actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set block actions", "serverScript": "let actions = {\n /** @property {String} - Blocked IPs file. */\n file: new Wb.File(Base.path, Wb.getConfig('sys.file.blockedIPs')),\n /**\n * Get IPs.\n */\n getIPs() {\n var file = this.file, result;\n\n if (file.exists) {\n result = file.text;\n } else {\n result = '';\n }\n Wb.send(result);\n },\n /**\n * Save and reload blocked ips to the cache.\n */\n save() {\n var file = this.file, text = Wb.payload;\n\n if (text)\n file.text = text;\n else if (file.exists)\n file.remove();\n this.clear();\n },\n /**\n * Clear and reload blocked ips to the cache.\n */\n clear() {\n Base.reloadBlockedIPs();\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # admin/blocked-ip.xwl Title: Blocked IPs ```json { "title": "@blockedIPs", "icon": "delete3", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Reload ips.\n */\n reload() {\n Wb.ajax({\n url: xpath + '/set-actions&xaction=getIPs',\n success(resp) {\n app.codeEditor1.value = resp;\n app.saveItem.disabled = true;\n }\n });\n },\n /**\n * Save ips.\n */\n save() {\n Wb.ajax({\n url: xpath + '/set-actions&xaction=save',\n data: app.codeEditor1.value,\n success(resp) {\n app.saveItem.disabled = true;\n }\n });\n }\n});", "beforeunload": "if (!app.saveItem.disabled) {\n return false;\n}" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "saveItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveItem", "text": "@Str.save", "icon": "save", "disabled": "true", "keys": "Ctrl+S" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "refreshItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshItem", "text": "@Str.refresh", "icon": "refresh" }, "events": { "click": "if (app.saveItem.disabled) {\n app.reload();\n} else {\n Wb.choose(Str.saveChanges.format('IPs'), btn => {\n if (btn == 'yes')\n app.save();\n else if (btn == 'no') {\n app.reload();\n }\n });\n}" } }, { "_icon": "item", "text": "clearItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "clearItem", "text": "@Str.clear", "icon": "recycle", "tip": "@Str.clearInvalidData" }, "events": { "click": "Wb.ajax({\n url: xpath + '/set-actions&xaction=clear',\n success() {\n Wb.tipDone(Str.clear);\n }\n});" } } ] }, { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "properties": { "cid": "codeEditor1", "language": "txt", "minimap": "false", "wrapBorder": "false" }, "events": { "ready": "app.reload();", "change": "app.saveItem.disabled = false;" } } ] } ] } # admin/buy.xwl Title: Buy WebBuilder Description: Buy WebBuilder ```json { "title": "@buyWebBuilder", "icon": "cart", "img": "", "tags": "{url: 'https://www.geejing.com/buy', newWin: true}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Buy WebBuilder" }, "_icon": "module" } # admin/cms/access-log/select-by-date.xwl Title: select-by-date Description: Select group by date ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select group by date", "serverScript": "function main() {\n let dbName = Wb.getConn().dbName.toLowerCase();\n if (dbName.includes('sql server'))\n Wb.sendRowx('select convert(varchar(100), sdate, 23) as date,count(distinct ip_addr) as ct from wb_access group by convert(varchar(100), sdate, 23) order by date desc');\n else\n Wb.sendRowx('select date(sdate) as date,count(distinct ip_addr) as ct from wb_access group by date(sdate) order by date(sdate) desc');\n}\nmain();" }, "_icon": "module" } # admin/cms/access-log/select-by-ip.xwl Title: select-by-ip Description: Select group by ip ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select group by ip", "serverScript": "function main() {\n Wb.sendRowx('select ip_addr,count(*) as ct from wb_access group by ip_addr order by count(*) desc');\n}\nmain();" }, "_icon": "module" } # admin/cms/access-log/select-by-url.xwl Title: select-by-url Description: Select group by url ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select group by url", "serverScript": "function main() {\n Wb.sendRowx('select url,count(*) as ct from wb_access group by url order by count(*) desc');\n}\nmain();" }, "_icon": "module" } # admin/cms/access-log/select-down-count.xwl Title: select-down-count Description: Select download count ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select download count", "serverScript": "function main() {\n let dbName = Wb.getConn().dbName.toLowerCase();\n if (dbName.includes('sql server'))\n Wb.sendRowx(`select convert(varchar(100), sdate, 23) as date,count(distinct ip_addr) as ct from wb_access where url='download' group by convert(varchar(100), sdate, 23) order by date desc`);\n else\n Wb.sendRowx(`select date(sdate) as date,count(distinct ip_addr) as ct from wb_access where url='download' group by date(sdate) order by date(sdate) desc`);\n}\nmain();" }, "_icon": "module" } # admin/cms/access-log/select.xwl Title: select Description: Select access logs ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select access logs", "serverScript": "function main() {\n let sql, where = [], orderBy;\n\n if (Params.date1)\n where.push('sdate>= {?timestamp|date1?}');\n if (Params.date2)\n where.push('sdate< {?timestamp|date2?}');\n where = where.length ? (' where ' + where.join(' and ')) : '';\n orderBy = Wb.getOrderSql();\n sql = `select * from wb_access${where} ${orderBy}`;\n Wb.sendRowx({ sql, rs: 2000 });\n}\nmain();" }, "_icon": "module" } # admin/cms/access-log.xwl Title: 访问日志 Description: Access log ```json { "title": "访问日志", "icon": "data", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Access log" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Create chart option. @priv\n * @param {Wb.Grid} grid Data source grid.\n * @param {Wb.Chart} chart Chart component.\n */\n createOption(grid, chart) {\n let xAxis = [], series = [], data;\n\n grid.each(item => {\n data = item.data;\n xAxis.push(data.date);\n series.push(data.ct);\n }, true, true);\n chart.option = {\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow'\n }\n },\n xAxis: {\n type: 'category',\n data: xAxis\n },\n yAxis: {\n type: 'value'\n },\n series: [\n {\n data: series,\n type: 'line',\n smooth: true\n }\n ]\n };\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1", "padding": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "placeholder": "@Str.from", "width": "9em" }, "_expanded": true }, { "_icon": "calendar", "text": "date2", "cls": "Wb.Date", "properties": { "cid": "date2", "placeholder": "@Str.to", "width": "9em" }, "_expanded": true }, { "_icon": "item", "text": "searchItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "searchItem", "tip": "@Str.search", "icon": "search" }, "events": { "click": "app.listGrid.load({ comps: app.viewport1.tbar });" } }, { "_icon": "item", "text": "resetItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "resetItem", "tip": "@Str.reset", "icon": "undo" }, "events": { "click": "let comps = app.viewport1.tbar;\nWb.reset(comps);\napp.listGrid.load({ comps });" } } ] }, { "_icon": "grid", "text": "listGrid", "cls": "Wb.Grid", "properties": { "cid": "listGrid", "url": "@xpath + '/select'", "sorters": "{name:'sdate',desc:true}", "columnsSortable": "true", "textSelectable": "true", "showMask": "false", "maxHeight": "20em", "title": "访问日志" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "日期", "fieldName": "sdate", "width": "13em" } }, { "_icon": "column", "text": "ipCol", "cls": "Wb.Column", "properties": { "cid": "ipCol", "text": "IP地址", "fieldName": "ip_addr" } }, { "_icon": "column", "text": "urlCol", "cls": "Wb.Column", "properties": { "cid": "urlCol", "text": "URL地址", "fieldName": "url", "width": "20em" } }, { "_icon": "column", "text": "langCol", "cls": "Wb.Column", "properties": { "cid": "langCol", "text": "语言", "fieldName": "lang", "width": "8em" } } ] } ] }, { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "layout": "fit", "height": "30em", "title": "根据日期统计 IP 统计图" }, "_expanded": true, "items": [ { "_icon": "chart-bar", "text": "dateChart", "cls": "Wb.Chart", "properties": { "cid": "dateChart" } } ] }, { "_icon": "grid", "text": "dateGrid", "cls": "Wb.Grid", "properties": { "cid": "dateGrid", "url": "@xpath + '/select-by-date'", "title": "根据日期统计 IP 数量", "textSelectable": "true", "showMask": "false", "maxHeight": "20em" }, "_expanded": true, "events": { "success": "app.createOption(this, app.dateChart);" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "日期", "fieldName": "date", "width": "7em" } }, { "_icon": "column", "text": "ctCol", "cls": "Wb.Column", "properties": { "cid": "ctCol", "text": "IP 数量", "fieldName": "ct", "width": "6em" } } ] } ] }, { "_icon": "panel", "text": "panel2", "cls": "Wb.Panel", "properties": { "cid": "panel2", "layout": "fit", "height": "30em", "title": "根据日期统计下载统计图" }, "_expanded": true, "items": [ { "_icon": "chart-bar", "text": "downloadChart", "cls": "Wb.Chart", "properties": { "cid": "downloadChart" } } ] }, { "_icon": "grid", "text": "downloadGrid", "cls": "Wb.Grid", "properties": { "cid": "downloadGrid", "url": "@xpath + '/select-down-count'", "title": "根据日期统计下载数量", "textSelectable": "true", "showMask": "false", "maxHeight": "20em" }, "_expanded": true, "events": { "success": "app.createOption(this, app.downloadChart);" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "日期", "fieldName": "date", "width": "7em" } }, { "_icon": "column", "text": "ctCol", "cls": "Wb.Column", "properties": { "cid": "ctCol", "text": "下载数量", "fieldName": "ct", "width": "6em" } } ] } ] }, { "_icon": "grid", "text": "ipGrid", "cls": "Wb.Grid", "properties": { "cid": "ipGrid", "url": "@xpath + '/select-by-ip'", "title": "根据 IP 统计次数", "textSelectable": "true", "showMask": "false", "maxHeight": "20em" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "ipCol", "cls": "Wb.Column", "properties": { "cid": "ipCol", "text": "IP 地址", "fieldName": "ip_addr", "width": "10em" } }, { "_icon": "column", "text": "ctCol", "cls": "Wb.Column", "properties": { "cid": "ctCol", "text": "访问次数", "fieldName": "ct", "width": "6em" } } ] } ] }, { "_icon": "grid", "text": "urlGrid", "cls": "Wb.Grid", "properties": { "cid": "urlGrid", "url": "@xpath + '/select-by-url'", "title": "根据 URL 统计次数", "textSelectable": "true", "showMask": "false", "maxHeight": "20em" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "urlCol", "cls": "Wb.Column", "properties": { "cid": "urlCol", "text": "URL 地址", "fieldName": "url", "width": "10em" } }, { "_icon": "column", "text": "ctCol", "cls": "Wb.Column", "properties": { "cid": "ctCol", "text": "访问次数", "fieldName": "ct", "width": "6em" } } ] } ] } ] } ] } # admin/cms/cms/add.xwl Title: add Description: Add page ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add page", "serverScript": "function main() {\n let date = new Date(), rec = { sid: Wb.getId(), sdate: date, last_modified: date };\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_cms', insert: Params });\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/buy.xwl Title: Buy ```json { "title": "@buy", "icon": "cart", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.invoke('view', { id: 'buy' });", "loginRequired": "false" }, "_icon": "module", "items": [] } # admin/cms/cms/del.xwl Title: del Description: Delete pages ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete pages", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let del = Wb.getObject('del'), rec;\n\n Wb.sync({ tableName: 'wb_cms', del });\n if (del.some(item => item.$is_news)) {\n //Update the latest news modification time to ensure the 304 status code is correct\n rec = Wb.getRow('select sid from wb_cms where is_news=1 order by last_modified desc');\n Wb.sync({ tableName: 'wb_cms', update: { $sid: rec.sid, last_modified: new Date() } });\n }\n Util.clearBuffer(del);\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/download.xwl Title: Download ```json { "title": "@download", "icon": "download", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.invoke('view', { id: 'download' });", "loginRequired": "false" }, "_icon": "module", "items": [] } # admin/cms/cms/edit.xwl Title: edit Description: Edit page ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit page", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let rec = { last_modified: new Date() };\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_cms', update: Params });\n Util.clearBuffer([Params]);\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/get-page.xwl Title: get-page Description: Get page content ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get page content", "serverScript": "function main() {\n Wb.send(Wb.getRecord('select html_content from wb_cms where sid={?sid?}')?.[0] ?? '');\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/search-page.xwl Title: search-page Description: Search pages ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Search pages", "serverScript": "function main() {\n let sql;\n\n sql = 'select distinct title,url from wb_cms';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where title like {?query?} or url like {?query?}';\n }\n sql += ' order by title';\n Wb.sendRows(sql);\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/search.xwl Title: search ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.sendRows({\n sql: `select title,url,'file' as \"_icon\" from wb_cms where status=1 and lang={?lang?} and url<>'header' and url<>'footer' and url<>'description' and title like {?query?} order by sdate desc`,\n params: { lang: Params.lang ?? Str.lang, query: '%' + Params.query + '%' }\n});", "loginRequired": "false" }, "_icon": "module", "items": [] } # admin/cms/cms/select.xwl Title: select Description: Select pages ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select pages", "serverScript": "function main() {\n let sql, where = [];\n\n sql = `select sid, sdate, url, title, lang, login_required, cached, is_news, is_all, status, '' as html_content, last_modified from wb_cms`;\n if (Params.searchPageSelect)\n where.push('(title like {?searchPageSelect?} or url like {?searchPageSelect?})');\n if (Params.fromDate)\n where.push('sdate >= {?timestamp|fromDate?}');\n if (Params.toDate)\n where.push('sdate <= {?timestamp|toDate?}');\n if (where.length)\n sql += ' where ' + where.join(' and ');\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # admin/cms/cms/submit.xwl Title: submit ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let now = new Date(), ct;\n\nWb.set({ sid: Wb.getId(), sdate: now, ymd: now.format('yMMdd'), ip_addr: request.getRemoteAddr() });\nct = Wb.getRecord('select count(*) from wb_orders where ymd={?ymd?} and ip_addr={?ip_addr?}')[0];\nif (ct > 200)\n Wb.raise('Submission exceeds the limit, please contact the administrator.');\nWb.sync({ tableName: 'wb_orders', insert: Params });", "loginRequired": "false" }, "_icon": "module", "items": [] } # admin/cms/cms/view.xwl Title: view ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "const cms = Classes.Cms;\n/**\n * Create page. @priv\n * @param {String} title Page title.\n * @param {String} lang Page language.\n * @param {String} content Page Content.\n * @param {String} [header] Header html.\n * @param {String} [footer] Footer html.\n */\nfunction createPage(title, lang, content, header, footer) {\n let html, desc;\n\n desc = getPageData('description', lang).html_content;\n header ??= getPageData('header', lang);\n header = header.html_content;\n footer ??= getPageData('footer', lang);\n footer = footer.html_content;\n html = `\n\n\n\n\n\n${title}\n\n\n\n\n\n\n\n\n\n
\n${header}\n${content}\n${footer}\n
\n\n`;\n return html;\n}\n/**\n * Get news items list.\n * @param {Number} count Items count.\n * @param {String} lang Page language.\n * @param {Boolean} wrapMode Whether auto wrap items.\n * @return {Object} News object with lastModified and content.\n */\nfunction createNews(count, lang, wrapMode) {\n let i = 0, frs, rs, html, time = 0, summary;\n\n html = '';\n frs = Wb.sqlRS({\n sql: 'select url,title,last_modified,html_content from wb_cms where is_news=1 and lang={?lang?} order by sdate desc',\n params: { lang }\n });\n try {\n rs = frs.resultSet;\n while (rs.next()) {\n i++;\n if (i > count)\n break;\n time = Math.max(time, rs.getTimestamp(3).getTime());\n html += '';\n html += '
' +\n rs.getString(2).substr(0, 80) + '
';\n summary = rs.getString(4).trimLeft();\n if (summary.startsWith('[')) {\n summary = summary.substring(1, summary.indexOf(']')).trimRight();\n html += summary;\n }\n html += '
';\n }\n } finally {\n frs.close();\n }\n return { lastModified: time, content: html };\n}\n/**\n * Get page data from buffer or db.\n * @param {String} url Page url.\n * @param {String} lang Page language.\n * @return {Object} Page data.\n */\nfunction getPageData(url, lang) {\n let key = lang + '$' + url, data;\n\n data = cms.buffer.get(key);\n if (!data) {\n data = Wb.getRow({\n sql: 'select last_modified,title,html_content,login_required,cached,is_all from wb_cms' +\n ' where url={?url?} and lang={?lang?} and status=1', params: { url, lang }\n });\n if (data?.cached) {\n let cmsData = new (Java.type('com.wb.tool.CmsData'))();\n delete data.cached;\n data.login_required = !!data.login_required;\n data.is_all = !!data.is_all;\n Wb.apply(cmsData, data);\n cms.buffer.put(key, cmsData);\n }\n }\n return data;\n}\n/**\n * Create 404 page. @priv\n */\nfunction create404Page() {\n let html = `
\n
\n
\n
\n
HTTP 404
\n
${Str.e404}
\n${Str.home}\n
\n
\n
`;\n return html;\n}\n/**\n * Get files size object of site folder.\n */\nfunction getFileSizeObject() {\n let folder = new Wb.File(true, 'site'), result;\n if (!folder)\n return null;\n result = { version: Wb.getConfig('sys.app.version') };\n folder.each(file => {\n if (file.isFile)\n result[file.name] = file.length.mb;\n });\n return result;\n}\n/**\n * Record access log. @priv\n */\nfunction recordLog(url, lang) {\n Wb.sync({ tableName: 'wb_access', insert: { sid: Wb.getId(), sdate: new Date(), ip_addr: request.getRemoteAddr(), url, lang } });\n}\n/**\n * Main function of the module. @priv\n */\nfunction main() {\n let etag, data, url = Params.id, lang = Params.lang ?? Str.lang, content, isNews, isHome, news;\n\n url ??= 'home';\n data = getPageData(url, lang);\n if (!data && lang != Config.defaultLanguage) {\n lang = Config.defaultLanguage;\n data = getPageData(url, lang);\n }\n if (data) {\n if (data.login_required && !Wb.checkLogin())\n return;\n recordLog(url, lang);\n let isAll = data.is_all, lastModified = data.last_modified, header, footer;\n if (isAll) {\n lastModified = lastModified.getTime();\n } else {\n header = getPageData('header', lang);\n footer = getPageData('footer', lang);\n lastModified = Math.max(lastModified, header.last_modified, footer.last_modified);\n }\n if (url == 'download') {\n content = data.html_content;\n content = content.replaceParams(getFileSizeObject());\n } else {\n isHome = url == 'home';\n isNews = url == 'news';\n if (isHome || isNews) {\n news = createNews(isHome ? 6 : 1000, lang, isHome);\n lastModified = Math.max(news.lastModified, lastModified);\n }\n etag = lastModified.toString();\n if (etag.equals(request.getHeader('If-None-Match'))) {\n response.setStatus(304);\n return;\n }\n response.setHeader('Etag', etag);\n content = data.html_content.trimLeft();\n if (content.startsWith('['))\n content = content.substr(content.indexOf(']') + 1).trimLeft();\n if (isHome || isNews)\n content = content.replace('_$x-news$_', news.content);\n }\n content = isAll ? content : createPage(data.title, lang, content, header, footer)\n } else {\n content = createPage(Str.e404, lang, create404Page(Str.e404))\n }\n WebUtil.send(response, content);\n}\nmain();", "loginRequired": "false" }, "_icon": "module" } # admin/cms/cms.xwl Title: 网站内容管理 Description: Content management system ```json { "title": "网站内容管理", "icon": "container", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/js/monaco.js\"\n]", "remark": "Content management system" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Object} - The edit window configs object for page window. */\n pageWinConfigs: {\n events: {\n ready() {\n let win = this, ct = new Wb.Container({ layout: 'grid5' }), editor = win.lastItem;\n\n ct.add(win.items.filter(item => item.cid != 'html_content'));\n ct.each(item => {\n if (item instanceof Wb.Text)\n item.gridColumn = 'span 5';\n });\n Wb.apply(editor, { text: null });\n win.add({\n cname: 'tab', tabPosition: 'bottom', minHeight: '22em', margin: ' 0 1.5em', flex: 1, items: [\n { title: Str.edit, icon: 'edit', layout: 'fit', closable: null, items: editor },\n {\n title: Str.preview, icon: 'preview', closable: null, layout: 'fit', items: { cname: 'viewer', border: 0 }, events: {\n show() {\n this.firstItem.html = editor.value;\n }\n }\n }\n ]\n });\n win.insert(0, ct);\n win.autoScroll = true;\n win.layout = 'column';\n },\n show() {\n this.height = this.el.offsetHeight;\n }\n }\n },\n /**\n * Load pages data.\n */\n loadPages() {\n app.pageGrid.load({ comps: app.viewport1.tbar });\n },\n /**\n * Method to execute when adding or updating page data fails。\n * @param {String} resp Response text.\n */\n onPageFailure(resp) {\n Wb.checkExists(resp, 'wb_cms_unq1', app.pageGrid.dictWin.down('url'));\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addPageBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addPageBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "let win = app.pageGrid.dictAdd({\n url: xpath + '/add',\n failure: app.onPageFailure\n}, null, null, (grid, row) => {\n row.data.html_content = null;\n}, app.pageWinConfigs, null, false);\nwin.down('lang').value = Str.lang;" } }, { "_icon": "item", "text": "editPageBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editPageBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let rec = app.pageGrid.selection;\n\nif (rec) {\n Wb.ajax({\n url: xpath + '/get-page',\n params: { sid: rec.data.sid },\n success(resp) {\n let win = app.pageGrid.dictEdit({\n url: xpath + '/edit',\n failure: app.onPageFailure\n }, 'title', null, (grid, row) => {\n row.data.html_content = null;\n }, app.pageWinConfigs);\n win.down('html_content').value = resp;\n }\n });\n} else {\n Wb.tipSelect();\n}" } }, { "_icon": "item", "text": "delPageBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delPageBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.pageGrid.removeRecords(xpath + '/del', 'title');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "combo", "text": "searchPageSelect", "cls": "Wb.Select", "properties": { "cid": "searchPageSelect", "url": "@xpath + '/search-page'", "placeholder": "@Str.title+'/'+Str.url", "triggerIcon": "search", "clearButton": "true", "enterTriggerClick": "true", "width": "20em", "itemTpl": "{title} ({url})", "textField": "url" }, "events": { "action": "app.loadPages();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "@Str.date" } }, { "_icon": "calendar", "text": "fromDate", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "fromDate", "width": "10em" } }, { "_icon": "label", "text": "toLabel", "cls": "Wb.Label", "properties": { "cid": "toLabel", "text": "@Str.to" } }, { "_icon": "calendar", "text": "toDate", "cls": "Wb.Date", "_expanded": false, "properties": { "cid": "toDate", "beginDate": "fromDate", "width": "10em" }, "events": { "select": "app.loadPages();" } }, { "_icon": "item", "text": "searchItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "searchItem", "icon": "search", "text": "@Str.search" }, "events": { "click": "app.loadPages();" } } ] }, { "_icon": "grid", "text": "pageGrid", "cls": "Wb.Grid", "properties": { "cid": "pageGrid", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "{name: 'sdate', desc: true}" }, "_expanded": true, "events": { "itemdblclick": "app.editPageBtn.fireEvent('click');", "beforeloadcolumns": "let col = columns.find(col => col.fieldName == 'title');\n\nif (col)\n col.width = -1;" } } ] } ] } # admin/cms/get-ips/create.xwl Title: create Description: Create ip list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Create ip list", "serverScript": "function main() {\n let condi = '', myIp = request.getRemoteAddr(), ipList;\n\n ipList = new Wb.File(true, 'site/fixed-ips.txt').text.split('\\n');\n condi = `sdate > '` + (Params.begin || '2025-9-18') + `'`;\n if (Params.end)\n condi += ` and sdate < '` + Params.end + `'`;\n Wb.getAllRows({\n sql: `select distinct ip_addr from wb_access where ip_addr not in\n (select distinct ip_addr from wb_access where url<>'home') and ` + condi, fn(row) {\n if (row.ip_addr != myIp)\n ipList.push(row.ip_addr);\n }\n });\n new Wb.File(true, 'site/ips.txt').text = ipList.unique().join('\\n');\n Base.reloadBlockedIPs();\n}\nmain();" }, "_icon": "module" } # admin/cms/get-ips.xwl Title: 获得 IP ```json { "title": "获得 IP", "icon": "script", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "center" }, "_expanded": true, "items": [ { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "calendar", "text": "begin", "cls": "Wb.Date", "properties": { "cid": "begin", "text": "开始时间", "required": "true", "value": "@new Date().addDay(-7)" } }, { "_icon": "calendar", "text": "end", "cls": "Wb.Date", "properties": { "cid": "end", "text": "结束时间" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "生成", "type": "primary" }, "events": { "click": "if (Wb.verify(app.panel1)) {\n Wb.ajax({\n url: xpath + '/create',\n comps: app.panel1,\n success(resp) {\n Wb.tipDone();\n }\n });\n}" } } ] } ] } ] } # admin/cms/order/create-license.xwl Title: create-license Description: Create license file ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Create license file", "serverScript": "function main() {\n let text, now = new Date(), years = Wb.getInt('years'), yearsText, users = Wb.getInt('user_count'), usersText,\n server = Params.serverCode, serverText, licenseText, licensee = Params.licensee;\n\n if (years == 6) {\n yearsText = '(No limit)';\n years = 0;\n } else {\n years = now.addDay(7).addYear(years).datePart;\n yearsText = years.format('y-MM-dd');\n }\n if (users == 1000)\n usersText = '(No limit)';\n else\n usersText = users;\n if (server == '$$$')\n serverText = '(Generic)';\n else\n serverText = server;\n licenseText = 'Licensee: ' + licensee +\n '\\nExpire date: ' + yearsText + '\\nUsers: ' + usersText + '\\nServer Code: ' + serverText;\n text = '--- Warning: Do not modify this file --- \\n' + licenseText +\n '\\nSignature: ' + Encrypter.encrypt(Wb.encode({ licensee, server, users, years, sn: Params.sid }), '@#7D1d9!');\n let remark, lock = new Wb.Lock('wb.tables.order');\n try {\n remark = Wb.getRecord('select remark from wb_orders where sid={?sid?}')[0];\n if (remark)\n remark += '\\n';\n else\n remark = '';\n remark += now.dateTimeText + ': create license (\\n' + licenseText + '\\n)';\n Wb.set({ remark });\n Wb.sql('update wb_orders set remark={?clob|remark?} where sid={?sid?}');\n } finally {\n lock.unlock();\n }\n Wb.send({ text, remark });\n}\nmain();" }, "_icon": "module" } # admin/cms/order/del.xwl Title: del Description: Delete orders ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete orders", "serverScript": "function main() {\n let del = Wb.getObject('del');\n\n Wb.sync({ tableName: 'wb_orders', del });\n}\nmain();" }, "_icon": "module" } # admin/cms/order/edit.xwl Title: edit Description: Edit order ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit order", "serverScript": "function main() {\n Wb.sync({ tableName: 'wb_orders', update: Params });\n}\nmain();" }, "_icon": "module" } # admin/cms/order/select.xwl Title: select Description: Select orders ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select orders", "serverScript": "function main() {\n let sql, dbName = Wb.getConn().dbName.toLowerCase(), where, orderBy;\n\n if (Params.search) {\n Wb.setLike('search');\n where = ' where payer like {?search?}'\n } else {\n where = '';\n }\n orderBy = Wb.getOrderSql();\n if (dbName.includes('sql server')) {\n sql = `select * from (select row_number() over(${orderBy}) as rownumber, * from\n wb_orders${where}) a\n where rownumber > {?bigint|_from?} and rownumber < {?bigint|_to?}+2 ${orderBy}\n `;\n Wb.sendRowx({ sql, paging: false, total: `select count(*) from wb_orders${where}` });\n } else {\n Wb.sendRowx('select * from wb_orders' + where + orderBy);\n }\n}\nmain();" }, "_icon": "module" } # admin/cms/order.xwl Title: 订单列表 Description: Order list ```json { "title": "订单列表", "icon": "order", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Order list" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "editWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "editWin", "layout": "form1", "resetDialog": "true", "icon": "edit", "title": "修改订单", "width": "50em" }, "items": [ { "_icon": "number-edit", "text": "total_price", "cls": "Wb.Number", "properties": { "cid": "total_price", "text": "实付总价" }, "_expanded": true }, { "_icon": "switcher-on", "text": "usd", "cls": "Wb.Toggle", "properties": { "cid": "usd", "text": "美元" }, "_expanded": true }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "可选项" } }, { "_icon": "text", "text": "payer", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "payer", "text": "付款人" } }, { "_icon": "text", "text": "licensee", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "licensee", "text": "被授权人" } }, { "_icon": "text", "text": "contact", "cls": "Wb.Text", "properties": { "cid": "contact", "text": "联系人" } }, { "_icon": "text", "text": "email", "cls": "Wb.Text", "properties": { "cid": "email", "text": "电子邮件" } }, { "_icon": "text", "text": "phone", "cls": "Wb.Text", "_expanded": false, "properties": { "cid": "phone", "text": "联系电话" } }, { "_icon": "switcher-on", "text": "online_support", "cls": "Wb.Toggle", "properties": { "cid": "online_support", "text": "技术支持" } }, { "_icon": "number-edit", "text": "user_count", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "user_count", "text": "用户数", "minValue": "10", "maxValue": "1000", "decimalCount": "0", "upDownKey": "true" } }, { "_icon": "number-edit", "text": "years", "cls": "Wb.Number", "properties": { "cid": "years", "text": "使用年限", "maxValue": "6", "minValue": "1", "decimalCount": "0", "upDownKey": "true" }, "_expanded": true }, { "_icon": "number-edit", "text": "total_count", "cls": "Wb.Number", "properties": { "cid": "total_count", "text": "授权数量" } }, { "_icon": "textarea", "text": "remark", "cls": "Wb.TextArea", "properties": { "cid": "remark", "text": "备注", "flex": "1", "minHeight": "15em" }, "_expanded": true } ] }, { "_icon": "window", "text": "licenseWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "licenseWin", "icon": "card", "layout": "grid1", "resetDialog": "true", "title": "下载授权证书" }, "events": { "ok": "let win = this, row = app.selectRow, data = row.data;\nif (Wb.verify(win)) {\n Wb.ajax({\n url: xpath + '/create-license',\n comps: win,\n params: data,\n json: true,\n success(resp) {\n row.set('remark', resp.remark);\n Wb.downloadText(resp.text, 'license.txt');\n win.close();\n }\n });\n}" }, "items": [ { "_icon": "trigger", "text": "serverCode", "cls": "Wb.Trigger", "properties": { "cid": "serverCode", "text": "服务器编号", "onTriggerClick": "this.value = '$$$';", "triggerIcon": "card", "trigger": "{tip: '不限制服务器'}", "required": "true" } }, { "_icon": "text", "text": "licensee", "cls": "Wb.Text", "properties": { "cid": "licensee", "text": "被授权人", "readonly": "true" } }, { "_icon": "number-edit", "text": "user_count", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "user_count", "text": "用户数", "minValue": "10", "maxValue": "1000", "decimalCount": "0", "upDownKey": "true", "readonly": "true" } }, { "_icon": "number-edit", "text": "years", "cls": "Wb.Number", "properties": { "cid": "years", "text": "使用年限", "maxValue": "6", "minValue": "1", "decimalCount": "0", "upDownKey": "true", "readonly": "true" }, "_expanded": true } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "columnsSortable": "true", "sorters": "{name: 'sdate', desc: true}", "stateId": "wb.cms.order", "multiSelect": "true" }, "events": { "itemdblclick": "app.editItem.fireClick('click');" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "editItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editItem", "icon": "edit", "text": "编辑", "keys": "Ctrl+E" }, "events": { "click": "let rec = app.grid1.selection;\napp.grid1.editRecord(xpath + '/edit', app.editWin, 'payer');" } }, { "_icon": "item", "text": "delItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delItem", "icon": "delete", "text": "删除", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'payer');" } }, { "_icon": "item", "text": "licenseItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "licenseItem", "icon": "card", "text": "证书", "keys": "Ctrl+M" }, "events": { "click": "let row = app.grid1.selection, win = app.licenseWin;\n\nif (!row) {\n Wb.tipSelect();\n return;\n}\napp.selectRow = row;\nWb.setValue(win, row.data);\nwin.show();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "fieldName": "sdate", "text": "日期", "width": "14em", "render": "let wrapEl = el.addEl('w-row w-align-center');\nel.removeCls('w-text');\nwrapEl.addEl('w-item-icon w-icon icon-' + (data.total_price == null ? 'help1' : 'ok'));\nwrapEl.addEl('w-text').textContent = value.dateTimeText;" } }, { "_icon": "column", "text": "idCol", "cls": "Wb.Column", "properties": { "cid": "idCol", "fieldName": "sid", "text": "序列号", "width": "11em" } }, { "_icon": "column", "text": "payerCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "payerCol", "fieldName": "payer", "text": "付款人", "width": "15em" } }, { "_icon": "column", "text": "licenseeCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "licenseeCol", "fieldName": "licensee", "text": "被授权人", "width": "15em" } }, { "_icon": "column", "text": "usdCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "usdCol", "fieldName": "usd", "text": "美元", "width": "4em", "checkBox": "roTrue" } }, { "_icon": "column", "text": "priceCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "priceCol", "fieldName": "total_price", "text": "实付总价", "type": "floatText", "width": "7em" } }, { "_icon": "column", "text": "price1Col", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "price1Col", "text": "应付总价", "width": "14em", "sortable": "false", "render": "let user = data.user_count, year = 1, price;\n\nprice = Math.round((10500 + (179 - (user / 20)) * (user - 10)) * year * (10 - year / 1.5) / 10);\nprice *= data.total_count;\nif (data.online_support)\n price += (24000 + user * 40);\nreturn '¥' + price.intText + ' / $' + Math.round(price / 6).intText;" } }, { "_icon": "column", "text": "contactCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "contactCol", "fieldName": "contact", "text": "联系人", "width": "7em" } }, { "_icon": "column", "text": "emailCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "emailCol", "fieldName": "email", "text": "电子邮件", "width": "13em" } }, { "_icon": "column", "text": "phoneCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "phoneCol", "fieldName": "phone", "text": "联系电话" } }, { "_icon": "column", "text": "supportCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "supportCol", "fieldName": "online_support", "text": "技术支持", "width": "6em", "checkBox": "roTrue" } }, { "_icon": "column", "text": "usersCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "usersCol", "fieldName": "user_count", "text": "用户数量", "width": "6em" } }, { "_icon": "column", "text": "yearsCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "yearsCol", "fieldName": "years", "text": "使用年限", "width": "6em" } }, { "_icon": "column", "text": "countCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "countCol", "fieldName": "total_count", "text": "授权数量", "width": "6em" } }, { "_icon": "column", "text": "remarkCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "remarkCol", "fieldName": "remark", "text": "备注", "width": "20em", "sortable": "false" } } ] } ] } ] } ] } # admin/cms/run-log/select-ip-count.xwl Title: select-ip-count Description: Select ip count list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select ip count list", "serverScript": "function main() {\n let dbName = Wb.getConn().dbName.toLowerCase();\n if (dbName.includes('sql server'))\n Wb.sendRowx('select convert(varchar(100), log_date, 23) as date,count(distinct ip_addr) as ct from wb_update group by convert(varchar(100), log_date, 23) order by date desc');\n else\n Wb.sendRowx('select date(log_date) as date,count(distinct ip_addr) as ct from wb_update group by date(log_date) order by date(log_date) desc');\n}\nmain();" }, "_icon": "module" } # admin/cms/run-log/select.xwl Title: select Description: Select run logs ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select run logs", "serverScript": "function main() {\n Wb.sendRowx({ sql: 'select * from wb_update ' + Wb.getOrderSql(), rs: 2000 });\n}\nmain();" }, "_icon": "module" } # admin/cms/run-log.xwl Title: 运行日志 Description: Run log ```json { "title": "运行日志", "icon": "play", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Run log" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1", "padding": "true" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "listGrid", "cls": "Wb.Grid", "properties": { "cid": "listGrid", "title": "运行日志", "icon": "log", "url": "@xpath + '/select'", "maxHeight": "20em", "columnsSortable": "true", "sorters": "{name:'log_date',desc:true}", "textSelectable": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "logDateCol", "cls": "Wb.Column", "properties": { "cid": "logDateCol", "text": "日期", "fieldName": "log_date", "width": "12em" } }, { "_icon": "column", "text": "ipAddrCol", "cls": "Wb.Column", "properties": { "cid": "ipAddrCol", "text": "IP 地址", "fieldName": "ip_addr", "width": "10em" } }, { "_icon": "column", "text": "userNameCol", "cls": "Wb.Column", "properties": { "cid": "userNameCol", "text": "用户名称", "fieldName": "user_name" } }, { "_icon": "column", "text": "macCol", "cls": "Wb.Column", "properties": { "cid": "macCol", "text": "机器码", "fieldName": "mac" } }, { "_icon": "column", "text": "computerNameCol", "cls": "Wb.Column", "properties": { "cid": "computerNameCol", "text": "计算机名", "fieldName": "computer_name" } }, { "_icon": "column", "text": "userDomainCol", "cls": "Wb.Column", "properties": { "cid": "userDomainCol", "text": "用户域", "fieldName": "user_domain" } }, { "_icon": "column", "text": "osNameCol", "cls": "Wb.Column", "properties": { "cid": "osNameCol", "text": "操作系统", "fieldName": "os_name" } }, { "_icon": "column", "text": "appTitleCol", "cls": "Wb.Column", "properties": { "cid": "appTitleCol", "text": "应用标题", "fieldName": "app_title", "width": "13em" } }, { "_icon": "column", "text": "licenseeCol", "cls": "Wb.Column", "properties": { "cid": "licenseeCol", "text": "被授权人", "fieldName": "licensee", "width": "13em" } }, { "_icon": "column", "text": "snCol", "cls": "Wb.Column", "properties": { "cid": "snCol", "text": "序列号", "fieldName": "sn" } } ] } ] }, { "_icon": "panel", "text": "chartPanel", "cls": "Wb.Panel", "properties": { "cid": "chartPanel", "title": "IP统计图", "layout": "fit", "height": "30em" }, "_expanded": true, "items": [ { "_icon": "chart-bar", "text": "ipChart", "cls": "Wb.Chart", "properties": { "cid": "ipChart" } } ] }, { "_icon": "grid", "text": "ipTotalGrid", "cls": "Wb.Grid", "properties": { "cid": "ipTotalGrid", "title": "按IP统计", "icon": "total", "maxHeight": "20em", "url": "@xpath + '/select-ip-count'", "pageSize": "1000", "textSelectable": "true" }, "events": { "success": "let xAxis = [], series = [], data;\n\nthis.each(item => {\n data = item.data;\n xAxis.push(data.date);\n series.push(data.ct);\n}, true, true);\napp.ipChart.option = {\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow'\n }\n },\n xAxis: {\n type: 'category',\n data: xAxis\n },\n yAxis: {\n type: 'value'\n },\n series: [\n {\n data: series,\n type: 'line',\n smooth: true\n }\n ]\n};" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "日期", "fieldName": "date", "width": "12em" } }, { "_icon": "column", "text": "ctCol", "cls": "Wb.Column", "properties": { "cid": "ctCol", "text": "数量", "fieldName": "ct" } } ] } ] } ] } ] } # admin/config/add.xwl Title: add Description: Add config item ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add config item", "serverScript": "Wb.checkDemo();\nfunction main() {\n let { nameEditor, typeEditor, valueEditor, listEditor, descEditor } = Params;\n Config.set(nameEditor, valueEditor, typeEditor, listEditor, descEditor);\n}\nmain();" }, "_icon": "module" } # admin/config/del.xwl Title: del Description: Delete config items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete config items", "serverScript": "Wb.checkDemo();\nfunction main() {\n Config.remove(Params.nameEditor);\n}\nmain();" }, "_icon": "module" } # admin/config/edit.xwl Title: edit Description: Edit config item ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit config item", "serverScript": "Wb.checkDemo();\nfunction main() {\n let { nameEditor, valueEditor } = Params;\n Wb.setConfig(nameEditor, valueEditor);\n}\nmain();" }, "_icon": "module" } # admin/config/select-list.xwl Title: select-list Description: Select config items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select config items", "serverScript": "function main() {\n let items = [], path = Params.path + '.', pos = path.length, name, value, type,\n object = new Wb.File(true, 'wb/system/config.json').object;\n\n Wb.each(object, (k, v) => {\n if (k.startsWith(path)) {\n name = k.substr(pos);\n if (!name.includes('.')) {\n v = object[k];\n value = v.value;\n type = v.type;\n if (type == 'object' || type == 'array')\n value = Wb.encode(value);\n items.push({\n name, value, type, list: Wb.encode(v.list),\n desc: v?.[Str.lang] ?? v?.text\n });\n }\n }\n });\n items.mixSort('name');\n Wb.send(items);\n}\nmain();" }, "_icon": "module" } # admin/config/select-tree.xwl Title: select-tree Description: Select config folder items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select config folder items", "serverScript": "function main() {\n let items = [], buffer = Config.getBuffer();\n buffer.forEach(k => items.push(k.beforeItem('.')));\n items = Wb.Builder.getTree(items, '.');\n items.find(item => item.text == 'sys')._expanded = true;\n Wb.send(items);\n}\nmain();" }, "_icon": "module" } # admin/config.xwl Title: System Config Description: System configuration tool ```json { "title": "@systemConfig", "icon": "gear", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "System configuration tool" }, "_icon": "module", "_expanded": true, "events": { "initialize": "/**\n * System configuration management tools.\n */\nWb.define(app, {\n /** @property {String} - The current config item path. */\n get$path() {\n return app.tree1.getPath('text', '.');\n },\n /**\n * Fix the value. @priv\n * @param {Object} value Value to be fixed.\n * @param {String} type Value type.\n * @return {Object} The fixed value.\n */\n fixValue(value, type) {\n if (type == 'object' || type == 'array')\n return Wb.encode(Wb.parse(value));\n else if (type == 'date')\n return value.textValue;\n else\n return value;\n },\n /**\n * Verify the validity of the input value. @priv\n * @return {Boolean} Return true if the value is valid.\n */\n verifyValue() {\n let type = app.typeEditor.value, value = app.valueEditor.value, isArray, valid;\n\n isArray = type == 'array';\n if (isArray || type == 'object') {\n try {\n valid = isArray ? Wb.isArray(Wb.parse(value)) : Wb.isObject(Wb.parse(value));\n } catch (e) {\n valid = false;\n }\n if (!valid) {\n Wb.warn(Str.invalidValue.format(value), f => app.valueEditor.focus());\n return false;\n }\n }\n return true;\n },\n /**\n * Creates a value editor of the specified type. @priv\n * @param {String} type The value type.\n * @param {String} [data] List data, only applicable when the type is enum.\n * @return {Wb.Control} The created editor.\n */\n createValueEditor(type, data) {\n let editor;\n switch (type) {\n case 'string':\n editor = { cname: 'text' };\n break;\n case 'int':\n case 'long':\n editor = { cname: 'number', decimalCount: 0 };\n break;\n case 'double':\n editor = { cname: 'number' };\n break;\n case 'date':\n editor = { cname: 'datetime' };\n break;\n case 'bool':\n editor = { cname: 'toggle' };\n break;\n case 'enum':\n if (data)\n editor = { cname: 'select', forceSelect: true, data };\n else\n editor = { cname: 'text' };\n break;\n default:\n editor = { cname: 'textArea', height: '6em' };\n }\n if (type != 'string')\n editor.required = true;\n Wb.apply(editor, { text: Str.value, cid: 'valueEditor', app });\n return Wb.create(editor);\n }\n});" }, "items": [ { "_icon": "window", "text": "addWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "addWin", "dialog": "true", "layout": "grid1", "width": "60em", "title": "@Str.add", "icon": "add" }, "events": { "ok": "let win = this, params = Wb.getValue(win), name = params.nameEditor, node = app.tree1, path,\n newNode, valid, listValue = params.listEditor, type = params.typeEditor, fixedList;\n\nif (listValue) {\n try {\n valid = Wb.isArray(Wb.parse(listValue));\n } catch (e) {\n valid = false;\n }\n if (!valid) {\n Wb.warn(Str.invalidValue.format(listValue), f => app.listEditor.focus());\n return;\n }\n}\nif (!app.verifyValue())\n return;\nfixedList = Wb.encode(Wb.parse(listValue));\nparams.listEditor = fixedList;\nif (name.startsWith('.'))\n name = app.path + name;\nelse if (!name.includes('.'))\n name = app.path + '.' + name;\nparams.nameEditor = name;\nWb.ajax({\n url: xpath + '/add',\n params,\n success() {\n path = name.beforeItem('.');\n name = name.lastItem('.');\n path.split('.').forEach(item => {\n node = node.find(sub => sub.text == item) ?? node.addData({ text: item, items: [] });\n });\n if (node.selected) {\n let desc = params.descEditor, trimDesc = desc.trim();\n\n //allow to set multi-lan desc\n if (trimDesc.startsWith('{') && trimDesc.endsWith('}')) {\n try {\n trimDesc = Wb.parse(trimDesc);\n desc = trimDesc[Str.lang] ?? trimDesc.text;\n } catch (e) {\n //ignore\n }\n }\n app.grid1.addData({\n name, value: app.fixValue(params.valueEditor, type), type, desc, list: fixedList\n }).select();\n } else {\n app.selConfigName = name;\n node.select();\n }\n win.hide();\n }\n});" }, "items": [ { "_icon": "text", "text": "nameEditor", "cls": "Wb.Text", "properties": { "cid": "nameEditor", "text": "@Str.name", "required": "true" } }, { "_icon": "combo", "text": "typeEditor", "cls": "Wb.Select", "_expanded": false, "properties": { "cid": "typeEditor", "text": "@Str.type", "data": "['string', 'int', 'long', 'double', 'date', 'bool', 'enum', 'array', 'object', 'text']", "editable": "false", "valueIndex": "0", "required": "true" }, "events": { "select": "let addWin = app.addWin, type = data.text;\naddWin.down('valueEditor')?.destroy();\naddWin.insertAfter(app.createValueEditor(type), this);\nif (type == 'enum') {\n if (!app.listEditor)\n addWin.insertAfter({ cname: 'text', text: Str.list, cid: 'listEditor', required: true, app },\n app.valueEditor);\n} else {\n app.listEditor?.destroy();\n}\naddWin.show();" } }, { "_icon": "text", "text": "valueEditor", "cls": "Wb.Text", "_expanded": false, "properties": { "cid": "valueEditor", "text": "@Str.value" } }, { "_icon": "text", "text": "descEditor", "cls": "Wb.Text", "properties": { "cid": "descEditor", "text": "@Str.desc", "required": "true" } } ] }, { "_icon": "window", "text": "editWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "editWin", "dialog": "true", "layout": "grid1", "width": "60em", "title": "@Str.edit", "icon": "edit" }, "events": { "ok": "let win = this, params = Wb.getValue(win), rec = app.grid1.selection;\n\nif (!app.verifyValue())\n return;\nparams.nameEditor = app.path + '.' + rec.data.name;\nWb.ajax({\n url: xpath + '/edit',\n params,\n success() {\n let value;\n\n try {\n value = app.fixValue(params.valueEditor, rec.data.type)\n } catch (e) {\n Wb.error(Str.invalidExpress);\n return;\n }\n rec.set('value', value);\n win.hide();\n }\n});" } }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "row" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "let addWin = app.addWin;\n\nWb.reset(Wb.pluck(addWin.children, ['nameEditor', 'valueEditor', 'listEditor', 'descEditor']));\naddWin.show();" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let data = app.grid1.selection?.data;\nif (!data) {\n Wb.tipSelect();\n return;\n}\nlet editWin = app.editWin, children = editWin.children, list = data.list;\nchildren.valueEditor?.destroy();\neditWin.add(app.createValueEditor(data.type, list ? Wb.decode(list) : null));\neditWin.subTitle = data.name;\nchildren.valueEditor.value = data.value;\neditWin.show();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "let rec = app.grid1.selection;\nif (!rec) {\n Wb.tipSelect();\n return;\n}\nWb.confirm(Wb.getActionHint(rec, 'name'), f => {\n Wb.ajax({\n url: xpath + '/del',\n params: { nameEditor: app.path + '.' + rec.data.name },\n success() {\n app.grid1.delRecords();\n }\n });\n});" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "refreshBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshBtn", "text": "@Str.refresh", "icon": "refresh" }, "events": { "click": "app.tree1.loadSelect();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "label", "text": "pathLabel", "cls": "Wb.Label", "properties": { "cid": "pathLabel", "textSelectable": "true" } } ] }, { "_icon": "tree-view", "text": "tree1", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "tree1", "width": "17em", "url": "@xpath + '/select-tree'", "autoSelect": "true" }, "events": { "selectionchange": "let path = app.path;\napp.grid1.load({ params: { path } });\napp.pathLabel.text = path;" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" }, "_expanded": true }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "flex": "1", "pagingBar": "false", "url": "@xpath + '/select-list'", "autoLoad": "false" }, "_expanded": true, "events": { "selectionchange": "let item = this.selection, node = app.tree1.selection;\napp.pathLabel.text = node.getPath('text', '.') + (item ? ('.' + item.data.name) : '');", "success": "/** @property {String} selConfigName The name of the configuration item selected after the table is loaded successfully. */\nif (app.selConfigName) {\n this.find(item => item.data.name == app.selConfigName)?.select();\n app.selConfigName = null;\n}", "itemdblclick": "app.editBtn.fireEvent('click');" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "nameCol", "fieldName": "name", "text": "@Str.name", "width": "14em" }, "text": "nameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "valueCol", "fieldName": "value", "text": "@Str.value", "width": "23em", "align": "left", "render": "if (data.type == 'date')\n return value.dateValue.dateTimeText;\nelse\n return value;" }, "text": "valueCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "descCol", "fieldName": "desc", "text": "@Str.desc", "width": "-1" }, "text": "descCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # admin/console/socket.xwl Title: socket Description: System console socket monitor ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n switch (event) {\n case 'open':\n com.wb.tool.Console.startCapture();\n break;\n case 'close':\n com.wb.tool.Console.stopCapture();\n break;\n }\n}\nmain();", "remark": "System console socket monitor" }, "_icon": "module" } # admin/console.xwl Title: Console Description: System console ```json { "title": "@console", "icon": "console", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "System console" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Number} - Default console size. */\n consoleSize: 100,\n /** @property {Number} - Current console total size. */\n totalSize: 0,\n /** @property {Boolean} - Whether allow to auto scroll to bottom. */\n allowScroll: false,\n /** @property {Boolean} - Parent card visible. */\n cardVisible: true,\n /**\n * Scroll to bottom.\n * @param {Boolean} [force] Force to bottom.\n */\n toBottom(force) {\n if (force || app.allowScroll && app.toBottomItem.active) {\n let el = app.viewer1.el;\n el.scrollTop = el.scrollHeight;\n app.allowScroll = false;\n }\n },\n /**\n * Add data to the console.\n * @param {String} [message] Console message.\n * @return {type} comments\n */\n addData(message) {\n let viewer = app.viewer1, el = viewer.el, maxLen = app.consoleSize * 1024, span;\n\n span = el.addTag('span');\n span.textContent = message;\n // Prevent too many dom fragments\n span.xSize = Math.max(message.length, 100);\n app.totalSize += span.xSize;\n if (app.totalSize > maxLen) {\n let children = el.children, i, j = children.length;\n for (i = 0; i < j; i++) {\n span = children[i];\n app.totalSize -= span.xSize;\n span.remove();\n i--;\n j--;\n if (app.totalSize < maxLen)\n break;\n }\n }\n app.allowScroll = true;\n if (app.cardVisible) {\n app.toBottom();\n }\n }\n});" }, "items": [ { "_icon": "plug", "text": "socket1", "cls": "Wb.Socket", "properties": { "cid": "socket1", "name": "$console", "xwl": "admin/console/socket.xwl" }, "events": { "message": "if (!app.pauseItem.active)\n app.addData(e.data);" }, "_expanded": true }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "autoScroll": "true", "layout": "fit" }, "_expanded": true, "events": { "ready": "parentContainer?.on('show', f => {\n app.cardVisible = true;\n app.toBottom();\n});\nparentContainer?.on('hide', f => {\n app.cardVisible = false;\n});" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "pauseItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "pauseItem", "icon": "pause", "text": "@Str.pause", "enableToggle": "true", "activeBgColor": "false" }, "events": { "toggle": "let item = this;\n\nitem.icon = active ? 'resume' : 'pause';\nitem.text = active ? Str.resume : Str.pause;" } }, { "_icon": "item", "text": "clearItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "clearItem", "icon": "recycle", "text": "@Str.clear" }, "events": { "click": "app.viewer1.el.clearChildren();\napp.totalSize = 0;" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "sizeItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "sizeItem", "text": "@Str.size", "icon": "property" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "gap": ".5em", "width": "15em" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "sizeSlider", "cls": "Wb.Slider", "properties": { "cid": "sizeSlider", "maxValue": "10000", "flex": "1", "minValue": "100", "value": "@app.consoleSize", "tabIndex": "null", "focusable": "false", "step": "100" }, "_expanded": true, "events": { "change": "app.consoleSize = value;" } }, { "_icon": "label", "text": "kbLabel", "cls": "Wb.Label", "properties": { "cid": "kbLabel", "text": "KB" } } ] } ] } ] }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "item", "text": "toBottomItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "toBottomItem", "icon": "bottom", "active": "true", "activeBgColor": "false", "tip": "Auto scroll to bottom" }, "events": { "toggle": "if (active)\n app.toBottom(true);" } } ] }, { "_icon": "desktop", "text": "viewer1", "cls": "Wb.Viewer", "properties": { "cid": "viewer1", "cls": "w-pre", "style": "line-height:1.8" } } ] } ] } # admin/dbc/config.xwl Title: config Description: Edit database source ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit database source", "serverScript": "function main() {\n let file = new Wb.File(true, 'wb/system/db/source.json'), configs = file.object, data, name = Params.name;\n\n /**\n * Sets the missing Boolean members in the data object. @priv\n * @param {String} name The data source name.\n * @param {Object} data Data object.\n */\n function setBoolMembers(name, data) {\n const members = {\n cacheState: true, autoCommitOnReturn: true, rollbackOnReturn: true, testOnBorrow: true,\n logExpiredConnections: true, lifo: true\n };\n Wb.each(members, (k, v) => {\n data[k] ??= v;\n });\n }\n /**\n * Determines whether the name is valid.\n */\n function checkName(name) {\n if (configs[name])\n Wb.raise(Str.alreadyExists.format(name));\n }\n\n /**\n * Operate data source.\n */\n function operateDataSource(mode) {\n Wb.checkDemo();\n const BasicDataSource = Java.type('org.apache.commons.dbcp2.BasicDataSource').class;\n const DefaultPooledObjectInfo = Java.type('org.apache.commons.pool2.impl.DefaultPooledObjectInfo').class;\n let dataSource, poolField, objectField, pool, object, conn, id, findId = Params.id, items = [];\n\n dataSource = DataSource.getSource(name);\n poolField = BasicDataSource.getDeclaredField('connectionPool');\n poolField.setAccessible(true);\n objectField = DefaultPooledObjectInfo.getDeclaredField('pooledObject');\n objectField.setAccessible(true);\n pool = poolField.get(dataSource);\n if (pool == null) {\n dataSource.getConnection().close(); // load lib\n pool = poolField.get(dataSource);\n }\n if (mode == 'clear') {\n pool.clear();\n return;\n }\n pool.listAllObjects().forEach(item => {\n object = objectField.get(item);\n conn = object.getObject();\n id = conn.hashCode();\n if (mode == 'close' && id == findId) {\n conn.close();\n return;\n }\n if (mode == 'get') {\n items.push({\n id,\n borrowedCount: object.getBorrowedCount(),\n createTime: new Date(object.getCreateTime()),\n lastBorrowTime: new Date(object.getLastBorrowTime()),\n lastReturnTime: new Date(object.getLastReturnTime()),\n lastUsedTime: new Date(object.getLastUsedTime()),\n isClosed: conn.isClosed()\n });\n }\n });\n if (mode == 'get') {\n items.mixSort('id');\n return {\n pool: {\n maxTotal: dataSource.getMaxTotal().intText, numActive: dataSource.getNumActive().intText,\n numIdle: dataSource.getNumIdle().intText, createdCount: pool.getCreatedCount().intText,\n destroyedCount: pool.getDestroyedCount().intText, borrowedCount: pool.getBorrowedCount().intText,\n numWaiters: pool.getNumWaiters().intText\n }, items\n };\n }\n }\n\n /**\n * Service handler.\n */\n function service() {\n switch (Params.type) {\n case 'list':\n //Get all database list\n Wb.send(Wb.load('wb/ss/dbe.mjs').getDbNames(true));\n break;\n case 'get':\n //Get details\n data = configs[name];\n data.text = name;\n setBoolMembers(name, data);\n data.password &&= Wb.UserUtil.protectedText;\n Wb.send(data);\n break;\n case 'add':\n //Add new database\n checkName(name);\n data = { driverClassName: 'driverClassName', url: 'url' };\n configs[name] = data;\n file.text = Wb.encodePretty(configs);\n DataSource.setSource(name, Wb.toJava(data));\n break;\n case 'delete':\n if (name == Wb.getConfig('sys.db.defaultSource'))\n Wb.raise(Str.cannotDelete.format(name));\n delete configs[name];\n file.text = Wb.encodePretty(configs);\n DataSource.removeSource(name);\n break;\n case 'copy':\n //Copy database\n let newName = Params.newName, dbConfigs;\n checkName(newName);\n dbConfigs = configs[newName] = configs[name];\n file.text = Wb.encodePretty(configs);\n DataSource.setSource(newName, Wb.toJava(dbConfigs));\n break;\n case 'save':\n //Save configs\n let oldName = Params.oldName, deferName = oldName != name, newPwd, oldPwd;\n if (deferName)\n checkName(name);\n data = Wb.decode(Params.data);\n delete data.text;\n newPwd = data.password;\n if (newPwd) {\n oldPwd = configs[name]?.password;\n if (newPwd == Wb.UserUtil.protectedText)\n newPwd = oldPwd;\n else\n newPwd = newPwd ? '$$:' + Encrypter.encrypt(newPwd, Config.key) : '';\n data.password = newPwd;\n }\n configs[name] = data;\n if (deferName)\n delete configs[oldName];\n file.text = Wb.encodePretty(configs);\n DataSource.setSource(name, Wb.toJava(data));\n if (deferName) {\n DataSource.removeSource(oldName);\n if (oldName == Config.defaultSource)\n Wb.setConfig('sys.db.defaultSource', name);\n }\n if (name == Config.defaultSource) {\n DataSource.defaultDataSource = DataSource.getSource(name);\n }\n break;\n case 'test':\n Wb.getConn(name).close();\n break;\n case 'property':\n Wb.send(operateDataSource('get'));\n break;\n case 'clear':\n operateDataSource('clear');\n break;\n case 'close':\n operateDataSource('close');\n break;\n case 'abort':\n operateDataSource('abort');\n break;\n }\n }\n //Start execute\n file.lock();\n try {\n service();\n } finally {\n file.unlock();\n }\n}\nmain();" }, "_icon": "module" } # admin/dbc/set-default.xwl Title: set-default Description: Set default database ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set default database", "serverScript": "function main() {\n /**\n * Sets the specified database as the default database. @priv\n */\n function setDefaultDb() {\n let defaultSource = Config.defaultSource, destName = Params.name, destSource, script;\n\n if (defaultSource == Params.name)\n Wb.raise('The destination is the same as the source database.');\n script = Wb.Query.removeComments(new Wb.File(true, 'wb/system/db/sqls.sql').text);\n script = replaceTypes(script, Params.dbType);\n defaultSource = Wb.getConn(defaultSource);\n destSource = Wb.getConn(destName);\n createTables(script, defaultSource, destSource, Wb.getBool('overwrite'));\n Wb.setConfig('sys.db.defaultSource', destName);\n //Explicit commit\n destSource.commit();\n DataSource.defaultDataSource = DataSource.getSource(destName);\n SysUtil.reloadSystem(true);\n }\n\n /**\n * Replace the type variable in the script. @priv\n * @param {String} script The script.\n * @param {String} dbType The db type.\n */\n function replaceTypes(script, dbType) {\n let types = new Wb.File(true, 'wb/system/db/types.json').object;\n\n return script.replaceParams(types[dbType]);\n }\n\n /**\n * Check whether the system tables of the specified database are consistent with the script. @priv\n */\n function checkTables() {\n let script, db, tableName, needCreate = false;\n\n db = Wb.getConn();\n script = Wb.Query.removeComments(new Wb.File(true, 'wb/system/db/sqls.sql').text);\n script = replaceTypes(script, Params.dbType);\n script.split(';').forEach(sql => {\n sql = sql.trim();\n if (!sql) return;\n if (sql.startsWith('create table')) {\n tableName = sql.substring(sql.indexOf('table') + 5, sql.indexOf('(') - 1).trim();\n needCreate = !checkConsistent(db, tableName, sql);\n if (needCreate)\n Wb.sql(sql, db);\n } else {\n if (needCreate)\n Wb.sql(sql, db);\n }\n });\n }\n\n /**\n * Create system tables. @priv\n * @param {String} script SQL script.\n * @param {Wb.Connection} source The source connection.\n * @param {Wb.Connection} dest The dest connection.\n * @param {Boolean} overwrite Whether to overwrite tables that already exist.\n */\n function createTables(script, source, dest, overwrite) {\n const emptyTables = ['wb_debug_files', 'wb_log'];\n let tables = script.split(';'), tableName, rs, needCreate = false, len;\n len = tables.length;\n tables.forEach((sql, index) => {\n sql = sql.trim();\n if (!sql) return;\n if (!sql.startsWith('create table')) {\n if (needCreate)\n Wb.sql(sql, dest);\n return;\n }\n tableName = sql.substring(sql.indexOf('table') + 5, sql.indexOf('(') - 1).trim();\n Wb.send([index / len * 100, Str.process.format(tableName)], 'sys.dbc');\n needCreate = false;\n if (overwrite) {\n try {\n Wb.sql('drop table ' + tableName, dest);\n } catch (e) {\n dest.rollback();\n }\n needCreate = true;\n } else {\n needCreate = !checkConsistent(dest, tableName, sql);\n }\n if (needCreate) {\n Wb.sql(sql, dest);\n if (!emptyTables.includes(tableName)) {\n try {\n try {\n rs = Wb.sqlRS('select * from ' + tableName, source);\n } catch (ex) {\n source.rollback();\n return;\n }\n // start trans in copyTo by default\n rs.copyTo(tableName, dest);\n rs.close();\n dest.commit();\n } catch (e) {\n Wb.sql('drop table ' + tableName, dest);\n Wb.raise(e);\n }\n }\n }\n });\n }\n\n /**\n * Check whether the target table is consistent with the source table, and an exception is thrown\n * if it is inconsistent.\n * @param {Wb.Connection} db Database connection.\n * @param {String} tableName Table name.\n * @param {String} sql SQL script.\n * @return {Boolean} Whether the table exists.\n */\n function checkConsistent(db, tableName, sql) {\n let rs, meta, colCount, oldFields, realCount = 0;\n\n try {\n rs = Wb.sqlRS('select * from ' + tableName + ' where 1=0', db);\n } catch (e) {\n db.rollback();\n //ignored if the table does not exist\n return false;\n }\n meta = rs.metaData;\n colCount = meta.getColumnCount();\n oldFields = sql.substring(sql.indexOf('(') + 1, sql.lastIndexOf(')') - 1).trim().split('\\n');\n oldFields.forEach(fieldName => {\n fieldName = fieldName.trimLeft();\n if (!fieldName.toLowerCase().startsWith('constraint ')) {\n realCount++;\n if (realCount <= colCount) {\n fieldName = fieldName.substr(0, fieldName.indexOf(' '));\n if (!fieldName.equalsIC(meta.getColumnLabel(realCount)))\n Wb.raise(Str.tableInconsistent.format(tableName, fieldName));\n }\n }\n });\n if (colCount != realCount)\n Wb.raise(Str.tableInconsistent.format(tableName, `${colCount} / ${realCount}`));\n rs.close();\n return true;\n }\n\n /**\n * Gets the database type. @priv\n */\n function getDbType() {\n Wb.send(Wb.getConn(Params.name).metaData.getDatabaseProductName());\n }\n switch (Params.type) {\n case 'get-db':\n getDbType();\n break;\n case 'create':\n checkTables();\n break;\n case 'set-default':\n let lock = new Wb.Lock('dbc.setDefault');\n try {\n setDefaultDb();\n } finally {\n lock.unlock();\n }\n break;\n }\n}\nmain();" }, "_icon": "module" } # admin/dbc.xwl Title: Database Configuration Description: Database source configuration ```json { "title": "@dbc", "icon": "data-provider", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Database source configuration" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /** @property {String} - Gets the currently selected database name. */\n get$currentName() {\n return app.listTree.selection.text;\n },\n /**\n * Fires when the controls value changes.\n */\n onChange() {\n if (!app.stopChange)\n app.saveBtn.disabled = false;\n },\n /**\n * Open a prompt window for database operations. @priv\n * @param {String} name Database name, null represents the default db.\n * @param {String} title The window title.\n * @param {String} icon The window icon.\n * @param {Function} callback The callback function of the window.\n * @param {Boolean} [overwrite] Whether to create an override option checkbox.\n */\n promptSetDb(name, title, icon, callback, overwrite) {\n Wb.ajax({\n url: xpath + '/set-default&type=get-db',\n params: { name },\n success(resp) {\n const data = [\n 'db2', 'derby', 'dameng', 'firebird', 'h2', 'hsqldb', 'informix', 'kingbase', 'mariadb', 'mysql',\n 'oracle', 'pointbase', 'postgresql', 'sap', 'sqlite', 'sql server', 'sybase', 'teradata'\n ];\n let value, items;\n resp = resp.toLowerCase();\n value = data.find(item => resp.includes(item));\n if (!value) {\n if (resp.includes('sqlserver'))\n value = 'sql server';\n else if (resp.includes('da meng') || resp.includes('dm'))\n value = 'dameng';\n }\n items = [{\n text: Str.dbType, cname: 'select', cid: 'dbType', required: true, forceSelect: true, data, value\n }];\n if (overwrite)\n items.push({ label: Str.overwriteTables, cname: 'check', cid: 'overwrite', showEmptyLabel: true });\n Wb.prompt({ title, icon }, items, callback);\n }\n });\n },\n /**\n * Save data.\n * @param {Function} [callback] Fires after success.\n */\n save(callback) {\n if (Wb.verify(app.detailPanel)) {\n Wb.ajax({\n url: xpath + '/config&type=save',\n params: { oldName: app.editNode.text, name: app.text.value, data: Wb.getValue(app.detailPanel, true) },\n success() {\n app.saveBtn.disabled = true;\n app.editNode.text = app.text.value;\n callback?.call();\n }\n });\n }\n },\n /**\n * Load connection properties.\n * @param {Function} [callback] Callback function.\n */\n loadProperties(callback) {\n let name = app.currentName;\n Wb.ajax({\n url: xpath + '/config&type=property',\n params: { name },\n json: true,\n success(resp) {\n let win = app.propWin;\n\n Wb.setValue(win, resp.pool);\n app.connGrid.data = resp.items;\n callback?.();\n }\n });\n }\n});", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "tags": "", "items": [ { "_icon": "plug", "text": "socket1", "cls": "Wb.Socket", "properties": { "cid": "socket1", "name": "sys.dbc" }, "events": { "message": "if (app.acceptProgress)\n Wb.progress(Wb.decode(e.data));" } }, { "_icon": "window", "text": "propWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "propWin", "modal": "true", "layout": "form1", "icon": "property", "title": "@Str.property", "width": "85em", "height": "46em", "padding": "1em" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "closeItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "closeItem", "icon": "security", "text": "Close" }, "events": { "click": "let name = app.currentName, rec = app.connGrid.selection, data = rec?.data;\n\nif (!rec) {\n Wb.tipSelect();\n return;\n}\nif (data.isClosed) {\n Wb.tipWarn('The connection is already closed.');\n return;\n}\nWb.confirm(`Are you sure to close the connection \"${data.id.intText}\"?`, f => {\n Wb.ajax({\n url: xpath + '/config&type=close',\n params: { name, id: data.id },\n success(resp) {\n app.loadProperties();\n rec.proxy.isClosed = true;\n }\n });\n});" } }, { "_icon": "item", "text": "clearItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "clearItem", "icon": "brush1", "text": "Clear" }, "events": { "click": "let name = app.currentName;\nWb.confirm('Are you sure to clear all idle connections?', f => {\n Wb.ajax({\n url: xpath + '/config&type=clear',\n params: { name },\n success(resp) {\n app.loadProperties();\n }\n });\n});" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "refreshItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshItem", "icon": "refresh", "text": "Refresh" }, "events": { "click": "app.loadProperties();" } } ] }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "flexWrap": "true", "gap": "true", "defaults": "({ width: '11em' })" }, "_expanded": true, "items": [ { "_icon": "text", "text": "maxTotal", "cls": "Wb.Text", "properties": { "cid": "maxTotal", "text": "Max", "readonly": "true", "width": "8em" } }, { "_icon": "text", "text": "numActive", "cls": "Wb.Text", "properties": { "cid": "numActive", "text": "Active", "readonly": "true", "width": "9em" } }, { "_icon": "text", "text": "numIdle", "cls": "Wb.Text", "properties": { "cid": "numIdle", "text": "Idle", "readonly": "true", "width": "8em" } }, { "_icon": "text", "text": "createdCount", "cls": "Wb.Text", "properties": { "cid": "createdCount", "text": "Created", "readonly": "true", "width": "13em" } }, { "_icon": "text", "text": "destroyedCount", "cls": "Wb.Text", "properties": { "cid": "destroyedCount", "text": "Destroyed", "readonly": "true", "width": "14em" } }, { "_icon": "text", "text": "borrowedCount", "cls": "Wb.Text", "properties": { "cid": "borrowedCount", "text": "Borrowed", "readonly": "true", "width": "18em" } }, { "_icon": "text", "text": "numWaiters", "cls": "Wb.Text", "properties": { "cid": "numWaiters", "text": "Waiters", "readonly": "true", "width": "9em" } } ] }, { "_icon": "grid", "text": "connGrid", "cls": "Wb.Grid", "properties": { "cid": "connGrid", "flex": "1", "pagingBar": "false", "defaultFields": "({\n createTime: { type: 'date' },\n lastBorrowTime: { type: 'date' },\n lastReturnTime: { type: 'date' },\n lastUsedTime: { type: 'date' }\n})", "reserveScrollbar": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "idCol", "text": "ID", "fieldName": "id", "width": "11em", "render": "if (!data.isClosed) {\n el.parentNode.setStyle('color', '#d75a4a');\n}\nreturn value;" }, "text": "idCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "borrowedCountCol", "text": "Borrowed", "fieldName": "borrowedCount", "width": "13em" }, "text": "borrowedCountCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "createTimeCol", "text": "Create Time", "fieldName": "createTime", "width": "13em" }, "text": "createTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastBorrowTimeCol", "text": "Last Borrow Time", "fieldName": "lastBorrowTime", "width": "13em" }, "text": "lastBorrowTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastReturnTimeCol", "text": "Last Return Time", "fieldName": "lastReturnTime", "width": "13em" }, "text": "lastReturnTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastUsedTimeCol", "text": "Last Used Time", "fieldName": "lastUsedTime", "width": "13em" }, "text": "lastUsedTimeCol", "_expanded": true, "_icon": "column" } ] } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addBtn", "icon": "add", "text": "@Str.add", "keys": "Ctrl+E" }, "events": { "click": "Wb.prompt({ title: Str.add, icon: 'add' }, { cid: 'name', text: Str.name, required: true }, (values, win) => {\n Wb.ajax({\n url: xpath + '/config&type=add',\n params: values,\n success() {\n let node = app.listTree.addData({ text: values.name, _icon: 'database', _leaf: true });\n node.select();\n win.close();\n }\n });\n});" } }, { "_icon": "item", "text": "copyBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "copyBtn", "icon": "copy", "text": "@Str.copy" }, "events": { "click": "let node = app.listTree.selection, name = node.text;\nWb.prompt({ title: Str.copy + ' - ' + name, icon: 'copy' },\n { cid: 'newName', text: Str.name, required: true, value: name + '1', selectOnInit: true },\n (values, win) => {\n values.name = name;\n Wb.ajax({\n url: xpath + '/config&type=copy',\n params: values,\n success() {\n node = app.listTree.insertDataAfter({ text: values.newName, _icon: 'database', _leaf: true }, node);\n node.select();\n win.close();\n }\n });\n });" } }, { "_icon": "item", "text": "deleteBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deleteBtn", "icon": "delete", "text": "@Str.del", "keys": "Ctrl+D" }, "events": { "click": "let name = app.currentName;\nWb.confirm(Str.deleteConfirm.format(name), f => {\n Wb.ajax({\n url: xpath + '/config&type=delete',\n params: { name },\n success() {\n app.saveBtn.disabled = true;\n app.listTree.delRecords();\n }\n });\n});" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "keys": "Ctrl+S", "disabled": "true" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "testBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "testBtn", "icon": "bolt", "text": "@Str.test" }, "events": { "click": "let name = app.currentName, testFn = f => Wb.ajax({\n url: xpath + '/config&type=test',\n params: { name },\n success() {\n Wb.tipDone();\n }\n});\nif (app.saveBtn.disabled)\n testFn();\nelse\n Wb.confirm(Str.modifiedConfirm.format(name), f => {\n app.save(testFn);\n });" } }, { "_icon": "item", "text": "defaultBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "defaultBtn", "icon": "favorite", "text": "@Str.default", "tip": "@Str.setDefaultDb", "disabled": "true" }, "events": { "click": "let listTree = app.listTree, node = listTree.selection, name = node.text;\napp.promptSetDb(name, Str.setDefaultDb + ' - ' + name, 'favorite', (values, win) => {\n let overwrite = values.overwrite, doSetDefault = f => {\n app.acceptProgress = true;\n Wb.ajax({\n url: xpath + '/set-default&type=set-default',\n params: { overwrite, name, dbType: values.dbType },\n mask: { width: '50vw', delay: 0 },\n callback() {\n Wb.unmask();\n },\n success() {\n listTree.cascade(node => {\n node.icon = node.text == name ? 'favorite' : 'database';\n });\n app.defaultBtn.disabled = true;\n app.acceptProgress = false;\n win.close();\n }\n });\n };\n if (overwrite)\n Wb.confirm(Str.doConfirm.format(Str.overwriteTables), doSetDefault);\n else\n doSetDefault();\n}, true);" } }, { "_icon": "item", "text": "createTablesBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "createTablesBtn", "icon": "table", "text": "@Str.createTables", "tip": "@Str.createSysTables" }, "events": { "click": "app.promptSetDb(null, Str.createSysTables, 'table', (params, win) => {\n Wb.ajax({\n url: xpath + '/set-default&type=create',\n params,\n success() {\n win.close();\n }\n });\n});" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "item", "text": "propertyBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "propertyBtn", "icon": "property", "text": "@Str.property" }, "events": { "click": "app.loadProperties(f => {\n let win = app.propWin;\n win.subTitle = app.currentName;\n win.show();\n});" } }, { "_icon": "item", "text": "refreshBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshBtn", "icon": "refresh", "text": "@Str.refresh" }, "events": { "click": "let listTree = app.listTree;\nif (app.saveBtn.disabled)\n listTree.loadSelect();\nelse\n Wb.choose(Str.saveChanges.format(Str.dbc), btn => {\n if (btn == 'yes') {\n app.save(f => listTree.loadSelect());\n } else if (btn == 'no') {\n app.saveBtn.disabled = true;\n listTree.loadSelect();\n }\n });" } } ] }, { "_icon": "tree-view", "text": "listTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "listTree", "url": "@xpath + '/config&type=list'", "width": "15em", "autoSelect": "true" }, "events": { "beforeselect": "let panel = app.detailPanel;\n\nif (app.saveBtn.disabled) {\n Wb.ajax({\n url: xpath + '/config&type=get',\n params: {\n name: item.text\n },\n comps: panel,\n json: true,\n success(data) {\n app.stopChange = true;\n app.editNode = item;\n Wb.setValue(panel, data, true);\n app.stopChange = false;\n }\n });\n} else {\n Wb.choose(Str.saveChanges.format(Str.dbc), btn => {\n if (btn == 'yes') {\n app.save(f => item.select());\n } else if (btn == 'no') {\n app.saveBtn.disabled = true;\n item.select()\n }\n });\n return false;\n}", "select": "app.defaultBtn.disabled = item.icon != 'database';" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "panel", "text": "detailPanel", "cls": "Wb.Panel", "properties": { "cid": "detailPanel", "flex": "1", "layout": "grid1", "wideLabel": "true", "tableStyle": "true", "autoGrid": "up" }, "_expanded": true, "events": { "ready": "Wb.setEvents(this, 'change', app.onChange);" }, "items": [ { "_icon": "title", "text": "title1", "cls": "Wb.Title", "properties": { "cid": "title1", "title": "@Str.general" } }, { "_icon": "text", "text": "text", "cls": "Wb.Text", "properties": { "cid": "text", "text": "@Str.name", "required": "true" }, "_expanded": true }, { "_icon": "text", "text": "desc", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "desc", "text": "@Str.desc" } }, { "_icon": "combo", "text": "driverClassName", "cls": "Wb.Select", "properties": { "cid": "driverClassName", "text": "driverClassName", "data": "[\n 'com.microsoft.sqlserver.jdbc.SQLServerDriver',\n 'oracle.jdbc.driver.OracleDriver',\n 'com.mysql.cj.jdbc.Driver',\n 'org.postgresql.Driver',\n 'org.apache.derby.jdbc.EmbeddedDriver',\n 'com.ibm.db2.jdbc.app.DB2Driver',\n 'com.ibm.db2.jdbc.net.DB2Driver',\n 'com.sybase.jdbc.SybDriver',\n 'com.teradata.jdbc.TeraDriver',\n 'org.h2.Driver',\n 'org.sqlite.JDBC',\n 'dm.jdbc.driver.DmDriver',\n 'com.kingbase.Driver',\n 'org.mariadb.jdbc.Driver',\n 'org.apache.hive.jdbc.HiveDriver',\n 'com.sap.db.jdbc.Driver'\n]", "required": "true" }, "events": { "select": "let urlText = app.url, urlValue = urlText.value;\nif (!urlValue || urlValue == 'url')\n urlText.valueIndex = item.itemIndex;" }, "_expanded": true }, { "_icon": "combo", "text": "url", "cls": "Wb.Select", "_expanded": true, "properties": { "cid": "url", "text": "url", "data": "[\n 'jdbc:sqlserver://127.0.0.1:1433;DatabaseName=mydb;encrypt=false;',\n 'jdbc:oracle:thin:@127.0.0.1:1521:mydb',\n 'jdbc:mysql://127.0.0.1:3306/mydb?autoReconnect=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&mysqlEncoding=utf8&nullCatalogMeansCurrent=true',\n 'jdbc:postgresql://127.0.0.1:5432/mydb',\n 'jdbc:derby:$$wb/system/mydb;create=true',\n 'jdbc:db2:mydb',\n 'jdbc:db2://127.0.0.1:6789/mydb',\n 'jdbc:sybase:Tds:127.0.0.1:4100/mydb',\n 'jdbc:teradata://127.0.0.1/database=mydb, tmode=ANSI, charset=UTF8',\n 'jdbc:h2:$$wb/system/mydb',\n 'jdbc:sqlite:$$wb/system/mydb',\n 'jdbc:dm://127.0.0.1:12345/mydb',\n 'jdbc:kingbase://127.0.0.1:54321/mydb',\n 'jdbc:mariadb://127.0.0.1:3306/test',\n 'jdbc:hive2://127.0.0.1:10000/hadoop',\n 'jdbc:sap://127.0.0.1:30015?reconnect=true'\n]", "required": "true" } }, { "_icon": "text", "text": "username", "cls": "Wb.Text", "properties": { "cid": "username", "text": "username" } }, { "_icon": "text", "text": "password", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "password", "text": "password", "password": "true", "eyeButton": "true" } }, { "_icon": "text", "text": "connectionProperties", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "connectionProperties", "text": "connectionProperties" } }, { "_icon": "switcher-on", "text": "disableConnectionPooling", "cls": "Wb.Toggle", "properties": { "cid": "disableConnectionPooling", "text": "disableConnectionPooling" } }, { "_icon": "title", "text": "title2", "cls": "Wb.Title", "properties": { "cid": "title2", "title": "@Str.connection" } }, { "_icon": "combo", "text": "defaultAutoCommit", "cls": "Wb.Select", "properties": { "cid": "defaultAutoCommit", "data": "[{ text: 'true', value: true }, { text: 'false', value: false }]", "text": "defaultAutoCommit", "forceSelect": "true", "clearButton": "true" } }, { "_icon": "combo", "text": "defaultReadOnly", "cls": "Wb.Select", "properties": { "cid": "defaultReadOnly", "data": "[{ text: 'true', value: true }, { text: 'false', value: false }]", "text": "defaultReadOnly", "forceSelect": "true", "clearButton": "true" } }, { "_icon": "combo", "text": "defaultTransactionIsolation", "cls": "Wb.Select", "properties": { "cid": "defaultTransactionIsolation", "data": "[\n { text: 'none', value: 0 },\n { text: 'read uncommitted', value: 1 },\n { text: 'read committed', value: 2 },\n { text: 'repeatable read', value: 4 },\n { text: 'serializable', value: 8 }\n]", "text": "defaultTransactionIsolation", "forceSelect": "true" }, "_expanded": true }, { "_icon": "text", "text": "defaultCatalog", "cls": "Wb.Text", "properties": { "cid": "defaultCatalog", "text": "defaultCatalog" } }, { "_icon": "switcher-on", "text": "cacheState", "cls": "Wb.Toggle", "properties": { "cid": "cacheState", "text": "cacheState" } }, { "_icon": "number-edit", "text": "defaultQueryTimeout", "cls": "Wb.Number", "_expanded": false, "properties": { "cid": "defaultQueryTimeout", "text": "defaultQueryTimeout(s)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "switcher-on", "text": "autoCommitOnReturn", "cls": "Wb.Toggle", "properties": { "cid": "autoCommitOnReturn", "text": "autoCommitOnReturn" } }, { "_icon": "switcher-on", "text": "rollbackOnReturn", "cls": "Wb.Toggle", "_expanded": false, "properties": { "cid": "rollbackOnReturn", "text": "rollbackOnReturn" } }, { "_icon": "title", "text": "title3", "cls": "Wb.Title", "_expanded": false, "properties": { "cid": "title3", "title": "@Str.connectionPool" } }, { "_icon": "number-edit", "text": "initialSize", "cls": "Wb.Number", "properties": { "cid": "initialSize", "text": "initialSize", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "maxTotal", "cls": "Wb.Number", "properties": { "cid": "maxTotal", "text": "maxTotal", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "maxIdle", "cls": "Wb.Number", "properties": { "cid": "maxIdle", "text": "maxIdle", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "minIdle", "cls": "Wb.Number", "properties": { "cid": "minIdle", "text": "minIdle", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "maxWaitMillis", "cls": "Wb.Number", "properties": { "cid": "maxWaitMillis", "text": "maxWaitMillis(ms)", "minValue": "-1", "decimalCount": "0" } }, { "_icon": "title", "text": "title4", "cls": "Wb.Title", "properties": { "cid": "title4", "title": "@Str.validation" } }, { "_icon": "text", "text": "validationQuery", "cls": "Wb.Text", "properties": { "cid": "validationQuery", "text": "validationQuery" } }, { "_icon": "number-edit", "text": "validationQueryTimeout", "cls": "Wb.Number", "properties": { "cid": "validationQueryTimeout", "text": "validationQueryTimeout(s)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "switcher-on", "text": "testOnCreate", "cls": "Wb.Toggle", "properties": { "cid": "testOnCreate", "text": "testOnCreate" } }, { "_icon": "switcher-on", "text": "testOnBorrow", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "testOnBorrow", "text": "testOnBorrow" } }, { "_icon": "switcher-on", "text": "testOnReturn", "cls": "Wb.Toggle", "_expanded": false, "properties": { "cid": "testOnReturn", "text": "testOnReturn" } }, { "_icon": "switcher-on", "text": "testWhileIdle", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "testWhileIdle", "text": "testWhileIdle" } }, { "_icon": "number-edit", "text": "timeBetweenEvictionRunsMillis", "cls": "Wb.Number", "properties": { "cid": "timeBetweenEvictionRunsMillis", "text": "timeBetweenEvictionRunsMillis(ms)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "numTestsPerEvictionRun", "cls": "Wb.Number", "properties": { "cid": "numTestsPerEvictionRun", "text": "numTestsPerEvictionRun", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "minEvictableIdleTimeMillis", "cls": "Wb.Number", "properties": { "cid": "minEvictableIdleTimeMillis", "text": "minEvictableIdleTimeMillis(ms)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "softMinEvictableIdleTimeMillis", "cls": "Wb.Number", "properties": { "cid": "softMinEvictableIdleTimeMillis", "text": "softMinEvictableIdleTimeMillis(ms)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "number-edit", "text": "maxConnLifetimeMillis", "cls": "Wb.Number", "properties": { "cid": "maxConnLifetimeMillis", "text": "maxConnLifetimeMillis(ms)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "switcher-on", "text": "logExpiredConnections", "cls": "Wb.Toggle", "properties": { "cid": "logExpiredConnections", "text": "logExpiredConnections" } }, { "_icon": "textarea", "text": "connectionInitSqls", "cls": "Wb.TextArea", "properties": { "cid": "connectionInitSqls", "text": "connectionInitSqls", "height": "7em" } }, { "_icon": "switcher-on", "text": "lifo", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "lifo", "text": "lifo" } }, { "_icon": "title", "text": "title5", "cls": "Wb.Title", "properties": { "cid": "title5", "title": "@Str.others" } }, { "_icon": "switcher-on", "text": "poolPreparedStatements", "cls": "Wb.Toggle", "properties": { "cid": "poolPreparedStatements", "text": "poolPreparedStatements" } }, { "_icon": "number-edit", "text": "maxOpenPreparedStatements", "cls": "Wb.Number", "properties": { "cid": "maxOpenPreparedStatements", "text": "maxOpenPreparedStatements", "minValue": "0", "decimalCount": "0" } }, { "_icon": "switcher-on", "text": "accessToUnderlyingConnectionAllowed", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "accessToUnderlyingConnectionAllowed", "text": "accessToUnderlyingConnectionAllowed" } }, { "_icon": "switcher-on", "text": "removeAbandonedOnMaintenance", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "removeAbandonedOnMaintenance", "text": "removeAbandonedOnMaintenance" } }, { "_icon": "switcher-on", "text": "removeAbandonedOnBorrow", "cls": "Wb.Toggle", "_expanded": false, "properties": { "cid": "removeAbandonedOnBorrow", "text": "removeAbandonedOnBorrow" } }, { "_icon": "number-edit", "text": "removeAbandonedTimeout", "cls": "Wb.Number", "properties": { "cid": "removeAbandonedTimeout", "text": "removeAbandonedTimeout(s)", "minValue": "0", "decimalCount": "0" } }, { "_icon": "switcher-on", "text": "logAbandoned", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "logAbandoned", "text": "logAbandoned" } }, { "_icon": "switcher-on", "text": "abandonedUsageTracking", "cls": "Wb.Toggle", "_expanded": false, "properties": { "cid": "abandonedUsageTracking", "text": "abandonedUsageTracking" } }, { "_icon": "switcher-on", "text": "fastFailValidation", "cls": "Wb.Toggle", "_expanded": true, "properties": { "cid": "fastFailValidation", "text": "fastFailValidation" } }, { "_icon": "textarea", "text": "disconnectionSqlCodes", "cls": "Wb.TextArea", "properties": { "cid": "disconnectionSqlCodes", "text": "disconnectionSqlCodes", "height": "7em" } }, { "_icon": "text", "text": "jmxName", "cls": "Wb.Text", "properties": { "cid": "jmxName", "text": "jmxName" } } ] } ] } ] } # admin/dbe/execute-sql.xwl Title: execute-sql Description: Execute arbitrary SQL ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Execute arbitrary SQL", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let params = { array: true };\n //If access to blobs is allowed, use the base64 format\n if (Wb.getBool('blob'))\n params.blob = 'text';\n //SQL is encoded using base64, so it needs to be decoded\n Wb.sendSql(Wb.apply(params, {\n sql: Wb.decodeBase64(Params.data), db: Params.db, returnObject: true, readonly: true,\n dateFormat: true, rs: Util.maxRows\n }));\n}\nmain();" }, "_icon": "module" } # admin/dbe/export.xwl Title: export Description: Export data to the client ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Export data to the client", "serverScript": "Wb.checkDemo();\nfunction main() {\n let sql, tableName = Params.tableName,\n writer = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new Classes.GZIPOutputStream(response.getOutputStream()), 'utf-8'));\n\n Wb.setContentType(tableName + '.wbt', true);\n sql = Params.data;\n if (sql)\n sql = Wb.decodeBase64(sql);\n else\n sql = 'select * from ' + tableName;\n Wb.sql({\n sql, db: Params.db, blob: 'text', fn(row) {\n writer.write(Wb.encode(row));\n writer.write('\\n');\n }\n });\n writer.close();\n}\nmain();" }, "_icon": "module" } # admin/dbe/import.xwl Title: import Description: Import data to table ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Import data to table", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs'), fileExt = Wb.getFileExt(Params.file.name);\n switch (fileExt) {\n case 'wbt':\n Util.importWbTable();\n break;\n case 'xls':\n case 'xlsx':\n Util.importExcel();\n break;\n case 'txt':\n case 'csv':\n Util.importText(fileExt);\n break;\n }\n}\nmain();" }, "_icon": "module" } # admin/dbe/select-table.xwl Title: select-table Description: Table select, save and download ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Table select, save and download", "serverScript": "function main() {\n if (Params.download || Params.save)\n Wb.sync(Params);\n else {\n const Util = Wb.load('./util.mjs');\n let sql = 'select * from ' + Params.tableName;\n if (Params.where)\n sql += ' where ' + Wb.decodeBase64(Params.where);\n sql += Wb.getOrderSql();\n Wb.sendRowx({ sql, db: Params.db, dateFormat: true, rs: Util.maxRows, paging: Wb.getBool('useDbPaging') ? 'db' : true });\n }\n}\nmain();" }, "_icon": "module" } # admin/dbe/select-tree.xwl Title: select-tree Description: Select database resource list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select database resource list", "serverScript": "function main() {\n const DBE = Wb.load('wb/ss/dbe.mjs');\n let result, db = Params.db, schem = Params.schem, type = Params.type;\n\n switch (type) {\n case 'db':\n result = DBE.getSchemas(db);\n break;\n case 'schem':\n result = DBE.getCategory(db, schem, Wb.getInt('cateMode'));\n break;\n case 'tableCate':\n result = DBE.getTables(db, schem);\n break;\n case 'viewCate':\n result = DBE.getTables(db, schem, true);\n break;\n case 'procCate':\n result = DBE.getProcs(db, schem);\n break;\n case 'proc':\n result = DBE.getProcColumns(db, schem, Params.procName);\n break;\n case 'func':\n result = DBE.getProcColumns(db, schem, Params.funcName);\n break;\n case 'funcCate':\n result = DBE.getFuncs(db, schem);\n break;\n case 'table':\n case 'view':\n result = DBE.getColumns(db, schem, Params.tableName, type == 'table');\n break;\n default:\n result = DBE.getDbNames();\n }\n Wb.send(result);\n}\nmain();" }, "_icon": "module" } # admin/dbe.xwl Title: Database Explorer Description: Database management tool ```json { "title": "@dbe", "icon": "database", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Database management tool" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /** @property {Number} - The current window number. */\n index: 1,\n /** @property {Boolean} - Max returned rows. */\n maxRows: 1000,\n /**\n * Get the currently open tab card.\n * @return {Wb.Card} The active card.\n */\n get$activeCard() {\n return app.tab.activeCard;\n },\n /**\n * Get the currently open grid.\n * @return {Wb.Grid} The active grid.\n */\n get$activeGrid() {\n let card = app.activeCard, grid = card?.tab1?.activeCard?.firstItem ?? card?.firstItem;\n return grid?.isGrid ? grid : null;\n },\n /**\n * Get the currently open editable grid.\n * @return {Wb.Grid} The edited grid.\n */\n get$editGrid() {\n let grid = app.activeCard?.firstItem;\n return grid instanceof Wb.Grid ? grid : null;\n },\n /**\n * Adds a new SQL tab for the specified data source.\n * @param {String} [sql] SQL statements. null does not update the SQL statement.\n * @param {String} [db] The name of the data source. The default is the currently selected data source name.\n * @param {Boolean} [newWin] If a window with the same data source already exists, a new window opens. The\n * default is true.\n */\n addSql(sql, db, newWin = true) {\n let card, editor;\n\n db ||= app.getKeyName('db');\n if (!newWin) {\n card = app.tab.findBy(card => card.db == db && card.sqlCard);\n if (card) {\n card.show();\n if (sql != null)\n card.editor1.value = sql;\n return;\n }\n }\n card = {\n title: 'SQL' + (app.index++) + ' - ' + db,\n db,\n sqlCard: true,\n icon: 'file-sql',\n layout: 'column',\n events: {\n destroy() {\n this.stopShowError = true;\n this.ajaxObject?.abort();\n }\n },\n items: [{\n cname: 'codeEditor',\n wrapBorder: 0,\n sqlDb: db,\n height: '9em',\n cid: 'editor1',\n language: 'sql',\n value: sql ?? '',\n popupMenu: true,\n editorConfigs: {\n minimap: { enabled: false }\n }\n }, '||', {\n flex: 1,\n cid: 'tab1',\n cname: 'tab',\n tabMenu: true,\n defaults: { closable: null },\n autoScroll: true,\n events: {\n cardchange() {\n app.propBtn.disabled = !app.activeGrid;\n app.setExportBtn();\n }\n }\n }]\n };\n card = app.tab.add(card);\n editor = card.editor1 = card.down('editor1');\n card.tab1 = card.down('tab1');\n editor.editor.addAction({\n id: 'runSql',\n keybindings: [\n monaco.KeyMod.CtrlCmd | (monaco.KeyCode.Enter)\n ],\n label: Str.runSql,\n run() {\n app.runSql(card);\n }\n });\n card.show();\n editor.focus();\n },\n /**\n * Fire after the grid callback.\n */\n onGridCallback() {\n let card = this.parent;\n if (card) {\n card.isLoading = false;\n app.setLoading.cancelDelay(app);\n app.setLoading(card, false);\n }\n },\n /**\n * Fires before the grid loads.\n */\n onGridBeforeLoad(configs, params) {\n let grid = this, card = grid.parent;\n if (card.isLoading)\n return;\n if (card.isModified) {\n Wb.choose(Str.modifiedConfirm.format(card.tableName), btn => {\n if (btn == 'yes')\n app.doSave(card, f => grid.reload());\n else if (btn == 'no') {\n Wb.unModified(card);\n app.setSaveBtns();\n grid.reload();\n }\n });\n return false;\n }\n params.useDbPaging = app.dbPagingBtn.active;\n app.setLoading.delay(app, Wb.configs.maskDelay, card, true);\n card.isLoading = true;\n },\n /**\n * Fires when grid data is changed. @priv\n */\n onChange() {\n let me = this, activeCard = app.activeCard, card = me.upBy(p => p.gridCard);\n if (card) {\n Wb.setModified(card);\n app.saveAllBtn.disabled = false;\n if (card == activeCard)\n app.saveBtn.disabled = false;\n }\n },\n /**\n * Sets the save button state.\n */\n setSaveBtns() {\n app.saveBtn.disabled = !app.activeCard?.isModified;\n app.saveAllBtn.disabled = !app.tab.find(card => card.isModified);\n },\n /**\n * Opens the specified db table for editing.\n * @param {String} [tableName] The table name to open. Default is currently selected table.\n * @param {String} [schem] Schem name. The default is the currently selected schem.\n * @param {String} [db] The name of the data source. The default is the currently selected data source name.\n * @param {Boolean} [isView] Whether is db view.\n */\n openTable(tableName, schem, db, isView) {\n let card, configs, fullTableName;\n\n tableName ||= app.getKeyName('tableName');\n db ||= app.getKeyName('db');\n schem ||= app.getKeyName('schem');\n card = app.tab.findBy(card => card.tableName == tableName && card.schem == schem && card.db == db);\n if (card) {\n card.show();\n return;\n }\n fullTableName = schem ? (schem + '.' + tableName) : tableName;\n configs = {\n title: tableName,\n xIsView: isView,\n tabTip: fullTableName + ' - ' + db,\n tableName,\n fullTableName,\n schem,\n db,\n gridCard: true,\n icon: isView ? 'viewport' : 'table',\n layout: 'fit',\n events: {\n beforeclose() {\n return this.confirmClose(app.doSave);\n }\n },\n items: {\n cname: 'grid',\n cid: 'grid1',\n url: xpath + '/select-table',\n contextMenu: app.contextMenu,\n columnsSortable: true,\n textSelectable: isView,\n multiSelect: true,\n exportFilename: tableName,\n params: { db, tableName: fullTableName, maxRows: app.maxRows },\n editable: !isView,\n autoLoad: false,\n showMask: false,\n enterAsTab: true,\n arrowDownAppend: true,\n events: {\n beforeload: app.onGridBeforeLoad,\n callback: app.onGridCallback,\n editing: app.onChange,\n itemchange: app.onChange\n }\n }\n };\n card = app.tab.add(configs);\n card.grid1 = card.down('grid1');\n card.show();\n card.grid1.load();\n },\n /**\n * Gets the key properties of the currently selected node.\n * @return {String} [name] The property name. Not found returns null.\n */\n getKeyName(name) {\n return app.tree.selection?.upBy(node => node.isNode && node.data[name])?.data[name] ?? null;\n },\n /**\n * Gets the category of the current node.\n * @return {String} Node category. Not found returns null.\n */\n get$category() {\n return app.tree.selection?.upBy(node => node.isNode && node.data.cateNode)?.data.type ?? null;\n },\n /**\n * Fires when the page is ready.\n */\n onReady() {\n app.tab.setNavigate(app.backBtn, app.forwardBtn);\n app.contextMenu = Wb.createMenu([app.addBtn, app.delBtn], false);\n },\n /**\n * Adds the SQL execution result to the specified container. @priv\n * @param {Wb.Tab} tab The container to render data.\n * @param {String} title The title.\n * @param {Object} result Render data.\n */\n addResult(tab, title, result) {\n let items = result?.items;\n if (Wb.isArray(items)) {\n tab.add({\n icon: 'grid', title, layout: 'fit', items: {\n cname: 'grid', columns: result.columns, fields: result.fields, localData: items,\n textSelectable: true, editable: true\n }\n });\n } else {\n if (Wb.isObject(result) || Wb.isArray(result))\n result = Wb.encode(result);\n else\n result = String(result);\n tab.add({ icon: 'component', cls: 'w-padding', autoScroll: true, title, text: result });\n }\n },\n /**\n * Gets the editor that currently using.\n * @return {Wb.CodeEditor} The active editor.\n */\n get$activeEditor() {\n return app.tab.activeCard?.editor1;\n },\n /**\n * Sets the loading status of the specified tab. @priv\n * @param {Wb.Card} card The tab card.\n * @param {Boolean} status True means loading, false means loading complete.\n */\n setLoading(card, status) {\n let isSqlCard = card.editor1;\n\n card.icon = status ? 'loading' : (isSqlCard ? 'file-sql' : 'table');\n card.spin = status;\n },\n /**\n * Runs SQL statements in the specified tab card.\n * @param {Wb.Card} card The tab card for running sql.\n * @param {Boolean} [blob] Whether to return blobs.\n */\n runSql(card, blob) {\n if (card.isLoading) {\n Wb.tipWarn(Str.loading);\n return;\n }\n let editor = card.editor1, tab = card.tab1, sql;\n\n editor.completeEdit();\n card.isLoading = true;\n app.setLoading.delay(app, Wb.configs.maskDelay, card, true);\n tab.destroyAll();\n sql = editor.selectedText || editor.value;\n card.lastSql = sql;\n card.ajaxObject = Wb.ajax({\n url: xpath + '/execute-sql',\n params: {\n blob,\n maxRows: app.maxRows,\n db: card.db,\n //Prevent potential SQL blocking\n data: Wb.encodeBase64(sql)\n },\n mask: false,\n json: true,\n showError: false,\n callback() {\n let xhr = card.ajaxObject;\n\n if (!card.stopShowError && !xhr.ok)\n Wb.Request.processError(xhr);\n delete card.ajaxObject;\n card.isLoading = false;\n app.setLoading.cancelDelay(app);\n app.setLoading(card, false);\n },\n success(resp) {\n let hasResult;\n //Get the results of returns\n resp.$return?.forEach((item, i) => {\n hasResult = true;\n app.addResult(tab, Str.itemX.format(i + 1), item);\n });\n //Get output parameters and other results\n Wb.each(resp, (k, v) => {\n if (k != '$return') {\n hasResult = true;\n app.addResult(tab, k, v);\n }\n });\n if (!hasResult)\n tab.add({ text: Str.done, cls: 'w-padding' });\n //hides tabBar if only has one item\n tab.tabBar.visible = tab.items.length > 1;\n tab.firstItem?.show();\n }\n });\n },\n /**\n * Saves the data for the specified tab. @priv\n * @param {Wb.Card} card Tab card.\n * @param {Function} [success] Fires after success.\n */\n doSave(card, success) {\n let grid = card.grid1;\n\n grid.completeEdit();\n grid.sync({\n params: { save: 1 },\n success() {\n Wb.unModified(card);\n app.setSaveBtns();\n success?.();\n }\n });\n },\n /**\n * Save data.\n * @param {Boolean} [isAll] whether to save all.\n */\n save(isAll) {\n if (isAll) {\n app.tab.each(card => {\n if (card.isModified)\n app.doSave(card);\n });\n } else {\n app.doSave(app.activeCard);\n }\n },\n /**\n * Rename the selected node.\n * @param {Boolean} [uppercase] Whether to change the value to uppercase.\n * -true: change to uppercase.\n * -false: change to lowercase.\n * -null: not change. Default value.\n */\n rename(uppercase) {\n let tree = app.tree, row = tree.selection, editor;\n\n if (!row) {\n Wb.tipSelect();\n return;\n }\n tree.startEdit(row, 'text', f => false);\n editor = Wb.Editor.activeEditor;\n if (uppercase != null) {\n let value = editor.value;\n editor.value = uppercase ? value.toUpperCase() : value.toLowerCase();\n }\n editor.select();\n },\n /**\n * Import file to the specified table. @priv\n */\n importTable() {\n let card = app.activeCard, tableName = card.fullTableName;\n\n\n Wb.selectFile(file => {\n Wb.ajax({\n url: xpath + '/import',\n params: { db: card.db, tableName, file },\n uploadProgress: Str.import + ' - ' + tableName + '...',\n success() {\n card.grid1.reload();\n }\n });\n }, '.wbt, .xls, .xlsx, .csv, .txt');\n },\n /**\n * Set export button status.\n */\n setExportBtn() {\n let card = app.activeCard;\n app.exportBtn.disabled = !(app.activeGrid && (!card.sqlCard || card.tab1.items.length == 1));\n },\n /**\n * Export all data to \"wbt\" format file.\n */\n exportData() {\n let card = app.activeCard, params = { db: card.db }, tableName;\n\n if (card.sqlCard) {\n const regex = /(?:FROM|JOIN|INTO)\\s+([\\w.]+)/gi;\n let sql = card.lastSql, match;\n while ((match = regex.exec(sql))) {\n tableName = match[1];\n break;\n }\n tableName ||= 'data';\n params.data = Wb.encodeBase64(sql);\n } else {\n tableName = card.fullTableName;\n }\n params.tableName = tableName;\n Wb.download(xpath + '/export', params);\n }\n});", "beforeunload": "if (!app.saveAllBtn.disabled) {\n let card = app.tab.find(card => card.isModified), btn = card?.tabButton;\n if (card) {\n card.show();\n btn.highlight();\n return false;\n }\n}" }, "tags": "", "items": [ { "_icon": "window", "text": "filterWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "filterWin", "width": "40em", "height": "15em", "icon": "filter", "title": "@Str.filter", "layout": "fit", "dialog": "true" }, "events": { "ok": "let where = app.activeCard.whereSql = app.sqlEditor.value;\napp.editGrid.load({ params: { where: Wb.encodeBase64(where) } });\nthis.close();", "ready": "let me = this;\nme.buttonsBar.insert(0, [{\n text: Str.reset, handler() {\n app.sqlEditor.value = '';\n me.downWhole('ok').fireEvent('click');\n }\n}, '->'])" }, "items": [ { "_icon": "edit", "text": "sqlEditor", "cls": "Wb.CodeEditor", "properties": { "cid": "sqlEditor", "language": "sql", "lineNumbers": "false", "minimap": "false" } } ] }, { "_icon": "window", "text": "propWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "propWin", "title": "@Str.property", "icon": "property", "layout": "column", "modal": "true", "width": "80em", "gap": "true", "padding": "true" }, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "gap": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "tableName", "cls": "Wb.Text", "properties": { "cid": "tableName", "text": "@Str.table", "readonly": "true" }, "_expanded": true }, { "_icon": "text", "text": "fieldNamesText", "cls": "Wb.Text", "properties": { "cid": "fieldNamesText", "readonly": "true", "flex": "1", "text": "@Str.fields" } } ] }, { "_icon": "grid", "text": "propGrid", "cls": "Wb.Grid", "properties": { "cid": "propGrid", "pagingBar": "false", "showIcon": "true", "textSelectable": "true", "flex": "1" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "fieldNameCol", "fieldName": "fieldName", "width": "-1", "text": "@Str.name" }, "text": "fieldNameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "typeCol", "fieldName": "typeName", "width": "10em", "text": "@Str.type" }, "text": "typeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "precisionCol", "fieldName": "precision", "width": "10em", "text": "@Str.size", "align": "right" }, "text": "precisionCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "scaleCol", "fieldName": "scale", "width": "10em", "text": "@Str.decimal", "align": "right" }, "text": "scaleCol", "_expanded": true, "_icon": "column" } ] } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "events": { "ready": "app.onReady();" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": false, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "newSqlBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "newSqlBtn", "text": "@Str.newSql", "icon": "file-sql", "keys": "Ctrl+J" }, "events": { "click": "app.addSql();" } }, { "_icon": "split", "text": "runSqlBtn", "cls": "Wb.SplitButton", "properties": { "cid": "runSqlBtn", "disabled": "true", "icon": "play", "keysText": "Ctrl+Enter", "text": "@Str.runSql" }, "events": { "click": "app.runSql(app.activeCard);" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "getBlobBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "getBlobBtn", "text": "@Str.runSqlBlob", "icon": "cube" }, "events": { "click": "app.runSql(app.activeCard, true);" } } ] } ] }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addBtn", "icon": "add", "disabled": "true", "keys": "Ctrl+E", "tip": "@Str.add", "menuText": "@Str.add" }, "events": { "click": "let grid = app.editGrid;\ngrid.addRecord(null, e.ctrlMeta ? grid.selection : null);" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "icon": "delete", "disabled": "true", "keys": "Ctrl+D", "tip": "@Str.del", "menuText": "@Str.del" }, "events": { "click": "app.editGrid.delRecords();" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveBtn", "icon": "save", "disabled": "true", "keys": "Ctrl+S", "tip": "@Str.save" }, "events": { "click": "app.save();" } }, { "_icon": "item", "text": "saveAllBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveAllBtn", "icon": "save-all", "disabled": "true", "keys": "Ctrl+Shift+S", "tip": "@Str.saveAll" }, "events": { "click": "app.save(true);" } }, { "_icon": "item", "text": "filterBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "filterBtn", "icon": "filter", "disabled": "true", "tip": "@Str.filter" }, "events": { "click": "app.filterWin.show();\napp.sqlEditor.value = app.activeCard.whereSql ?? '';" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" }, "_expanded": true }, { "_icon": "item", "text": "propBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "propBtn", "icon": "property", "disabled": "true", "tip": "@Str.property" }, "events": { "click": "let item, data = [], fieldNames = [], tableName;\napp.activeGrid.leafColumns.forEach(col => {\n if (col.rowNum) return;\n item = Wb.applyWith({}, col, ['typeName', 'precision', 'scale', 'required']);\n item.fieldName = col.rawName ?? col.fieldName;\n fieldNames.push(item.fieldName);\n item._icon = col.required ? 'ok' : 'item';\n data.push(item);\n});\napp.propGrid.data = data;\ntableName = app.activeCard.tableName;\napp.tableName.visible = tableName;\napp.tableName.value = tableName;\napp.fieldNamesText.value = fieldNames.join(', ');\napp.propWin.show();\napp.propWin.center();" } }, { "_icon": "item", "text": "maxRowsBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "maxRowsBtn", "icon": "record", "tip": "@Str.maxRecords+' ('+app.maxRows+')'" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "slidebar", "text": "slider1", "cls": "Wb.Slider", "properties": { "cid": "slider1", "width": "12em", "step": "100", "maxValue": "100000", "minValue": "100", "value": "@app.maxRows" }, "events": { "enddrag": "app.maxRows = value;\napp.maxRowsBtn.tip = Str.maxRecords + ' (' + value + ')';\nthis.parent.hide();" }, "_expanded": true } ] } ] }, { "_icon": "split", "text": "renameBtn", "cls": "Wb.SplitButton", "properties": { "cid": "renameBtn", "icon": "edit", "keys": "F2", "tip": "@Str.rename", "stopEvent": "false" }, "events": { "click": "if (document.activeElement.isInput)\n return;\napp.rename();\ne.stopEvent();" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "lowercaseBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "lowercaseBtn", "text": "@Str.lowercase", "keys": "Ctrl+Q" }, "events": { "click": "app.rename(false);" } }, { "_icon": "item", "text": "uppercaseBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "uppercaseBtn", "text": "@Str.uppercase", "keys": "Ctrl+U" }, "events": { "click": "app.rename(true);" } } ] } ] }, { "_icon": "item", "text": "dbPagingBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "dbPagingBtn", "icon": "pagenum", "tip": "Database Paging", "enableToggle": "true", "activeBgColor": "false" } }, { "_icon": "item", "text": "exportBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "exportBtn", "icon": "export", "disabled": "true", "tip": "@Str.export", "handler": "app.exportData" } }, { "_icon": "item", "text": "importBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "importBtn", "icon": "import", "disabled": "true", "handler": "app.importTable", "tip": "@Str.import" } }, { "_icon": "divider", "text": "divider3", "cls": "Wb.Divider", "properties": { "cid": "divider3" }, "_expanded": true }, { "_icon": "item", "text": "backBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "backBtn", "icon": "left4", "tip": "@Str.back" } }, { "_icon": "item", "text": "forwardBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "forwardBtn", "icon": "right4", "tip": "@Str.forward" } } ] }, { "_icon": "tree-view", "text": "tree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "tree", "width": "20em", "icon": "database", "title": "@Str.dbList", "url": "@xpath + '/select-tree'", "autoSelect": "true", "autoPostParams": "true", "keyWalking": "true" }, "events": { "itemdblclick": "if (e.ctrlMeta && item.data.type != 'db') {\n app.activeEditor?.setter('selectedText', item.text);\n}", "itemclick": "let data = item.data, type = data.type;\nif (e.ctrlMeta) {\n app.addSql(null, app.getKeyName('db'), false);\n} else {\n if (type == 'table')\n app.openTable();\n else if (type == 'view')\n app.openTable(data.viewName, null, null, true);\n}" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "textCol", "expander": "true", "width": "-1", "fieldName": "text", "render": "//use sub-color to render subText\nlet subText = data.subText, index;\n\nif (data.type == 'field')\n index = data.fieldIndex + '. ';\nelse\n index = '';\nif (subText) {\n let span = el.addTag('span');\n span.textContent = index + value;\n span = el.addEl('w-sub-color w-margin-l', 'span');\n span.textContent = subText;\n} else\n return index + value;" }, "text": "textCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "readonly": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] } ] }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "Wb.openNormal('m?xwl=admin/dbc');" }, "properties": { "cid": "setItem", "icon": "gear", "tip": "@Str.set" }, "text": "setItem", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "events": { "click": "app.tree.loadSelect();" }, "properties": { "cid": "refreshItem", "icon": "refresh", "tip": "@Str.refresh" }, "text": "refreshItem", "_expanded": true, "_icon": "item" } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "tab", "text": "tab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "tab", "flex": "1", "tabMenu": "true" }, "events": { "cardchange": "app.runSqlBtn.disabled = !newCard?.sqlCard;\napp.addBtn.disabled = app.delBtn.disabled = app.importBtn.disabled = !newCard?.gridCard || newCard?.xIsView;\napp.filterBtn.disabled = !newCard?.gridCard\napp.propBtn.disabled = !app.activeGrid;\napp.setExportBtn();\napp.setSaveBtns();" } } ] } ] } # admin/dept/add.xwl Title: add Description: Add department ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add department", "serverScript": "function main() {\n let rec = { sid: Params.dept_id_disp || Wb.getId() };\n\n Wb.set(rec);\n Params.parent_id ||= '0';\n Wb.sync({ tableName: 'wb_dept', insert: Params });\n rec.dept_id_disp = rec.sid;\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # admin/dept/del.xwl Title: del Description: Delete departments ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete departments", "serverScript": "function main() {\n let items, del = [];\n\n items = Wb.Builder.getTreeItems(Wb.getAllRows('select sid,parent_id from wb_dept'), Wb.getObject('del').pluck('$sid'));\n items.forEach(item => del.push({ $sid: item }));\n Wb.sync({ tableName: 'wb_dept', del });\n}\nmain();" }, "_icon": "module" } # admin/dept/edit.xwl Title: edit Description: Edit department ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit department", "serverScript": "function main() {\n Wb.sync({ tableName: 'wb_dept', update: Params });\n}\nmain();" }, "_icon": "module" } # admin/dept/move.xwl Title: move Description: Move departments ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Move departments", "serverScript": "function main() {\n let update = [], parent_id = Params.parentId || '0';\n\n Wb.getObject('source').forEach(item => {\n update.push({ $sid: item, parent_id });\n });\n Wb.sync({ tableName: 'wb_dept', update });\n}\nmain();" }, "_icon": "module" } # admin/dept/select-manager.xwl Title: select-manager Description: Select department manager ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select department manager", "serverScript": "function main() {\n let sql;\n\n sql = 'select sid as manager_id,user_name as manager_user,display_name as manager_name from wb_user';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where (user_name like {?query?} or display_name like {?query?})';\n }\n sql += ' order by display_name';\n Wb.sendRows(sql);\n}\nmain();" }, "_icon": "module" } # admin/dept/select.xwl Title: select Description: Select departments ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select departments", "serverScript": "function main() {\n let sql, rows, firstItem, search = Params.search;\n\n sql = `\n select a.dept_name, a.dept_code, a.sid, a.parent_id, b.sid as user_id,\n b.display_name as manager_name, a.status, 'folder1' as \"_icon\", a.sid as dept_id_disp,\n case when (select count(*) from wb_dept c where c.parent_id=a.sid)>0 then 1 else 0 end as items\n from wb_dept a left join wb_user b on a.manager_id=b.sid\n `;\n if (search) {\n Wb.setLike('search');\n sql += ' where a.dept_name like {?search?} or a.dept_code like {?search?} or a.sid like {?search?}';\n } else {\n Params.parent_id = Params.sid || '0';\n sql += ' where a.parent_id={?parent_id?}';\n }\n sql += Wb.getOrderSql({ manager_name: 'b.display_name' });\n rows = Wb.getDict({ sql, columns: 'tree', rs: search ? 100 : -1 }, 'wb,');\n if (!search && !Params.sid && (firstItem = rows.items[0]) && rows.items.length == 1)\n firstItem._expanded = true;\n Wb.send(rows);\n}\nmain();" }, "_icon": "module" } # admin/dept.xwl Title: Department Management Description: Department management tool ```json { "title": "@deptMng", "icon": "dept", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Department management tool" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Add new department.\n * @param {Boolean} [isSibling] Whether to add sibling.\n */\n addDept(isSibling) {\n let data, parentId, node, parentNode, win, deptName, tree = app.tree1;\n\n node = tree.selection;\n if (isSibling)\n parentNode = node?.parent ?? tree;\n else\n parentNode = node ?? tree;\n data = node?.data;\n if (data) {\n parentId = isSibling ? data.parent_id : data.sid;\n deptName = data.dept_name;\n }\n win = tree.dictAdd({\n url: xpath + '/add',\n failure: app.onFailure\n }, deptName || null, { parent_id: parentId }, (tree, node) => {\n node.update({ items: [], _icon: 'folder1' });\n }, null, null, null, parentNode);\n if (isSibling) {\n win.icon = 'insert';\n win.title = Str.addToSibling;\n win.subTitle = deptName;\n }\n win.down('dept_id_disp').readonly = false;\n },\n /**\n * Method to execute when adding or updating data fails.\n * @param {String} resp Response text.\n */\n onFailure(resp) {\n let checkFields = { wb_dept_pk: 'dept_id_disp', wb_dept_dept_code: 'dept_code' };\n\n Wb.each(checkFields, (k, v) => {\n if (Wb.checkExists(resp, k, app.tree1.dictWin.down(v)))\n return false;\n });\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.addDept();" } }, { "_icon": "item", "text": "addToSiblingBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addToSiblingBtn", "text": "@Str.addToSibling", "icon": "insert" }, "events": { "click": "app.addDept(true);" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let win = app.tree1.dictEdit({\n url: xpath + '/edit',\n failure: app.onFailure\n}, 'code');\nwin.down('dept_id_disp').readonly = true;" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.tree1.removeRecords(xpath + '/del', 'dept_name');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.tree1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "tree-view", "text": "tree1", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "tree1", "url": "@xpath + '/select'", "columnsSortable": "true", "multiSelect": "true", "sorters": "dept_code", "stateId": "wb.dept", "pagingBar": "true", "defaultColumns": "false", "draggable": "{ autoDrop: false }", "droppable": "wb.dept", "serverExport": "true", "keyFields": "sid" }, "events": { "itemdrop": "let dest = draggable.dest, parentId;\n\nparentId = draggable.mode == 'append' ? dest.data.sid : dest.parent.data.sid;\nWb.ajax({\n url: xpath + '/move',\n params: {\n source: Wb.Tree.getTopNodes(draggable.source).pluck('data').pluck('sid'),\n parentId\n },\n success() {\n draggable.acceptDrop();\n }\n});" } } ] } ] } # admin/file.xwl Title: File Manager Description: File management tool ```json { "title": "@fileManager", "icon": "file-admin", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "File management tool" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "fit", "border": "false" }, "items": [ { "_icon": "module", "text": "browserXwl", "cls": "Wb.Xwl", "properties": { "cid": "browserXwl", "path": "sys/file/browser.xwl" } } ] } ] } # admin/flow.xwl Title: Workflow Manager Description: Workflow management tool ```json { "title": "@flowMng", "icon": "flow1", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Workflow management tool", "serverScript": "function main() {\n Params.flowPathLength = new Wb.File(true, 'wb/system/resource/flow').path.length;\n}\nmain();", "links": "[\n \"wb/libs/x6.js\",\n \"wb/js/flow-designer.js\",\n \"wb/js/monaco.js\"\n]" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /** @property {String} - Workflow files base path. */\n basePath: '|wb/system/resource/flow',\n /** @property {String} - The URL used to get the workflow files path. */\n getFileUrl: 'm?xwl=sys/file/get-resource',\n /** @property {Object} - Current actived workflow graph. */\n get$graph() {\n return app.tab1.activeCard?.graph;\n },\n /** @property {Boolean} - Whether current focus in the input. */\n get$inInput() {\n return document.activeElement.isInput;\n },\n /** @property {Object} - Current actived workflow designer. */\n get$flowDesigner() {\n return app.tab1.activeCard?.flowDesigner;\n },\n /** @property {Wb.Card} - Current active card. */\n get$activeCard() {\n return app.tab1.activeCard;\n },\n /** @property {String} - Root path length of the workflow folder. */\n flowPathLength: _$flowPathLength$_,\n /**\n * Create a new flow file.\n */\n newFile() {\n Wb.promptFile((fullname, win) => {\n if (!fullname.endsWith('.flw'))\n fullname += '.flw';\n Wb.ajax({\n url: 'm?xwl=sys/file/add',\n params: { fullname },\n json: true,\n success(resp) {\n app.createCard(null, resp.path, resp.lastModified.dateValue.getTime());\n win.close();\n }\n });\n }, app.basePath, '.flw', Str.addFile, false, app.getFileUrl);\n },\n /**\n * Create a new flow file.\n */\n openFile() {\n Wb.promptFiles((files, win) => {\n files.forEach(file => app.doOpenFile(file));\n win.close();\n }, app.basePath, '.flw', Str.selectFile, app.getFileUrl);\n },\n /**\n * Find the file tab from the file path.\n * @param {String} path The file path.\n * @return {Wb.Card} The found card, returns null if not found.\n */\n findCard(path) {\n return this.tab1.findBy(card => card.path == path);\n },\n /**\n * Open the file at the specified path.\n * @param {String} path Full file path.\n * @param {Function} [callback] The callback function after successfully opening.\n * @param {Wb.Card} callback.card The opened card.\n */\n doOpenFile(path, callback) {\n let card = app.findCard(path);\n if (card) {\n card.show();\n callback?.call(app, card);\n } else {\n Wb.ajax({\n url: 'm?xwl=sys/file/open-resource', params: { path, charset: 'UTF-8' }, success(resp) {\n let divPos, lastModified, content;\n\n divPos = resp.indexOf('|');\n lastModified = resp.substr(0, divPos);\n content = resp.substr(divPos + 1);\n if (content)\n content = Wb.decode(content);\n app.createCard(content, path, lastModified);\n callback?.call(app, card);\n }\n });\n }\n },\n /**\n * Create a flow card from the flow data.\n * @param {Object} [data] Flow data.\n * @param {String} [path] Flow file path.\n * @param {Number} [lastModified] File last modified date.\n * @return {Wb.Card} New created card.\n */\n createCard(data, path, lastModified) {\n let card, tabTip, title, me = this;\n\n if (Wb.isString(lastModified))\n lastModified = parseInt(lastModified);\n if (path) {\n title = Wb.getFilename(path);\n tabTip = path.substr(app.flowPathLength + 1);\n } else {\n app.fileIndex ??= 1;\n title = Str.new + ' - ' + (app.fileIndex++)\n tabTip = undefined;\n }\n card = app.tab1.add({\n title, tabTip, path, lastModified, icon: 'flow1', layout: 'fit',\n events: {\n beforeclose() {\n return this.confirmClose(me.saveCard, me);\n }\n }, items: {\n cname: 'flowDesigner', cid: 'designerComp', events: {\n change() {\n app.setModified(this.parent);\n }\n }\n }\n });\n card.flowDesigner = card.down('designerComp')\n card.graph = card.flowDesigner.graph;\n card.flowDesigner.flowData = data ?? {};\n card.show();\n return card;\n },\n /**\n * Save workflow files.\n * @param {Boolean} [isAll] Whether to save all files.\n * @param {Function} [callback] The callback function after success.\n * @param {Boolean} [noConfirm] If the file has been modified, whether to prompt to overwrite it.\n * @param {Wb.Card} [card] The saved card. Default to the current card.\n */\n saveFile(isAll, callback, noConfirm, card) {\n let data = '', cards = [], content, path, designer, activeCard = card ?? app.activeCard;\n\n app.tab1.each(card => {\n if (card.isModified && (isAll || card == activeCard)) {\n designer = card.flowDesigner;\n designer.completeEdit();\n content = Wb.encode(designer.flowData);\n path = card.path;\n data += path + '|UTF-8|' + card.lastModified + '|' + content.length + '|' + content;\n cards.push(card);\n }\n });\n if (data) {\n Wb.ajax({\n url: 'm?xwl=sys/file/save', data, json: true,\n params: {\n confirm: noConfirm ? 0 : 1\n },\n success(lastModified) {\n cards.forEach((card, i) => {\n card.lastModified = lastModified[i];\n app.unModified(card);\n });\n callback?.call();\n },\n failure(resp) {\n if (resp.errorCode == 'modified')\n Wb.confirm(Str.modifiedConfirm.format(Wb.decode(resp.errorText).join(', ')),\n f => app.saveFile(isAll, callback, true));\n }\n });\n } else {\n callback?.call();\n }\n },\n /**\n * Save the file where the specified card has been modified.\n * @param {Wb.Card} [card] The saved card. Default to the current card.\n * @param {Function} [callback] The callback function after successfully saving.\n */\n saveCard(card, callback) {\n app.saveFile(false, callback, null, card);\n },\n /**\n * Mark the specified file card modified.\n * @param {Wb.Card} card File card.\n */\n setModified(card) {\n Wb.setModified(card);\n if (card == app.activeCard)\n app.saveItem.disabled = false;\n app.saveAllItem.disabled = false;\n },\n /**\n * Mark the specified file card unmodified.\n * @param {Wb.Card} card File card.\n */\n unModified(card) {\n Wb.unModified(card);\n if (card == app.activeCard)\n app.saveItem.disabled = true;\n app.saveAllItem.disabled = !app.tab1.some(t => t.isModified);\n },\n /**\n * Copy the specified cells. @priv\n * @param {Boolean} [cut] Whether perform cut.\n */\n copy(cut) {\n if (app.inInput)\n return;\n let designer = app.flowDesigner, cells = designer.graph.getSelectedCells();\n\n if (cells.length)\n app.clipboard = designer[cut ? 'cut' : 'copy'](cells);\n },\n /**\n * Paste clone cells to the current graph.\n */\n paste() {\n if (app.inInput)\n return;\n let designer = app.flowDesigner, clipboard = app.clipboard;\n\n if (clipboard) {\n let cells = designer.paste(clipboard), graph = designer.graph;\n graph.cleanSelection();\n graph.select(cells);\n }\n }\n});", "beforeunload": "if (!app.saveAllItem.disabled) {\n let card = app.tab1.find(card => card.isModified), btn = card?.tabButton;\n if (card) {\n card.show();\n btn.highlight();\n return false;\n }\n}" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "newItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "newItem", "text": "@Str.new", "icon": "file", "keys": "Ctrl+J" }, "events": { "click": "app.newFile();" } }, { "_icon": "item", "text": "openItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "openItem", "text": "@Str.open", "icon": "folder-open", "keys": "F3" }, "events": { "click": "app.openFile();" } }, { "_icon": "item", "text": "saveItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveItem", "text": "@Str.save", "icon": "save", "keys": "Ctrl+S", "disabled": "true" }, "events": { "click": "app.saveFile();" } }, { "_icon": "item", "text": "saveAllItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveAllItem", "text": "@Str.saveAll", "icon": "save-all", "keys": "Ctrl+Shift+S", "disabled": "true" }, "events": { "click": "app.saveFile(true);" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "cutItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "cutItem", "text": "@Str.cut", "icon": "cut", "keys": "Ctrl+X", "stopEvent": "false", "disabled": "true" }, "events": { "click": "app.copy(true);" } }, { "_icon": "item", "text": "copyItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "copyItem", "text": "@Str.copy", "icon": "copy", "keys": "Ctrl+C", "stopEvent": "false", "disabled": "true" }, "events": { "click": "app.copy();" } }, { "_icon": "item", "text": "pasteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "pasteItem", "text": "@Str.paste", "icon": "paste", "keys": "Ctrl+V", "stopEvent": "false", "disabled": "true" }, "events": { "click": "app.paste();" } }, { "_icon": "item", "text": "delItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delItem", "text": "@Str.del", "icon": "delete", "keys": "Delete", "stopEvent": "false", "disabled": "true" }, "events": { "click": "if (app.inInput)\n return;\nlet graph = app.graph, cells = app.graph.getSelectedCells();\n\nif (cells.length)\n graph.removeCells(cells);" } }, { "_icon": "item", "text": "undoItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "undoItem", "text": "@Str.undo", "icon": "undo", "keys": "Ctrl+Z", "stopEvent": "false", "disabled": "true" }, "events": { "click": "if (app.inInput)\n return;\nlet graph = app.graph;\n\nif (graph.canUndo())\n graph.undo();" } }, { "_icon": "item", "text": "redoItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "redoItem", "text": "@Str.redo", "icon": "redo", "keys": "Ctrl+Y", "stopEvent": "false", "disabled": "true" }, "events": { "click": "if (app.inInput)\n return;\nlet graph = app.graph;\n\nif (graph.canRedo())\n graph.redo();" } }, { "_icon": "item", "text": "selectAllItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "selectAllItem", "text": "@Str.selectAll", "icon": "panel", "keys": "Ctrl+A", "stopEvent": "false", "disabled": "true" }, "events": { "click": "if (app.inInput)\n return;\nlet graph = app.graph;\ngraph.select(graph.getCells());" } } ] }, { "_icon": "tab", "text": "tab1", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "tab1", "tabMenu": "true" }, "events": { "cardchange": "const editButtons = ['cutItem', 'copyItem', 'pasteItem', 'delItem', 'undoItem', 'redoItem', 'selectAllItem'];\nlet isModified = newCard?.isModified;\napp.saveItem.disabled = !isModified;\napp.saveAllItem.disabled = !app.tab1.some(t => t.isModified);\neditButtons.forEach(item => app[item].disabled = !newCard);" } } ] } ] } # admin/log/select.xwl Title: select Description: Select logs ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select logs", "serverScript": "function main() {\n let sql, where = [];\n\n sql = `select a.log_date, b.user_name as mix_user_name,b.display_name as mix_user_name_sub, a.ip, a.log_level, a.log_type, a.msg\n from wb_log a left join wb_user b on a.user_id=b.sid`;\n if (Params.beginDt)\n where.push('log_date >= {?timestamp|beginDt?}');\n if (Params.endDt)\n where.push('log_date <= {?timestamp|endDt?}');\n if (Params.username) {\n Wb.setLike('username');\n where.push('(b.user_name like {?username?} or b.display_name like {?username?})');\n }\n if (Params.msg) {\n Wb.setLike('msg');\n where.push('msg like {?msg?}');\n }\n if (Params.ip) {\n Wb.setLike('ip');\n where.push('ip like {?ip?}');\n }\n if (Params.logLevel)\n where.push('log_level={?int|logLevel?}');\n if (Params.logType) {\n Wb.setLike('logType');\n where.push('log_type like {?logType?}');\n }\n if (where.length) {\n sql += ' where ' + where.join(' and ');\n }\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # admin/log.xwl Title: System Log Description: System log ```json { "title": "@systemLog", "icon": "log", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "System log" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Pass the search parameters and reload the grid.\n */\n reload() {\n if (app.stopReload)\n return;\n app.grid1.delayLoad({ comps: app.viewport1.tbar });\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "flexWrap": "true", "gap": ".1em" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "dt-picker", "text": "beginDt", "cls": "Wb.Datetime", "properties": { "cid": "beginDt", "placeholder": "@Str.startTime", "clearButton": "true", "width": "15em" }, "events": { "change": "app.reload();" } }, { "_icon": "dt-picker", "text": "endDt", "cls": "Wb.Datetime", "properties": { "cid": "endDt", "placeholder": "@Str.endTime", "clearButton": "true", "width": "15em" }, "events": { "change": "app.reload();" } }, { "_icon": "combo", "text": "logLevel", "cls": "Wb.Select", "properties": { "cid": "logLevel", "keyName": "logLevel", "placeholder": "@Str.logLevel", "width": "9em", "clearButton": "true", "editable": "false" }, "events": { "change": "app.reload();" } }, { "_icon": "text", "text": "logType", "cls": "Wb.Text", "properties": { "cid": "logType", "placeholder": "@Str.logType", "width": "9em", "clearButton": "true" }, "events": { "change": "app.reload();" } }, { "_icon": "text", "text": "username", "cls": "Wb.Text", "properties": { "cid": "username", "placeholder": "@Str.username", "width": "9em", "clearButton": "true" }, "events": { "change": "app.reload();" }, "_expanded": true }, { "_icon": "text", "text": "msg", "cls": "Wb.Text", "properties": { "cid": "msg", "placeholder": "@Str.content", "width": "9em", "clearButton": "true" }, "events": { "change": "app.reload();" } }, { "_icon": "text", "text": "ip", "cls": "Wb.Text", "properties": { "cid": "ip", "placeholder": "@Str.ip", "width": "11em", "clearButton": "true" }, "events": { "change": "app.reload();" } }, { "_icon": "item", "text": "resetItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "resetItem", "icon": "undo", "text": "@Str.reset" }, "events": { "click": "app.stopReload = true;\nWb.reset(app.viewport1.tbar);\napp.stopReload = false;\napp.reload();" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "columnsSortable": "true", "sorters": "{name: 'log_date', desc: true}", "textSelectable": "true", "stateId": "wb.log" } } ] } ] } # admin/online-users/remove-sessions.xwl Title: remove-sessions Description: Remove sessions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Remove sessions", "serverScript": "Wb.checkDemo();\nfunction main() {\n let del = Wb.getObject('del');\n del.forEach(item => Sessions.invalidate(item.$userid));\n}\nmain();" }, "_icon": "module" } # admin/online-users/select-sessions.xwl Title: select-sessions Description: Select online sessions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select online sessions", "serverScript": "Wb.checkDemo();\nfunction main() {\n let fromIndex = Wb.getInt('_from'), toIndex = Wb.getInt('_to');\n Wb.send(Wb.UserUtil.getSessions(Params.userid, fromIndex, toIndex));\n}\nmain();" }, "_icon": "module" } # admin/online-users/select-users.xwl Title: select-users Description: Select online users ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select online users", "serverScript": "Wb.checkDemo();\nfunction main() {\n let fromIndex = Wb.getInt('_from'), toIndex = Wb.getInt('_to');\n Wb.send(Wb.UserUtil.getOnlineUsers(fromIndex, toIndex));\n}\nmain();" }, "_icon": "module" } # admin/online-users.xwl Title: Online Users Description: View online users ```json { "title": "@onlineUsers", "icon": "earth", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "View online users" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "column" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "userGrid", "cls": "Wb.Grid", "properties": { "cid": "userGrid", "url": "@xpath + '/select-users'", "autoSelect": "true", "textSelectable": "true", "flex": "1", "multiSelect": "true" }, "events": { "selectionchange": "let userid = this.selection?.data.userid;\n\nif (userid)\n app.sessionGrid.load({ params: { userid } });" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "usernameCol", "fieldName": "username", "width": "12em", "text": "@Str.username", "render": "let ct = data.sessions;\nif (ct > 1)\n return value + ' (' + ct + ')';\nelse\n return value;" }, "text": "usernameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "dispnameCol", "fieldName": "dispname", "width": "12em", "text": "@Str.displayName" }, "text": "dispnameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "ipCol", "fieldName": "ip", "width": "18em", "text": "@Str.ip" }, "text": "ipCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "createTimeCol", "fieldName": "createTime", "width": "13em", "text": "@Str.createTime" }, "text": "createTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastAccessTimeCol", "fieldName": "lastAccessTime", "width": "13em", "text": "@Str.lastAccessTime" }, "text": "lastAccessTimeCol", "_expanded": true, "_icon": "column" } ] }, { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "delItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delItem", "text": "@Str.logout", "icon": "delete" }, "events": { "click": "app.userGrid.removeRecords(xpath + '/remove-sessions', 'username', null, null, null, Str.logout);" } } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "grid", "text": "sessionGrid", "cls": "Wb.Grid", "properties": { "cid": "sessionGrid", "url": "@xpath + '/select-sessions'", "autoLoad": "false", "textSelectable": "true", "height": "14em" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "ipCol", "fieldName": "ip", "width": "18em", "text": "@Str.ip" }, "text": "ipCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "createTimeCol", "fieldName": "createTime", "width": "13em", "text": "@Str.createTime" }, "text": "createTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastAccessTimeCol", "fieldName": "lastAccessTime", "width": "13em", "text": "@Str.lastAccessTime" }, "text": "lastAccessTimeCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # admin/perm/select-modules.xwl Title: select-modules Description: Select modules ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select modules", "serverScript": "function main() {\n const fs = Wb.load('wb/modules/sys/file/fs.mjs');\n let items, rolesMap = {}, roles;\n\n Wb.getRows('select module_path,role_id from wb_perm', row => {\n roles = rolesMap[row.module_path] ??= [];\n roles.push(row.role_id);\n });\n items = fs.listPermModules();\n Wb.cascade(items, item => {\n if (item._leaf) {\n item.roles = rolesMap[item.path];\n }\n });\n Wb.send([{ _checked: false, text: Str.all, _expanded: true, items }]);\n}\nmain();" }, "_icon": "module" } # admin/perm/select-roles.xwl Title: select-roles Description: Select roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select roles", "serverScript": "function main() {\n let roles = Wb.roles, inRoles, params;\n\n if (Wb.isAdmin) {\n inRoles = '';\n } else {\n let sqlMap = Wb.Query.getArraySql(roles, 'varchar');\n inRoles = ' and sid not in (' + sqlMap.sql + ')';\n params = sqlMap.params;\n }\n Wb.sendRows({\n sql: `select sid,role_name as text` + (Params.check ? `,0 as \"_checked\"` : '') +\n `,'true' as \"_leaf\" from wb_role where sid<>'admin'${inRoles} order by role_name`,\n params,\n rs: -1\n });\n}\nmain();" }, "_icon": "module" } # admin/perm/set-actions.xwl Title: set-actions Description: Set permission actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set permission actions", "serverScript": "let actions = {\n /**\n * Set permissions.\n */\n setPerm() {\n let modules = Params.modules, oldModules, file, roleId = Params.roleId, checked = Wb.getBool('checked'),\n roles = Wb.roles, filename, isAdmin = Wb.isAdmin;\n\n if (!roleId || !isAdmin && roles.includes(roleId))\n Wb.raise('You are not allowed to set your own permissions. Please contact the administrator.');\n Wb.startTrans();\n if (checked) {\n let insert = [];\n oldModules = Wb.getAllRecords('select module_path from wb_perm where role_id={?roleId?}').pluck(0);\n modules = modules.diff(oldModules);\n modules.forEach(item => {\n filename = item + '.xwl';\n file = new Wb.File(Wb.File.moduleFolder, filename);\n if (!file.exists)\n Wb.raise(Str.notExists.format(item));\n if (!isAdmin && !Perm.permit(filename, roles))\n Wb.raise(Str.notHavePerm.format(filename));\n insert.push({ sid: Wb.getId(), module_path: item, role_id: roleId });\n });\n Wb.sync({ tableName: 'wb_perm', insert });\n modules.forEach(item => Perm.put(item, roleId));\n } else {\n let del = [];\n\n modules.forEach(item => {\n filename = item + '.xwl';\n if (!isAdmin && !Perm.permit(filename, roles))\n Wb.raise(Str.notHavePerm.format(filename));\n del.push({ $module_path: item, $role_id: roleId });\n });\n Wb.sync({ tableName: 'wb_perm', del, whereFields: 'module_path,role_id', unique: false });\n modules.forEach(item => Perm.remove(item, roleId));\n }\n },\n /**\n * Clean invalid data.\n */\n cleanInvalid() {\n let params = [];\n\n Wb.getRows('select module_path from wb_perm', row => {\n if (!new Wb.File(true, 'wb/modules/' + row.module_path + '.xwl').exists)\n params.push(row);\n });\n Wb.sql({ sql: 'delete from wb_perm where module_path={?module_path?}', params });\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # admin/perm.xwl Title: Permission Management Description: System permission management tool ```json { "title": "@permMng", "icon": "lock", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "System permission management tool" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /** @property {String} - The currently selected role ID. */\n get$roleId() {\n return app.roleTree1.selectionData?.sid;\n },\n /**\n * Sets permissions for the specified list of module nodes.\n * @param {Wb.TreeItem[]/Wb.TreeItem} nodes List of module nodes.\n * @param {String} roleId The role id.\n * @param {Boolean} checked True allows, false prohibits.\n * @param {Function} [success] Fires after success.\n */\n setPerm(nodes, roleId, checked, success) {\n let len;\n\n nodes = Wb.toArray(nodes);\n len = nodes.length;\n if (len > 1 || !nodes[0].leaf) {\n let word = len > 1 ? Str.nItems.format(len) : nodes[0].text;\n word = ' \"' + word + '\" ';\n Wb.confirm(Str.doConfirm.format(checked ? (Str.permit + word) : (Str.forbid + word)),\n f => app.doSetPerm(nodes, roleId, checked, success));\n } else\n app.doSetPerm(nodes, roleId, checked, success);\n },\n /**\n * Executes Set the permissions that specify the list of module nodes. @priv\n * @param {Array} nodes List of module nodes.\n * @param {String} roleId The role id.\n * @param {Boolean} checked True allows, false prohibits.\n * @param {Function} [success] Fires after success.\n */\n doSetPerm(nodes, roleId, checked, success) {\n let modules = [], leafNodes = [], oldRoles;\n\n nodes.forEach(node => {\n if (node.leaf)\n leafNodes.push(node);\n else\n leafNodes.pushAll(node.downAll(sub => sub.leaf));\n });\n leafNodes.forEach(node => modules.push(node.data.path));\n Wb.ajax({\n url: xpath + '/set-actions&xaction=setPerm',\n //Data can upload more data than params\n data: { modules, roleId, checked },\n success() {\n leafNodes.forEach(node => {\n if (node.leaf) {\n oldRoles = node.data.roles ??= [];\n if (checked) {\n if (!oldRoles.includes(roleId))\n oldRoles.push(roleId);\n } else {\n oldRoles.remove(roleId);\n }\n }\n });\n app.refreshPerms();\n app.refreshRoles();\n success?.();\n }\n });\n },\n /**\n * Updates the check box of the module tree.\n */\n refreshPerms() {\n let tree = app.moduleTree;\n\n tree.suspendEvent();\n app.scanPerms(app.roleId, tree, true);\n tree.resumeEvent();\n },\n /**\n * Updates the check boxes for the role tree.\n */\n refreshRoles() {\n let tree = app.roleTree2, moduleNode = app.moduleTree.selection;\n\n tree.suspendEvent();\n tree.each(node => {\n node.checked = app.scanPerms(node.data.sid, moduleNode);\n });\n tree.resumeEvent();\n },\n /**\n * Updates the check box of the module tree. @priv\n * @param {String} roleId The role id.\n * @param {Wb.TreeView/Wb.TreeItem} baseNode Specifies that the node and all its child nodes are set.\n * @param {Boolean} [doCheck] Whether to perform check module nodes.\n * @return {Boolean} Whether the node and all its child nodes are selected. If both checked and unchecked\n * nodes exist, return \"half\".\n */\n scanPerms(roleId, baseNode, doCheck) {\n let hasPerm, checked, allChecked = true, allUnchecked = true;\n\n if (baseNode.leaf) {\n hasPerm = baseNode.data.roles?.includes(roleId);\n if (doCheck)\n baseNode.checked = hasPerm;\n if (hasPerm)\n allUnchecked = false;\n else\n allChecked = false;\n } else {\n baseNode.each(node => {\n checked = app.scanPerms(roleId, node, doCheck);\n if (checked == 'half') {\n allChecked = false;\n allUnchecked = false;\n } else if (checked)\n allUnchecked = false;\n else\n allChecked = false;\n });\n }\n if (allChecked)\n checked = true;\n else if (allUnchecked)\n checked = false;\n else\n checked = 'half';\n if (doCheck && baseNode.isNode)\n baseNode.checked = checked;\n return checked;\n },\n /**\n * Select the first entry after the tree loads.\n * @param {Wb.Tree} tree The tree.\n */\n selectOnLoad(tree) {\n if (tree.loaded)\n tree.firstItem?.doSelect(true);\n else\n tree.on('success', f =>\n tree.firstItem?.doSelect(true)\n , true, { once: true });\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "tree-view", "text": "roleTree1", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "roleTree1", "width": "20vw", "title": "@Str.role", "url": "@xpath + '/select-roles'", "showIcon": "false", "leafExpander": "false", "icon": "role" }, "events": { "selectionchange": "this.subTitle = this.selection.text;\napp.refreshPerms();" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "tree-view", "text": "moduleTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "moduleTree", "flex": "1", "url": "@xpath + '/select-modules'", "multiSelect": "true", "allowDeselect": "false", "minWidth": "10em", "itemIcon": "module" }, "events": { "selectionchange": "app.roleTree2.subTitle = this.selection.text;\napp.refreshRoles();", "beforecheckchange": "if (app.roleId)\n app.setPerm(node, app.roleId, checked);\nreturn false;", "success": "app.selectOnLoad(app.roleTree1);" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "permitItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "permitItem", "icon": "ok", "text": "@Str.permit", "keys": "Ctrl+E" }, "events": { "click": "if (app.roleId)\n app.setPerm(app.moduleTree.topSelections, app.roleId, true);\nelse\n Wb.tipSelect(Str.role);" } }, { "_icon": "item", "text": "forbidItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "forbidItem", "icon": "cancel", "text": "@Str.forbid", "keys": "Ctrl+D" }, "events": { "click": "if (app.roleId)\n app.setPerm(app.moduleTree.topSelections, app.roleId, false);\nelse\n Wb.tipSelect(Str.role);" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "expandAll", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "expandAll", "text": "@Str.expandAll", "icon": "expand" }, "events": { "click": "app.moduleTree.expandAll();" } }, { "_icon": "item", "text": "collapseAll", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "collapseAll", "text": "@Str.collapseAll", "icon": "compress" }, "events": { "click": "app.moduleTree.collapseAll();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "item", "text": "clearItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "clearItem", "icon": "recycle", "text": "@Str.clear", "tip": "@Str.clearInvalidData" }, "events": { "click": "Wb.confirm(Str.doConfirm.format(Str.clear), f => {\n Wb.ajax({\n url: xpath + '/set-actions&xaction=cleanInvalid',\n success() {\n Wb.tipDone(Str.clear);\n }\n });\n});" } } ] }, { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "expanderCol", "fieldName": "text", "expander": "true", "render": "let remark = data.remark;\n\nif (remark) {\n let span = el.addTag('span');\n span.textContent = value;\n span = el.addEl('w-sub-color w-margin-l', 'span');\n span.textContent = Wb.optText(remark);\n} else {\n return value;\n}" }, "text": "expanderCol", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "splitter", "text": "splitter2", "cls": "Wb.Splitter", "properties": { "cid": "splitter2" } }, { "_icon": "tree-view", "text": "roleTree2", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "roleTree2", "width": "20vw", "url": "@xpath + '/select-roles&check=1'", "showIcon": "false", "leafExpander": "false", "title": "@Str.set", "icon": "role" }, "events": { "beforecheckchange": "app.setPerm(app.moduleTree.selection, node.data.sid, checked, f => {\n this.suspendEvent();\n node.checked = checked;\n this.resumeEvent();\n});\nreturn false;", "success": "app.selectOnLoad(app.moduleTree);" } } ] } ] } # admin/role/add.xwl Title: add Description: Add role ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add role", "serverScript": "function main() {\n let sid = Params.role_id_disp || Wb.getId();\n\n Params.sid = sid;\n Wb.sync({ tableName: 'wb_role', insert: Params });\n Wb.send({ sid, role_id_disp: sid });\n}\nmain();" }, "_icon": "module" } # admin/role/del.xwl Title: del Description: Delete roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete roles", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let del = Wb.getObject('del'), roleName, buffer = Perm.buffer, keys = [];\n\n del.forEach(item => (roleName = item.$role_name) && Util.isReservedRole(roleName) &&\n Wb.raise(Str.cannotDelete.format(roleName)));\n Wb.sync({ tableName: 'wb_role', del });\n Wb.sql({ sql: 'delete from wb_user_role where role_id={?$sid?}', params: del });\n Wb.sql({ sql: 'delete from wb_perm where role_id={?$sid?}', params: del });\n buffer.forEach(k => {\n if (del.some(item => k.endsWith('|' + item.$sid)))\n keys.push(k);\n });\n keys.forEach(k => buffer.remove(k));\n}\nmain();" }, "_icon": "module" } # admin/role/edit.xwl Title: edit Description: Edit role ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit role", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let oldRoleName = Params.$role_name;\n if (Params.role_name && Util.isReservedRole(oldRoleName))\n Wb.raise(Str.cannotModify.format(Params.role_name));\n Params.sid = undefined;\n Wb.sync({ tableName: 'wb_role', update: Params });\n}\nmain();" }, "_icon": "module" } # admin/role/get-modules-by-role.xwl Title: get-modules-by-role Description: Get modules by role ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get modules by role", "serverScript": "function main() {\n let permItems, module, path, fullPath, inRole, text, curText, normalName, scan, icon, img, indexFile, total = 0,\n rows = [], search = Params.search;\n\n scan = (folder, pathText) => {\n folder.each(file => {\n if (file.isModuleFile && !file.isMinFile) {\n fullPath = file.modulePath;\n path = fullPath.slice(0, -4);\n if (inRole && permItems.includes(path) || !inRole && !permItems.includes(path)) {\n module = Xwl.get(fullPath);\n if (module.loginRequired) {\n text = Wb.optText(module.title);\n normalName = file.normalName;\n if (search && !text.includes(search) && !normalName.includes(search))\n return;\n total++;\n icon = module.icon;\n img = module.img;\n if (img)\n img = 'wb/images/' + img + '.png';\n if (!img && !icon)\n icon = 'module';\n rows.push({\n text: pathText + (text || normalName), subtext: module.remark, path, _icon: icon, _img: img,\n });\n }\n }\n } else if (file.isFolder) {\n indexFile = new Wb.File(file, 'index.json');\n curText = (indexFile.exists ? Wb.optText(indexFile.object.title) : null) || file.name;\n if (pathText)\n curText = pathText + curText;\n scan(file, curText + '/');\n }\n });\n }\n inRole = Wb.getBool('inRole');\n permItems = Wb.getAllRecords('select module_path from wb_perm where role_id={?role_id?}')?.pluck(0);\n scan(Wb.File.moduleFolder, '');\n rows.mixSort('text');\n Wb.send({ items: rows.slice(Wb.getInt('_from'), Wb.getInt('_to') + 1), total });\n}\nmain();" }, "_icon": "module" } # admin/role/get-users-by-role.xwl Title: get-users-by-role Description: Get users by role ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get users by role", "serverScript": "let sql;\n\nif (Wb.getBool('inRole')) {\n sql = `select sid,user_name,display_name from wb_user where sid in\n (select user_id from wb_user_role where role_id={?role_id?})`;\n} else {\n sql = `select sid,user_name,display_name from wb_user where sid not in\n (select user_id from wb_user_role where role_id={?role_id?})`;\n}\nif (Params.search) {\n Wb.setLike('search');\n sql += ' and (user_name like {?search?} or display_name like {?search?})';\n}\nWb.sendRows(sql);" }, "_icon": "module" } # admin/role/select.xwl Title: select Description: Select roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select roles", "serverScript": "function main() {\n let sql = 'select t.*,t.sid as role_id_disp from wb_role t';\n if (Params.search) {\n Wb.setLike('search');\n sql += ' where t.role_name like {?search?} or t.sid like {?search?}';\n }\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # admin/role/set-module-roles.xwl Title: set-module-roles Description: Set module roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set module roles", "serverScript": "let insert = [], del = [], user_id, include = Wb.getBool('include'), role_id = Params.role_id;\n\nParams.items.forEach(item => {\n if (include)\n insert.push({ sid: Wb.getId(), module_path: item.path, role_id });\n else\n del.push({ $module_path: item.path, $role_id: role_id });\n});\nif (include)\n Wb.sync({ tableName: 'wb_perm', insert });\nelse\n Wb.sync({ tableName: 'wb_perm', del, whereFields: 'module_path,role_id' });" }, "_icon": "module" } # admin/role/set-user-roles.xwl Title: set-user-roles Description: Set user roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set user roles", "serverScript": "let insert = [], del = [], user_id, include = Wb.getBool('include'), role_id = Params.role_id;\n\nParams.items.forEach(item => {\n if (include)\n insert.push({ sid: Wb.getId(), user_id: item.sid, role_id });\n else\n del.push({ $user_id: item.sid, $role_id: role_id });\n});\nif (include)\n Wb.sync({ tableName: 'wb_user_role', insert });\nelse\n Wb.sync({ tableName: 'wb_user_role', del, whereFields: 'user_id,role_id' });" }, "_icon": "module" } # admin/role.xwl Title: Role Config Description: Add role ```json { "title": "@roleConfig", "icon": "role", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add role" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Fires after insert or update fails.\n */\n onFailure(resp) {\n let checkFields = { wb_role_pk: 'role_id_disp', wb_role_role_name: 'role_name' };\n\n Wb.each(checkFields, (k, v) => {\n if (Wb.checkExists(resp, k, app.grid1.dictWin.down(v)))\n return false;\n });\n },\n /** @property {Object} - The edit window configs object. */\n winConfigs: {\n width: '45em'\n },\n /**\n * Load the specified box data. @priv\n * @param {Wb.DualBox} box Dual box component.\n */\n loadBoxData(box) {\n if (!box.visible)\n return;\n let data = app.selectedData, srcGrid, destGrid, configs;\n\n box.disabled = !data || box == app.moduleBox && data?.sid == 'admin';\n srcGrid = box.sourceGrid;\n destGrid = box.destGrid;\n srcGrid.subTitle = destGrid.subTitle = data ? data.role_name : Str.notSelected;\n if (data) {\n configs = { params: { role_id: data.sid } };\n srcGrid.load(configs);\n destGrid.load(configs);\n } else {\n srcGrid.destroyAll();\n destGrid.destroyAll();\n }\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "column", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "let win = app.grid1.dictAdd({\n url: xpath + '/add',\n failure: app.onFailure\n}, Str.role, null, null, app.winConfigs);\nwin.down('role_id_disp').readonly = false;" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let win = app.grid1.dictEdit({\n url: xpath + '/edit',\n failure: app.onFailure\n}, 'role_name', null, null, app.winConfigs);\nwin.down('role_id_disp').readonly = true;" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'role_name');" } }, { "_icon": "divider", "text": "divider", "cls": "Wb.Divider", "properties": { "cid": "divider" } }, { "_icon": "item", "text": "userBoxBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "userBoxBtn", "active": "false", "icon": "user2", "text": "@Str.user", "activeBgColor": "false" }, "events": { "toggle": "app.userSplitter.visible = app.userBox.visible = active;\napp.loadBoxData(app.userBox);" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "moduleBoxBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "moduleBoxBtn", "active": "false", "icon": "module", "text": "@Str.module", "activeBgColor": "false" }, "events": { "toggle": "app.moduleSplitter.visible = app.moduleBox.visible = active;\napp.loadBoxData(app.moduleBox);" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "role_name", "stateId": "wb.role", "keyFields": "sid,role_name", "flex": "1" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');", "selectionchange": "app.selectedData = app.grid1.selectionData;\napp.loadBoxData(app.userBox);\napp.loadBoxData(app.moduleBox);" } }, { "_icon": "splitter", "text": "userSplitter", "cls": "Wb.Splitter", "_expanded": true, "properties": { "cid": "userSplitter", "visible": "false" } }, { "_icon": "dual-box", "text": "userBox", "cls": "Wb.DualBox", "properties": { "cid": "userBox", "sourceUrl": "@xpath + '/get-users-by-role&inRole=0'", "destUrl": "@xpath + '/get-users-by-role&inRole=1'", "autoLoad": "false", "visible": "false", "height": "18em", "searchBar": "true", "textField": "display_name", "subtextField": "user_name" }, "events": { "beforemove": "Wb.ajax({\n url: xpath + '/set-user-roles',\n data: { items, include, role_id: app.selectedData.sid },\n success: f => {\n this.acceptMove();\n }\n});\nreturn false;" }, "_expanded": true, "items": [ { "cls": "Wb.Grid", "properties": { "cid": "sourceGridConfigs", "isProperty": "true", "title": "@Str.availableUsers" }, "text": "sourceGridConfigs", "_expanded": true, "_icon": "grid" }, { "cls": "Wb.Grid", "properties": { "cid": "destGridConfigs", "isProperty": "true", "title": "@Str.selectedUsers" }, "text": "destGridConfigs", "_expanded": true, "_icon": "grid" }, { "cls": "Wb.Array", "properties": { "cid": "columnsx" }, "text": "columnsx", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "userNameCol", "fieldName": "user_name", "width": "-1" }, "text": "userNameCol", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "splitter", "text": "moduleSplitter", "cls": "Wb.Splitter", "_expanded": true, "properties": { "cid": "moduleSplitter", "visible": "false" } }, { "_icon": "dual-box", "text": "moduleBox", "cls": "Wb.DualBox", "properties": { "cid": "moduleBox", "sourceUrl": "@xpath + '/get-modules-by-role&inRole=0'", "destUrl": "@xpath + '/get-modules-by-role&inRole=1'", "autoLoad": "false", "visible": "false", "height": "18em", "searchBar": "true" }, "events": { "beforemove": "Wb.ajax({\n url: xpath + '/set-module-roles',\n data: { items, include, role_id: app.selectedData.sid },\n success: f => {\n this.acceptMove();\n }\n});\nreturn false;" }, "_expanded": true, "items": [ { "cls": "Wb.Grid", "properties": { "cid": "sourceGridConfigs", "isProperty": "true", "title": "@Str.availableModules", "showIcon": "true" }, "text": "sourceGridConfigs", "_expanded": true, "_icon": "grid" }, { "cls": "Wb.Grid", "properties": { "cid": "destGridConfigs", "isProperty": "true", "title": "@Str.selectedModules", "showIcon": "true" }, "text": "destGridConfigs", "_expanded": true, "_icon": "grid" } ] } ] } ] } # admin/sysinfo/select.xwl Title: select Description: Select system information ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select system information", "serverScript": "Wb.checkDemo();\nlet actions = {\n /**\n * Get modules information.\n */\n moduleInfo() {\n let items = [], duration, times, sorter = Wb.getObject('_sort')?.[0];\n Classes.Executor.dataMap.forEach((k, v) => {\n duration = v.duration.get();\n times = v.times.get();\n items.push({\n module: k.slice(0, -4), duration: duration / 1000, times, lastAccess: new Date(v.lastAccess),\n avgDuration: Math.round(duration / times)\n });\n });\n if (sorter) {\n items.mixSort(sorter.name, sorter.desc);\n }\n Wb.send({ items: items.slice(Wb.getInt('_from'), Wb.getInt('_to') + 1), total: items.length });\n },\n /**\n * Clear all module runtime data.\n */\n clear() {\n Classes.Executor.dataMap.clear();\n },\n /**\n * Get system information.\n */\n sysInfo() {\n let items = [], rt = Runtime.getRuntime(), props = System.getProperties(), env = System.getenv(),\n addr = Classes.InetAddress.getLocalHost(), total = rt.totalMemory(), free = rt.freeMemory(), cpu = getCpuUsage();\n\n items = [{\n name: 'Current Time',\n value: new Date().format(Str.dateTimeFormat)\n }, {\n name: 'System startup time',\n value: new Date(Base.startTime.getTime()).format(Str.dateTimeFormat)\n }, {\n name: 'Available Processors',\n value: rt.availableProcessors().intText\n }, {\n name: 'CPU Usage',\n numValue: cpu,\n value: cpu.percentAuto\n }, {\n name: 'JVM CPU Usage',\n value: getCpuUsage(true).percentAuto\n }, {\n name: 'Total Memory',\n numValue: total,\n value: total.mb\n }, {\n name: 'Used Memory',\n numValue: total - free,\n value: (total - free).mb\n }, {\n name: 'Free Memory',\n value: free.mb\n }, {\n name: 'Max Memory',\n value: rt.maxMemory().mb\n }, {\n name: 'Username',\n value: env?.get('USERNAME')\n }, {\n name: 'Computer Name',\n value: env?.get('COMPUTERNAME')\n }, {\n name: 'User Domain',\n value: env?.get('USERDOMAIN')\n }, {\n name: 'Host Address',\n value: addr.getHostAddress()\n }, {\n name: 'Host Name',\n value: addr.getHostName()\n }, {\n name: 'OS Name',\n value: props.getProperty('os.name')\n }, {\n name: 'OS Architecture',\n value: props.getProperty('os.arch')\n }, {\n name: 'OS Version',\n value: props.getProperty('os.version')\n }, {\n name: 'Java Version',\n value: props.getProperty('java.version')\n }, {\n name: 'Java Vendor',\n value: props.getProperty('java.vendor')\n }, {\n name: 'Java Vendor URL',\n value: props.getProperty('java.vendor.url')\n }, {\n name: 'Java Home',\n value: props.getProperty('java.home')\n }, {\n name: 'Java VM Specification Version',\n value: props.getProperty('java.vm.specification.version')\n }, {\n name: 'Java VM Specification Vendor',\n value: props.getProperty('java.vm.specification.vendor')\n }, {\n name: 'Java VM Specification Name',\n value: props.getProperty('java.vm.specification.name')\n }, {\n name: 'Java VM Version',\n value: props.getProperty('java.vm.version')\n }, {\n name: 'Java VM Vendor',\n value: props.getProperty('java.vm.vendor')\n }, {\n name: 'Java VM Name',\n value: props.getProperty('java.vm.name')\n }, {\n name: 'Polyglot Version',\n value: Classes.ContextPool.getEngineVersion()\n }, {\n name: 'Java Specification Version',\n value: props.getProperty('java.specification.version')\n }, {\n name: 'Java Specification Vendor',\n value: props.getProperty('java.specification.vendor')\n }, {\n name: 'Java Specification Name',\n value: props.getProperty('java.specification.name')\n }, {\n name: 'Java Class Version',\n value: props.getProperty('java.class.version')\n }, {\n name: 'Java Class Path',\n value: props.getProperty('java.class.path')\n }, {\n name: 'Java Library Path',\n value: props.getProperty('java.library.path')\n }, {\n name: 'File Separator',\n value: Wb.encode(props.getProperty('file.separator'))\n }, {\n name: 'Path Separator',\n value: Wb.encode(props.getProperty('path.separator'))\n }, {\n name: 'Line Separator',\n value: Wb.encode(props.getProperty('line.separator'))\n }, {\n name: 'User Account Name',\n value: props.getProperty('user.name')\n }, {\n name: 'User Home Directory',\n value: props.getProperty('user.home')\n }, {\n name: 'User Directory',\n value: props.getProperty('user.dir')\n }, {\n name: 'Java Extension Directories',\n value: props.getProperty('java.ext.dirs')\n }, {\n name: 'Java Temp Directory',\n value: props.getProperty('java.io.tmpdir')\n }];\n if (Params.chart) {\n items = items.filter(item => item.numValue != null);\n }\n Wb.send(items);\n }\n};\nactions[Params.xaction]();\n// get cpu usage\nfunction getCpuUsage(process) {\n try {\n const SunOSBean = Java.type(\"com.sun.management.OperatingSystemMXBean\");\n const os = java.lang.management.ManagementFactory.getPlatformMXBean(SunOSBean);\n const load = process ? os.getProcessCpuLoad() : os.getSystemCpuLoad();\n return load >= 0 ? load : 0;\n } catch (e) {\n return 0;\n }\n}" }, "_icon": "module" } # admin/sysinfo.xwl Title: System Information Description: View system information ```json { "title": "@sysinfo", "icon": "system", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "View system information" }, "_icon": "module", "_expanded": true, "events": { "initialize": "const points = 200;\nWb.apply(app, {\n /** @property {Number} - Failure count. */\n failCount: 0,\n /**\n * Viewport ready event handler.\n */\n onReady() {\n app.autoRefreshTimer ??= setInterval(f => {\n if (app.isLoading)\n return;\n app.isLoading = true;\n Wb.ajax({\n url: xpath + '/select&xaction=sysInfo&chart=1',\n showError: false,\n showMask: false,\n json: true,\n callback(resp, xhr) {\n app.isLoading = false;\n if (xhr.ok) {\n app.failCount = 0;\n app.addToChart(resp);\n } else {\n app.failCount++;\n if (app.failCount > 30)\n clearInterval(app.autoRefreshTimer);\n }\n }\n });\n }, 1000)\n },\n /**\n * Viewport destroy event handler.\n */\n onDestroy() {\n clearInterval(app.autoRefreshTimer);\n app.autoRefreshTimer = null;\n },\n /**\n * Add CPU and memory to chart.\n * @param {Array} data System information data.\n */\n addToChart(data) {\n const VIEW_LIMIT = points - 7;\n let cpu = data[0].numValue * 100, totalMemory = data[1].numValue / 1048576, memory = data[2].numValue / 1048576,\n option = app.chart1.option, cpuSeries = option.series[0], memorySeries = option.series[1], index;\n\n if (app.currentIndex == null) {\n app.currentIndex = 0;\n }\n index = app.fixedIndex ?? app.currentIndex;\n if (app.currentIndex >= VIEW_LIMIT) {\n index = app.fixedIndex = VIEW_LIMIT - 1;\n cpuSeries.data.shift();\n cpuSeries.data.push(null);\n memorySeries.data.shift();\n memorySeries.data.push(null);\n } else {\n app.currentIndex++;\n }\n if (cpu !== null) {\n cpuSeries.data[index] = cpu;\n }\n if (memory !== null) {\n memorySeries.data[index] = memory;\n }\n option.yAxis[1].max = totalMemory;\n option.yAxis[1].interval = Math.ceil(totalMemory / 5);\n app.chart1.option = option;\n }\n});" }, "items": [ { "_icon": "plug", "text": "socket1", "cls": "Wb.Socket", "properties": { "cid": "socket1" }, "events": { "open": "app.onReady();", "close": "app.onDestroy();" } }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "column" }, "_expanded": true, "events": { "destroy": "app.onDestroy();" }, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "flex": "1" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select&xaction=sysInfo'", "textSelectable": "true", "reserveScrollbar": "true", "flex": "1", "pageSize": "-1" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "nameCol", "fieldName": "name", "text": "Name", "width": "16em" }, "text": "nameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "valueCol", "text": "Value", "fieldName": "value", "width": "-1", "autoWrap": "break-all", "minWidth": "10em" }, "text": "valueCol", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "grid", "text": "grid2", "cls": "Wb.Grid", "properties": { "cid": "grid2", "url": "@xpath + '/select&xaction=moduleInfo'", "textSelectable": "true", "reserveScrollbar": "true", "sorters": "{name:'avgDuration',desc:true}", "width": "50%", "columnsSortable": "true", "defaultFields": "({ lastAccess: { type: 'date' } })" }, "_expanded": true, "events": { "ready": "let bar = this.pagingBar;\nbar.insertAfter({\n icon: 'trash', tip: 'Clear data', handler() {\n Wb.ajax({\n url: xpath + '/select&xaction=clear',\n success() {\n app.grid2.destroyAll();\n }\n });\n }\n}, bar.menuItem);" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "moduleCol", "fieldName": "module", "text": "Module", "width": "-1", "minWidth": "10em" }, "text": "moduleCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "durationCol", "text": "CPU (s)", "fieldName": "duration", "width": "7em", "type": "intText" }, "text": "durationCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "timesCol", "text": "Times", "fieldName": "times", "width": "7em" }, "text": "timesCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "avgDurationCol", "text": "Avg (ms)", "width": "7em", "fieldName": "avgDuration" }, "text": "avgDurationCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "lastAccessCol", "text": "Last Access", "fieldName": "lastAccess", "width": "12em", "type": "dateTimeTextHM" }, "text": "lastAccessCol", "_expanded": true, "_icon": "column" } ] } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "chart-bar", "text": "chart1", "cls": "Wb.Chart", "properties": { "cid": "chart1", "height": "20em", "option": "({\n tooltip: {\n trigger: 'axis',\n formatter: function (params) {\n const result = [];\n params.forEach(function (param) {\n let value = param.value;\n if (value == null)\n return '';\n if (param.seriesName === 'CPU Usage') {\n value = (value / points).percent;\n } else if (param.seriesName === 'Used Memory') {\n value = value.intText + ' MB';\n }\n result.push(`${param.seriesName}: ${value}`);\n });\n return result.join('
');\n }\n },\n animation: false,\n legend: { data: ['CPU Usage', 'Used Memory'] },\n xAxis: {\n type: 'category',\n boundaryGap: false,\n show: false,\n data: new Array(points).fill(Wb.getId()),\n },\n yAxis: [\n {\n type: 'value',\n name: 'CPU (%)',\n position: 'left',\n min: 0,\n max: 100,\n interval: 20\n },\n {\n type: 'value',\n splitLine: { show: false },\n name: 'Memory (MB)',\n position: 'right',\n min: 0,\n max: 1000\n }\n ],\n series: [\n {\n name: 'CPU Usage',\n type: 'line',\n yAxisIndex: 0,\n lineStyle: {\n color: '#ff4d4f'\n },\n itemStyle: {\n color: '#e74c3c'\n },\n data: new Array(points).fill(null)\n },\n {\n name: 'Used Memory',\n type: 'line',\n yAxisIndex: 1,\n data: new Array(points).fill(null)\n }\n ]\n})" } } ] } ] } # admin/task/add.xwl Title: add Description: Add task ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add task", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let sid = Wb.getId(), rec = { sid }, db = Wb.getConn();\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_job', insert: Params, db });\n JobUtil.reloadJob(sid, db.connection);\n Wb.send(Wb.apply(rec, Util.getFireTime(sid)));\n}\nmain();" }, "_icon": "module" } # admin/task/del.xwl Title: del Description: Delete tasks ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete tasks", "serverScript": "function main() {\n let del = Wb.getObject('del');\n\n del.forEach(item => JobUtil.stopJob(item.$sid));\n Wb.sync({ tableName: 'wb_job', del });\n}\nmain();" }, "_icon": "module" } # admin/task/edit.xwl Title: edit Description: Edit task ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit task", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let id = Params.$sid, db = Wb.getConn();\n Wb.sync({ tableName: 'wb_job', update: Params, db });\n if (Wb.parseBool(Wb.getx('status'))) {\n JobUtil.reloadJob(id, db.connection);\n } else {\n JobUtil.stopJob(id);\n }\n Wb.send(Util.getFireTime(id));\n}\nmain();" }, "_icon": "module" } # admin/task/select.xwl Title: select Description: Select tasks ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select tasks", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let sql, rows, dateType = { type: \"date\" };\n\n sql = 'select * from wb_job';\n if (Params.search) {\n Wb.setLike('search');\n sql += ' where job_name like {?search?}';\n }\n sql += ' order by status desc,' + Wb.getOrderSql(null, null, false);\n rows = Wb.getRowx(sql);\n Wb.apply(rows.fields, { trigger_time: dateType, previous_time: dateType, next_time: dateType });\n rows.items?.forEach(item => {\n Wb.apply(item, Util.getFireTime(item.sid));\n });\n Wb.send(rows);\n}\nmain();" }, "_icon": "module" } # admin/task/set-status.xwl Title: set-status Description: Set tasks status ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set tasks status", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let update = Wb.getObject('update'), status = Wb.getBool('status') ? 1 : 0, times = [], id, db = Wb.getConn();\n\n update.forEach(item => item.status = status);\n Wb.sync({ tableName: 'wb_job', update, db });\n if (status) {\n JobUtil.reloadJobs(update.pluck('$sid'), db.connection);\n }\n update.forEach(item => {\n id = item.$sid;\n if (!status)\n JobUtil.stopJob(id);\n times.push(Util.getFireTime(id));\n });\n Wb.send(times);\n}\nmain();" }, "_icon": "module" } # admin/task/start-stop-task.xwl Title: start-stop-task Description: Start or stop tasks ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Start or stop tasks", "serverScript": "function main() {\n let status = Wb.getBool('status');\n\n if (status)\n JobUtil.startEngine();\n else\n JobUtil.shutdownEngine();\n Wb.setConfig(\"sys.task.enabled\", status);\n}\nmain();" }, "_icon": "module" } # admin/task.xwl Title: Task Manager Description: Scheduled task management tool ```json { "title": "@taskMng", "icon": "task", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.set('isStartup', JobUtil.isStartup());\n}\nmain();", "remark": "Scheduled task management tool" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n isStartup: _$isStartup$_,\n /**\n * Set status of the specified tasks.\n * @param {Boolean} status false disabled, true enabled.\n */\n setStatus(status) {\n let grid = app.grid1, selRecs = grid.selections;\n if (!selRecs.length) {\n Wb.tipSelect();\n return;\n }\n selRecs = selRecs.filter(rec => rec.data.status != status);\n if (!selRecs.length)\n return;\n Wb.ajax({\n url: xpath + '/set-status',\n json: true,\n params: { update: selRecs.pluck('originData'), status },\n success(items) {\n selRecs.forEach((rec, i) => {\n items[i].status = status;\n rec.update(items[i]);\n });\n }\n });\n },\n /**\n * Set the startStop btn text and icon.\n */\n setStartStopBtn() {\n let b = app.isStartup, btn = app.startStopBtn;\n btn.icon = b ? 'stop' : 'play';\n btn.text = b ? Str.stop : Str.start;\n }\n});" }, "items": [ { "_icon": "window", "text": "editWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "editWin", "resetDialog": "true", "layout": "form1", "width": "70em", "tableStyle": "true", "icon": "task" }, "items": [ { "_icon": "text", "text": "job_name", "cls": "Wb.Text", "properties": { "cid": "job_name", "text": "@Str.name", "required": "true" } }, { "_icon": "model", "text": "intervalCt", "cls": "Wb.ControlCt", "properties": { "cid": "intervalCt", "required": "true", "text": "@Str.interval", "layout": "grid1", "gap": ".5em" }, "_expanded": true, "items": [ { "_icon": "radios", "text": "interval_type", "cls": "Wb.RadioGroup", "properties": { "cid": "interval_type", "layout": "row", "gap": "2em" }, "_expanded": true, "events": { "change": "let value = this.value;\n\napp.interval_value.visible = [0, 1, 2].includes(value);\napp.trigger_time.visible = value > 2 && value < 7;\napp.trigger_weekday.visible = value == 4;\napp.trigger_day.visible = value == 5 || value == 6;\napp.trigger_month.visible = value == 6;\napp.cron_express.visible = value == 7;" }, "items": [ { "_icon": "check2", "text": "secondRadio", "cls": "Wb.Radio", "properties": { "cid": "secondRadio", "label": "@Str.s" } }, { "_icon": "check2", "text": "minuteRadio", "cls": "Wb.Radio", "properties": { "cid": "minuteRadio", "label": "@Str.m" } }, { "_icon": "check2", "text": "hourRadio", "cls": "Wb.Radio", "properties": { "cid": "hourRadio", "label": "@Str.h" } }, { "_icon": "check2", "text": "dayRadio", "cls": "Wb.Radio", "properties": { "cid": "dayRadio", "label": "@Str.day" } }, { "_icon": "check2", "text": "weekRadio", "cls": "Wb.Radio", "properties": { "cid": "weekRadio", "label": "@Str.week" } }, { "_icon": "check2", "text": "monthRadio", "cls": "Wb.Radio", "properties": { "cid": "monthRadio", "label": "@Str.month" } }, { "_icon": "check2", "text": "yearRadio", "cls": "Wb.Radio", "properties": { "cid": "yearRadio", "label": "@Str.year" } }, { "_icon": "check2", "text": "cronRadio", "cls": "Wb.Radio", "properties": { "cid": "cronRadio", "label": "Cron" } } ] }, { "_icon": "container", "text": "valuesCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "valuesCt", "layout": "row", "gap": "true" }, "items": [ { "_icon": "number-edit", "text": "interval_value", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "interval_value", "minValue": "1", "decimalCount": "0", "required": "true", "width": "15em", "text": "@Str.every" } }, { "_icon": "combo", "text": "trigger_month", "cls": "Wb.Select", "properties": { "cid": "trigger_month", "data": "(f => {\n let date = new Date(2022, 0, 1), i, months = [],\n formatter = new Intl.DateTimeFormat(Str.lang, { month: 'long' });\n for (i = 0; i < 12; i++)\n months.push({ text: formatter.format(date.addMonth(i)), value: i + 1 });\n return months;\n})()", "required": "true", "text": "@Str.month", "forceSelect": "true" } }, { "_icon": "combo", "text": "trigger_weekday", "cls": "Wb.Select", "properties": { "cid": "trigger_weekday", "data": "(f => {\n let date = new Date(2022, 10, 6), i, days = [],\n formatter = new Intl.DateTimeFormat(Str.lang, { weekday: 'long' });\n for (i = 0; i < 7; i++)\n days.push({ text: formatter.format(date.addDay(i)), value: i + 1 });\n return days;\n})()", "required": "true", "text": "@Str.week", "forceSelect": "true", "width": "15em" } }, { "_icon": "number-edit", "text": "trigger_day", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "trigger_day", "required": "true", "text": "@Str.day", "minValue": "-31", "maxValue": "31", "width": "10em", "validator": "if (value == 0)\n return Str.invalidDate.format(value);" } }, { "_icon": "time", "text": "trigger_time", "cls": "Wb.Time", "properties": { "cid": "trigger_time", "text": "@Str.time", "required": "true", "width": "15em" } }, { "_icon": "text", "text": "cron_express", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "cron_express", "text": "@Str.expression", "required": "true", "flex": "1" } } ] } ] }, { "_icon": "model", "text": "durationCt", "cls": "Wb.ControlCt", "properties": { "cid": "durationCt", "gap": "true", "text": "@Str.duration" }, "_expanded": true, "items": [ { "_icon": "dt-picker", "text": "begin_date", "cls": "Wb.Datetime", "properties": { "cid": "begin_date", "text": "@Str.from" } }, { "_icon": "dt-picker", "text": "end_date", "cls": "Wb.Datetime", "properties": { "cid": "end_date", "text": "@Str.to" } } ] }, { "_icon": "model", "text": "optionCt", "cls": "Wb.ControlCt", "_expanded": true, "properties": { "cid": "optionCt", "gap": "2em", "layout": "row", "text": "@Str.options" }, "items": [ { "_icon": "switcher-on", "text": "status", "cls": "Wb.Toggle", "properties": { "cid": "status", "text": "@Str.enabled", "value": "true" } }, { "_icon": "switcher-on", "text": "concurrent", "cls": "Wb.Toggle", "properties": { "cid": "concurrent", "text": "@Str.concurrent", "value": "true" }, "_expanded": true }, { "_icon": "switcher-on", "text": "auto_removed", "cls": "Wb.Toggle", "properties": { "cid": "auto_removed", "text": "@Str.oneTimeTask" } } ] }, { "_icon": "text", "text": "job_desc", "cls": "Wb.Text", "properties": { "cid": "job_desc", "text": "@Str.desc" } }, { "_icon": "model", "text": "scriptCt", "cls": "Wb.ControlCt", "_expanded": true, "properties": { "cid": "scriptCt", "text": "@Str.script", "flex": "1", "layout": "fit", "minHeight": "15em", "padding": "0", "required": "true" }, "items": [ { "_icon": "edit", "text": "server_script", "cls": "Wb.CodeEditor", "properties": { "cid": "server_script", "minimap": "false", "required": "true" } } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "let type = app.interval_type;\napp.grid1.insertRecord(\n {\n url: xpath + '/add',\n failure(resp) {\n Wb.checkExists(resp, 'wb_job_job_name', app.job_name);\n }\n }, app.editWin);\nif (type.value == -1)\n type.value = 3;" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "app.grid1.editRecord(\n {\n url: xpath + '/edit',\n failure(resp) {\n Wb.checkExists(resp, 'wb_job_job_name', app.job_name);\n }\n }, app.editWin, 'job_name');" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'job_name');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "pauseBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "pauseBtn", "text": "@Str.pause", "icon": "pause" }, "events": { "click": "app.setStatus(false);" } }, { "_icon": "item", "text": "resumeBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "resumeBtn", "text": "@Str.resume", "icon": "resume" }, "events": { "click": "app.setStatus(true);" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" }, "_expanded": true }, { "_icon": "item", "text": "startStopBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "startStopBtn" }, "events": { "click": "Wb.confirm(Str.doConfirm.format(app.startStopBtn.text), f => {\n Wb.ajax({\n url: xpath + '/start-stop-task',\n params: { status: !app.isStartup },\n success() {\n app.isStartup = !app.isStartup;\n app.setStartStopBtn();\n app.grid1.reload();\n }\n });\n});", "ready": "app.setStartStopBtn();" } }, { "_icon": "divider", "text": "divider3", "cls": "Wb.Divider", "properties": { "cid": "divider3" }, "_expanded": true }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "job_name", "stateId": "wb.task", "keyFields": "sid,status" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "numCol", "rowNum": "true" }, "text": "numCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "nameCol", "fieldName": "job_name", "width": "15em", "text": "@Str.name", "render": "el.insertCellIcon(data.status ? (data.next_time ? 'play' : 'ok') : 'delete', value);" }, "text": "nameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "intervalCol", "fieldName": "interval_type", "width": "17em", "text": "@Str.interval", "render": "let intervalValue = data.interval_value, time = ' (' + data.trigger_time?.timeText + ')', weekday, month;\nswitch (value) {\n case 0:\n return Str.every + ' ' + intervalValue + ' ' + Str.s;\n case 1:\n return Str.every + ' ' + intervalValue + ' ' + Str.m;\n case 2:\n return Str.every + ' ' + intervalValue + ' ' + Str.h;\n case 3:\n return Str.every + ' \"' + Str.day + '\" ' + time;\n case 4:\n weekday = data.trigger_weekday;\n return Str.every + ' \"' + app.trigger_weekday.data.find(item => item.value == weekday).text + '\"' + time;\n case 5:\n return Str.every + ' \"' + Str.month + '\" ' + data.trigger_day + time;\n case 6:\n month = data.trigger_month;\n return Str.every + ' \"' + app.trigger_month.data.find(item => item.value == month).text + '\" ' + data.trigger_day + time;\n case 7:\n return data.cron_express;\n}", "align": "left" }, "text": "intervalCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "runTimeCol", "fieldName": "previous_date", "width": "17em", "text": "@Str.runTime", "render": "return Str.previous + Str.labelSeparator + (data.previous_time?.dateTimeText || '') + '\\n' +\n Str.next + Str.labelSeparator + (data.next_time?.dateTimeText || '');", "autoWrap": "pre", "sortable": "false" }, "text": "runTimeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "durationCol", "fieldName": "begin_date", "width": "17em", "text": "@Str.duration", "render": "return Str.from + Str.labelSeparator + (value?.dateTimeText || '') + '\\n' +\n Str.to + Str.labelSeparator + (data.end_date?.dateTimeText || '');", "autoWrap": "pre" }, "text": "durationCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "descCol", "fieldName": "job_desc", "width": "-1", "text": "@Str.desc", "sortable": "false" }, "text": "descCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # admin/user/add.xwl Title: add Description: Add user ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add user", "serverScript": "function main() {\n const UserUtil = Wb.UserUtil;\n const protectedText = UserUtil.protectedText;\n let sid = Params.user_id_disp || Wb.getId(), create_date = new Date(), login_times = 0;\n\n if (UserUtil.reservedName.includes(Params.user_name))\n Wb.raise(Str.cannotModify.format(Params.user_name));\n Wb.set({ sid, create_date, login_times, password: UserUtil.encryptPassword(Params.password) });\n Wb.sync({ tableName: 'wb_user', insert: Params });\n addRoles(sid);\n Wb.send({ sid, user_id_disp: sid, password: protectedText, confirm_password: protectedText, create_date, login_times });\n}\n/**\n * add user roles.\n * @param {String} user_id User id.\n */\nfunction addRoles(user_id) {\n let roles = Wb.getObject('roleBox'), insert = [];\n\n roles.forEach(role_id => insert.push({ sid: Wb.getId(), user_id, role_id }));\n Wb.sync({ tableName: 'wb_user_role', insert });\n}\nmain();" }, "_icon": "module" } # admin/user/del.xwl Title: del Description: Delete users ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete users", "serverScript": "function main() {\n const reservedName = Wb.UserUtil.reservedName;\n let del = Wb.getObject('del'), username;\n\n //Reserved accounts cannot be deleted\n del.forEach(item => (username = item.$user_name) && reservedName.includes(username) &&\n Wb.raise(Str.cannotDelete.format(username)));\n Wb.sync({ tableName: 'wb_user', del });\n Wb.sql({ sql: 'delete from wb_user_role where user_id={?$sid?}', params: del });\n //logout\n del.forEach(item => Sessions.invalidate(item.$sid));\n}\nmain();" }, "_icon": "module" } # admin/user/edit.xwl Title: edit Description: Edit user ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit user", "serverScript": "function main() {\n const Util = Wb.UserUtil;\n const protectedText = Util.protectedText;\n let password = Params.password, oldUserName = Params.$user_name, username = Params.user_name;\n\n if (username && Util.reservedName.includes(oldUserName))\n Wb.raise(Str.cannotModify.format(oldUserName));\n if (username && Util.reservedName.includes(username))\n Wb.raise(Str.cannotModify.format(username));\n if (password)\n Wb.set('password', Util.encryptPassword(password));\n Wb.sync({ tableName: 'wb_user', update: Params });\n updateRoles(Params.$sid);\n Wb.send({ password: protectedText, confirm_password: protectedText });\n}\n/**\n * Update user roles.\n * @param {String} user_id User id.\n */\nfunction updateRoles(user_id) {\n let roles = Wb.getObject('roleBox'), insert = [], oldUserid = Params.$sid;\n\n Wb.sql({ sql: 'delete from wb_user_role where user_id={?user_id?}', params: { user_id } });\n roles.forEach(role_id => insert.push({ sid: Wb.getId(), user_id, role_id }));\n Wb.sync({ tableName: 'wb_user_role', insert });\n if (Params.user_name || Params.status == '0') {\n //logout when changed\n Sessions.invalidate(oldUserid);\n } else {\n //Update the session role\n let sessions = Sessions.getSessions(oldUserid);\n if (sessions) {\n if (Config.getBool('sys.session.addDefaultRole'))\n roles.push('default');\n roles = roles.stringArray;\n sessions.forEach(session => session.setAttribute('sys.roles', roles));\n }\n }\n}\nmain();" }, "_icon": "module" } # admin/user/select-roles.xwl Title: select-roles Description: Select all roles and the specified user's roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select all roles and the specified user's roles", "serverScript": "function main() {\n let sourceRoles, destRoles;\n\n if (Params.userId) {\n sourceRoles = Wb.getAllRows(`select sid,role_name as text,remark as subtext from wb_role where sid<>'default' and status=1\n and sid not in (select role_id from wb_user_role where user_id={?userId?}) order by role_name`);\n destRoles = Wb.getAllRows(`select sid,role_name as text,remark as subtext from wb_role where sid<>'default' and status=1\n and sid in (select role_id from wb_user_role where user_id={?userId?}) order by role_name`);\n } else {\n sourceRoles = Wb.getAllRows(`select sid,role_name as text,remark as subtext from wb_role where sid<>'default' and status=1\n order by role_name`);\n }\n Wb.send({ sourceRoles, destRoles });\n}\nmain();" }, "_icon": "module" } # admin/user/select.xwl Title: select Description: Select users ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select users", "serverScript": "function main() {\n const protectedText = Wb.UserUtil.protectedText;\n let sql;\n\n sql = `select a.sid, a.user_name, a.display_name, '${protectedText}' as password, '${protectedText}' as confirm_password,\n a.email, a.mobile_phone, a.use_lang, b.sid as dept_id, b.dept_code as dept_code_hide, b.dept_name as dept_name_tree,\n a.login_times, a.create_date, a.last_login,a.status, a.sid as user_id_disp\n from wb_user a left join wb_dept b on a.dept_id=b.sid`;\n if (Params.search) {\n Wb.setLike('search');\n sql += ' where a.user_name like {?search?} or a.display_name like {?search?} or a.sid like {?search?}';\n }\n sql += Wb.getOrderSql({ dept_name_tree: 'b.dept_name', user_id_disp: 'a.sid', $: 'a' });\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # admin/user.xwl Title: User Management Description: User account management tool ```json { "title": "@userMng", "icon": "user2", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "User account management tool" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /** @property {Object} - The edit window configs object. */\n winConfigs: {\n tagName: 'form',\n layout: 'form1',\n height: '45em',\n width: '75em',\n autoScroll: true,\n manualShow: true,\n events: {\n ready() {\n let win = this, ct = new Wb.Container({ layout: 'grid2', padding: false, autoGrid: true });\n\n win.down('display_name').inputEl.autocomplete = 'off';\n win.el.autocomplete = 'off';\n ct.add(win.items.copy());\n win.add(ct);\n win.add({\n cid: 'roleBox', cname: 'dualBox', flex: 1, minHeight: '10em', url: xpath + '/select-roles',\n getValue() {\n return this.destData.pluck('sid');\n },\n sourceGridConfigs: {\n title: Str.availableRoles, tools: {\n icon: 'refresh', tip: Str.refresh, handler() {\n let roleBox = this.up('roleBox');\n app.loadRoles(data => {\n let excludeItems = roleBox.destGrid.items;\n\n roleBox.sourceData = data.sourceRoles.filter(item => !excludeItems.some(t => t.data.sid == item.sid))\n });\n }\n }\n }, destGridConfigs: { title: Str.selectedRoles }\n });\n },\n beforeok() {\n let win = this, pwd = win.down('password');\n //The two passwords are not the same\n if (pwd.value != win.down('confirm_password').value) {\n Wb.warn(Str.pwdNotSame, f => pwd.focus(false, true));\n return false;\n }\n }\n }\n },\n /**\n * Fires after insert or update fails.\n */\n onFailure(resp) {\n let checkFields = { wb_user_pk: 'user_id_disp', wb_user_user_name: 'user_name' };\n\n Wb.each(checkFields, (k, v) => {\n if (Wb.checkExists(resp, k, app.grid1.dictWin.down(v)))\n return false;\n });\n },\n /**\n * Load available roles.\n * @param {Function} success The callback function after success.\n * @param {Array} .items Available roles.\n * @param {String} [userId] User id for getting dest roles.\n */\n loadRoles(success, userId) {\n Wb.ajax({\n url: xpath + '/select-roles',\n json: true,\n params: { userId },\n success(data) {\n success?.(data);\n }\n });\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.loadRoles(data => {\n let win, roleBox;\n\n win = app.grid1.dictAdd({\n url: xpath + '/add',\n failure: app.onFailure\n }, Str.username, null, null, app.winConfigs);\n roleBox = win.down('roleBox');\n roleBox.sourceData = data.sourceRoles;\n roleBox.destData = [];\n win.show();\n win.down('user_id_disp').readonly = false;\n});" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let grid = app.grid1, data = grid.selectionData;\nif (!data) {\n Wb.tipSelect();\n return;\n}\napp.loadRoles(data => {\n let win, roleBox;\n win = grid.dictEdit({\n url: xpath + '/edit',\n failure: app.onFailure\n }, 'user_name', null, null, app.winConfigs);\n roleBox = win.down('roleBox');\n roleBox.sourceData = data.sourceRoles;\n roleBox.destData = data.destRoles;\n win.show();\n win.down('user_id_disp').readonly = true;\n}, data.sid);" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'user_name');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "user_name", "stateId": "wb.user", "keyFields": "sid,user_name" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" } } ] } ] } # dev/controls/save.xwl Title: save Description: Save control data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Save control data", "serverScript": "function main() {\n new Wb.File(true, 'wb/docs/groups.js').text = 'globalThis.WbControlsGroup=' + Wb.payload + ';';\n}\nmain();" }, "_icon": "module" } # dev/controls.xwl Title: Control Manager Description: Controls management tool ```json { "title": "@controlsMng", "icon": "container", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/docs/data.js\",\n \"wb/docs/groups.js\"\n]", "remark": "Controls management tool" }, "_icon": "module", "events": { "initialize": "/**\n * Controls manager.\n */\nWb.apply(app, {\n /**\n * Add new folder.\n */\n addFolder() {\n let tree = app.controlTree, node = tree.selection ?? tree.lastItem;\n\n Wb.prompt(Str.addFolder, { text: Str.name, cid: 'name', required: true }, (values, win) => {\n let text = values.name;\n\n if (text == 'Ungrouped') {\n Wb.tipWarn(Str.nameCannotBe.format(text));\n return;\n }\n node.parent.insertDataAfter({ text, items: [] }, node).select();\n app.modified();\n win.close();\n });\n },\n /**\n * Remove the selected nodes.\n */\n remove() {\n app.controlTree.delRecords();\n app.modified();\n },\n /**\n * Edit the selected node.\n */\n edit() {\n let node = app.controlTree.selection, text = node.text;\n\n Wb.prompt(Str.edit + ' - ' + text, { text: Str.name, cid: 'name', required: true, value: text },\n (values, win) => {\n node.proxy.text = values.name;\n app.modified();\n win.close();\n });\n },\n /**\n * Set modified status. @priv\n */\n modified() {\n app.saveBtn.disabled = false;\n },\n /**\n * Save current data.\n */\n save() {\n let allData = app.controlTree.data;\n Wb.cascade(allData, data => {\n data.sort = undefined;\n if (data.cls) {\n data.items = undefined;\n data._leaf = true;\n }\n });\n Wb.ajax({\n url: xpath + '/save',\n data: allData,\n success() {\n app.saveBtn.disabled = true;\n }\n });\n },\n /**\n * Load controls to the tree. @priv\n */\n loadControls() {\n let tree = app.controlTree, grouped = {}, ungrouped = [], data, cls;\n\n tree.data = WbControlsGroup;\n tree.cascade(node => {\n data = node.data;\n grouped[data.cls] = true;\n });\n Wb.each(WbDocsData, (k, v) => {\n cls = v.cls;\n if (v.icon && !grouped[cls] && cls != 'Wb.Module') {\n ungrouped.push({\n _icon: v.icon, text: v.cname, cls: k, _leaf: true,\n });\n }\n });\n tree.downBy(node => node.text == 'Ungrouped').addData(ungrouped);\n }\n});", "finalize": "app.loadControls();", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "_expanded": true, "tags": "", "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addFolderBtn", "cls": "Wb.Item", "properties": { "cid": "addFolderBtn", "text": "@Str.addFolder", "icon": "folder1", "handler": "app.addFolder", "keys": "Ctrl+E" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "properties": { "cid": "editBtn", "icon": "edit", "text": "@Str.edit", "handler": "app.edit", "disabled": "true", "keys": "Ctrl+J" }, "_expanded": true }, { "_icon": "item", "text": "removeBtn", "cls": "Wb.Item", "properties": { "cid": "removeBtn", "icon": "delete", "text": "@Str.del", "handler": "app.remove", "disabled": "true", "keys": "Ctrl+D" }, "_expanded": true }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_leaf": true, "items": [], "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "properties": { "cid": "saveBtn", "text": "@Str.save", "icon": "save", "handler": "app.save", "disabled": "true", "keys": "Ctrl+S" } } ] }, { "_icon": "tree-view", "text": "controlTree", "cls": "Wb.Tree", "properties": { "cid": "controlTree", "draggable": "true", "droppable": "wb.controls", "multiSelect": "true", "keyWalking": "true" }, "_expanded": true, "events": { "itemdrop": "app.modified();", "selectionchange": "let nodes = this.selections, node = nodes[0];\napp.editBtn.disabled = nodes.length != 1 || node.leaf || node.text == 'Ungrouped';\napp.removeBtn.disabled = !nodes.length;" } } ] } ] } # dev/dict/add.xwl Title: add Description: Add dictionary item ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add dictionary item", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let rec = { sid: Wb.getId() };\n\n Util.checkDuplicate(Params.name, Params.group_name);\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_dict', insert: Params });\n Util.updateBuffer();\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # dev/dict/del.xwl Title: del Description: Delete dictionary items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete dictionary items", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let del = Wb.getObject('del'), rows = Wb.getAllRows('select name,alias,group_name from wb_dict where ' +\n Wb.Query.make('sid', del.pluck('$sid')));\n\n Wb.sync({ tableName: 'wb_dict', del });\n Util.clearBuffer(rows);\n}\nmain();" }, "_icon": "module" } # dev/dict/edit.xwl Title: edit Description: Edit dictionary item ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let rows = Wb.getAllRows('select name,alias,group_name from wb_dict where sid={?$sid?}');\n\n Util.checkDuplicate(Params.name ?? Params.oldName, Params.group_name ?? Params.oldGroup, Params.$sid);\n Wb.sync({ tableName: 'wb_dict', update: Params });\n Util.clearBuffer(rows);\n Util.updateBuffer(true);\n}\nmain();", "remark": "Edit dictionary item" }, "_icon": "module" } # dev/dict/select.xwl Title: select Description: Select dictionary items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select dictionary items", "serverScript": "function main() {\n let sql = 'select * from wb_dict', where = [];\n\n if (Params.search) {\n Wb.setLike('search');\n where.push(`(name like {?search?} or alias like {?search?} or title like {?search?})`);\n }\n if (Params.searchGroup) {\n Wb.setLike('searchGroup');\n where.push(`group_name like {?searchGroup?}`);\n }\n if (Params.searchContent) {\n Wb.setLike('searchContent');\n where.push(`(validate_script like {?searchContent?} or edit_tags like {?searchContent?}\n or render_script like {?searchContent?} or column_tags like {?searchContent?})`);\n }\n if (where.length) {\n sql += ' where ' + where.join(' and ');\n }\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # dev/dict.xwl Title: Dictionary Config Description: Dictionary configuration utility ```json { "title": "@dictConfig", "icon": "dict", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/js/monaco.js\"\n]", "remark": "Dictionary configuration utility" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Load grid with search controls.\n */\n load() {\n app.grid1.delayLoad({ comps: app.viewport1.tbar });\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.dictAdd(xpath + '/add', Str.dictConfig);" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let data = app.grid1.selection?.data;\napp.grid1.dictEdit(xpath + '/edit', 'name', { oldName: data?.name, oldGroup: data?.group_name });" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'name');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.name", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.load();" } }, { "_icon": "text", "text": "searchGroup", "cls": "Wb.Text", "properties": { "cid": "searchGroup", "clearButton": "true", "placeholder": "@Str.groupName", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.load();" } }, { "_icon": "text", "text": "searchContent", "cls": "Wb.Text", "properties": { "cid": "searchContent", "clearButton": "true", "placeholder": "@Str.content", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.load();" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "name", "keyWalking": "name", "keyFields": "sid" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" } } ] } ] } # dev/docs.xwl Title: Documents Description: Documents reader ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "['wb/docs/wb-docs.css', 'wb/docs/data.js', 'wb/js/monaco.js', 'wb/docs/wb-docs.js']", "remark": "Documents reader" }, "events": { "initialize": "Wb.docs.App.initDocs(app);" }, "_icon": "module", "title": "@docs", "icon": "book1", "img": "", "hideInMenu": "false" } # dev/ide/actions.xwl Title: actions Description: IDE server side actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "IDE server side actions", "serverScript": "Wb.load('./ide-ss.js');\nlet actions = {\n /**\n * Create query modules.\n */\n createQuery() {\n let generator = new Wb.ide.Generator(Params);\n\n generator.buildQuery();\n },\n /**\n * Create crud modules.\n */\n createCRUD() {\n let generator = new Wb.ide.Generator(Params);\n\n generator.buildCRUD();\n },\n /**\n * Create source data.\n */\n createSource() {\n let generator = new Wb.ide.Generator(Params), modulePath = Params.modulePath, params = Params.params;\n\n if (modulePath) {\n params &&= Wb.parse(params);\n Wb.invoke(new Wb.File(modulePath).modulePath, params);\n } else {\n Wb.send(generator.getSourceData());\n }\n },\n /**\n * Provide JS completion.\n */\n jsProvider() {\n const predefinedCls = ['com', 'edu', 'java', 'javax', 'javafx', 'org', 'jakarta'];\n let result, searcher, isPack;\n\n try {\n let cls = Params.cls;\n if ((cls + '.').startsWith('Packages.')) {\n cls = cls.substr(9);\n isPack = true;\n } else if (cls.startsWith('Classes.'))\n cls = Classes[cls.substr(8)].class.getName();\n else if (!cls.includes('.') && Java.isJavaObject(globalThis[cls]))\n cls = globalThis[cls].class.getName()\n searcher = new Wb.ide.ClassSearcher(cls);\n if (!Java.isJavaObject(Wb.getNS(cls)) && !isPack && !predefinedCls.includes(cls.firstItem('.')))\n result = searcher.getJSMembers(cls)\n else\n result = searcher.getJavaMembers(cls) || searcher.getClassMembers(cls + '.');\n } catch (e) {\n result = [];\n }\n Wb.send(result);\n },\n /**\n * Get all threads.\n */\n getThreads() {\n const Thread = Java.type(\"java.lang.Thread\");\n const Threads = Java.type(\"java.lang.Thread[]\");\n let threads = [], thread, rootGroup, threadArray, i, actualSize, stackTraceToString, sorter;\n\n stackTraceToString = stackTrace => {\n if (!stackTrace?.length)\n return '';\n let str = [], i, j, frame;\n j = stackTrace.length;\n for (i = 0; i < j; i++) {\n frame = stackTrace[i];\n str.push(` at ${frame.getClassName()}.${frame.getMethodName()}` +\n `(${frame.getFileName() || 'Unknown'}:${frame.getLineNumber() >= 0 ? frame.getLineNumber() : '?'})`);\n }\n return str.join('\\n');\n };\n rootGroup = Thread.currentThread().getThreadGroup();\n while (rootGroup.getParent()) {\n rootGroup = rootGroup.getParent();\n }\n threadArray = new Threads(rootGroup.activeCount() * 3);\n actualSize = rootGroup.enumerate(threadArray, true);\n for (i = 0; i < actualSize; i++) {\n thread = threadArray[i];\n threads.push({\n name: thread.getName(), id: thread.getId(), state: thread.getState().toString(), priority: thread.getPriority(),\n daemon: thread.isDaemon(), groupName: thread.getThreadGroup()?.getName(), live: thread.isAlive(),\n stack: stackTraceToString(thread.getStackTrace())\n });\n }\n sorter = Wb.getObject('_sort')?.[0];\n if (sorter) {\n threads.mixSort(sorter.name, sorter.desc);\n }\n Wb.send({\n items: threads, columns: [\n { rowNum: true },\n { fieldName: 'name', text: 'Name', width: '-1', minWidth: '10em', maxWidth: '25em' },\n { fieldName: 'id', text: 'ID', width: '4em' },\n { fieldName: 'state', text: 'State' },\n { fieldName: 'priority', text: 'Priority', width: '6em' },\n { fieldName: 'daemon', text: 'Daemon', width: '6em' },\n { fieldName: 'live', text: 'Live', width: '5em' },\n { fieldName: 'groupName', text: 'Group Name', width: '-1', minWidth: '10em', maxWidth: '25em' }\n\n ]\n });\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # dev/ide/checkin.xwl Title: checkin Description: Check in files to the database ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Check in files to the database", "serverScript": "function main() {\n let file, files = Wb.getObject('files');\n\n Wb.startTrans();\n files.forEach(name => {\n file = new Wb.File(name);\n if (file.isFile) {\n importFile(file)\n } else {\n file.cascade(file => { file.isFile && importFile(file) });\n }\n })\n}\n\n/**\n * Import file to the database. @priv\n * @param {Wb.File} file Import file object.\n */\nfunction importFile(file) {\n let params = {\n sid: Wb.getId(), sdate: new Date(), file_path: file.relPath, file_version: Params.version,\n version_remark: Params.remark, modify_date: file.lastModifiedDate, file_content: file.bytes\n };\n\n Wb.sql({\n sql: 'delete from wb_version where file_path={?file_path?} and file_version={?file_version?}',\n params\n });\n Wb.sql({\n sql:\n `insert into wb_version values({?sid?}, {?sdate?}, {?file_path?}, {?file_version?}, {?version_remark?},\n {?modify_date?}, {?file_content?})`,\n params\n });\n}\nmain();" }, "_icon": "module" } # dev/ide/compress.xwl Title: compress Description: Compress and protect source code ```json { "title": "", "icon": "", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Compress files.\n */\nWb.checkDemo();\nconst buildDate = new Date().textValue, cssConfigs = { restructure: false },\n obfsConfigs = {\n compact: true,\n controlFlowFlattening: false,\n deadCodeInjection: false,\n debugProtection: false,\n debugProtectionInterval: 0,\n disableConsoleOutput: false,\n identifierNamesGenerator: 'hexadecimal',\n log: false,\n numbersToExpressions: false,\n renameGlobals: false,\n selfDefending: false,\n simplify: true,\n splitStrings: false,\n stringArray: true,\n stringArrayCallsTransform: false,\n stringArrayCallsTransformThreshold: 0.5,\n stringArrayEncoding: [],\n stringArrayIndexShift: true,\n stringArrayRotate: true,\n stringArrayShuffle: true,\n stringArrayWrappersCount: 1,\n stringArrayWrappersChainedCalls: true,\n stringArrayWrappersParametersMaxCount: 2,\n stringArrayWrappersType: 'variable',\n stringArrayThreshold: 0.75,\n unicodeEscapeSequence: false\n },\n jsConfigs = { compress: false, keep_fnames: true, mangle: true, parse: { bare_returns: true } };\nlet forceObfuscate = Wb.getConfig('sys.app.obfuscate'), client = Params.client;\n/**\n * Compress script\n */\nfunction compress() {\n const copyrightFiles = ['wb', 'wb-client', 'wb-server', 'wb-docs', 'ide'];\n let filename, script, minFile, isJs, isMjs, isCss, isXwl, path, object, module, text, obfuscate, modulePath,\n libPath = new Wb.File(true, 'wb/libs').path, doCompress, rebuild = Wb.getBool('rebuild');\n\n if (forceObfuscate == 'null')\n forceObfuscate = null;\n else\n forceObfuscate = Wb.parseBool(forceObfuscate);\n doCompress = file => {\n path = file.path;\n if (file.isFolder)\n return;\n if (path.startsWith(libPath))\n return;\n path = path.substr(Base.pathLen);\n if (path == 'wb/docs/data.js')\n return;\n filename = file.name;\n isJs = filename.endsWith('.js') && !filename.endsWith('.min.js');\n isMjs = filename.endsWith('.mjs') && !filename.endsWith('.min.mjs');\n isCss = filename.endsWith('.css') && !filename.endsWith('.min.css');\n isXwl = filename.endsWith('.xwl') && !filename.endsWith('.min.xwl');\n if (isJs || isMjs || isCss || isXwl) {\n if (isJs)\n filename = filename.slice(0, -3) + '.min.js';\n else if (isMjs)\n filename = filename.slice(0, -4) + '.min.mjs';\n else if (isCss)\n filename = filename.slice(0, -4) + '.min.css';\n else\n filename = filename.slice(0, -4) + '.min.xwl';\n minFile = new Wb.File(file.parent, filename);\n if (rebuild || file.lastModified > minFile.lastModified) {\n notify(Str.compress + ' ' + path + '...');\n try {\n if (isJs || isMjs) {\n text = file.text;\n text = compressJs(text, text.includes('/* obfuscate */'));\n if (copyrightFiles.some(name => name + '.min.js' == filename))\n text = '/*\\n * WebBuilder Javascript Library\\n * Copyright (c) Geejing, ' +\n 'All Rights Reserved.\\n * https://www.geejing.com\\n * Build Date: ' + buildDate + '\\n */\\n' + text;\n minFile.text = text;\n } else if (isCss) {\n if (!globalThis.csso)\n Wb.load('wb/libs/csso.js');\n minFile.text = csso.minify(file.text, cssConfigs).css;\n } else {\n modulePath = file.modulePath;\n if (modulePath) {\n object = file.object;\n module = Xwl.get(modulePath);\n obfuscate = object.properties.obfuscate == 'true';\n script = module.clientScript;\n object.properties.links = mergeLinks(object.properties.links, module.libList.toString());\n if (script)\n object.events = { initialize: compressJs(script, obfuscate) };\n script = object.properties.serverScript;\n if (script)\n object.properties.serverScript = compressJs(script, obfuscate);\n if (module.hasStateData)\n object.stateMap = toJSType(module.stateMap);\n if (module.hasModuleBind)\n object.moduleMap = toJSType(module.moduleMap);\n if (module.hasXwl)\n object.xwlMap = toJSType(module.xwlMap);\n delete object.items;\n minFile.object = object;\n }\n }\n } catch (e) {\n notify(Str.loadFailed.format(path) + '\\n' + e?.toString(), true);\n Wb.sleep(500);\n }\n }\n }\n };\n Wb.File.appFolder.cascadeSelf(doCompress);\n}\n\n/**\n * Convert HashSet, HashMap to it's JS types.\n */\nfunction toJSType(data) {\n const XwlData = Java.type('com.wb.tool.XwlData');\n let result = {};\n\n data.forEach((k, v) => {\n if (v instanceof XwlData)\n v = Wb.applyValue({}, v);\n result[k] = v;\n });\n return result;\n}\n/**\n * Merge links @priv\n * @param {Array} links1 links 1\n * @param {Array} links2 links 2\n * @return {Array} The merged links\n */\nfunction mergeLinks(links1, links2) {\n let links = [], urls = [], url;\n\n try {\n links1 = links1 ? Wb.parse(links1) : [];\n } catch (e) {\n links1 = [];\n }\n try {\n links2 = links2 ? Wb.parse(links2) : [];\n } catch (e) {\n links2 = [];\n }\n links1.pushAll(links2);\n links1.forEach(object => {\n if (Wb.isString(object))\n url = object;\n else\n url = object.url;\n if (!urls.includes(url)) {\n urls.push(url);\n links.push(object);\n }\n });\n if (links.length > 0)\n return Wb.encode(links);\n else\n return undefined;\n}\n/**\n * Notify progress\n * @param {String} text message\n * @param {Boolean} failed whether to send failed flag\n */\nfunction notify(text, failed) {\n let data = { client, text, type: 'notifyProgress' };\n\n if (text !== true)\n Wb.info(text);\n if (failed)\n data.failed = 1;\n Wb.send(data, '$ide');\n}\n/**\n * Compress script @priv\n * @param {String} script Script content\n * @param {Boolean} [obfuscate] whether to obfuscate\n * @return {String} compressed script\n */\nfunction compressJs(script, obfuscate) {\n if (forceObfuscate != null)\n obfuscate = forceObfuscate;\n if (obfuscate) {\n if (!globalThis.JavaScriptObfuscator)\n Wb.load('wb/libs/obfuscator.js');\n return JavaScriptObfuscator.obfuscate(script, obfsConfigs).getObfuscatedCode();\n } else {\n if (!globalThis.Terser)\n Wb.load('wb/libs/terser.js');\n return Terser.minify(script, jsConfigs).code;\n }\n}\ntry {\n compress();\n} finally {\n if (!Wb.getBool('finalUnmask'))\n notify(true);\n}", "remark": "Compress and protect source code" }, "_icon": "module" } # dev/ide/create-docs.xwl Title: create-docs Description: Create documents from the files ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\n/** @property {DocsCreator} creator Docs creator. @priv */\n/** @property {Number} index Manual docs segment index. @priv */\nlet creator, index = 1;\nfunction main() {\n Wb.load('./ide-ss.js');\n const DocsCreator = Wb.ide.DocsCreator;\n creator = new DocsCreator();\n processFile(new Wb.File(Wb.File.wbFolder, 'js/wb.js'));\n processFile(new Wb.File(Wb.File.wbFolder, 'js/wb-client.js'));\n ['js', 'ss', 'modules', 'docs'].forEach(folderName => {\n new Wb.File(Wb.File.wbFolder, folderName).cascade(file => {\n if (file.path.endsWith('/wb/js/wb.js') || file.path.endsWith('/wb/js/wb-client.js'))\n return;\n processFile(file);\n }, true, false, true);\n });\n creator.build();\n}\n/**\n * Create API docs @priv\n * @param {Wb.File} file doc file.\n */\nfunction processFile(file) {\n let script, clsName, object, name = file.name, relPath, pos;\n switch (file.extension) {\n case 'js':\n case 'mjs':\n if (name.endsWith('.min.js') || name.endsWith('.min.mjs'))\n return;\n script = file.text;\n if (script.includes('/**')) {\n relPath = file.relPath;\n clsName = relPath.replaceAll('/', '.');\n if (relPath.startsWith('wb/modules'))\n clsName = 'Modules.' + clsName.substr(11).beforeItem('.');\n else\n clsName = clsName.beforeItem('.').capital;\n script = script.replaceAll('@class $path', '@class ' + clsName);\n creator.addScript(script, file.relPath);\n }\n break;\n case 'xwl':\n if (name.endsWith('.min.xwl'))\n return;\n clsName = file.relPath.replaceAll('/', '.');\n //Get xxx of wb.module.xxx.xwl\n clsName = clsName.substr(11).beforeItem('.');\n object = file.object;\n //serverScript\n script = object.properties.serverScript;\n if (script?.includes('/**')) {\n script = script.replaceAll('@class $path', '@class Modules.' + clsName + '#server')\n creator.addScript(script, file.relPath);\n }\n //clientScript\n script = extractXwlClient(object);\n if (script) {\n script = script.replaceAll('@class $path', '@class Modules.' + clsName + '#client')\n creator.addScript(script, file.relPath);\n }\n break;\n case 'wd':\n (\"\\n\" + file.text).split('\\n##').forEach((item, i) => {\n if (i > 0) {\n pos = item.indexOf('\\n');\n creator.addDoc({ cls: item.substr(0, pos), index: index++, title: item.substr(pos + 1) });\n }\n });\n break;\n }\n}\n/**\n * Extract xwl script @priv\n * @param {Object} object Module file object.\n */\nfunction extractXwlClient(object) {\n let result = object.events?.initialize ?? '';\n Wb.cascade([object], item => {\n Wb.each(item.properties, (k, v) => {\n if ((item != object || k != 'serverScript') && v.includes('/**')) {\n if (result)\n result += '\\n';\n result += v;\n }\n });\n Wb.each(item.events, (k, v) => {\n if ((item != object || k != 'initialize') && v.includes('/**')) {\n if (result)\n result += '\\n';\n result += v;\n }\n });\n });\n return result;\n}\nmain();", "remark": "Create documents from the files" }, "_icon": "module", "title": "" } # dev/ide/create-release.xwl Title: create-release Description: Create release version ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Create release application\n */\nlet client = Params.client, path = Params.path, releaseFolder, wbFolder;\nWb.apply(app, {\n /**\n * Start build\n */\n build() {\n let appName = 'wb';\n\n if (path.startsWith('.'))\n releaseFolder = new Wb.File(true, path);\n else\n releaseFolder = new Wb.File(path);\n wbFolder = new Wb.File(releaseFolder, 'meta/apache-tomcat/webapps/webbuilder');\n app.notify('Copy app folder to release folder...');\n try {\n app.clearDb();\n Wb.sleep(1000);\n FileUtils.copyDirectory(Base.path, wbFolder.file);\n app.packJar();\n app.removeFiles();\n // app.protectObfuscateFile();\n // app.protectFiles();\n if (Wb.getBool('createOfficialVersion')) {\n FileUtils.copyFile(new Wb.File(releaseFolder, 'meta/license.txt').file,\n new Wb.File(wbFolder.file, 'wb/system/license.txt').file);\n app.clearUrls();\n app.setDbSource('official');\n app.setVars('Enterprise', 'admin/cms/cms/view.xwl', true, false, null, true);\n app.pack(appName + '-official', false, true);\n new Wb.File(wbFolder.file, 'wb/system/license.txt').remove();\n }\n FileUtils.deleteDirectory(new File(wbFolder.file, 'wb/modules/sys/service/site'));\n FileUtils.deleteDirectory(new File(wbFolder.file, 'wb/modules/admin/cms'));\n new Wb.File(wbFolder.file, 'wb/js/cms.js').remove();\n new Wb.File(wbFolder.file, 'wb/js/cms.min.js').remove();\n app.clearUrls();\n if (Wb.getBool('createNormalVersion')) {\n app.setDbSource('system');\n app.setVars('Enterprise', 'sys/portal/index.xwl', false, true);\n app.pack(appName + '-ent');\n }\n if (Wb.getBool('allNormalVersion')) {\n app.setDbSource('system');\n app.setVars('Enterprise', 'sys/portal/index.xwl', false, true);\n app.pack(appName + '-ent', true);\n }\n // app.removeNoneEntFiles();\n // app.protectUnentFiles();\n if (Wb.getBool('createDemoVersion')) {\n FileUtils.copyFile(new Wb.File(releaseFolder, 'meta/license.txt').file,\n new Wb.File(wbFolder.file, 'wb/system/license.txt').file);\n app.setDbSource('demo');\n app.setVars('Demo', 'sys/portal/index.xwl', true, false, true);\n app.pack(appName + '-demo', false, true);\n new Wb.File(wbFolder.file, 'wb/system/license.txt').remove();\n }\n if (Wb.getBool('createTrialVersion')) {\n app.setDbSource('system');\n app.setVars('Enterprise', 'sys/portal/index.xwl', false, true);\n app.pack(appName + '-trial');\n }\n if (Wb.getBool('allTrialVersion')) {\n app.setDbSource('system');\n app.setVars('Enterprise', 'sys/portal/index.xwl', false, true);\n app.pack(appName + '-trial', true);\n }\n } finally {\n app.restoreDb();\n app.notify('Clear release folder...');\n if (wbFolder.exists)\n wbFolder.remove();\n }\n },\n /**\n * Clear invalid url shortcuts.\n */\n clearUrls() {\n let file = new Wb.File(true, 'wb/system/url.json'), object = file.object;\n Wb.each(object, (k, v) => {\n if (v && !(new File(wbFolder.file, 'wb/modules/' + v).exists())) {\n object[k] = undefined;\n }\n });\n new Wb.File(wbFolder.file, 'wb/system/url.json').text = Wb.encodePretty(object);\n },\n /**\n * Notify current progress.\n * @param {String} text message\n */\n notify(text) {\n Wb.info(text);\n Wb.send({ client, text, type: 'notifyProgress' }, '$ide');\n },\n //Protect obfuscate files\n protectObfuscateFile() {\n let filename, isJs, isMjs, isXwl, isCss, text, minFile, modulePath, obfuscate, folderLen;\n app.notify('Protect all obfuscate files...');\n folderLen = wbFolder.path.length + 12;\n wbFolder.cascade(file => {\n if (!file.isFile)\n return;\n filename = file.name;\n isJs = filename.endsWith('.js') && !filename.endsWith('.min.js');\n isMjs = filename.endsWith('.mjs') && !filename.endsWith('.min.mjs');\n isXwl = filename.endsWith('.xwl') && !filename.endsWith('.min.xwl');\n isCss = filename.endsWith('.css') && !filename.endsWith('.min.css');\n if (isJs || isMjs || isXwl || isCss) {\n if (isXwl) {\n modulePath = file.path.substr(folderLen);\n obfuscate = modulePath ? Xwl.get(modulePath)?.obfuscate : false;\n } else {\n text = file.text;\n obfuscate = text.includes('/* obfuscate */');\n }\n if (obfuscate) {\n minFile = file.minFile;\n if (minFile.exists)\n FileUtils.copyFile(minFile.file, file.file);\n }\n }\n });\n },\n //Protect all version files\n protectFiles() {\n let files = ['wb/js/wb.js'];\n\n if (!Wb.getBool('source'))\n files.pushAll([\n 'wb/js/ide.js',\n 'wb/ss/wb-server.js'\n ]);\n files.forEach(file => {\n file = new Wb.File(wbFolder, file);\n FileUtils.copyFile(file.minFile.file, file.file);\n });\n },\n //Protect un-enterprise version files\n protectUnentFiles() {\n let files = [\n 'wb/docs/wb-docs.css',\n 'wb/docs/wb-docs.js',\n 'wb/css/iconfont.css',\n 'wb/css/dark-wb.css',\n 'wb/css/red-wb.css',\n 'wb/css/classic-wb.css',\n 'wb/js/monaco.js',\n 'wb/ss/dbe.mjs'\n ];\n files.forEach(file => {\n file = new Wb.File(wbFolder, file);\n FileUtils.copyFile(file.minFile.file, file.file);\n });\n },\n //Set data source\n setDbSource(name) {\n let file = new Wb.File(wbFolder, 'wb/system/db/source.json'), object = file.object;\n app.systemSource ??= object.system;\n app.demoSource ??= object.demo;\n app.officialSource ??= object.official;\n app.officialAdminSource ??= object['official-admin'];\n if (name == 'official')\n file.text = Wb.encodePretty({ system: app[name + 'Source'], derby: app.systemSource, demo: app.officialAdminSource });\n else\n file.text = Wb.encodePretty({ system: app[name + 'Source'] });\n },\n //Remove non-essential files\n removeFiles() {\n // let cssFolder = new Wb.File(wbFolder, 'wb/css'), name;\n let minFile;\n // const files = [\n // 'wb/system/license.txt',\n // 'wb/modules/dev/ide/create-release.xwl',\n // 'wb/modules/dev/ide/create-docs.xwl',\n // 'wb/docs/help.wd',\n // 'wb/modules/sys/backup',\n // 'WEB-INF/classes'\n // ];\n const files = [\n 'wb/system/license.txt',\n 'wb/modules/dev/ide/create-release.xwl',\n 'wb/modules/sys/backup',\n 'WEB-INF/classes'\n ];\n app.notify('Removing all unnecessary files...');\n app.removeRootFiles();\n files.forEach(file => {\n file = new Wb.File(wbFolder, file);\n file.remove();\n minFile = file.minFile;\n if (minFile?.exists)\n minFile.remove();\n });\n // cssFolder.cascade(file => {\n // name = file.name;\n // if (!name.endsWith('.css') || name == 'wb-tpl.css' || name == 'wb-tpl.min.css')\n // file.remove();\n // });\n },\n //Remove none-ent files\n removeNoneEntFiles() {\n const files = [\n 'wb/modules/dev/ide/compress.xwl',\n 'wb/libs/csso.js',\n 'wb/libs/obfuscator.js',\n 'wb/libs/terser.js'\n ];\n let minFile;\n files.forEach(file => {\n file = new Wb.File(wbFolder, file);\n file.remove();\n minFile = file.minFile;\n if (minFile?.exists)\n minFile.remove();\n });\n },\n //Remove root modules\n removeRootFiles() {\n let object, items, indexFile = new Wb.File(wbFolder, 'wb/modules/index.json');\n new Wb.File(wbFolder, 'wb/modules').each(file => {\n if (file.isFile && file.name != 'index.json')\n file.remove();\n });\n object = indexFile.object;\n items = object.items;\n items.each((k, i) => {\n if (k.endsWith('.xwl'))\n items.erase(i);\n }, true, true);\n indexFile.object = object;\n },\n /**\n * Pack webbuilder jar\n */\n packJar() {\n let wbPath = wbFolder.file, jarFile = new File(wbPath, 'WEB-INF/lib/webbuilder-' +\n Wb.getConfig('sys.app.version') + '.jar'), metaInf = new File(wbPath, 'WEB-INF/classes/META-INF');\n\n app.notify('Packing WebBuilder Jar file..');\n FileUtils.copyDirectory(new File(releaseFolder.file, 'meta/META-INF'), metaInf);\n ZipUtil.zip([new File(wbPath, 'WEB-INF/classes/com'), metaInf], jarFile);\n },\n /**\n * Restore db data\n */\n restoreDb() {\n Wb.startTrans('system');\n Wb.each(app.saveTables, (tableName, insert) => {\n Wb.sql('delete from ' + tableName, 'system');\n Wb.sync({ tableName, db: 'system', insert });\n });\n Wb.commit('system');\n },\n /**\n * Clear db data\n */\n clearDb() {\n let sysdate = new Date(), rows, params = [], i, s,\n tableNames = ['wb_perm', 'wb_debug_files', 'wb_user', 'wb_user_role', 'wb_value', 'wb_resource',\n 'wb_reimburse', 'wb_ra_opinions', 'wb_flow', 'wb_flow_user', 'wb_leave', 'wb_version'];\n Wb.set({ sysdate });\n for (i = 0; i <= 10; i++) {\n try {\n if (i == 10)\n s = '';\n else\n s = String(i);\n Wb.sql('drop table test' + s, 'system');\n } catch (e) {\n Wb.rollback('system');\n //ignore\n }\n }\n //Clear invalid perms\n rows = Wb.getAllRows('select module_path from wb_perm', 'system');\n rows.forEach(row => {\n let path = row.module_path;\n if (!path.includes('/') || !new Wb.File(true, 'wb/modules/' + path + '.xwl').exists)\n params.push(row);\n });\n app.saveTables = {};\n tableNames.forEach(table => {\n app.saveTables[table] = Wb.getAllRows({ sql: 'select * from ' + table, db: 'system', blob: true });\n });\n Wb.sql({ sql: 'delete from wb_perm where module_path={?module_path?}', db: 'system', params });\n Wb.sql('truncate table wb_debug_files', 'system');\n Wb.sql('truncate table wb_reimburse', 'system');\n Wb.sql('truncate table wb_ra_opinions', 'system');\n Wb.sql('truncate table wb_flow', 'system');\n Wb.sql('truncate table wb_flow_user', 'system');\n Wb.sql('truncate table wb_leave', 'system');\n Wb.sql('truncate table wb_version', 'system');\n Wb.sql('truncate table wb_log', 'system');\n Wb.sql(`truncate table wb_value`, 'system');\n Wb.sql(`delete from wb_user where sid<>'admin' and sid<>'demo1' and sid<>'demo2' and sid<>'demo3' and sid<>'default'`, 'system');\n Wb.sql(`update wb_user set create_date={?sysdate?},login_times=0,last_login=null`, 'system');\n Wb.sql(`delete from wb_user_role where user_id<>'admin' and user_id<>'demo1' and user_id<>'demo2' and user_id<>'demo3' and user_id<>'default'`, 'system');\n Wb.sql(`delete from wb_resource where sid<>'admin@desktop'`, 'system');\n Wb.commit('system');\n },\n /**\n * Set config items\n */\n setVars(type, index, optimal, closeDerby, disableLog, officeVer) {\n let file = new Wb.File(wbFolder, 'wb/system/config.json'), object;\n const resetConfigs = {\n 'sys.theme': 'classic',\n 'sys.db.defaultSource': 'system',\n 'sys.app.date': new Date().textValue,\n 'sys.index': 'sys/portal/index.xwl',\n 'sys.app.releasePath': '../release',\n 'sys.file.syncPath': '',\n 'sys.db.closeDerby': !!closeDerby,\n 'sys.optimal': optimal,\n 'sys.app.type': type,\n 'sys.logEnabled': !disableLog,\n 'sys.file.blockedIPs': officeVer ? 'site/ips.txt' : 'wb/system/ips.txt',\n 'sys.file.allowedHeaders': officeVer ? 'site/headers.txt' : 'wb/system/headers.txt',\n 'sys.index': index\n };\n object = file.object;\n Wb.each(resetConfigs, (k, v) => {\n object[k].value = v;\n });\n file.text = Wb.encodePretty(object);\n },\n /**\n * Pack zip file\n * @param {String} filename zip filename\n * @param {Boolean} containAll whether contains jre and tomcat\n * @param {Boolean} onlyWbJar whether pack wb jar files only\n */\n pack(filename, containAll, onlyWbJar) {\n let suffix, metaFile = new File(releaseFolder.file, 'meta');\n // sourceFolder = new File(Base.path.getParentFile(), 'src')\n suffix = '-' + Wb.format(new Date(), 'y-MM-dd') + '.zip';\n app.notify('Packing ' + filename + '...');\n if (containAll) {\n wbFolder.name = 'ROOT';\n ZipUtil.zip([\n new File(metaFile, 'apache-tomcat'),\n new File(metaFile, 'java-win64'),\n new File(metaFile, 'web-page.bat'),\n new File(metaFile, 'readme.html'),\n new File(metaFile, 'startup-tomcat.bat')\n //,sourceFolder\n ], new File(releaseFolder.file, filename + '-win64' + suffix));\n ZipUtil.zip([\n new File(metaFile, 'apache-tomcat'),\n new File(metaFile, 'java-linux64'),\n new File(metaFile, 'web-page.txt'),\n new File(metaFile, 'readme.txt'),\n new File(metaFile, 'startup-tomcat.sh')\n //,sourceFolder\n ], new File(releaseFolder.file, filename + '-linux64' + suffix));\n } else {\n wbFolder.name = 'webbuilder';\n if (onlyWbJar) {\n let wbPath = wbFolder.file, tempFolder = new Wb.File(wbFolder.parent, 'temp/webbuilder'), tempLib;\n tempLib = new Wb.File(tempFolder, 'WEB-INF/lib');\n FileUtils.copyDirectoryToDirectory(new File(wbPath, 'wb'), tempFolder.file);\n FileUtils.copyFileToDirectory(new File(wbPath, 'WEB-INF/lib/webbuilder-' + Wb.getConfig('sys.app.version') + '.jar'), tempLib.file);\n ZipUtil.zip([\n tempFolder.file,\n new File(metaFile, 'single-wb/readme.html')\n //,sourceFolder\n ], new File(releaseFolder.file, filename + suffix));\n new Wb.File(tempFolder.parent).remove();\n } else {\n ZipUtil.zip([\n wbFolder.file,\n new File(metaFile, 'single-wb/readme.html')\n //,sourceFolder\n ], new File(releaseFolder.file, filename + suffix));\n }\n }\n }\n});\n//Start build\nWb.setConfig('sys.app.releasePath', path);\nlet lock = new Wb.Lock('wb.createRelease');\ntry {\n //compile css\n app.notify('Compile css...');\n Wb.run('dev/ide/create-wb-css');\n //compile docs\n app.notify('Compile docs...');\n Wb.run('dev/ide/create-docs');\n //compress script\n Wb.run('dev/ide/compress', { finalUnmask: true });\n app.build();\n} finally {\n lock.unlock();\n app.notify(true);\n}", "remark": "Create release version" }, "_icon": "module", "title": "" } # dev/ide/create-wb-css.xwl Title: create-wb-css Description: Create css theme files ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let files = new Wb.File(true, 'wb/css').items,\n cssTpl = new Wb.File(true, 'wb/css/wb-tpl.css').text,\n name, colorData;\n\n proccessIconFont();\n colorData = new Wb.File(true, 'wb/css/icon-color.json').object;\n files.forEach(file => {\n name = file.name;\n if (name.endsWith('-wb.json')) {\n name = name.slice(0, -8);\n createCss(cssTpl, file.object, name, colorData);\n }\n });\n};\n/**\n * Create Css file from template\n * @param {String} cssTpl CSS template\n * @param {Object} tplData theme data\n * @param {String} theme theme name\n * @param {Object} colorData icon-color.json\n */\nfunction createCss(cssTpl, tplData, theme, colorData) {\n let colorFile = new Wb.File(true, 'wb/css/' + theme + '-icon-color.json'),\n key, value, mergeColorData, iconCssText = '';\n\n mergeColorData = colorFile.exists ? Wb.apply({}, colorData, colorFile.object) : colorData;\n Wb.each(mergeColorData, (name, color) => {\n if (iconCssText)\n iconCssText += '\\n';\n iconCssText += '/* ' + name + ' color */\\n.' + name + ' {\\n color: ' + color + ';\\n}';\n });\n cssTpl = cssTpl.replaceAll(/__.*?__/g, v => {\n key = v.slice(2, -2)\n value = tplData[key];\n if (!value)\n Wb.warn('Invalid name \"' + key + '\"');\n return value ?? v;\n });\n new Wb.File(true, 'wb/css/' + theme + '-wb.css').text = iconCssText + '\\n' + cssTpl;\n}\n/**\n * Process iconfont.css\n */\nfunction proccessIconFont() {\n let file = new Wb.File(true, 'wb/css/iconfont.css'),\n text = file.text, pos = text.indexOf('.wb {');\n\n //pos!=-1 means iconfont.css is modified\n if (pos != -1) {\n let woffFile = new Wb.File(true, 'wb/css/iconfont.woff2');\n file.text = text = '@font-face {\\n font-family: \"wb\";\\n' +\n \" src: url('data:application/x-font-woff2;charset=utf-8;base64,\" +\n woffFile.base64 + \"') format('woff2');\\n}\" + text.substr(text.indexOf('}', pos) + 1);\n woffFile.remove();\n let icons = text.match(/(?<=\\.).*?(?=\\:)/g),\n jsonFile = new Wb.File(true, 'wb/css/icon-color.json'),\n jsonObject = jsonFile.object,\n newJson = {},\n colorStr = '3456789ABCD', color, i;\n icons.forEach(icon => {\n color = jsonObject[icon];\n if (!color) {\n color = '#';\n for (i = 0; i < 6; i++) {\n color += colorStr[Wb.random(11)];\n }\n }\n newJson[icon] = color;\n });\n\n jsonFile.text = Wb.encodePretty(newJson);\n }\n}\nmain();", "remark": "Create css theme files" }, "_icon": "module", "title": "" } # dev/ide/reload-system.xwl Title: reload-system Description: Reload all system resources ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\nfunction main() {\n SysUtil.reloadSystem(true);\n}\nmain();", "remark": "Reload all system resources" }, "_icon": "module", "title": "" } # dev/ide/replace.xwl Title: replace Description: Replace text in app folder ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\nfunction main() {\n Wb.load('./ide-ss.js');\n let result, fileSearcher, FileSearcher = Wb.ide.FileSearcher;\n\n fileSearcher = new FileSearcher(Wb.getObject('path'), Params.search, Params.fileType,\n Wb.getObject('options'), null, Params.replaceTo);\n result = fileSearcher.searchReplace();\n Wb.send(result);\n}\nmain();", "remark": "Replace text in app folder" }, "_icon": "module", "title": "" } # dev/ide/search.xwl Title: search Description: Search text in app folder ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Search text in app folder.\n */\nWb.checkDemo();\nlet actions = {\n /**\n * Search text in the files\n */\n searchText() {\n Wb.load('./ide-ss.js');\n let result, fileSearcher, FileSearcher = Wb.ide.FileSearcher;\n\n fileSearcher = new FileSearcher(Wb.getObject('path'), Params.search, Params.fileType, Wb.getObject('options'));\n result = fileSearcher.searchReplace();\n Wb.send(result);\n },\n /**\n * Search file name\n */\n searchFile() {\n let name = Params.search, result = [];\n\n name = '*' + name + '*';\n Wb.File.appFolder.cascade(file => {\n if (!file.isMinFile && file.match(name)) {\n result.push({ path: file.path, content: file.name.htmlText, lineNumber: 1, column: 1 });\n if (result.length > 999)\n return false;\n }\n });\n Wb.send(result);\n },\n /**\n * Search url shortcut\n */\n searchUrl() {\n let result = [], object = new Wb.File(true, 'wb/system/url.json').object, key = Params.search, value,\n modulePath = Base.modulePathText;\n\n if (value = object['/' + key]) {\n result.push({ path: modulePath + value, content: key.htmlText, lineNumber: 1, column: 1 });\n delete object['/' + key];\n }\n Wb.each(object, (k, v) => {\n if (k.includes(key))\n result.push({ path: modulePath + v, content: k.substr(1).htmlText, lineNumber: 1, column: 1 });\n });\n Wb.send(result);\n },\n /**\n * Peek file name\n */\n peekFile() {\n let result = [], query = Params.query, module, text, name, title, notMinFile;\n Wb.File.appFolder.cascade(file => {\n name = file.name;\n notMinFile = !file.isMinFile;\n if (notMinFile && file.isModuleFile) {\n title = Wb.optText(file.object.title);\n } else {\n title = null;\n }\n if (notMinFile && (name.includes(query) || title?.includes(query))) {\n module = file.inModuleFolder;\n if (module)\n text = file.modulePath;\n else\n text = file.relPath;\n result.push({ text, module, subtext: title });\n if (result.length > 999)\n return false;\n }\n });\n Wb.send(result);\n },\n /**\n * Search none login modules.\n */\n noneLoginModule() {\n let object, result = [];\n Wb.File.moduleFolder.cascade(file => {\n if (file.isModuleFile && !file.isMinFile) {\n try {\n object = file.object.properties;\n if (!object)\n throw object;\n } catch (e) {\n Wb.raise('Invalid module \"' + file.modulePath + '\".')\n }\n if (!Wb.parseBool(object.loginRequired ?? true)) {\n result.push({\n path: file.path, compPath: object.cid, propName: 'loginRequired',\n propType: 'properties', content: 'loginRequired', lineNumber: 1, column: 1\n });\n }\n }\n });\n Wb.send(result);\n }\n};\nactions[Params.xaction]();", "remark": "Search text in app folder" }, "_icon": "module", "title": "" } # dev/ide/select-debug.xwl Title: select-debug Description: Select debug module list ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n if (!Config.debug)\n return;\n let data, userid = Wb.userid, items = [],\n map = DebugFiles.getDebugFiles(userid);\n\n if (map) {\n map.each((k, v) => {\n data = { file: k, path: v.debugPath };\n if (v.context)\n data.status = 2;\n else\n data.status = v.status;\n items.push(data);\n })\n items.sort((a, b) => {\n let x = 9, y = 9;\n\n if (a.status == 2)\n x -= 5;\n if (b.status == 2)\n y -= 5;\n if (a.file < b.file)\n x--;\n else\n y--;\n return x - y;\n });\n }\n Wb.send({ items });\n}\nmain();", "remark": "Select debug module list" }, "_icon": "module", "title": "" } # dev/ide/set-debug.xwl Title: set-debug Description: Set module debug status ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\nfunction main() {\n let files = Wb.getObject('files'),\n type = Params.type, userid = Wb.userid,\n types = Wb.has('types') ? Wb.getObject('types') : null;\n\n files.forEach((file, index) => {\n switch (types ? types[index] : type) {\n case 'add':\n DebugFiles.addDebugFile(userid, file);\n break;\n case 'remove':\n DebugFiles.removeDebugFile(userid, file);\n break;\n case 'disable':\n DebugFiles.setDebugStatus(userid, file, 0);\n break;\n case 'enable':\n DebugFiles.setDebugStatus(userid, file, 1);\n break;\n case 'terminate':\n DebugFiles.terminate(userid, file, true);\n break;\n case 'resume':\n DebugFiles.terminate(userid, file, false);\n break;\n }\n });\n}\nmain();", "remark": "Set module debug status" }, "_icon": "module", "title": "" } # dev/ide/view-source.xwl Title: view-source Description: View file source code ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "View file source code", "serverScript": "function main() {\n let items = Params.file.split(':'), path = items[0], line = parseInt(items[1]), code;\n\n if (path.endsWith('.xwl'))\n code = Xwl.get(path).getServerScript();\n else {\n //module path first\n let modulePath = 'wb/modules/' + path\n if ((new File(Base.path, modulePath)).exists())\n path = modulePath;\n code = SourceBuffer.get(path).getCharacters();\n }\n code = Wb.encode(code);\n code = code.replaceAll('', '<\\\\/script>');\n Wb.set({ line, code });\n}\nmain();" }, "_icon": "module", "_expanded": true, "events": { "finalize": "app.codeEditor1.cursor = { lineNumber: _$line$_, column: 1 };" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "value": "@_$code$_", "wrapBorder": "0", "readonly": "true" }, "events": { "cursorchange": "app.cursorLabel.text = cursor ? (cursor.lineNumber + ' : ' + cursor.column) : Wb.nbsp;" } }, { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true", "justify": "end" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "label", "text": "cursorLabel", "cls": "Wb.Label", "properties": { "cid": "cursorLabel", "text": "1 : 1" } } ] } ] } ] } # dev/ide.xwl Title: Development Environment Description: Integrated development environment ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.load('./ide/ide-ss.js');\n const Util = Wb.ide.Util, idePath = 'wb/modules/dev/ide/';\n Wb.set('args', Wb.encode({\n path: Base.pathText,\n devTools: Wb.getConfig('sys.ss.devTools'),\n osCharset: Base.osCharset?.toUpperCase(),\n charset: System.getProperty('file.encoding')?.toUpperCase(),\n fileCharset: Wb.getConfig('sys.file.charset')?.toUpperCase(),\n filenameCharset: Wb.getConfig('sys.locale.filenameCharset')?.toUpperCase(),\n sysFilenameCharset: SysUtil.filenameCharset?.name()?.toUpperCase(),\n createWbCss: new Wb.File(true, idePath + 'create-wb-css.xwl').exists,\n createDocs: new Wb.File(true, idePath + 'create-docs.xwl').exists,\n createRelease: new Wb.File(true, idePath + 'create-release.xwl').exists,\n compressScript: new Wb.File(true, idePath + 'compress.xwl').exists,\n releasePath: Wb.getConfig('sys.app.releasePath'),\n version: Wb.getConfig('sys.app.version'),\n heartbeat: Wb.getConfig('sys.session.heartbeatInterval'),\n httpHeartbeat: Wb.getConfig('sys.session.httpHeartbeatInterval'),\n username: Wb.username,\n openExample: Params.openExample,\n openModule: Params.openModule,\n imgs: Util.getImgs(),\n icons: Util.getIcons(),\n globalsList: Util.getGlobalsList()\n }));\n}\nmain();", "links": "['wb/js/monaco.js', 'wb/docs/data.js', 'wb/docs/groups.js', 'wb/js/ide.js']", "remark": "Integrated development environment" }, "events": { "initialize": "let obj = new Wb.ide.IDE(parentContainer, _$args$_);\nif (parentContainer)\n app.app = obj;\nelse\n globalThis.app = obj;" }, "_icon": "module", "title": "@ide", "icon": "devtool", "img": "", "hideInMenu": "false", "_expanded": true, "tags": "{url: 'ide', newWin: true}" } # dev/kve/add-type.xwl Title: add-type Description: Add key type ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add key type", "serverScript": "function main() {\n let rec = { sid: Wb.getId() };\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_key_type', insert: Params, send: rec });\n}\nmain();" }, "_icon": "module" } # dev/kve/del-types.xwl Title: del-types Description: Delete key types ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete key types", "serverScript": "function main() {\n let del = Wb.getObject('del');\n\n Wb.sync({ tableName: 'wb_key_type', del });\n Wb.sql({ sql: 'delete from wb_key where rid={?$sid?}', params: del });\n del.forEach(item => { KVBuffer.buffer.remove(item.$key_name) });\n}\nmain();" }, "_icon": "module" } # dev/kve/edit-type.xwl Title: edit-type Description: Edit key type ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Edit key type", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let oldKeyName = Params.$key_name;\n\n Wb.sync({ tableName: 'wb_key_type', update: Params });\n KVBuffer.buffer.remove(oldKeyName);\n Util.loadKey(Params.key_name || oldKeyName);\n}\nmain();" }, "_icon": "module" } # dev/kve/save-list.xwl Title: save-list Description: Save key list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Save key list", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let sid, rid = Params.keyId, insert = [], rec;\n\n Params.insert?.forEach(item => {\n sid = Wb.getId();\n rec = { sid, rid };\n Wb.apply(item, rec);\n insert.push(rec);\n });\n Params.tableName = 'wb_key';\n Params.db = '';//prevent inject db from params\n Wb.sync(Params);\n Util.loadKey(Params.keyName);\n Wb.send({ insert });\n}\nmain();" }, "_icon": "module" } # dev/kve/select-list.xwl Title: select-list Description: Select key list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select key list", "serverScript": "function main() {\n let data, sql = 'select * from wb_key where rid={?rid?}';\n if (Params.searchList) {\n Wb.setLike('searchList');\n sql += ' and (map_k like {?searchList?} or map_v like {?searchList?})';\n }\n sql += ' order by map_k';\n data = Wb.getDict(sql, 'wb,');\n //sort by number\n if (Params.keyType == '1') {\n data.items.sort((a, b) => {\n return parseInt(a.map_k) - parseInt(b.map_k);\n });\n }\n Wb.send(data);\n}\nmain();" }, "_icon": "module" } # dev/kve/select-type.xwl Title: select-type Description: Select key types ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select key types", "serverScript": "function main() {\n let sql = 'select * from wb_key_type';\n if (Params.searchType) {\n Wb.setLike('searchType');\n sql += ' where key_name like {?searchType?}';\n }\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, ['wb_key_type', 'wb']);\n}\nmain();" }, "_icon": "module" } # dev/kve.xwl Title: Key Value Editor Description: Key value mapping setting ```json { "title": "@kve", "icon": "list-view", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Key value mapping setting" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /**\n * Method to execute when adding or updating key type fails.\n * @param {String} resp Response text.\n */\n onFailure(resp) {\n Wb.checkExists(resp, 'wb_key_type_key_name', app.typeGrid.dictWin.down('key_name'));\n },\n /** @property {String} - The currently selected key name. */\n get$keyName() {\n return app.typeGrid.selection?.data.key_name;\n },\n /** @property {String} - The currently selected key name ID. */\n get$keyId() {\n return app.typeGrid.selection?.data.sid;\n },\n /** @property {String} - The currently selected key category. */\n get$keyType() {\n return app.typeGrid.selection?.data.key_type;\n },\n /**\n * Fires after the list table data is changed. @priv\n */\n onChange() {\n app.saveBtn.disabled = false;\n },\n /**\n * Save the list data. @priv\n * @param {Function} [success] The callback function after save successfully.\n */\n save(success) {\n let grid = app.listGrid;\n grid.sync({\n url: xpath + '/save-list',\n params: { keyId: app.keyId, keyName: app.keyName },\n success() {\n app.saveBtn.disabled = true;\n success?.();\n },\n failure(resp) {\n Wb.checkExists(resp, 'wb_key_unq1', Str.key);\n }\n });\n }\n});", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "typeGrid", "cls": "Wb.Grid", "properties": { "cid": "typeGrid", "url": "@xpath + '/select-type'", "multiSelect": "true", "columnsSortable": "true", "width": "50vw", "autoContextMenu": "true", "title": "@Str.keyName", "sorters": "key_name", "maxWidth": "30em", "keyFields": "sid,key_name" }, "_expanded": true, "events": { "itemdblclick": "this.downWhole('editBtn').fireEvent('click');", "selectionchange": "let data = app.typeGrid.selectionData, keyName = data?.key_name, listGrid = app.listGrid, searchList = app.searchList;\n\nlistGrid.disabled = !keyName;\nlistGrid.subTitle = keyName;\nsearchList.suspendEvent();\nsearchList.clear();\nsearchList.resumeEvent();\nif (keyName) {\n listGrid.load();\n} else {\n listGrid.destroyAll();\n listGrid.commit();\n app.saveBtn.disabled = true;\n}", "beforeselect": "if (!app.saveBtn.disabled) {\n Wb.choose(Str.saveChanges.format(Str.list), btn => {\n if (btn == 'yes') {\n app.save(f => item.select());\n } else if (btn == 'no') {\n app.saveBtn.disabled = true;\n item.select()\n }\n });\n return false;\n}" }, "items": [ { "_icon": "pagenum", "text": "pagingBar", "cls": "Wb.PagingBar", "properties": { "cid": "pagingBar", "isProperty": "true", "showColumnsMenu": "false" }, "_expanded": true }, { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.typeGrid.dictAdd({\n url: xpath + '/add-type',\n failure: app.onFailure\n}, Str.keyName);" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "app.typeGrid.dictEdit({\n url: xpath + '/edit-type',\n failure: app.onFailure\n}, 'key_name');" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.typeGrid.removeRecords(xpath + '/del-types', 'key_name', null, f => app.saveBtn.disabled = true);" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "searchType", "cls": "Wb.Text", "properties": { "cid": "searchType", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.typeGrid.delayLoad({ comps: app.searchType });" } } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" }, "_expanded": true }, { "_icon": "grid", "text": "listGrid", "cls": "Wb.Grid", "properties": { "cid": "listGrid", "url": "@xpath + '/select-list'", "multiSelect": "true", "flex": "1", "autoContextMenu": "true", "title": "@Str.list", "autoLoad": "false", "disabled": "true", "editable": "true", "keyFields": "sid" }, "_expanded": true, "events": { "itemdblclick": "this.downWhole('editBtn').fireEvent('click');", "editing": "app.onChange();", "itemchange": "app.onChange();", "beforeload": "Wb.apply(params, { searchList: app.searchList.value, rid: app.keyId, keyType: app.keyType });\nreturn this.saveConfirm(app.saveBtn, app.save);" }, "items": [ { "_icon": "pagenum", "text": "pagingBar", "cls": "Wb.PagingBar", "properties": { "cid": "pagingBar", "isProperty": "true", "showColumnsMenu": "false" }, "_expanded": true }, { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.listGrid.addRecord();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.listGrid.delRecords();" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "disabled": "true", "keys": "Ctrl+S" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider2" } }, { "_icon": "text", "text": "searchList", "cls": "Wb.Text", "properties": { "cid": "searchList", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.listGrid.delayLoad();" } } ] } ] } ] } ] } # dev/lang/actions.xwl Title: actions Description: Multilingual editor server side actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Multilingual editor server side actions", "serverScript": "let actions = {\n /**\n * Select lang items.\n */\n select() {\n const enUS = 'en-us';\n const search = Params.search?.toLowerCase();\n let columns = [], rows = [], langs, value, found, type, row, langNames, keys;\n\n langs = getLangs();\n langNames = Object.keys(langs).lowerSort();\n langNames.remove(enUS);\n langNames.insert(0, enUS);\n keys = Object.keys(langs[enUS]).lowerSort();\n keys.forEach(key => {\n found = false;\n row = { name: key };\n if (search && key.includesIC(search))\n found = true;\n langNames.forEach(lang => {\n value = langs[lang][key];\n if (lang == enUS) {\n if (Wb.isNumber(value))\n type = 'number';\n else if (Wb.isBoolean(value))\n type = 'boolean';\n else if (Wb.isObject(value) || Wb.isArray(value))\n type = 'object';\n else\n type = 'string';\n row.type = type;\n }\n if (Wb.isObject(value) || Wb.isArray(value))\n value = Wb.encode(value);\n row[lang] = value;\n if (search && String(value).includesIC(search))\n found = true;\n });\n if (found || !search)\n rows.push(row);\n });\n columns.push(\n { rowNum: true },\n { text: 'name', width: '15em', fieldName: 'name', editor: { cname: 'text', required: true } }\n );\n langNames.forEach(lang => {\n columns.push({\n text: lang, align: 'left', minWidth: '15em', width: -1, fieldName: lang,\n editor: { cname: 'text', required: true }\n });\n });\n columns.push({\n text: 'type', width: '7em', fieldName: 'type', editor: {\n cname: 'select', forceSelect: true, required: true,\n data: ['string', 'number', 'boolean', 'object']\n }\n });\n Wb.send({ items: rows.slice(Wb.getInt('_from'), Wb.getInt('_to') + 1), total: rows.length, columns });\n },\n /**\n * Save data.\n */\n save() {\n let langs, type, object, name, enLang, oldValue;\n\n langs = getLangs(true);\n enLang = langs['en-us'];\n // delete\n Params.del?.forEach(item => {\n Wb.each(langs, (k, v) => {\n delete v[1][item.$name];\n });\n });\n // update\n Params.update?.forEach(item => {\n if (item.name && enLang[1][item.name])\n Wb.raise(Str.alreadyExists.format(item.name));\n type = item.type ?? item.$type;\n name = item.name ?? item.$name;\n Wb.each(langs, (k, v) => {\n object = v[1];\n oldValue = object[item.$name];\n delete object[item.$name];\n object[name] = createValue(type, item[k] ?? oldValue);\n });\n });\n // insert\n Params.insert?.forEach(item => {\n if (enLang[1][item.name])\n Wb.raise(Str.alreadyExists.format(item.name));\n Wb.each(langs, (k, v) => {\n v[1][item.name] = createValue(item.type, item[k]);\n });\n });\n // save\n Wb.each(langs, (k, v) => {\n v[0].text = '// Define resources for a specified language.\\nglobalThis.Str = ' + Wb.encodePretty(v[1]) + ';';\n });\n StrCls.load();\n },\n};\nactions[Params.xaction]();\n\n/**\n * Get all language data. @priv\n * @param {Boolean} [containsFile] Whether contains file.\n */\nfunction getLangs(containsFile) {\n let folder = new Wb.File(true, 'wb/js/locale'), langs = {}, text, filename, object;\n\n folder.each(file => {\n filename = file.name;\n if (!file.isMinFile && filename.startsWith('wb-') && filename.endsWith('.js')) {\n text = file.text;\n object = Wb.parse(text.substring(text.indexOf('{',\n text.indexOf('globalThis.Str')), text.lastIndexOf('}') + 1));\n langs[filename.slice(3, -3)] = containsFile ? [file, object] : object;\n }\n });\n return langs;\n}\n\n/**\n * Creates a value based on the specified type. @priv\n * @param {String} type Data type.\n * @param {Object} value Data value.\n * @return {Object} New value.\n */\nfunction createValue(type, value) {\n switch (type) {\n case 'number':\n value = parseFloat(value);\n break;\n case 'boolean':\n value = Wb.parseBool(value);\n break;\n case 'object':\n if (!Wb.isArray(value) && !Wb.isObject(value)) {\n try {\n value = Wb.parse(String(value));\n } catch (e) {\n Wb.raise(Str.invalidValue.format(value));\n }\n }\n break;\n default:\n value = String(value);\n }\n return value;\n}" }, "_icon": "module" } # dev/lang.xwl Title: Language Management Description: Multilingual editor ```json { "title": "@langMng", "icon": "book", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Multilingual editor" }, "_icon": "module", "_expanded": true, "events": { "beforeunload": "if (!app.saveBtn.disabled)\n return false;", "initialize": "Wb.apply(app, {\n /**\n * Fires after the table data is changed. @priv\n */\n onChange() {\n app.saveBtn.disabled = false;\n },\n /**\n * Save grid data.\n * @param {Function} [callback] Callback function after success.\n */\n save(callback) {\n app.grid1.sync({\n url: xpath + '/actions&xaction=save',\n success() {\n app.saveBtn.disabled = true;\n callback?.();\n }\n });\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.addRecord({ type: 'string' });" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.delRecords();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "keys": "Ctrl+S", "disabled": "true" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/actions&xaction=select'", "multiSelect": "true", "stateId": "wb.lang", "editable": "true", "keyFields": "name,type" }, "_expanded": true, "events": { "editing": "app.onChange();", "itemchange": "app.onChange();", "beforeload": "return this.saveConfirm(app.saveBtn, app.save);" } } ] } ] } # dev/version/check-out.xwl Title: check-out Description: Check out files ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Check out files", "serverScript": "Wb.checkDemo();\nfunction main() {\n let sqlMap = Wb.Query.getArraySql(Wb.getObject('ids'), 'varchar');\n\n Wb.sql({\n sql: 'select file_path,file_content from wb_version where sid in (' + sqlMap.sql + ')',\n params: sqlMap.params,\n blob: true,\n fn(row) {\n new Wb.File(true, row.file_path).stream = row.file_content;\n }\n });\n}\nmain();" }, "_icon": "module" } # dev/version/del.xwl Title: del Description: Delete version files ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Delete version files", "serverScript": "function main() {\n let del = Wb.getObject('del');\n\n Wb.sync({ tableName: 'wb_version', del });\n}\nmain();" }, "_icon": "module" } # dev/version/rollback.xwl Title: rollback Description: Rollback to the specified version ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Rollback to the specified version", "serverScript": "Wb.checkDemo();\nfunction main() {\n Wb.sql({\n sql: 'select file_path,file_content from wb_version where file_version={?version?}',\n blob: true,\n fn(row) {\n new Wb.File(true, row.file_path).stream = row.file_content;\n }\n });\n}\nmain();" }, "_icon": "module" } # dev/version/select-version.xwl Title: select-version Description: Select all versions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select all versions", "serverScript": "function main() {\n Wb.sendRecords({\n sql: 'select distinct file_version from wb_version order by file_version desc',\n rs: -1\n });\n}\nmain();" }, "_icon": "module" } # dev/version/select.xwl Title: select Description: Select version files ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select version files", "serverScript": "function main() {\n let sql, where = [];\n\n sql = 'select sid, sdate, file_path, file_version, version_remark, modify_date from wb_version';\n if (Params.searchVersion)\n where.push('file_version={?searchVersion?}');\n if (Params.searchFile) {\n Wb.setLike('searchFile');\n where.push('file_path like {?searchFile?}');\n }\n if (where.length)\n sql += ' where ' + where.join(' and ');\n sql += Wb.getOrderSql();\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # dev/version.xwl Title: Version Management Description: File version management ```json { "title": "@versionMng", "icon": "form", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "File version management" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Check out files.\n */\n checkOut() {\n let sels = app.grid1.selections;\n if (!sels.length) {\n Wb.tipSelect();\n return;\n }\n Wb.confirm(Wb.getActionHint(sels, 'file_path', Str.checkOut), f => {\n Wb.ajax({\n url: xpath + '/check-out',\n params: { ids: sels.map(item => item.data.sid) },\n success() {\n Wb.tipDone(Str.checkOut);\n }\n });\n }).showBy(app.checkOutBtn, 'br');\n },\n /**\n * Load grid data.\n */\n load() {\n app.grid1.delayLoad({ comps: app.viewport1.tbar });\n }\n});" }, "items": [ { "_icon": "window", "text": "backWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "backWin", "layout": "grid1", "dialog": "true", "icon": "undo", "title": "@Str.back" }, "events": { "ok": "let version = app.versionSelect.value;\nWb.confirm(Str.actionConfirm.format(Str.back, version), f => {\n Wb.ajax({\n url: xpath + '/rollback',\n params: { version },\n success() {\n app.backWin.close();\n }\n });\n});" }, "items": [ { "_icon": "combo", "text": "versionSelect", "cls": "Wb.Select", "properties": { "cid": "versionSelect", "url": "@xpath + '/select-version'", "text": "@Str.version", "required": "true", "editable": "false" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "checkOutBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "checkOutBtn", "text": "@Str.checkOut", "icon": "logout", "keys": "Ctrl+E" }, "events": { "click": "app.checkOut();" } }, { "_icon": "item", "text": "backBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "backBtn", "text": "@Str.back", "icon": "undo" }, "events": { "click": "app.backWin.show();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'file_path');" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "combo", "text": "searchVersion", "cls": "Wb.Select", "properties": { "cid": "searchVersion", "url": "@xpath + '/select-version'", "placeholder": "@Str.version", "clearButton": "true", "width": "8em", "editable": "false" }, "events": { "select": "app.load();", "clearclick": "app.load();" } }, { "_icon": "text", "text": "searchFile", "cls": "Wb.Text", "properties": { "cid": "searchFile", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.load();" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "{name:'sdate', desc: true}", "keyFields": "sid" }, "_expanded": true } ] } ] } # dev/welcome.xwl Title: Welcome Description: Welcome page ```json { "title": "@welcome", "icon": "logo", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.set('title', Wb.getConfig('sys.app.title'));", "remark": "Welcome page" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "html": "\n", "autoScroll": "true" }, "_expanded": true, "events": { "click": "let node;\nswitch (e.target.getAttribute('cid')) {\n case 'docs':\n Wb.open('m?xwl=dev/docs');\n break;\n case 'dbc':\n Wb.open('m?xwl=admin/dbc');\n break;\n case 'user':\n Wb.open('m?xwl=admin/user');\n break;\n case 'ide':\n Wb.openWin({ url: 'ide', params: { openExample: 1 } });\n break;\n case 'demos':\n if (parentApp?.inHome)\n node = parentApp.moduleTree.find(node => node.text == Str.example);\n else if (parentApp?.inIDE)\n node = parentApp.moduleNode.find(node => node.text == 'example');\n if (node) {\n node.expand();\n node.selected = true;\n node.highlight();\n } else {\n Wb.openWin({ url: 'ide', params: { openExample: 1 } });\n }\n break;\n}", "ready": "let el = this.el, div;\nif (Str.lang == 'zh-cn')\n div = el.query('[cid=lang-zh-cn]');\nelse\n div = el.query('[cid=lang-en]');\ndiv.setStyle('display', 'block');" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true", "padding": "true" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "label", "text": "copyrightLabel", "cls": "Wb.Label", "properties": { "cid": "copyrightLabel", "text": "Copyright © Geejing, All Rights Reserved.", "cls": "w-sub-color", "fontSize": ".8em" } } ] } ] } ] } # example/apps/oa/home.xwl Title: Office Home ```json { "title": "Office Home", "icon": "home", "img": "", "tags": "{newWin: true}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Params.oaPath = Wb.encode(Base.pathText + 'wb/modules/example/apps/oa');\n}\nmain();" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Open the specified module.\n * @param {Object} data Configs data.\n * @param {Boolean} [reload] Whether reload module.\n */\n openModule(data, reload) {\n let configs, url = 'm?xwl=' + data.path;\n\n configs = Wb.apply({ url }, Wb.parse(data.tags));\n if (configs.frame)\n Wb.browse(configs);\n else if (configs.newWin)\n Wb.openWin(configs);\n else {\n let ct = app.clientCardCt, card;\n\n card = ct.find(card => card.moduleUrl == url);\n if (card) {\n if (reload) {\n card.destroy();\n card = null;\n } else {\n app.clientCardCt.activeCard = card;\n }\n }\n if (!card) {\n let modulePanel = app.clientCardCt.add({ cname: 'container', moduleUrl: url, moduleData: data });\n app.clientCardCt.activeCard = modulePanel;\n configs.container = modulePanel;\n Wb.run(configs);\n }\n }\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "row", "border": "false" }, "items": [ { "_icon": "array", "text": "tbar", "cls": "Wb.Array", "properties": { "cid": "tbar" }, "_expanded": true, "items": [ { "_icon": "container", "text": "bannerCt", "cls": "Wb.Container", "properties": { "cid": "bannerCt", "height": "50", "border": "false", "layout": "row", "align": "center", "gap": "20px", "padding": "0 15px 0 15px", "textSelectable": "false", "justify": "space-between", "cls": "w-bar-color", "background": "url(wb/images/app/banner1.png;) no-repeat 0 0 / 100% 100%" }, "_expanded": false, "items": [ { "_icon": "container", "text": "leftCt", "cls": "Wb.Container", "_expanded": false, "properties": { "cid": "leftCt", "layout": "row", "align": "center" }, "items": [ { "_icon": "logo", "text": "logoIcon", "cls": "Wb.Icon", "_expanded": true, "properties": { "cid": "logoIcon", "icon": "flower", "fontSize": "38px" } }, { "_icon": "component", "text": "titleComp", "cls": "Wb.Component", "_expanded": true, "properties": { "cid": "titleComp", "html": "My Office System" } } ] }, { "_icon": "container", "text": "centerCt", "cls": "Wb.Container", "_expanded": false, "properties": { "cid": "centerCt" } }, { "_icon": "container", "text": "rightCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "rightCt" }, "items": [ { "_icon": "button", "text": "menuBtn", "cls": "Wb.Button", "properties": { "cid": "menuBtn", "icon": "menu", "type": "tool" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "logoutItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "logoutItem", "text": "@Str.logout", "icon": "power" }, "events": { "click": "// Wb.ajax({\n// url: 'logout'\n// });" } } ] } ] } ] } ] }, { "_icon": "container", "text": "addressCt", "cls": "Wb.Container", "properties": { "cid": "addressCt", "layout": "row", "padding": "true", "align": "stretch", "gap": ".2em" }, "_expanded": false, "items": [ { "_icon": "text", "text": "urlText", "cls": "Wb.Text", "properties": { "cid": "urlText", "readonly": "true", "text": "URL", "flex": "1", "selectOnFocus": "true" }, "_expanded": true }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "button", "text": "refreshItem", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "refreshItem", "icon": "refresh", "tip": "@Str.refresh", "type": "tool" }, "events": { "click": "let moduleData = app.clientCardCt.activeCard?.moduleData;\nif (moduleData) {\n app.openModule(moduleData, true);\n}" } }, { "_icon": "button", "text": "closeItem", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "closeItem", "icon": "delete", "tip": "@Str.close", "type": "tool" }, "events": { "click": "app.clientCardCt.activeCard?.destroy();" } } ] } ] }, { "_icon": "tree-view", "text": "moduleTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "moduleTree", "url": "m?xwl=sys/portal/home/get-modules-tree", "cls": "w-home-tree", "treeStyle": "menu", "dblclickExpand": "false", "width": "18em", "rightExpander": "true" }, "events": { "beforeload": "let node = configs.node;\n\n// params.path = node?.data.path || _$oaPath$_;\nparams.path = node?.data.path;", "itemclick": "if (item.leaf)\n app.openModule(item.data);\nelse\n item.toggleExpand();" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "_expanded": true, "properties": { "cid": "splitter1" } }, { "_icon": "win-restore", "text": "clientCardCt", "cls": "Wb.CardCt", "properties": { "cid": "clientCardCt", "flex": "1", "useHash": "true" }, "events": { "cardchange": "let url = newCard?.moduleUrl;\napp.urlText.value = url ? Wb.qualifyURL(url) : '';" }, "_expanded": true, "items": [ { "_icon": "container", "text": "mainCt", "cls": "Wb.Container", "properties": { "cid": "mainCt", "background": "true", "gap": "1em", "padding": "1em", "layout": "column", "shrink": "false", "autoScroll": "true" }, "_expanded": true, "items": [ { "_icon": "container", "text": "searchCt", "cls": "Wb.Container", "properties": { "cid": "searchCt", "layout": "row", "gap": ".8em", "padding": "true", "background": "false", "align": "center", "roundBorder": "true" }, "_expanded": false, "items": [ { "_icon": "logo", "text": "icon1", "cls": "Wb.Icon", "properties": { "cid": "icon1", "icon": "calendar" } }, { "_icon": "button", "text": "today", "cls": "Wb.Button", "properties": { "cid": "today", "text": "Today", "groupName": "dateButtons", "active": "true", "shape": "round", "border": "false" }, "_expanded": true }, { "_icon": "button", "text": "week", "cls": "Wb.Button", "properties": { "cid": "week", "text": "This Week", "groupName": "dateButtons", "shape": "round", "border": "false" }, "_expanded": true }, { "_icon": "button", "text": "month", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "month", "text": "This Month", "groupName": "dateButtons", "shape": "round", "border": "false" } }, { "_icon": "button", "text": "year", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "year", "text": "This Year", "groupName": "dateButtons", "shape": "round", "border": "false" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "placeholder": "Select Date" }, "_expanded": true } ] }, { "_icon": "container", "text": "summaryCt", "cls": "Wb.Container", "properties": { "cid": "summaryCt", "layout": "grid4", "padding": "false", "textSelectable": "false", "color": "#555" }, "_expanded": false, "items": [ { "_icon": "component", "text": "data1", "cls": "Wb.Component", "properties": { "cid": "data1", "html": "
\n
\n
9.5% Increase
\n
387 Amount
\n
\n
\n
", "frame": "true" }, "_expanded": true }, { "_icon": "component", "text": "data2", "cls": "Wb.Component", "properties": { "cid": "data2", "html": "
\n
\n
$3,259 Total
\n
2,328 Visits
\n
\n
\n
", "frame": "true" } }, { "_icon": "component", "text": "data3", "cls": "Wb.Component", "properties": { "cid": "data3", "html": "
\n
\n
165 Items
\n
5.2% Percent
\n
\n
\n
", "frame": "true" } }, { "_icon": "component", "text": "data4", "cls": "Wb.Component", "properties": { "cid": "data4", "html": "
\n
\n
629 Users
\n
9,185 Count
\n
\n
\n
", "frame": "true" } } ] }, { "_icon": "container", "text": "chartCt", "cls": "Wb.Container", "_expanded": false, "properties": { "cid": "chartCt", "layout": "grid2", "padding": "false", "frame": "true", "background": "false" }, "items": [ { "_icon": "chart-bar", "text": "chart1", "cls": "Wb.Chart", "properties": { "cid": "chart1", "option": "({\n legend: false,\n grid: {\n left: 20,\n right: 20,\n bottom: 20,\n top: 20,\n containLabel: true\n },\n xAxis: [\n {\n type: 'category',\n boundaryGap: false,\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n }\n ],\n yAxis: [\n {\n type: 'value'\n }\n ],\n series: [\n {\n name: 'Email',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 90, 230, 210]\n },\n {\n name: 'Union Ads',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [220, 182, 191, 234, 290, 330, 310]\n },\n {\n name: 'Video Ads',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [150, 232, 201, 154, 190, 330, 410]\n },\n {\n name: 'Direct',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [320, 332, 301, 334, 390, 330, 320]\n },\n {\n name: 'Search Engine',\n type: 'line',\n stack: 'Total',\n label: {\n show: true,\n position: 'top'\n },\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [820, 932, 901, 934, 1290, 1330, 1320]\n }\n ]\n})", "height": "25em", "roundBorder": "true" } }, { "_icon": "chart-bar", "text": "chart2", "cls": "Wb.Chart", "properties": { "cid": "chart2", "option": "({\n legend: false,\n grid: {\n left: 20,\n right: 20,\n bottom: 20,\n top: 20,\n containLabel: true\n },\n xAxis: [\n {\n type: 'category',\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n }\n ],\n yAxis: [\n {\n type: 'value'\n }\n ],\n series: [\n {\n name: 'Direct',\n type: 'bar',\n emphasis: {\n focus: 'series'\n },\n data: [320, 332, 301, 334, 390, 330, 320]\n },\n {\n name: 'Email',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 90, 230, 210]\n },\n {\n name: 'Union Ads',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [220, 182, 191, 234, 290, 330, 310]\n },\n {\n name: 'Video Ads',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [150, 232, 201, 154, 190, 330, 410]\n },\n {\n name: 'Search Engine',\n type: 'bar',\n data: [862, 1018, 964, 1026, 1679, 1600, 1570],\n emphasis: {\n focus: 'series'\n },\n markLine: {\n lineStyle: {\n type: 'dashed'\n },\n data: [[{ type: 'min' }, { type: 'max' }]]\n }\n },\n {\n name: 'Baidu',\n type: 'bar',\n barWidth: 5,\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [620, 732, 701, 734, 1090, 1130, 1120]\n },\n {\n name: 'Google',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 290, 230, 220]\n },\n {\n name: 'Bing',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [60, 72, 71, 74, 190, 130, 110]\n },\n {\n name: 'Others',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [62, 82, 91, 84, 109, 110, 120]\n }\n ]\n})", "height": "25em", "roundBorder": "true" } } ] }, { "_icon": "icon-list", "text": "iconView", "cls": "Wb.IconView", "properties": { "cid": "iconView", "data": "[\n { icon: 'user', text: 'User Management' },\n { icon: 'support', text: 'Support Service' },\n { icon: 'list', text: 'Consumption List' },\n { icon: 'preview', text: 'Disabled Item', _disabled: true, _tip: 'This item is disabled' },\n { icon: 'gear', text: 'System Settings' },\n { icon: 'truck', text: 'The text content of this item is too long and maybe overflowed' },\n { icon: 'database', text: 'Database Management' },\n { icon: 'flow1', text: 'WorkFlow Design' }\n ]", "iconField": "icon", "selectColor": "active", "defaultFields": "({\n badge: { value: 99 }\n})", "layout": "grid4", "padding": ".5em", "gap": "1em", "roundBorder": "true" }, "events": { "itemclick": "Wb.tip(item.data.text + ' clicked');" } } ] } ] } ] } ] } # example/apps/oa/leave/add.xwl Title: add ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let flow, rec;\n\n flow = new Wb.Workflow({ file: 'example/leave.flw', title: Params.title });\n flow.start();\n rec = { sid: Wb.getId(), flow_id: flow.flowId, user_id: Wb.userid };\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_leave', insert: Params });\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # example/apps/oa/leave/del.xwl Title: del ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n\n Params.flowId = Wb.getObject('del').$flow_id;\n Wb.startTrans();\n Util.checkProcess();\n Wb.sql('delete from wb_flow where sid={?flowId?}');\n Wb.sql('delete from wb_flow_user where flow_id={?flowId?}');\n Wb.sql('delete from wb_leave where flow_id={?flowId?}');\n}\nmain();" }, "_icon": "module" } # example/apps/oa/leave/edit.xwl Title: edit ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let flowId = Params.$flow_id, title;\n\n Params.flowId = flowId;\n Wb.startTrans();\n Util.checkProcess();\n title = Params.title;\n if (title)\n Wb.sync({ tableName: 'wb_flow', update: { $sid: flowId, title } });\n Wb.sync({ tableName: 'wb_leave', update: Params });\n}\nmain();" }, "_icon": "module" } # example/apps/oa/leave/select.xwl Title: select ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let sql;\n\n sql = 'select a.*,b.title,b.node_text from wb_leave a, wb_flow b where a.flow_id=b.sid and a.user_id={?sys.userid?}';\n sql += Wb.getOrderSql({ title: 'b.title', node_text: 'b.node_text' });\n Wb.sendRowx(sql);\n}\nmain();" }, "_icon": "module" } # example/apps/oa/leave.xwl Title: Leave Application ```json { "title": "Leave Application", "icon": "paper-plane", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "layout": "grid1", "title": "Leave application", "icon": "paper-plane", "autoScroll": "true", "resetDialog": "true" }, "items": [ { "_icon": "text", "text": "title", "cls": "Wb.Text", "properties": { "cid": "title", "text": "Title", "required": "true" } }, { "_icon": "calendar", "text": "begin_date", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "begin_date", "text": "Begin Date", "required": "true" } }, { "_icon": "calendar", "text": "end_date", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "end_date", "text": "End Date", "required": "true" } }, { "_icon": "number-edit", "text": "leave_days", "cls": "Wb.Number", "properties": { "cid": "leave_days", "decimalCount": "0", "text": "Leave days", "required": "true", "minValue": "0", "maxLength": "5" } }, { "_icon": "text", "text": "leave_reason", "cls": "Wb.Text", "properties": { "cid": "leave_reason", "text": "Reason", "required": "true" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.insertRecord(xpath + '/add', app.window1);" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "app.grid1.editRecord(xpath + '/edit', app.window1);" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'title');" } } ] }, { "_icon": "label1", "text": "bbar", "cls": "Wb.DisplayField", "properties": { "cid": "bbar", "icon": "info1", "isProperty": "true", "value": "This module demonstrates workflow and multi-tables CRUD", "padding": "true" } }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "sorters": "{name: 'begin_date', desc: true}", "url": "@xpath + '/select'", "columnsSortable": "true" }, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "beginDateCol", "cls": "Wb.Column", "properties": { "cid": "beginDateCol", "text": "Begin Date", "fieldName": "begin_date", "type": "dateText" } }, { "_icon": "column", "text": "endDateCol", "cls": "Wb.Column", "properties": { "cid": "endDateCol", "text": "End Date", "fieldName": "end_date", "type": "dateText" }, "_expanded": true }, { "_icon": "column", "text": "titleCol", "cls": "Wb.Column", "properties": { "cid": "titleCol", "text": "Title", "fieldName": "title", "width": "15em" } }, { "_icon": "column", "text": "leaveDaysCol", "cls": "Wb.Column", "properties": { "cid": "leaveDaysCol", "text": "Leave Days", "fieldName": "leave_days" }, "_expanded": true }, { "_icon": "column", "text": "approvalNodeCol", "cls": "Wb.Column", "properties": { "cid": "approvalNodeCol", "text": "Approval Node", "fieldName": "node_text" }, "_expanded": true }, { "_icon": "column", "text": "leaveReasonCol", "cls": "Wb.Column", "properties": { "cid": "leaveReasonCol", "text": "Leave Reason", "fieldName": "leave_reason", "width": "-1", "minWidth": "8em" } }, { "_icon": "column", "text": "actionsCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "actionsCol", "width": "3em", "freeze": "true" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "withdrawItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "withdrawItem", "icon": "undo", "tip": "Withdraw Application" }, "events": { "click": "this.gridItem.select();\napp.grid1.removeRecords(xpath + '/del', 'title');" } } ] } ] } ] } ] } ] } ] } # example/apps/oa/person/add.xwl Title: add ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let rec = { sid: Wb.getId() };\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_staff', insert: Params });\n Wb.send(rec);\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person/del.xwl Title: del ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let del = Wb.getObject('del');\n\n Wb.sync({ tableName: 'wb_staff', del });\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person/edit.xwl Title: edit ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.sync({ tableName: 'wb_staff', update: Params });\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person/get-photo.xwl Title: get-photo ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let row = Wb.getRow({\n sql: 'select photo from wb_staff where sid={?sid?}',\n blob: true\n });\n if (row?.photo)\n Wb.exportData(row.photo);\n else\n Wb.exportData(new Wb.File(true, 'wb/images/null.png').stream);\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person/select-dept.xwl Title: select-dept ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let firstItem, sql, rows, isRoot;\n\n // whether is root node\n isRoot = !Params.sid;\n if (isRoot) {\n Params.sid = '0';\n };\n sql = `\n select a.sid, a.dept_code, a.dept_name, 'folder1' as \"_icon\",\n case when (select count(*) from wb_dept b where b.parent_id=a.sid)>0 then 1 else 0 end as items\n from wb_dept a where a.status=1 and a.parent_id={?sid?} order by a.dept_code\n `;\n rows = Wb.getAllRows(sql);\n if (isRoot) {\n if ((firstItem = rows[0]) && rows.length == 1)\n firstItem._expanded = true;\n rows.insert(0, { dept_name: Str.all, _icon: 'list1', _leaf: true });\n }\n Wb.send(rows);\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person/select.xwl Title: select ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let download = Wb.getObject('download');\n if (download) {\n //download blob\n let row = Wb.getRow({\n sql: 'select full_name, photo from wb_staff where sid={?$sid?}',\n blob: true,\n params: download\n });\n if (row?.photo)\n Wb.exportData(row.photo, row.full_name + '.png');\n else\n Wb.raise('Photo not found.');\n } else {\n // select rows\n // getOrderSql will not cause SQL injection\n let sql;\n\n sql = `\n select a.*,b.user_name,c.dept_name,c.dept_code from wb_staff a, wb_user b, wb_dept c\n where a.user_id=b.sid and a.dept_id=c.sid\n `;\n if (Params.searchText) {\n Wb.setLike('searchText');\n sql += ' and (a.full_name like {?searchText?} or a.code like {?searchText?})';\n } else if (Params.searchDeptId) {\n sql += ' and a.dept_id={?searchDeptId?}';\n }\n sql += Wb.getOrderSql({ email: 'a.email' });// There are 2 emails fields in the tables\n Wb.sendRowx({ sql, kv: { gender: 'gender' } }); // or Wb.sendRowx({ sql, kv: 'gender' });\n }\n}\nmain();" }, "_icon": "module" } # example/apps/oa/person.xwl Title: Person Management ```json { "title": "Person Management", "icon": "user3", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "editWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "editWin", "layout": "column", "resetDialog": "true", "width": "60em", "gap": "true", "padding": "true", "autoScroll": "true" }, "items": [ { "_icon": "fieldset", "text": "generalFieldSet", "cls": "Wb.Fieldset", "properties": { "cid": "generalFieldSet", "title": "General Information", "layout": "grid2", "collapsible": "true", "icon": "address-book", "autoGrid": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Text", "properties": { "cid": "code", "required": "true", "maxLength": "5", "text": "Code" }, "text": "code", "_expanded": true, "_icon": "text" }, { "_icon": "search-file", "text": "photo", "cls": "Wb.FileInput", "properties": { "cid": "photo", "accept": ".png", "text": "Photo", "gridRow": "span 3", "browseMode": "true", "browseHeight": "8em" } }, { "cls": "Wb.Text", "properties": { "cid": "full_name", "required": "true", "text": "Full name" }, "text": "full_name", "_expanded": true, "_icon": "text" }, { "_icon": "combo", "text": "user_name", "cls": "Wb.Select", "properties": { "cid": "user_name", "textField": "user_name", "valueField": "sid", "url": "m?xwl=sys/dialog/user-selector/select", "required": "true", "forceSelect": "true", "text": "Username", "bindField": "user_id", "subtextField": "display_name" } }, { "_icon": "combo", "text": "dept_name", "cls": "Wb.Select", "properties": { "cid": "dept_name", "url": "m?xwl=sys/dialog/dept-selector/select", "textField": "dept_name", "valueField": "sid", "clearButton": "true", "treePicker": "true", "subtextField": "dept_code", "required": "true", "text": "Dept name", "gridColumn": "span 2", "valueMap": "{ sid: 'dept_id', dept_name: 'dept_name', dept_code: 'dept_code' }" } }, { "_icon": "calendar", "text": "birth_date", "cls": "Wb.Date", "properties": { "cid": "birth_date", "text": "Birth date" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "properties": { "cid": "gender", "text": "Gender", "keyName": "gender" } }, { "_icon": "number-edit", "text": "height", "cls": "Wb.Number", "properties": { "cid": "height", "minValue": "0", "maxValue": "999", "decimalCount": "0", "text": "Height" } }, { "cls": "Wb.Text", "properties": { "cid": "email", "valueType": "email", "text": "Email" }, "text": "email", "_expanded": true, "_icon": "text" }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "decimalCount": "2", "text": "Salary" } } ] }, { "_icon": "fieldset", "text": "resumeFieldSet", "cls": "Wb.Fieldset", "_expanded": true, "properties": { "cid": "resumeFieldSet", "layout": "fit", "title": "Personal Resume", "collapsible": "true", "icon": "text1", "flex": "1" }, "items": [ { "_icon": "textarea", "text": "cv", "cls": "Wb.TextArea", "properties": { "cid": "cv", "minHeight": "10em" } } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "let deptData;\n\napp.grid1.insertRecord({\n url: xpath + '/add',\n failure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n }\n}, app.editWin);\n// set default dept\ndeptData = app.tree1.selectionData;\nif (deptData?.sid)\n app.dept_name.value = Wb.applyWith({}, deptData, 'sid,dept_code,dept_name');" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let rec = app.grid1.selection;\napp.grid1.editRecord({\n url: xpath + '/edit',\n failure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n }\n}, app.editWin);\nif (rec)\n app.editWin.down('photo').preview(xpath + '/get-photo&sid=' + rec.data.sid + '&' + Wb.getId());" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/del', 'code');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" }, "_expanded": true }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "let params;\n\nif (value)\n params = { searchText: value };\nelse\n params = { searchDeptId: app.tree1.selectionData?.sid };\napp.grid1.delayLoad({ params });" } } ] }, { "_icon": "label1", "text": "bbar", "cls": "Wb.DisplayField", "properties": { "cid": "bbar", "icon": "info1", "isProperty": "true", "value": "This module demonstrates database CRUD", "padding": "true" } }, { "_icon": "tree-view", "text": "tree1", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "tree1", "width": "18em", "url": "@xpath + '/select-dept'", "textField": "dept_name", "autoSelect": "true" }, "events": { "selectionchange": "app.grid1.load({ params: { searchDeptId: app.tree1.selectionData?.sid } });" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "code", "stateId": "wb.oa.person", "autoLoad": "false", "flex": "1" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "codeCol", "fieldName": "code", "text": "Code", "width": "5em" }, "text": "codeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "fullNameCol", "fieldName": "full_name", "text": "Full name", "width": "13em" }, "text": "fullNameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "usernameCol", "fieldName": "user_name", "text": "Username" }, "text": "usernameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "deptCol", "fieldName": "dept_name", "text": "Department", "render": "Wb.Column.addSubText(el, value, data.dept_code);", "width": "13em" }, "text": "deptCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "birthDateCol", "fieldName": "birth_date", "text": "Birth date" }, "text": "birthDateCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "genderCol", "fieldName": "gender", "text": "Gender", "width": "6em", "keyValue": "true" }, "text": "genderCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "heightCol", "fieldName": "height", "text": "Height", "width": "6em" }, "text": "heightCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "emailCol", "fieldName": "email", "text": "Email", "width": "18em" }, "text": "emailCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "salaryCol", "fieldName": "salary", "text": "Salary", "type": "usd", "width": "9em" }, "text": "salaryCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "cvCol", "fieldName": "cv", "text": "CV", "width": "15em", "sortable": "false" }, "text": "cvCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "photoCol", "fieldName": "photo", "text": "Photo", "width": "15em", "render": "if (value)\n Wb.Column.createDownload(el, column.fieldName, data.full_name + '.png');", "sortable": "false" }, "text": "photoCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # example/basic/add-tab-card.xwl Title: add-tab-card ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "card", "text": "cardTpl", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "cardTpl", "layout": "grid1", "instanced": "false" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } } ] }, { "_icon": "tab", "text": "tab1", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "tab1", "full": "true" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addNewCardItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addNewCardItem", "text": "Add New Card", "icon": "card" }, "events": { "click": "let newCard = app.cardTpl;\n\n//app.cardObject ??= app.cardTpl;\nnewCard.cid = Wb.getId(); // let card cid unique\napp.cardIndex ??= 0;\napp.cardIndex++;\nnewCard.title = 'Card ' + app.cardIndex;\nnewCard = app.tab1.add(app.cardTpl);\nnewCard.down('text1').value = 'text ' + app.cardIndex;\nnewCard.show();" } } ] } ] } ] } # example/basic/create-page.xwl Title: create-page ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Create Page", "cls": "w-title3" } }, { "_icon": "label", "text": "descLabel", "cls": "Wb.Label", "properties": { "cid": "descLabel", "text": "This example demonstrates how to create pages" } }, { "_icon": "title", "text": "staticPageTitle", "cls": "Wb.Title", "properties": { "cid": "staticPageTitle", "title": "Static page" } }, { "_icon": "label", "text": "staticPageLabel", "cls": "Wb.Label", "properties": { "cid": "staticPageLabel", "text": "Create a page by defining HTML property" } }, { "_icon": "panel", "text": "staticPagePanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "staticPagePanel", "html": "
\n
Code:
\n
10001
\n
Name:
\n
Terri Duffy
\n
Birth Date:
\n
2002/07/01
\n
Email:
\n
terri0@geejing.com
\n
" } }, { "_icon": "title", "text": "dynamicPageTitle", "cls": "Wb.Title", "properties": { "cid": "dynamicPageTitle", "title": "Dynamic page" } }, { "_icon": "label", "text": "dynamicPageLabel", "cls": "Wb.Label", "properties": { "cid": "dynamicPageLabel", "text": "Create a page by set HTML and create elements in ready event" } }, { "_icon": "panel", "text": "dynamicPagePanel", "cls": "Wb.Panel", "_expanded": false, "properties": { "cid": "dynamicPagePanel", "html": "
\n
\n
\n
\n
\n
" }, "events": { "ready": "let el = this.el, listEl;\n\n// use textContent\nel.query('[cid=title]').textContent = 'Staff form';\n// use innerHTML\nel.query('[cid=subTitle]').innerHTML = '' + new Date().dateText + '';\n// dynamic create element (Suggested)\nlistEl = el.query('[cid=list]');\nWb.ajax({\n url: 'demo-source?xaction=staffFirstRow',\n json: true,\n success(resp) {\n listEl.addEl().textContent = 'Code:';\n listEl.addEl().textContent = resp.code;\n listEl.addEl().textContent = 'Name:';\n listEl.addEl().textContent = resp.full_name;\n listEl.addEl().textContent = 'Birth Date:';\n listEl.addEl().textContent = resp.birth_date.dateValue.dateText;\n listEl.addEl().textContent = 'Email:';\n listEl.addEl().textContent = resp.email;\n }\n});" } }, { "_icon": "title", "text": "tplPageTitle", "cls": "Wb.Title", "properties": { "cid": "tplPageTitle", "title": "Template page" } }, { "_icon": "label", "text": "tplPageLabel", "cls": "Wb.Label", "properties": { "cid": "tplPageLabel", "text": "Create a page by defining tpl and update data in ready event" } }, { "_icon": "panel", "text": "tplPagePanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "tplPagePanel", "tpl": "
\n
Code:
\n
{code}
\n
Name:
\n
{full_name}
\n
Birth Date:
\n
{birth_date}
\n
Email:
\n
{email}
\n
" }, "events": { "ready": "Wb.ajax({\n url: 'demo-source?xaction=staffFirstRow',\n json: true,\n success(data) {\n app.tplPagePanel.update(data);\n }\n});" } }, { "_icon": "title", "text": "compPageTitle", "cls": "Wb.Title", "properties": { "cid": "compPageTitle", "title": "Component page" } }, { "_icon": "label", "text": "compPageLabel", "cls": "Wb.Label", "properties": { "cid": "compPageLabel", "text": "Create a page by adding components in ready event" } }, { "_icon": "panel", "text": "compPagePanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "compPagePanel", "layout": "grid1" }, "events": { "ready": "let panel = app.compPagePanel;\n\nWb.ajax({\n url: 'demo-source?xaction=staffFirstRow',\n json: true,\n success(data) {\n panel.add({ cname: 'displayField', cid: 'code', text: 'Code', value: data.code });\n panel.add({ cname: 'text', cid: 'full_name', text: 'Name', value: data.full_name });\n panel.add({ cname: 'text', cid: 'birth_date', text: 'Birth Date', value: data.birth_date });\n panel.add({ cname: 'text', cid: 'email', text: 'Email', value: data.email });\n panel.add({ cname: 'component', html: 'WebBuilder components' });\n // Wb.setValue(app.compPagePanel, data); // set compPagePanel data\n }\n});" } } ] } ] } # example/basic/custom-style.xwl Title: custom-style ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/css/demo.css\"\n]" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "column", "padding": "2em", "gap": "2em", "cls": "d-tab1" }, "_expanded": true, "items": [ { "_icon": "tab", "text": "tab1", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "tab1", "height": "10em", "cls": "d-tab1", "activeIndex": "2" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "properties": { "cid": "card1", "title": "Card 1" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "properties": { "cid": "card2", "title": "Card 2" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card 3" } }, { "_icon": "card", "text": "card4", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card4", "title": "Card 4" } }, { "_icon": "card", "text": "card5", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card5", "title": "Card 5" } } ] }, { "_icon": "desktop", "text": "viewer1", "cls": "Wb.Viewer", "properties": { "cid": "viewer1", "html": "This example demonstrates how to use CSS to customize the style of a component.\n
    \n
  1. Set \"links\" property of the \"module\" to [\"wb/css/demo.css\"].
  2. \n
  3. Set \"cls\" property of the \"tab1\" to \"w-tab1\".
  4. \n
  5. Define the CSS style for \"w-tab1\" in the file \"wb/css/demo.css\".
  6. \n
", "flex": "1" } } ] } ] } # example/basic/dashboard.xwl Title: dashboard ```json { "title": "", "icon": "", "img": "", "tags": "{newWin: true}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "theme": "false", "description": "demo-source=example/common/demo-source.xwl" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "grid": "5fr 4fr / repeat(4, 1fr)", "defaults": "({ background: false })", "background": "true", "gap": "1em", "padding": "1em" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "layout": "center", "background": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "titleType": "title3", "text": "Dashboard Title" } } ] }, { "_icon": "chart-bar", "text": "stackedAreaChart", "cls": "Wb.Chart", "properties": { "cid": "stackedAreaChart", "option": "({\n color: ['#80FFA5', '#00DDFF', '#37A2FF', '#FF0087', '#FFBF00'],\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'cross',\n label: {\n backgroundColor: '#6a7985'\n }\n }\n },\n grid: {\n left: '3%',\n right: '4%',\n bottom: '3%',\n containLabel: true\n },\n xAxis: [\n {\n type: 'category',\n boundaryGap: false,\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n }\n ],\n yAxis: [\n {\n type: 'value'\n }\n ],\n series: [\n {\n name: 'Line 1',\n type: 'line',\n stack: 'Total',\n smooth: true,\n lineStyle: {\n width: 0\n },\n showSymbol: false,\n areaStyle: {\n opacity: 0.8,\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n {\n offset: 0,\n color: 'rgb(128, 255, 165)'\n },\n {\n offset: 1,\n color: 'rgb(1, 191, 236)'\n }\n ])\n },\n emphasis: {\n focus: 'series'\n },\n data: [140, 232, 101, 264, 90, 340, 250]\n },\n {\n name: 'Line 2',\n type: 'line',\n stack: 'Total',\n smooth: true,\n lineStyle: {\n width: 0\n },\n showSymbol: false,\n areaStyle: {\n opacity: 0.8,\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n {\n offset: 0,\n color: 'rgb(0, 221, 255)'\n },\n {\n offset: 1,\n color: 'rgb(77, 119, 255)'\n }\n ])\n },\n emphasis: {\n focus: 'series'\n },\n data: [120, 282, 111, 234, 220, 340, 310]\n },\n {\n name: 'Line 3',\n type: 'line',\n stack: 'Total',\n smooth: true,\n lineStyle: {\n width: 0\n },\n showSymbol: false,\n areaStyle: {\n opacity: 0.8,\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n {\n offset: 0,\n color: 'rgb(55, 162, 255)'\n },\n {\n offset: 1,\n color: 'rgb(116, 21, 219)'\n }\n ])\n },\n emphasis: {\n focus: 'series'\n },\n data: [320, 132, 201, 334, 190, 130, 220]\n },\n {\n name: 'Line 4',\n type: 'line',\n stack: 'Total',\n smooth: true,\n lineStyle: {\n width: 0\n },\n showSymbol: false,\n areaStyle: {\n opacity: 0.8,\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n {\n offset: 0,\n color: 'rgb(255, 0, 135)'\n },\n {\n offset: 1,\n color: 'rgb(135, 0, 157)'\n }\n ])\n },\n emphasis: {\n focus: 'series'\n },\n data: [220, 402, 231, 134, 190, 230, 120]\n },\n {\n name: 'Line 5',\n type: 'line',\n stack: 'Total',\n smooth: true,\n lineStyle: {\n width: 0\n },\n showSymbol: false,\n label: {\n show: true,\n position: 'top'\n },\n areaStyle: {\n opacity: 0.8,\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n {\n offset: 0,\n color: 'rgb(255, 191, 0)'\n },\n {\n offset: 1,\n color: 'rgb(224, 62, 76)'\n }\n ])\n },\n emphasis: {\n focus: 'series'\n },\n data: [220, 302, 181, 234, 210, 290, 150]\n }\n ]\n})" }, "_expanded": true }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "column" }, "_expanded": true, "items": [ { "_icon": "chart-bar", "text": "lineChart", "cls": "Wb.Chart", "properties": { "cid": "lineChart", "option": "(f => {\n const series = [\n {\n name: 'Email',\n type: 'line',\n stack: 'Total',\n data: [120, 132, 101, 134, 90, 230, 210]\n },\n {\n name: 'Union Ads',\n type: 'line',\n stack: 'Total',\n data: [220, 182, 191, 234, 290, 330, 310]\n }\n ];\n return {\n tooltip: {\n trigger: 'axis'\n },\n grid: {\n left: '3%',\n right: '4%',\n bottom: '3%',\n containLabel: true\n },\n xAxis: {\n type: 'category',\n boundaryGap: false,\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n },\n yAxis: {\n type: 'value'\n },\n series\n };\n})()", "flex": "1" }, "_expanded": true }, { "_icon": "chart-bar", "text": "barChart", "cls": "Wb.Chart", "properties": { "cid": "barChart", "option": "({\n xAxis: {\n type: 'category',\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n },\n yAxis: {\n type: 'value'\n },\n series: [\n {\n data: [120, 200, 150, 80, 70, 110, 130],\n type: 'bar',\n showBackground: true,\n backgroundStyle: {\n color: 'rgba(180, 180, 180, 0.2)'\n }\n }\n ]\n})", "flex": "1" }, "_expanded": true } ] }, { "_icon": "chart-bar", "text": "ringChart", "cls": "Wb.Chart", "properties": { "cid": "ringChart", "option": "(f => {\n const gaugeData = [\n {\n value: 20,\n name: 'Perfect',\n title: {\n offsetCenter: ['0%', '-40%']\n },\n detail: {\n valueAnimation: true,\n offsetCenter: ['0%', '-15%']\n }\n },\n {\n value: 40,\n name: 'Good',\n title: {\n offsetCenter: ['0%', '10%']\n },\n detail: {\n valueAnimation: true,\n offsetCenter: ['0%', '35%']\n }\n }\n ];\n app.gaugeTimer = setInterval(function () {\n gaugeData[0].value = +(Math.random() * 100).toFixed(2);\n gaugeData[1].value = +(Math.random() * 100).toFixed(2);\n app.ringChart.setOption({\n series: [\n {\n data: gaugeData,\n pointer: {\n show: false\n }\n }\n ]\n });\n }, 2000);\n return {\n series: [\n {\n type: 'gauge',\n startAngle: 90,\n endAngle: -270,\n pointer: {\n show: false\n },\n progress: {\n show: true,\n overlap: false,\n roundCap: true,\n clip: false,\n itemStyle: {\n borderWidth: 1,\n borderColor: '#464646'\n }\n },\n axisLine: {\n lineStyle: {\n width: 40\n }\n },\n splitLine: {\n show: false,\n distance: 0,\n length: 10\n },\n axisTick: {\n show: false\n },\n axisLabel: {\n show: false,\n distance: 50\n },\n data: gaugeData,\n title: {\n fontSize: 14\n },\n detail: {\n width: 50,\n height: 14,\n fontSize: 14,\n color: 'inherit',\n borderColor: 'inherit',\n borderRadius: 20,\n borderWidth: 1,\n formatter: '{value}%'\n }\n }\n ]\n }\n})()" }, "_expanded": true, "events": { "destroy": "clearInterval(app.gaugeTimer);" } }, { "_icon": "chart-bar", "text": "gaugeChart", "cls": "Wb.Chart", "properties": { "cid": "gaugeChart", "option": "({\n tooltip: {\n formatter: '{a}
{b} : {c}%'\n },\n series: [\n {\n name: 'Pressure',\n type: 'gauge',\n detail: {\n formatter: '{value}'\n },\n data: [\n {\n value: 50,\n name: 'SCORE'\n }\n ]\n }\n ]\n})", "flex": "1" }, "_expanded": true }, { "_icon": "chart-bar", "text": "sunburstChart", "cls": "Wb.Chart", "properties": { "cid": "sunburstChart", "option": "(f => {\n let data = [\n {\n name: 'Grandpa',\n children: [\n {\n name: 'Uncle Leo',\n value: 15,\n children: [\n {\n name: 'Cousin Jack',\n value: 2\n },\n {\n name: 'Cousin Mary',\n value: 5,\n children: [\n {\n name: 'Jackson',\n value: 2\n }\n ]\n },\n {\n name: 'Cousin Ben',\n value: 4\n }\n ]\n },\n {\n name: 'Father',\n value: 10,\n children: [\n {\n name: 'Me',\n value: 5\n },\n {\n name: 'Brother Peter',\n value: 1\n }\n ]\n }\n ]\n },\n {\n name: 'Nancy',\n children: [\n {\n name: 'Uncle Nike',\n children: [\n {\n name: 'Cousin Betty',\n value: 1\n },\n {\n name: 'Cousin Jenny',\n value: 2\n }\n ]\n }\n ]\n }\n ];\n return {\n series: {\n type: 'sunburst',\n data: data,\n radius: [0, '90%'],\n label: {\n rotate: 'radial'\n }\n }\n }\n})()" }, "_expanded": true }, { "_icon": "grid", "text": "staffGrid", "cls": "Wb.Grid", "properties": { "cid": "staffGrid", "flex": "1", "url": "demo-source?xaction=staffAllDict", "gridColumn": "span 2", "title": "Staff List", "pagingBar": "false" }, "_expanded": false, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "nameCol", "cls": "Wb.Column", "properties": { "cid": "nameCol", "fieldName": "full_name", "text": "Name", "width": "-1" } }, { "_icon": "column", "text": "emailCol", "cls": "Wb.Column", "properties": { "cid": "emailCol", "fieldName": "email", "text": "Email", "width": "-1" } } ] } ] }, { "_icon": "chart-bar", "text": "pieChart", "cls": "Wb.Chart", "properties": { "cid": "pieChart", "option": "({\n tooltip: {\n trigger: 'item'\n },\n series: [\n {\n name: 'Access From',\n type: 'pie',\n radius: '50%',\n data: [\n { value: 1048, name: 'Search Engine' },\n { value: 735, name: 'Direct' },\n { value: 580, name: 'Email' },\n { value: 484, name: 'Union Ads' },\n { value: 300, name: 'Video Ads' }\n ],\n emphasis: {\n itemStyle: {\n shadowBlur: 10,\n shadowOffsetX: 0,\n shadowColor: 'rgba(0, 0, 0, 0.5)'\n }\n }\n }\n ]\n})", "flex": "1" }, "_expanded": true } ] } ] } # example/basic/drag-drop.xwl Title: drag-drop ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Drag and Drop", "cls": "w-title3" } }, { "_icon": "title", "text": "sortableTitle", "cls": "Wb.Title", "properties": { "cid": "sortableTitle", "title": "Items sortable" } }, { "_icon": "container", "text": "sortableCt", "cls": "Wb.Container", "properties": { "cid": "sortableCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "sortableLabel", "cls": "Wb.Label", "properties": { "cid": "sortableLabel", "text": "Please drag a button to adjust it's position" } }, { "_icon": "container", "text": "itemsSortableCt", "cls": "Wb.Container", "properties": { "cid": "itemsSortableCt", "layout": "form", "itemsSortable": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "text": "Button3" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button7", "text": "Button7" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button9", "text": "Button9" } } ] } ] }, { "_icon": "title", "text": "gridRowDragDropTitle", "cls": "Wb.Title", "properties": { "cid": "gridRowDragDropTitle", "title": "Grid row drag and drop" } }, { "_icon": "grid", "text": "commonRemoteGrid", "cls": "Wb.Grid", "properties": { "cid": "commonRemoteGrid", "height": "15em", "url": "demo-source?xaction=staffAllDict", "droppable": "true", "draggable": "true" }, "_expanded": true }, { "_icon": "title", "text": "dualDragDropTitle", "cls": "Wb.Title", "properties": { "cid": "dualDragDropTitle", "title": "Dual drag and drop" } }, { "_icon": "container", "text": "dualDragDropCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "dualDragDropCt", "layout": "row", "height": "15em", "gap": "true" }, "items": [ { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "demo-source?xaction=staffAllDict", "draggable": "true", "title": "Source Grid", "flex": "1", "droppable": "dualGroup", "multiSelect": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "column1", "rowNum": "true" }, "text": "column1", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column2", "text": "code", "fieldName": "code", "width": "6em" }, "text": "column2", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column3", "fieldName": "full_name", "text": "Full name", "width": "-1" }, "text": "column3", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "grid", "text": "grid2", "cls": "Wb.Grid", "properties": { "cid": "grid2", "droppable": "dualGroup", "title": "Drag source to here", "flex": "1", "draggable": "true", "multiSelect": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "column1", "rowNum": "true" }, "text": "column1", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column2", "text": "code", "fieldName": "code", "width": "6em" }, "text": "column2", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column3", "fieldName": "full_name", "text": "Full name", "width": "-1" }, "text": "column3", "_expanded": true, "_icon": "column" } ] } ] } ] }, { "_icon": "title", "text": "dragGridToPanelTitle", "cls": "Wb.Title", "properties": { "cid": "dragGridToPanelTitle", "title": "Drag grid to panel" } }, { "_icon": "container", "text": "dragGridToPanelCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "dragGridToPanelCt", "layout": "row", "height": "15em", "gap": "true" }, "items": [ { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "demo-source?xaction=staffAllDict", "title": "Source Grid", "flex": "1", "dropGroup": "panelGroup", "multiSelect": "true", "draggable": "true" }, "_expanded": true, "events": { "itemdrag": "// only allow odd code rows\ndraggable.allowDrop = draggable.source.every(item => parseInt(item.data.code) % 2);\ndraggable.mode = 'append'; // show append drag icon\ndraggable.autoDrop = false; // prevent default drop behavior", "itemdrop": "let items = [];\ndraggable.source.forEach(item => {\n items.push({ cname: 'text', text: item.data.full_name });\n})\nitems = app.dropPanel.add(items);\nitems[0].intoView();\nitems.each(item => item.highlight());\nWb.destroy(draggable.source); // remove source rows" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "column1", "rowNum": "true" }, "text": "column1", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column2", "text": "code", "fieldName": "code", "width": "6em" }, "text": "column2", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column3", "fieldName": "full_name", "text": "Full name", "width": "-1" }, "text": "column3", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "panel", "text": "dropPanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "dropPanel", "title": "Drag odd code rows to here", "flex": "1", "droppable": "panelGroup", "layout": "grid1" } } ] }, { "_icon": "title", "text": "asyncDragDropTitle", "cls": "Wb.Title", "properties": { "cid": "asyncDragDropTitle", "title": "Asynchronous drag and drop" } }, { "_icon": "grid", "text": "asyncDragDropGrid", "cls": "Wb.Grid", "properties": { "cid": "asyncDragDropGrid", "url": "demo-source?xaction=staffAllDict", "draggable": "{ autoDrop: false }", "droppable": "asyncGroup", "height": "15em" }, "_expanded": true, "events": { "itemdrop": "// do some server side operations\nWb.ajax({\n url: 'demo-source?xaction=staffDict',\n params: { code: draggable.source[0].data.code },\n success(resp) {\n if (resp.length)\n draggable.acceptDrop();\n else\n Wb.tipWarn('Only allow dragging odd code row.')\n }\n});" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "column1", "rowNum": "true" }, "text": "column1", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column2", "text": "code", "fieldName": "code", "width": "6em" }, "text": "column2", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "column3", "fieldName": "full_name", "text": "Full name", "width": "-1" }, "text": "column3", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # example/basic/geejing-link.xwl Title: geejing-link ```json { "title": "", "icon": "", "img": "", "tags": "{frame: true, url: 'https://www.geejing.com'}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "description": "Please select this module and click [Properties] button on the IDE toolbar to view properties of this module:\nsee parameters: {frame: true, url: 'https://www.geejing.com'}" }, "_icon": "module", "items": [] } # example/basic/grid1-form.xwl Title: grid1-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "border": "bottom" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" } } ] }, { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "Employee onboarding", "cls": "w-title3" } }, { "_icon": "title", "text": "basicInfoTitle", "cls": "Wb.Title", "properties": { "cid": "basicInfoTitle", "title": "Basic information" }, "_expanded": true }, { "_icon": "text", "text": "name", "cls": "Wb.Text", "properties": { "cid": "name", "text": "Name", "required": "true" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "_expanded": true, "properties": { "cid": "gender", "text": "Gender", "keyName": "gender", "required": "true" } }, { "_icon": "calendar", "text": "birthdate", "cls": "Wb.Date", "properties": { "cid": "birthdate", "text": "Birthdate", "required": "true" }, "_expanded": true }, { "_icon": "title", "text": "eduInfoTitle", "cls": "Wb.Title", "properties": { "cid": "eduInfoTitle", "title": "Education" }, "_expanded": true }, { "_icon": "text", "text": "degree", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "degree", "text": "Degree" } }, { "_icon": "text", "text": "university", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "university", "text": "University" } }, { "_icon": "text", "text": "major", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "major", "text": "Major" } }, { "_icon": "title", "text": "deptTitle", "cls": "Wb.Title", "properties": { "cid": "deptTitle", "title": "Department" }, "_expanded": true }, { "_icon": "text", "text": "department", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "department", "text": "Department" } }, { "_icon": "text", "text": "duty", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "duty", "text": "Duty" } }, { "_icon": "text", "text": "period", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "period", "text": "Probation period" } }, { "_icon": "calendar", "text": "entryDate", "cls": "Wb.Date", "properties": { "cid": "entryDate", "text": "Entry Date" } }, { "_icon": "text", "text": "project", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "project", "text": "Project" } }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "text": "Salary", "minValue": "1000", "prefix": "$" } }, { "_icon": "text", "text": "address", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "address", "text": "Address" } }, { "_icon": "title", "text": "commentTitle", "cls": "Wb.Title", "properties": { "cid": "commentTitle", "title": "Comments" }, "_expanded": true }, { "_icon": "textarea", "text": "office", "cls": "Wb.TextArea", "properties": { "cid": "office", "text": "Office", "height": "5em" } }, { "_icon": "textarea", "text": "manager", "cls": "Wb.TextArea", "properties": { "cid": "manager", "text": "Manager", "height": "5em" } }, { "_icon": "textarea", "text": "ceo", "cls": "Wb.TextArea", "properties": { "cid": "ceo", "text": "CEO", "height": "5em" } }, { "_icon": "button", "text": "saveBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "saveBtn", "icon": "save", "text": "Save Form", "type": "primary" }, "events": { "click": "if (Wb.verify(app.viewport1)) {\n Wb.ajax({\n url: xpath,\n comps: app.viewport1,\n success() {\n Wb.tipDone();\n }\n });\n}" } } ] } ] } # example/basic/grid3-form.xwl Title: grid3-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid3" }, "_expanded": true, "items": [ { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "Employee onboarding", "cls": "w-title3" } }, { "_icon": "title", "text": "basicInfoTitle", "cls": "Wb.Title", "properties": { "cid": "basicInfoTitle", "title": "Basic information" }, "_expanded": true }, { "_icon": "text", "text": "name", "cls": "Wb.Text", "properties": { "cid": "name", "text": "Name", "required": "true" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "_expanded": true, "properties": { "cid": "gender", "text": "Gender", "keyName": "gender", "required": "true" } }, { "_icon": "calendar", "text": "birthdate", "cls": "Wb.Date", "properties": { "cid": "birthdate", "text": "Birthdate", "required": "true" }, "_expanded": true }, { "_icon": "title", "text": "eduInfoTitle", "cls": "Wb.Title", "properties": { "cid": "eduInfoTitle", "title": "Education" }, "_expanded": true }, { "_icon": "text", "text": "degree", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "degree", "text": "Degree" } }, { "_icon": "text", "text": "university", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "university", "text": "University" } }, { "_icon": "text", "text": "major", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "major", "text": "Major" } }, { "_icon": "title", "text": "deptTitle", "cls": "Wb.Title", "properties": { "cid": "deptTitle", "title": "Department" }, "_expanded": true }, { "_icon": "text", "text": "department", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "department", "text": "Department", "gridColumn": "span 2" } }, { "_icon": "text", "text": "duty", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "duty", "text": "Duty" } }, { "_icon": "text", "text": "period", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "period", "text": "Probation period", "gridColumn": "span 2" } }, { "_icon": "calendar", "text": "entryDate", "cls": "Wb.Date", "properties": { "cid": "entryDate", "text": "Entry Date" } }, { "_icon": "text", "text": "project", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "project", "text": "Project", "gridColumn": "span 2" } }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "text": "Salary", "minValue": "1000", "prefix": "$" } }, { "_icon": "text", "text": "address", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "address", "text": "Address", "gridColumn": "span 3" } }, { "_icon": "title", "text": "commentTitle", "cls": "Wb.Title", "properties": { "cid": "commentTitle", "title": "Comments" }, "_expanded": true }, { "_icon": "textarea", "text": "office", "cls": "Wb.TextArea", "properties": { "cid": "office", "text": "Office", "gridColumn": "span 3", "height": "5em" } }, { "_icon": "textarea", "text": "manager", "cls": "Wb.TextArea", "properties": { "cid": "manager", "text": "Manager", "gridColumn": "span 3", "height": "5em" } }, { "_icon": "textarea", "text": "ceo", "cls": "Wb.TextArea", "properties": { "cid": "ceo", "text": "CEO", "gridColumn": "span 3", "height": "5em" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "icon": "save", "text": "Save Form", "type": "primary", "gridColumn": "span 3" }, "events": { "click": "Wb.ajax({\n url: xpath,\n comps: app.viewport1,\n success() {\n Wb.tipDone();\n }\n});" } } ] } ] } # example/basic/layout.xwl Title: layout ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Layout", "cls": "w-title3" } }, { "_icon": "label", "text": "descLabel", "cls": "Wb.Label", "properties": { "cid": "descLabel", "text": "Set the layout property to specify the layout of child components." } }, { "_icon": "title", "text": "rowTitle", "cls": "Wb.Title", "properties": { "cid": "rowTitle", "title": "Row" } }, { "_icon": "label", "text": "commonRowLabel", "cls": "Wb.Label", "properties": { "cid": "commonRowLabel", "text": "Common Row" } }, { "_icon": "container", "text": "rowCt", "cls": "Wb.Container", "properties": { "cid": "rowCt", "layout": "row", "frame": "true", "autoScroll": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "unsetBtn", "cls": "Wb.Button", "properties": { "cid": "unsetBtn", "text": "Unset", "minWidth": "5em" } }, { "_icon": "button", "text": "setWidthBtn", "cls": "Wb.Button", "properties": { "cid": "setWidthBtn", "text": "Set Width", "width": "10em" } }, { "_icon": "button", "text": "flex1Btn", "cls": "Wb.Button", "properties": { "cid": "flex1Btn", "text": "Flex1", "flex": "1" } }, { "_icon": "button", "text": "flex2Btn", "cls": "Wb.Button", "properties": { "cid": "flex2Btn", "text": "Flex2", "flex": "2" } }, { "_icon": "button", "text": "customFlexBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "customFlexBtn", "flex": "2 0 12em", "text": "Custom Flex" } } ] }, { "_icon": "label", "text": "autoWrapRowLabel", "cls": "Wb.Label", "properties": { "cid": "autoWrapRowLabel", "text": "Row with auto wrap" } }, { "_icon": "container", "text": "autoWrapRowCt", "cls": "Wb.Container", "properties": { "cid": "autoWrapRowCt", "layout": "row", "frame": "true", "autoScroll": "true", "flexWrap": "true", "gap": ".5em", "padding": "true", "resizable": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2", "width": "20em" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "text": "Button3", "width": "30em" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button4", "text": "Button4", "width": "40em" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button5", "text": "Button5" } } ] }, { "_icon": "label", "text": "rowWithFlexLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithFlexLabel", "text": "Row with flex" } }, { "_icon": "container", "text": "rowFlexCt", "cls": "Wb.Container", "properties": { "cid": "rowFlexCt", "layout": "row", "frame": "true", "autoScroll": "true", "padding": "true", "gap": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "unsetBtn", "cls": "Wb.Button", "properties": { "cid": "unsetBtn", "text": "Unset" } }, { "_icon": "button", "text": "setWidthBtn", "cls": "Wb.Button", "properties": { "cid": "setWidthBtn", "text": "Set Width", "width": "10em" } }, { "_icon": "button", "text": "flex1Btn", "cls": "Wb.Button", "properties": { "cid": "flex1Btn", "text": "Flex1", "flex": "1" } }, { "_icon": "button", "text": "flex2Btn", "cls": "Wb.Button", "properties": { "cid": "flex2Btn", "text": "Flex2", "flex": "2" } }, { "_icon": "button", "text": "customFlexBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "customFlexBtn", "flex": "2 0 12em", "text": "Custom Flex" } } ] }, { "_icon": "label", "text": "rowWithJustifyCenterLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithJustifyCenterLabel", "text": "Row with justify center" } }, { "_icon": "container", "text": "rowWithJustifyCenterCt", "cls": "Wb.Container", "properties": { "cid": "rowWithJustifyCenterCt", "layout": "row", "frame": "true", "autoScroll": "true", "justify": "center" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button3", "text": "Button3" } } ] }, { "_icon": "label", "text": "rowWithAlignJustifyLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithAlignJustifyLabel", "text": "Row with align and justify" } }, { "_icon": "container", "text": "rowWithAlignJustifyCt", "cls": "Wb.Container", "properties": { "cid": "rowWithAlignJustifyCt", "layout": "row", "frame": "true", "autoScroll": "true", "align": "center", "justify": "end", "height": "8em", "gap": ".5em", "padding": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1", "alignSelf": "start" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button3", "text": "Button3", "alignSelf": "end" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button4", "text": "Button4", "alignSelf": "stretch" } } ] }, { "_icon": "label", "text": "rowWithBetweenLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithBetweenLabel", "text": "Row with justify between" } }, { "_icon": "container", "text": "rowWithBetweenCt", "cls": "Wb.Container", "properties": { "cid": "rowWithBetweenCt", "layout": "row", "frame": "true", "autoScroll": "true", "align": "center", "justify": "space-between", "height": "8em", "gap": ".5em", "padding": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1", "alignSelf": "start" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button3", "text": "Button3", "alignSelf": "end" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button4", "text": "Button4", "alignSelf": "stretch" } } ] }, { "_icon": "label", "text": "rowWithAroundLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithAroundLabel", "text": "Row with justify around" } }, { "_icon": "container", "text": "rowWithAroundCt", "cls": "Wb.Container", "properties": { "cid": "rowWithAroundCt", "layout": "row", "frame": "true", "autoScroll": "true", "align": "center", "justify": "space-around", "height": "8em", "gap": ".5em", "padding": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1", "alignSelf": "start" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button3", "text": "Button3", "alignSelf": "end" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button4", "text": "Button4", "alignSelf": "stretch" } } ] }, { "_icon": "label", "text": "rowWithFillLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "rowWithFillLabel", "text": "Row with fill" } }, { "_icon": "container", "text": "rowWithFillCt", "cls": "Wb.Container", "properties": { "cid": "rowWithFillCt", "layout": "row", "frame": "true", "autoScroll": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "_expanded": false, "properties": { "cid": "fill1" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "text": "Button3" } }, { "_icon": "right1", "text": "fill2", "cls": "Wb.Fill", "_expanded": true, "properties": { "cid": "fill2" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button4", "text": "Button4" } } ] }, { "_icon": "title", "text": "columnTitle", "cls": "Wb.Title", "properties": { "cid": "columnTitle", "title": "Column" }, "_expanded": true }, { "_icon": "container", "text": "columnCt", "cls": "Wb.Container", "properties": { "cid": "columnCt", "layout": "column", "frame": "true", "autoScroll": "true", "height": "15em", "width": "15em" }, "_expanded": false, "items": [ { "_icon": "button", "text": "unsetBtn", "cls": "Wb.Button", "properties": { "cid": "unsetBtn", "text": "Unset", "minWidth": "5em" } }, { "_icon": "button", "text": "setHeightBtn", "cls": "Wb.Button", "properties": { "cid": "setHeightBtn", "text": "Set Height", "height": "3em" } }, { "_icon": "button", "text": "flex1Btn", "cls": "Wb.Button", "properties": { "cid": "flex1Btn", "text": "Flex1", "flex": "1" } }, { "_icon": "button", "text": "customFlexBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "customFlexBtn", "flex": "2 0 1em", "text": "Custom Flex" } } ] }, { "_icon": "label", "text": "plsReferRowLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "plsReferRowLabel", "text": "Please refer to the above Row demos for more Column usages" } }, { "_icon": "title", "text": "rowColBordersTitle", "cls": "Wb.Title", "properties": { "cid": "rowColBordersTitle", "title": "Row Column borders" }, "_expanded": true }, { "_icon": "container", "text": "rowColBordersCt", "cls": "Wb.Container", "properties": { "cid": "rowColBordersCt", "layout": "column", "frame": "true", "height": "20em" }, "_expanded": true, "items": [ { "_icon": "container", "text": "topCt", "cls": "Wb.Container", "properties": { "cid": "topCt", "text": "Top", "layout": "center", "height": "5em", "frame": "true" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "container", "text": "middleCt", "cls": "Wb.Container", "properties": { "cid": "middleCt", "layout": "row", "flex": "1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "container", "text": "leftCt", "cls": "Wb.Container", "properties": { "cid": "leftCt", "text": "Floatable Left", "width": "10em", "layout": "center", "frame": "true" } }, { "_icon": "splitter", "text": "splitter2", "cls": "Wb.Splitter", "properties": { "cid": "splitter2", "enterShowTarget": "true" } }, { "_icon": "container", "text": "centerCt", "cls": "Wb.Container", "properties": { "cid": "centerCt", "text": "Center", "flex": "1", "layout": "center", "frame": "true" } }, { "_icon": "splitter", "text": "splitter3", "cls": "Wb.Splitter", "properties": { "cid": "splitter3" } }, { "_icon": "container", "text": "rightCt", "cls": "Wb.Container", "properties": { "cid": "rightCt", "text": "Right", "width": "10em", "layout": "center", "frame": "true" } } ] }, { "_icon": "splitter", "text": "splitter4", "cls": "Wb.Splitter", "properties": { "cid": "splitter4" } }, { "_icon": "container", "text": "bottomCt", "cls": "Wb.Container", "properties": { "cid": "bottomCt", "text": "Bottom", "height": "5em", "layout": "center", "frame": "true" } } ] }, { "_icon": "title", "text": "formTitle", "cls": "Wb.Title", "properties": { "cid": "formTitle", "title": "Form" } }, { "_icon": "label", "text": "commonFormLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "commonFormLabel", "text": "Common Form" } }, { "_icon": "container", "text": "formCt", "cls": "Wb.Container", "properties": { "cid": "formCt", "layout": "form", "frame": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2", "width": "20em" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3", "width": "30em" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "properties": { "cid": "button7", "text": "Button7", "width": "25em" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "properties": { "cid": "button9", "text": "Button9" } } ] }, { "_icon": "label", "text": "formWithoutGapLabel", "cls": "Wb.Label", "_expanded": false, "properties": { "cid": "formWithoutGapLabel", "text": "Form without gap" } }, { "_icon": "container", "text": "formWithoutGapCt", "cls": "Wb.Container", "properties": { "cid": "formWithoutGapCt", "layout": "form", "frame": "true", "padding": "true", "gap": "false" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2", "width": "20em" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3", "width": "30em" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "properties": { "cid": "button7", "text": "Button7", "width": "25em" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "properties": { "cid": "button9", "text": "Button9" } } ] }, { "_icon": "label", "text": "form1Label", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "form1Label", "text": "Form1 with textArea vertical flex" } }, { "_icon": "container", "text": "form1Ct", "cls": "Wb.Container", "properties": { "cid": "form1Ct", "layout": "form1", "frame": "true", "height": "15em", "resizable": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text1" } }, { "_icon": "textarea", "text": "textArea1", "cls": "Wb.TextArea", "properties": { "cid": "textArea1", "text": "textArea", "flex": "1", "minHeight": "3em" } }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "properties": { "cid": "text2", "text": "text2" } } ] }, { "_icon": "title", "text": "gridTitle", "cls": "Wb.Title", "properties": { "cid": "gridTitle", "title": "Grid" } }, { "_icon": "container", "text": "gridCt", "cls": "Wb.Container", "properties": { "cid": "gridCt", "layout": "grid", "frame": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "properties": { "cid": "button7", "text": "Button7" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "properties": { "cid": "button9", "text": "Button9" } } ] }, { "_icon": "title", "text": "customGridTitle", "cls": "Wb.Title", "properties": { "cid": "customGridTitle", "title": "Grid with custom gap and padding" } }, { "_icon": "container", "text": "customGridCt", "cls": "Wb.Container", "properties": { "cid": "customGridCt", "layout": "grid", "frame": "true", "gap": ".5em", "padding": "3em" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "properties": { "cid": "button7", "text": "Button7" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "properties": { "cid": "button9", "text": "Button9" } } ] }, { "_icon": "title", "text": "grid1Title", "cls": "Wb.Title", "properties": { "cid": "grid1Title", "title": "Grid with 1 column" } }, { "_icon": "container", "text": "grid1Ct", "cls": "Wb.Container", "properties": { "cid": "grid1Ct", "layout": "grid1", "frame": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3" } } ] }, { "_icon": "title", "text": "grid5Title", "cls": "Wb.Title", "properties": { "cid": "grid5Title", "title": "Grid with 5 columns" } }, { "_icon": "container", "text": "grid5Ct", "cls": "Wb.Container", "properties": { "cid": "grid5Ct", "layout": "grid5", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Span 3", "gridColumn": "span 3" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Span 3 / 2", "gridColumn": "span 3", "gridRow": "span 2" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "properties": { "cid": "button7", "text": "Button7" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "properties": { "cid": "button8", "text": "Button8" } }, { "_icon": "button", "text": "button9", "cls": "Wb.Button", "properties": { "cid": "button9", "text": "Button9" } }, { "_icon": "component", "text": "component1", "cls": "Wb.Component", "properties": { "cid": "component1" } }, { "_icon": "button", "text": "button10", "cls": "Wb.Button", "properties": { "cid": "button10", "text": "Button10" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "button", "text": "button11", "cls": "Wb.Button", "properties": { "cid": "button11", "text": "Button11" } }, { "_icon": "button", "text": "button12", "cls": "Wb.Button", "properties": { "cid": "button12", "text": "Button12" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "properties": { "cid": "space1" } }, { "_icon": "button", "text": "button13", "cls": "Wb.Button", "properties": { "cid": "button13", "text": "Button13" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "gap": ".5em", "defaults": "({ flex: 1 })", "gridColumn": "span 2" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button14", "cls": "Wb.Button", "properties": { "cid": "button14", "text": "Sub1" } }, { "_icon": "button", "text": "button15", "cls": "Wb.Button", "properties": { "cid": "button15", "text": "Sub2" } }, { "_icon": "button", "text": "button16", "cls": "Wb.Button", "properties": { "cid": "button16", "text": "Sub3" } } ] } ] }, { "_icon": "title", "text": "gridTableStyleTitle", "cls": "Wb.Title", "properties": { "cid": "gridTableStyleTitle", "title": "Grid Table Style" } }, { "_icon": "container", "text": "gridTableStyleCt", "cls": "Wb.Container", "properties": { "cid": "gridTableStyleCt", "layout": "grid3", "frame": "true", "tableStyle": "true" }, "_expanded": false, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text1" } }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text2", "text": "text2" } }, { "_icon": "text", "text": "text3", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text3", "text": "text3" } }, { "_icon": "text", "text": "text4", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text4", "text": "text4" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "text", "text": "text5", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text5", "text": "text5" } }, { "_icon": "text", "text": "text6", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text6", "text": "text6", "gridColumn": "span 2" } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "Split Line", "dashed": "true", "dimTitle": "true" } }, { "_icon": "text", "text": "text7", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text7", "text": "text7" } }, { "_icon": "text", "text": "text8", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text8", "text": "text8" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "_expanded": true, "properties": { "cid": "space1" } }, { "_icon": "button", "text": "toggleTableStyleBtn", "cls": "Wb.Button", "properties": { "cid": "toggleTableStyleBtn", "text": "Toggle Table Style" }, "events": { "click": "app.gridTableStyleCt.tableStyle = !app.gridTableStyleCt.tableStyle;" } } ] }, { "_icon": "title", "text": "gridLastRowAutoFit", "cls": "Wb.Title", "properties": { "cid": "gridLastRowAutoFit", "title": "Grid Last Row Auto Fit" } }, { "_icon": "container", "text": "gridLastRowAutoFitCt", "cls": "Wb.Container", "properties": { "cid": "gridLastRowAutoFitCt", "layout": "grid2", "frame": "true", "gridTplRows": "auto auto 1fr", "height": "15em" }, "_expanded": false, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text1" } }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text2", "text": "text2" } }, { "_icon": "text", "text": "text3", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text3", "text": "text3" } }, { "_icon": "text", "text": "text4", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text4", "text": "text4" } }, { "_icon": "textarea", "text": "textArea1", "cls": "Wb.TextArea", "properties": { "cid": "textArea1", "gridColumn": "span 2" } } ] }, { "_icon": "title", "text": "fitTitle", "cls": "Wb.Title", "properties": { "cid": "fitTitle", "title": "Fit" } }, { "_icon": "container", "text": "fitCt", "cls": "Wb.Container", "properties": { "cid": "fitCt", "layout": "fit", "frame": "true", "height": "5em", "width": "15em", "padding": "1em" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Auto fit to container" } } ] }, { "_icon": "title", "text": "centerTitle", "cls": "Wb.Title", "properties": { "cid": "centerTitle", "title": "Center" } }, { "_icon": "label", "text": "centerDescLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "centerDescLabel", "text": "The center point of the child control is always located at the center point of the container, crop components when it overflow." } }, { "_icon": "container", "text": "centerCt", "cls": "Wb.Container", "properties": { "cid": "centerCt", "layout": "center", "frame": "true", "height": "5em", "resizable": "true", "autoScroll": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Center", "width": "20em", "height": "3em" } } ] }, { "_icon": "title", "text": "middleTitle", "cls": "Wb.Title", "properties": { "cid": "middleTitle", "title": "Middle" } }, { "_icon": "label", "text": "middleDesc", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "middleDesc", "text": "Center horizontally and vertically. Do not crop components when it overflow." } }, { "_icon": "container", "text": "middleCt", "cls": "Wb.Container", "properties": { "cid": "middleCt", "layout": "middle", "frame": "true", "height": "5em", "autoScroll": "true", "resizable": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Middle", "width": "20em", "height": "3em" } } ] }, { "_icon": "label", "text": "hmiddleDesc", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "hmiddleDesc", "text": "Center horizontally. Do not crop components when it overflow." } }, { "_icon": "container", "text": "hmiddleCt", "cls": "Wb.Container", "properties": { "cid": "hmiddleCt", "layout": "hmiddle", "frame": "true", "height": "5em", "autoScroll": "true", "resizable": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "hMiddle", "width": "20em", "height": "3em" } } ] }, { "_icon": "label", "text": "vmiddleDesc", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "vmiddleDesc", "text": "Center vertically. Do not crop components when it overflow." } }, { "_icon": "container", "text": "vmiddleCt", "cls": "Wb.Container", "properties": { "cid": "vmiddleCt", "layout": "vmiddle", "frame": "true", "height": "8em", "autoScroll": "true", "resizable": "true" }, "_expanded": false, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "vMiddle", "width": "20em", "height": "3em" } } ] } ] } ] } # example/basic/load-destroy.xwl Title: load-destroy ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n // Called after the module is loaded, regardless of whether it's a singleton.\n onLoad() {\n Wb.tip('Module is loaded')\n },\n // Called after the module is destroyed.\n onDestroy() {\n Wb.tip('Module is destroyed')\n }\n});" } } # example/basic/module-bind-ui.xwl Title: module-bind-ui ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.set({ delDisabled: !Wb.permit('example/crud/dict-edit-dialog/del') })" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "html": "
This example demonstrates how a component's \"visible\" property bind to a specified module. If the module\n is accessible, it is visible, otherwise it is hidden.
\n", "padding": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E", "bindModule": "example/crud/dict-edit-dialog/add.xwl" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J", "bindModule": "example/crud/dict-edit-dialog/edit.xwl" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D", "disabled": "_$delDisabled$_" } } ] } ] } ] } # example/basic/no-container.xwl Title: no-container ```json { "title": "", "icon": "", "img": "", "tags": "{container: false}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "main", "closeAction": "destroy", "width": "50em", "height": "20em", "title": "No container module", "visible": "true", "html": "

\n This example demonstrates that there is no default container (usually a tab card) when the module is displayed, and\n the\n entire module is automatically destroyed when the main window is closed.\n

\n

\n The module has parameters: {container: false}.\n Please click the [Properties] button to view the module parameters on the IDE.\n

", "padding": "true", "autoScroll": "true" }, "events": { "destroy": "Wb.tip('The module is destroyed.');" } } ] } # example/basic/performance.xwl Title: performance ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "autoScroll": "true", "html": "
\n

Applications built with WebBuilder are high-performance, and the client-applications and\n server-applications can be deployed separately as independent applications or merged into a single application.

\n
Client applications:
\n \n
Server applications:
\n \n
" } } ] } # example/basic/portlets/chart.xwl Title: chart ```json { "title": "", "icon": "chart-bar", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "fit" }, "items": [ { "_icon": "chart-bar", "text": "chart1", "cls": "Wb.Chart", "properties": { "cid": "chart1", "option": "({\n legend: false,\n grid: {\n left: 15,\n right: 15,\n bottom: 15,\n top: 15,\n containLabel: true\n },\n xAxis: [\n {\n type: 'category',\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n }\n ],\n yAxis: [\n {\n type: 'value'\n }\n ],\n series: [\n {\n name: 'Direct',\n type: 'bar',\n emphasis: {\n focus: 'series'\n },\n data: [320, 332, 301, 334, 390, 330, 320]\n },\n {\n name: 'Email',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 90, 230, 210]\n },\n {\n name: 'Union Ads',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [220, 182, 191, 234, 290, 330, 310]\n },\n {\n name: 'Video Ads',\n type: 'bar',\n stack: 'Ad',\n emphasis: {\n focus: 'series'\n },\n data: [150, 232, 201, 154, 190, 330, 410]\n },\n {\n name: 'Search Engine',\n type: 'bar',\n data: [862, 1018, 964, 1026, 1079, 980, 1030],\n emphasis: {\n focus: 'series'\n },\n markLine: {\n lineStyle: {\n type: 'dashed'\n },\n data: [[{ type: 'min' }, { type: 'max' }]]\n }\n },\n {\n name: 'Baidu',\n type: 'bar',\n barWidth: 5,\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [620, 732, 701, 734, 1090, 1130, 1120]\n },\n {\n name: 'Google',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 290, 230, 220]\n },\n {\n name: 'Bing',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [60, 72, 71, 74, 190, 130, 110]\n },\n {\n name: 'Others',\n type: 'bar',\n stack: 'Search Engine',\n emphasis: {\n focus: 'series'\n },\n data: [62, 82, 91, 84, 109, 110, 120]\n }\n ]\n})", "roundBorder": "true", "flex": "1" } } ] } ] } # example/basic/portlets/hint.xwl Title: hint ```json { "title": "", "icon": "info1", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "// don't show titlebar in home\n// app.noTitlebar = true;" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "html": "", "textSelectable": "false", "cls": "w-lh", "autoScroll": "true" } } ] } # example/basic/portlets/mailbox.xwl Title: mailbox ```json { "title": "", "icon": "mail", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "fit", "title": "My Emails", "icon": "mail" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "gear" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "preview" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "icon": "close" }, "events": { "click": "app.mailGrid.close();" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "flex": "1", "plainTitle": "true", "roundBorder": "true", "localData": "[\n { title: 'Quarterly Sales Report', from: 'sales@geejing.com', date: new Date().addHour(-1), unread: 1 },\n { title: 'Urgent: Action Required on Contract Amendments', from: 'legal@geejing.com', date: new Date().addHour(-2), unread: 1 },\n { title: 'Invitation to the Annual Employee Recognition Ceremony', from: 'hr@geejing.com', date: new Date().addHour(-3) },\n { title: 'Reminder: Product Launch Meeting on Tuesday', from: 'marketing@geejing.com', date: new Date().addHour(-4) },\n { title: 'Upcoming IT Maintenance', from: 'it@geejing.com', date: new Date().addHour(-5) },\n { title: 'Customer Feedback Summary', from: 'customer@geejing.com', date: new Date().addHour(-6) },\n { title: 'New Policy Implementation: Employee Travel Guidelines', from: 'management@geejing.com', date: new Date().addHour(-7) },\n { title: 'Feedback Request: Recent Website Updates', from: 'dev@geejing.com', date: new Date().addHour(-8) }\n]", "columnsSortable": "true", "sorters": "{name: 'date', desc: true}" }, "events": { "itemclick": "Wb.tip('Open email \"' + item.data.title + '\".');" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "properties": { "cid": "dateCol", "fieldName": "date", "text": "Date", "render": "el.insertCellIcon('mail', value.dateTimeText);\nel.parentNode.setCls(data.unread, 'w-bold');\nel.parentNode.cls = 'w-pointer';", "width": "15em" } }, { "_icon": "column", "text": "fromCol", "cls": "Wb.Column", "properties": { "cid": "fromCol", "fieldName": "from", "text": "From" } }, { "_icon": "column", "text": "titleCol", "cls": "Wb.Column", "properties": { "cid": "titleCol", "fieldName": "title", "text": "Title", "width": "-1" } } ] } ] } ] } ] } # example/basic/portlets/todo.xwl Title: todo ```json { "title": "", "icon": "form", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "title": "To Do List", "icon": "form" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "gear" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "share" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "icon": "close" }, "events": { "click": "app.todoView.close();" } } ] }, { "_icon": "list-view", "text": "view1", "cls": "Wb.View", "properties": { "cid": "view1", "itemTpl": "
\n
\n
{text}
\n
", "layout": "column", "data": "[\n { text: 'To complete the project report by the end of this week.', done: 1 },\n { text: 'To schedule a meeting with my team to discuss the progress of the project.', done: 1 },\n { text: 'To review the financial reports and identify any areas of concern.' },\n { text: 'To prepare a presentation for the upcoming board meeting.' },\n { text: 'To catch up on any outstanding emails and replies.' },\n { text: 'To update the company website with the latest news and announcements.' },\n { text: 'To research potential new business opportunities and identify potential markets.' },\n { text: 'To organize a training session for new employees to familiarize them with company policies and procedures.' }\n]", "flex": "1", "plainTitle": "true", "roundBorder": "true" }, "_expanded": true } ] } ] } # example/basic/render-to-html.xwl Title: render-to-html ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "array", "text": "bindComps", "cls": "Wb.Array", "properties": { "cid": "bindComps" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "instanced": "false" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "instanced": "false" } }, { "_icon": "button", "text": "makeBtn", "cls": "Wb.Button", "properties": { "cid": "makeBtn", "text": "Make", "instanced": "false" }, "events": { "click": "app.renderComp.make();" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1", "autoScroll": "true" }, "_expanded": true, "items": [ { "_icon": "title", "text": "title1", "cls": "Wb.Title", "properties": { "cid": "title1", "title": "Create comps in HTML" } }, { "_icon": "label", "text": "descLabel", "cls": "Wb.Label", "properties": { "cid": "descLabel", "text": "This example demonstrates how to create comps in HTML." } }, { "_icon": "component", "text": "renderComp", "cls": "Wb.Component", "properties": { "cid": "renderComp", "html": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
text1\n
\n
number1\n
\n
date1\n
\n
Manual make\n
\n
Set Value\n \n \n
Get Value\n
\n
\n
", "autoMake": "true" } }, { "_icon": "title", "text": "title2", "cls": "Wb.Title", "properties": { "cid": "title2", "title": "Create comp to the specified element" } }, { "_icon": "component", "text": "htmlComp", "cls": "Wb.Component", "properties": { "cid": "htmlComp", "html": "
\n
\n
Please click \"Create Date Comp\" button to create a new Date component below.
\n
\n
" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Create Date Comp", "justifySelf": "start" }, "events": { "click": "app.myDate = new Wb.Date({ owner: app.viewport1, text: 'Date', el: app.viewport1.el.query('.my-date') });\nthis.destroy(); // destroy this button" } } ] } ] } # example/basic/scrollbar.xwl Title: scrollbar ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Scrollbar", "cls": "w-title3" } }, { "_icon": "title", "text": "defaultTitle", "cls": "Wb.Title", "properties": { "cid": "defaultTitle", "title": "Overflow visible by default" } }, { "_icon": "component", "text": "defaultComp", "cls": "Wb.Component", "properties": { "cid": "defaultComp", "html": "No scrollbar by default
\nand overflow content will be displayed
\n(overflow content)", "height": "3em", "frame": "true", "margin": "0 0 1em 0", "padding": "true" } }, { "_icon": "title", "text": "overflowHiddenTitle", "cls": "Wb.Title", "properties": { "cid": "overflowHiddenTitle", "title": "Overflow hidden" } }, { "_icon": "component", "text": "overflowHiddenComp", "cls": "Wb.Component", "properties": { "cid": "overflowHiddenComp", "html": "No scrollbar
\nand overflow content will be hidden
\n(overflow content)", "height": "3em", "frame": "true", "padding": "true", "autoScroll": "false" } }, { "_icon": "title", "text": "overflowScrollTitle", "cls": "Wb.Title", "properties": { "cid": "overflowScrollTitle", "title": "Overflow scroll" } }, { "_icon": "component", "text": "overflowScrollComp", "cls": "Wb.Component", "properties": { "cid": "overflowScrollComp", "html": "Enable scrollbar
\nscrollbar is auto
\n(overflow content)", "height": "3em", "frame": "true", "padding": "true", "autoScroll": "true" } }, { "_icon": "title", "text": "overflowScrollAutoTitle", "cls": "Wb.Title", "properties": { "cid": "overflowScrollAutoTitle", "title": "Overflow scroll with auto show scrollbar" } }, { "_icon": "component", "text": "overflowScrollAutoComp", "cls": "Wb.Component", "properties": { "cid": "overflowScrollAutoComp", "html": "Enable scrollbar
\ndisplay scrollbars only when hovering
\n(overflow content)", "height": "3em", "frame": "true", "padding": "true", "autoScroll": "auto" } }, { "_icon": "title", "text": "overflowScrollNoBarTitle", "cls": "Wb.Title", "properties": { "cid": "overflowScrollNoBarTitle", "title": "Overflow scroll without show scrollbar" } }, { "_icon": "component", "text": "overflowScrollNoBarComp", "cls": "Wb.Component", "properties": { "cid": "overflowScrollNoBarComp", "html": "Enable scrollbar
\nalways hide scroll bars
\n(overflow content)", "height": "3em", "frame": "true", "padding": "true", "autoScroll": "hide" } } ] } ] } # example/basic/search-form.xwl Title: search-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "column", "background": "true", "gap": ".7em", "padding": ".7em" }, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "Search Form", "titleType": "title3" } }, { "_icon": "panel", "text": "formPanel", "cls": "Wb.Panel", "properties": { "cid": "formPanel", "layout": "row", "roundBorder": "true", "gap": "true", "padding": "true", "shrink": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Name", "placeholder": "search", "width": "15em" } }, { "_icon": "combo", "text": "select1", "cls": "Wb.Select", "properties": { "cid": "select1", "text": "Type1", "width": "15em" } }, { "_icon": "combo", "text": "select2", "cls": "Wb.Select", "properties": { "cid": "select2", "text": "Type2", "width": "15em" } }, { "_icon": "combo", "text": "select3", "cls": "Wb.Select", "properties": { "cid": "select3", "text": "Type3", "width": "15em" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "type": "primary", "text": "Search", "icon": "search", "shrinkSelf": "false" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Reset", "icon": "undo", "shrinkSelf": "false" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "demo-source?xaction=staffAllDict", "flex": "1" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "padding": "true", "gap": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "button", "text": "addBtn", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "type": "primary" } }, { "_icon": "button", "text": "editBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit" } }, { "_icon": "button", "text": "delBtn", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete" } } ] } ] } ] } ] } # example/basic/table-form.xwl Title: table-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "middle", "autoScroll": "true" }, "items": [ { "_icon": "container", "text": "gridCt", "cls": "Wb.Container", "properties": { "cid": "gridCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "Approval Form", "titleType": "title2", "textAlign": "center" } }, { "_icon": "container", "text": "formCt", "cls": "Wb.Container", "properties": { "cid": "formCt", "layout": "grid4", "tableStyle": "true", "gridTplColumns": "auto 1fr 1fr 1fr", "padding": "false", "width": "70em", "defaults": "({ labelSeparator: false })", "background": "true", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "box-label", "text": "generalLabel", "cls": "Wb.BoxLabel", "properties": { "cid": "generalLabel", "text": "General", "gridRow": "span 6", "padding": "true" } }, { "_icon": "text", "text": "name", "cls": "Wb.Text", "properties": { "cid": "name", "text": "Name", "required": "true" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "_expanded": true, "properties": { "cid": "gender", "text": "Gender", "keyName": "gender", "required": "true" } }, { "_icon": "calendar", "text": "birthdate", "cls": "Wb.Date", "properties": { "cid": "birthdate", "text": "Birthdate", "required": "true" }, "_expanded": true }, { "_icon": "text", "text": "degree", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "degree", "text": "Degree" } }, { "_icon": "text", "text": "university", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "university", "text": "University" } }, { "_icon": "text", "text": "major", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "major", "text": "Major" } }, { "_icon": "text", "text": "department", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "department", "text": "Department", "gridColumn": "span 2" } }, { "_icon": "text", "text": "duty", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "duty", "text": "Duty" } }, { "_icon": "text", "text": "period", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "period", "text": "Probation period", "gridColumn": "span 2" } }, { "_icon": "calendar", "text": "entryDate", "cls": "Wb.Date", "properties": { "cid": "entryDate", "text": "Entry Date" } }, { "_icon": "text", "text": "project", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "project", "text": "Project", "gridColumn": "span 2" } }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "text": "Salary", "minValue": "1000", "prefix": "$" } }, { "_icon": "text", "text": "address", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "address", "text": "Address", "gridColumn": "span 3" } }, { "_icon": "box-label", "text": "commentsLabel", "cls": "Wb.BoxLabel", "properties": { "cid": "commentsLabel", "text": "Comments", "gridRow": "span 3", "padding": "true" } }, { "_icon": "textarea", "text": "office", "cls": "Wb.TextArea", "properties": { "cid": "office", "text": "Office", "gridColumn": "span 3", "height": "5em" } }, { "_icon": "textarea", "text": "manager", "cls": "Wb.TextArea", "properties": { "cid": "manager", "text": "Manager", "gridColumn": "span 3", "height": "5em" } }, { "_icon": "textarea", "text": "ceo", "cls": "Wb.TextArea", "properties": { "cid": "ceo", "text": "CEO", "gridColumn": "span 3", "height": "5em" } } ] } ] } ] } ] } # example/basic/template.xwl Title: template ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Use Template", "cls": "w-title3" } }, { "_icon": "title", "text": "tplTitle", "cls": "Wb.Title", "properties": { "cid": "tplTitle", "title": "HTML template" } }, { "_icon": "component", "text": "tplComp", "cls": "Wb.Component", "properties": { "cid": "tplComp", "frame": "true", "tpl": "
\n
\n {p1}\n
Growth\n
\n
\n {[data.p2.usd]}\n
Income\n
\n
\n {p3}\n
Market\n
\n
\n {[data.p4.timeText12]}\n
Datetime\n
\n
\n {[data.p5.intText]}\n
Total\n
\n
", "cls": "w-fit", "textSelectable": "false", "tplData": "({ p1: '68.5%', p2: 325892, p3: 'Geejing', p4: new Date(), p5: 83236 })" } }, { "_icon": "button", "text": "updateTplBtn", "cls": "Wb.Button", "properties": { "cid": "updateTplBtn", "text": "Update template data", "type": "primary" }, "events": { "click": "app.tplComp.update({ p1: '56.82%', p2: 839213, p4: new Date() });" } }, { "_icon": "title", "text": "useViewTplTitle", "cls": "Wb.Title", "properties": { "cid": "useViewTplTitle", "title": "Use view template" } }, { "_icon": "list-view", "text": "tplView", "cls": "Wb.View", "properties": { "cid": "tplView", "html": "
\n
", "data": "[\n { name: 'Growth', value: '68.5%' },\n { name: 'Income', value: (325892).usd },\n { name: 'Market', value: 'Geejing' },\n { name: 'Datetime', value: new Date().timeText12 },\n { name: 'Total', value: (83236).intText }\n]", "itemTpl": "
\n {value}\n
{name}\n
", "selectColor": "none" } }, { "_icon": "button", "text": "updateViewBtn", "cls": "Wb.Button", "properties": { "cid": "updateViewBtn", "text": "Update view data", "type": "primary" }, "events": { "click": "app.tplView.data = [\n { name: 'Growth', value: '32.5%' },\n { name: 'Income', value: (48372).usd },\n { name: 'Datetime', value: new Date().timeText12 }\n]" } } ] } ] } # example/basic/visual-design.xwl Title: visual-design ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "grid1" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text1" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "number1" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button1", "text": "button" } }, { "_icon": "label", "text": "label1", "cls": "Wb.Label", "properties": { "cid": "label1", "html": "
    \n
  1. Select container control that requires visual design, such as click viewport1 node.
  2. \n
  3. Click the [UI Designer] button on the toolbar to launch the visual layout designer.
  4. \n
  5. Drag the control(or double click/Ctrl + double click) from the control tree to the designer.
  6. \n
  7. Drag the control to adjust its position.
  8. \n
" } } ] } ] } # example/basic/vue-el.xwl Title: vue-el ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n 'https://unpkg.com/element-ui/lib/theme-chalk/index.css',\n 'https://unpkg.com/vue@2/dist/vue.js',\n 'https://unpkg.com/element-ui/lib/index.js'\n]" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Cls['My.Select'] = class mySelect extends Wb.Control {\n /** @property {Element} selectEl Select dom element. */\n /** @property {Object} vue Vue object. */\n /***/\n init(configs) {\n let me = this;\n super.init(configs);\n me.selectEl = me.addEl('w-flex w-fit').addEl();\n me.vue = new Vue({\n el: me.selectEl,\n template: `\n \n \n `,\n data: {\n multiple: false,\n clearable: false,\n items: [],\n value: ''\n },\n methods: {\n handleVisibleChange(visible) {\n if (visible) {\n // ElementUI PopupManager may read zindex from Globals.zIndex++\n setTimeout(f => this.$refs.select.popperElm.style.zIndex = Globals.zIndex++);\n }\n }\n }\n });\n }\n /***/\n destroy() {\n super.destroy();\n this.vue.$destroy();\n }\n /** @property {String} - The value of the select control. */\n set value(value) {\n this.vue.value = value;\n }\n /***/\n get value() {\n return this.vue.value;\n }\n /** @property {Array} - Dropdown option list. @key */\n set items(value) {\n this.vue.items = value;\n }\n /***/\n get items() {\n return this.vue.items;\n }\n /** @property {Boolean} - Whether to include a clear button. */\n set clearable(value) {\n this.vue.clearable = value;\n }\n /***/\n get clearable() {\n return this.vue.clearable;\n }\n}" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Use Vue Element UI", "cls": "w-title3" } }, { "_icon": "label", "text": "descLabel", "cls": "Wb.Label", "properties": { "cid": "descLabel", "text": "This example demonstrates how to use third-party components, such as vue element UI. We strongly recommend that you use WebBuilder components, this example is only for demonstration purposes." } }, { "_icon": "title", "text": "tplTitle", "cls": "Wb.Title", "properties": { "cid": "tplTitle", "title": "Element Select" } }, { "_icon": "component", "text": "selectComp", "cls": "Wb.Component", "properties": { "cid": "selectComp", "cls": "w-fit" }, "events": { "ready": "let comp = this;\n\ncomp.vue = new Vue({\n el: comp.el.addEl(),\n template: `\n \n \n `,\n data() {\n return {\n options: [{\n value: 'option1',\n label: 'Golden Cake'\n }, {\n value: 'option2',\n label: 'Chocolate'\n }, {\n value: 'option3',\n label: 'Cookie'\n }, {\n value: 'option4',\n label: 'Noodles'\n }, {\n value: 'option5',\n label: 'Beef'\n }],\n value: ''\n }\n }\n});" } }, { "_icon": "button", "text": "setValueBtn", "cls": "Wb.Button", "properties": { "cid": "setValueBtn", "text": "Set Value", "justifySelf": "start" }, "events": { "click": "app.selectComp.vue.value = 'option4';" } }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "getValueBtn", "text": "Get Value", "justifySelf": "start" }, "events": { "click": "let vue = app.selectComp.vue, value = vue.value;\nWb.tip('Select value is: ' + vue.options.find(opt => opt.value == value)?.label);" } }, { "_icon": "title", "text": "encapsulateToClassTitle", "cls": "Wb.Title", "properties": { "cid": "encapsulateToClassTitle", "title": "Encapsulate into a class as a WebBuilder control" } }, { "_icon": "button", "text": "addSelectBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "addSelectBtn", "text": "Add Select Component", "justifySelf": "start" }, "events": { "click": "let comp;\n\napp.selectIndex ??= 1;\ncomp = app.selectContainer.add({\n cname: 'mySelect',\n text: 'Select ' + app.selectIndex,\n value: 'value2',\n clearable: true,\n items: [{\n value: 'value1',\n text: 'Golden Cake'\n }, {\n value: 'value2',\n text: 'Chocolate'\n }, {\n value: 'value3',\n text: 'Cookie'\n }]\n});\ncomp.focus();\ncomp.highlight();\napp.selectIndex++;" } }, { "_icon": "container", "text": "selectContainer", "cls": "Wb.Container", "properties": { "cid": "selectContainer", "layout": "grid2", "height": "10em" }, "_expanded": true }, { "_icon": "label", "text": "sourceLabel", "cls": "Wb.Label", "properties": { "cid": "sourceLabel", "text": "Source code of the class" } }, { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "properties": { "cid": "codeEditor1", "value": "// Defined in module.initialize event\nCls['My.Select'] = class mySelect extends Wb.Control {\n /** @property {Element} selectEl Select dom element. */\n /** @property {Object} vue Vue object. */\n /***/\n init(configs) {\n let me = this;\n super.init(configs);\n me.selectEl = me.addEl('w-flex w-fit').addEl();\n me.vue = new Vue({\n el: me.selectEl,\n template: `\n \n \n `,\n data: {\n multiple: false,\n clearable: false,\n items: [],\n value: ''\n },\n methods: {\n handleVisibleChange(visible) {\n if (visible) {\n // ElementUI PopupManager may read zindex from Globals.zIndex++\n setTimeout(f => this.$refs.select.popperElm.style.zIndex = Globals.zIndex++);\n }\n }\n }\n });\n }\n /***/\n destroy() {\n super.destroy();\n this.vue.$destroy();\n }\n /** @property {String} - The value of the select control. */\n set value(value) {\n this.vue.value = value;\n }\n /***/\n get value() {\n return this.vue.value;\n }\n /** @property {Array} - Dropdown option list. @key */\n set items(value) {\n this.vue.items = value;\n }\n /***/\n get items() {\n return this.vue.items;\n }\n /** @property {Boolean} - Whether to include a clear button. */\n set clearable(value) {\n this.vue.clearable = value;\n }\n /***/\n get clearable() {\n return this.vue.clearable;\n }\n}", "readonly": "true", "height": "25em" }, "_expanded": true } ] } ] } # example/basic/wizard.xwl Title: wizard ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Set buttons disabled.\n */\n setButtons() {\n let ct = app.cardCt1, activeIndex = ct.activeIndex;\n\n app.prevBtn.disabled = activeIndex == 0;\n app.nextBtn.disabled = activeIndex >= ct.items.length - 1;\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "middle", "autoScroll": "true", "background": "true" }, "_expanded": true, "items": [ { "_icon": "win-restore", "text": "cardCt1", "cls": "Wb.CardCt", "properties": { "cid": "cardCt1", "buttonAlign": "center", "width": "40em", "height": "20em", "title": "Application wizard", "icon": "database", "padding": "true", "minButtonWidth": "8em", "frame": "true", "cls": "w-limit-width" }, "events": { "ready": "app.setButtons();" }, "_expanded": true, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "text": "Step1" } }, { "_icon": "container", "text": "container2", "cls": "Wb.Container", "properties": { "cid": "container2", "text": "Step2" } }, { "_icon": "container", "text": "container3", "cls": "Wb.Container", "properties": { "cid": "container3", "text": "Step3" } }, { "_icon": "container", "text": "container4", "cls": "Wb.Container", "properties": { "cid": "container4", "text": "Step4" } }, { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Button", "events": { "click": "app.cardCt1.activeIndex--;\napp.setButtons();" }, "properties": { "cid": "prevBtn", "text": "Previous", "icon": "left4" }, "text": "prevBtn", "_expanded": true, "_icon": "button" }, { "cls": "Wb.Button", "events": { "click": "app.cardCt1.activeIndex++;\napp.setButtons();" }, "properties": { "cid": "nextBtn", "text": "Next", "icon": "right4", "iconAlign": "right" }, "text": "nextBtn", "_expanded": true, "_icon": "button" } ] } ] } ] } ] } # example/coding/client-js/common-usage.xwl Title: common-usage ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates the general usage of client JavaScript programming\n//For more resources, please visit: https://developer.mozilla.org/en-US/docs/Web/JavaScript\n\n//Open/Run modules, open windows and submit forms\nWb.open('m?xwl=admin/dbe'); //Open the database explorer module\nWb.open({ url: 'dbe', params: { foo: 'bar' }, method: 'POST' }); //Pass parameters and set method\nWb.openNormal('dbe'); //Open the database explorer module and allow the page to refresh\nWb.run({ url: 'dbe', params: { foo: 'bar' }, container: app.panel1 }); //Runs the module and displays it in the specified container\n//Run the module and dynamically add it's viewport1 to panel1 in the callback function. Owner means that viewport1 in dbe owns the\n//entire module, and destroys the entire module when viewport1 is destroyed\nWb.run({ url: 'dbe', owner: 'viewport1', success(scope) { app.panel1.add(scope.viewport1) } });\nWb.openWin('https://developer.mozilla.org/'); //Opens MDN in a new window\n//Set the parameters and method and open into the specified iframe\nWb.openWin({ url: 'dbe', params: { foo: 'bar' }, method: 'POST', target: 'myIframe' });\n//Submit the form with parameters\nWb.submit('https://www.geejing.com', { p1: 'foo', p2: new Date() });\n//Browse URL in Tab card(Wb.Tab.mainTab)\nWb.browse('https://www.geejing.com');\n\n//Download\nWb.download('m?xwl=foo/bar', { param1: 'abc' }); //Download url with parameters\nWb.downloadBlob(file1, 'myFile.txt'); //Download blob\nWb.downloadBase64(base64Text, 'myFile.dat'); //Download the Base64-encoded string as a file\n\n//Displays a dialog box containing the specified controls\nWb.prompt('My Dialog', [{ text: 'Your Name', cid: 'name' }], (values, win) => {\n Wb.tip(values.name);\n win.close();\n});\n\n//Show message\nWb.info('Hello'); //Show info\nWb.info('Hello', f => { Wb.tip('click ok') }, true); //Show HTML info\nWb.succ('Hello'); //Show succ\nWb.warn('Hello'); //Show warn\nWb.error('Hello'); //Show error\n//Displays a confirmation dialog box with OK and Cancel buttons\nWb.confirm('Are you sure you want to delete?', f => doSomething());\n//Displays a confirmation dialog box with Yes, No, and Cancel buttons\nWb.choose('Are you sure you want to save?', button => Wb.info(button));\nWb.tip('Hello'); //Show tip that is automatically close with a delay\nWb.tip('Hello', true); //Show HTML tip\nWb.tipAt('Hello', 200, 30); //Show tip at the specified location\nWb.tipSucc('Hello'); //Show succ tip\nWb.tipWarn('Hello'); //Show warn tip\nWb.tipError('Hello'); //Show error tip\nWb.toast('Hello'); //Show single tip that is automatically close with a delay in the center of the window\nWb.toast('Hello', true); //Show HTML toast\nWb.toastSucc('Hello'); //Show succ toast\nWb.toastWarn('Hello'); //Show warn succ\nWb.toastError('Hello'); //Show error succ\nWb.tipSelect(); //Show \"Please select a valid item\" tip in the local language\n\n//Load JS/MJS/CSS files\nWb.load('foo/bar.js', f => doSomething()); //Load js file\n//Load CSS/JS in a specific way\nWb.load(['file.css', 'file.js', { url: 'foo/bar', async: true, type: 'js', reload: true, autoRemove: true }], callback);\nWb.loadx('foo/bar.js').then(f => doSomething()); //Promise version of Wb.load\nWb.loadModule('wb/js/my.mjs', module => module.MyCls.doSomething()); //Load mjs module file\n\n//Access elements as components\nWb.get(div).tip = 'message'; //Gets the Wb.Component object of the specified element and sets the property\nWb.fly('my-div').hide(); //Gets a shared Wb.Component object for the specified element and makes a method call\n\n//Access, setting, and validation values\nvalues = Wb.getValue(panel1); //Get the values of all components in panel1\nvalues = Wb.getValue([panel1, viewport1], true); //Get the values of all components in panel1, viewport1\nWb.setValue(container1, { text1: 'foo', number1: 123 }); //Set the values in container1\n///Set the values to the specific component in container1, panel1\nWb.setValue([container1, panel1], { text1: 'foo', number1: 123 }, true, true);\nWb.reset(panel1); //Resets the values of all components in panel1\nWb.reset([panel1, text1], true); //Resets the values of specific components in panel1 and text1\nWb.clear(panel1); //Clears the values of all components in panel1\nWb.clear([panel1, text1], true); //Clears the values of specific components in panel1 and text1\nif (Wb.verify(panel1)) return; //Verify the values of all components in panel1\nWb.verify([panel1, date1], true, true); //Verify the values of specific components in panel1 and date1\n\n//Send requests\n//Send GET request with parameters\nWb.ajax({ url: path, params: { p1: 'abc', p2: 123 }, method: 'GET', success(resp) { doSuccess(); } });\n//Send POST request with parameters, file and blob\nWb.ajax({ url: path, params: { p1: 'abc', p2: 123, p3: file, p4: blob } });\n//Send request with form, comps and params\nWb.ajax({ url: path, form: myForm, comps: [panel1, file1], params: { foo: 'bar' } });\n//Send request with object and array parameters\nWb.ajax({ url: path, params: { object: { foo: 'bar' }, array: [1, 'abc', new Date()] } });\n//Send request with multiple parameters with the same name\nWb.ajax({ url: path, params: { myParam: Wb.markParams([1, 'abc', new Date()]) } });\n//Send request with payload data and specific header\nWb.ajax({ url: path, data: bigDataContent, header: { 'Content-Type': 'text/html;charset=utf-8' } });\n//Download file in ajax mode\nWb.ajax({ url: path, download: true });\n//Send request with object that can be auto deserialized in server side\nWb.ajax({ url: path, object: { foo: 'bar', num: 123, date: new Date() } });\n//Promise version of Wb.ajax\nWb.fetch({ url: path, params: { p1: 'abc', p2: 123 } }).then(\n result => {\n if (result.ok)\n console.log(result.response);\n else\n console.warn('failed');\n }\n);\n\n//Set the style and class of documentElement\nWb.addCls('w-cls'); //Add class\nWb.removeCls('w-cls'); //Remove class\nWb.setCls(true, 'w-cls'); //Add or remove class\nWb.toggleCls('w-cls'); //Toggle class\n\n//Some getter properties of Wb\nWb.activeComp; //The component that currently has focus\nWb.activeWindow; //The window that currently has focus\n\n//The properties and methods of Event\ne.stopEvent(); //Prevents default and stops the propagation of event\ne.stopSpread(); //Alias for Event.prototype.stopImmediatePropagation\ne.hasAssistKey; //Whether to press any of the Ctrl, Shift, Alt, or Meta keys\n\n//The methods of Function\nWb.info.delay(Wb, 1000, 'Hello'); //Show info with delay\nWb.info.delay(Wb, 1000, 'Hello World'); //Cancel pending delay and show info with delay again\nWb.warn.delays(Wb, 1000, 'Hello'); //Show warn with delay without cancel pending delay\nWb.tip.delay(Wb, 1000, 'tip'); //Show tip with delay\nWb.tip.cancelDelay(Wb); //Cancel pending tip immediately", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/client-js/control.xwl Title: control ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "wrapBorder": "0", "readonly": "true", "value": "//Access components and controls\n\n//General properties and functions\nlet text = control.text; //Get label text of the control\ncontrol.text = 'text label'; //Text label\ncontrol.html = 'html label'; //HTML label, this property is invalid after setting text property\ncontrol.width = '10em'; //Set width\ncontrol.height = 80; //Set height\ncontrol.visible = false; //Hide control\ncontrol.hide(); //Same as above\ncontrol?.hide(); //Call hide with optional chaining\ncontrol.visible = true; //Show control\ncontrol.show(); //Same as above\ncontrol.appeared = false; //Hide control(not drawn), but still affects layout as normal.\ncontrol.setAppeared(false); //Same as above\ncontrol.disabled = true; //Disable control\ncontrol.setDisabled(true); //Same as above\ncontrol.icon = 'paste'; //Set icon\ncontrol.el.cls = 'cls1 cls2'; //Add cls1, cls2 class name to control's element\ncontrol.cls = 'cls1 cls2'; //Same as above\nconrols.el.removeCls('cls1'); //Remove control's element class name\nconrols.removeCls('cls1'); //Same as above\ncontrol.el.setStyle('color', 'red'); //Set control's element style\ncontrol.setStyle('color', 'red'); //Same as above\ncontrol.el.removeStyle('color'); //Remove control's element style\ncontrol.removeStyle('color'); //Same as above\n\n//Add and delete controls\npanel.insertBefore({ cname: 'text' }, text1); //Insert a new text box before text1\npanel.insertAfter({ cname: 'text' }, text1); //Insert a new text box after text1\npanel.insert(2, { cname: 'text' }); //Insert a new text box at the specific index\npanel.add({ cname: 'button', text: 'My Button' }); //Add components at the last\npanel.addHeader({ cname: 'text' }); //Add a text box as a sub-component in the panel header\npanel.addFooter({ cname: 'text' }); //Add a text box as a sub-component in the panel footer\ncontrol.remove(); //Remove control (control is reusable)\npanel.removeAll(); //Remove all child components in panel (components are reusable)\ncontrol.destroy(); //Destroy control (Really delete)\npanel.destroyAll(); //Destroy all child components in panel (Really delete)\n\n//Event and DOM listeners\npanel.on('destroy', app.onDestroy); //Add component event\npanel.un('destroy', app.onDestroy); //Remove component event\npanel.mon('keydown', app.onKeyDown); //Add dom listeners to panel's element\npanel.mun('keydown', app.onKeyDown); //Remove dom listeners from panel's element\npanel.mon(DocEl, 'keydown', app.onKeyDown); //Add dom listeners to DocEl, the listener will be removed after panel is destroyed.\npanel.mun(DocEl, 'keydown', app.onKeyDown); //Remove dom listeners from DocEl\n\n//Traverse and find\ncontrol = app.myControl; //Down control by app\ncontrol = panel.find('nameText'); //Find direct control by cid\ncontrol = panel.find(item => item.visible && item.foo == 'bar'); //Find direct control by function\ncontrol = panel.down('myControl'); //Down control by cid\ncontrol = panel.down(item => item.visible && item.foo == 'bar'); //Down control by function\ncontrol = panel.children.myControl; //Down control by proxy \"children\"\npanel = text.up('myPanel'); //Up control by cid\npanel = text.up(item => item.visible && item.foo == 'bar'); //Up control by function\ncomps = panel.filter(fn); //Find all direct comps by function\ncomps = panel.downAll(fn); //Down all comps by function\ncomps = text.upAll(fn); //Up all comps by function\npanel.each(item => console.log(item)); // Each direct child comps\npanel.eachOwned(item => console.log(item)); // Each sub-comps\npanel.eachWhole(item => console.log(item)); //Each direct child comps and sub-comps\npanel.cascade(item => console.log(item)); //Cascade comps\npanel.bubble(item => console.log(item)); //Bubble comps\ncontrol = comp.nextSibling; //Gets comp's next sibling\ncontrol = comp.previousSibling; //Gets comp's previous sibling" } } ] } # example/coding/client-js/dom-element.xwl Title: dom-element ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "wrapBorder": "0", "readonly": "true", "value": "//This example demonstrates dom elements. Only extended members are demonstrated, and native members are described at:\n//https://developer.mozilla.org/en-US/docs/Web/API/Element\n\n//Associations between DOM elements and components\nlet buttonEl = button1.el; //Gets the DOM element associated with the button1\nlet windowEl = window1.el; //Gets the DOM element associated with the window1\nlet button1 = buttonEl.citem; //Gets the button component associated with the button element\nlet window1 = windowEl.citem; //Gets the window component associated with the window element\nlet grid = div.getClosestComp(Wb.Grid); //Get the closest Wb.Grid component that contains div\n\n//Add, delete and modify\nnewEl = parentEl.insertEl(3, 'my-class', 'span'); //Creates a new element and inserts it before the specified index element\nnewEl = parentEl.addEl('my-class'); ///Creates a new element and adds it to the last\nnewEl = parentEl.addTag('span'); //Creates a new element with specific tag and adds it to the last\nnewEl = parentEl.insertAfter(el, refEl); //Inserts a node after the specified node\nnewEl = parentEl.insertElBefore('my-class', 'span', refNode); //Creates a new element and inserts it before the specified node\nnewEl = parentEl.insertElAfter('my-class', 'span', refNode); //Creates a new element and inserts it after the specified node\ndiv.insertHtml('afterend', '
abc
') //insert HTML, alias for insertAdjacentHTML\ndiv.clearChildren(); //Empty all child nodes in the div\n\n//Element class name\nlet cls = div.cls; //Gets class name of div\ndiv.cls = 'cls1'; //Add new class name cls1 to div. Keep the old classNames.\ndiv.cls = 'cls1 cls2 cls3'; //Add new classNames cls1, cls2, cls3 to div. Keep the old classNames.\nel.addCls('my-cls'); //Add a single class name to el\nel.removeCls('my-cls'); //Remove a single class name from el\nel.removeClasses('cls1 cls2 cls3'); ///Remove multiple class names from el\nel.setCls(true, 'my-cls'); //Add or remove a single class name\nel.toggleCls('my-cls'); //Toggle a single class name\nel.containsCls('my-cls'); //Determines whether to include a class name\nel.plainIcon = true; //All icons in this element use a uniform icon color\nel.layout = 'grid3'; //Setting the layout, unlike setting the class, setting a new layout will remove the original layout\n\n//Element style\nel.setStyle('color: red'); //Set element style\nel.getStyle('color'); //Gets element style\nel.removeStyle('color'); //Remove element style\nel.computeStyle(); //Returns a list of calculated styles\nel.styleText = 'color: red; width: 10em'; //Add styles separated by semicolons to an element. Keep the old styles.\n\n//Traverse elements\ndiv.each((el, index) => console.log(el, index)); //Iterate direct child elements\ndiv.bubble(el => console.log(el)); //Bubble traverse\ndiv.bubbleParent(fn); //Bubble traverse without div self\ndiv.cascade(el => console.log(el)); //Cascade traverse\ndiv.cascadeSelf(fn); //Cascade traverse with div self\ndiv.some(el => el.cls.includes('w-disp-none')); //Determines whether there is a specific direct child element\ndiv.every(el => el.cls.includes('w-disp-none')); //Determines whether all direct child elements pass the test function\ndiv.cascadeSome(el => el.cls.includes('w-disp-none')); //Determines whether there is a specific child element\ndiv.cascadeEvery(el => el.cls.includes('w-disp-none')); //Determines whether all child elements pass the test function\ndiv.bubbleSome(el => el.cls.includes('w-disp-none')); //Determines whether there is a specific parent element\ndiv.bubbleEvery(el => el.cls.includes('w-disp-none')); //Determines whether all parent elements pass the test function\n\n//Find elements\nel = div.query('div.w-row'); //Down query the first element, alias for querySelector\nelList = div.queryAll('div.w-row'); //Down query all elements, alias for querySelectorAll\nel = div.closest('div.w-row'); //Match the closest parent element\nel = div.find('w-row'); //Down query the first child element with the specific class name\nel = div.findParent('w-row'); //Up query the first parent element with the specific class name\nelList = div.findParents('w-row'); //Up query all parent elements with the specific class name\nelList = div.filter('w-row'); //Down query all child elements with the specific class name, alias for getElementsByClassName.\nel = div.down('div.w-row'); //Down query the first element, similar to query\nelList = div.downAll(selectors); //Down query all elements, similar to queryAll\nel.downBy(fn, scope); //Down query the first element by function\nel.downAllBy(fn, scope); //Down query all elements by function\nel = div.up('div.w-row'); //Up query the first element, similar to closest\nelList = div.upAll(selectors); //Up query all elements\nel.upBy(fn, scope); //Up query the first element by function\nel.upAllBy(fn, scope); //Up query all elements by function\n\n//Animation effects\ndiv.fadeIn(); //Displays a fade-in effect\ndiv.fadeIn(e => fn(), 300); //Displays a fade-in effect for the specified duration. Execute the callback function when finished.\nWb.info('ok').el.fadeIn(); //Displays a info dialog with the fade-in effect\ndiv.fadeOut(); //Displays a fade-out effect\nwindow1.el.fadeOut(e => window1.close()); //Close the window after displaying the fade-out effect\ndiv.slideIn(); //Slide in from the left\ndiv.slideIn(true); //Slide in from the top\n//Slide in from {x: '10px', y: '5em'} for 2 seconds, and finally remove div\ndiv.slideIn({ x: 10, y: '5em', callback() { div.remove() }, duration: 2000, easing: 'ease-in-out' });\nWb.error('error').el.slideIn(); //Displays an error dialog with the slide-in effect\nel.slideOut(); //Slide out from the right side\nel.slideOut(true); //Slide out from the bottom\nSlide to {x: '10px', y: '5em'} for 2 seconds, and finally remove div\ndiv.slideOut({ x: 10, y: '5em', callback() { div.remove() }, duration: 2000, easing: 'ease-in-out' });\nwindow1.el.slideOut({ callback() { window1.close() } }) //Close the window after displaying the slide-out effect\ndiv.slideTo({ x: 10, y: '2em' }) //The element slides from the current position to the specified position\ndiv.rippleEffect(100, 200); //Generates a ripple effect at a specific location\ndiv.highlight(); //Highlight effect\ndiv.highlight('#f00'); //Highlight effect with the specific color\n\n//Size, location, appearance etc.\nrect = div.getRect(); //Gets the rect of the element, alias for getBoundingClientRect\ndiv.setRect({ x, y, width, height }); //Set the rect of the element\nel.alignTo(destEl, \"tl-bl?\"); // Aligns the element\nel.alignTo(destEl, \"bl-c\", [-8, 0]);// Aligns the element with offsets\ndiv.visible = false; //Turns off the display of an element so that it has no effect on layout.\ndiv.setVisible(false); //Same as above\ndiv.appeared = false; //The element is invisible (not drawn), but still affects layout as normal.\ndiv.setAppeared(false); //Same as above\nisVisible = div.isVisible(); //Determines whether the element is visible deeply\ndiv.show(); //Show element, same as visible = true\ndiv.hide(); //Hide element, same as visible = false\ndiv.width = '8em'; //Set width\ndiv.setWidth('8em'); //Same as above\ndiv.height = 90; //Set height\ndiv.setHeight(90); //Same as above\ndiv.x = '8em'; //Set left\ndiv.setX('8em'); //Same as above\ndiv.y = 90; //Set top\ndiv.setY(90); //Same as above\ndiv.xy = ['8em', 90]; //Set left and top\ndiv.intoView(); //Scroll div into view\ndiv.intoViewCenter(); ///Scroll div into view center\ndiv.focusOnly(); //Sets the focus on div without adjusting the scroll bar\ndiv.autoScroll = true; //Whether scrolling is allowed" } } ] } # example/coding/js/array-set.xwl Title: array-set ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates array and set. Only extended members are demonstrated, and native members are described at:\n//Array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\n//Set: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set\n\n//Add, delete and modify\narray = [1, 2];\narray.push(3); //push new item\narray.pushAll([1, 3, 5]); //All items are added to the array, output: [1, 2, 3, 1, 3, 5]\n[1, 2, 3].merge(new Set([3, 4, 5])); //array merge array/set, output: [1, 2, 3, 3, 4, 5]\narray.remove(2); //remove the first item\narray.removeAll(3); //remove all items\narray.removeFirst(item => item === 2); //remove the first item by function\narray.removeBy(item => item === 2); //remove all items by function\narray.erase(2); //remove item by item index\n[1, 2, 3].insert(0, 'a', 'b'); //Insert items at the specified index, output: [\"a\", \"b\", 1, 2, 3]\narray.pushIf(null, 'b'); //Push values without null/undefined value\n\n//Traverse\n[1, 2, 3].forEach((item, index) => console.log(item));\n[1, 2, 3].each((item, index) => { //each is similar to foreach, each can be interrupted and reversed\n console.log(item);\n if (item == 2)\n return false; //interrupted\n}, scope, true); //true means reverse traversal\n(new Set()).forEach(fn); //forEach set\n(new Set()).each(item => { console.log(item) }); //each set\n\n//Sort\n[1, 2, 3].sort();\narray = [123, 'abc', 'utf-string'];\narray.normalSort(); //Local sort\narray = [{ a: 3, b: 2 }, { a: 1, b: 4 }];\narray.normalSort('a'); //Sort by the \"a\" property\narray.normalSort(['a', 'b'], [false, true]); //Sort by the \"a\" property asc, \"b\" property desc.\narray.lowerSort('a'); //Similar to normalSort, case insensitive.\narray.mixSort('b'); //Similar to normalSort, Mix sort string, number and date locally in case-insensitive. Recommended sorting method.\n(new Set()).sort(params);\n(new Set()).normalSort(params);\n(new Set()).lowerSort(params);\n(new Set()).mixSort(params);\n\n//Prototype function\n[{ name: 'Allen' }, { name: 'Linda' }].pluck('name'); //Extracts the specified name attribute value, output: [\"Allen\", \"Linda\"]\n[1, 3, 5].diff([3, 5]); //Get difference, output: [1]\n[1, 3, 5].intersect([3, 5]); //Get intersect, output: [3,5]\n[1, { foo: 'bar' }, 5].copy(); //Shallow copy\n[1, 3, 5].equals([1, 3, 5]); //Determines whether the content is the same\n[1, 2, 1, 3].unique(); //Distinct array, output: [1, 2, 3]\n[1, 2, 3].unique([3, 4, 5]); //Distinct array, output:[1, 2, 3, 4, 5]\n['a', 'b', 'c'].unique(['d', 'b'], true); //Distinct array with subtract, output: ['a', 'c', 'd', 'b']\nindex = array.indexOf(2); //Get the index of item\nincludes = array.includes(2); //Determines whether the specified item is included\n\n//Getter properties\n[1, 2, 3].firstItem; //Return the first item\n[1, 2, 3].lastItem; //Return the last item", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/js/common-usage.xwl Title: common-usage ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates the general usage of JavaScript in client and server programming\n//For more resources, please visit: https://developer.mozilla.org/en-US/docs/Web/JavaScript\n\n//Define a class\nCls['My.pack.ClassName'] = class myClassName extends Wb.Base {\n //static class prototype property\n static foo = 'bar';\n\n //static class prototype function\n static func() {\n }\n\n //instance property\n myProp = 'xxx'\n\n //private instance property\n #privateProp = new Date();\n\n //instance prototype members(all members of \"protos\" will be added to the prototype of the class instance)\n static protos = {\n foo: 'bar',\n abc: 123\n };\n\n //constructor function\n constructor(param) {\n super(param); //call super function\n this.param = param; //add param to the class instance\n this.abc = 234; //Add class instance property abc\n this.def = 456; //Add class instance property def\n console.log(this.foo); //show prototype property foo, foo value is \"bar\"\n console.log(this.abc); //show instance property abc, abc value is \"234\"\n delete this.abc; //delete instance property abc\n console.log(this.abc); //show prototype property abc, abc value is \"123\", because there is no instance property at this time\n console.log(this.#privateProp); //show private instance property #privateProp\n this.height = 456; //use setter\n console.log(this.height); //use getter\n }\n\n //prototype function\n myFunc(param) {\n super.myFunc(param); //call super function\n }\n\n //Setter\n set height(value) {\n let me = this;\n\n if (me.height$ !== value) {\n me.height$ = value;\n me.doSomething();\n }\n }\n\n //Getter\n get height() {\n return this.height$;\n }\n}\nlet myCls = new My.pack.ClassName(); //create a new instance\n\n//Define getter and setter in app\nWb.define(app, {\n /** @property {String} - Setter description. */\n set$name(value) {\n //this is equal to app\n if (this.name$ !== value) {\n this.name$ = value;\n doSomething();\n }\n },\n /** @property {String} - Getter description. */\n get$name() {\n //this is equal to app\n return this.name$;\n },\n /**\n * Function description.\n */\n myMethod() {\n }\n});\n\n//Determines the type of value\nisString = Wb.isString(123); //Determines whether the value is a string\nisNumber = Wb.isNumber('abc'); //Determines whether the value is a number\nisNumeric = Wb.isNumeric('123'); //Determines whether the value is a numeric value\nisDate = Wb.isDate(123); //Determines whether the value is a date\nisBoolean = Wb.isBoolean('abc'); //Determines whether the value is a boolean\nisArray = Wb.isArray([1, 2, 3]); //Determines whether the value is an array\nisObject = Wb.isObject({ foo: 'bar' }); //Determines whether the value is a \"JavaScript Object\"\nisFunction = Wb.isFunction('abc'); ///Determines whether the value is a Function\nisPrimitive = Wb.isPrimitive(123); //Determines whether the value is of the narrow original type(String, Number, and Boolean)\nisIterable = Wb.isIterable([]); //Determines whether the value is traversable\nisEmpty = Wb.isEmpty({}); //Determines whether the value is empty(null, undefined, '', [], {} and other object with length 0)\n\n//Conversion of values\nstringValue = String(value); //to a string\nboolValue = Wb.parseBool('false'); //to a boolean. 'false', '0' and falsy value return false, others return true\ndateValue = Wb.parseDate('2021-3-10 15:13:12.18', 'y-MM-dd HH:mm:ss.S'); //Converts specified format text to date\nintValue = parseInt('123'); //to an integer\nfloatValue = parseFloat('1.23'); //to a float\n\n//Copies all enumerable own properties from one or more source objects to a target object. Alias for Object.assign.\nresult = Wb.apply({ abc: 123 }, { foo: 'bar' });\n//Copies non-existent properties from source objects\nresult = Wb.applyIf({ foo: 'abc' }, { foo: 'def', bar: 123 });\n//Copies non undefined/null properties from source objects\nresult = Wb.applyValue({ foo: 'abc' }, { bar: 123, more: null });\n//Copies properties from source objects with specified names\nresult = Wb.applyWith({ foo: 'abc' }, { param1: 'def', param2: 123 }, ['param2']);\n//Copies non undefined/null properties from source objects with specified names\nresult = Wb.applyValueWith({ foo: 'abc' }, { param1: 'def', param2: null }, ['param2']);\n//Copies properties from source objects without specified names\nresult = Wb.applyWithout({ foo: 'abc' }, { param1: 'def', param2: 123 }, ['param2']);\n//Copies properties from source objects and merge object\nresult = Wb.applyMerge({ a: { v1: 1, v2: 2 }, b: 'abc' }, { a: { v3: 3, v4: 4 }, c: 'xyz' });\n//Shallow copy object\nresult = Wb.copy({ abc: 123 });\n//Deep clone object\nresult = Wb.clone({ foo: 'bar', arr: [1, 2, 3] });\n//Copies object with getter/setter support\nresult = Wb.define({ get$method() { }, set$method() { } });\n\n//Encode and decode\n//Converts a JavaScript value to a JSON string. Alias for JSON.stringify.\nlet text = Wb.encode({ foo: 'bar', abc: 123 });\n//Parses a JSON string, constructing the JavaScript value or object described by the string. Alias for JSON.parse.\nlet object = Wb.decode(text);\n//Wb.encode with pretty formatting\nlet prettyText = Wb.encodePretty({ foo: 'bar' });\n//Serialize a JavaScript value to a string. The difference from Wb.encode is that it supports date encoding.\ntext = Wb.serialize({ foo: 'bar', date: new Date()});\n//Deserialize a string to a JavaScript value. The difference from Wb.decode is that it supports date decoding.\nobject = Wb.deserialize(text);\n//Encode the string to a Base64 string\nbase64Text = Wb.encodeBase64(text);\n//Decodes the Base64 string to a string\ntext = Wb.decodeBase64(base64Text);\n\n//Iterates through all members of the object\nWb.each({ abc: 123 }, (k, v) => {\n console.log(k);\n if (k == 'foo')\n return false; //Break iteration\n});\n\n//Find object\n//Find the first member name and output \"bar\"\nWb.find({ foo: 123, bar: 'abc' }, (k, v) => v === 'abc');\n//Find all member names\nWb.filter(object, fn);\n//Determines whether some members meet test condition\nWb.some({ foo: { name: 'Allen' }, bar: { name: 'Linda' } }, (k, v) => v.name == 'Linda');\n//Determines whether all members meet test condition\nWb.every({ foo: { name: 'Allen' }, bar: { name: 'Linda' } }, (k, v) => v.name == 'Linda');\n//Finds the first member name in an object that has the specified value\nWb.findKey({ a: 123 }, 123);\n\n//Down traverse\nitems = [{ param: 'one' }, { param: 'two', items: [{ param: 'three' }] }];\nWb.cascade(items, item => console.log(item.param)); //output: one, two, three\nWb.cascade(parentNode, node => console.log(node), 'childNodes'); //Traverses all child nodes of the element\nobject = { param: 'two', items: [{ param: 'three' }] };\nitems = [{ param: 'one' }, object];\nWb.down(items, item => item.param === 'two'); //Down traverses the object and find the first item\nWb.downAll(items, fn); //Down traverses the object and find all items\n\n//Up traverse\nlet items = { param: 'one', parent: { param: 'two', parent: { param: 'three' } } };\nWb.bubble(items, parent => console.log(parent.param)); //output: one, two, three\nWb.bubble(childNode, parent => console.log(parent), 'parentNode'); //Traverses all parent nodes of an element\nlet object = { param: 'two', parent: { param: 'three' } };\nlet items = { param: 'one', parent: object };\nWb.up(items, parent => parent.param === 'two'); //Up traverses the object and find the first item\nWb.upAll(items, fn); //Up traverses the object and find all items\n\n//Exception handling\ntry {\n doSomething();\n Wb.raise('error message'); //throw and Error\n} catch (e) {\n processException();\n throw e;\n} finally {\n finallyMethod();\n}\n\n//Value comparison\nWb.compare(a, b); //Intl.Collator().compare\nWb.lowerCompare(a, b); //to lowercase compare\nWb.mixCompare(a, b); //Mixed values compare, supports local comparison of UTF characters.\n\n//Value formatting\nval = Wb.format(1234, '#,##0.00'); //Format a number, output: \"1,234.00\"\nval = Wb.format('Your name is {name}', { name: 'Jeena' }); //Format a string, output: \"Your name is Jeena\"\nval = Wb.format('foo {0} bar {1} and {0}', 'abc', 123); //Format a string, output: \"foo abc bar 123 and abc\"\nval = Wb.format(new Date('2021-3-10'), 'y-MM-dd'); //Format a date, output: \"2021-03-10\"", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/js/date.xwl Title: date ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates date. Only extended members are demonstrated, and native members are described at:\n//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date\n\nlet date1 = new Date(), date2 = date1.addDay(3), date3 = date1.addDay(10);\n\n//Date add/subtract\ndate1.addMilliSec(3); //add milliseconds\ndate1.addMilliSec(-3); //Subtract milliseconds\ndate1.addSecond(3); //add seconds\ndate1.addMinute(3); //add minutes\ndate1.addHour(3); //add hours\ndate1.addDay(3); //add days\ndate1.addMonth(3); //add months\ndate1.addYear(3); //add years\n\n//Prototype functions\ndate1.equals(date2); //Determines whether the current date is equal to the specified date.\ndate1.equalsDate(date2); //Determines whether the current date is equal to the specified date, only compare date part.\ndate1.equalsMonth(date2); //Determines whether the current date is equal to the specified date, only compare year and month.\ndate2.between(date1, date3); //Determines whether the current date is between the specified start and end date.\ndate2.elapse(date1); //Gets the number of milliseconds from the current date to the specified date\n\n//Formatting\n//output like: \"2023-03-02 10:24:03.672\"\ndate1.format('y-MM-dd HH:mm:ss.S');\n//to date value in text, region independent.\ndate1.textValue;\n//equals to textValue property\ndate1.toString();\n//to local date text in 4-digit year and 2-digit month days, in some regions output: \"2021/03/09\"\ndate1.dateText;\n//to local time text in 24-hour 2-digit hours, minutes, and seconds, in some regions output: \"15:03:23\"\ndate1.timeText;\n//to local time text in 12-hour 2-digit hours, minutes, and seconds, in some regions output: \"PM 02:15:29\"\ndate1.timeText12;\n//to local date time text in 4-digit year and 2-digit month days, 24-hour 2-digit hours, minutes, and seconds,\n//in some regions output: \"2021/03/09 15:01:10\"\ndate1.dateTimeText;\n//to local date time text in 4-digit year and 2-digit month days, 14-hour 2-digit hours, minutes, and seconds,\n//in some regions output: \"2022/10/06 PM 02:17:06\"\ndate1.dateTimeText12;\n//similar to the dateTimeText property. If hours, minutes, seconds are 0, only the date part is displayed.\ndate1.autoText;\n//similar to the dateTimeText property, with 3-digit millisecond, in some regions output: \"2021/03/09 15:01:10.120\"\ndate1.dateTimeMilliText;\n//similar to the dateTimeText12 property, with 3-digit millisecond, in some regions output: \"2021/03/09 PM 02:17:06.120\"\ndate1.dateTimeMilliText12;\n\n//Getter properties\ndate1.isLeapYear; //Determines whether it is a leap year\ndate1.monthFirstDate; //Return the date of the first day of the month\ndate1.monthLastDate; //Return the date of the last day of the month\ndate1.monthDays; //Return the number of days in the month\ndate1.mondayDate; //Return the date value of the Monday of the week. Monday as the first day of the week.\ndate1.sundayDate; //Return the date value of the Sunday of the week. Sunday as the first day of the week.\ndate1.datePart; //Return the date part, the time part is set to 0.\ndate1.timePart; //Return the time part, the date part is set to \"1900-01-01\".", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/js/map.xwl Title: map ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates map. Only extended members are demonstrated, and native members are described at:\n//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\n\n//Add, delete and modify\nlet map = new Map([['key1', 'Allen'], ['key2', 'Linda']]);\nmap.set('key', 'value'); //Add or modify\nmap.remove('key'); //Delete\n\n//Traverse\nmap.forEach((v, k, map) => console.log(v));\nmap.each((k, v) => { console.log(k, v) }); //each is similar to foreach, each can be interrupted\nmap.some((k, v) => v === 'Linda'); //Like Array.some\nmap.every((k, v) => v.includes('e')); //Like Array.every\nmap.find(k => k == 'key2'); //Like Array.find\nmap.filter((k, v) => v.includes('e')); //Like Array.filter", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/js/number.xwl Title: number ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates number. Only extended members are demonstrated, and native members are described at:\n//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\n\n//General usage\n(92).snap(5); //Converts to the value closest to the specified step, output: 90\n(56).constrain(80, 90); //limit value >= minValue and value <= maxValue, output: 80\n\n//Formatting\n(12345.625).format('$#,##0.00'); //\"$12,345.63\"\n(12345.625).format('0.0###'); //\"12345.625\"\n(1.23).format('000'); //\"001\"\n(1.235).format('0.00%'); //\"1.24%\"\n(1234.5678).text; //to local text, in some regions output: \"1,234.568\"\n(1234.5678).intText; //to local integer text, in some regions output: \"1,235\"\n(1.2).floatText; //to local float text, in some regions output: \"1.2\"\n(1.2).percent; //to local percent text(2 decimal places), in some regions output: \"120.00%\"\n(1.2).percentInt; //to local percent text(no decimals), in some regions output: \"120%\"\n(1.2).percentAuto; //to local percent text(Keep up to 2 decimal places), in some regions output: \"120%\"\n\n//Currency\n(1234.5).usd; //to local USD currency text, in some regions output: \"US$1,234.50\"\n(1234.5).cny; //to local RMB currency text, in some regions output: \"¥1,234.50\"\n(1234.5).eur; //to local Euro currency text, in some regions output: \"€1,234.50\"\n(1234.5).gbp; //to local GBP currency text, in some regions output: \"£1,234.50\"\n(1234.5).jpy; //to local Yen currency text, in some regions output: \"JP¥1,235\"\n(1234.5).cad; //to local Cad currency text, in some regions output: \"CA$1,234.50\"\n(1234.5).aud; //to local Australian dollars currency text, in some regions output: \"AU$1,234.50\"\n(1234.5).hkd; //to local Hong Kong dollars currency text, in some regions output: \"HK$1,234.50\"\n\n//Byte size\n(12345678).kb; //to local KB size text, in some regions output: \"12,056 KB\"\n(12345678912).mb; //to local MB size text, in some regions output: \"11,774 MB\"\n(12345678912).fileSize; //to local MB/KB/B size text, in some regions output: \"11,774 MB\"\n\n//Getter properties\n(123.45).decimalCount; //Decimal place count", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/js/string.xwl Title: string ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates string. Only extended members are demonstrated, and native members are described at:\n//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String\n\n//General usage\n'my name is'.contains('name'); //Whether to contain \"name\", alias for String.includes\n'foo bar foo'.occur('foo'); //Gets the number of occurrences of the specified string\n'my name is: _$name$_'.replaceParams({ name: 'Allen' }); //Replaces the text using the _$name$_ syntax\n'
'.toHTML(true, true); //To HTML\n'abc, def, ghi'.splitTrim(); //Split the string and trim each item.\n\n//Formatting\n'foo {0} bar {1} and {0}'.format('abc', 123);\n'foo {value1} bar {value2}'.format({ value1: 'abc', value2: 123 });\n'23508172639'.formatGroup('???? ???? ???'); //Group formatting, output: \"2350 8172 639\"\n'abc def'.formatGroup('??-?? ?? ??'); //Group formatting, output: \"ab-cd ef\"\n'abc def'.formatGroup('?? ??'); //Group formatting, output: \"ab cd\"\n\n//Get the substring\n'foo.bar.abc'.firstItem('.'); //Gets the substring before the first specified string, output: \"foo\"\n'foo.bar.abc'.lastItem('.'); //Gets the substring after the last specified string, output: \"abc\"\n'foo.bar.abc'.beforeItem('.'); //Gets the substring before the last specified string, output: \"foo.bar\"\n'foo.bar.abc'.afterItem('.'); //Gets the substring after the first specified string, output: \"bar.abc\"\n'abc (foo) def'.getPart('(', ')'); //Gets the string between two strings, output: \"foo\"\n\n//Getter properties\n'allen'.capital; //Convert the first char to an uppercase char, output: \"Allen\"\n'
'.htmlText; //to HTML text, output: \"<div>\"\n'
\\n'.htmlLine; //to single line HTML text\n'2021-03-12 14:19:39.614'.dateValue; //to date value with format \"y-MM-dd HH:mm:ss.SSS\"", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/call-python.xwl Title: call-python ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "true", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "// Please deploy Python related jars before using these feature: https://www.geejing.com/site/python/graal.zip\n// eg: copy these jars to \"apache-tomcat/graal\" folder\n// call demo.py to get the text content of wb/system/config.json\n// pyArray = Polyglot.eval('python', '[1,2,42,4]'); // Call Python code directly\nlet result = Polyglot.evalFile('python', 'wb/modules/example/coding/server-js/demo.py');\nWb.send(result);" }, "_icon": "module" } # example/coding/server-js/common-usage.xwl Title: common-usage ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//This example demonstrates the general usage of server JavaScript programming and other language programming\n//For more resources, please visit: https://developer.mozilla.org/en-US/docs/Web/JavaScript\n\n//Acess Java classes\n//Access arbitrary Java classes starting with the \"Packages\" keyword. Not recommended.\nlet file = new Packages.java.io.File('/path');\n//Package name starts with \"com\", \"java\", \"org\", etc. can omit the \"Packages\" keyword. Not recommended.\nlet ArrayList = new java.util.ArrayList();\n//Using \"Java.type\" to get classes has higher performance and applicability. Recommended.\nlet HashMap = Java.type('java.util.HashMap');\n//Create a HashMap object, some classes like HashMap/FileUtil/IOUtils are predefined and ready to use.\nlet map = new HashMap();\n\n//Java objects to JS objects. Usually Java objects can be used directly in JS without conversion,\n//and the system will automatically convert to the corresponding type.\nstrArrType = Java.type(\"java.lang.String[]\"); //Defines the String[] type\njavaArr = new strArrType(3); //Create an array of length 3\njsArray = Java.from(javaArr); //Java array to JS array\n\n//Js objects to Java objects. Usually the system automatically converts JS objects when they are passed to Java,\n//and in some cases the conversion can be specified in the following ways:\njsArr1 = [\"a\", \"b\", \"c\"]; //Define the JS array\nstrArrType1 = Java.type(\"java.lang.String[]\"); //Define String[]\njavaArr1 = Java.to(jsArr1, strArrType1); //JS array to Java array\n\n//Java-related functions\njsJavaObj = Java.isJavaObject(123); //Determines whether it is a Java object\nisCls = Java.isType(HashMap); //Determines whether it is a Java Type\ntypeName = Java.typeName(HashMap); //Gets the class name, return: java.util.HashMap\n\n//Call overloaded Java methods\nSystem.out.println(123); //Automatically adapt parameter types\nSystem.out['println(boolean)'](true); //Explicitly specify function with Boolean parameter\nSystem.out['println(char[])']([1, 2]); //Explicitly specify function with char[] parameter\nSystem.out['println(java.lang.String)']('foo'); //Explicitly specify function with String parameter\n\n//Access to Java array/list\nObjectArray = Java.type('java.lang.Object[]');\nobjArray = new ObjectArray(3); //Create an array of length 3\nobjArray[0] = 1;\nobjArray[1] = 'abc';\nobjArray[2] = new JavaDate();\nobjArray.forEach(item => Wb.log(item)); //Iterate through the array\nobjArray.each(item => {\n Wb.log(item);\n if (item == 1)\n return false; //Break iteration\n});\nobjArray.sort(); //call native sort function\nobjArray.mixSort(); //call mixSort function, see WebBuilder docs.\n\n//Access to Java Map\nmap = new HashMap();\nmap.put('abc', 123);\nmap.put('foo', 'bar');\nabc = map.abc; //123\nmap.forEach((k, v) => Wb.log(k + '=' + v)); //Traverse the Map\nmap.each((k, v) => {\n Wb.log(k + '=' + v);\n if (k == 'abc')\n return false; //Break iteration\n});\n\n//Java String\njavaString = new (Java.type('java.lang.String'))(\"Java\");\njavaString.length === 4; //length is a property, and Java string are treatable as JS string\nbytes = javaString.getBytes('utf-8'); //Call the extended getBytes function to get the utf8 bytes of string\n\n//Java date, usually when calling the Java method, the system will automatically convert the JS date to Java date.\nDateUtil.format(new Date(), 'yyyy'); //The system automatically converts JS dates to Java dates\nnew JavaDate(new Date().getTime()); //Explicitly convert JS dates to Java dates, JavaDate is java.util.Date\n\n//Access JS objects from Java\nmap = { foo: 'bar', abc: 123 };\nJavaClass.javaMethod(map); //The map parameter implements the Map interface in Java, map.get(\"foo\") to get \"bar\"\n\n//JS Object/Array to Java org.json.JSONObject/org.json.JSONArray\njsonObject = Wb.toJava(jsObject); //Use api Wb.toJava to convert to JSONObject\njsonArray = Wb.toJava(jsArray); //Use api Wb.toJava to convert to JSONArray\njsonObject = new JSONObject(Wb.encode(jsObject)); //Convert jsObject to a string and then convert it to JSONObject\njsonArray = new JSONArray(Wb.encode(jsArray)); //Convert jsArray to a string and then convert it to JSONArray\njsonObject = new JSONObject({ foo: 'bar', abc: 123, date: new Date() });//Efficient way, js Object to JSONObject. Please note that \"new Date()\" will return \"{}\"(a JSONObject), because it is a Map in Java.\njsonArray = new JSONArray(Java.to(['abc', 123, new Date()]));//Efficient way, js Array to JSONArray. Please note that \"new Date()\" will return \"{}\"(a JSONObject), because it is a Map in Java.\n\n//Java org.json.JSONObject/org.json.JSONArray to JS Object/Array\njsObject = Wb.toJs(jsonObject); //Use api Wb.toJs to convert to Object\njsArray = Wb.toJs(jsonArray); //Use api Wb.toJs to convert to Array\narray = Wb.decode(jsonArray.toString());\nobject = Wb.decode(jsonObject.toString());\narray = Wb.getProxy(jsonArray); //Access JSONArray via proxy, when jsonArray is large, this method is efficient.\nobject = Wb.getProxy(jsonObject); //Access JSONObject via proxy, when jsonObject is large, this method is efficient.\n\n//app is a global visible object in execution-context, created at start and deleted at end\napp.myVar = 'abc'; //Add myVar to the app\nWb.run('my/file1.xwl'); //\"app.myVar\" is visible in file1.xwl\n\n//Regular traversal\narray.forEach(item => Wb.log(item));\n//Interruptible traversal\narray.each(item => {\n Wb.log(item);\n if (item == 'foo')\n return false; //Break iteration\n});\n//Suggest changing to [array.each(item => {item.method()})], avoid unexpected interruptions caused by return false\narray.each(item => item.method());\n//Traverse the object, return false to interrupt the traversal\nWb.each(object, (k, v) => {\n console.log(k, v);\n});\n//Iterate Java members\nm = Java.type('java.lang.Math')\nfor (i in m) { print(i); }\n\n//Java class extends\nJavaExt = Java.extend(Java.type(\"some.AbstractClass\"), Java.type(\"some.Interface1\"));\nimpl = new JavaExt({\n superclassMethod: function () { },\n interfaceMethod: function () { },\n toString() { return \"MyClass\"; }\n});\nimpl.superclassMethod();\nsw = new (Java.type(\"java.io.StringWriter\"));\nFilterWriterAdapter = Java.extend(Java.type(\"java.io.FilterWriter\"));\nfw = new FilterWriterAdapter(sw, {\n write: function (s, off, len) {\n }\n});\nfw_super = Java.super(fw); //call super\nfw.write(\"abc\");\n\n//Java classes variables\nnew HashMap();//HashMap is java.util.HashMap\nnew JavaDate(); //JavaDate is java.util.Date\nIOUtils.copy(source, dst); //IOUtils is org.apache.commons.io.IOUtils\n\n//Run ServerScript in Java\nresult = com.wb.graal.Executor.run(\"let a=123;return Wb.run('my/file.xwl');\"); // Run any script\nresult = com.wb.graal.Executor.execute(\"Wb.sql\", \"select * from wb_user\"); // Run Wb.sql function and get result\nresult = com.wb.graal.Executor.execute(\"Wb.loadCall\", \"wb/ss/myModule.mjs\", \"myExportFunc\", \"param1\", \"param2\"); // Call exposed function in a specified module\n\n//High frequency call JS function in Java code\nfn = new com.wb.graal.JSFunc(\"Wb.encode\");\n// fn = new com.wb.graal.JSFunc(\"Wb.encode\", request, response); // share request and response. This way, parameters can be shared\ntry {\n for (i = 0; i < 1000; i++)\n fn.execute(i);\n} finally {\n fn.close();\n}\n\n//Call other programming languages directly\n//When using other languages, please install the corresponding language first,\n//and the installation method is to run it in the bin directory of the JDK:\n//gu install python //Install python\n//gu install R //Install R\npyArray = Polyglot.eval('python', '[1,2,42,4]'); //Call Python code directly\nrArray = Polyglot.eval('R', 'runif(1000)'); //Call R code directly\nrFunc = Polyglot.evalFile('R', 'myExample.r'); //call R file\nrResult = rFunc(); //Call R function", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/database-access.xwl Title: database-access ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Access database by JDBC\nlet conn, statement, resultSet;\n\ntry {\n conn = DataSource.getConnection('wb-sqlserver');\n statement = conn.prepareStatement('select user_name from wb_user where sid=?');\n statement.setString(1, 'admin');\n resultSet = statement.executeQuery();\n while (resultSet.next()) {\n Wb.log(resultSet.getString(1));\n }\n} finally {\n //Note that the closing order is resultSet, statement, conn\n //SysUtil.close performs the close without throwing any exception\n SysUtil.close(resultSet);\n SysUtil.close(statement);\n SysUtil.close(conn);\n}\n\n//Gets the default encapsulated db connection, which is automatically closed after the execution-context is completed\n//regardless of whether an exception occurs\nconn = Wb.getConn(); //Gets a shared connection of the default database\nconn = Wb.getConn('wb-sqlserver'); //Gets the shared connection with the specified name\nconn = new Wb.Connection('wb-sqlserver'); //Create a new stand-alone connection\nconn.startTrans(); //Start transaction\nconn.startTrans('serializable'); //Start transaction with the specific isolation level\nconn.commit(); //Commit transaction\nconn.rollback(); //Rollback transaction\n\n//Run arbitrary SQL by Wb.Query and immediately release all resources except the db shared connection,\n//which is automatically closed after the execution-context is completed. See Wb.Query.run docs.\n//Result is an object composed of all results returned by SQL, including any number of return values and output parameters\nresult = Wb.sql('select * from wb_user where sid={?param1?}');\ncount = Wb.sql('delete from table1 where 1 = 0', 'wb-oracle'); //\"wb-oracle\" is the database name\nWb.sql({ sql: 'select * from table1', db: 'wb-oracle', fn(row) { process(row); } });\n//Access stored procedure, {?inParam?} is the input parameter and {*outParam*} is the output parameter\nWb.sql('{call sp({?timestamp|inParam?}, {*cursor|p1*}, {*double|3|p2*})}');\n//Perform a batch operation to insert records\nWb.sql({\n sql: 'insert into test (sid, varchar_field) values({?sid?}, {?varchar_field?})',\n params: [{ sid: 'foo', varchar_field: 'bar' }, { sid: 'abc', varchar_field: 'def' }]\n});\n//Set fn to traverse all records, and specify fn to traverse all records by default\nWb.sql({\n sql: 'select * from wb_perm', fn(item, name, index) {\n if (index > 10)\n return false; //Break traversal\n Wb.log(item)\n }\n});\n\n//Gets the first result set returned by SQL\nrows = Wb.getRows('select * from wb_user'); //Gets rows in object format\nWb.table(rows); //Display the data as a table in the IDE devtools console\nrows = Wb.getAllRows('select * from wb_user'); //Gets all rows in object format, recommend using fn parameter\nrecs = Wb.getRecords('select * from wb_user'); //Gets records in array format\nWb.table(recs);\nrecs = Wb.getAllRecords('select * from wb_user'); //Gets all records in array format, recommend using fn parameter\nWb.getRows('select * from wb_user', 'wb-oracle'); //Access the specific database\nWb.getRecords({ sql: 'select * from wb_user', db: 'wb-oracle', blob: 'text' }); //Use object as parameter configurations\n\nrow = Wb.getRow('select * from wb_user'); //Gets the first row int object format\nrec = Wb.getRecord('select * from wb_user'); //Gets the first record int array format\n\n//Gets object that includes columns metadata, rows and others, rows in object format\nrows = Wb.getRowx('select * from wb_user');\n//Gets object that includes columns metadata, records and others, records in array format\nrecs = Wb.getRecordx('select * from wb_user');\nrows = Wb.getDict('select * from wb_user'); //Gets the dictionaryized object by Wb.getRowx\nrecs = Wb.getDictRecords('select * from wb_user'); //Gets the dictionaryized object by Wb.getRecordx\n\nrs = Wb.sqlRS('select * from wb_user').resultSet; //Run SQL to get the ResultSet\nrows = Wb.sqlAll('select * from test'); //Gets rows for all values including blob values\nrows = Wb.Query.getRows(resultSet, configs); //Gets rows in object format by ResultSet\nrecords = Wb.Query.getRecords(resultSet, configs); //Gets records in array format by ResultSet\n\nWb.sendRows('select * from wb_user'); //Send the results generated by Wb.getRows\nWb.sendRow('select * from wb_user'); //Send the results generated by Wb.getRow\nWb.sendRecords('select * from wb_user'); //Send the results generated by Wb.getRecords\nWb.sendRecord('select * from wb_user'); //Send the results generated by Wb.getRecord\nWb.sendRowx('select * from wb_user'); //Send the results generated by Wb.getRowx\nWb.sendRecordx('select * from wb_user'); //Send the results generated by Wb.getRecordx\nWb.sendDict('select * from wb_user'); //Send the results generated by Wb.getDict\nWb.sendDictRecords('select * from wb_user'); //Send the results generated by Wb.getDictRecords\n\n//Use JS string template to define large SQL\nsql = `\n select user_name as Name from wb_user\n where sid='admin'\n`;\n\n//Access stored procedures\n\n//Create the following stored procedure in SQL Server:\nWb.sql(`\n create procedure test_proc\n (\n @inParam int, -- in param\n @outParam int out -- in and out param\n )\n as\n begin\n set @outParam=@inParam+2 --Returns the output parameters\n select * from wb_user --Returns ResultSet 1\n delete from wb_key where 1=0 --Returns the affected rows\n select * from wb_role --Returns ResultSet 2\n return 123 --returned value\n end\n`, 'wb-sqlserver');\n\n//Call the above test_proc procedure and get a total of 5 results:\n//including outParam, returned value, 2 ResultSets, and 1 affected row\n//Run the stored procedure using Wb.sql, {*type|name*} represents output parameter, {?type|name?} represents input parameter\n//You can also run the following SQL in [Management Tools]->[Database Explorer]:\n// {{*returnValue*}=call test_proc(3,{*outParam*})}\n//to get the return 5 results\nWb.set({ myInParam: 3 }); //Set the input parameter value\nlet result = Wb.sql('{{*returnValue*}=call test_proc({?myInParam?},{*outParam*})}', 'wb-sqlserver'); //Run sql\nWb.log(result); //Display the results in the IDE devtools console\nWb.log(result.$return[0]); //Get the first ResultSet\nWb.log(result.outParam); //Get outParam\n\n//Create the following stored procedure in Oracle:\nWb.sql(`\n CREATE OR REPLACE NONEDITIONABLE PROCEDURE USER_PROC\n (\n P_USER OUT TYPES.X_CURSOR,\n P_NAME IN VARCHAR\n )\n AS\n BEGIN\n OPEN P_USER FOR SELECT * FROM WB_USER WHERE USER_NAME = P_NAME;\n END USER_PROC;\n`, 'wb-oracle');\n//Send the first ResultSet output parameter p_user to the client\n//The \"cursor\" in {*cursor|p_user*} explicitly indicates that the output type of p_user is cursor\nWb.sendRows(`{call user_proc({*cursor|p_user*}, 'admin')}`, 'wb-oracle');\n\n//select, insert, delete, update, and synchronize\n//Insert, delete, or update the specified data to my_table in a transaction.\n//Field names starts with \"$\" are represented as old values, and field names starts without \"$\" represent new values.\nWb.sync({\n tableName: 'my_table',\n insert: [{ field1: 'ab', field2: 12 }, { field1: 'cd', field2: 34 }],\n update: [{ field1: 'newValue', $field1: 'oldValue' }],\n del: [{ $field1: 'xyz' }]\n});\n//Specify whereFields\nWb.sync({\n tableName: 'my_table',\n update: [{ field1: 'newValue', $field1: 'oldValue', $field2: 'abc' }],\n //Explicitly specify field1 and field2 as the where key fields, otherwise the system will automatically get the key fields\n whereFields: 'field1, field2'\n});\n//Perform a conditional select\nWb.sync({\n tableName: 'wb_user',\n fields: 'sid, user_name',\n select: { $sid: 'admin' }\n});\n//Downloads the specified BLOB field as a file\nWb.sync({\n tableName: 'wb_resource',\n download: { _meta: { fieldName: 'svalue', filename: 'desktop.json' }, $sid: 'admin@desktop' }\n});", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/devtools-debug.xwl Title: devtools-debug ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "html": "\n", "autoScroll": "true" }, "events": { "ready": "let div, el = this.el;\n\nif (Str.lang == 'zh-cn')\n div = el.query('[cid=lang-zh-cn]');\nelse\n div = el.query('[cid=lang-en]');\ndiv.setStyle('display', 'block');" } } ] } # example/coding/server-js/file-access.xwl Title: file-access ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Use java.io.File to acess files\nlet file = new File(Base.path, 'wb/js/wb.js'); //File = java.io.File\nlet text = FileUtils.readFileToString(file, Wb.utf8); //Use org.apache.commons.io.FileUtils.readFileToString\nWb.send(text); //Send text to the client\n\n//Use Wb.File to access files\nfile = new Wb.File(true, 'wb/js/wb.js'); //Create file object\ntext = file.text; //Re-read the file text contents\nWb.send(text); //Send text to the client\nfileHandle = file.file; //file's file property is java.io.File\n\n//Read JSON objects or arrays in a file\nWb.log(new Wb.File(true, 'wb/system/config.json').object);\n\n//Read and write files\nfile = new Wb.File(true, 'test.txt');\nfile.text = 'abc'; //Save \"abc\" to a file immediately\nfile.object = { foo: 'bar', abc: [1, 2, 3] }; //Save the JSON object or array to a file immediately\nWb.log(file.object); //Re-read the JSON object in the file\nfile.bytes = [1, 2, 3]; //Save bytes to a file immediately\nWb.log(Wb.encode(file.bytes)); //Re-read the byte array in the file\nbs = file.byteStream; //Re-read the ByteArrayInputStream in the file\nfile.stream = inputStream; //Save the inputStream to a file immediately\ninputStream = file.stream; //Re-read the buffered FileInputStream in the file\nbase64 = file.base64; ///Re-read the content represented by base64 in the file\nfile.base64 = base64; //Save the content represented by base64 to a file immediately\n\n//File name and path access\nname = file.name; //Get file name\nfile.name = name; //Set file name\nextension = file.extension; //Get file name extension\nfile.extension = extension; //Set file name extension\nnormalName = file.normalName; //Get a file name without an extension\npath = file.path; //Get file path\nrelPath = file.relPath; //Get file relative path under the application directory\n\n//Get file iist\nWb.File.listRoots(); //List root files\nfiles = file.listFiles(sortType, desc); //List files of folder\n\n//Traverse\nfile.each(f => Wb.log(f.name)); //Traverse the current directory\nfile.cascade(f => Wb.log(f)); //Iterate through all subfiles and subdirectories\nfile.cascadeSelf(f => { //Iterate include file itself\n Wb.log(f);\n if (f.name == 'myfile1.txt')\n return false; //Break traversal\n if (f.name == 'myfile2.txt')\n return null; //The remaining files in the current directory will no longer be traversed\n});\nfile.bubble(f => Wb.log(f)); //Traverse the current file/directory and all parent directories\nfile.bubbleParent(f => Wb.log(f)); //Traverse without current file/directory\n\n//File lock, only synchronous multithreaded access, and does not lock the file itself\nfile.lock(); //Thread lock\ndoSomething();\nfile.unlock(); //Unlock the thread immediately. The block will auto unlock when execution-context finished.\n\n//Others\nfile.createFile(); //Create a file\nfile.createFolder(); //Create a file\nfile.remove(); //Remove a file or folder\nexists = file.exists; //Determines whether the file exists\nlastModified = file.lastModified; //Last modified date as a numeric value\nlastModifiedDate = file.lastModifiedDate; //Last modified date\nisEqual = file1.equals(file1); //Determines whether the paths are the same\nisFile = file.isFile; //Determines whether it is a file\nisFolder = file.isFolder; //Determines whether it is a folder\nlength = file.length; //File size\nparent = file.parent; //File parent directory", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/load-modules.xwl Title: load-modules ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Loads a JS/MJS script file at the specified path. Use Wb.load method to load only once,\n//and if it is already loaded, the script will no longer be executed.\nWb.load('wb/ss/my.js'); //Load files based on the root directory of the web-app\nWb.load('./foo/bar.mjs'); //Load the foo/bar.mjs file in the current directory\nlet module = Wb.load('../foo/my.mjs'); //Load the foo/my.mjs module file in the parent directory and get exported object\nmodule.exportObject.method(); //Call the method of exportObject\n\n//Run ServerScript of the xwl module, and the ServerScript will be executed every time\nWb.run('shortcut'); //Run modules through module shortcut URL\nWb.run('my/file.xwl', {foo:'bar'}); //Run the my/file module in the module root directory and pass the parameters\nWb.run('./my/file.xwl'); //Run the my/file module in the current directory\nWb.run('../my/file'); //Run the my/file module in the parent directory (.xwl extension can be omitted)\nWb.run('m?xwl=my/file'); //Run the module through URI\nWb.log(Wb.run('myModule')); //Log the return value in myModule's ServerScript\n\n//Call the xwl module, Wb.execute/Wb.invoke differs from Wb.run in that it retrieves client script\n//Invoke the module, run the called module's ServerScript and output client script\nWb.execute('my/file');\nWb.invoke('my/file');\n//Invoke the module, run the called module's ServerScript and get the client full HTML to script variable\nlet script = Wb.invoke('my/file', params, true, false);", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/logs.xwl Title: logs ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Output to the IDE devtools console associated with the specified user.\n//These methods are recommended to show logging information\nWb.log('log'); //Output log message to IDE devtools console of current user, if current user is not available then output to the anonymous user(Config item: \"sys.ss.anonymousDebugUser\")\nWb.log('admin-log', \"admin\"); //Output log message to IDE devtools console of admin user\nWb.log('all-log', true); //Output log message to IDE devtools console of all users\nWb.info('info');\nWb.info('all-info', true);\nWb.warn('warn');\nWb.warn('all-warn', true);\nWb.error('error');\nWb.error('all-error', true);\nWb.table([{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }]); //Output table to IDE devtools console of the current user\nWb.table([{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }], true); //Output table to IDE devtools console of all users\nWb.debug('debug');\nWb.debug('all-debug', true); //Output \"debug\" to IDE devtools console of all users\n\n//Output to the IDE devtools console and the server file logs.\nWb.recordTrace('trace');\nWb.recordDebug('debug');\nWb.recordInfo('info');\nWb.recordWarn('warn');\nWb.recordError('error');\nWb.recordExcept(new Classes.NullPointerException('exception'));\nWb.recordFatal('fatal');\n\n//Output to the IDE devtools console and the server db logs.\nWb.recordInfox('info', 'myInfo');\nWb.recordWarnx('warn');\nWb.recordErrorx('error');\nWb.recordExceptx(new Classes.NullPointerException('exception'));\n\n//Output to the server logs\nLogUtil.trace('trace');\nLogUtil.trace('trace', request); //Logs object as trace and outputs to the client IDE devtools console associated with the specified session or request.\nLogUtil.debug('debug');\nLogUtil.info('info');\nLogUtil.warn('warn');\nLogUtil.error('error');\nLogUtil.except(new Classes.NullPointerException('exception'));\nLogUtil.fatal('fatal');\n\n//Output to the server db\nLogxUtil.info('info');\nLogxUtil.info('info', 'type');\nLogxUtil.info('info', 'type', request); //Logs object as information and outputs to the client IDE devtools console associated with the specified session.\nLogxUtil.warn('warn');\nLogxUtil.error('error');\nLogxUtil.except(new Classes.NullPointerException('exception'));\n\n//Output to the remote debugging devtools console\nconsole.log('log');\nconsole.info('info');\nconsole.debug('debug');\nconsole.warn('info');\nconsole.error('error')\nconsole.assert(1 == 2, 'not equal');\nconsole.clear();\nconsole.count();\nconsole.countReset();\nconsole.group();\nconsole.groupEnd();\nconsole.time();\nconsole.timeLog();\nconsole.timeEnd();\n\n//Others\nSystem.out.println('msg'); //Output to the system console\nprint('msg'); //Output to the system console and the remote debugging devtools console", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/multi-threads.xwl Title: multi-threads ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Multithreaded programming\n\n//Create a new thread and get the result returned by the thread\nlet map = Wb.startThread(params => {\n Wb.log(params.date);\n Wb.sleep(100);\n return { result: 'ok' };\n}, { foo: 'bar', abc: 123, date: new Date() });\nmap.thread.join(); //Wait for the thread\nWb.log(map.result); //Displays the results: {result: 'ok'}\n\nlet future = Wb.poolStart(params => {\n Wb.log(params.date);\n Wb.sleep(100);\n return { result: 'ok' };\n}, { foo: 'bar', abc: 123, date: new Date() });\nfuture.get(); //Wait for executing\nWb.log('ok');\n\n//Each thread has an exclusive execution-context, and the JS objects can only be accessed by the\n//current execution-context, so no concurrency control is required.\n//Concurrency control still needs to be handled when accessing Java objects, such as when accessing\n//a globally shared Java static object.\nBase.map.put('foo', 'bar'); //Add variables to the global static Java ConcurrentHashMap object\n//Add \"myVar\" to the global JS object app in the execution-context, which is visible only to the current execution-context\napp.myVar = 'value';\nWb.run('my/file1'); //Call the file1 module to safely access app.myVar\n\n//Sync lock\n//Create a lock named my.lock1, and when executed again, the code will be blocked until the lock is released\nlet lock = new Wb.Lock('my.lock1');\ntry {\n let myJavaObject = BaseMap.get('myJavaObject'); //Access BaseMap\n myJavaObject.doSomeThing(); //Execution is safe in locking\n} finally {\n lock.unlock(); //Release the lock. The block will auto unlock when execution-context finished.\n}\n\n//Execute function after the specified delay\n//Since the delayed execution method is in an independent thread and context, external variables cannot be referenced, only parameters in \"params\" can be referenced\nlet future = Wb.setTimeout(params => {\n Wb.log(params.date);\n return { result: 'ok' };\n}, 1000, { foo: 'bar', abc: 123, date: new Date() });\n// future.cancel(false); // cancel setTimeout\n\n//Execute function periodically\n//Since the execution method periodically is in an independent thread and context, external variables cannot be referenced, only parameters in \"params\" can be referenced\nlet future = Wb.setInterval(params => {\n Wb.log(params.date);\n return { result: 'ok' };\n}, 1000, { foo: 'bar', abc: 123, date: new Date() });\nWb.sleep(3000);\nfuture.cancel(false); // cancel interval", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/session.xwl Title: session ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Gets the current user session\nlet session = request.getSession();\n//Gets the current user name\nlet username = Wb.username;\n//Gets the current user ID\nlet userid = Wb.userid;\n//Gets the current user display name\nlet dispname = Wb.dispname;\n//Gets the current user role\nlet roles = Wb.roles;\n\n//Determines whether the current user can access dbe.xwl\nlet result = Wb.permit('admin/dbe.xwl');\n//Determines whether the current user contains a role\nlet hasRole = Wb.hasRole('admin');\n//Determines whether the current user contains some roles\nhasRole = Wb.hasRole(['admin', 'manager']);\n//If the specified role is not included, the specified exception information is thrown\nWb.permitRole('manager', 'Only manager is allowed');\nWb.permitRole(['manager', 'test'], 'Only manager and test are allowed');\n//If the specified role is included, the specified exception information is thrown\nWb.forbidRole('manager', 'manager is not allowed');\nWb.forbidRole(['manager', 'test'], 'manager and test are not allowed');\n\n//Gets the session list map of the specified user\nlet map = Sessions.getSessions('admin');\n//Get all the corresponding websocket sessions by user id\nlet list = Sessions.getWSSessions('admin', '$ide');", "wrapBorder": "0", "readonly": "true" } } ] } # example/coding/server-js/web-access.xwl Title: web-access ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "edit", "text": "codeEditor1", "cls": "Wb.CodeEditor", "_expanded": true, "properties": { "cid": "codeEditor1", "full": "true", "value": "//Gets the parameters submitted by the client. It is commonly used in application/x-www-form-urlencoded,\n//multipart/form-data and application/json\nlet val = Wb.get('paramName'); //Gets session attribute, request attribute and request parameters\nval = Wb.getString('paramName'); //Gets the parameter and converts it to string\nval = Wb.getBool('paramName'); //Gets the parameter and converts it to boolean\nval = Wb.getInt('paramName'); //Gets the parameter and converts it to int\nval = Wb.getFloat('paramName'); //Gets the parameter and converts it to float\nval = Wb.getDate('paramName'); //Gets the parameter and converts it to date\nval = Wb.getObject('paramName'); //Gets the parameter and converts it to Object/Array\n//Gets multiple parameters with the same name, always returning array or Java List. Example: Get multiple uploaded files\nval = Wb.getParams('paramName');\nval = Params.paramName; //Get the value through the proxy, same as Wb.get\nval = Params[name];\nlet hasParam = Wb.has('paramName'); //Determines whether the parameter exists\nlet payload = Wb.payload; //Gets the payload content of the request\nlet payloadParams = Wb.payloadParams; //Gets the application/json payload object\n\n//Set attribute values\nWb.set('paramName', 'abc'); //set \"abc\" to request attribute \"paramName\", same as request.setAttribute('paramName', 'abc');\nParams.paramName = 'abc'; //Set attribute by Proxy, same as above\nParams[name] = 'abc'; //Same as above\n\n//Send object to the client\nWb.send('text'); //Send text\nWb.send(123); //Send after converting the number to text\nWb.send(new Date()); //Send after converting the date to text\nWb.send({ foo: 'bar' }); //Send after encoding the object to text\nWb.send([1, 2, 3]); //Send after encoding the array to text\nWb.send(inputStream); //Send inputstream\nWb.send(bytes); //Send byte array\nWb.send('text', 'mySocket'); //Send text to the current user webSocket with the name \"mySocket\"\nWb.send(inputStream, 'mySocket', 'admin'); ///Send inputStream to all \"admin\" users webSocket with the name \"mySocket\"\nWb.send({ type: 'log', style: 3, data: 'msg' }, '$ide', true); //Send content to the webSocket of the IDE\n\n//Gets the uploaded file\nlet file = Wb.getParams('fileInput'); //Gets single file\nfilename = file.name; //Gets filename\nstream = file.stream; //Gets file inputstream\nsize = file.size; //Gets file size\nlet files = Wb.getParams('fileInput'); //Gets single or multiple files\nfiles.forEach(file => {\n new Wb.File(true, 'upload/' + filename).stream = file.stream; //Save the uploaded file to the specified directory\n //Set the stream to a parameter named \"myStream\". Note that the inputstream is unidirectional,\n //and if the stream is already in use, the stream pointer will point to the end of the stream.\n Params.myStream = file.stream;\n Wb.sql('insert into table values({?blob|myStream?})'); //Insert the uploaded file into the database table blob field\n});\n\n//Send HTTP requests\nlet html = Wb.submit('https://developer.mozilla.org'); //Sends a GET request to the specified URL and gets the returned content\n//Sends with parameters\nWb.submit({ url: 'http://localhost:8080/wb/m?xwl=test2', params: { foo: 'bar' } });\n//Sends with payload data\nWb.submit({ url: 'http://localhost:8080/wb/m?xwl=test2', data: payloadObject });\n//Login to the system, verify the username and password, and get the cookie token\nlet cookie = Wb.submit({\n url: 'http://localhost:8080/wb/verify', all: true, params: { username: 'admin', password: 'admin' }\n}).cookie;\n//Access module1 with login cookie token\nlet result = Wb.submit({ url: 'http://localhost:8080/wb/m?xwl=module1', cookie }, { foo: 'bar' });\n//Logout\nWb.submit({ url: 'http://localhost:8080/wb/logout', cookie });", "wrapBorder": "0", "readonly": "true" } } ] } # example/common/demo-source.xwl Title: demo-source ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n // staff dict data\n staffDict() {\n Wb.sendDict('select code, full_name from wb_staff' + Wb.getOrderSql(), 'wb,');\n },\n // staff dict data desc\n staffDictDesc() {\n Wb.sendDict('select code, full_name from wb_staff order by code desc', 'wb,');\n },\n // staff dict all data\n staffAllDict() {\n if (!this.downloadBlob())\n Wb.sendDict('select * from wb_staff' + Wb.getOrderSql(), 'wb,');\n },\n // staff rows\n staffRows() {\n Wb.sendRows('select code, full_name from wb_staff');\n },\n // staff row\n staffFirstRow() {\n Wb.sendRow(\"select * from wb_staff where code='10001'\")\n },\n // search staff rows\n staffSearch() {\n let sql;\n\n sql = 'select code, full_name, email from wb_staff';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where full_name like {?query?}';\n }\n sql += ' order by code'\n Wb.sendRows(sql);\n },\n // list continents\n listRootArea() {\n Wb.sendDict(`select * from wb_area where parent_id='0' order by area_name`);\n },\n // list areas\n listArea() {\n Wb.sendDict('select * from wb_area where parent_id={?parent_id?} order by area_name');\n },\n // list areas tree\n listAreaTree() {\n Params.sid ??= '0'; //\"0\" is root parent_id\n Wb.sendDict(`\n select area_name as text, sid as subtext, 0 as \"_checked\", area_name, sid, parent_id,\n case when (select count(*) from wb_area b where b.parent_id=a.sid)>0 then 0 else 1 end as \"_leaf\"\n from wb_area a where parent_id={?sid?} order by area_name\n `);\n },\n // list areas tree without check box\n listAreaTree1() {\n let whereClause = '';\n\n Params.sid ??= '0'; //\"0\" is root parent_id\n if (Params.query) {\n Wb.setLike('query');\n whereClause = 'area_name like {?query?}';\n } else {\n whereClause = 'parent_id={?sid?}'\n }\n Wb.sendDict(`\n select area_name as text, sid as subtext, area_name, sid, parent_id,\n case when (select count(*) from wb_area b where b.parent_id=a.sid)>0 then 0 else 1 end as \"_leaf\"\n from wb_area a where ${whereClause} order by area_name\n `);\n },\n // search areas rows\n areaSearch() {\n let sql;\n\n sql = 'select * from wb_area';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where sid like {?query?}';\n }\n Wb.sendRows(sql);\n },\n // Database side pagination\n staffDbPaging() {\n if (this.downloadBlob())\n return;\n\n // auto database-side paging for simple sql\n // Wb.sendDict({ sql: 'select * from wb_staff', paging: 'db', dict: 'wb' });\n\n // For demonstration purposes, database-side pagination is implemented manually below\n let db = Wb.getConn();\n\n if (db.match('derby')) {\n // For derby only, some paging parameter: _from, _to, _size\n Wb.sendDict({\n sql: 'select * from wb_staff offset {?bigint|_from?} rows fetch first {?bigint|_size?} rows only',\n db, dict: 'wb', paging: false /* stop app serverside paging */, total: 'select count(*) from wb_staff'\n });\n } else {\n // For other database pagination SQL, please refer to their respective manuals\n // Other databases here do not use database pagination\n Wb.sendDict({ sql: 'select * from wb_staff', db, dict: 'wb' })\n }\n },\n // Perform download if necessary.\n downloadBlob() {\n let download = Wb.getObject('download');\n if (download) {\n //download blob\n let row = Wb.getRow({\n sql: 'select full_name, photo from wb_staff where sid={?$sid?}',\n blob: true,\n params: download\n });\n if (row?.photo)\n Wb.exportData(row.photo, row.full_name + '.png');\n else\n Wb.raise('Photo not found.');\n return true;\n } else\n return false;\n },\n // Check username\n checkUser() {\n Wb.send(Wb.getRow('select 1 from wb_user where user_name={?username?}') ? 'failed' : 'ok');\n },\n // Select admin from staff\n selectAdminStaff() {\n let sql;\n\n sql = \"select sid,full_name as text,code as subtext from wb_staff where user_id='admin'\";\n if (Params.search) {\n Wb.setLike('search');\n sql += ' and full_name like {?search?}';\n }\n Wb.sendRowx(sql);\n },\n // Select none admin from staff\n selectNoneAdminStaff() {\n let sql;\n\n sql = \"select sid,full_name as text,code as subtext from wb_staff where user_id<>'admin'\";\n if (Params.search) {\n Wb.setLike('search');\n sql += ' and full_name like {?search?}';\n }\n Wb.sendRowx(sql);\n },\n // Select report1\n selectReport1() {\n Wb.sendRowx('select * from wb_report_demo1')\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/comps/button.xwl Title: button ```json { "title": "", "icon": "button", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "finalize": "app.useIdeTipField.highlight();" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Button", "cls": "w-title3" } }, { "_icon": "label1", "text": "useIdeTipField", "cls": "Wb.DisplayField", "properties": { "cid": "useIdeTipField", "icon": "info", "htmlValue": "true", "value": "For a better learning experience, please review the examples in the WebBuilder IDE" }, "events": { "ready": "if (parentApp?.inIDE)\n this.hide();" } }, { "_icon": "title", "text": "listTitle", "cls": "Wb.Title", "properties": { "cid": "listTitle", "title": "Button list" } }, { "_icon": "container", "text": "listCt", "cls": "Wb.Container", "properties": { "cid": "listCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "commonBtn", "cls": "Wb.Button", "properties": { "cid": "commonBtn", "text": "Common Button" }, "events": { "click": "Wb.tip(this.cid + ' clicked'); // equals to: Wb.tip(app.commonBtn.cid + ' clicked');" } }, { "_icon": "button", "text": "iconBtn", "cls": "Wb.Button", "properties": { "cid": "iconBtn", "text": "Icon Button", "icon": "gear" } }, { "_icon": "button", "text": "imgBtn", "cls": "Wb.Button", "properties": { "cid": "imgBtn", "text": "Image Button", "img": "cut" } }, { "_icon": "button", "text": "charIconBtn", "cls": "Wb.Button", "properties": { "cid": "charIconBtn", "text": "Char Icon", "icon": "🌻", "tip": "Any char as icon" } }, { "_icon": "button", "text": "badgeBtn", "cls": "Wb.Button", "properties": { "cid": "badgeBtn", "text": "58", "icon": "bell", "badgeText": "true", "tip": "Badge text" } }, { "_icon": "button", "text": "leftBtn", "cls": "Wb.Button", "properties": { "cid": "leftBtn", "text": "Left", "icon": "left4", "iconAlign": "left" } }, { "_icon": "button", "text": "rightBtn", "cls": "Wb.Button", "properties": { "cid": "rightBtn", "text": "Right", "icon": "right4", "iconAlign": "right" } }, { "_icon": "button", "text": "topBtn", "cls": "Wb.Button", "properties": { "cid": "topBtn", "text": "Top", "icon": "up4", "iconAlign": "top" } }, { "_icon": "button", "text": "bottomBtn", "cls": "Wb.Button", "properties": { "cid": "bottomBtn", "text": "Bottom", "icon": "down4", "iconAlign": "bottom" } }, { "_icon": "button", "text": "keyBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "keyBtn", "icon": "keyboard", "text": "Ctrl+Shift+K", "keys": "Ctrl+Shift+K", "tip": "Press Ctrl+Shift+K to fire click event", "keysTextTip": "false" }, "events": { "click": "Wb.tip(this.cid + ' clicked');" } }, { "_icon": "button", "text": "noFocusBtn", "cls": "Wb.Button", "properties": { "cid": "noFocusBtn", "text": "No Focus", "icon": "flower", "tabIndex": "undefined", "focusable": "false" } }, { "_icon": "button", "text": "menuBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "menuBtn", "text": "menu", "icon": "menu" }, "items": [ { "_icon": "menu2", "text": "menu", "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "item 1", "icon": "calendar" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "item 3" } } ] } ] }, { "_icon": "split", "text": "splitButton1", "cls": "Wb.SplitButton", "properties": { "cid": "splitButton1", "text": "Split Button" }, "events": { "click": "Wb.tip(this.cid + ' clicked');" }, "_expanded": true, "items": [ { "_icon": "menu2", "text": "menu", "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "item 1", "icon": "calendar" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "item 3" } } ] } ] }, { "_icon": "button", "text": "tapBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "tapBtn", "tapClick": "true", "text": "MouseDown Click" }, "events": { "click": "Wb.tip(this.cid + ' clicked');" } }, { "_icon": "button", "text": "repeatBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "repeatBtn", "text": "Repeat Click", "repeatInterval": "true" }, "events": { "click": "app.repeatCt ??= 0;\nWb.toast(this.cid + ' clicked ' + (app.repeatCt++));" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "icon": "delete", "text": "Disabled", "disabled": "true" } } ] }, { "_icon": "title", "text": "styleTitle", "cls": "Wb.Title", "properties": { "cid": "styleTitle", "title": "Button style" } }, { "_icon": "label", "text": "styleLabel", "cls": "Wb.Label", "properties": { "cid": "styleLabel", "text": "Set the \"type\" property to set the button style" }, "_expanded": true }, { "_icon": "container", "text": "styleCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "styleCt", "layout": "form", "frame": "true" }, "items": [ { "_icon": "button", "text": "primary", "cls": "Wb.Button", "properties": { "cid": "primary", "type": "primary", "text": "Primary", "icon": "address-book" } }, { "_icon": "button", "text": "plain", "cls": "Wb.Button", "properties": { "cid": "plain", "type": "plain", "icon": "delete", "tip": "Plain Button" } }, { "_icon": "button", "text": "tool1", "cls": "Wb.Button", "properties": { "cid": "tool1", "type": "tool", "text": "cut", "icon": "cut", "tip": "Text Tool Button" } }, { "_icon": "button", "text": "noFocusTool1", "cls": "Wb.Button", "properties": { "cid": "noFocusTool1", "text": "cut", "icon": "cut", "tip": "Text Tool Button no focus", "cname": "tool" } }, { "_icon": "button", "text": "tool2", "cls": "Wb.Button", "properties": { "cid": "tool2", "type": "tool", "icon": "add1", "tip": "Tool Button" } }, { "_icon": "button", "text": "noFocusTool2", "cls": "Wb.Button", "properties": { "cid": "noFocusTool2", "icon": "add1", "tip": "Tool Button no focus", "cname": "tool" } }, { "_icon": "button", "text": "icon", "cls": "Wb.Button", "properties": { "cid": "icon", "icon": "database", "tip": "Icon Button no focus", "cname": "iconButton" }, "_expanded": true }, { "_icon": "button", "text": "light", "cls": "Wb.Button", "properties": { "cid": "light", "icon": "cube", "tip": "Light Button no focus", "cname": "lightButton" } } ] }, { "_icon": "title", "text": "shapeTitle", "cls": "Wb.Title", "properties": { "cid": "shapeTitle", "title": "Button shape" } }, { "_icon": "label", "text": "shapeLabel", "cls": "Wb.Label", "properties": { "cid": "shapeLabel", "text": "Set the \"shape\" property to set the button shape" }, "_expanded": true }, { "_icon": "container", "text": "shapeCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "shapeCt", "layout": "form", "frame": "true" }, "items": [ { "_icon": "button", "text": "circleBtn", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "circleBtn", "icon": "gear", "shape": "circle", "tip": "Circle" } }, { "_icon": "button", "text": "rectBtn", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "rectBtn", "icon": "gear", "shape": "rect", "text": "Rect" } }, { "_icon": "button", "text": "roundBtn", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "roundBtn", "icon": "gear", "shape": "round", "text": "Round" } } ] }, { "_icon": "title", "text": "groupTitle", "cls": "Wb.Title", "properties": { "cid": "groupTitle", "title": "Grouping and toggle button" } }, { "_icon": "label", "text": "groupLabel", "cls": "Wb.Label", "properties": { "cid": "groupLabel", "text": "Set the \"groupName\" property for grouping and set the \"active\" property for toggle" }, "_expanded": true }, { "_icon": "container", "text": "groupCt", "cls": "Wb.Container", "properties": { "cid": "groupCt", "layout": "form", "frame": "true" }, "events": { "buttontoggle": "Wb.tip(button.cid + ' is ' + active);" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button 1", "groupName": "group1", "active": "false" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "groupName": "group1", "text": "Button 2", "active": "false" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "groupName": "group1", "text": "Button 3", "active": "false" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" }, "_expanded": true }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button4", "groupName": "group2", "text": "Button 4", "active": "false" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button5", "groupName": "group2", "text": "Button 5", "active": "true" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button6", "groupName": "group2", "text": "Button 6", "active": "false" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "properties": { "cid": "space1" } }, { "_icon": "button", "text": "button7", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button7", "text": "Toggle", "active": "false" } }, { "_icon": "space", "text": "space2", "cls": "Wb.Space", "properties": { "cid": "space2" } }, { "_icon": "button", "text": "button8", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button8", "text": "No Background", "active": "true", "activeBgColor": "false" } } ] }, { "_icon": "title", "text": "sizeTitle", "cls": "Wb.Title", "properties": { "cid": "sizeTitle", "title": "Button size" } }, { "_icon": "label", "text": "sizeLabel", "cls": "Wb.Label", "properties": { "cid": "sizeLabel", "text": "Set \"fontSize\" property to set whole button size, and set \"iconSize\" property to set icon size only." }, "_expanded": true }, { "_icon": "container", "text": "sizeCt", "cls": "Wb.Container", "properties": { "cid": "sizeCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button 1", "icon": "gift", "fontSize": ".8em" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button 2", "icon": "gift", "fontSize": "1.5em" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Big icon only", "icon": "gift", "iconSize": "2em", "iconAlign": "top" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Big icon only", "icon": "gift", "iconSize": "2.5em", "iconAlign": "top" } } ] }, { "_icon": "title", "text": "layoutTitle", "cls": "Wb.Title", "properties": { "cid": "layoutTitle", "title": "Button layout" } }, { "_icon": "label", "text": "layoutLabel", "cls": "Wb.Label", "properties": { "cid": "layoutLabel", "text": "Set the \"Layout\" property to arrange buttons." }, "_expanded": true }, { "_icon": "container", "text": "layoutCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "layoutCt", "frame": "true", "layout": "row" }, "items": [ { "_icon": "item", "text": "setupItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "setupItem", "icon": "setup", "iconAlign": "top", "text": "Setup", "cname": "tool", "iconSize": "2.8em" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "item", "text": "pasteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "pasteItem", "icon": "paste", "text": "Paste", "cname": "tool", "iconAlign": "top", "iconSize": "2.8em" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "container1", "layout": "column", "align": "start" }, "items": [ { "_icon": "item", "text": "cutItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "cutItem", "icon": "cut", "text": "Cut", "cname": "tool" } }, { "_icon": "item", "text": "copyItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "copyItem", "icon": "copy", "text": "Copy", "cname": "tool" } }, { "_icon": "item", "text": "deleteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deleteItem", "icon": "delete", "text": "Delete", "cname": "tool" } } ] } ] }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "container", "text": "container2", "cls": "Wb.Container", "_expanded": false, "properties": { "cid": "container2", "layout": "column", "align": "center" }, "items": [ { "_icon": "item", "text": "addItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addItem", "icon": "add", "text": "Add", "cname": "tool" } }, { "_icon": "item", "text": "editItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editItem", "icon": "edit", "text": "Edit", "cname": "tool" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "container1", "layout": "row" }, "items": [ { "_icon": "item", "text": "upItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "upItem", "icon": "up4", "cname": "tool", "shape": "circle" } }, { "_icon": "item", "text": "rightItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "rightItem", "icon": "right4", "cname": "tool", "shape": "circle" } }, { "_icon": "item", "text": "downItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "downItem", "icon": "down4", "cname": "tool", "shape": "circle" } }, { "_icon": "item", "text": "leftItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "leftItem", "icon": "left4", "cname": "tool", "shape": "circle" } } ] } ] }, { "_icon": "split", "text": "setItem", "cls": "Wb.SplitButton", "properties": { "cid": "setItem", "icon": "gear", "iconSize": "2.8em" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "text": "Item 3" } } ] } ] } ] }, { "_icon": "title", "text": "eventTitle", "cls": "Wb.Title", "properties": { "cid": "eventTitle", "title": "Events" }, "_expanded": true }, { "_icon": "container", "text": "eventCt", "cls": "Wb.Container", "properties": { "cid": "eventCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button1", "text": "Click" }, "events": { "click": "Wb.tip('click');" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": false, "properties": { "cid": "button2", "active": "true", "text": "Toggle" }, "events": { "activate": "Wb.tip('activate');", "deactivate": "Wb.tip('deactivate');", "toggle": "Wb.tip('toggle: ' + active);" } } ] }, { "_icon": "title", "text": "codingTitle", "cls": "Wb.Title", "properties": { "cid": "codingTitle", "title": "Coding" }, "_expanded": true }, { "_icon": "container", "text": "codingCt", "cls": "Wb.Container", "properties": { "cid": "codingCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "container", "text": "demoCt", "cls": "Wb.Container", "properties": { "cid": "demoCt", "layout": "form-compact" }, "_expanded": true, "items": [ { "_icon": "button", "text": "demoButton", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "demoButton", "text": "Demo Button" } } ] }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "_expanded": false, "properties": { "cid": "line1", "title": "Demonstrate", "dimTitle": "true", "dashed": "true" } }, { "_icon": "container", "text": "actionCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "actionCt", "layout": "form-compact" }, "items": [ { "_icon": "button", "text": "addBtn", "cls": "Wb.Button", "properties": { "cid": "addBtn", "text": "Add Button" }, "_expanded": true, "events": { "click": "app.demoCt.add({ cname: 'button', icon: 'gear', text: 'New Button' });" } }, { "_icon": "button", "text": "setTextIconBtn", "cls": "Wb.Button", "properties": { "cid": "setTextIconBtn", "text": "Set Text Icon" }, "_expanded": true, "events": { "click": "let btn = app.demoButton;\nif (btn) {\n btn.text = 'Changed Text';\n btn.icon = 'earth';\n}" } }, { "_icon": "button", "text": "disableBtn", "cls": "Wb.Button", "properties": { "cid": "disableBtn", "text": "Set Disabled" }, "_expanded": true, "events": { "click": "app.demoButton?.setter('disabled', true); //equals to: if (app.demoButton) app.demoButton.disabled = true;\n//app.demoButton.visible = false; //Hide\n//app.demoButton?.hide(); //Hide" } }, { "_icon": "button", "text": "destroyBtn", "cls": "Wb.Button", "properties": { "cid": "destroyBtn", "text": "Destroy" }, "_expanded": true, "events": { "click": "app.demoButton?.destroy();" } }, { "_icon": "button", "text": "addEventBtn", "cls": "Wb.Button", "properties": { "cid": "addEventBtn", "text": "Add Event" }, "_expanded": true, "events": { "click": "app.demoBtnOnClick ??= f => Wb.tip('clicked'); //Define function\napp.demoButton?.on('click', app.demoBtnOnClick); //The same function can only be registered once\nWb.tip('Please click Demo Button');" } }, { "_icon": "button", "text": "removeEventBtn", "cls": "Wb.Button", "properties": { "cid": "removeEventBtn", "text": "Remove Event" }, "_expanded": true, "events": { "click": "app.demoButton?.un('click', app.demoBtnOnClick);\nWb.tip('Please click Demo Button (Event removed)');" } }, { "_icon": "button", "text": "addListenerBtn", "cls": "Wb.Button", "properties": { "cid": "addListenerBtn", "text": "Add Listener" }, "_expanded": true, "events": { "click": "app.demoBtnOnMouseEnter ??= f => Wb.tip('entered'); //Define function\napp.demoButton?.mon('mouseenter', app.demoBtnOnMouseEnter); //Add managed dom listener\nWb.tip('Please move mouse to Demo Button');" } }, { "_icon": "button", "text": "removeListenerBtn", "cls": "Wb.Button", "properties": { "cid": "removeListenerBtn", "text": "Remove Listener" }, "_expanded": true, "events": { "click": "app.demoButton?.mun('mouseenter', app.demoBtnOnMouseEnter);\nWb.tip('Please move mouse to Demo Button (Listener removed)');" } } ] } ] } ] } ] } # example/comps/chart/create-chart.xwl Title: create-chart ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.load('wb/libs/echarts.js');\n let i, theta, r, chart, data = [];\n\n //Please remove the theme when only used in the serverside\n chart = echarts.init(null, Wb.get('sys.theme') == 'dark' ? 'dark' : null, {\n renderer: 'svg',\n locale: Str.lang == 'zh-cn' ? 'ZH' : 'EN',\n ssr: true,\n width: 500,\n height: 400\n });\n for (i = 0; i <= 100; i++) {\n theta = (i / 100) * 360;\n r = 5 * (1 + Math.sin((theta / 180) * Math.PI));\n data.push([r, theta]);\n }\n chart.setOption({\n title: {\n text: 'Server render'\n },\n legend: {\n data: ['line']\n },\n polar: {},\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'cross'\n }\n },\n angleAxis: {\n type: 'value',\n startAngle: 0\n },\n radiusAxis: {},\n series: [\n {\n coordinateSystem: 'polar',\n name: 'line',\n type: 'line',\n data: data\n }\n ]\n });\n // response.setHeader('Content-Type', 'application/xml');\n Wb.send(chart.renderToSVGString());\n}\nmain();" }, "_icon": "module" } # example/comps/chart/get-chart-data.xwl Title: get-chart-data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.send({\n xAxis: {\n type: 'category',\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n },\n yAxis: {\n type: 'value'\n },\n series: [\n {\n data: [120, 200, 150, 80, 70, 110, 130],\n type: 'line',\n symbol: 'triangle',\n symbolSize: 20,\n lineStyle: {\n color: '#5470C6',\n width: 4,\n type: 'dashed'\n },\n itemStyle: {\n borderWidth: 3,\n borderColor: '#EE6666',\n color: 'yellow'\n }\n }\n ]\n });\n}\nmain();" }, "_icon": "module" } # example/comps/chart.xwl Title: chart ```json { "title": "", "icon": "chart-bar", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Chart", "cls": "w-title3" } }, { "_icon": "title", "text": "commonTitle", "cls": "Wb.Title", "properties": { "cid": "commonTitle", "title": "Common chart" }, "_expanded": true }, { "_icon": "chart-bar", "text": "commonChart", "cls": "Wb.Chart", "properties": { "cid": "commonChart", "option": "({\n title: {\n text: 'ECharts Getting Started Example'\n },\n tooltip: {},\n xAxis: {\n data: ['shirt', 'cardigan', 'chiffon', 'pants', 'heels', 'socks']\n },\n yAxis: {},\n series: [\n {\n name: 'sales',\n type: 'bar',\n data: [5, 20, 36, 10, 10, 20]\n }\n ]\n})", "height": "20em" } }, { "_icon": "title", "text": "manualSetOptionTitle", "cls": "Wb.Title", "properties": { "cid": "manualSetOptionTitle", "title": "Manual setOption" }, "_expanded": true }, { "_icon": "chart-bar", "text": "manualSetOptionChart", "cls": "Wb.Chart", "properties": { "cid": "manualSetOptionChart", "height": "20em" }, "events": { "ready": "// For more parameters please use [this.setOption] method\nthis.option = {\n title: {\n text: 'Stacked Area Chart'\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'cross',\n label: {\n backgroundColor: '#6a7985'\n }\n }\n },\n legend: {\n data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine']\n },\n toolbox: {\n feature: {\n saveAsImage: {}\n }\n },\n grid: {\n left: '3%',\n right: '4%',\n bottom: '3%',\n containLabel: true\n },\n xAxis: [\n {\n type: 'category',\n boundaryGap: false,\n data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n }\n ],\n yAxis: [\n {\n type: 'value'\n }\n ],\n series: [\n {\n name: 'Email',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [120, 132, 101, 134, 90, 230, 210]\n },\n {\n name: 'Union Ads',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [220, 182, 191, 234, 290, 330, 310]\n },\n {\n name: 'Video Ads',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [150, 232, 201, 154, 190, 330, 410]\n },\n {\n name: 'Direct',\n type: 'line',\n stack: 'Total',\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [320, 332, 301, 334, 390, 330, 320]\n },\n {\n name: 'Search Engine',\n type: 'line',\n stack: 'Total',\n label: {\n show: true,\n position: 'top'\n },\n areaStyle: {},\n emphasis: {\n focus: 'series'\n },\n data: [820, 932, 901, 934, 1290, 1330, 1320]\n }\n ]\n};" } }, { "_icon": "title", "text": "remoteTitle", "cls": "Wb.Title", "properties": { "cid": "remoteTitle", "title": "Load remote data" }, "_expanded": true }, { "_icon": "chart-bar", "text": "remoteChart", "cls": "Wb.Chart", "properties": { "cid": "remoteChart", "height": "20em" }, "events": { "ready": "//You can set url property to autoload chart\nthis.load({ url: xpath + '/get-chart-data', mask: { target: this } });" } }, { "_icon": "button", "text": "manualLoadBtn", "cls": "Wb.Button", "properties": { "cid": "manualLoadBtn", "text": "Manual load data" }, "events": { "click": "app.remoteChart.clear();\napp.remoteChart.load({ params: { foo: 'bar' } });\n// app.remoteChart.reload();" } }, { "_icon": "title", "text": "serverRenderTitle", "cls": "Wb.Title", "properties": { "cid": "serverRenderTitle", "title": "Server rendering chart" } }, { "_icon": "label", "text": "serverRenderLabel", "cls": "Wb.Label", "properties": { "cid": "serverRenderLabel", "text": "WebBuilder can directly load echarts library in the serverside to create charts, which will bring great convenience. For example, we can use this feature to create charts in the serverside and send them via email." } }, { "_icon": "panel", "text": "serverRenderPanel", "cls": "Wb.Panel", "properties": { "cid": "serverRenderPanel", "html": "_$chartSvg$_", "layout": "center", "minHeight": "8em" }, "events": { "ready": "let me = this;\nWb.ajax({\n url: xpath + '/create-chart',\n mask: { target: me },\n success(resp) {\n me.html = resp;\n }\n});" } } ] } ] } # example/comps/check-slider.xwl Title: check-slider ```json { "title": "", "icon": "check6", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Check, radio, toggle and slider", "cls": "w-title3" } }, { "_icon": "title", "text": "checkTitle", "cls": "Wb.Title", "properties": { "cid": "checkTitle", "title": "Check" } }, { "_icon": "container", "text": "checkCt", "cls": "Wb.Container", "properties": { "cid": "checkCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "check6", "text": "commonCheck", "cls": "Wb.Check", "properties": { "cid": "commonCheck", "text": "Common check" }, "events": { "change": "Wb.tip(this.cid + ' value is ' + value);" } }, { "_icon": "check6", "text": "labelCheck", "cls": "Wb.Check", "properties": { "cid": "labelCheck", "text": "With label", "label": "Label check", "value": "true" } }, { "_icon": "check6", "text": "onlyLabelCheck", "cls": "Wb.Check", "properties": { "cid": "onlyLabelCheck", "label": "Only label check" }, "_expanded": true }, { "_icon": "check6", "text": "onlyLabelEmptyTextCheck", "cls": "Wb.Check", "properties": { "cid": "onlyLabelEmptyTextCheck", "label": "Only label check with empty text", "showEmptyLabel": "true" } }, { "_icon": "model", "text": "intValueCt", "cls": "Wb.ControlCt", "properties": { "cid": "intValueCt", "gap": "1em", "showEmptyLabel": "true" }, "_expanded": true, "items": [ { "_icon": "check6", "text": "intValueCheck", "cls": "Wb.Check", "_expanded": true, "properties": { "cid": "intValueCheck", "returnType": "int", "label": "return int value" } }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "properties": { "cid": "getValueBtn", "text": "Get value" }, "events": { "click": "Wb.tip('The value is ' + this.previousSibling.value);" } } ] } ] }, { "_icon": "title", "text": "checkGroupTitle", "cls": "Wb.Title", "properties": { "cid": "checkGroupTitle", "title": "CheckGroup" } }, { "_icon": "container", "text": "checkGroupCt", "cls": "Wb.Container", "properties": { "cid": "checkGroupCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonCheckGroupLabel", "cls": "Wb.Label", "properties": { "cid": "commonCheckGroupLabel", "text": "Common checkGroup" } }, { "_icon": "container", "text": "commonCheckCt", "cls": "Wb.Container", "properties": { "cid": "commonCheckCt", "gap": "1em", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "checks", "text": "commonCheckGroup", "cls": "Wb.CheckGroup", "properties": { "cid": "commonCheckGroup" }, "_expanded": true, "items": [ { "_icon": "check6", "text": "check1", "cls": "Wb.Check", "properties": { "cid": "check1", "label": "item 1" } }, { "_icon": "check6", "text": "check2", "cls": "Wb.Check", "properties": { "cid": "check2", "label": "item 2", "value": "true" } }, { "_icon": "check6", "text": "check3", "cls": "Wb.Check", "_expanded": true, "properties": { "cid": "check3", "label": "item 3", "value": "true" } } ] }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "properties": { "cid": "getValueBtn", "text": "Get value" }, "events": { "click": "Wb.tip(Wb.encode(app.commonCheckGroup.value));" } }, { "_icon": "button", "text": "setValueBtn", "cls": "Wb.Button", "properties": { "cid": "setValueBtn", "text": "Set value" }, "events": { "click": "app.commonCheckGroup.setValue({ check1: true, check3: true });" } } ] }, { "_icon": "label", "text": "allCheckGroupLabel", "cls": "Wb.Label", "properties": { "cid": "allCheckGroupLabel", "text": "Return all and return array value checkGroup" } }, { "_icon": "container", "text": "allCheckCt", "cls": "Wb.Container", "properties": { "cid": "allCheckCt", "gap": "1em", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "checks", "text": "allCheckGroup", "cls": "Wb.CheckGroup", "properties": { "cid": "allCheckGroup", "returnAll": "true", "returnArray": "true" }, "_expanded": true, "items": [ { "_icon": "check6", "text": "check1", "cls": "Wb.Check", "properties": { "cid": "check1", "label": "item 1" } }, { "_icon": "check6", "text": "check2", "cls": "Wb.Check", "properties": { "cid": "check2", "label": "item 2", "value": "true" } }, { "_icon": "check6", "text": "check3", "cls": "Wb.Check", "_expanded": true, "properties": { "cid": "check3", "label": "item 3", "value": "true" } } ] }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "properties": { "cid": "getValueBtn", "text": "Get value" }, "events": { "click": "Wb.tip(Wb.encode(app.allCheckGroup.value));" } }, { "_icon": "button", "text": "setValueObjectBtn", "cls": "Wb.Button", "properties": { "cid": "setValueObjectBtn", "text": "Set value by object" }, "events": { "click": "app.allCheckGroup.setValue({ check1: true, check3: 'true' });" } }, { "_icon": "button", "text": "setValueArrayBtn", "cls": "Wb.Button", "properties": { "cid": "setValueArrayBtn", "text": "Set value by array" }, "events": { "click": "app.allCheckGroup.setValue([false, 1, 'true']);" }, "_expanded": true }, { "_icon": "button", "text": "setValueCidsBtn", "cls": "Wb.Button", "properties": { "cid": "setValueCidsBtn", "text": "Set value by cids" }, "events": { "click": "app.allCheckGroup.setValue(['check1', 'check3'] );" } } ] } ] }, { "_icon": "title", "text": "radioTitle", "cls": "Wb.Title", "properties": { "cid": "radioTitle", "title": "Radio" }, "_expanded": true }, { "_icon": "container", "text": "radioCt", "cls": "Wb.Container", "properties": { "cid": "radioCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "check2", "text": "radio1", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "radio1", "label": "item 1", "group": "group1" } }, { "_icon": "check2", "text": "radio2", "cls": "Wb.Radio", "_expanded": false, "properties": { "cid": "radio2", "label": "item 2", "group": "group1" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "check2", "text": "radio3", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "radio3", "label": "item 3", "group": "group2" } }, { "_icon": "check2", "text": "radio4", "cls": "Wb.Radio", "_expanded": false, "properties": { "cid": "radio4", "label": "item 4", "group": "group2", "value": "true" } }, { "_icon": "check2", "text": "radio5", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "radio5", "label": "item 5", "group": "group2" } } ] }, { "_icon": "title", "text": "radioGroupTitle", "cls": "Wb.Title", "properties": { "cid": "radioGroupTitle", "title": "RadioGroup" } }, { "_icon": "container", "text": "radioGroupCt", "cls": "Wb.Container", "properties": { "cid": "radioGroupCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonRadioGroupLabel", "cls": "Wb.Label", "properties": { "cid": "commonRadioGroupLabel", "text": "Common radioGroup" } }, { "_icon": "container", "text": "commonRadioCt", "cls": "Wb.Container", "properties": { "cid": "commonRadioCt", "gap": "1em", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "radios", "text": "commonRadioGroup", "cls": "Wb.RadioGroup", "_expanded": true, "properties": { "cid": "commonRadioGroup" }, "items": [ { "_icon": "check2", "text": "radio1", "cls": "Wb.Radio", "properties": { "cid": "radio1", "label": "item 1" } }, { "_icon": "check2", "text": "radio2", "cls": "Wb.Radio", "properties": { "cid": "radio2", "label": "item 2" } }, { "_icon": "check2", "text": "radio3", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "radio3", "label": "item 3" } } ] }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "properties": { "cid": "getValueBtn", "text": "Get value" }, "events": { "click": "Wb.tip(app.commonRadioGroup.value);" } }, { "_icon": "button", "text": "setValueBtn", "cls": "Wb.Button", "properties": { "cid": "setValueBtn", "text": "Set value" }, "events": { "click": "app.commonRadioGroup.setValue(2);" } } ] }, { "_icon": "label", "text": "returnCidRadioGroupLabel", "cls": "Wb.Label", "properties": { "cid": "returnCidRadioGroupLabel", "text": "Return cid as value radioGroup" } }, { "_icon": "container", "text": "returnNameRadioCt", "cls": "Wb.Container", "properties": { "cid": "returnNameRadioCt", "gap": "1em", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "radios", "text": "returnNameRadioGroup", "cls": "Wb.RadioGroup", "_expanded": true, "properties": { "cid": "returnNameRadioGroup", "returnName": "true" }, "items": [ { "_icon": "check2", "text": "radio1", "cls": "Wb.Radio", "properties": { "cid": "radio1", "label": "item 1", "value": "true" } }, { "_icon": "check2", "text": "radio2", "cls": "Wb.Radio", "properties": { "cid": "radio2", "label": "item 2" } }, { "_icon": "check2", "text": "radio3", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "radio3", "label": "item 3" } } ] }, { "_icon": "button", "text": "getValueBtn", "cls": "Wb.Button", "properties": { "cid": "getValueBtn", "text": "Get value" }, "events": { "click": "Wb.tip(app.returnNameRadioGroup.value);" } }, { "_icon": "button", "text": "setValueByIndexBtn", "cls": "Wb.Button", "properties": { "cid": "setValueByIndexBtn", "text": "Set value by index" }, "events": { "click": "app.returnNameRadioGroup.setValue(2);" } }, { "_icon": "button", "text": "setValueByCidBtn", "cls": "Wb.Button", "properties": { "cid": "setValueByCidBtn", "text": "Set value by cid" }, "events": { "click": "app.returnNameRadioGroup.setValue('radio2');" } } ] } ] }, { "_icon": "title", "text": "toggleTitle", "cls": "Wb.Title", "properties": { "cid": "toggleTitle", "title": "Toggle" } }, { "_icon": "container", "text": "toggleCt", "cls": "Wb.Container", "properties": { "cid": "toggleCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "switcher-on", "text": "commonToggle", "cls": "Wb.Toggle", "properties": { "cid": "commonToggle", "text": "Common toggle" }, "events": { "change": "Wb.tip(this.cid + ' is ' + value);" } }, { "_icon": "switcher-on", "text": "prefixSuffixToggle", "cls": "Wb.Toggle", "properties": { "cid": "prefixSuffixToggle", "text": "Prefix suffix", "prefix": "Prefix text", "suffix": "Suffix text" } }, { "_icon": "switcher-on", "text": "dragToToggle", "cls": "Wb.Toggle", "properties": { "cid": "dragToToggle", "text": "Drag to toggle", "clickToggle": "false" }, "_expanded": true }, { "_icon": "switcher-on", "text": "alignRightToggle", "cls": "Wb.Toggle", "properties": { "cid": "alignRightToggle", "text": "Align right toggle", "toggleAlign": "end" } }, { "_icon": "switcher-on", "text": "verticalToggle", "cls": "Wb.Toggle", "properties": { "cid": "verticalToggle", "text": "Vertical toggle", "vertical": "true" } }, { "_icon": "model", "text": "returnIntCt", "cls": "Wb.ControlCt", "properties": { "cid": "returnIntCt", "gap": "1em", "text": "Return int value" }, "_expanded": true, "items": [ { "_icon": "switcher-on", "text": "returnIntToggle", "cls": "Wb.Toggle", "properties": { "cid": "returnIntToggle", "returnType": "int" } }, { "_icon": "button", "text": "getValue", "cls": "Wb.Button", "properties": { "cid": "getValue", "text": "Get value" }, "events": { "click": "Wb.tip(this.cid + ' value is ' + this.previousSibling.value);" } } ] } ] }, { "_icon": "title", "text": "sliderTitle", "cls": "Wb.Title", "properties": { "cid": "sliderTitle", "title": "Slider" } }, { "_icon": "container", "text": "sliderCt", "cls": "Wb.Container", "properties": { "cid": "sliderCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "commonSlider", "cls": "Wb.Slider", "properties": { "cid": "commonSlider", "text": "Common slider", "value": "30" }, "events": { "startdrag": "Wb.tip('Start drag at ' + value);", "enddrag": "Wb.tip('End drag at ' + value);" } }, { "_icon": "slidebar", "text": "multiSlider", "cls": "Wb.Slider", "properties": { "cid": "multiSlider", "text": "Multi slider", "value": "[10, 50, 80]", "suffix": "Suffix", "prefix": "Prefix" }, "events": { "enddrag": "Wb.tip('The values are ' + Wb.encode(value));" } }, { "_icon": "model", "text": "verticalSliderCt", "cls": "Wb.ControlCt", "properties": { "cid": "verticalSliderCt", "text": "Vertical slider", "layout": "row", "gap": "2em", "height": "10em", "align": "stretch" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "verticalSlider", "cls": "Wb.Slider", "properties": { "cid": "verticalSlider", "vertical": "true", "value": "20", "text": "Text", "labelUp": "true", "labelAlign": "center", "labelSeparator": "false" }, "_expanded": true }, { "_icon": "slidebar", "text": "verticalMulSlider", "cls": "Wb.Slider", "properties": { "cid": "verticalMulSlider", "vertical": "true", "value": "[30, 70]", "prefix": "Prefix", "suffix": "Suffix", "labelUp": "true" }, "events": { "enddrag": "Wb.tip('The values are ' + Wb.encode(value));" }, "_expanded": true } ] }, { "_icon": "slidebar", "text": "justifyLeftVerticalSlider", "cls": "Wb.Slider", "properties": { "cid": "justifyLeftVerticalSlider", "vertical": "true", "justifySelf": "start", "value": "20", "text": "Justify left", "height": "6em" } }, { "_icon": "slidebar", "text": "volumeSlider", "cls": "Wb.Slider", "properties": { "cid": "volumeSlider", "text": "Volume", "suffix": "true", "maxValue": "100", "suffixWidth": "3em", "value": "50" }, "events": { "change": "Wb.toast('Volumn is ' + value);" }, "_expanded": true }, { "_icon": "slidebar", "text": "miscSlider", "cls": "Wb.Slider", "properties": { "cid": "miscSlider", "text": "Misc slider", "prefix": "100", "suffix": "500", "maxValue": "500", "step": "10", "value": "200", "minValue": "100", "tipRender": "return 'Custom render ' + value;" } }, { "_icon": "check3", "text": "areaSlider1", "cls": "Wb.AreaSlider", "properties": { "cid": "areaSlider1", "text": "Area slider", "width": "30em", "height": "10em", "value": "[20, 30]", "maxValue": "[300, 200]" }, "events": { "enddrag": "Wb.toast('The value is ' + Wb.encode(value));" } } ] } ] } ] } # example/comps/code-editor.xwl Title: code-editor ```json { "title": "", "icon": "edit", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "CodeEditor", "cls": "w-title3" } }, { "_icon": "title", "text": "jsEditorTitle", "cls": "Wb.Title", "properties": { "cid": "jsEditorTitle", "title": "JavaScript editor" } }, { "_icon": "edit", "text": "jsEditor", "cls": "Wb.CodeEditor", "properties": { "cid": "jsEditor", "value": "Cls['Wb.Button'] = class button extends Wb.mixin.Icon(Wb.Component) {\n static configs = {\n tabIndex: Wb.isTouch ? undefined : 0,\n rippleOnClick: true\n };\n /***/\n init(configs) {\n let me = this;\n super.init(configs);\n me.on('click', me.onClickEvent);\n me.mon({ [me.tapClick ? Event.tapDownName : 'click']: me.onClick, keydown: me.onKeyDown });\n }\n}", "height": "18em" } }, { "_icon": "title", "text": "sqlEditorTitle", "cls": "Wb.Title", "properties": { "cid": "sqlEditorTitle", "title": "SQL editor" } }, { "_icon": "edit", "text": "sqlEditor", "cls": "Wb.CodeEditor", "properties": { "cid": "sqlEditor", "value": "select a.field1, b.field2 from table1 a, table2 b where a.sid=b.sid\norder by a.field1", "height": "3em", "language": "sql" } }, { "_icon": "title", "text": "htmlEditorTitle", "cls": "Wb.Title", "properties": { "cid": "htmlEditorTitle", "title": "HTML editor without border" } }, { "_icon": "edit", "text": "htmlEditor", "cls": "Wb.CodeEditor", "properties": { "cid": "htmlEditor", "value": "\n\n\nhtml\n\n\n\n\n\n\n\n\n\n\n", "height": "18em", "language": "html", "wrapBorder": "false" } }, { "_icon": "label", "text": "otherLanguageLabel", "cls": "Wb.Label", "properties": { "cid": "otherLanguageLabel", "text": "For other languages, please set the language property." } } ] } ] } # example/comps/container.xwl Title: container ```json { "title": "", "icon": "container", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Containers", "cls": "w-title3" } }, { "_icon": "title", "text": "containerTitle", "cls": "Wb.Title", "properties": { "cid": "containerTitle", "title": "Container" } }, { "_icon": "container", "text": "containerCt", "cls": "Wb.Container", "properties": { "cid": "containerCt", "layout": "grid", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "container", "text": "commonCt", "cls": "Wb.Container", "properties": { "cid": "commonCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "line", "text": "descLine", "cls": "Wb.Line", "properties": { "cid": "descLine", "title": "Common Container" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text" }, "_expanded": true }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Custom Label Separator", "labelSeparator": "-", "labelUp": "true" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "No Label Separator", "labelUp": "true", "labelSeparator": "false" } } ] }, { "_icon": "container", "text": "customLabelCt", "cls": "Wb.Container", "properties": { "cid": "customLabelCt", "layout": "grid1", "frame": "true", "labelUp": "true", "labelAlign": "center" }, "_expanded": true, "items": [ { "_icon": "line", "text": "descLine", "cls": "Wb.Line", "properties": { "cid": "descLine", "title": "Custom Label Align" } }, { "_icon": "text", "text": "defaultText", "cls": "Wb.Text", "properties": { "cid": "defaultText", "text": "Default to parent" }, "_expanded": true }, { "_icon": "text", "text": "leftCommonText", "cls": "Wb.Text", "properties": { "cid": "leftCommonText", "text": "Left Common", "labelAlign": "left", "labelUp": "false" }, "_expanded": true }, { "_icon": "text", "text": "rightCommonText", "cls": "Wb.Text", "properties": { "cid": "rightCommonText", "text": "Right Common", "labelAlign": "right", "labelUp": "false" }, "_expanded": true }, { "_icon": "text", "text": "leftAboveText", "cls": "Wb.Text", "properties": { "cid": "leftAboveText", "text": "Left Above", "labelAlign": "left", "labelUp": "true" }, "_expanded": true }, { "_icon": "text", "text": "rightAboveText", "cls": "Wb.Text", "properties": { "cid": "rightAboveText", "text": "Right Above", "labelAlign": "right", "labelUp": "true" }, "_expanded": true } ] } ] }, { "_icon": "title", "text": "panelTitle", "cls": "Wb.Title", "properties": { "cid": "panelTitle", "title": "Panel" } }, { "_icon": "container", "text": "panelCt", "cls": "Wb.Container", "properties": { "cid": "panelCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "panel", "text": "commonPanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "commonPanel", "layout": "grid1", "html": "Common Panel" } }, { "_icon": "panel", "text": "titledPanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "titledPanel", "title": "Titled Panel", "collapsible": "true", "closable": "true", "layout": "grid1", "width": "30em", "maximizable": "true", "minimizable": "true", "tagProperties": "({\n minimize() {\n Wb.tip('Do minimize');\n }\n})" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "number" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "date" } } ] }, { "_icon": "panel", "text": "miscPanel", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "miscPanel", "frame": "true", "title": "Misc Panel", "layout": "grid1", "maximizable": "true", "buttonAlign": "center", "defaults": "({ labelWidth: '5em' })", "height": "20em", "icon": "address-book", "minButtonWidth": "6em", "collapsible": "true" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "tbar" }, "text": "tbar", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "toolbar1" }, "text": "toolbar1", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addItem", "icon": "add1", "text": "Add" } }, { "_icon": "item", "text": "delItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "delItem", "icon": "delete", "text": "Delete" } } ] }, { "_icon": "toolbar", "text": "toolbar2", "cls": "Wb.Toolbar", "properties": { "cid": "toolbar2", "fontSize": ".8em" }, "_expanded": true, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "Address:" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "flex": "1" } }, { "_icon": "item", "text": "playBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "playBtn", "icon": "play", "alignSelf": "stretch" } } ] } ] }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text1" }, "_expanded": true }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "properties": { "cid": "text2", "text": "text2" } }, { "_icon": "text", "text": "text3", "cls": "Wb.Text", "properties": { "cid": "text3", "text": "text3" } }, { "_icon": "text", "text": "text4", "cls": "Wb.Text", "properties": { "cid": "text4", "text": "text4" } }, { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Button", "properties": { "cid": "okBtn", "text": "@Str.ok", "type": "primary" }, "text": "okBtn", "_expanded": true, "_icon": "button" }, { "cls": "Wb.Button", "properties": { "cid": "cancelBtn", "text": "@Str.cancel" }, "text": "cancelBtn", "_expanded": true, "_icon": "button" } ] }, { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true", "justify": "end" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "menuItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "menuItem", "icon": "menu" }, "items": [ { "_icon": "menu2", "text": "menu", "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "item1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item2", "text": "item2" } } ] } ] } ] }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "properties": { "cid": "setItem", "icon": "gear", "tip": "Set" }, "text": "setItem", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "properties": { "cid": "printItem", "icon": "print", "tip": "Print" }, "text": "printItem", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "properties": { "cid": "pinItem", "icon": "pin", "tip": "Pin" }, "text": "pinItem", "_expanded": true, "_icon": "item" } ] }, { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "cls": "Wb.Item", "properties": { "cid": "setItem", "icon": "gear", "text": "Set Menu" }, "text": "setItem", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "properties": { "cid": "printItem", "icon": "print", "text": "Print Menu" }, "text": "printItem", "_expanded": true, "_icon": "item" } ] } ] } ] }, { "_icon": "title", "text": "treeStyleTitle", "cls": "Wb.Title", "properties": { "cid": "treeStyleTitle", "title": "Tree style panels" } }, { "_icon": "container", "text": "treeStyleCt", "cls": "Wb.Container", "properties": { "cid": "treeStyleCt", "frame": "true", "layout": "column" }, "_expanded": true, "items": [ { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "layout": "grid1", "collapsible": "tree", "title": "Panel1", "textSelectable": "false" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1" } }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "properties": { "cid": "text2" } } ] }, { "_icon": "panel", "text": "panel2", "cls": "Wb.Panel", "properties": { "cid": "panel2", "collapsible": "tree", "height": "5em", "text": "Panel2", "title": "Panel2", "collapsed": "true", "textSelectable": "false" } }, { "_icon": "panel", "text": "panel3", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "panel3", "collapsible": "tree", "height": "8em", "text": "Panel3", "title": "Panel3", "textSelectable": "false" } } ] }, { "_icon": "title", "text": "accordionStyleTitle", "cls": "Wb.Title", "properties": { "cid": "accordionStyleTitle", "title": "Accordion style panels" }, "_expanded": true }, { "_icon": "container", "text": "accordionStyleCt", "cls": "Wb.Container", "properties": { "cid": "accordionStyleCt", "frame": "true", "layout": "column", "height": "20em" }, "_expanded": true, "items": [ { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "layout": "grid1", "collapsible": "accordion", "title": "Panel1", "textSelectable": "false", "flex": "1", "icon": "gear" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1" } }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "properties": { "cid": "text2" } } ] }, { "_icon": "panel", "text": "panel2", "cls": "Wb.Panel", "properties": { "cid": "panel2", "collapsible": "accordion", "text": "Panel2", "title": "Panel2", "textSelectable": "false", "flex": "1", "collapsed": "true", "icon": "excel" } }, { "_icon": "panel", "text": "panel3", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "panel3", "collapsible": "accordion", "text": "Panel3", "title": "Panel3", "textSelectable": "false", "flex": "1", "collapsed": "true", "icon": "word" } } ] }, { "_icon": "title", "text": "plainTitlePanelBlocksTitle", "cls": "Wb.Title", "properties": { "cid": "plainTitlePanelBlocksTitle", "title": "Plain title panel blocks" } }, { "_icon": "label", "text": "plainTitlePanelBlocksLabel", "cls": "Wb.Label", "properties": { "cid": "plainTitlePanelBlocksLabel", "text": "A list of panels organized by blocks" } }, { "_icon": "container", "text": "plainTitlePanelBlocksCt", "cls": "Wb.Container", "properties": { "cid": "plainTitlePanelBlocksCt", "layout": "grid1", "frame": "true", "gap": "1em", "padding": "1em", "background": "true" }, "_expanded": true, "items": [ { "_icon": "panel", "text": "formPanel", "cls": "Wb.Panel", "properties": { "cid": "formPanel", "plainTitle": "true", "title": "Block 1 - Form panel1", "icon": "form", "layout": "grid1", "roundBorder": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } } ] }, { "_icon": "panel", "text": "formPanel2", "cls": "Wb.Panel", "properties": { "cid": "formPanel2", "plainTitle": "true", "title": "Block 2 - Form panel2", "icon": "word", "layout": "grid1", "roundBorder": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } } ] }, { "_icon": "panel", "text": "formPanel3", "cls": "Wb.Panel", "properties": { "cid": "formPanel3", "plainTitle": "true", "title": "Block 3 - Form panel3", "icon": "excel", "layout": "grid1", "roundBorder": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } } ] } ] }, { "_icon": "title", "text": "fieldsetTitle", "cls": "Wb.Title", "properties": { "cid": "fieldsetTitle", "title": "Fieldset" }, "_expanded": true }, { "_icon": "container", "text": "fieldsetCt", "cls": "Wb.Container", "properties": { "cid": "fieldsetCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "fieldset", "text": "comonFieldset", "cls": "Wb.Fieldset", "properties": { "cid": "comonFieldset", "title": "Common Fieldset", "layout": "grid" }, "_expanded": true, "items": [ { "_icon": "text", "text": "nameText", "cls": "Wb.Text", "properties": { "cid": "nameText", "text": "Name" } }, { "_icon": "text", "text": "addrText", "cls": "Wb.Text", "properties": { "cid": "addrText", "text": "Address" } }, { "_icon": "calendar", "text": "birthDate", "cls": "Wb.Date", "properties": { "cid": "birthDate", "text": "Birth date" } } ] }, { "_icon": "fieldset", "text": "collapsibleFieldset", "cls": "Wb.Fieldset", "properties": { "cid": "collapsibleFieldset", "title": "Collapsible Fieldset", "layout": "grid", "collapsible": "true", "icon": "id-card", "labelAlign": "left" }, "_expanded": true, "items": [ { "_icon": "text", "text": "nameText", "cls": "Wb.Text", "properties": { "cid": "nameText", "text": "Name" } }, { "_icon": "text", "text": "addrText", "cls": "Wb.Text", "properties": { "cid": "addrText", "text": "Address" } }, { "_icon": "calendar", "text": "birthDate", "cls": "Wb.Date", "properties": { "cid": "birthDate", "text": "Birth date" } } ] } ] }, { "_icon": "title", "text": "tabTitle", "cls": "Wb.Title", "properties": { "cid": "tabTitle", "title": "Tab" } }, { "_icon": "container", "text": "tabCt", "cls": "Wb.Container", "properties": { "cid": "tabCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonLabel", "cls": "Wb.Label", "properties": { "cid": "commonLabel", "text": "Common Tab" } }, { "_icon": "tab", "text": "commonTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "commonTab", "height": "10em", "width": "48em" }, "items": [ { "_icon": "card", "text": "iconCard", "cls": "Wb.Card", "properties": { "cid": "iconCard", "icon": "home", "title": "Icon Card" } }, { "_icon": "card", "text": "imageIconCard", "cls": "Wb.Card", "properties": { "cid": "imageIconCard", "img": "support", "title": "Image Icon", "closable": "null" } }, { "_icon": "card", "text": "loadingCard", "cls": "Wb.Card", "properties": { "cid": "loadingCard", "icon": "loading", "title": "Loading", "spin": "true" } }, { "_icon": "card", "text": "disabledCard", "cls": "Wb.Card", "properties": { "cid": "disabledCard", "disabled": "true", "title": "Disabled", "icon": "calendar" } }, { "_icon": "card", "text": "noSortableCard", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "noSortableCard", "title": "No Sortable", "sortable": "false", "icon": "🌻" } }, { "_icon": "card", "text": "overflowedCard", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "overflowedCard", "title": "Overflowed", "tabTip": "This tab card is overflowed" } } ] }, { "_icon": "label", "text": "miscTabLabel", "cls": "Wb.Label", "properties": { "cid": "miscTabLabel", "text": "Miscellaneous Tab" }, "_expanded": true }, { "_icon": "tab", "text": "miscTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "miscTab", "height": "10em", "width": "30em", "resizable": "true", "dblclickFull": "true", "shrinkTabButton": "true", "clipTabText": "true", "frame": "true" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card1", "title": "Cliped Text", "html": "Try resizing small
\nDouble click tab button", "layout": "center" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card2", "title": "Shrink Tab Button" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card3" } }, { "_icon": "card", "text": "card4", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card4", "title": "Card4" } } ] }, { "_icon": "label", "text": "wrappedTabLabel", "cls": "Wb.Label", "properties": { "cid": "wrappedTabLabel", "text": "Wrapped Tab Buttons" }, "_expanded": true }, { "_icon": "tab", "text": "wrappedTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "wrappedTab", "height": "10em", "width": "20em", "resizable": "true", "wrapTab": "true", "frame": "true" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "properties": { "cid": "card1", "title": "Card1" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "properties": { "cid": "card2", "title": "Card2" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card3" } }, { "_icon": "card", "text": "card4", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card4", "title": "Card4" } }, { "_icon": "card", "text": "card5", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card5", "title": "Card5" } } ] }, { "_icon": "label", "text": "bottomLabel", "cls": "Wb.Label", "properties": { "cid": "bottomLabel", "text": "Bottom Tab" } }, { "_icon": "tab", "text": "bottomTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "bottomTab", "tabPosition": "bottom", "height": "10em" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card1", "title": "Card1" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card2", "title": "Card2" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card3" } } ] }, { "_icon": "label", "text": "leftLabel", "cls": "Wb.Label", "properties": { "cid": "leftLabel", "text": "Left Tab" } }, { "_icon": "tab", "text": "leftTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "leftTab", "tabPosition": "left", "height": "10em" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card1", "title": "Card1" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card2", "title": "Card2" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card3" } } ] }, { "_icon": "label", "text": "rightLabel", "cls": "Wb.Label", "properties": { "cid": "rightLabel", "text": "Right Tab" } }, { "_icon": "tab", "text": "rightTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "rightTab", "tabPosition": "right", "height": "10em" }, "items": [ { "_icon": "card", "text": "card1", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card1", "title": "Card1" } }, { "_icon": "card", "text": "card2", "cls": "Wb.Card", "_expanded": false, "properties": { "cid": "card2", "title": "Card2" } }, { "_icon": "card", "text": "card3", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "card3", "title": "Card3" } } ] } ] } ] } ] } # example/comps/date.xwl Title: date ```json { "title": "", "icon": "calendar", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Date and Time", "cls": "w-title3" } }, { "_icon": "title", "text": "dateTitle", "cls": "Wb.Title", "properties": { "cid": "dateTitle", "title": "Date" } }, { "_icon": "container", "text": "dateCt", "cls": "Wb.Container", "properties": { "cid": "dateCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "calendar", "text": "commonDate", "cls": "Wb.Date", "properties": { "cid": "commonDate", "text": "Common" } }, { "_icon": "calendar", "text": "constraintDate", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "constraintDate", "text": "Constraint Value", "maxValue": "@new Date().addDay(7)", "minValue": "@new Date().addDay(-7)" } }, { "_icon": "model", "text": "dateRangeControlCt", "cls": "Wb.ControlCt", "properties": { "cid": "dateRangeControlCt", "text": "Date Range", "layout": "row", "gap": "1em" }, "_expanded": true, "items": [ { "_icon": "calendar", "text": "fromDate", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "fromDate" } }, { "_icon": "label", "text": "toLabel", "cls": "Wb.Label", "properties": { "cid": "toLabel", "text": "to" } }, { "_icon": "calendar", "text": "toDate", "cls": "Wb.Date", "_expanded": false, "properties": { "cid": "toDate", "beginDate": "fromDate", "rangeOffset": "3" } } ] } ] }, { "_icon": "title", "text": "timeTitle", "cls": "Wb.Title", "properties": { "cid": "timeTitle", "title": "Time" } }, { "_icon": "container", "text": "timeCt", "cls": "Wb.Container", "properties": { "cid": "timeCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "time", "text": "commonTime", "cls": "Wb.Time", "properties": { "cid": "commonTime", "text": "Common" } }, { "_icon": "time", "text": "localFormatTime", "cls": "Wb.Time", "properties": { "cid": "localFormatTime", "localFormat": "timeText12", "text": "Local Format", "clearButton": "true", "width": "22em" } } ] }, { "_icon": "title", "text": "dateTimeTitle", "cls": "Wb.Title", "properties": { "cid": "dateTimeTitle", "title": "Datetime" }, "_expanded": true }, { "_icon": "container", "text": "datetimeCt", "cls": "Wb.Container", "properties": { "cid": "datetimeCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "dt-picker", "text": "commonDateTime", "cls": "Wb.Datetime", "properties": { "cid": "commonDateTime", "text": "Common" } } ] }, { "_icon": "title", "text": "othersTitle", "cls": "Wb.Title", "properties": { "cid": "othersTitle", "title": "Others" }, "_expanded": true }, { "_icon": "container", "text": "othersCt", "cls": "Wb.Container", "properties": { "cid": "othersCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "month", "text": "yearMonth1", "cls": "Wb.YearMonth", "properties": { "cid": "yearMonth1", "text": "Year Month" } } ] }, { "_icon": "title", "text": "promptTitle", "cls": "Wb.Title", "properties": { "cid": "promptTitle", "title": "Display date/time prompt window through methods" }, "_expanded": true }, { "_icon": "label", "text": "tipLabel", "cls": "Wb.Label", "properties": { "cid": "tipLabel", "text": "There are different dialog representations on the desktop and touch mode." } }, { "_icon": "container", "text": "promptCt", "cls": "Wb.Container", "properties": { "cid": "promptCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "dateAutoBtn", "cls": "Wb.Button", "properties": { "cid": "dateAutoBtn", "text": "Prompt Date auto" }, "events": { "click": "// Auto select drawer or dialog base on touch or desktop\nWb.promptDate(date => Wb.tip(date.dateText), new Date(), 'Select Date');" } }, { "_icon": "button", "text": "dateDrawerBtn", "cls": "Wb.Button", "properties": { "cid": "dateDrawerBtn", "text": "Prompt Date Drawer" }, "events": { "click": "Wb.promptDate(date => Wb.tip(date.dateText), new Date(), 'Select Date', true);" } }, { "_icon": "button", "text": "dateDialogBtn", "cls": "Wb.Button", "properties": { "cid": "dateDialogBtn", "text": "Prompt Date Dialog" }, "events": { "click": "Wb.promptDate(date => Wb.tip(date.dateText), new Date(), 'Select Date', false);" } }, { "_icon": "button", "text": "timeDrawerBtn", "cls": "Wb.Button", "properties": { "cid": "timeDrawerBtn", "text": "Prompt Time Drawer" }, "events": { "click": "Wb.promptTime(date => Wb.tip(date.timeText), null, null, true);" } }, { "_icon": "button", "text": "timeDialogBtn", "cls": "Wb.Button", "properties": { "cid": "timeDialogBtn", "text": "Prompt Time Dialog" }, "events": { "click": "Wb.promptTime(date => Wb.tip(date.timeText), null, null, false);" } }, { "_icon": "button", "text": "dateTimeDrawerBtn", "cls": "Wb.Button", "properties": { "cid": "dateTimeDrawerBtn", "text": "Prompt Datetime Drawer" }, "events": { "click": "Wb.promptDateTime(date => Wb.tip(date.dateTimeText), null, null, true);" } }, { "_icon": "button", "text": "dateTimeDialogBtn", "cls": "Wb.Button", "properties": { "cid": "dateTimeDialogBtn", "text": "Prompt Datetime Dialog" }, "events": { "click": "Wb.promptDateTime(date => Wb.tip(date.dateTimeText), null, null, false);" } }, { "_icon": "button", "text": "monthDrawerBtn", "cls": "Wb.Button", "properties": { "cid": "monthDrawerBtn", "text": "Prompt Month Drawer" }, "events": { "click": "Wb.promptMonth(date => Wb.tip(date.format('y-M')), null, null, true);" } }, { "_icon": "button", "text": "monthDialogBtn", "cls": "Wb.Button", "properties": { "cid": "monthDialogBtn", "text": "Prompt Month Dialog" }, "events": { "click": "Wb.promptMonth(date => Wb.tip(date.format('y-M')), null, null, false);" } }, { "_icon": "button", "text": "preventCloseBtn", "cls": "Wb.Button", "properties": { "cid": "preventCloseBtn", "text": "Prevent Close" }, "events": { "click": "Wb.promptDate(date => {\n Wb.tip('Close prevented');\n return false;\n});" } } ] } ] } ] } # example/comps/decoration.xwl Title: decoration ```json { "title": "", "icon": "label", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Label and decorative components", "cls": "w-title3" } }, { "_icon": "title", "text": "labelTitle", "cls": "Wb.Title", "properties": { "cid": "labelTitle", "title": "Label" }, "_expanded": true }, { "_icon": "container", "text": "labelCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "labelCt", "layout": "form", "frame": "true" }, "items": [ { "_icon": "label", "text": "textLabel", "cls": "Wb.Label", "properties": { "cid": "textLabel", "text": "Text label" } }, { "_icon": "label", "text": "htmlLabel", "cls": "Wb.Label", "properties": { "cid": "htmlLabel", "html": "HTML label" } }, { "_icon": "label", "text": "linkLabel", "cls": "Wb.Label", "properties": { "cid": "linkLabel", "target": "_blank", "href": "https://www.geejing.com", "text": "Link label" } } ] }, { "_icon": "title", "text": "boxLabelTitle", "cls": "Wb.Title", "properties": { "cid": "boxLabelTitle", "title": "BoxLabel" }, "_expanded": true }, { "_icon": "container", "text": "boxLabelCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "boxLabelCt", "layout": "form", "frame": "true", "defaults": "({ width: '10em', height: '5em' })" }, "items": [ { "_icon": "box-label", "text": "centerLabel", "cls": "Wb.BoxLabel", "properties": { "cid": "centerLabel", "text": "Center", "frame": "true" } }, { "_icon": "box-label", "text": "topLeftLabel", "cls": "Wb.BoxLabel", "properties": { "cid": "topLeftLabel", "text": "Top left", "align": "topLeft", "frame": "true" } }, { "_icon": "box-label", "text": "bottomRightLabel", "cls": "Wb.BoxLabel", "properties": { "cid": "bottomRightLabel", "text": "Bottom right", "align": "bottomRight", "frame": "true" } } ] }, { "_icon": "title", "text": "decTitle", "cls": "Wb.Title", "properties": { "cid": "decTitle", "title": "Decorative components" }, "_expanded": true }, { "_icon": "container", "text": "decCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "decCt", "layout": "grid1", "frame": "true" }, "items": [ { "_icon": "title", "text": "commonTitle", "cls": "Wb.Title", "_expanded": true, "properties": { "cid": "commonTitle", "title": "Title" } }, { "_icon": "title", "text": "iconTitle", "cls": "Wb.Title", "_expanded": true, "properties": { "cid": "iconTitle", "title": "Icon title", "icon": "external-link" } }, { "_icon": "title", "text": "noLineTitle", "cls": "Wb.Title", "_expanded": true, "properties": { "cid": "noLineTitle", "title": "Title without line", "icon": "map", "line": "false" } }, { "_icon": "line", "text": "commonLine", "cls": "Wb.Line", "properties": { "cid": "commonLine" } }, { "_icon": "line", "text": "titleLine", "cls": "Wb.Line", "properties": { "cid": "titleLine", "title": "Line Title" } }, { "_icon": "line", "text": "dashedLine", "cls": "Wb.Line", "properties": { "cid": "dashedLine", "dashed": "true", "title": "Dashed Line", "dimTitle": "true" } }, { "_icon": "line", "text": "iconLine", "cls": "Wb.Line", "properties": { "cid": "iconLine", "icon": "favorite", "title": "Icon line" } }, { "_icon": "fieldset", "text": "horizontalFieldSet", "cls": "Wb.Fieldset", "properties": { "cid": "horizontalFieldSet", "title": "Horizontal split and fill", "icon": "splitter", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button 1" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button 2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "text": "Button 3" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "_expanded": false, "properties": { "cid": "space1" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button4", "text": "Button 4" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button5", "text": "Button 5" } } ] }, { "_icon": "fieldset", "text": "verticalFieldSet", "cls": "Wb.Fieldset", "properties": { "cid": "verticalFieldSet", "title": "Vertical split and fill", "icon": "splitter", "layout": "column", "height": "20em", "width": "20em" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button1", "text": "Button 1" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button2", "text": "Button 2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button3", "text": "Button 3" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "_expanded": false, "properties": { "cid": "space1" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button4", "text": "Button 4" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "button5", "text": "Button 5" } } ] } ] }, { "_icon": "title", "text": "compTitle", "cls": "Wb.Title", "properties": { "cid": "compTitle", "title": "Component" }, "_expanded": true }, { "_icon": "container", "text": "compCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "compCt", "layout": "form", "frame": "true" }, "items": [ { "_icon": "component", "text": "component1", "cls": "Wb.Component", "properties": { "cid": "component1", "height": "7em", "width": "25em", "cls": "w-key-color", "html": "Component is a \"div\" element that can show HTML or serve as a placeholder for third-party components.", "padding": "true", "border": "true", "autoScroll": "true" } }, { "_icon": "file-json", "text": "script1", "cls": "Wb.Script", "properties": { "cid": "script1", "script": "({ cname: 'component', html: '
Custom script
' })" } } ] } ] } ] } # example/comps/dual-box/sync-select.xwl Title: sync-select ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let update = [], user_id;\n\nuser_id = Wb.getBool('include') ? 'admin' : 'default';\nWb.getObject('items').forEach(item => {\n update.push({ $sid: item.sid, user_id });\n});\nWb.sync({ tableName: 'wb_staff', update });" }, "_icon": "module" } # example/comps/dual-box.xwl Title: dual-box ```json { "title": "", "icon": "dual-box", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "DualBox", "cls": "w-title3" } }, { "_icon": "title", "text": "localDataTitle", "cls": "Wb.Title", "properties": { "cid": "localDataTitle", "title": "Local data" }, "_expanded": true }, { "_icon": "label", "text": "localDataLabel", "cls": "Wb.Label", "properties": { "cid": "localDataLabel", "text": "Use local data to select" } }, { "_icon": "dual-box", "text": "localDataDualBox", "cls": "Wb.DualBox", "properties": { "cid": "localDataDualBox", "sourceData": "[\n { code: \"10001\", full_name: \"Terri Duffy\" },\n { code: \"10002\", full_name: \"Roberto Tamburello\" },\n { code: \"10003\", full_name: \"Michael Sullivan\" },\n { code: \"10004\", full_name: \"Sharon Salavaria\" },\n { code: \"10005\", full_name: \"Gail Erickson\" },\n { code: \"10006\", full_name: \"Jossef Goldberg\" }\n]", "destData": "[\n { code: \"10007\", full_name: \"Ovidiu Cracium\" },\n { code: \"10008\", full_name: \"Janice Galvin\" },\n { code: \"10009\", full_name: \"Thierry D'Hers\" }\n]", "height": "15em", "textField": "full_name", "subtextField": "code" } }, { "_icon": "button", "text": "getSelectedDataBtn", "cls": "Wb.Button", "properties": { "cid": "getSelectedDataBtn", "text": "Get Selected Data", "justifySelf": "start" }, "events": { "click": "Wb.tip('Selected: ' + Wb.encode(app.localDataDualBox.destData));" } }, { "_icon": "title", "text": "remoteDataTitle", "cls": "Wb.Title", "properties": { "cid": "remoteDataTitle", "title": "Remote data" }, "_expanded": true }, { "_icon": "label", "text": "remoteDataLabel", "cls": "Wb.Label", "properties": { "cid": "remoteDataLabel", "text": "Use remote data to select and sync selections in database" } }, { "_icon": "dual-box", "text": "remoteDataDualBox", "cls": "Wb.DualBox", "properties": { "cid": "remoteDataDualBox", "height": "15em", "sourceUrl": "demo-source?xaction=selectNoneAdminStaff", "destUrl": "demo-source?xaction=selectAdminStaff", "autoLoad": "false", "searchBar": "true" }, "events": { "ready": "let me = this;\n\nme.sourceGrid.pageSize = 10;\nme.sourceGrid.load();\nme.destGrid.pageSize = 10;\nme.destGrid.load();", "beforemove": "Wb.ajax({\n url: xpath + '/sync-select',\n params: { items, include },\n success: f => {\n this.acceptMove(); // this == app.remoteDataDualBox;\n }\n});\nreturn false;" }, "_expanded": true, "items": [ { "cls": "Wb.Grid", "properties": { "cid": "sourceGridConfigs", "isProperty": "true", "title": "User List" }, "text": "sourceGridConfigs", "_expanded": true, "_icon": "grid" }, { "cls": "Wb.Grid", "properties": { "cid": "destGridConfigs", "isProperty": "true", "title": "Admin Users" }, "text": "destGridConfigs", "_expanded": true, "_icon": "grid" } ] }, { "_icon": "title", "text": "customizeColsTitle", "cls": "Wb.Title", "properties": { "cid": "customizeColsTitle", "title": "Customize Columns" }, "_expanded": true }, { "_icon": "label", "text": "customizeColsLabel", "cls": "Wb.Label", "properties": { "cid": "customizeColsLabel", "text": "Customize grid columns" } }, { "_icon": "dual-box", "text": "customizeColsDualBox", "cls": "Wb.DualBox", "properties": { "cid": "customizeColsDualBox", "height": "15em", "sourceUrl": "demo-source?xaction=staffDict", "gridHeader": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "codeCol", "fieldName": "code", "text": "Code" }, "text": "codeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "fullNameCol", "fieldName": "full_name", "text": "Full name", "width": "-1" }, "text": "fullNameCol", "_expanded": true, "_icon": "column" } ] }, { "cls": "Wb.Grid", "properties": { "cid": "sourceGridConfigs", "isProperty": "true", "pagingBar": "false" }, "text": "sourceGridConfigs", "_expanded": true, "_icon": "grid" } ] } ] } ] } # example/comps/grid.xwl Title: grid ```json { "title": "", "icon": "grid", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "description": "demo-source=example/common/demo-source.xwl" }, "_icon": "module", "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "shareMenu", "isProperty": "true", "autoDestroy": "false" }, "text": "shareMenu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Item1" }, "events": { "click": "Wb.tip('Set ' + app.popupRecord.data.full_name);" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Item2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Item3" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Grid", "cls": "w-title3" } }, { "_icon": "title", "text": "commonRemoteGridTitle", "cls": "Wb.Title", "properties": { "cid": "commonRemoteGridTitle", "title": "Common remote grid" } }, { "_icon": "grid", "text": "commonRemoteGrid", "cls": "Wb.Grid", "properties": { "cid": "commonRemoteGrid", "height": "15em", "url": "demo-source?xaction=staffAllDict", "pageSize": "10" }, "_expanded": true, "items": [ { "_icon": "pagenum", "text": "pagingBar", "cls": "Wb.PagingBar", "_expanded": true, "properties": { "cid": "pagingBar", "isProperty": "true", "showPageEdit": "false" } } ] }, { "_icon": "title", "text": "miscGridTitle", "cls": "Wb.Title", "properties": { "cid": "miscGridTitle", "title": "Miscillaneous grid" }, "_expanded": true }, { "_icon": "grid", "text": "miscGrid", "cls": "Wb.Grid", "properties": { "cid": "miscGrid", "height": "20em", "localData": "[\n { _icon: \"user1\", code: \"10001\", full_name: \"Terri Duffy\", gender: \"Female\", birth_date: \"2002-07-01\".dateValue, salary: 28743, checked: 1, email: \"terri0@geejing.com\" },\n { _icon: \"user\", code: \"10002\", full_name: \"Roberto Tamburello\", gender: \"Male\", birth_date: \"1986-12-13\".dateValue, salary: 16453, checked: 0, email: \"roberto0@geejing.com\" },\n { _icon: \"user\", code: \"10003\", full_name: \"Michael Sullivan\", gender: \"Male\", birth_date: \"1991-07-17\".dateValue, salary: 32893, checked: 1, email: \"michael8@geejing.com\" },\n { _icon: \"user1\", code: \"10004\", full_name: \"Sharon Salavaria\", gender: \"Female\", birth_date: \"1973-06-03\".dateValue, salary: 63237, checked: 0, email: \"sharon0@geejing.com\" },\n { _icon: \"user1\", code: \"10005\", full_name: \"Gail Erickson\", gender: \"Female\", birth_date: \"1964-10-29\".dateValue, salary: 63219.5, checked: 1, email: \"gail0@geejing.com\" },\n { _icon: \"user\", code: \"10006\", full_name: \"Jossef Goldberg\", gender: \"Male\", birth_date: \"1971-04-11\".dateValue, salary: 23130, checked: 0, email: \"jossef0@geejing.com\" },\n { _icon: \"user\", code: \"10007\", full_name: \"Ovidiu Cracium\", gender: \"Male\", birth_date: \"1990-02-18\".dateValue, salary: 83231, checked: 0, email: \"ovidiu0@geejing.com\" },\n { _icon: \"user1\", code: \"10008\", full_name: \"Janice Galvin\", gender: \"Female\", birth_date: \"2001-06-29\".dateValue, salary: 152310, checked: 0, email: \"janice0@geejing.com\" },\n { _icon: \"user\", code: \"10009\", full_name: \"Thierry D'Hers\", gender: \"Male\", birth_date: \"1971-08-29\".dateValue, salary: 2383, checked: 1, email: \"thierry0@geejing.com\" },\n { _icon: \"user\", code: \"10010\", subtext: 'Sub text', full_name: \"Brian Welcker\", gender: \"Male\", birth_date: \"1989-07-08\".dateValue, salary: 98313, checked: 1, email: \"brian3@geejing.com\" },\n { _icon: \"user\", code: \"10011\", full_name: \"Stephen Jiang\", gender: \"Male\", birth_date: \"1963-11-17\".dateValue, salary: 53231, checked: 0, email: \"stephen0@geejing.com\" },\n { _icon: \"user\", code: \"10012\", full_name: \"Syed Abbas\", gender: \"Male\", birth_date: \"1987-02-11\".dateValue, salary: 38925.8, checked: 1, _disabled: true, email: \"syed0@geejing.com\" }\n]", "pageSize": "10", "showIcon": "true", "sorters": "full_name", "columnsSortable": "true", "resizable": "true", "stateId": "wb.miscGrid", "frame": "true", "captureClass": "@'.w-btn' /* prevent select and focus row when click row buttons */", "exportFilename": "staff-list", "exportTitle": "Staff List" }, "_expanded": true, "events": { "itemdblclick": "Wb.tip(item.data.full_name + ' row double clicked');", "click": "let link = e.target.closest('.my-link');\nif (link) {\n let row = this.findItemByEl(link);\n Wb.tip(link.textContent + ' clicked at ' + row.data.full_name);\n}", "beforesort": "// Customize local sort\n// data.sort((a, b) => Wb.mixCompare(a.full_name, b.full_name));\n// return false;" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": false, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true", "freeze": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "codeCol", "text": "Code", "width": "8em", "fieldName": "code", "freeze": "true", "summaryRender": "return 'Total:';" }, "text": "codeCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "personalCol", "cls": "Wb.Column", "properties": { "cid": "personalCol", "text": "Personal" }, "_expanded": true, "items": [ { "_icon": "column", "text": "commonCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "commonCol", "text": "Common" }, "items": [ { "cls": "Wb.Column", "properties": { "cid": "fullNameCol", "width": "-1", "fieldName": "full_name", "autoWrap": "normal", "titleAlign": "center", "titleAutoWrap": "normal", "html": "Full name", "align": "center", "summary": "count", "summaryRender": "return value + ' P';", "render": "el.setStyle('background', 'linear-gradient(to right, rgb(142 36 159) ' + (data.salary / 1800) + '%, rgb(85, 85, 85) 0%)', 'important');\nel.setStyle('color', '#fff');\nreturn value;" }, "text": "fullNameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "genderCol", "text": "Gender", "width": "8em", "fieldName": "gender", "render": "let div = el.addEl('w-center').addEl('w-ta-center');\n\ndiv.style = `color:#fff;width:5em;background:${value == 'Male' ? '#ff5d8d' : '#095c09'}`;\ndiv.textContent = value;" }, "text": "genderCol", "_expanded": true, "_icon": "column" } ] }, { "cls": "Wb.Column", "properties": { "cid": "birthDateCol", "text": "Birth_date", "width": "12em", "fieldName": "birth_date", "render": "if (value < '1974-1-1'.dateValue) {\n // if (value < '1974-1-1'.dateValue) {\n // let div = el.parentNode;\n\n // //tip: Setting important classes or styles for elements has higher css priority and can override the default background/color\n // //Setting td classes/styles will override all default background/color\n // if (value < '1968-1-1'.dateValue) {\n // div.setStyle('background', '#1890ff');\n // } else {\n // div.setStyle('background', '#f90');\n // }\n // div.setStyle('color', 'white');\n // value = value + ' *';\n // }\n //w-succ-bgcolor-row, w-error-bgcolor-row etc\n el.parentNode.cls = value < '1968-1-1'.dateValue ? 'w-succ-bgcolor-row' : 'w-warn-bgcolor-row';\n value += ' *';\n};\n\n//add icon manually\nel.insertCellIcon('time', value);\n//el.insertCellImage('wb/images/sound.png');" }, "text": "birthDateCol", "_expanded": true, "_icon": "column" } ] }, { "cls": "Wb.Column", "properties": { "cid": "salaryCol", "text": "Salary", "fieldName": "salary", "titleAlign": "right", "type": "usd", "summary": "sum", "summaryRender": "let ct = data.full_name;// full_name column summary is \"count\"\nif (ct == null)\n return ''; // full_name column is hidden\nelse\n return 'Avg: ' + column.formatValue(value / ct);", "align": "right" }, "text": "salaryCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "checkCol1", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol1", "checkBox": "int", "fieldName": "checked", "checkRefresh": "true", "menuText": "Check" } }, { "_icon": "column", "text": "checkCol2", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol2", "checkBox": "roTrue", "fieldName": "checked" } }, { "_icon": "column", "text": "checkCol3", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol3", "checkBox": "roAll", "fieldName": "checked" } }, { "_icon": "column", "text": "toggleCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "toggleCol", "render": "let row = this;\nvalue = row.data.checked;\nrow.addFooter({\n cname: 'toggle', returnType: 'int', value, toggleAlign: 'center', clickToggle: true,\n events: {\n change(value) {\n // If there is no need to synchronously update other fields, this is more efficient\n // row.data.checked = value; // only update checked field value\n row.set('checked', value); // update whole row\n app.checkCol1.syncHeaderCheck(); // manual sync header check of checkCol1\n }\n }\n}, el);", "width": "5em", "text": "Toggle" } }, { "_icon": "column", "text": "linkCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "linkCol", "render": "let a = el.addEl('my-link', 'a');\nel.cls = 'w-ta-center';\na.textContent = 'Download';\n// a.onclick = f => Wb.tip(data.full_name); // not recommended\n// miscGrid.click mon the link click event // recommended", "width": "8em", "text": "Link" } }, { "_icon": "column", "text": "actionsCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "actionsCol", "text": "Actions", "width": "8em", "freeze": "true" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "setItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "setItem", "icon": "gear", "tip": "Set" }, "events": { "click": "Wb.tip('Set ' + this.data.code + ', ' + this.gridItem.data.code);" } }, { "_icon": "item", "text": "shareItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "shareItem", "icon": "share2", "tip": "Add" }, "events": { "click": "Wb.tip('Share ' + this.data.code);" } }, { "_icon": "item", "text": "menuItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "menuItem", "icon": "menu" }, "events": { "click": "app.popupRecord = this.parent.parent;\n//app.popupRecord = app.miscGrid.selection; // same as above\n//app.popupRecord = this.el.getClosestComp(Wb.ViewItem); // same as above\napp.shareMenu.showBy(this);" } } ] } ] } ] }, { "cls": "Wb.Menu", "properties": { "cid": "contextMenu", "isProperty": "true" }, "text": "contextMenu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "showRowColumnItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "showRowColumnItem", "icon": "grid", "text": "Show row column" }, "events": { "click": "let el, row, col;\n\nel = this.contextTarget; // clicked element\nrow = app.miscGrid.findItemByEl(el); // same as app.miscGrid.selection\ncol = app.miscGrid.findColumnByEl(el);\nif (row && col)\n Wb.tip('Row code is ' + row.data.code + ' and column field name is ' + col.fieldName);" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Other item" } } ] } ] }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "form", "padding": "false" }, "_expanded": true, "items": [ { "_icon": "button", "text": "testfrozenBtn", "cls": "Wb.Button", "properties": { "cid": "testfrozenBtn", "text": "Test frozen columns" }, "events": { "click": "app.fullNameCol.width = app.miscGrid.width;\nWb.toast('Now please scroll horizontally to test the left and right frozen columns.')" } }, { "_icon": "button", "text": "sortDataBtn", "cls": "Wb.Button", "properties": { "cid": "sortDataBtn", "text": "Sort Data" }, "events": { "click": "app.miscGrid.sort({ name: 'code', desc: true });" } }, { "_icon": "button", "text": "sortItemsBtn", "cls": "Wb.Button", "properties": { "cid": "sortItemsBtn", "text": "Sort Items" }, "events": { "click": "// Sort view items only\napp.miscGrid.sortItems((a, b) => Wb.mixCompare(a.data.code, b.data.code));" } } ] }, { "_icon": "component", "text": "miscDescComp", "cls": "Wb.Component", "properties": { "cid": "miscDescComp", "html": "
Feature List:
\n
    \n
  • Columns sortable, resizable, draggable and freezable.
  • \n
  • Arbitrary multi-Level Headers.
  • \n
  • Customize cell rendering.
  • \n
  • Rows and columns highlighing.
  • \n
  • Local data pagination.
  • \n
  • Bind buttons or any controls to cells.
  • \n
  • Multiple styles of check columns.
  • \n
  • Customize columns and persistence to the database.
  • \n
  • Summary row.
  • \n
", "textSelectable": "false" } }, { "_icon": "title", "text": "editableGridTitle", "cls": "Wb.Title", "properties": { "cid": "editableGridTitle", "title": "Editable grid" } }, { "_icon": "grid", "text": "editableGrid", "cls": "Wb.Grid", "properties": { "cid": "editableGrid", "height": "15em", "url": "demo-source?xaction=staffAllDict", "columnsSortable": "true", "sorters": "[{name: 'gender', desc: true}, 'salary']", "editable": "true", "multiSelect": "true", "pageSize": "10", "arrowDownAppend": "true", "enterAppend": "true", "enterAsTab": "true", "frame": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "//Some related methods: grid.add()/grid.addData()/grid.insert()/grid.insertData()/grid.insertXXX()/grid.insertDataXXX() etc.\napp.editableGrid.addRecord();" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let firstRec = app.editableGrid.firstItem;\nif (firstRec) {\n firstRec.set({ code: 'code', full_name: 'new name' });\n app.editableGrid.startEdit(firstRec, 'code');\n firstRec.highlight();\n}" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "//Some related methods: grid.destroySelection()/item.destroy()/Wb.destroy(items);\napp.editableGrid.delRecords();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveBtn", "text": "@Str.save", "icon": "save", "keys": "Ctrl+S" }, "events": { "click": "app.editableGrid.sync({\n url: xpath, //Should be changed to a valid URL\n success() {\n Wb.tipDone(Str.save);\n }\n});" } } ] } ] }, { "_icon": "title", "text": "dbPaginationTitle", "cls": "Wb.Title", "properties": { "cid": "dbPaginationTitle", "title": "Database side pagination" } }, { "_icon": "label", "text": "dbPaginationLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "dbPaginationLabel", "text": "This example demonstrates database side pagination." } }, { "_icon": "grid", "text": "dbPaginationGrid", "cls": "Wb.Grid", "properties": { "cid": "dbPaginationGrid", "height": "15em", "url": "demo-source?xaction=staffDbPaging", "pageSize": "10", "pagingBar": "pageNums" }, "_expanded": true }, { "_icon": "title", "text": "noPagingTitle", "cls": "Wb.Title", "properties": { "cid": "noPagingTitle", "title": "No pagination" } }, { "_icon": "grid", "text": "noPagingGrid", "cls": "Wb.Grid", "properties": { "cid": "noPagingGrid", "height": "15em", "url": "demo-source?xaction=staffAllDict", "pageSize": "-1" }, "_expanded": true }, { "_icon": "title", "text": "mergeTitle", "cls": "Wb.Title", "properties": { "cid": "mergeTitle", "title": "Merge rows and columns" } }, { "_icon": "label", "text": "mergeLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "mergeLabel", "text": "Merge f1 rows and merge f1, f2 columns, see f1Col and f2Col properties." } }, { "_icon": "grid", "text": "mergeGrid", "cls": "Wb.Grid", "properties": { "cid": "mergeGrid", "url": "demo-source?xaction=selectReport1" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f1Col", "text": "f1", "fieldName": "f1", "mergeRows": "true", "mergeColsGroup": "mergeTotal", "autoWrap": "normal", "width": "12em" }, "text": "f1Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f2Col", "text": "f2", "fieldName": "f2", "mergeColsGroup": "mergeTotal", "width": "14em" }, "text": "f2Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f3Col", "text": "f3", "fieldName": "f3" }, "text": "f3Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f4Col", "text": "f4", "fieldName": "f4" }, "text": "f4Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f5Col", "text": "f5", "fieldName": "f5" }, "text": "f5Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f6Col", "text": "f6", "fieldName": "f6" }, "text": "f6Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f7Col", "text": "f7", "fieldName": "f7" }, "text": "f7Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f8Col", "text": "f8", "fieldName": "f8" }, "text": "f8Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f9Col", "text": "f9", "fieldName": "f9" }, "text": "f9Col", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "f10Col", "text": "f10", "fieldName": "f10" }, "text": "f10Col", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "title", "text": "dragDropTitle", "cls": "Wb.Title", "properties": { "cid": "dragDropTitle", "title": "Drag-drop rows" } }, { "_icon": "grid", "text": "dragDropGrid", "cls": "Wb.Grid", "properties": { "cid": "dragDropGrid", "height": "30em", "url": "demo-source?xaction=staffAllDict", "pageSize": "10", "draggable": "true", "droppable": "demo.dragDropGrid", "multiSelect": "true" }, "_expanded": true, "events": { "itemdrop": "let n = draggable.source.length;\nWb.tip(draggable.source.length + ' ' + (n > 1 ? 'items' : 'item') + ' dropped.');", "itemdrag": "if (draggable.source.some(row => row.data.code == '10009') || draggable.dest.data.code == '10001') {\n //Do not allow to drop when the source record code contains 10009 or dest record code is 10001\n draggable.allowDrop = false;\n}" } }, { "_icon": "title", "text": "propertyGridTitle", "cls": "Wb.Title", "properties": { "cid": "propertyGridTitle", "title": "Property grid" }, "_expanded": true }, { "_icon": "grid", "text": "propertyGrid", "cls": "Wb.Grid", "properties": { "cid": "propertyGrid", "localData": "[\n { name: 'String', value: 'abc' },\n { name: 'Integer', value: 123 },\n { name: 'Float', value: 456.78 },\n { name: 'Date', value: new Date().datePart },\n { name: 'Boolean', value: true },\n]", "frame": "true", "editable": "true", "pagingBar": "false" }, "_expanded": true, "events": { "beforeedit": "if (column.fieldName == 'value') {\n app.editors ??= {\n String: new Wb.Text(),\n Integer: new Wb.Number({ decimalCount: 0 }),\n Float: new Wb.Number(),\n Date: new Wb.Date(),\n Boolean: new Wb.BoolSelect()\n };\n column.editor = app.editors[row.data.name] ?? app.editors.String;\n}" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "nameCol", "text": "Name", "fieldName": "name", "render": "el.addCls('w-fixed-cell');\nreturn value;" }, "text": "nameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "valueCol", "text": "Value", "width": "-1", "fieldName": "value", "align": "left" }, "text": "valueCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # example/comps/html-editor.xwl Title: html-editor ```json { "title": "", "icon": "file-html", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "file-html", "text": "htmlEditor1", "cls": "Wb.HtmlEditor", "properties": { "cid": "htmlEditor1", "wrapBorder": "false", "value": "

\n Rich\n Text\n Editor\n

" } } ] } ] } # example/comps/input.xwl Title: input ```json { "title": "", "icon": "text", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Input controls", "cls": "w-title3" } }, { "_icon": "title", "text": "textTitle", "cls": "Wb.Title", "properties": { "cid": "textTitle", "title": "Text" } }, { "_icon": "container", "text": "textCt", "cls": "Wb.Container", "properties": { "cid": "textCt", "layout": "grid", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "commonText", "cls": "Wb.Text", "properties": { "cid": "commonText", "text": "Common", "placeholder": "placeholder" } }, { "_icon": "text", "text": "passwordText", "cls": "Wb.Text", "properties": { "cid": "passwordText", "text": "Password", "eyeButton": "true", "password": "true", "icon": "lock" } }, { "_icon": "text", "text": "clearText", "cls": "Wb.Text", "properties": { "cid": "clearText", "text": "With Clear", "clearButton": "true" } }, { "_icon": "text", "text": "hintText", "cls": "Wb.Text", "properties": { "cid": "hintText", "hint": "Please enter your name", "text": "Input Hint" } }, { "_icon": "text", "text": "alignText", "cls": "Wb.Text", "_expanded": false, "properties": { "cid": "alignText", "text": "Left Align Text", "labelAlign": "left" } }, { "_icon": "text", "text": "prefixSuffixText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "prefixSuffixText", "prefix": "$", "suffix": "%", "text": "Prefix Suffix" } }, { "_icon": "text", "text": "readonlyText", "cls": "Wb.Text", "_expanded": false, "properties": { "cid": "readonlyText", "readonly": "true", "text": "Readonly" } }, { "_icon": "text", "text": "disabledText", "cls": "Wb.Text", "_expanded": false, "properties": { "cid": "disabledText", "disabled": "true", "text": "Disabled" } }, { "_icon": "text", "text": "emptyLabelText", "cls": "Wb.Text", "properties": { "cid": "emptyLabelText", "showEmptyLabel": "true", "placeholder": "empty label" } }, { "_icon": "text", "text": "loadingText", "cls": "Wb.Text", "properties": { "cid": "loadingText", "spin": "true", "icon": "loading1", "text": "Loading" } }, { "_icon": "text", "text": "flatText", "cls": "Wb.Text", "properties": { "cid": "flatText", "text": "Flat", "flat": "true", "inactiveBorder": "true" }, "_expanded": true }, { "_icon": "label1", "text": "displayField1", "cls": "Wb.DisplayField", "properties": { "cid": "displayField1", "value": "Display value", "icon": "info", "showEmptyLabel": "true" } }, { "_icon": "label1", "text": "displayField2", "cls": "Wb.DisplayField", "properties": { "cid": "displayField2", "value": "No label", "icon": "info" } }, { "_icon": "text", "text": "iconLabelText", "cls": "Wb.Text", "properties": { "cid": "iconLabelText", "labelIcon": "book1", "text": "Icon label", "labelAlign": "left", "labelSeparator": "false" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "_expanded": true, "properties": { "cid": "fill1" } }, { "_icon": "text", "text": "upLabelText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "upLabelText", "labelUp": "true", "text": "The label is above the input box" } } ] }, { "_icon": "title", "text": "numberTitle", "cls": "Wb.Title", "properties": { "cid": "numberTitle", "title": "Number" }, "_expanded": true }, { "_icon": "container", "text": "numberCt", "cls": "Wb.Container", "properties": { "cid": "numberCt", "layout": "grid", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "number-edit", "text": "commonNumber", "cls": "Wb.Number", "properties": { "cid": "commonNumber", "text": "Common Number" } }, { "_icon": "number-edit", "text": "upDownNumber", "cls": "Wb.Number", "properties": { "cid": "upDownNumber", "text": "Up Down", "spinner": "upDown" }, "_expanded": true }, { "_icon": "number-edit", "text": "leftRightNumber", "cls": "Wb.Number", "properties": { "cid": "leftRightNumber", "text": "Left Right", "spinner": "leftRight" } }, { "_icon": "number-edit", "text": "beforeAfterNumber", "cls": "Wb.Number", "properties": { "cid": "beforeAfterNumber", "text": "Before After", "spinner": "beforeAfter" } }, { "_icon": "number-edit", "text": "noSpinnerNumber", "cls": "Wb.Number", "properties": { "cid": "noSpinnerNumber", "text": "No Spinner", "spinner": "false", "numberInput": "true /* Show number keyboard in phone */" } }, { "_icon": "number-edit", "text": "step5Number", "cls": "Wb.Number", "properties": { "cid": "step5Number", "text": "Step 5", "step": "5" } }, { "_icon": "number-edit", "text": "dicimal3Number", "cls": "Wb.Number", "properties": { "cid": "dicimal3Number", "text": "Max 3 Dicimals", "decimalCount": "3" }, "_expanded": true }, { "_icon": "number-edit", "text": "autoFormatNumber", "cls": "Wb.Number", "properties": { "cid": "autoFormatNumber", "text": "Auto Format", "decimalCount": "2", "prefix": "$", "suffix": "%", "autoFormat": "true", "value": "1234.567" }, "_expanded": true }, { "_icon": "number-edit", "text": "constrainNumber", "cls": "Wb.Number", "properties": { "cid": "constrainNumber", "text": "10 - 20", "minValue": "10", "maxValue": "20" } } ] }, { "_icon": "title", "text": "textAreaTitle", "cls": "Wb.Title", "properties": { "cid": "textAreaTitle", "title": "Text Area" }, "_expanded": true }, { "_icon": "container", "text": "textAreaCt", "cls": "Wb.Container", "properties": { "cid": "textAreaCt", "layout": "grid", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "textarea", "text": "commonTextArea", "cls": "Wb.TextArea", "properties": { "cid": "commonTextArea", "text": "Common TextArea" }, "_expanded": true }, { "_icon": "textarea", "text": "noWrapTextArea", "cls": "Wb.TextArea", "properties": { "cid": "noWrapTextArea", "text": "No Wrap", "value": "WebBuilder is a powerful rapid application development and runtime platform", "noWrap": "true" }, "_expanded": true }, { "_icon": "textarea", "text": "overflowTextArea", "cls": "Wb.TextArea", "properties": { "cid": "overflowTextArea", "text": "Now The Text Label Overflowed" }, "_expanded": true }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1" } }, { "_icon": "textarea", "text": "autoResizeTextArea", "cls": "Wb.TextArea", "properties": { "cid": "autoResizeTextArea", "text": "Auto Resize", "autoResize": "true", "rows": "1", "value": "Auto resize to fit content height", "maxHeight": "10em" }, "_expanded": true } ] }, { "_icon": "title", "text": "fileInputTitle", "cls": "Wb.Title", "properties": { "cid": "fileInputTitle", "title": "File Input" }, "_expanded": true }, { "_icon": "label", "text": "fileInputLabel", "cls": "Wb.Label", "properties": { "cid": "fileInputLabel", "text": "You can drag and drop files from the operating system shell to the file control." } }, { "_icon": "container", "text": "fileInputCt", "cls": "Wb.Container", "properties": { "cid": "fileInputCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "search-file", "text": "commonFileInput", "cls": "Wb.FileInput", "properties": { "cid": "commonFileInput", "text": "Common" } }, { "_icon": "search-file", "text": "multipleFileInput", "cls": "Wb.FileInput", "properties": { "cid": "multipleFileInput", "text": "Multiple", "multiple": "true" } }, { "_icon": "search-file", "text": "browseFileInput", "cls": "Wb.FileInput", "properties": { "cid": "browseFileInput", "browseMode": "true", "text": "Browse file", "multiple": "true" } }, { "_icon": "search-file", "text": "virtualFilesFileInput", "cls": "Wb.FileInput", "properties": { "cid": "virtualFilesFileInput", "text": "Virtual Files", "multiple": "true", "value": "[{name: 'file1.xlsx', size: 8958}, {name:' file2.png', size: 32842}]" } } ] }, { "_icon": "title", "text": "validationTitle", "cls": "Wb.Title", "properties": { "cid": "validationTitle", "title": "Validation value" }, "_expanded": true }, { "_icon": "container", "text": "validationCt", "cls": "Wb.Container", "properties": { "cid": "validationCt", "layout": "grid", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "requiredText1", "cls": "Wb.Text", "properties": { "cid": "requiredText1", "text": "Required1", "required": "true" } }, { "_icon": "text", "text": "requiredText2", "cls": "Wb.Text", "properties": { "cid": "requiredText2", "text": "Required2", "required": "true", "sideErrorTip": "true" } }, { "_icon": "text", "text": "lengthText", "cls": "Wb.Text", "properties": { "cid": "lengthText", "text": "Limit Length", "minLength": "3", "maxLength": "9" } }, { "_icon": "text", "text": "alphaNumText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "alphaNumText", "valueType": "alphaNum", "text": "Alpha num" } }, { "_icon": "text", "text": "emailText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "emailText", "valueType": "email", "text": "Email" } }, { "_icon": "text", "text": "urlText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "urlText", "valueType": "url", "text": "URL" } }, { "_icon": "text", "text": "regExpText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "regExpText", "text": "Regular Exp", "regexText": "Please enter at least 5 digits", "placeholder": "enter 5 digits", "regex": "/\\d{5}$/" } }, { "_icon": "text", "text": "customValidateText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "customValidateText", "validator": "if (value != 'good')\n return 'Please enter \"good\"';", "text": "Custom Validation" } }, { "_icon": "text", "text": "remoteValidateText", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "remoteValidateText", "validator": "let editor = this;\n\nWb.ajax({\n url: 'demo-source?xaction=checkUser',\n params: { username: value },\n mask: false,\n callback(resp, xhr) {\n editor.removeError();\n if (resp == 'failed' || !xhr.ok)\n editor.addError(Str.alreadyExists.format(value));\n }\n});", "text": "Remote Validation", "placeholder": "user name" } } ] }, { "_icon": "title", "text": "sizeTitle", "cls": "Wb.Title", "properties": { "cid": "sizeTitle", "title": "Input size" } }, { "_icon": "label", "text": "sizeLabel", "cls": "Wb.Label", "properties": { "cid": "sizeLabel", "text": "Set the \"fontSize\" property to set input size" }, "_expanded": true }, { "_icon": "container", "text": "sizeCt", "cls": "Wb.Container", "properties": { "cid": "sizeCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "text", "fontSize": ".8em" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "number", "fontSize": "1.2em" } }, { "_icon": "combo", "text": "select1", "cls": "Wb.Select", "properties": { "cid": "select1", "text": "select", "fontSize": "1.4em", "data": "['item1', 'item2', 'item3']" } } ] } ] } ] } # example/comps/misc-comps.xwl Title: misc-comps ```json { "title": "", "icon": "list1", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Miscellaneous comps", "cls": "w-title3" } }, { "_icon": "title", "text": "controlCtTitle", "cls": "Wb.Title", "properties": { "cid": "controlCtTitle", "title": "ControlCt" } }, { "_icon": "label", "text": "controlCtLabel", "cls": "Wb.Label", "properties": { "cid": "controlCtLabel", "text": "Control container, like a control with a label, can also add child controls." }, "_expanded": true }, { "_icon": "container", "text": "controlCtCt", "cls": "Wb.Container", "properties": { "cid": "controlCtCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "model", "text": "controlCt", "cls": "Wb.ControlCt", "properties": { "cid": "controlCt", "text": "Container label", "layout": "form" }, "_expanded": true, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1" }, "_expanded": true }, { "_icon": "label", "text": "label1", "cls": "Wb.Label", "properties": { "cid": "label1", "text": "Label" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button" }, "_expanded": true } ] }, { "_icon": "text", "text": "controlCtAlignText", "cls": "Wb.Text", "properties": { "cid": "controlCtAlignText", "text": "Other control" } } ] }, { "_icon": "title", "text": "scrolledCtTitle", "cls": "Wb.Title", "properties": { "cid": "scrolledCtTitle", "title": "ScrolledCt" } }, { "_icon": "label", "text": "scrolledCtLabel", "cls": "Wb.Label", "properties": { "cid": "scrolledCtLabel", "text": "Scrolled container can automatically scroll without scrollbar." }, "_expanded": true }, { "_icon": "container", "text": "scrolledCtCt", "cls": "Wb.Container", "properties": { "cid": "scrolledCtCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "position", "text": "scrolledCt", "cls": "Wb.ScrolledCt", "properties": { "cid": "scrolledCt", "layout": "row", "width": "30em", "gap": "true", "padding": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button1" } }, { "_icon": "button", "text": "button2", "cls": "Wb.Button", "properties": { "cid": "button2", "text": "Button2" } }, { "_icon": "button", "text": "button3", "cls": "Wb.Button", "properties": { "cid": "button3", "text": "Button3" } }, { "_icon": "button", "text": "button4", "cls": "Wb.Button", "properties": { "cid": "button4", "text": "Button4" } }, { "_icon": "button", "text": "button5", "cls": "Wb.Button", "properties": { "cid": "button5", "text": "Button5" } }, { "_icon": "button", "text": "button6", "cls": "Wb.Button", "properties": { "cid": "button6", "text": "Button6" } } ] } ] }, { "_icon": "title", "text": "carouselTitle", "cls": "Wb.Title", "properties": { "cid": "carouselTitle", "title": "Carousel" } }, { "_icon": "label", "text": "carouselLabel", "cls": "Wb.Label", "properties": { "cid": "carouselLabel", "text": "Automatic carousel play container." }, "_expanded": true }, { "_icon": "container", "text": "carouselCt", "cls": "Wb.Container", "properties": { "cid": "carouselCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "play1", "text": "carousel1", "cls": "Wb.Carousel", "properties": { "cid": "carousel1", "frame": "true", "height": "8em", "interval": "2000" }, "_expanded": true, "items": [ { "_icon": "component", "text": "component1", "cls": "Wb.Component", "properties": { "cid": "component1", "background": "#f88", "cls": "w-center", "text": "Comp1", "style": "color:#fff" } }, { "_icon": "component", "text": "component2", "cls": "Wb.Component", "properties": { "cid": "component2", "background": "#8f8", "cls": "w-center", "text": "Comp2", "style": "color:#000" } }, { "_icon": "component", "text": "component3", "cls": "Wb.Component", "properties": { "cid": "component3", "background": "#ababf7", "cls": "w-center", "text": "Comp3", "style": "color:#fff" } }, { "_icon": "component", "text": "component4", "cls": "Wb.Component", "properties": { "cid": "component4", "background": "#3bdbd9", "cls": "w-center", "text": "Comp4", "style": "color:#fff" } } ] } ] }, { "_icon": "title", "text": "progressBarTitle", "cls": "Wb.Title", "properties": { "cid": "progressBarTitle", "title": "ProgressBar" } }, { "_icon": "label", "text": "progressBarLabel", "cls": "Wb.Label", "properties": { "cid": "progressBarLabel", "text": "Display progress through graphics and text." }, "_expanded": true }, { "_icon": "container", "text": "progressBarCt", "cls": "Wb.Container", "properties": { "cid": "progressBarCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "progress", "text": "progressBar1", "cls": "Wb.ProgressBar", "properties": { "cid": "progressBar1", "value": "35" } }, { "_icon": "progress", "text": "progressBar2", "cls": "Wb.ProgressBar", "properties": { "cid": "progressBar2", "value": "68.5", "progressText": "Copying files" } } ] } ] } ] } # example/comps/option.xwl Title: option ```json { "title": "", "icon": "options", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "autoScroll": "true", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Option", "cls": "w-title3" } }, { "_icon": "title", "text": "commonTitle", "cls": "Wb.Title", "properties": { "cid": "commonTitle", "title": "Common Options" }, "_expanded": true }, { "_icon": "container", "text": "optionCt", "cls": "Wb.Container", "properties": { "cid": "optionCt", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "options", "text": "commonOption", "cls": "Wb.Option", "properties": { "cid": "commonOption", "text": "Common options, click show dialog", "border": "bottom", "valueText": "Value text" }, "_expanded": true, "events": { "click": "app.dialog1 ??= new Wb.Dialog({\n title: 'New dialog', border: 0, defaults: { cname: 'option' }, items: [\n { cname: 'label', text: 'Group1', indent: true, titleType: 'title5' },\n { text: 'Option1', handler() { Wb.tip('Option1 clicked') } },\n { text: 'Option2', handler() { Wb.tip('Option2 clicked') } },\n '-',\n { cname: 'label', text: 'Group2', indent: true, titleType: 'title5' },\n { text: 'Option3', editor: { cname: 'toggle' } },\n { text: 'Option4', editor: { cname: 'toggle' } },\n ]\n});\napp.dialog1.show();" } }, { "_icon": "options", "text": "checkedItemsOption", "cls": "Wb.Option", "properties": { "cid": "checkedItemsOption", "text": "Web browser", "border": "bottom", "description": "The default browser to be used", "options": "[\n { text: 'Chrome', value: 1, _icon: 'chrome' },\n { text: 'Edge', value: 2, _icon: 'edge', _selected: true },\n { text: 'Firefox', value: 3, _icon: 'firefox' },\n { text: 'Safari', value: 4, _icon: 'safari' }\n]", "value": "2", "optionsTitle": "Select Browser" }, "_expanded": true }, { "_icon": "options", "text": "toggleOption", "cls": "Wb.Option", "properties": { "cid": "toggleOption", "text": "Option with toggle", "border": "bottom" }, "_expanded": true, "items": [ { "cls": "Wb.Toggle", "properties": { "cid": "editor", "isProperty": "true" }, "text": "editor", "_expanded": true, "_icon": "switcher-on" } ] }, { "_icon": "options", "text": "toggleClickOnToggleOption", "cls": "Wb.Option", "properties": { "cid": "toggleClickOnToggleOption", "text": "Option with toggle, only allow click on the toggle component", "border": "bottom", "allowClick": "false" }, "_expanded": true, "items": [ { "cls": "Wb.Toggle", "properties": { "cid": "editor", "isProperty": "true" }, "text": "editor", "_expanded": true, "_icon": "switcher-on" } ] }, { "_icon": "options", "text": "iconOption", "cls": "Wb.Option", "properties": { "cid": "iconOption", "text": "Option with icon", "border": "bottom", "icon": "calendar", "flagIcon": "menu" }, "_expanded": true, "events": { "click": "Wb.tip('clicked');" } }, { "_icon": "options", "text": "customOption", "cls": "Wb.Option", "properties": { "cid": "customOption", "text": "Custom option", "border": "bottom", "icon": "message", "flagIcon": "share1", "valueText": "Some value" }, "_expanded": true, "events": { "click": "Wb.tip('clicked');", "ready": "let imgEl = this.el.insertElBefore('w-unselect', 'img', this.flagEl);\nimgEl.src = 'wb/images/order.png';\nimgEl.draggable = false;" } }, { "_icon": "options", "text": "disabledOption", "cls": "Wb.Option", "properties": { "cid": "disabledOption", "text": "Disabled option", "disabled": "true" }, "_expanded": true } ] }, { "_icon": "title", "text": "editorTitle", "cls": "Wb.Title", "properties": { "cid": "editorTitle", "title": "Editor Options" }, "_expanded": true }, { "_icon": "container", "text": "editorCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "editorCt", "background": "true", "layout": "grid1" }, "items": [ { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "Option style" } }, { "_icon": "container", "text": "optionCt1", "cls": "Wb.Container", "properties": { "cid": "optionCt1", "background": "false", "roundBorder": "true", "defaults": "({ labelWidth: '8em' })" }, "_expanded": true, "items": [ { "_icon": "options", "text": "nameOption", "cls": "Wb.Option", "properties": { "cid": "nameOption", "text": "Name", "border": "bottom" }, "_expanded": true, "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "flex": "1", "flat": "true", "placeholder": "Your name" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "_icon": "options", "text": "heightOption", "cls": "Wb.Option", "properties": { "cid": "heightOption", "text": "Height (cm)", "border": "bottom" }, "_expanded": true, "items": [ { "cls": "Wb.Number", "properties": { "cid": "editor", "isProperty": "true", "flex": "1", "flat": "true", "placeholder": "Your height" }, "text": "editor", "_expanded": true, "_icon": "number-edit" } ] }, { "_icon": "options", "text": "genderOption", "cls": "Wb.Option", "properties": { "cid": "genderOption", "text": "Gender", "border": "bottom", "options": "['Male', 'Female']", "optionsTitle": "Select Gender" }, "_expanded": true }, { "_icon": "options", "text": "statusOption", "cls": "Wb.Option", "properties": { "cid": "statusOption", "text": "Status" }, "_expanded": true, "items": [ { "cls": "Wb.Toggle", "properties": { "cid": "editor", "isProperty": "true" }, "text": "editor", "_expanded": true, "_icon": "switcher-on" } ] } ] }, { "_icon": "line", "text": "line2", "cls": "Wb.Line", "properties": { "cid": "line2", "title": "Form style" } }, { "_icon": "container", "text": "optionCt2", "cls": "Wb.Container", "properties": { "cid": "optionCt2", "background": "false", "roundBorder": "true", "tableStyle": "simple" }, "_expanded": true, "items": [ { "_icon": "text", "text": "defaults", "cls": "Wb.Text", "properties": { "cid": "defaults", "labelWidth": "8em", "labelSeparator": "false", "isProperty": "true" } }, { "cls": "Wb.Text", "properties": { "cid": "name", "text": "Name", "placeholder": "Your name" }, "text": "name", "_expanded": true, "_icon": "text" }, { "cls": "Wb.Number", "properties": { "cid": "height", "text": "Height (cm)", "placeholder": "Your height" }, "text": "height", "_expanded": true, "_icon": "number-edit" }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "properties": { "cid": "gender", "data": "(['Male', 'Female'])", "text": "Gender", "placeholder": "Male / Female" } }, { "_icon": "options", "text": "genderOption", "cls": "Wb.Option", "properties": { "cid": "genderOption", "text": "Gender Option", "border": "bottom", "options": "['Male', 'Female']", "optionsTitle": "Select Gender" }, "_expanded": true }, { "cls": "Wb.Toggle", "properties": { "cid": "status", "text": "Status" }, "text": "status", "_expanded": true, "_icon": "switcher-on" } ] } ] } ] } ] } # example/comps/select.xwl Title: select ```json { "title": "", "icon": "combo", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Add trigger button to fetch value. @priv\n * @param {Wb.Select} select select control.\n */\n addFetchValueButton(select) {\n select.addTrigger({\n icon: 'share', tip: 'Show value', weight: 991, handler() {\n Wb.tip(select.cid + ' value is: ' + select.value);\n }\n });\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Select, Trigger and Picker", "cls": "w-title3" } }, { "_icon": "title", "text": "selectTitle", "cls": "Wb.Title", "properties": { "cid": "selectTitle", "title": "Select" }, "_expanded": true }, { "_icon": "container", "text": "selectCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "selectCt", "layout": "grid", "frame": "true", "gridTplColumns": "repeat(auto-fill, 22em)" }, "items": [ { "_icon": "combo", "text": "commonSelect", "cls": "Wb.Select", "properties": { "cid": "commonSelect", "text": "Common Select", "data": "['item1', 'item2', 'item3']" } }, { "_icon": "combo", "text": "noEditableSelect", "cls": "Wb.Select", "properties": { "cid": "noEditableSelect", "text": "No Editable", "data": "['item1', 'item2', 'item3']", "editable": "false" } }, { "_icon": "combo", "text": "nameValueSelect", "cls": "Wb.Select", "properties": { "cid": "nameValueSelect", "text": "Name Value", "data": "[['name1', 'value1'], ['name2', 'value2'], ['name3', 'value3']]" }, "events": { "ready": "app.addFetchValueButton(this);" } }, { "_icon": "combo", "text": "remoteSelect", "cls": "Wb.Select", "properties": { "cid": "remoteSelect", "text": "Remote Select No Wrap", "url": "demo-source?xaction=staffRows", "textField": "full_name", "valueField": "code", "loadOnce": "true", "noWrap": "true" }, "events": { "ready": "app.addFetchValueButton(this);" } }, { "_icon": "combo", "text": "autoLoadSelect", "cls": "Wb.Select", "properties": { "cid": "autoLoadSelect", "text": "Auto Load", "url": "demo-source?xaction=staffRows", "textField": "full_name", "valueField": "code", "autoLoad": "all", "value": "'10003'", "subtextField": "code", "noWrap": "true" } }, { "_icon": "combo", "text": "liveSearchSelect", "cls": "Wb.Select", "properties": { "cid": "liveSearchSelect", "text": "Live Seach", "url": "demo-source?xaction=staffSearch", "textField": "full_name", "valueField": "code" }, "_expanded": true }, { "_icon": "combo", "text": "templateSelect", "cls": "Wb.Select", "properties": { "cid": "templateSelect", "text": "Template Select", "url": "demo-source?xaction=staffRows", "loadOnce": "true", "itemTpl": "
\n
\n
\n
{code}
\n
{full_name}
\n
", "pickerMinWidth": "20em", "cls": "w-rownum-reset", "textField": "full_name", "valueField": "code" }, "events": { "ready": "app.addFetchValueButton(this);" } }, { "_icon": "combo", "text": "templateFnSelect", "cls": "Wb.Select", "properties": { "cid": "templateFnSelect", "text": "Template Function", "url": "demo-source?xaction=staffRows", "loadOnce": "true", "pickerMinWidth": "20em", "cls": "w-rownum-reset", "textField": "full_name", "valueField": "code", "itemTplFn": "return `
\n
\n
\n
${data.code}
\n
${data.full_name}
\n
`;" }, "events": { "ready": "app.addFetchValueButton(this);" } }, { "_icon": "combo", "text": "keyNameSelect", "cls": "Wb.Select", "properties": { "cid": "keyNameSelect", "text": "Key Name", "keyName": "status" }, "events": { "ready": "app.addFetchValueButton(this);" }, "_expanded": true }, { "_icon": "combo", "text": "forceSelect", "cls": "Wb.Select", "properties": { "cid": "forceSelect", "text": "Force Select", "forceSelect": "true", "url": "demo-source?xaction=staffSearch", "valueField": "code", "textField": "full_name" }, "_expanded": true, "events": { "ready": "app.addFetchValueButton(this);" }, "items": [ { "cls": "Wb.Item", "events": { "click": "//When the remote drop-down list data has not yet been loaded, we can specify both the value and text\nthis.parent.value = ['10003', 'Michael Sullivan'];" }, "properties": { "cid": "triggers", "icon": "data-provider", "tip": "Set value" }, "text": "triggers", "_expanded": true, "_icon": "item" } ] }, { "_icon": "combo", "text": "customMatchSelect", "cls": "Wb.Select", "properties": { "cid": "customMatchSelect", "text": "Custom Match", "data": "['item1 abc item1', 'item2 abc item2', 'item3 def item3']", "matchMode": "includesIC", "selectMode": "startsWithIC" }, "_expanded": true }, { "_icon": "combo", "text": "miscSelect", "cls": "Wb.Select", "properties": { "cid": "miscSelect", "data": "[\n { text: 'With icon', _icon: 'user2' },\n { text: 'With image', _img: 'add' },\n { text: 'With tip', _tip: 'Item tip' },\n { text: 'Nowrap line with overflow text', _cls: 'w-nowrap' },\n { text: 'Fixed item', _fixed: true },\n { text: 'Disabled Item', _disabled: true }\n]", "text": "Miscellaneous" }, "_expanded": true }, { "_icon": "combo", "text": "bindFieldSelect", "cls": "Wb.Select", "properties": { "cid": "bindFieldSelect", "text": "Bind Field", "bindField": "myValueField", "url": "demo-source?xaction=staffSearch", "textField": "full_name", "valueField": "code" }, "events": { "ready": "let select = this;\nselect.addTrigger({\n icon: 'share', tip: 'Show values', weight: 991, handler() {\n Wb.tip(Wb.encode(Wb.getValue(select)));\n }\n});" }, "_expanded": true, "items": [ { "cls": "Wb.Item", "events": { "click": "Wb.setValue(app.viewport1, { myValueField: '10003', bindFieldSelect: 'Michael Sullivan' });" }, "properties": { "cid": "triggers", "icon": "data-provider", "tip": "Set value" }, "text": "triggers", "_expanded": true, "_icon": "item" } ] }, { "_icon": "combo", "text": "valueFieldSelect", "cls": "Wb.Select", "properties": { "cid": "valueFieldSelect", "text": "Value Field", "url": "demo-source?xaction=staffSearch", "textField": "full_name", "valueField": "code" }, "events": { "ready": "let select = this;\nselect.addTrigger({\n icon: 'share', tip: 'Show values', weight: 991, handler() {\n Wb.tip(Wb.encode(Wb.getValue(select)));\n }\n});" }, "_expanded": true, "items": [ { "cls": "Wb.Item", "events": { "click": "// valueFieldSelect$ is text\nWb.setValue(app.viewport1, { valueFieldSelect: '10003', valueFieldSelect$: 'Michael Sullivan' });" }, "properties": { "cid": "triggers", "icon": "data-provider", "tip": "Set value" }, "text": "triggers", "_expanded": true, "_icon": "item" } ] }, { "_icon": "combo", "text": "valueMapSelect", "cls": "Wb.Select", "properties": { "cid": "valueMapSelect", "text": "Value Map", "url": "demo-source?xaction=staffSearch", "textField": "full_name", "valueMap": "{code: 'my_code', email: 'my_email', full_name: 'valueMapSelect' }", "gridColumn": "1 / -1", "subtextField": "code" }, "events": { "ready": "let select = this;\nselect.addTrigger({\n icon: 'share', tip: 'Show values', weight: 991, handler() {\n Wb.tip(Wb.encode(Wb.getValue(select)));\n }\n});" }, "_expanded": true, "items": [ { "cls": "Wb.Item", "events": { "click": "Wb.setValue(app.valueMapSelect, { my_code: '10003', my_email: 'michael8@geejing.com', valueMapSelect: 'Michael Sullivan' });" }, "properties": { "cid": "triggers", "icon": "data-provider", "tip": "Set value" }, "text": "triggers", "_expanded": true, "_icon": "item" } ] }, { "_icon": "combo", "text": "multiSelect", "cls": "Wb.Select", "properties": { "cid": "multiSelect", "text": "Multi Select", "url": "demo-source?xaction=staffRows", "textField": "full_name", "valueField": "code", "noWrap": "true", "multiSelect": "true", "gridColumn": "1 / -1", "clearButton": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "triggers" }, "text": "triggers", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "this.parent.value = [{ code: '10001', full_name: 'Terri Duffy' }, { code: '10005', full_name: 'Gail Erickson' },\n{ code: '10008', full_name: 'Janice Galvin' }];" }, "properties": { "cid": "setBtn", "icon": "data-provider", "tip": "Set values" }, "text": "setBtn", "_expanded": false, "_icon": "item" }, { "cls": "Wb.Item", "events": { "click": "Wb.tip(Wb.encode(this.parent.value));" }, "properties": { "cid": "getBtn", "icon": "share", "tip": "Get values" }, "text": "getBtn", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "events": { "click": "let select = this.parent;\nselect.picker.load({\n success() {\n select.value = this.data.firstItem;\n }\n});" }, "properties": { "cid": "manualSelect", "icon": "setup", "tip": "Manual select the first item" }, "text": "manualSelect", "_expanded": true, "_icon": "item" } ] } ] }, { "_icon": "combo", "text": "multiSelectWrap", "cls": "Wb.Select", "properties": { "cid": "multiSelectWrap", "text": "Multi Select Wrap", "url": "demo-source?xaction=staffSearch", "textField": "full_name", "valueField": "code", "noWrap": "true", "multiSelect": "true", "gridColumn": "1 / -1", "tagSortable": "true", "tagWrap": "true", "clearButton": "true", "tagTipField": "email", "subtextField": "code", "maxHeight": "10em", "tagWidth": "calc(100% - 8em)" }, "_expanded": true }, { "_icon": "combo", "text": "treeSelect", "cls": "Wb.Select", "properties": { "cid": "treeSelect", "text": "Tree Select", "textField": "text", "valueField": "sid", "gridColumn": "1 / -1", "treePicker": "true", "data": "[\n {\n text: 'Asia', _icon: 'flag1', myCheck: 1, sid: 'a',\n remark: 'Asia is the largest continent in the world', area: 44579000, percentage: 0.3, items: [\n { text: 'China', _leaf: true, myCheck: 0, sid: 'a1' },\n { text: 'Japan', _leaf: true, myCheck: 1, sid: 'a2' },\n { text: 'Korea', _leaf: true, myCheck: 0, sid: 'a3' }\n ]\n },\n {\n text: 'Europe', _icon: 'flag1', myCheck: 1, sid: 'b',\n remark: 'Europe is between Asia and Africa', area: 9938000, percentage: 0.067, items: [\n { text: 'France', _leaf: true, sid: 'b1' },\n { text: 'Germany', _leaf: true, sid: 'b2' },\n { text: 'UK', _leaf: true, sid: 'b3' }\n ]\n },\n {\n text: 'North America', _icon: 'flag1', _selected: true, _expanded: true, sid: 'c',\n remark: \"North America is the third largest of the world's continents\", area: 24256000, percentage: 0.165, items: [\n { text: 'Canada', _leaf: true, sid: 'c1' },\n { text: 'Mexico', _leaf: true, sid: 'c2' },\n { text: 'USA', _leaf: true, sid: 'c3' }\n ]\n },\n {\n text: 'South America', _icon: 'flag1', _disabled: true, sid: 'd',\n remark: \"Sorth America is the fourth largest of the world's continents\", area: 17819000, percentage: 0.12, items: [\n { text: 'Argentina', _leaf: true, sid: 'd1' },\n { text: 'Brazil', _leaf: true, sid: 'd2' }\n ]\n }\n]" }, "events": { "beforeselect": "if (!item.leaf) {\n Wb.tip('Please select a leaf node');\n return false;\n}" } }, { "_icon": "combo", "text": "singleTagTreeSelect", "cls": "Wb.Select", "properties": { "cid": "singleTagTreeSelect", "text": "Single Tag Tree", "url": "demo-source?xaction=listAreaTree1", "textField": "text", "valueField": "sid", "gridColumn": "1 / -1", "clearButton": "true", "treePicker": "true", "useTag": "true" }, "events": { "change": "// Wb.tip(Wb.encode(value));" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "triggers" }, "text": "triggers", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "this.parent.value = { text: 'Paris', subtext: '004LMY1FA9D40', sid: '004LMY1FA9D40' };" }, "properties": { "cid": "setBtn", "icon": "data-provider", "tip": "Set values" }, "text": "setBtn", "_expanded": false, "_icon": "item" }, { "cls": "Wb.Item", "events": { "click": "Wb.tip(Wb.encode(this.parent.value));" }, "properties": { "cid": "getBtn", "icon": "share", "tip": "Get values" }, "text": "getBtn", "_expanded": true, "_icon": "item" } ] } ] }, { "_icon": "combo", "text": "multiTreeSelect", "cls": "Wb.Select", "properties": { "cid": "multiTreeSelect", "text": "Multi Select Tree", "url": "demo-source?xaction=listAreaTree1", "textField": "text", "valueField": "sid", "gridColumn": "1 / -1", "tagSortable": "true", "tagWrap": "true", "clearButton": "true", "treePicker": "true", "maxHeight": "10em", "tagWidth": "70%", "multiSelect": "true" }, "events": { "change": "// Wb.tip(Wb.encode(value));" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "triggers" }, "text": "triggers", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "this.parent.value = [\n { text: 'Lyon', subtext: '004LMY1FA9D41', sid: '004LMY1FA9D41' },\n { text: 'Paris', subtext: '004LMY1FA9D40', sid: '004LMY1FA9D40' }\n];" }, "properties": { "cid": "setBtn", "icon": "data-provider", "tip": "Set values" }, "text": "setBtn", "_expanded": false, "_icon": "item" }, { "cls": "Wb.Item", "events": { "click": "Wb.tip(Wb.encode(this.parent.value));" }, "properties": { "cid": "getBtn", "icon": "share", "tip": "Get values" }, "text": "getBtn", "_expanded": true, "_icon": "item" } ] } ] } ] }, { "_icon": "title", "text": "linkedSelectTitle", "cls": "Wb.Title", "properties": { "cid": "linkedSelectTitle", "title": "Linked Select" }, "_expanded": true }, { "_icon": "container", "text": "linkedSelectCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "linkedSelectCt", "layout": "grid", "frame": "true" }, "items": [ { "_icon": "combo", "text": "continentSelect", "cls": "Wb.Select", "properties": { "cid": "continentSelect", "placeholder": "Continent", "forceSelect": "true", "url": "demo-source?xaction=listRootArea", "textField": "area_name", "valueField": "sid", "required": "true" }, "events": { "ready": "let me = this;\n//Pick up the first item\nme.picker.load({ success() { me.valueIndex = 0; } });" } }, { "_icon": "combo", "text": "countrySelect", "cls": "Wb.Select", "properties": { "cid": "countrySelect", "placeholder": "Country", "forceSelect": "true", "url": "demo-source?xaction=listArea", "textField": "area_name", "valueField": "sid", "required": "true" }, "events": { "beforeload": "let select = app.continentSelect;\nif (select.verify())\n params.parent_id = select.value;\nelse {\n select.focus();\n return false;\n}" } }, { "_icon": "combo", "text": "citySelect", "cls": "Wb.Select", "_expanded": true, "properties": { "cid": "citySelect", "placeholder": "City", "forceSelect": "true", "url": "demo-source?xaction=listArea", "textField": "area_name", "valueField": "sid", "required": "true" }, "events": { "beforeload": "let select = app.countrySelect;\nif (select.verify())\n params.parent_id = select.value;\nelse {\n select.focus();\n return false;\n}" } } ] }, { "_icon": "title", "text": "triggerTitle", "cls": "Wb.Title", "properties": { "cid": "triggerTitle", "title": "Trigger" }, "_expanded": true }, { "_icon": "container", "text": "triggerCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "triggerCt", "layout": "grid", "frame": "true" }, "items": [ { "_icon": "trigger", "text": "commonTrigger", "cls": "Wb.Trigger", "properties": { "cid": "commonTrigger", "text": "Common Trigger" }, "events": { "triggerclick": "Wb.tip(this.cid + ' triggered');" } }, { "_icon": "trigger", "text": "readonlyTrigger", "cls": "Wb.Trigger", "properties": { "cid": "readonlyTrigger", "text": "Readonly Trigger", "editable": "false", "enterTriggerClick": "true", "triggerIcon": "location", "placeholder": "Press enter" }, "events": { "triggerclick": "Wb.tip(this.cid + ' triggered');" } }, { "_icon": "trigger", "text": "extraTrigger", "cls": "Wb.Trigger", "properties": { "cid": "extraTrigger", "text": "Extra Triggers" }, "events": { "triggerclick": "Wb.tip('Default trigger clicked');" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "triggers" }, "text": "triggers", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "Wb.tip('Set trigger clicked');" }, "properties": { "cid": "setItem", "icon": "gear", "tip": "@Str.set" }, "text": "setItem", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "properties": { "cid": "copyItem", "icon": "copy", "tip": "@Str.copy" }, "text": "copyItem", "_expanded": true, "_icon": "item" } ] } ] } ] }, { "_icon": "title", "text": "pickerTitle", "cls": "Wb.Title", "properties": { "cid": "pickerTitle", "title": "Picker" }, "_expanded": true }, { "_icon": "container", "text": "pickerCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "pickerCt", "layout": "grid", "frame": "true" }, "items": [ { "_icon": "picker", "text": "commonPicker", "cls": "Wb.Picker", "_expanded": true, "properties": { "cid": "commonPicker", "text": "Common Picker", "editable": "false" }, "events": { "collapse": "this.value = Wb.encode(Wb.getValue(this.picker));", "expand": "Wb.setValue(this.picker, this.value ? Wb.decode(this.value) : {});" }, "items": [ { "cls": "Wb.Container", "properties": { "cid": "picker", "isProperty": "true", "layout": "grid1", "defaults": "({ labelWidth: '5em' })" }, "text": "picker", "_expanded": true, "_icon": "container", "items": [ { "_icon": "text", "text": "nameText", "cls": "Wb.Text", "properties": { "cid": "nameText", "text": "name" } }, { "_icon": "text", "text": "typeText", "cls": "Wb.Text", "properties": { "cid": "typeText", "text": "type" } }, { "_icon": "number-edit", "text": "countNumber", "cls": "Wb.Number", "properties": { "cid": "countNumber", "text": "Count" } } ] } ] }, { "_icon": "picker", "text": "gridPicker", "cls": "Wb.Picker", "_expanded": true, "properties": { "cid": "gridPicker", "text": "Grid Picker" }, "items": [ { "_icon": "grid", "text": "picker", "cls": "Wb.Grid", "properties": { "cid": "picker", "isProperty": "true", "url": "demo-source?xaction=staffDict" } } ] }, { "_icon": "picker", "text": "treePicker", "cls": "Wb.Picker", "_expanded": true, "properties": { "cid": "treePicker", "text": "Tree Picker", "editable": "false" }, "events": { "collapse": "this.value = this.picker.checkedNodes.pluck('text').join(', ');" }, "items": [ { "_icon": "tree-view", "text": "picker", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "picker", "isProperty": "true", "url": "demo-source?xaction=listAreaTree" }, "events": { "itemclick": "let picker = this.parent;\nif (item.leaf) {\n picker.setValue(item.data.area_name);\n picker.collapse();\n picker.focus();\n}" } } ] }, { "_icon": "picker", "text": "lazyPicker", "cls": "Wb.Picker", "_expanded": true, "properties": { "cid": "lazyPicker", "text": "Lazy Picker", "lazyPicker": "true" }, "items": [ { "_icon": "container", "text": "picker", "cls": "Wb.Container", "properties": { "cid": "picker", "text": "Load large data asynchronously", "isProperty": "true", "frame": "true", "padding": "true" } } ] }, { "_icon": "calendar", "text": "dockedPicker", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "dockedPicker", "text": "Picker docked bottom", "dockedPicker": "true", "shareView": "false" } } ] }, { "_icon": "title", "text": "othersTitle", "cls": "Wb.Title", "properties": { "cid": "othersTitle", "title": "Others" }, "_expanded": true }, { "_icon": "container", "text": "othersCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "othersCt", "layout": "grid", "frame": "true" }, "items": [ { "_icon": "color", "text": "color1", "cls": "Wb.Color", "properties": { "cid": "color1", "placeholder": "Color" }, "_expanded": true }, { "_icon": "brush", "text": "colorSelect1", "cls": "Wb.ColorSelect", "properties": { "cid": "colorSelect1" } }, { "_icon": "check8", "text": "boolSelect1", "cls": "Wb.BoolSelect", "properties": { "cid": "boolSelect1", "placeholder": "Bool selector" } } ] }, { "_icon": "title", "text": "codingTitle", "cls": "Wb.Title", "properties": { "cid": "codingTitle", "title": "Coding" }, "_expanded": true }, { "_icon": "container", "text": "codingCt", "cls": "Wb.Container", "properties": { "cid": "codingCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "container", "text": "demoCt", "cls": "Wb.Container", "properties": { "cid": "demoCt", "layout": "form-compact" }, "_expanded": true, "items": [ { "_icon": "combo", "text": "localSelect", "cls": "Wb.Select", "properties": { "cid": "localSelect", "text": "Local Select", "data": "['item1', 'item2', 'item3']" } }, { "_icon": "combo", "text": "remoteSelect1", "cls": "Wb.Select", "properties": { "cid": "remoteSelect1", "text": "Remote Select", "url": "demo-source?xaction=staffRows", "textField": "full_name", "valueField": "code", "loadOnce": "true" }, "events": { "beforeload": "params.foo = 'bar';" } } ] }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "_expanded": false, "properties": { "cid": "line1", "title": "Demonstrate", "dimTitle": "true", "dashed": "true" } }, { "_icon": "container", "text": "actionCt", "cls": "Wb.Container", "_expanded": true, "properties": { "cid": "actionCt", "layout": "form-compact" }, "items": [ { "_icon": "button", "text": "addBtn", "cls": "Wb.Button", "properties": { "cid": "addBtn", "text": "Insert Item" }, "_expanded": true, "events": { "click": "app.localSelect.data.push({ text: 'New Item' }); //add permanently\n//app.localSelect.picker.addData({ text: 'New Item' }); //add transiently because the picker data will be reloaded when expand it" } }, { "_icon": "button", "text": "removeBtn", "cls": "Wb.Button", "properties": { "cid": "removeBtn", "text": "Remove Item" }, "_expanded": true, "events": { "click": "app.localSelect.data.erase(0); //erase is a function ofArray, see Array functions" } }, { "_icon": "button", "text": "expandLocalBtn", "cls": "Wb.Button", "properties": { "cid": "expandLocalBtn", "text": "Expand Local Selet" }, "_expanded": true, "events": { "click": "app.localSelect.expand();" } }, { "_icon": "button", "text": "expandRemoteBtn", "cls": "Wb.Button", "properties": { "cid": "expandRemoteBtn", "text": "Expand Remote Select" }, "_expanded": true, "events": { "click": "app.remoteSelect1.query(); //expand function has no effect because the picker's data has not been loaded yet" } } ] } ] } ] } ] } # example/comps/slot.xwl Title: slot ```json { "title": "", "icon": "slots", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "description": "demo-source=example/common/demo-source.xwl" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Slot", "cls": "w-title3" } }, { "_icon": "title", "text": "slotListTitle", "cls": "Wb.Title", "properties": { "cid": "slotListTitle", "title": "Slot list" } }, { "_icon": "container", "text": "slotListCt", "cls": "Wb.Container", "properties": { "cid": "slotListCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonSlotLabel", "cls": "Wb.Label", "properties": { "cid": "commonSlotLabel", "text": "Common slot" } }, { "_icon": "slots", "text": "commonSlot", "cls": "Wb.Slot", "properties": { "cid": "commonSlot", "data": "[\n [{ text: 'a1' }, { text: 'a2' }, { text: 'a3' }, { text: 'a4' }, { text: 'a5' }, { text: 'a6' }],\n [{ text: 'b1' }, { text: 'b2' }, { text: 'b3' }, { text: 'b4' }, { text: 'b5' }, { text: 'b6' }]\n]", "buttonAlign": "center" }, "events": { "itemselect": "Wb.tip(Wb.encode(this.value) + ' selected');" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Button", "events": { "click": "app.commonSlot.value = ['a2', 'b2'];" }, "properties": { "cid": "setValueBtn", "text": "Set value" }, "text": "setValueBtn", "_expanded": true, "_icon": "button" }, { "cls": "Wb.Button", "events": { "click": "Wb.tip(this.cid + ' values is: ' + Wb.encode(app.commonSlot.value));" }, "properties": { "cid": "getValueBtn", "text": "Get value" }, "text": "getValueBtn", "_expanded": true, "_icon": "button" } ] } ] }, { "_icon": "label", "text": "customSlotLabel", "cls": "Wb.Label", "properties": { "cid": "customSlotLabel", "text": "Custom slot" } }, { "_icon": "slots", "text": "customSlot", "cls": "Wb.Slot", "properties": { "cid": "customSlot", "height": "15em" }, "_expanded": true, "items": [ { "_icon": "list", "text": "slotView1", "cls": "Wb.SlotView", "properties": { "cid": "slotView1", "url": "demo-source?xaction=staffDict", "textField": "full_name", "valueField": "code", "topTitle": "Staff list" } } ] } ] }, { "_icon": "title", "text": "linkedSlotTitle", "cls": "Wb.Title", "properties": { "cid": "linkedSlotTitle", "title": "Linked slot without scrollbar" } }, { "_icon": "slots", "text": "linkedSlot", "cls": "Wb.Slot", "properties": { "cid": "linkedSlot", "height": "10em", "defaults": "({ autoScroll: 'hide' })", "border": "false" }, "_expanded": true, "items": [ { "_icon": "list", "text": "continentView", "cls": "Wb.SlotView", "properties": { "cid": "continentView", "url": "demo-source?xaction=listRootArea", "topTitle": "Continent", "textField": "area_name" }, "events": { "selectionchange": "app.countryView.load({ params: { parent_id: this.selection.data.sid } });" }, "_expanded": true }, { "_icon": "list", "text": "countryView", "cls": "Wb.SlotView", "properties": { "cid": "countryView", "url": "demo-source?xaction=listArea", "topTitle": "Country", "textField": "area_name" }, "events": { "selectionchange": "app.cityView.load({ params: { parent_id: this.selection?.data.sid } });" } }, { "_icon": "list", "text": "cityView", "cls": "Wb.SlotView", "properties": { "cid": "cityView", "url": "demo-source?xaction=listArea", "topTitle": "City", "textField": "area_name" } } ] } ] } ] } # example/comps/toolbar-menu.xwl Title: toolbar-menu ```json { "title": "", "icon": "toolbar", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "array", "text": "components", "cls": "Wb.Array", "properties": { "cid": "components" }, "_expanded": true, "items": [ { "_icon": "menu2", "text": "sharedContextMenu", "cls": "Wb.Menu", "properties": { "cid": "sharedContextMenu" }, "_expanded": true, "items": [ { "_icon": "item", "text": "showTargetItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "showTargetItem", "text": "Show target", "icon": "cube" }, "events": { "click": "Wb.tip('Popup context menu from ' + this.contextTarget.getClosestComp().cid);" } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1" } }, { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "@Str.add", "icon": "add" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "@Str.edit", "icon": "edit" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "@Str.del", "icon": "delete" } } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Toolbar and menu", "cls": "w-title3" } }, { "_icon": "title", "text": "toolbarTitle", "cls": "Wb.Title", "properties": { "cid": "toolbarTitle", "title": "Toolbar" }, "_expanded": true }, { "_icon": "container", "text": "toolbarCt", "cls": "Wb.Container", "properties": { "cid": "toolbarCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonToolBarLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "commonToolBarLabel", "text": "Common toolbar" } }, { "_icon": "toolbar", "text": "commonToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "commonToolbar", "border": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "addItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addItem", "icon": "add", "text": "@Str.add", "tip": "Add new item" } }, { "_icon": "item", "text": "deleteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deleteItem", "icon": "delete", "text": "@Str.del" } }, { "_icon": "item", "text": "shortCutKeyItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "shortCutKeyItem", "text": "Bind key", "icon": "keyboard", "keys": "Ctrl+K" }, "events": { "click": "Wb.tip(this.cid + ' clicked');" } }, { "_icon": "item", "text": "disabledItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "disabledItem", "icon": "property", "text": "Disabled", "disabled": "true" } }, { "_icon": "item", "text": "menuItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "menuItem", "icon": "menu", "text": "Menu" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Menu item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Menu item 3" } } ] } ] }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "trigger", "text": "trigger1", "cls": "Wb.Trigger", "properties": { "cid": "trigger1", "triggerIcon": "module" }, "events": { "triggerclick": "Wb.tip(this.cid + ' clicked');" } }, { "_icon": "item", "text": "centerAlignItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "centerAlignItem", "icon": "data", "alignSelf": "center", "tip": "Centered button" } }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "item", "text": "fillRightItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "fillRightItem", "icon": "calendar" } } ] }, { "_icon": "label", "text": "overflowedToolbarLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "overflowedToolbarLabel", "text": "Overflowed toolbar" } }, { "_icon": "toolbar", "text": "overflowedToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "overflowedToolbar", "border": "true", "width": "25em", "overflowMenu": "true", "resizable": "true", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "item 1", "icon": "calculator" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "item 2", "icon": "add1" } }, { "_icon": "item", "text": "menuTextItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "menuTextItem", "icon": "broadcast", "menuText": "MenuText Item" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "item 3", "icon": "click" } }, { "_icon": "item", "text": "item4", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item4", "text": "item 4", "icon": "lantern" } }, { "_icon": "item", "text": "item5", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item5", "text": "item 5", "icon": "mail" } } ] }, { "_icon": "label", "text": "centeredShrinkToolbarLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "centeredShrinkToolbarLabel", "text": "Centered shrink toolbar" } }, { "_icon": "toolbar", "text": "centeredShrinkToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "centeredShrinkToolbar", "justify": "center", "border": "true", "resizable": "true", "shrink": "true", "width": "25em", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "book1", "text": "Item1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "card", "text": "Item2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "icon": "cube", "text": "Item3" } } ] }, { "_icon": "label", "text": "verticalToolbarLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "verticalToolbarLabel", "text": "Vertical toolbar" } }, { "_icon": "toolbar", "text": "verticalToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "verticalToolbar", "frame": "true", "vertical": "true", "maxWidth": "10em" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "book1", "text": "Item1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "card", "text": "Item2 Card" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "icon": "cube", "text": "Item3" } } ] }, { "_icon": "label", "text": "menuStyleToolbarLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "menuStyleToolbarLabel", "text": "Menu style toolbar" } }, { "_icon": "toolbar", "text": "menuStyleToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "menuStyleToolbar", "frame": "true", "type": "menu", "maxWidth": "10em" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "book1", "text": "Item1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "card", "text": "Item2 Card" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "icon": "cube", "text": "Item3" } } ] } ] }, { "_icon": "title", "text": "menuTitle", "cls": "Wb.Title", "properties": { "cid": "menuTitle", "title": "Menu" }, "_expanded": true }, { "_icon": "container", "text": "menuCt", "cls": "Wb.Container", "properties": { "cid": "menuCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "toolbar", "text": "toolbar1", "cls": "Wb.Toolbar", "properties": { "cid": "toolbar1", "layout": "center", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu Item" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "iconItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "iconItem", "text": "Menu item 1", "icon": "briefcase" } }, { "_icon": "item", "text": "imgItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "imgItem", "text": "Menu item 1", "img": "sitemap" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "disabledItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "disabledItem", "disabled": "true", "icon": "download", "text": "Disabled" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "gap": ".2em", "cls": "w-mi-margin" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "fsSlider", "cls": "Wb.Slider", "properties": { "cid": "fsSlider", "text": "@Str.fontSize", "maxValue": "50", "flex": "1", "minValue": "12", "tabIndex": "null", "focusable": "false" }, "_expanded": true }, { "_icon": "button", "text": "resetBtn", "cls": "Wb.Button", "properties": { "cid": "resetBtn", "tip": "@Str.reset", "icon": "refresh", "type": "tool", "tabIndex": "undefined", "focusable": "false" } } ] }, { "_icon": "item", "text": "bindKeyItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "bindKeyItem", "text": "Bind key item", "keys": "Ctrl+L" }, "events": { "click": "Wb.tip(this.cid + ' clicked');" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "properties": { "cid": "space1" } }, { "_icon": "item", "text": "subMenuItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "subMenuItem", "text": "Sub menu" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item1", "text": "Item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item2", "text": "Item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "text": "Item 3" } } ] } ] } ] } ] } ] }, { "_icon": "button", "text": "menuButton", "cls": "Wb.Button", "properties": { "cid": "menuButton", "text": "Menu Button", "icon": "menu" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "uncheckItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "uncheckItem", "text": "Unchecked item", "checked": "false" }, "events": { "checkchange": "Wb.tip(this.cid + ' checked is ' + checked);" } }, { "_icon": "item", "text": "checkedItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "checkedItem", "text": "Checked Item", "checked": "true" } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1" } }, { "_icon": "item", "text": "groupedItem1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "groupedItem1", "text": "Grouped item1", "checkGroup": "group1", "checked": "true" } }, { "_icon": "item", "text": "groupedItem2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "groupedItem2", "text": "Grouped item2", "checkGroup": "group1", "checked": "false" } }, { "_icon": "item", "text": "groupedItem3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "groupedItem3", "text": "Grouped item3", "checkGroup": "group1", "checked": "false" } }, { "_icon": "line", "text": "line2", "cls": "Wb.Line", "_expanded": true, "properties": { "cid": "line2" } }, { "_icon": "item", "text": "ellipsisItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "ellipsisItem", "ellipsis": "true", "text": "Ellipsis Item (means to show dialog)" } }, { "_icon": "line", "text": "line3", "cls": "Wb.Line", "_expanded": true, "properties": { "cid": "line3" } }, { "_icon": "item", "text": "noHideItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "noHideItem", "text": "Click not to hide menu", "clickHide": "false" }, "events": { "click": "Wb.tip('clicked');" } } ] } ] }, { "_icon": "container", "text": "contextMenuCt", "cls": "Wb.Container", "properties": { "cid": "contextMenuCt", "layout": "center", "text": "Please click the mouse context menu button to show context menu", "width": "20em", "height": "5em", "padding": "true", "textSelectable": "false", "frame": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "contextMenu", "isProperty": "true" }, "text": "contextMenu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu item 1", "icon": "book1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Menu item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Menu item 3" } } ] } ] }, { "_icon": "container", "text": "sharedContextMenuCt1", "cls": "Wb.Container", "properties": { "cid": "sharedContextMenuCt1", "layout": "center", "text": "Shared context menu comp1", "height": "5em", "padding": "true", "contextMenu": "app.sharedContextMenu", "frame": "true" }, "_expanded": true }, { "_icon": "container", "text": "sharedContextMenuCt2", "cls": "Wb.Container", "properties": { "cid": "sharedContextMenuCt2", "layout": "center", "text": "Shared context menu comp2", "height": "5em", "padding": "true", "contextMenu": "app.sharedContextMenu", "frame": "true" }, "_expanded": true }, { "_icon": "toolbar", "text": "menuToolbar", "cls": "Wb.Toolbar", "properties": { "cid": "menuToolbar", "layout": "column", "fontSize": "1.6em", "plainIcon": "true", "defaults": "({ alignSelf: 'start', menu: { defaultAlign: 'tl-tr?', defaultOffset: [3, 0] } })", "frame": "true", "alignSelf": "start" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "card" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Menu item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Menu item 3" } } ] } ] }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "grid" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Menu item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Menu item 3" } } ] } ] }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "icon": "text1" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "text": "Menu item 1" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "text": "Menu item 2" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "text": "Menu item 3" } } ] } ] } ] } ] } ] } ] } # example/comps/tree.xwl Title: tree ```json { "title": "", "icon": "tree-view", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "description": "demo-source=example/common/demo-source.xwl" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Tree", "cls": "w-title3" } }, { "_icon": "title", "text": "commonRemoteTreeTitle", "cls": "Wb.Title", "properties": { "cid": "commonRemoteTreeTitle", "title": "Common remote tree" } }, { "_icon": "tree-view", "text": "commonRemoteTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "commonRemoteTree", "url": "demo-source?xaction=listAreaTree", "height": "15em" } }, { "_icon": "title", "text": "miscTreeTitle", "cls": "Wb.Title", "properties": { "cid": "miscTreeTitle", "title": "Miscillaneous tree" } }, { "_icon": "tree-view", "text": "miscTree", "cls": "Wb.Tree", "_expanded": false, "properties": { "cid": "miscTree", "localData": "[\n {\n text: 'Asia', _icon: 'flag1', _checked: true, myCheck: 1,\n remark: 'Asia is the largest continent in the world', area: 44579000, percentage: 0.3, items: [\n { text: 'China', _leaf: true, _checked: true, myCheck: 0 },\n { text: 'Japan', _leaf: true, _checked: true, myCheck: 1 },\n { text: 'Korea', _leaf: true, _checked: true, myCheck: 0 }\n ]\n },\n {\n text: 'Europe', _icon: 'flag1', myCheck: 1,\n remark: 'Europe is between Asia and Africa', area: 9938000, percentage: 0.067, items: [\n { text: 'France', _leaf: true },\n { text: 'Germany', _leaf: true },\n { text: 'UK', _leaf: true }\n ]\n },\n {\n text: 'North America', _icon: 'flag1', _selected: true, _expanded: true,\n remark: \"North America is the third largest of the world's continents\", area: 24256000, percentage: 0.165, items: [\n { text: 'Canada', _leaf: true },\n { text: 'Mexico', _leaf: true },\n { text: 'USA', _leaf: true }\n ]\n },\n {\n text: 'South America', _icon: 'flag1', _disabled: true,\n remark: \"Sorth America is the fourth largest of the world's continents\", area: 17819000, percentage: 0.12, items: [\n { text: 'Argentina', _leaf: true },\n { text: 'Brazil', _leaf: true }\n ]\n }\n]", "height": "20em", "pagingBar": "true", "resizable": "true", "gridLine": "true", "columnsSortable": "true", "sorters": "text", "stateId": "wb.miscTree", "frame": "true", "linkedCheck": "true", "defaultFields": "({\n _icon: { value: 'geejing' },\n _checked: {\n convert(value, data) {\n if (value === true)\n return true;\n else\n return data.text == 'Mexico' ? null : false;\n }\n }\n})" }, "events": { "itemdblclick": "Wb.tip(item.data.text + ' row double clicked');" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "textCol", "fieldName": "text", "expander": "true", "text": "Area", "freeze": "true", "width": "18em", "render": "//use sub-color to render subText\nlet textEl, subText = data.percentage > 0.15 ? 'Large area' : null;\nif (subText) {\n // Manual add sub text, please use subtext field instead\n el.cls = 'w-text-wrap';\n el.removeCls('w-text');\n el.addEl('w-text').textContent = value;\n el.addEl('w-sub-text').textContent = subText;\n // let span = el.addTag('span');\n // span.textContent = value;\n // span = el.addEl('w-sub-color w-margin-l', 'span');\n // span.textContent = subText;\n} else\n return value;" }, "text": "textCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "landAreasCol", "cls": "Wb.Column", "properties": { "cid": "landAreasCol", "text": "Land Areas" }, "_expanded": true, "items": [ { "cls": "Wb.Column", "properties": { "cid": "percentageCol", "fieldName": "percentage", "text": "Percentage", "type": "percent", "titleAlign": "right" }, "text": "percentageCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "areaCol", "fieldName": "area", "text": "Area(Sq. Km)", "titleAlign": "right", "render": "if (value < 10000000) {\n el.parentNode.cls = 'w-succ-bgcolor-row';\n el.cls = 'w-error-color';\n value = '* ' + value.intText;\n} else {\n value = value?.intText;\n}\n\n//add icon manually\nlet wrapEl = el.addEl('w-row w-align-center');\nel.removeCls('w-text');\nwrapEl.addEl('w-item-icon w-icon icon-thumb');\nwrapEl.addEl('w-text').textContent = value;" }, "text": "areaCol", "_expanded": true, "_icon": "column" } ] }, { "cls": "Wb.Column", "properties": { "cid": "remarkCol", "fieldName": "remark", "text": "Remark", "width": "-1" }, "text": "remarkCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "checkCol1", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol1", "checkBox": "int", "fieldName": "myCheck", "checkRefresh": "true", "menuText": "Check" } }, { "_icon": "column", "text": "checkCol2", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol2", "checkBox": "roTrue", "fieldName": "myCheck" } }, { "_icon": "column", "text": "checkCol3", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "checkCol3", "checkBox": "roAll", "fieldName": "myCheck" } }, { "_icon": "column", "text": "toggleCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "toggleCol", "render": "let row = this;\nvalue = row.data.myCheck;\nrow.addFooter({\n cname: 'toggle', returnType: 'int', value, toggleAlign: 'center', clickToggle: true,\n events: {\n change(value) {\n // If there is no need to synchronously update other fields, this is more efficient\n // row.data.myCheck = value; // only update myCheck field value\n row.set('myCheck', value); // update whole row\n }\n }\n}, el);", "width": "5em", "text": "Toggle" } }, { "_icon": "column", "text": "linkCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "linkCol", "render": "let a = el.addTag('a');\nel.cls = 'w-ta-center';\na.textContent = 'Download';\na.onclick = e => Wb.tip('Download data of ' + data.text);\n// a.onclick = app.myFunc;", "width": "8em", "text": "Link" } }, { "_icon": "column", "text": "actionsCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "actionsCol", "text": "Actions", "width": "8em" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "setItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "setItem", "icon": "gear", "tip": "Set" }, "events": { "click": "Wb.tip('Set ' + this.data.text);" } }, { "_icon": "item", "text": "shareItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "shareItem", "icon": "share2", "tip": "Add" }, "events": { "click": "Wb.tip('Share ' + this.data.text);" } } ] } ] } ] } ] }, { "_icon": "component", "text": "miscDescComp", "cls": "Wb.Component", "properties": { "cid": "miscDescComp", "html": "
Feature List:
\n
    \n
  • Columns sortable, resizable, draggable and freezable.
  • \n
  • Arbitrary multi-Level Headers.
  • \n
  • Customize cell rendering.
  • \n
  • Rows and columns highlighing.
  • \n
  • Local data pagination.
  • \n
  • Bind buttons or any controls to cells.
  • \n
  • Multiple styles of check columns.
  • \n
  • Customize columns and persistence to the database.
  • \n
", "textSelectable": "false" } }, { "_icon": "title", "text": "groupingTreeTitle", "cls": "Wb.Title", "properties": { "cid": "groupingTreeTitle", "title": "Grouping tree" } }, { "_icon": "tree-view", "text": "groupingTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "groupingTree", "height": "20em", "resizable": "true", "gridLine": "true", "columnsSortable": "true", "sorters": "department", "frame": "true", "grouping": "true", "localData": "[\n { name: 'Alice', department: 'Engineering', jobTitle: 'Software Engineer', country: 'USA', _leaf: true },\n { name: 'Bob', department: 'Marketing', jobTitle: 'Marketing Manager', country: 'UK', _leaf: true },\n { name: 'Charlie', department: 'Engineering', jobTitle: 'Junior Software Engineer', country: 'USA', _leaf: true },\n { name: 'David', department: 'Sales', jobTitle: 'Sales Representative', country: 'China', _leaf: true },\n { name: 'Eve', department: 'Marketing', jobTitle: 'Content Marketer', country: 'UK', _leaf: true },\n { name: 'Frank', department: 'Engineering', jobTitle: 'Software Engineer', country: 'USA', _leaf: true },\n { name: 'Grace', department: 'Sales', jobTitle: 'Sales Manager', country: 'China', _leaf: true },\n { name: 'Heidi', department: 'Engineering', jobTitle: 'Junior Software Engineer', country: 'USA', _leaf: true },\n { name: 'Ivan', department: 'Marketing', jobTitle: 'Social Media Marketer', country: 'UK', _leaf: true },\n { name: 'Judy', department: 'Sales', jobTitle: 'Sales Representative', country: 'China', _leaf: true },\n { name: 'Kevin', department: 'Engineering', jobTitle: 'Software Engineer', country: 'USA', _leaf: true },\n { name: 'Luna', department: 'Marketing', jobTitle: 'Marketing Coordinator', country: 'UK', _leaf: true },\n { name: 'Mike', department: 'Engineering', jobTitle: 'Junior Software Engineer', country: 'USA', _leaf: true },\n { name: 'Nora', department: 'Sales', jobTitle: 'Sales Manager', country: 'China', _leaf: true },\n { name: 'Oscar', department: 'Engineering', jobTitle: 'Intern', country: 'USA', _leaf: true }\n]" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "nameCol", "fieldName": "name", "expander": "true", "text": "Name", "width": "18em", "sortable": "false" }, "text": "nameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "departmentCol", "fieldName": "department", "text": "Department", "width": "18em" }, "text": "departmentCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "jobTitleCol", "fieldName": "jobTitle", "text": "Job Title", "width": "18em" }, "text": "jobTitleCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "countryCol", "fieldName": "country", "text": "Country", "width": "-1" }, "text": "countryCol", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "title", "text": "editableTreeTitle", "cls": "Wb.Title", "properties": { "cid": "editableTreeTitle", "title": "Editable tree" } }, { "_icon": "tree-view", "text": "editableTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "editableTree", "columnsSortable": "true", "editable": "true", "height": "15em", "multiSelect": "true", "sorters": "area_name", "url": "demo-source?xaction=listAreaTree", "pagingBar": "true", "frame": "true" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "//Some related methods: tree.add()/tree.addData()/tree.insert()/tree.insertData()/tree.insertXXX()/tree.insertDataXXX() etc.\napp.editableTree.addRecord({ area_name: 'New item', _checked: false });" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let firstRec = app.editableTree.firstItem;\nif (firstRec) {\n firstRec.set({ sid: 'code', area_name: 'new name' });\n app.editableTree.startEdit(firstRec, 'area_name');\n firstRec.highlight();\n}" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "//Some related methods: tree.destroySelection()/item.destroy()/Wb.destroy(items);\napp.editableTree.delRecords();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "addChild", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addChild", "text": "Add Child", "icon": "insert" }, "events": { "click": "let tree = this.upBy(p => p instanceof Wb.Tree); //same as: app.editableTree\nlet firstNode = tree.items[0], newNode;\nfirstNode.expand(n => {\n newNode = firstNode.addData({ area_name: 'new node', _leaf: true, _icon: 'earth', _checked: true });\n //other relative methods: insertData, insertDataBefore, insertDataAfter, insert, add etc\n newNode.select();\n});" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveBtn", "text": "@Str.save", "icon": "save", "keys": "Ctrl+S" }, "events": { "click": "app.editableTree.sync({\n url: xpath, //Should be changed to a valid URL\n success() {\n Wb.tipDone();\n }\n});" } } ] }, { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "areaNameCol", "text": "Area name", "fieldName": "area_name", "expander": "true", "width": "-1" }, "text": "areaNameCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "sidCol", "text": "Id", "fieldName": "sid", "width": "15em" }, "text": "sidCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "parentIdCol", "text": "Parent id", "fieldName": "parent_id", "width": "15em" }, "text": "parentIdCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "combo", "text": "editor", "cls": "Wb.Select", "properties": { "cid": "editor", "isProperty": "true", "forceSelect": "true", "url": "demo-source?xaction=areaSearch", "textField": "sid", "required": "true" } } ] } ] } ] } ] } ] } # example/comps/view.xwl Title: view ```json { "title": "", "icon": "list-view", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/css/demo.css\"\n]", "description": "demo-source=example/common/demo-source.xwl" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Array} - Common view data. */\n viewData: [\n { icon: 'user', text: 'User Management' },\n { icon: 'support', text: 'Support Service' },\n { icon: 'list', text: 'Consumption List' },\n { icon: 'preview', text: 'Disabled Item', _disabled: true, _tip: 'This item is disabled' },\n { icon: 'gear', text: 'System Settings' },\n { icon: 'truck', text: 'The text content of this item is too long and maybe overflowed' },\n { icon: 'database', text: 'Database Management' },\n { icon: 'flow1', text: 'WorkFlow Design' }\n ]\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "View", "cls": "w-title3" } }, { "_icon": "title", "text": "commonViewTitle", "cls": "Wb.Title", "properties": { "cid": "commonViewTitle", "title": "Common view" }, "_expanded": true }, { "_icon": "label", "text": "commonItemTplViewLabel", "cls": "Wb.Label", "properties": { "cid": "commonItemTplViewLabel", "text": "Define the content of ViewItem by defining itemTpl." } }, { "_icon": "list-view", "text": "commonItemTplView", "cls": "Wb.View", "properties": { "cid": "commonItemTplView", "itemTpl": "
\n
\n
{text}
\n
", "layout": "column", "data": "app.viewData", "height": "15em" }, "_expanded": true }, { "_icon": "label", "text": "commonItemTplFnViewLabel", "cls": "Wb.Label", "properties": { "cid": "commonItemTplFnViewLabel", "text": "Define the content of ViewItem by defining itemTplFn." } }, { "_icon": "list-view", "text": "commonItemTplFnView", "cls": "Wb.View", "properties": { "cid": "commonItemTplFnView", "layout": "column", "data": "app.viewData", "height": "15em", "frame": "true", "itemTplFn": "//Warning: [Wb.toHTML] must be used to convert value to HTML to avoid potential XSS security risks\n\nreturn `
\n
\n
${Wb.toHTML(data.text)}
\n
`;" }, "_expanded": true }, { "_icon": "title", "text": "customItemViewTitle", "cls": "Wb.Title", "properties": { "cid": "customItemViewTitle", "title": "Customized item itself" }, "_expanded": true }, { "_icon": "label", "text": "customItemViewLabel", "cls": "Wb.Label", "properties": { "cid": "customItemViewLabel", "text": "Define ViewItem itself by identifying the \"w-item\" class in itemTpl." } }, { "_icon": "label", "text": "fixed4ColumnsLabel", "cls": "Wb.Label", "properties": { "cid": "fixed4ColumnsLabel", "text": "Fixed 4 columns" } }, { "_icon": "list-view", "text": "fixed4ColumnsView", "cls": "Wb.View", "properties": { "cid": "fixed4ColumnsView", "itemTpl": "
\n
\n
{text}
\n
", "data": "app.viewData", "resizable": "true", "frame": "true", "bodyCls": "w-grid4 w-padding w-gapd5" } }, { "_icon": "label", "text": "autoWrapItemsLabel", "cls": "Wb.Label", "properties": { "cid": "autoWrapItemsLabel", "text": "Auto wrap items with fixed item width" }, "_expanded": true }, { "_icon": "list-view", "text": "autoWrapView", "cls": "Wb.View", "properties": { "cid": "autoWrapView", "itemTpl": "
\n
\n
{text}
\n
", "data": "app.viewData", "resizable": "true", "frame": "true", "bodyCls": "w-form w-padding w-gapd5" } }, { "_icon": "label", "text": "noWrapItemsLabel", "cls": "Wb.Label", "properties": { "cid": "noWrapItemsLabel", "text": "No wrap items with fixed item width and stick selection" }, "_expanded": true }, { "_icon": "list-view", "text": "noWrapView", "cls": "Wb.View", "properties": { "cid": "noWrapView", "itemTpl": "
\n
\n
{text}
\n
\n
", "data": "app.viewData", "multiSelect": "true", "resizable": "true", "frame": "true", "bodyCls": "w-row w-padding w-gapd5 w-visible-all", "stickSelect": "true" }, "events": { "click": "let view = this, target = e.target;\nif (target.closest('[cid=menu-btn]')) {\n let menu;\n menu = app.viewContextMenu ??= new Wb.Menu({\n items: [\n {\n text: 'Item 1', icon: 'grid', handler() {\n Wb.tip('Click at ' + app.currentWrapViewData.text);\n }\n },\n { text: 'Item 2', icon: 'earth' }\n ]\n });\n app.currentWrapViewData = target.getClosestComp().data;\n menu.showBy(target);\n}" } }, { "_icon": "title", "text": "variousTemplateSyntaxTitle", "cls": "Wb.Title", "properties": { "cid": "variousTemplateSyntaxTitle", "title": "Various template syntax" }, "_expanded": true }, { "_icon": "label", "text": "useItemTplLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "useItemTplLabel", "text": "Use itemTpl" } }, { "_icon": "list-view", "text": "variousItemTplSyntaxView", "cls": "Wb.View", "properties": { "cid": "variousItemTplSyntaxView", "itemTpl": "\n
\n
{num}
\n
{[data.money.usd]}
\n
{[data.date.dateTimeText12]}
\n
{for data.array}{if index > 0}, {/if}{[index + 1]}: {[value]}{/for}
\n
", "layout": "column", "data": "[\n { num: 1, money: 581234.56, date: new Date(), array: ['item1', 'item2', 'item3'] },\n { num: 2, money: 324549.7, date: new Date(), array: ['item4', 'item5', 'item6'] },\n { num: 3, money: 53543.28, date: new Date(), array: ['item7', 'item8', 'item9'] }\n]", "resizable": "true", "frame": "true" }, "_expanded": true }, { "_icon": "label", "text": "useItemTplFnLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "useItemTplFnLabel", "text": "Use itemTplFn with fixed header" } }, { "_icon": "list-view", "text": "useItemTplFnView", "cls": "Wb.View", "properties": { "cid": "useItemTplFnView", "layout": "column", "data": "[\n { num: 1, money: 581234.56, date: new Date(), array: ['item1', 'item2', 'item3'] },\n { num: 2, money: 324549.7, date: new Date(), array: ['item4', 'item5', 'item6'] },\n { num: 3, money: 53543.28, date: new Date(), array: ['item7', 'item8', 'item9'] }\n]", "resizable": "true", "frame": "true", "itemTplFn": "//Warning: [Wb.toHTML] must be used to convert value to HTML to avoid potential XSS security risks\n\nlet arrayText = '';\ndata.array.forEach((item, i) => {\n if (i > 0)\n arrayText += ', ';\n arrayText += '' + (i + 1) + ': ' + Wb.toHTML(item) + '';\n});\nreturn `
\n
${Wb.toHTML(data.num)}
\n
${Wb.toHTML(data.money.usd)}
\n
${Wb.toHTML(data.date.dateTimeText12)}
\n
${arrayText}
\n
`;", "html": "
\n
\n
Money
\n
Date
\n
Content
\n
\n
\n
", "height": "12em" }, "_expanded": true }, { "_icon": "title", "text": "nameListTitle", "cls": "Wb.Title", "properties": { "cid": "nameListTitle", "title": "Name list with remote data" }, "_expanded": true }, { "_icon": "label", "text": "nameListLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "nameListLabel", "text": "A common way to display a list of names with remote data and remote pagination." } }, { "_icon": "list-view", "text": "nameListView", "cls": "Wb.View", "properties": { "cid": "nameListView", "itemTpl": "
\n
\n
\n
{full_name}
\n
{code}
\n
\n
\n
\n
{[new Date().format('HH:mm')]}
\n
\n
\n
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDict", "height": "20em", "pagingBar": "true", "pageSize": "10" }, "_expanded": true, "events": { "itemclick": "if (e.target.closest('[cid=xicon]')) {\n Wb.tip('Click icon at: ' + item.data.full_name);\n}" } }, { "_icon": "title", "text": "tagListTitle", "cls": "Wb.Title", "properties": { "cid": "tagListTitle", "title": "Tag style list" }, "_expanded": true }, { "_icon": "label", "text": "tagListLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "tagListLabel", "text": "Display a list of tags with customized css and closed button." } }, { "_icon": "list-view", "text": "tagListView", "cls": "Wb.View", "properties": { "cid": "tagListView", "itemTpl": "
\n
\n
{full_name}
\n
\n
\n
\n
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDict", "height": "15em", "bodyCls": "w-form w-padding w-gapd5", "cls": "d-tag", "multiSelect": "true", "rectSelect": "true", "captureClass": ".w-close-btn" }, "_expanded": true, "events": { "captureclick": "if (e.target.closest('.w-close-btn'))\n item.destroy();" } }, { "_icon": "title", "text": "pagingTitle", "cls": "Wb.Title", "properties": { "cid": "pagingTitle", "title": "Pagination display" }, "_expanded": true }, { "_icon": "label", "text": "remoteDataPagingLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "remoteDataPagingLabel", "text": "Remote data pagination" } }, { "_icon": "list-view", "text": "remotePagingView", "cls": "Wb.View", "properties": { "cid": "remotePagingView", "itemTpl": "
{code} - {full_name}
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDict", "height": "20em", "pagingBar": "pageNums", "pageSize": "10" }, "_expanded": true }, { "_icon": "label", "text": "cachedPagingLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "cachedPagingLabel", "text": "Caching remote data and paging locally." } }, { "_icon": "list-view", "text": "cachedPagingView", "cls": "Wb.View", "properties": { "cid": "cachedPagingView", "itemTpl": "
{code} - {full_name}
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDict", "height": "20em", "pagingBar": "pageNums", "pageSize": "10", "cached": "true" }, "_expanded": true }, { "_icon": "label", "text": "localDataPagingLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "localDataPagingLabel", "text": "Local data pagination" } }, { "_icon": "list-view", "text": "localDataPagingView", "cls": "Wb.View", "properties": { "cid": "localDataPagingView", "layout": "column", "resizable": "true", "height": "15em", "frame": "true", "localData": "[\n { text: 'item1' }, { text: 'item2' }, { text: 'item3' }, { text: 'item4' }, { text: 'item5' },\n { text: 'item6' }, { text: 'item7' }, { text: 'item8' }, { text: 'item9' }, { text: 'item10' },\n { text: 'item11' }, { text: 'item12' }, { text: 'item13' }, { text: 'item14' }, { text: 'item15' },\n { text: 'item16' }, { text: 'item17' }, { text: 'item18' }, { text: 'item19' }\n]", "pagingBar": "true", "pageSize": "10", "itemTpl": "
{text}
" }, "_expanded": true }, { "_icon": "label", "text": "bottomNextPageLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "bottomNextPageLabel", "text": "Auto load next page when scroll to the bottom" } }, { "_icon": "list-view", "text": "bottomNextPageView", "cls": "Wb.View", "properties": { "cid": "bottomNextPageView", "itemTpl": "
{code} - {full_name}
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDict", "height": "20em", "pageSize": "10", "autoPaging": "true" }, "_expanded": true }, { "_icon": "label", "text": "topNextPageLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "topNextPageLabel", "text": "Auto load next page when scroll to the top" } }, { "_icon": "list-view", "text": "topNextPageView", "cls": "Wb.View", "properties": { "cid": "topNextPageView", "itemTpl": "
{code} - {full_name}
", "resizable": "true", "frame": "true", "url": "demo-source?xaction=staffDictDesc", "height": "20em", "pageSize": "10", "autoPaging": "false", "reverseData": "true", "autoToBottom": "true" }, "_expanded": true }, { "_icon": "title", "text": "miscViewTitle", "cls": "Wb.Title", "properties": { "cid": "miscViewTitle", "title": "Miscillaneous view" }, "_expanded": true }, { "_icon": "list-view", "text": "miscView", "cls": "Wb.View", "properties": { "cid": "miscView", "itemTpl": "
\n
\n
{text}
\n
", "layout": "grid4", "data": "app.viewData", "multiSelect": "true", "rectSelect": "true", "resizable": "true", "frame": "true", "keyWalking": "true", "bodyCls": "w-grid4", "padding": "2em", "gap": "2em", "reserveScrollbar": "true", "draggable": "true", "droppable": "demo.miscView" }, "events": { "itemdrop": "Wb.tip('Drop items: ' + draggable.dropItems.length + '\\nDest: ' + draggable.dest.data.text + '\\nMode: ' + draggable.mode);" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "gap": ".5em" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "selectItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "selectItem", "text": "Select" }, "events": { "click": "let miscView = app.miscView;\nmiscView.selection = [miscView.items[0], miscView.items[1]];\n// miscView.items[2].selected = true;" } }, { "_icon": "item", "text": "deselectItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deselectItem", "text": "Deselect" }, "events": { "click": "app.miscView.deselectAll();" } }, { "_icon": "item", "text": "addItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addItem", "text": "Add" }, "events": { "click": "let item = app.miscView.addData({ text: 'New Item', icon: 'earth' });\nitem.selected = true;\nitem.highlight();\n// app.miscView.add({ data: { text: 'New Item', icon: 'earth' } }); //equals above" } }, { "_icon": "item", "text": "insertItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "insertItem", "text": "Insert" }, "events": { "click": "let item = app.miscView.insertData(1, { text: 'Insert Item', icon: 'record' });\nitem.selected = true;\nitem.highlight();\n// app.miscView.insert(1, { data: { text: 'Insert Item', icon: 'record' } }); //equals above" } }, { "_icon": "item", "text": "deleteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deleteItem", "text": "Delete" }, "events": { "click": "app.miscView.firstItem?.destroy();" } }, { "_icon": "item", "text": "deleteSelectionsItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "deleteSelectionsItem", "text": "Delete selections" }, "events": { "click": "let view = app.miscView;\n\nif (!view.selections.length) {\n Wb.tipSelect();\n return;\n}\nview.destroySelections();" } }, { "_icon": "item", "text": "updateItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "updateItem", "text": "Update" }, "events": { "click": "let item = app.miscView.items[0];\n\nif (item) {\n item.set('text', 'Updated'); // equals to: item.proxy.text='Updated';\n item.set('icon', 'flower'); // equals to: item.proxy.icon='flower';\n item.focus();\n item.highlight();\n // item.update({ text: 'Updated', icon: 'flower' }); // More effective when updating multiple properties\n // item.data = { text: 'Updated', icon: 'flower' }; // Update all data\n}" } } ] } ] }, { "_icon": "component", "text": "miscDescComp", "cls": "Wb.Component", "properties": { "cid": "miscDescComp", "html": "
Feature List:
\n
    \n
  • Drag to draw a rectangle to select items.
  • \n
  • Press key to enter name in the view can navigate to the specified item.
  • \n
  • Maintain scrollbar position after reloading data.
  • \n
  • Intelligent navigate to specified item based on arrow key direction.
  • \n
  • Drag-and-Drop support.
  • \n
", "textSelectable": "false" } }, { "_icon": "title", "text": "listViewTitle", "cls": "Wb.Title", "properties": { "cid": "listViewTitle", "title": "List view" }, "_expanded": true }, { "_icon": "label", "text": "listViewLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "listViewLabel", "text": "List items in the specified pattern" } }, { "_icon": "list1", "text": "listView", "cls": "Wb.ListView", "properties": { "cid": "listView", "height": "20em", "url": "demo-source?xaction=staffDict", "textField": "full_name", "subtextField": "code", "defaultFields": "({\n _icon: { value: 'user2' },\n badge: { value: 8 },\n iconvalue: { value: 'bell-off' },\n datevalue: { value: new Date() }\n})", "resizable": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "events": { "buttonclick": "app.listView.viewType = button.cid;" }, "properties": { "cid": "tbar", "isProperty": "true", "gap": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "smallList", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "smallList", "text": "Small List", "groupName": "viewType", "active": "true" } }, { "_icon": "item", "text": "list", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "list", "text": "List", "groupName": "viewType", "active": "true" } }, { "_icon": "item", "text": "smallIcon", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "smallIcon", "text": "Small Icon", "groupName": "viewType" } }, { "_icon": "item", "text": "mediumIcon", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "mediumIcon", "text": "Medium Icon", "groupName": "viewType" } }, { "_icon": "item", "text": "bigIcon", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "bigIcon", "text": "Big Icon", "groupName": "viewType" } } ] } ] }, { "_icon": "title", "text": "iconViewTitle", "cls": "Wb.Title", "properties": { "cid": "iconViewTitle", "title": "Icon view" }, "_expanded": true }, { "_icon": "label", "text": "iconViewLabel", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "iconViewLabel", "text": "Display items with a big icon and text label, set layout to \"grid4\" to display 4 fixed columns, set \"padding\" and \"gap\" to adjust space." } }, { "_icon": "icon-list", "text": "iconView", "cls": "Wb.IconView", "properties": { "cid": "iconView", "data": "app.viewData", "iconField": "icon", "resizable": "true", "selectColor": "active", "defaultFields": "({\n badge: { value: 99 }\n})", "layout": "grid4", "padding": ".5em", "gap": "1em" }, "events": { "itemclick": "Wb.tip(item.data.text + ' clicked');" } }, { "_icon": "title", "text": "checkViewTitle", "cls": "Wb.Title", "properties": { "cid": "checkViewTitle", "title": "Check view" }, "_expanded": true }, { "_icon": "label", "text": "checkViewLabel1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "checkViewLabel1", "text": "Display items for single or multiple check" } }, { "_icon": "check7", "text": "checkView1", "cls": "Wb.CheckView", "properties": { "cid": "checkView1", "data": "[\n { text: 'Chrome', value: 1, _icon: 'chrome' },\n { text: 'Edge', value: 2, _icon: 'edge', _selected: true },\n { text: 'Firefox', value: 3, _icon: 'firefox' },\n { text: 'Safari', value: 4, _icon: 'safari' },\n { text: 'Image icon', value: 5, _img: 'wb/images/chart.png' }\n]", "multiSelect": "true", "maxWidth": "15em" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "gap": ".5em" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "setValueItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "setValueItem", "text": "Set Value" }, "events": { "click": "app.checkView1.value = [2, 3];" } }, { "_icon": "item", "text": "getValueItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "getValueItem", "text": "Get Value" }, "events": { "click": "Wb.tip('The value is: ' + Wb.encode(app.checkView1.value));" } } ] } ] } ] } ] } # example/comps/visual.xwl Title: visual ```json { "title": "", "icon": "image", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Image, Video and Icon", "cls": "w-title3" } }, { "_icon": "title", "text": "imageVideoIconListTitle", "cls": "Wb.Title", "properties": { "cid": "imageVideoIconListTitle", "title": "Image, video and icon list" } }, { "_icon": "container", "text": "imageVideoIconListCt", "cls": "Wb.Container", "properties": { "cid": "imageVideoIconListCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "commonImageLabel", "cls": "Wb.Label", "properties": { "cid": "commonImageLabel", "text": "Common image with click preview feature" } }, { "_icon": "image", "text": "commonImage", "cls": "Wb.Image", "properties": { "cid": "commonImage", "src": "wb/images/app/logo.png", "height": "6em", "clickPreview": "true", "width": "6em" } }, { "_icon": "label", "text": "commonPictureLabel", "cls": "Wb.Label", "properties": { "cid": "commonPictureLabel", "text": "Common picture with click preview feature" } }, { "_icon": "picture", "text": "commonPicture", "cls": "Wb.Picture", "properties": { "cid": "commonPicture", "src": "wb/images/app/logo.png", "clickPreview": "true" } }, { "_icon": "label", "text": "originalSizeLabel", "cls": "Wb.Label", "properties": { "cid": "originalSizeLabel", "text": "Original size image" } }, { "_icon": "image", "text": "originalSizeImage", "cls": "Wb.Image", "properties": { "cid": "originalSizeImage", "src": "wb/images/support.png", "size": "auto", "width": "6em", "height": "5em" } }, { "_icon": "label", "text": "videoLabel", "cls": "Wb.Label", "properties": { "cid": "videoLabel", "text": "Video" } }, { "_icon": "video", "text": "demoVideo", "cls": "Wb.Video", "properties": { "cid": "demoVideo", "src": "https://59b5fe18-b640-4ed9-a7d0-5867d0563fe4.mdnplay.dev/shared-assets/videos/flower.mp4", "height": "20em", "controls": "true" } }, { "_icon": "label", "text": "commonIconLabel", "cls": "Wb.Label", "properties": { "cid": "commonIconLabel", "text": "Common icon" } }, { "_icon": "logo", "text": "commonIcon", "cls": "Wb.Icon", "properties": { "cid": "commonIcon", "icon": "gear" }, "_expanded": true }, { "_icon": "label", "text": "commonImageIconLabel", "cls": "Wb.Label", "properties": { "cid": "commonImageIconLabel", "text": "Image icon" } }, { "_icon": "logo", "text": "commonImageIcon", "cls": "Wb.Icon", "properties": { "cid": "commonImageIcon", "img": "support" }, "_expanded": true }, { "_icon": "label", "text": "anySizeIconLabel", "cls": "Wb.Label", "properties": { "cid": "anySizeIconLabel", "text": "Any size icon, image and char Icon" } }, { "_icon": "container", "text": "anySizeCt", "cls": "Wb.Container", "properties": { "cid": "anySizeCt", "layout": "form" }, "_expanded": true, "items": [ { "_icon": "logo", "text": "icon1", "cls": "Wb.Icon", "_expanded": true, "properties": { "cid": "icon1", "icon": "flower" } }, { "_icon": "logo", "text": "icon2", "cls": "Wb.Icon", "_expanded": true, "properties": { "cid": "icon2", "fontSize": "1.2em", "img": "field" } }, { "_icon": "logo", "text": "icon3", "cls": "Wb.Icon", "_expanded": false, "properties": { "cid": "icon3", "fontSize": "1.5em", "icon": "🏥" } }, { "_icon": "logo", "text": "icon4", "cls": "Wb.Icon", "_expanded": false, "properties": { "cid": "icon4", "fontSize": "2em", "icon": "list" } }, { "_icon": "logo", "text": "icon5", "cls": "Wb.Icon", "_expanded": false, "properties": { "cid": "icon5", "fontSize": "3em", "icon": "🥋" } }, { "_icon": "logo", "text": "icon6", "cls": "Wb.Icon", "_expanded": false, "properties": { "cid": "icon6", "fontSize": "4em", "icon": "🎭" } } ] } ] } ] } ] } # example/comps/web-socket/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Send text to \"wb.ws.commonSocket\" of current user.\n */\n sendTextToCurrentUser() {\n Wb.send(Params.text, 'wb.ws.commonSocket');\n },\n /**\n * Send binary to \"wb.ws.binarySocket\" of current user.\n */\n sendBinaryToCurrentUser() {\n // Caution: if use Wb.send(inputStream, 'wb.ws.binarySocket') to send InputStream,\n // only the first websocket client will receive data, because the InputStream is unidirectional\n\n let bytes = new Wb.File(true, 'wb/images/app/logo.png').bytes;\n Wb.send(bytes, 'wb.ws.binarySocket');\n },\n /**\n * Send text to \"wb.ws.commonSocket\" of the specified user.\n */\n sendTextToSpecifiedUser() {\n Wb.send(Params.text, 'wb.ws.commonSocket', 'admin');\n },\n /**\n * Broadcast JSON to \"wb.ws.commonSocket\" of all users.\n */\n broadcastJSONToSpecifiedUser() {\n //use Wb.serialize/Wb.deserialize to send object\n Wb.send({ text: 'text message', number: 123 }, 'wb.ws.commonSocket', true);\n },\n /**\n * Receive data from client web socket.\n */\n receiveData() {\n //Global parameters:\n //data: data sent by the client websocket\n //event: message, open, close, error\n //session: websocket session\n //httpSession: http session; may be invalidated\n //closeReason: close reason\n //error: exception object\n\n if (event == 'message') {\n let value;\n\n if (data instanceof InputStream)\n value = IOUtils.toString(data); // data is ByteArrayInputStream, no need to close\n else\n value = data;\n Wb.log('Received: ' + value);\n Wb.send('result'); // send text to the client web socket\n // Wb.send(inputStream); // send inputStream to the client web socket\n // Wb.send(bytes); // send bytes to the client web socket\n }\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/comps/web-socket.xwl Title: web-socket ```json { "title": "", "icon": "plug", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "plug", "text": "commonSocket", "cls": "Wb.Socket", "properties": { "cid": "commonSocket", "name": "wb.ws.commonSocket" }, "events": { "message": "// let object = Wb.decode(e.data); // if e.data is JSON text\nWb.tip('Received: ' + e.data);" } }, { "_icon": "plug", "text": "xwlSocket", "cls": "Wb.Socket", "_expanded": true, "properties": { "cid": "xwlSocket", "name": "wb.ws.xwlSocket", "xwl": "@xpath + \"/actions {xaction: 'receiveData'}\"" }, "events": { "message": "Wb.tip('Received: ' + e.data);" } }, { "_icon": "plug", "text": "binarySocket", "cls": "Wb.Socket", "_expanded": false, "properties": { "cid": "binarySocket", "name": "wb.ws.binarySocket" }, "events": { "message": "let blob = e.data;\nWb.readBlob(blob, value => {\n Wb.tip('', true);\n});" } }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "WebSocket", "cls": "w-title3" } }, { "_icon": "label", "text": "sendTextToCurrentUserLabel", "cls": "Wb.Label", "properties": { "cid": "sendTextToCurrentUserLabel", "text": "Send text to the specified web socket of current user" } }, { "_icon": "button", "text": "sendTextToCurrentUserBtn", "cls": "Wb.Button", "properties": { "cid": "sendTextToCurrentUserBtn", "text": "Send text to current user", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=sendTextToCurrentUser',\n params: { text: 'text message' }\n});" } }, { "_icon": "label", "text": "sendBinaryToCurrentUserLabel", "cls": "Wb.Label", "properties": { "cid": "sendBinaryToCurrentUserLabel", "text": "Send binary to the specified web socket of current user" } }, { "_icon": "button", "text": "sendBinaryToCurrentUserBtn", "cls": "Wb.Button", "properties": { "cid": "sendBinaryToCurrentUserBtn", "text": "Send binary to current user", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=sendBinaryToCurrentUser'\n});" } }, { "_icon": "label", "text": "sendTextToSpecifyUserLabel", "cls": "Wb.Label", "properties": { "cid": "sendTextToSpecifyUserLabel", "text": "Send text to the specified web socket of the specified user" } }, { "_icon": "button", "text": "sendTextToSpecifiedUserBtn", "cls": "Wb.Button", "properties": { "cid": "sendTextToSpecifiedUserBtn", "text": "Send text to \"admin\" user", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=sendTextToSpecifiedUser',\n params: { text: 'text message' }\n});" } }, { "_icon": "label", "text": "broadcastJsonToAllUsersLabel", "cls": "Wb.Label", "properties": { "cid": "broadcastJsonToAllUsersLabel", "text": "Broadcast JSON to the specified web socket of all users" } }, { "_icon": "button", "text": "broadcastJsonToAllUsersBtn", "cls": "Wb.Button", "properties": { "cid": "broadcastJsonToAllUsersBtn", "text": "Broadcast JSON to all users", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=broadcastJSONToSpecifiedUser'\n});" } }, { "_icon": "label", "text": "sendTextBySocketLabel", "cls": "Wb.Label", "properties": { "cid": "sendTextBySocketLabel", "text": "Send text to the specified xwl module by xwlSocket" } }, { "_icon": "button", "text": "sendTextBySocketBtn", "cls": "Wb.Button", "properties": { "cid": "sendTextBySocketBtn", "text": "Send text by socket", "type": "primary" }, "events": { "click": "app.xwlSocket.send('text');" } }, { "_icon": "label", "text": "sendBinaryBySocketLabel", "cls": "Wb.Label", "properties": { "cid": "sendBinaryBySocketLabel", "text": "Send binary to the specified xwl module by xwlSocket" } }, { "_icon": "button", "text": "sendBinaryBySocketBtn", "cls": "Wb.Button", "properties": { "cid": "sendBinaryBySocketBtn", "text": "Send binary by socket", "type": "primary" }, "events": { "click": "let blob = new Blob([Wb.encode({ foo: 'bar' })], { type: 'application/json' });\napp.xwlSocket.send(blob);" } } ] } ] } # example/comps/window.xwl Title: window ```json { "title": "", "icon": "window", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n //Define Share tip\n myShareTip: new Wb.Tip({\n cls: 'w-error-color', fontSize: '1.5em', padding: '.2em', events: {\n beforetip(comp) {\n this.text = 'My share tip: ' + comp.cid;\n }\n }\n })\n});" }, "items": [ { "_icon": "array", "text": "components", "cls": "Wb.Array", "properties": { "cid": "components" }, "_expanded": true, "items": [ { "_icon": "window", "text": "dynamicNewWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "dynamicNewWin", "instanced": "false", "layout": "grid1", "closeAction": "destroy", "title": "Dynamic window" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Your name" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "Birth date" }, "_expanded": true } ] }, { "_icon": "window", "text": "modalWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "modalWin", "modal": "true", "icon": "bluetooth1", "title": "Modal window", "layout": "grid1" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Your name" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "Birth date" }, "_expanded": true } ] }, { "_icon": "window", "text": "autoResetWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "autoResetWin", "icon": "bluetooth1", "title": "Auto reset window", "layout": "grid1", "resetDialog": "true" }, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "properties": { "cid": "label1", "text": "The values of all controls will be automatically reset after the window is hidden" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Your name" }, "_expanded": true }, { "_icon": "text", "text": "text2", "cls": "Wb.Text", "properties": { "cid": "text2", "value": "abc", "text": "Default value" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "Birth date" }, "_expanded": true } ] }, { "_icon": "dialog", "text": "normalDialog", "cls": "Wb.Dialog", "_expanded": false, "properties": { "cid": "normalDialog", "title": "Normal Dialog" }, "items": [ { "_icon": "options", "text": "showDialogOption", "cls": "Wb.Option", "properties": { "cid": "showDialogOption", "text": "Show custom dialog" }, "_expanded": true, "events": { "click": "app.customDialog.show();" } } ] }, { "_icon": "dialog", "text": "customDialog", "cls": "Wb.Dialog", "_expanded": false, "properties": { "cid": "customDialog", "title": "Custom Dialog", "layout": "grid1", "plainTitle": "false", "labelUp": "true", "titleCenter": "false" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Your name" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "Birth date" }, "_expanded": true }, { "_icon": "button", "text": "newDialog", "cls": "Wb.Button", "properties": { "cid": "newDialog", "text": "New Dialog", "type": "primary" }, "events": { "click": "app.newDialog.show();" } }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "Wb.tip(Str.set);" }, "properties": { "cid": "item1", "icon": "gear" }, "text": "item1", "_expanded": true, "_icon": "item" } ] }, { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "add", "text": "@Str.add" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "edit", "text": "@Str.edit" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "item3", "icon": "delete", "text": "@Str.del" } } ] } ] }, { "_icon": "dialog", "text": "newDialog", "cls": "Wb.Dialog", "_expanded": true, "properties": { "cid": "newDialog", "title": "New Dialog", "layout": "grid1" } }, { "_icon": "drawer", "text": "defaultDrawer", "cls": "Wb.Drawer", "properties": { "cid": "defaultDrawer", "layout": "fit", "icon": "fieldset", "title": "Default Drawer", "closable": "true", "focusControl": "false" }, "_expanded": false, "items": [ { "_icon": "toolbar", "text": "toolbar1", "cls": "Wb.Toolbar", "_expanded": true, "properties": { "cid": "toolbar1", "layout": "grid5", "vertical": "true" }, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "add", "text": "Item1", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "edit", "text": "Item2", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "icon": "delete", "text": "Item3", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item4", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item4", "icon": "book1", "text": "Item4", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item5", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item5", "icon": "discovery", "text": "Item5", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item6", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item6", "icon": "comment2", "text": "Item6", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item7", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item7", "icon": "flow1", "text": "Item7", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item8", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item8", "icon": "dict", "text": "Item8", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item9", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item9", "icon": "grid", "text": "Item9", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "item", "text": "item10", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item10", "icon": "layout", "text": "Item10", "iconAlign": "top", "iconSize": "2em" } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "My Title" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Input text", "gridColumn": "span 5" }, "_expanded": true }, { "_icon": "switcher-on", "text": "toggle1", "cls": "Wb.Toggle", "properties": { "cid": "toggle1", "text": "Toggle", "gridColumn": "span 5" } } ] }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "properties": { "cid": "item1", "icon": "gear" }, "text": "item1", "_expanded": true, "_icon": "item" }, { "cls": "Wb.Item", "properties": { "cid": "item2", "icon": "share" }, "text": "item2", "_expanded": true, "_icon": "item" } ] } ] }, { "_icon": "drawer", "text": "rightDrawer", "cls": "Wb.Drawer", "properties": { "cid": "rightDrawer", "layout": "fit", "title": "Right Drawer", "dockPosition": "right" }, "_expanded": false, "items": [ { "_icon": "toolbar", "text": "toolbar1", "cls": "Wb.Toolbar", "properties": { "cid": "toolbar1", "type": "menu" }, "events": { "buttonclick": "Wb.tip(button.text + ' clicked');\nthis.parent.close();" }, "_expanded": true, "items": [ { "_icon": "item", "text": "item1", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item1", "icon": "favorite", "text": "Favorite Pages" } }, { "_icon": "item", "text": "item2", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item2", "icon": "gear", "text": "Setting" } }, { "_icon": "item", "text": "item3", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item3", "icon": "command", "text": "Command" } }, { "_icon": "item", "text": "item4", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item4", "icon": "word", "text": "Export to Word" } }, { "_icon": "item", "text": "item5", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item5", "icon": "excel", "text": "Export to Excel" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "item6", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item6", "icon": "print", "text": "Print" } }, { "_icon": "item", "text": "item7", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "item7", "icon": "table", "text": "Show Table" } } ] } ] }, { "_icon": "panel", "text": "hoverPanel", "cls": "Wb.Panel", "_expanded": false, "properties": { "cid": "hoverPanel", "layout": "grid1", "visible": "false", "minButtonWidth": "8em" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text1", "text": "User name" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "date1", "text": "Date" } }, { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Button", "events": { "click": "let panel = this.up('hoverPanel');\nWb.tip(Wb.encode(Wb.getValue(panel)));\npanel.hide();" }, "properties": { "cid": "button1", "icon": "ok", "text": "OK", "type": "primary" }, "text": "button1", "_expanded": true, "_icon": "button" }, { "cls": "Wb.Button", "events": { "click": "this.up('hoverPanel').hide();" }, "properties": { "cid": "button2", "text": "Cancel", "icon": "cancel" }, "text": "button2", "_expanded": true, "_icon": "button" } ] } ] }, { "_icon": "panel", "text": "hideGetValuePanel", "cls": "Wb.Panel", "_expanded": false, "properties": { "cid": "hideGetValuePanel", "layout": "grid1", "visible": "false", "minButtonWidth": "8em", "tagProperties": "({ closeOnEsc: false })" }, "items": [ { "_icon": "text", "text": "text1", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text1", "text": "User name" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "date1", "text": "Date" } } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Window and Tip", "cls": "w-title3" }, "_expanded": true }, { "_icon": "title", "text": "winTitle", "cls": "Wb.Title", "properties": { "cid": "winTitle", "title": "Window List" }, "_expanded": true }, { "_icon": "container", "text": "winCt", "cls": "Wb.Container", "properties": { "cid": "winCt", "layout": "form", "frame": "true", "cls": "w-rel", "height": "20em" }, "_expanded": true, "items": [ { "_icon": "button", "text": "dynamicNewWinBtn", "cls": "Wb.Button", "properties": { "cid": "dynamicNewWinBtn", "text": "Dynamic new window" }, "events": { "click": "let win = app.dynamicNewWin;\n\ndelete win.cid; //Prevent conflicts with the instance cid\nwin.owner = parentContainer; //make the win automatically destroy when parentContainer is destroyed\n\n//You can render the win to winCt by the following code:\n//win.renderEl = app.winCt.el; //Render to winCt, default render to BodyEl\n\nwin.x = Wb.random(70) + 'vw';\nwin.y = Wb.random(70) + 'vh';\nwin = Wb.create(win);\nwin.show();" } }, { "_icon": "button", "text": "showModalWinBtn", "cls": "Wb.Button", "properties": { "cid": "showModalWinBtn", "text": "Show modal window" }, "events": { "click": "app.modalWin.show();" } }, { "_icon": "button", "text": "showAutoResetWinBtn", "cls": "Wb.Button", "properties": { "cid": "showAutoResetWinBtn", "text": "Show auto reset window" }, "events": { "click": "app.autoResetWin.show();" } }, { "_icon": "window", "text": "normalWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "normalWin", "title": "Normal window", "width": "20em", "height": "10em", "visible": "true", "icon": "edit", "html": "Hide on Close", "layout": "center" }, "events": { "hide": "Wb.tip('Show again after 2 secs.')\nsetTimeout(f => app.normalWin.show().el.fadeIn(), 2000);" } }, { "_icon": "window", "text": "dialogWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "dialogWin", "title": "Dialog window without modal", "width": "20em", "height": "10em", "visible": "true", "dialog": "true", "modal": "false", "closeAction": "destroy", "html": "Destroy on Close", "layout": "center", "x": "23em", "collapsible": "true" }, "events": { "destroy": "Wb.tip(this.cid + ' is destroyed.');", "ok": "Wb.tip('You click \"' + Str.ok + '\" button.');\n// Close the window after performing asynchronous operation\n// let me = this;\n// Wb.ajax({\n// url,\n// success(resp) {\n// me.close();\n// }\n// });" } }, { "_icon": "window", "text": "noTitleWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "noTitleWin", "visible": "true", "titleBar": "false", "layout": "grid1", "labelUp": "true", "x": "45em" }, "items": [ { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "No title window", "dimTitle": "true" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Your name" } } ] } ] }, { "_icon": "title", "text": "messageTitle", "cls": "Wb.Title", "properties": { "cid": "messageTitle", "title": "Message" } }, { "_icon": "container", "text": "messageCt", "cls": "Wb.Container", "properties": { "cid": "messageCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "infoBtn", "cls": "Wb.Button", "properties": { "cid": "infoBtn", "text": "Info" }, "events": { "click": "Wb.info('Some information', f => Wb.tip('do something after show message'));" } }, { "_icon": "button", "text": "htmlInfoBtn", "cls": "Wb.Button", "properties": { "cid": "htmlInfoBtn", "text": "HTML Info" }, "events": { "click": "Wb.info('HTML information', null, true);" } }, { "_icon": "button", "text": "succBtn", "cls": "Wb.Button", "properties": { "cid": "succBtn", "text": "Succ" }, "events": { "click": "Wb.succ('Some information');" } }, { "_icon": "button", "text": "warnBtn", "cls": "Wb.Button", "properties": { "cid": "warnBtn", "text": "Warn" }, "events": { "click": "Wb.warn('Some information');" } }, { "_icon": "button", "text": "errorBtn", "cls": "Wb.Button", "properties": { "cid": "errorBtn", "text": "Error" }, "events": { "click": "Wb.error('Some information');" } }, { "_icon": "button", "text": "confirmBtn", "cls": "Wb.Button", "properties": { "cid": "confirmBtn", "text": "Confirm" }, "events": { "click": "Wb.confirm('Are you sure you want to delete?', f => Wb.tip('click OK'), f => Wb.tip('click Cancel'));" } }, { "_icon": "button", "text": "chooseBtn", "cls": "Wb.Button", "properties": { "cid": "chooseBtn", "text": "Choose" }, "events": { "click": "Wb.choose('Are you sure you want to save?', button => Wb.tip(button));" } }, { "_icon": "button", "text": "customizeBtn", "cls": "Wb.Button", "properties": { "cid": "customizeBtn", "text": "Customize" }, "events": { "click": "Wb.Window.showMessage({\n title: 'Customize', text: 'Some message', icon: 'share',\n name: 'sys.dialog', //name for shareing one dialog,\n buttons: [\n // The first button is the default enter button (press Enter to do), for more details see enterButton docs.\n { text: 'Primary', type: 'primary', cid: 'primary' },\n // The last button is the default esc button (press ESC or close dialog to do), for more details see escButton docs.\n { text: Str.cancel, cid: 'cancel' }\n ], callback(btn) {\n this.close();\n Wb.tip(btn + ' clicked');\n }\n});" } }, { "_icon": "button", "text": "fadeAnimateBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "fadeAnimateBtn", "text": "Fade Animate" }, "events": { "click": "Wb.error('Some message').el.fadeIn();" } }, { "_icon": "button", "text": "slideAnimateBtn", "cls": "Wb.Button", "_expanded": true, "properties": { "cid": "slideAnimateBtn", "text": "Slide Animate" }, "events": { "click": "Wb.info('Some message', function () {\n this.show().el.slideOut({ callback: f => this.hide() });\n}).el.slideIn();" } } ] }, { "_icon": "title", "text": "tipTitle", "cls": "Wb.Title", "properties": { "cid": "tipTitle", "title": "Tip" } }, { "_icon": "container", "text": "tipCt", "cls": "Wb.Container", "properties": { "cid": "tipCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "infoBtn", "cls": "Wb.Button", "properties": { "cid": "infoBtn", "text": "Info" }, "events": { "click": "Wb.tip('Some information');" } }, { "_icon": "button", "text": "htmlInfoBtn", "cls": "Wb.Button", "properties": { "cid": "htmlInfoBtn", "text": "HTML tip" }, "events": { "click": "Wb.tip('HTML information', true);" } }, { "_icon": "button", "text": "succBtn", "cls": "Wb.Button", "properties": { "cid": "succBtn", "text": "Succ" }, "events": { "click": "Wb.tipSucc('Some information');" } }, { "_icon": "button", "text": "warnBtn", "cls": "Wb.Button", "properties": { "cid": "warnBtn", "text": "Warn" }, "events": { "click": "Wb.tipWarn('Some information');" } }, { "_icon": "button", "text": "errorBtn", "cls": "Wb.Button", "properties": { "cid": "errorBtn", "text": "Error" }, "events": { "click": "Wb.tipError('Some information');" } }, { "_icon": "button", "text": "tipSelectBtn", "cls": "Wb.Button", "properties": { "cid": "tipSelectBtn", "text": "Tip Select" }, "events": { "click": "Wb.tipSelect();" } }, { "_icon": "button", "text": "tipDoneBtn", "cls": "Wb.Button", "properties": { "cid": "tipDoneBtn", "text": "Tip Done" }, "events": { "click": "Wb.tipDone(Str.save);" } } ] }, { "_icon": "title", "text": "toastTitle", "cls": "Wb.Title", "properties": { "cid": "toastTitle", "title": "Toast" } }, { "_icon": "container", "text": "toastCt", "cls": "Wb.Container", "properties": { "cid": "toastCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "infoBtn", "cls": "Wb.Button", "properties": { "cid": "infoBtn", "text": "Info" }, "events": { "click": "Wb.toast('Some information');" } }, { "_icon": "button", "text": "htmlInfoBtn", "cls": "Wb.Button", "properties": { "cid": "htmlInfoBtn", "text": "HTML tip" }, "events": { "click": "Wb.toast('HTML information', true);" } }, { "_icon": "button", "text": "succBtn", "cls": "Wb.Button", "properties": { "cid": "succBtn", "text": "Succ" }, "events": { "click": "Wb.toastSucc('Some information');" } }, { "_icon": "button", "text": "warnBtn", "cls": "Wb.Button", "properties": { "cid": "warnBtn", "text": "Warn" }, "events": { "click": "Wb.toastWarn('Some information');" } }, { "_icon": "button", "text": "errorBtn", "cls": "Wb.Button", "properties": { "cid": "errorBtn", "text": "Error" }, "events": { "click": "Wb.toastError('Some information');" } } ] }, { "_icon": "title", "text": "dialogTitle", "cls": "Wb.Title", "properties": { "cid": "dialogTitle", "title": "Dialog" } }, { "_icon": "container", "text": "dialogCt", "cls": "Wb.Container", "properties": { "cid": "dialogCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "normalBtn", "cls": "Wb.Button", "properties": { "cid": "normalBtn", "text": "Normal dialog" }, "events": { "click": "app.normalDialog.show();" } }, { "_icon": "button", "text": "customBtn", "cls": "Wb.Button", "properties": { "cid": "customBtn", "text": "Custom dialog" }, "events": { "click": "app.customDialog.show();" } } ] }, { "_icon": "title", "text": "drawerTitle", "cls": "Wb.Title", "properties": { "cid": "drawerTitle", "title": "Drawer" } }, { "_icon": "container", "text": "drawerCt", "cls": "Wb.Container", "properties": { "cid": "drawerCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "defaultBtn", "cls": "Wb.Button", "properties": { "cid": "defaultBtn", "text": "Default drawer" }, "events": { "click": "app.defaultDrawer.show();" } }, { "_icon": "button", "text": "topBtn", "cls": "Wb.Button", "properties": { "cid": "topBtn", "text": "Top drawer" }, "events": { "click": "app.topDrawer ??= new Wb.Drawer({ dockPosition: 'top', height: '40vh', title: 'Top Drawer', plainTitle: true });\napp.topDrawer.show();" } }, { "_icon": "button", "text": "rightBtn", "cls": "Wb.Button", "properties": { "cid": "rightBtn", "text": "Right drawer" }, "events": { "click": "app.rightDrawer.show();" } }, { "_icon": "button", "text": "leftBtn", "cls": "Wb.Button", "properties": { "cid": "leftBtn", "text": "Left drawer" }, "events": { "click": "app.leftDrawer ??= new Wb.Drawer({ dockPosition: 'left', width: '40vw', title: 'Left Drawer' });\napp.leftDrawer.show();" } } ] }, { "_icon": "title", "text": "promptTitle", "cls": "Wb.Title", "properties": { "cid": "promptTitle", "title": "Prompt Window" } }, { "_icon": "container", "text": "promptCt", "cls": "Wb.Container", "properties": { "cid": "promptCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "promptStringBtn", "cls": "Wb.Button", "properties": { "cid": "promptStringBtn", "text": "Prompt string" }, "events": { "click": "Wb.promptString('Enter String', (text, win) => {\n Wb.tip('Enter \"' + text + '\".');\n win.close();\n}, 'old string');" } }, { "_icon": "button", "text": "promptTextBtn", "cls": "Wb.Button", "properties": { "cid": "promptTextBtn", "text": "Prompt text" }, "events": { "click": "Wb.promptText('Enter Text', (text, win) => {\n Wb.tip('Enter \"' + text + '\".');\n win.close();\n}, 'old text');" }, "_expanded": true }, { "_icon": "button", "text": "customPromptBtn", "cls": "Wb.Button", "properties": { "cid": "customPromptBtn", "text": "Custom prompt" }, "events": { "click": "Wb.prompt('My Dialog', [\n { text: 'Your Name', cid: 'name', value: 'old value' },\n { text: 'Date', cid: 'date', cname: 'date' }\n], (values, win) => {\n Wb.tip(Wb.encode(values));\n win.close();\n});" } }, { "_icon": "button", "text": "singleInstanceBtn", "cls": "Wb.Button", "properties": { "cid": "singleInstanceBtn", "text": "Single instance" }, "events": { "click": "let win = Wb.prompt({ title: 'My Single Dialog', icon: 'chart-bar'/*, resetDialog: true*/ }, [\n { text: 'Your Name', cid: 'name', value: 'old value' },\n { text: 'Date', cid: 'date', cname: 'date' }\n], (values, win) => {\n Wb.tip(Wb.encode(values));\n win.close();\n}, 'my.win.id');\n// Wb.reset(win);" } }, { "_icon": "button", "text": "hoverPanelBtn", "cls": "Wb.Button", "properties": { "cid": "hoverPanelBtn", "text": "Hover panel" }, "events": { "click": "Wb.hover(app.hoverPanel, this);" } }, { "_icon": "button", "text": "hideGetValueBtn", "cls": "Wb.Button", "properties": { "cid": "hideGetValueBtn", "text": "Hide to get value" }, "events": { "click": "Wb.hover(app.hideGetValuePanel, this, panel => {\n Wb.tip(Wb.encode(Wb.getValue(panel)));\n});" } } ] }, { "_icon": "title", "text": "tooltipTitle", "cls": "Wb.Title", "properties": { "cid": "tooltipTitle", "title": "Tooltip" } }, { "_icon": "container", "text": "tooltipCt", "cls": "Wb.Container", "properties": { "cid": "tooltipCt", "layout": "form", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "component", "text": "tipComp", "cls": "Wb.Component", "properties": { "cid": "tipComp", "tip": "Common tip message", "text": "Move the mouse here", "padding": "1em", "frame": "true" } }, { "_icon": "component", "text": "retainTipComp", "cls": "Wb.Component", "properties": { "cid": "retainTipComp", "tip": "{enterRetain: true, textSelectable: true, html: 'When the pointer is in the Tip, it will not auto hide.'}", "text": "Retain tip", "padding": "1em", "frame": "true" } }, { "_icon": "component", "text": "customTip", "cls": "Wb.Component", "properties": { "cid": "customTip", "text": "Custom retain tip", "padding": "1em", "frame": "true" }, "_expanded": false, "items": [ { "_icon": "info", "text": "tip", "cls": "Wb.Tip", "properties": { "cid": "tip", "isProperty": "true", "layout": "grid1", "enterRetain": "true", "width": "40em", "gap": "1em", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "properties": { "cid": "label1", "titleType": "title4", "text": "Some descriptions" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } }, { "_icon": "label1", "text": "displayField1", "cls": "Wb.DisplayField", "properties": { "cid": "displayField1", "text": "Display Field", "value": "Some value" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "text": "Button", "icon": "button" } } ] } ] }, { "_icon": "component", "text": "customShareTip1", "cls": "Wb.Component", "properties": { "cid": "customShareTip1", "text": "Custom share tip 1", "padding": "1em", "tip": "@app.myShareTip", "frame": "true" }, "_expanded": true }, { "_icon": "component", "text": "customShareTip2", "cls": "Wb.Component", "properties": { "cid": "customShareTip2", "text": "Custom share tip 2", "padding": "1em", "tip": "@app.myShareTip", "frame": "true" }, "_expanded": true }, { "_icon": "component", "text": "clickToTipComp", "cls": "Wb.Component", "properties": { "cid": "clickToTipComp", "text": "Click to tip", "padding": "1em", "frame": "true" }, "events": { "click": "Wb.tipAt('Some message', e.x, e.y);" } } ] } ] } ] } # example/crud/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "true", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Select and download data\n */\n select() {\n let download = Wb.getObject('download');\n if (download) {\n //download blob\n let row = Wb.getRow({\n sql: 'select full_name, photo from wb_staff where sid={?$sid?}',\n blob: true,\n params: download\n });\n if (row?.photo)\n Wb.exportData(row.photo, row.full_name + '.png');\n else\n Wb.raise('Photo not found.');\n } else {\n let sql;\n\n sql = `\n select a.*,b.user_name,c.dept_name,c.dept_code from wb_staff a, wb_user b, wb_dept c\n where a.user_id=b.sid and a.dept_id=c.sid\n `;\n if (Params.search) {\n Wb.setLike('search');\n sql += ' and (a.full_name like {?search?} or a.code like {?search?} or b.user_name like {?search?})';\n }\n // getOrderSql will not cause SQL injection\n sql += Wb.getOrderSql({ email: 'a.email' });// There are 2 emails fields in the tables\n Wb.sendRowx({ sql, kv: { gender: 'gender' } });\n }\n },\n /**\n * Select and download data by using dict.\n */\n dictSelect() {\n if (Wb.has('download')) {\n this.select(); // invoke select download handler\n } else {\n let sql;\n sql = `\n select a.sid, a.code, a.full_name, a.user_id, b.user_name as user_name_bind,\n a.dept_id, c.dept_code as dept_code_hide, c.dept_name as dept_name_tree, a.birth_date, a.gender, a.height,\n a.email, a.salary, a.cv, a.photo from wb_staff a, wb_user b, wb_dept c\n where a.user_id=b.sid and a.dept_id=c.sid\n `;\n if (Params.search) {\n Wb.setLike('search');\n sql += ' and (a.full_name like {?search?} or a.code like {?search?} or b.user_name like {?search?})';\n }\n // getOrderSql will not cause SQL injection\n sql += Wb.getOrderSql({ email: 'a.email', user_name_bind: 'b.user_name', dept_name_tree: 'c.dept_name' });\n Wb.sendDict(sql, 'wb,');\n }\n },\n /**\n * select usernames.\n */\n selectUsers() {\n let sql;\n\n sql = 'select sid,user_name from wb_user';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where user_name like {?query?}';\n }\n sql += ' order by user_name';\n Wb.sendRows(sql);\n },\n /**\n * select depts.\n */\n selectDepts() {\n let sql;\n\n sql = 'select sid,dept_name from wb_dept';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where dept_name like {?query?}';\n }\n sql += ' order by dept_name';\n Wb.sendRows(sql);\n },\n /**\n * Save data.\n */\n save() {\n let sid, rec, insert = [];\n\n Params.insert?.forEach(item => {\n sid = Wb.getId();\n rec = { sid };\n Wb.apply(item, rec);\n insert.push(rec);\n });\n Wb.sync({\n tableName: 'wb_staff',\n insert: Params.insert,\n update: Params.update,\n del: Params.del\n });\n // Another way for executing sync:\n // Wb.set({tableName: 'wb_staff'}); //Warning: Must set tableName otherwise tableName in parameters will be used\n // Wb.sync(Params);\n Wb.send({ insert });\n },\n /**\n * Add record.\n */\n add() {\n let rec = { sid: Wb.getId() };\n\n Wb.set(rec);\n Wb.sync({ tableName: 'wb_staff', insert: Params });\n Wb.send(rec);\n },\n /**\n * Update record.\n */\n edit() {\n Wb.sync({ tableName: 'wb_staff', update: Params });\n },\n /**\n * Delete records.\n */\n del() {\n let del = Wb.getObject('del');\n\n Wb.sync({ tableName: 'wb_staff', del });\n },\n /**\n * Get photo.\n */\n getPhoto() {\n let row = Wb.getRow({\n sql: 'select photo from wb_staff where sid={?sid?}',\n blob: true\n });\n if (row?.photo)\n Wb.exportData(row.photo);\n else\n Wb.exportData(new Wb.File(true, 'wb/images/null.png').stream);\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/crud/dict-edit-dialog.xwl Title: dict-edit-dialog ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Object} - The edit window configs object. */\n winConfigs: {\n events: {\n ready() {\n let win = this, ct = new Wb.Container({ layout: 'grid2', autoGrid: 'up' }), cv, photo;\n\n //add all items to ct without cv\n ct.add(win.items.filter(item => item.cid != 'cv'));\n\n //add titles and ct to win\n win.layout = 'form1';\n win.insert(0, { cname: 'title', title: 'General Information' });\n win.insert(1, ct);\n win.insert(2, { cname: 'title', title: 'Personal Resume' });\n\n //customize cv\n cv = win.down('cv');\n Wb.apply(cv, { flex: 1, text: null, minHeight: '5em' });\n\n //customize photo\n photo = ct.down('photo');\n //Insert to 2nd position\n ct.insert(1, photo);\n //You can configure these properties into the dictionary\n Wb.apply(photo, {\n gridRow: 'span 3', browseMode: true, browseHeight: '8em', browseWidth: '12em', fileButtons: false\n });\n\n //insert table style toggle button\n win.buttonsBar.insert(0, [{\n cname: 'button', active: false, text: 'Table Style', plainIcon: true, icon: 'table', handler() {\n ct.tableStyle = !ct.tableStyle;\n }\n }, '->']);\n }\n }\n },\n /**\n * Method to execute when adding or updating data fails.\n * @param {String} resp Response text.\n */\n onFailure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', app.grid1.dictWin.down('code'));\n }\n});" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.dictAdd({\n url: xpath + '/../actions&xaction=add',\n failure: app.onFailure\n}, null, null, null, app.winConfigs);" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "let win = app.grid1.dictEdit({\n url: xpath + '/../actions&xaction=edit',\n failure: app.onFailure\n}, 'code', null, null, app.winConfigs);\nlet rec = app.grid1.selection;\nif (rec)\n win.down('photo').preview(xpath + '/../actions&xaction=getPhoto&sid=' + rec.data.sid + '&' + Wb.getId());" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.removeRecords(xpath + '/../actions&xaction=del', 'code');" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/../actions&xaction=dictSelect'", "multiSelect": "true", "columnsSortable": "true", "sorters": "code", "stateId": "wb.crud-dialog" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');", "beforeloadcolumns": "// Customize columns from the dict regardless of whether this grid is in a saved state.\nlet col = columns.find(col => col.fieldName == 'full_name');\n\nif (col)\n col.width = '12em';\n\n// remove default row number column\n// columns.removeBy(col => col.rowNum);" } } ] } ] } # example/crud/dict-edit-grid.xwl Title: dict-edit-grid ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Fires after the table data is changed. @priv\n */\n onChange() {\n app.saveBtn.disabled = false;\n },\n /**\n * Save grid data.\n * @param {Function} [callback] Callback function after success.\n */\n save(callback) {\n app.grid1.sync({\n url: xpath + '/../actions&xaction=save',\n success() {\n app.saveBtn.disabled = true;\n callback?.();\n //Wb.tip('Successfully saved');\n },\n failure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', Str.code);\n }\n });\n }\n});", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.addRecord();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.delRecords();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "keys": "Ctrl+S", "disabled": "true" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/../actions&xaction=dictSelect'", "editable": "true", "multiSelect": "true", "columnsSortable": "true", "sorters": "code" }, "_expanded": true, "events": { "editing": "app.onChange();", "itemchange": "app.onChange();", "beforeedit": "//Set photo file name\nif (column.fieldName == 'photo') {\n let value = column.render.call(row, configs.value, row.data);\n if (value)\n configs.value = value;\n}", "beforeload": "return this.saveConfirm(app.saveBtn, app.save);" } } ] } ] } # example/crud/edit-dialog.xwl Title: edit-dialog ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "editWin", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "editWin", "layout": "grid2", "resetDialog": "true", "autoGrid": "true" }, "items": [ { "_icon": "title", "text": "generalTitle", "cls": "Wb.Title", "properties": { "cid": "generalTitle", "title": "General Information" } }, { "cls": "Wb.Text", "properties": { "cid": "code", "required": "true", "maxLength": "5", "text": "Code" }, "text": "code", "_expanded": true, "_icon": "text" }, { "_icon": "search-file", "text": "photo", "cls": "Wb.FileInput", "properties": { "cid": "photo", "accept": ".png", "text": "Photo", "gridRow": "span 3", "browseMode": "true", "browseHeight": "8em" } }, { "cls": "Wb.Text", "properties": { "cid": "full_name", "required": "true", "text": "Full name" }, "text": "full_name", "_expanded": true, "_icon": "text" }, { "_icon": "combo", "text": "user_name", "cls": "Wb.Select", "properties": { "cid": "user_name", "textField": "user_name", "valueField": "sid", "url": "@xpath + '/../actions&xaction=selectUsers'", "required": "true", "forceSelect": "true", "text": "Username", "bindField": "user_id" } }, { "_icon": "combo", "text": "dept_name", "cls": "Wb.Select", "properties": { "cid": "dept_name", "url": "m?xwl=sys/dialog/dept-selector/select", "textField": "dept_name", "clearButton": "true", "treePicker": "true", "subtextField": "dept_code", "required": "true", "text": "Dept name", "gridColumn": "span 2", "valueMap": "{ sid: 'dept_id', dept_name: 'dept_name', dept_code: 'dept_code' }" } }, { "_icon": "calendar", "text": "birth_date", "cls": "Wb.Date", "properties": { "cid": "birth_date", "text": "Birth date" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "properties": { "cid": "gender", "text": "Gender", "keyName": "gender" } }, { "_icon": "number-edit", "text": "height", "cls": "Wb.Number", "properties": { "cid": "height", "minValue": "0", "maxValue": "999", "decimalCount": "0", "text": "Height" } }, { "cls": "Wb.Text", "properties": { "cid": "email", "valueType": "email", "text": "Email" }, "text": "email", "_expanded": true, "_icon": "text" }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "decimalCount": "2", "text": "Salary" } }, { "_icon": "title", "text": "cvTitle", "cls": "Wb.Title", "properties": { "cid": "cvTitle", "title": "Personal Resume" } }, { "_icon": "textarea", "text": "cv", "cls": "Wb.TextArea", "properties": { "cid": "cv", "gridColumn": "span 2", "height": "8em" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit", "autoContextMenu": "true" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "// Preferred way:\n// app.grid1.insertRecord({\n// url: xpath + '/../actions&xaction=add',\n// failure(resp) {\n// Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n// }\n// }, app.editWin);\n\n\n// The following code demonstrates the detailed implementation\nlet win = app.editWin;\n\nwin.icon = 'add';\nwin.title = Str.add;\nwin.focusControl = null;\nwin.okHandler = (win, values) => {\n Wb.ajax({\n url: xpath + '/../actions&xaction=add',\n params: values,\n json: true,\n success(resp) {\n app.grid1.appendRecord(Wb.apply(values, resp));\n win.hide();\n },\n failure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n }\n });\n};\nwin.show();\nwin.scrollEl.scrollTop = win.scrollEl.scrollLeft = 0;" } }, { "_icon": "item", "text": "editBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editBtn", "text": "@Str.edit", "icon": "edit", "keys": "Ctrl+J" }, "events": { "click": "// Preferred way:\n// let rec = app.grid1.selection;\n// app.grid1.editRecord({\n// url: xpath + '/../actions&xaction=edit',\n// failure(resp) {\n// Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n// }\n// }, app.editWin);\n// if (rec)\n// app.editWin.down('photo').preview(xpath + '/../actions&xaction=getPhoto&sid=' + data.sid + '&' + Wb.getId());\n\n\n// The following code demonstrates the detailed implementation\nlet win = app.editWin, rec = app.grid1.selection, data;\n\nif (!rec) {\n Wb.tipSelect();\n return;\n}\ndata = rec.data;\nwin.icon = 'edit';\nwin.title = Str.edit + ' - ' + data.code;\nwin.focusControl = true;\nWb.setValue(win, data);\nwin.down('photo').preview(xpath + '/../actions&xaction=getPhoto&sid=' + data.sid + '&' + Wb.getId());\nwin.okHandler = (win, values) => {\n Wb.ajax({\n url: xpath + '/../actions&xaction=edit',\n params: rec.getDiffer(values),\n json: true,\n success(resp) {\n rec.update(Wb.apply(values, resp));\n win.hide();\n },\n failure(resp) {\n Wb.checkExists(resp, 'wb_staff_code', app.editWin.down('code'));\n }\n });\n};\nwin.show();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "// Preferred way:\n// app.grid1.removeRecords( xpath + '/../actions&xaction=del', 'code');\n\n\n// The following code demonstrates the detailed implementation\nlet grid = app.grid1, recs = grid.selections;\nif (!recs.length) {\n Wb.tipSelect();\n return;\n}\nWb.confirm(Wb.getActionHint(recs, 'code'), f => {\n Wb.ajax({\n url: xpath + '/../actions&xaction=del',\n params: { del: grid.originData },\n success() {\n grid.delRecords();\n }\n });\n});" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/../actions&xaction=select'", "multiSelect": "true", "columnsSortable": "true", "sorters": "code", "stateId": "wb.crud-dialog" }, "_expanded": true, "events": { "itemdblclick": "app.editBtn.fireEvent('click');" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "codeCol", "fieldName": "code", "text": "Code", "width": "5em" }, "text": "codeCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "fullNameCol", "fieldName": "full_name", "text": "Full name", "width": "13em" }, "text": "fullNameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "usernameCol", "fieldName": "user_name", "text": "Username" }, "text": "usernameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "deptCol", "fieldName": "dept_name", "text": "Department", "render": "Wb.Column.addSubText(el, value, data.dept_code);" }, "text": "deptCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "birthDateCol", "fieldName": "birth_date", "text": "Birth date" }, "text": "birthDateCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "genderCol", "fieldName": "gender", "text": "Gender", "width": "6em", "keyValue": "true" }, "text": "genderCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "heightCol", "fieldName": "height", "text": "Height", "width": "6em" }, "text": "heightCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "emailCol", "fieldName": "email", "text": "Email", "width": "18em" }, "text": "emailCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "salaryCol", "fieldName": "salary", "text": "Salary", "type": "usd", "width": "9em" }, "text": "salaryCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "cvCol", "fieldName": "cv", "text": "CV", "width": "15em", "sortable": "false" }, "text": "cvCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "photoCol", "fieldName": "photo", "text": "Photo", "width": "15em", "render": "if (value)\n Wb.Column.createDownload(el, column.fieldName, data.full_name + '.png');", "sortable": "false" }, "text": "photoCol", "_expanded": true, "_icon": "column" } ] } ] } ] } ] } # example/crud/edit-grid.xwl Title: edit-grid ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Fires after the table data is changed. @priv\n */\n onChange() {\n app.saveBtn.disabled = false;\n },\n /**\n * Save grid data.\n * @param {Function} [callback] Callback function after success.\n */\n save(callback) {\n app.grid1.sync({\n url: xpath + '/../actions&xaction=save',\n success() {\n app.saveBtn.disabled = true;\n callback?.();\n //Wb.tip('Successfully saved');\n },\n failure(resp) {\n // Preferred way:\n // Wb.checkExists(resp, 'wb_staff_code', Str.code);\n if (resp?.toLowerCase().includes('wb_staff_code'))\n Wb.error(Str.duplicate.format(Str.code));\n }\n });\n }\n});", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.addRecord();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.delRecords();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "keys": "Ctrl+S", "disabled": "true" }, "events": { "click": "app.save();" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.grid1.delayLoad({ comps: app.search });" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/../actions&xaction=select'", "editable": "true", "multiSelect": "true", "columnsSortable": "true", "sorters": "code" }, "_expanded": true, "events": { "editing": "app.onChange();", "itemchange": "app.onChange();", "beforeedit": "//Set photo file name\nif (column.fieldName == 'photo') {\n let value = column.render.call(row, configs.value, row.data);\n if (value)\n configs.value = value;\n}", "beforeload": "// Preferred way:\n// return this.saveConfirm(app.saveBtn, app.save);\nlet grid = this, saveBtn = app.saveBtn;\n//saveBtn is null before initialized\nif (saveBtn && !saveBtn.disabled) {\n Wb.choose(Str.modifiedConfirm.format(Str.list), btn => {\n if (btn == 'yes')\n app.save(f => grid.reload());\n else if (btn == 'no') {\n saveBtn.disabled = true;\n grid.reload();\n }\n });\n return false;\n}" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "codeCol", "fieldName": "code", "text": "Code", "width": "5em" }, "text": "codeCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "required": "true", "maxLength": "5" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "fullNameCol", "fieldName": "full_name", "text": "Full name", "width": "13em" }, "text": "fullNameCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "usernameCol", "fieldName": "user_name", "text": "Username" }, "text": "usernameCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "combo", "text": "editor", "cls": "Wb.Select", "properties": { "cid": "editor", "textField": "user_name", "valueField": "sid", "isProperty": "true", "url": "@xpath + '/../actions&xaction=selectUsers'", "required": "true", "forceSelect": "true", "bindField": "user_id" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "deptCol", "fieldName": "dept_name", "text": "Department", "width": "20em", "render": "Wb.Column.addSubText(el, value, data.dept_code);" }, "text": "deptCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "combo", "text": "editor", "cls": "Wb.Select", "properties": { "cid": "editor", "url": "m?xwl=sys/dialog/dept-selector/select", "textField": "dept_name", "treePicker": "true", "subtextField": "dept_code", "valueMap": "{ sid: 'dept_id', dept_name: 'dept_name', dept_code: 'dept_code' }", "isProperty": "true", "required": "true" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "birthDateCol", "fieldName": "birth_date", "text": "Birth date" }, "text": "birthDateCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "calendar", "text": "editor", "cls": "Wb.Date", "properties": { "cid": "editor", "isProperty": "true" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "genderCol", "fieldName": "gender", "text": "Gender", "width": "6em", "keyValue": "true" }, "text": "genderCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "combo", "text": "editor", "cls": "Wb.Select", "properties": { "cid": "editor", "isProperty": "true", "keyName": "gender" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "heightCol", "fieldName": "height", "text": "Height", "width": "6em" }, "text": "heightCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "number-edit", "text": "editor", "cls": "Wb.Number", "properties": { "cid": "editor", "isProperty": "true", "minValue": "0", "maxValue": "999", "decimalCount": "0" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "emailCol", "fieldName": "email", "text": "Email", "width": "18em" }, "text": "emailCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "valueType": "email" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "salaryCol", "fieldName": "salary", "text": "Salary", "type": "usd", "width": "9em" }, "text": "salaryCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "number-edit", "text": "editor", "cls": "Wb.Number", "properties": { "cid": "editor", "isProperty": "true", "decimalCount": "2" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "cvCol", "fieldName": "cv", "text": "CV", "width": "15em", "sortable": "false" }, "text": "cvCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "textarea", "text": "editor", "cls": "Wb.TextArea", "properties": { "cid": "editor", "isProperty": "true", "maximizable": "true" } } ] }, { "cls": "Wb.Column", "properties": { "cid": "photoCol", "fieldName": "photo", "text": "Photo", "width": "15em", "render": "if (value)\n return value instanceof File ? value.name : '(photo)';", "sortable": "false" }, "text": "photoCol", "_expanded": true, "_icon": "column", "items": [ { "_icon": "search-file", "text": "editor", "cls": "Wb.FileInput", "properties": { "cid": "editor", "isProperty": "true", "accept": ".png", "download": "true" } } ] } ] } ] } ] } ] } # example/crud/select-staff.xwl Title: select-staff ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "true", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.sendRowx('select * from wb_staff');" }, "_icon": "module" } # example/crud/staff.xwl Title: staff ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "url": "@xpath + '/../select-staff'" } } ] } ] } # example/load/client-load-module/card.xwl Title: card ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Init the module.\n */\n init() {\n // app.date1.focus();\n }\n});" }, "items": [ { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "panel1", "layout": "grid1" }, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "This card from card.xwl" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "text1", "text": "Text" } }, { "_icon": "calendar", "text": "date1", "cls": "Wb.Date", "properties": { "cid": "date1", "text": "Date" } }, { "_icon": "button", "text": "setValueBtn", "cls": "Wb.Button", "properties": { "cid": "setValueBtn", "text": "Set text value", "width": "20em", "justifySelf": "center" }, "events": { "click": "app.text1.value = 'card value';" } }, { "_icon": "button", "text": "setParentTitleBtn", "cls": "Wb.Button", "properties": { "cid": "setParentTitleBtn", "text": "Set parent module tab title", "width": "20em", "justifySelf": "center" }, "events": { "click": "parentApp.runModuleCardTab.title = 'New Title';" } } ] }, { "_icon": "window", "text": "thisWinAutoDestroyedAfterOwnerDestroyed", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "thisWinAutoDestroyedAfterOwnerDestroyed" } } ] } # example/load/client-load-module/common-window.xwl Title: common-window ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /** @property {Function} callback The callback function. @priv */\n /**\n * Perform add.\n * @param {Number} value1 value 1.\n * @param {Number} value2 value 2.\n * @param {Function} callback The callback function after completion.\n * @param {Number} .total The total value.\n * @param {Wb.Window} .win The edit window.\n */\n add(value1, value2, callback) {\n app.number1.value = value1;\n app.number2.value = value2;\n app.callback = callback;\n app.window1.show();\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "Perform add", "layout": "grid1", "visible": "true", "resetDialog": "true", "closeAction": "destroy" }, "events": { "ok": "app.callback(app.number1.value + app.number2.value, this);" }, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "This window from common-window.xwl" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "required": "true", "text": "Value1" } }, { "_icon": "number-edit", "text": "number2", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "number2", "required": "true", "text": "Value2" } } ] }, { "_icon": "window", "text": "thisWinAutoDestroyedAfterWindow1Destroyed", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "thisWinAutoDestroyedAfterWindow1Destroyed" } } ] } # example/load/client-load-module/panel.xwl Title: panel ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "panel", "text": "main", "cls": "Wb.Panel", "_expanded": true, "properties": { "cid": "main", "layout": "grid1", "title": "This panel from panel.xwl", "closable": "true" }, "items": [ { "_icon": "label", "text": "descLabel", "cls": "Wb.Label", "_expanded": false, "properties": { "cid": "descLabel", "text": "The component which cid is \"main\" represents the owner of the entire module, and when the main component is destroyed, the entire module will be destroyed." } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "title": "Form" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Text" }, "_expanded": true }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "text": "Number" } } ] }, { "_icon": "window", "text": "thisWinAutoDestroyedAfterMainDestroyed", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "thisWinAutoDestroyedAfterMainDestroyed" } } ] } # example/load/client-load-module/single-window.xwl Title: single-window ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Execute every time when this module is loaded, regardless of whether singleton or not. @priv\n */\n onLoad() {\n app.number3.value = Wb.random(100);\n },\n /** @property {Function} callback The callback function. @priv */\n /**\n * Perform add.\n * @param {Number} value1 value 1.\n * @param {Number} value2 value 2.\n * @param {Function} callback The callback function after completion.\n * @param {Number} .total The total value.\n * @param {Wb.Window} .win The edit window.\n */\n add(value1, value2, callback) {\n app.number1.value = value1;\n app.number2.value = value2;\n app.callback = callback;\n app.window1.show();\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "Perform add", "layout": "grid1", "visible": "true", "resetDialog": "true" }, "events": { "ok": "app.callback(app.number1.value + app.number2.value + app.number3.value, this);" }, "items": [ { "_icon": "label", "text": "label1", "cls": "Wb.Label", "_expanded": true, "properties": { "cid": "label1", "text": "This window from single-window.xwl" } }, { "_icon": "number-edit", "text": "number1", "cls": "Wb.Number", "properties": { "cid": "number1", "required": "true", "text": "Value1" } }, { "_icon": "number-edit", "text": "number2", "cls": "Wb.Number", "_expanded": true, "properties": { "cid": "number2", "required": "true", "text": "Value2" } }, { "_icon": "number-edit", "text": "number3", "cls": "Wb.Number", "_expanded": false, "properties": { "cid": "number3", "required": "true", "text": "Value3" } } ] } ] } # example/load/client-load-module.xwl Title: client-load-module ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Client load module, js, mjs and css", "cls": "w-title3" } }, { "_icon": "title", "text": "openModuleTitle", "cls": "Wb.Title", "properties": { "cid": "openModuleTitle", "title": "Open module" } }, { "_icon": "label", "text": "openModuleLabel", "cls": "Wb.Label", "properties": { "cid": "openModuleLabel", "text": "Open module in \"main tab\" or new window." } }, { "_icon": "button", "text": "openModuleBtn", "cls": "Wb.Button", "properties": { "cid": "openModuleBtn", "text": "Open module", "type": "primary" }, "events": { "click": "//equals to: Wb.run({ url: 'm?xwl=admin/role', container: Globals.WbMainTab, title: 'custom title', icon: 'gear' });\nWb.open('m?xwl=admin/role');" } }, { "_icon": "title", "text": "openNormalModuleTitle", "cls": "Wb.Title", "properties": { "cid": "openNormalModuleTitle", "title": "Open module as \"normal type\"" } }, { "_icon": "label", "text": "openNormalModuleLabel", "cls": "Wb.Label", "properties": { "cid": "openNormalModuleLabel", "text": "Open module in \"main tab\" or new window, and allow the page to reload/refresh." } }, { "_icon": "button", "text": "openNormalModuleBtn", "cls": "Wb.Button", "properties": { "cid": "openNormalModuleBtn", "text": "Open module as \"normal type\"", "type": "primary" }, "events": { "click": "//equals to: Wb.run({ url: 'm?xwl=admin/perm', container: Globals.WbMainTab, allowRefresh: true });\nWb.openNormal('m?xwl=admin/perm');" } }, { "_icon": "title", "text": "runModulePanelTitle", "cls": "Wb.Title", "properties": { "cid": "runModulePanelTitle", "title": "Run module and get panel" } }, { "_icon": "label", "text": "runModulePanelLabel", "cls": "Wb.Label", "properties": { "cid": "runModulePanelLabel", "text": "Run module and get it's content to the container." } }, { "_icon": "button", "text": "runModulePanelBtn", "cls": "Wb.Button", "properties": { "cid": "runModulePanelBtn", "text": "Run module", "type": "primary" }, "events": { "click": "let ct = app.runModulePanelCt;\nct.destroyAll();\nWb.run({\n url: xpath + '/panel',\n success(scope) {\n ct.add(scope.main);\n }\n});" } }, { "_icon": "container", "text": "runModulePanelCt", "cls": "Wb.Container", "properties": { "cid": "runModulePanelCt", "frame": "true", "minHeight": "10em" } }, { "_icon": "title", "text": "runModuleCardTitle", "cls": "Wb.Title", "properties": { "cid": "runModuleCardTitle", "title": "Run module and get tab card" }, "_expanded": true }, { "_icon": "label", "text": "runModuleCardLabel", "cls": "Wb.Label", "properties": { "cid": "runModuleCardLabel", "text": "Run module and get it's content to the new tab card." } }, { "_icon": "button", "text": "runModuleCardBtn", "cls": "Wb.Button", "properties": { "cid": "runModuleCardBtn", "text": "Run module", "type": "primary" }, "events": { "click": "let card;\n\napp.cardIndex ??= 1;\ncard = app.runModuleCardTab.add({ title: 'Card ' + app.cardIndex++, icon: 'card', layout: 'fit' }).show();\nWb.run({\n url: xpath + '/card',\n app, // pass app as parentApp, the sub module can be referred to the parent module\n owner: card, // pass card as owner of module card.xwl, when the card is destroyed, the module will be automatically destroyed\n cached: true, // store the module to the cache, enables the next request to fetch directly from the cache\n success(scope) {\n card.add(scope.panel1);\n scope.init(); // call init function defined in card.xwl\n //app.cardModule = scope; // save scope to app for further access, eg: app.cardModule.text1 = 'abc';\n }\n});" } }, { "_icon": "tab", "text": "runModuleCardTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "runModuleCardTab", "minHeight": "10em", "frame": "true" } }, { "_icon": "title", "text": "invokeWindowTitle", "cls": "Wb.Title", "properties": { "cid": "invokeWindowTitle", "title": "Invoke window" }, "_expanded": true }, { "_icon": "label", "text": "invokeWindowLabel", "cls": "Wb.Label", "properties": { "cid": "invokeWindowLabel", "text": "Invoke a common window and pass callback function as parameter." } }, { "_icon": "button", "text": "invokeWindowBtn", "cls": "Wb.Button", "properties": { "cid": "invokeWindowBtn", "text": "Invoke window", "type": "primary" }, "events": { "click": "Wb.run({\n url: xpath + '/common-window',\n owner: 'window1', //destroy the module when window1 is destroyed\n success(scope) {\n scope.add(3, 5, (total, win) => {\n Wb.tip('Total value is: ' + total);\n win.close();\n });\n }\n});" } }, { "_icon": "title", "text": "invokeSingleModuleTitle", "cls": "Wb.Title", "properties": { "cid": "invokeSingleModuleTitle", "title": "Invoke single module" }, "_expanded": true }, { "_icon": "label", "text": "invokeSingleModuleLabel", "cls": "Wb.Label", "properties": { "cid": "invokeSingleModuleLabel", "text": "Invoke a single module and pass callback function as parameter." } }, { "_icon": "button", "text": "invokeSingleBtn", "cls": "Wb.Button", "properties": { "cid": "invokeSingleBtn", "text": "Invoke single module", "type": "primary" }, "events": { "click": "Wb.run({\n url: xpath + '/single-window',\n single: true, //single instance module\n success(scope) {\n scope.add(3, 5, (total, win) => {\n Wb.tip('Total value is: ' + total);\n win.close();\n });\n }\n});" } }, { "_icon": "title", "text": "dynamicLoadJsCssTitle", "cls": "Wb.Title", "properties": { "cid": "dynamicLoadJsCssTitle", "title": "Dynamic load js/css" } }, { "_icon": "label", "text": "dynamicLoadJsCssLabel", "cls": "Wb.Label", "properties": { "cid": "dynamicLoadJsCssLabel", "text": "Use [Wb.load] method to dynamic load js/css resources. Set the [links] property of the module node to static load js/mjs/css resources, you can drag js/mjs/css files to the [links] property directly." } }, { "_icon": "button", "text": "dynamicLoadJsCssBtn", "cls": "Wb.Button", "properties": { "cid": "dynamicLoadJsCssBtn", "text": "Dynamic load JS/CSS", "type": "primary" }, "events": { "click": "Wb.load(\n ['wb/css/demo.css', { url: 'wb/libs/echarts.js', async: true }],\n f => Wb.tipSucc('The js/css resources has been successfully loaded.')\n);\n// Promise style\n// Wb.loadx(['wb/css/demo.css', { url: 'wb/libs/echarts.js', async: true }]).then(\n// f => Wb.tipSucc('The js/css resources has been successfully loaded.'));" } }, { "_icon": "label", "text": "importMJSLabel", "cls": "Wb.Label", "properties": { "cid": "importMJSLabel", "text": "Dynamic import Javascript module." } }, { "_icon": "button", "text": "importMJSBtn", "cls": "Wb.Button", "properties": { "cid": "importMJSBtn", "text": "Dynamic import mjs", "type": "primary" }, "events": { "click": "// Resources in the module directory are protected except for path containing the \"$\" character\nWb.loadModule(xpath + '/demo$', module => Wb.tip('The result is: ' + module.Demo.add(3, 4)));" } } ] } ] } # example/load/client-request/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Process get request.\n */\n get() {\n Wb.log(Wb.get('string'));\n Wb.log(Params.string);\n Wb.log(Wb.getInt('int')); //Params.int is string type\n Wb.log(Wb.getFloat('float'));\n Wb.log(Wb.getDate('date'));\n Wb.log(Wb.getBool('bool'));\n Wb.log(Wb.getObject('object'));\n Wb.log(Wb.getObject('array'));\n Wb.send('done');\n },\n /**\n * Process post request.\n */\n post() {\n let val = Wb.get('foo');\n //For the processing of uploading files, please refer to [file-updownload] example\n Wb.send(val);\n },\n /**\n * Process object.\n */\n deserializeObject() {\n //The system will automatically deserialize the values sent by the client\n Wb.log(Wb.get('string')); // same as Params.string\n Wb.log(Wb.get('int')); // Params.int is Number type\n Wb.log(Params.float); // Params.float is Number type\n Wb.log(Params.date); // Params.date is Date type\n Wb.log(Params.bool); // Params.bool is Boolean type\n Wb.log(Params.object);// Params.object is Object type\n Wb.log(Params.array);// Params.array is Array type\n },\n /**\n * Process multiple same parameters.\n */\n postMultipleParams() {\n let arrayList = Wb.getParams('myParam');\n Wb.log(Wb.encode(arrayList)); //Use Wb.getParams to always return array like params\n },\n /**\n * Process payload data.\n */\n postPayload() {\n Wb.log(Wb.payload);\n },\n /**\n * Process payload json.\n */\n postPayloadJson() {\n Wb.log(Wb.get('foo') + ',' + Params.bar);\n Wb.log(Wb.payload); // text\n Wb.log(Wb.payloadParams); // json\n },\n /**\n * Process submit.\n */\n postSubmit() {\n Wb.invoke('docs');\n }\n};\nactions[Params.xaction]();" }, "_icon": "module", "items": [] } # example/load/client-request.xwl Title: client-request ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Client side web request", "cls": "w-title3" } }, { "_icon": "title", "text": "getTitle", "cls": "Wb.Title", "properties": { "cid": "getTitle", "title": "Send GET request with parameters." } }, { "_icon": "button", "text": "getBtn", "cls": "Wb.Button", "properties": { "cid": "getBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=get',\n params: { string: 'abc', int: 123, float: 123.4, date: new Date(), bool: true, object: { foo: 'bar' }, array: [1, 2, 3] },\n method: 'GET',\n success(resp) {\n Wb.tipSucc(resp);\n }\n});" } }, { "_icon": "title", "text": "postTitle", "cls": "Wb.Title", "properties": { "cid": "postTitle", "title": "Send POST request with parameters, files and blobs." } }, { "_icon": "button", "text": "postBtn", "cls": "Wb.Button", "properties": { "cid": "postBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=post',\n // form: myHTMLForm,\n // comps: [app.panel1, app.fileInput1],\n // params: Wb.apply({ foo: 'bar' }, Wb.getValue(app.viewport1)),\n params: { foo: 'bar' },\n success(resp) {\n Wb.tipSucc(resp);\n }\n});" } }, { "_icon": "title", "text": "useFormTitle", "cls": "Wb.Title", "properties": { "cid": "useFormTitle", "title": "Send POST request with large parameters" } }, { "_icon": "button", "text": "useFormPostBtn", "cls": "Wb.Button", "properties": { "cid": "useFormPostBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=post',\n // Use multipart/form-data to support large parameter values,\n // otherwise will result in failure, because application/x-www-form-urlencoded has length restrictions\n form: true,\n params: { foo: 'large text...' },\n success(resp) {\n Wb.tipSucc(resp);\n }\n});" } }, { "_icon": "title", "text": "deserializeObjectTitle", "cls": "Wb.Title", "properties": { "cid": "deserializeObjectTitle", "title": "Send request using object" } }, { "_icon": "label", "text": "deserializeObjectLabel", "cls": "Wb.Label", "properties": { "cid": "deserializeObjectLabel", "text": "It can serialize object before sending and auto deserialize all original values on the server side." } }, { "_icon": "button", "text": "deserializeObjectBtn", "cls": "Wb.Button", "properties": { "cid": "deserializeObjectBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=deserializeObject',\n object: { string: 'abc', int: 123, float: 123.4, date: new Date(), bool: true, object: { foo: 'bar' }, array: [1, 2, 3] },\n success() {\n Wb.tipDone();\n }\n});" } }, { "_icon": "title", "text": "postMultipleTitle", "cls": "Wb.Title", "properties": { "cid": "postMultipleTitle", "title": "Post multiple parameters with the same name" } }, { "_icon": "button", "text": "postMultipleBtn", "cls": "Wb.Button", "properties": { "cid": "postMultipleBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postMultipleParams',\n params: { myParam: Wb.markParams([1, 'abc', new Date()]) },\n success() {\n Wb.tipDone();\n }\n});" } }, { "_icon": "title", "text": "postPayloadDataTitle", "cls": "Wb.Title", "properties": { "cid": "postPayloadDataTitle", "title": "Send request with payload data and specific header" } }, { "_icon": "button", "text": "postPayloadDataBtn", "cls": "Wb.Button", "properties": { "cid": "postPayloadDataBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postPayload',\n data: 'large text...',\n header: { 'Content-Type': 'text/html;charset=utf-8' },\n success() {\n Wb.tipDone();\n }\n});" } }, { "_icon": "title", "text": "postPayloadJsonTitle", "cls": "Wb.Title", "properties": { "cid": "postPayloadJsonTitle", "title": "Send request with payload json data" } }, { "_icon": "button", "text": "postPayloadJsonBtn", "cls": "Wb.Button", "properties": { "cid": "postPayloadJsonBtn", "text": "Send request", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postPayloadJson',\n data: { foo: 'abc', bar: 123 },\n success() {\n Wb.tipDone();\n }\n});" } }, { "_icon": "title", "text": "submitTitle", "cls": "Wb.Title", "properties": { "cid": "submitTitle", "title": "Submit a regular HTTP request" } }, { "_icon": "button", "text": "submitBtn", "cls": "Wb.Button", "properties": { "cid": "submitBtn", "text": "Regular submit", "type": "primary" }, "events": { "click": "Wb.submit(xpath + '/actions&xaction=postSubmit', { foo: 'abc', bar: 123 });" } }, { "_icon": "title", "text": "browseTitle", "cls": "Wb.Title", "properties": { "cid": "browseTitle", "title": "Browse url" } }, { "_icon": "button", "text": "browseBtn", "cls": "Wb.Button", "properties": { "cid": "browseBtn", "text": "Browse url", "type": "primary" }, "events": { "click": "Wb.browse({ url: 'https://www.geejing.com', title: 'Geejing', icon: 'earth', params: { foo: 'abc', bar: 123 } });" } }, { "_icon": "title", "text": "openWinTitle", "cls": "Wb.Title", "properties": { "cid": "openWinTitle", "title": "Open window" } }, { "_icon": "button", "text": "openWinBtn", "cls": "Wb.Button", "properties": { "cid": "openWinBtn", "text": "Open window", "type": "primary" }, "events": { "click": "Wb.openWin('https://www.geejing.com');\n//Wb.openWin({url: 'dbe', params: {foo: 'bar'}, method: 'POST'});" } } ] } ] } # example/load/code-static-load.xwl Title: code-static-load ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.set({ user: Wb.encode(Wb.execute('user')), dbe: Wb.encode(Wb.execute('admin/dbe')) });" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "events": { "ready": "// add user client\nWb.run({\n script: _$user$_, success(scope) {\n app.container1.add(scope.viewport1);\n }\n});\n// add dbe client\nWb.run({\n script: _$dbe$_, success(scope) {\n app.container2.add(scope.viewport1);\n }\n});" }, "_expanded": true, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "fit", "width": "50%" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "container", "text": "container2", "cls": "Wb.Container", "properties": { "cid": "container2", "layout": "fit", "flex": "1" } } ] } ] } # example/load/file-updownload/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Upload file.\n */\n upload() {\n let singleFile, multiFiles;\n\n singleFile = Params.singleFileInput;// same as Wb.get('singleFileInput');\n //if singleFileInput uploaded\n if (singleFile) {\n Wb.log(singleFile.name + ' file size is: ' + singleFile.size);\n //This example outputs the uploaded stream to a file, which you can also output to a database.\n new Wb.File(true, 'temp/' + singleFile.name).stream = singleFile.stream;\n }\n\n //Whether uploading a single or multiple files, using getParams will result in an array like parameter list\n multiFiles = Wb.getParams('multiFileInput');\n multiFiles.forEach(file => {\n Wb.log(file.name + ' file size is: ' + file.size);\n new Wb.File(true, 'temp/' + file.name).stream = file.stream;\n });\n\n Wb.log('text1 value is: ' + Params.text1);\n\n Wb.send(Base.pathText + 'temp');\n //All streams will be automatically closed\n },\n /**\n * Download wb.js file.\n */\n downloadWbJs() {\n Wb.exportData(new Wb.File(true, 'wb/js/wb.js'));\n },\n /**\n * Download a database blob.\n */\n downloadBlob() {\n let row = Wb.getRow({ sql: \"select full_name, photo from wb_staff where sid='0040CCVTQ71JG'\", blob: true });\n\n // row.photo is ByteArrayInputStream, no need to close\n // row.photo.available is blob size, notify the client the length of the blob to display the download progress on the client\n Wb.exportData(row.photo, row.full_name + '.png', row.photo.available())\n },\n /**\n * Download a zipped css folder file.\n */\n downloadZip() {\n Wb.setContentType('css.zip');\n ZipUtil.zip([new File(Base.path, 'wb/css')], response.getOutputStream());\n },\n /**\n * Download after upload.\n */\n downloadAfterUpload() {\n let multiFiles = Wb.getParams('multiFileInput');\n multiFiles.forEach(file => {\n Wb.log(file.name + ' file size is: ' + file.size);\n new Wb.File(true, 'temp/' + file.name).stream = file.stream;\n });\n Wb.exportData(new Wb.File(true, 'wb/js/wb.js'));\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/load/file-updownload.xwl Title: file-updownload ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "File upload & download", "cls": "w-title3" } }, { "_icon": "title", "text": "uploadTitle", "cls": "Wb.Title", "properties": { "cid": "uploadTitle", "title": "Upload files" } }, { "_icon": "container", "text": "uploadCt", "cls": "Wb.Container", "properties": { "cid": "uploadCt", "layout": "grid1", "frame": "true", "labelUp": "true" }, "_expanded": true, "items": [ { "_icon": "search-file", "text": "singleFileInput", "cls": "Wb.FileInput", "properties": { "cid": "singleFileInput", "text": "Please select a file" } }, { "_icon": "search-file", "text": "multiFileInput", "cls": "Wb.FileInput", "properties": { "cid": "multiFileInput", "browseMode": "true", "text": "Please select multiple files", "multiple": "true", "accept": "image/*", "browseHeight": "6em" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Other control" } }, { "_icon": "button", "text": "uploadButton", "cls": "Wb.Button", "properties": { "cid": "uploadButton", "text": "Upload all", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=upload',\n comps: app.uploadCt,\n params: { foo: 'bar' },\n // params: Wb.getValue(app.uploadCt), // same as comps property\n success(resp) {\n Wb.tipSucc('All files have been saved to \"' + resp + '\".');\n }\n});\n\n//Please also refer to Wb.fetch the promise version of wb.ajax" } } ] }, { "_icon": "title", "text": "downloadTitle", "cls": "Wb.Title", "properties": { "cid": "downloadTitle", "title": "Download files" }, "_expanded": true }, { "_icon": "container", "text": "downloadCt", "cls": "Wb.Container", "properties": { "cid": "downloadCt", "layout": "grid1", "frame": "true" }, "_expanded": true, "items": [ { "_icon": "button", "text": "commonDownloadWbJsButton", "cls": "Wb.Button", "properties": { "cid": "commonDownloadWbJsButton", "text": "Common download wb.js", "type": "primary" }, "events": { "click": "//Using Wb.download is the recommended method for downloading\nWb.download(xpath + '/actions&xaction=downloadWbJs', { foo: 'bar' });" } }, { "_icon": "button", "text": "ajaxDownloadWbJsButton", "cls": "Wb.Button", "properties": { "cid": "ajaxDownloadWbJsButton", "text": "Ajax download wb.js", "type": "primary" }, "events": { "click": "//Using Wb.ajax is usually not a recommended method for downloading, please use Wb.download instead\nWb.ajax({\n url: xpath + '/actions&xaction=downloadWbJs',\n download: true,\n params: { foo: 'bar' },\n onDownload(percent) {\n Wb.progress(percent);\n }\n});" } }, { "_icon": "button", "text": "downloadBlobButton", "cls": "Wb.Button", "properties": { "cid": "downloadBlobButton", "text": "Download blob", "type": "primary" }, "events": { "click": "Wb.download(xpath + '/actions&xaction=downloadBlob');" } }, { "_icon": "button", "text": "downloadZipButton", "cls": "Wb.Button", "properties": { "cid": "downloadZipButton", "text": "Download zip", "type": "primary" }, "events": { "click": "Wb.download(xpath + '/actions&xaction=downloadZip');" } }, { "_icon": "button", "text": "downloadBase64BlobButton", "cls": "Wb.Button", "properties": { "cid": "downloadBase64BlobButton", "text": "Download base64/blob", "type": "primary" }, "events": { "click": "let base64Text = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAJlJREFUOE/FkjsOgzAQBWfLEOUIqbgInCrQmQpuFXMmFNpFJiTCfCIMSHG9nn1vtMLBJwf/0wNeJWYP6JpjekBb8QSSEIgqxXmApgzb/kl6y7GeRFclykhDqkwBGmVvsSM3izxVas+BCHdVYsC6Hy5JW6FraTyJo43TBKsAEczlQfGzwhYX51zi/w9pSLCl8ndGBDuTGEQYhjv9pkQRnIOeTgAAAABJRU5ErkJggg==';\nWb.downloadBase64(base64Text, 'insert.png');\n//Wb.downloadBlob(fileOrBlob, 'myFile.dat');" } } ] }, { "_icon": "title", "text": "downloadAfterUploadingTitle", "cls": "Wb.Title", "properties": { "cid": "downloadAfterUploadingTitle", "title": "Download after uploading" } }, { "_icon": "container", "text": "downloadAfterUploadingCt", "cls": "Wb.Container", "properties": { "cid": "downloadAfterUploadingCt", "layout": "grid1", "frame": "true", "labelUp": "true" }, "_expanded": true, "items": [ { "_icon": "search-file", "text": "multiFileInput", "cls": "Wb.FileInput", "properties": { "cid": "multiFileInput", "browseMode": "true", "text": "Please select multiple files", "multiple": "true", "accept": "image/*", "browseHeight": "6em" } }, { "_icon": "text", "text": "text1", "cls": "Wb.Text", "properties": { "cid": "text1", "text": "Other control" } }, { "_icon": "button", "text": "downloadAfterUploadButton", "cls": "Wb.Button", "properties": { "cid": "downloadAfterUploadButton", "text": "Download after upload", "type": "primary" }, "events": { "click": "const uploading = 'Uploading now, please wait...';\nconst downloading = 'Downloading now, please wait...';\n\nWb.ajax({\n url: xpath + '/actions&xaction=downloadAfterUpload',\n comps: app.downloadAfterUploadingCt,\n download: true,\n params: { foo: 'bar' },\n mask: uploading, //let the default mask is \"uploading\"\n onUpload(percent) {\n Wb.progress(percent, uploading);\n },\n onDownload(percent) {\n Wb.progress(percent, downloading);\n },\n callback() {\n Wb.unmask(downloading);\n }\n});" } } ] } ] } ] } # example/load/server-load-module/execute.xwl Title: execute ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Load a javascript library.\n */\n loadJs() {\n let result;\n\n Wb.load('./util.js');\n result = My.Util.add(Wb.getInt('value1'), Wb.getInt('value2'));\n Wb.send(result);\n },\n /**\n * Synchronous load a javascript module.\n */\n loadMjs() {\n let result, Util = Wb.load('./util.mjs');\n\n result = Util.add(Wb.getInt('value1'), Wb.getInt('value2'));\n Wb.send(result);\n },\n /**\n * Asynchronous import a javascript module. This method is not recommended, please use Wb.load instead.\n */\n importMjs() {\n import('wb/modules/example/load/server-load-module/util.mjs').then(m => {\n let result = m.default.add(Wb.getInt('value1'), Wb.getInt('value2'));\n Wb.send(result);\n }).catch(e => {\n Wb.error(e?.toString());\n });\n },\n /**\n * Run a xwl module serverscript function.\n */\n runXwl() {\n let result;\n\n Wb.run('./util.xwl');\n result = app.add(Wb.getInt('value1'), Wb.getInt('value2'));\n Wb.send(result);\n },\n /**\n * Invoke a xwl module execute serverscript and obtain client script.\n */\n invokeXwl() {\n let script = Wb.execute('./query');\n Wb.send(script);\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/load/server-load-module/query.xwl Title: query ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.sendRows('select * from wb_staff');" }, "_icon": "module" } # example/load/server-load-module/util.xwl Title: util ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.apply(app, {\n /**\n * Perform add.\n * @param {Number} value1 Value 1\n * @param {Number} value2 Value 2\n * @return {Number} The result\n */\n add(value1, value2) {\n return value1 + value2;\n }\n});\nWb.log('Util.xwl runs every time.');" }, "_icon": "module" } # example/load/server-load-module.xwl Title: server-load-module ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Server load module, js and mjs", "cls": "w-title3" } }, { "_icon": "title", "text": "runModuleTitle", "cls": "Wb.Title", "properties": { "cid": "runModuleTitle", "title": "Run module" } }, { "_icon": "label", "text": "runModuleLabel", "cls": "Wb.Label", "properties": { "cid": "runModuleLabel", "text": "Run the module at serverside and call function of the module." } }, { "_icon": "button", "text": "runModuleBtn", "cls": "Wb.Button", "properties": { "cid": "runModuleBtn", "text": "Run module", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/execute&xaction=runXwl',\n params: { value1: 12, value2: 34 },\n success(resp) {\n Wb.tip('The result is ' + resp);\n }\n});" } }, { "_icon": "title", "text": "invokeModuleTitle", "cls": "Wb.Title", "properties": { "cid": "invokeModuleTitle", "title": "Invoke module" } }, { "_icon": "label", "text": "InvokeModuleLabel", "cls": "Wb.Label", "properties": { "cid": "InvokeModuleLabel", "text": "Call the module and obtain the HTML or script returned by the module." } }, { "_icon": "button", "text": "invokeModuleBtn", "cls": "Wb.Button", "properties": { "cid": "invokeModuleBtn", "text": "Invoke module", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/execute&xaction=invokeXwl',\n success(resp) {\n app.invokeModuleViewer.text = resp;\n console.table(Wb.decode(resp));\n }\n});" } }, { "_icon": "desktop", "text": "invokeModuleViewer", "cls": "Wb.Viewer", "properties": { "cid": "invokeModuleViewer", "height": "10em" } }, { "_icon": "title", "text": "loadJSTitle", "cls": "Wb.Title", "properties": { "cid": "loadJSTitle", "title": "Load Javascript" } }, { "_icon": "label", "text": "loadJSLabel", "cls": "Wb.Label", "properties": { "cid": "loadJSLabel", "text": "Load Javascript library at serverside." } }, { "_icon": "button", "text": "loadJSBtn", "cls": "Wb.Button", "properties": { "cid": "loadJSBtn", "text": "Load js", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/execute&xaction=loadJs',\n params: { value1: 12, value2: 34 },\n success(resp) {\n Wb.tip('The result is ' + resp);\n }\n});" } }, { "_icon": "title", "text": "loadMJSTitle", "cls": "Wb.Title", "properties": { "cid": "loadMJSTitle", "title": "Load mjs" } }, { "_icon": "label", "text": "loadMJSLabel", "cls": "Wb.Label", "properties": { "cid": "loadMJSLabel", "text": "Load Javascript module at serverside by Wb.load(recommended)." } }, { "_icon": "button", "text": "loadMJSBtn", "cls": "Wb.Button", "properties": { "cid": "loadMJSBtn", "text": "Load mjs", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/execute&xaction=loadMjs',\n params: { value1: 12, value2: 34 },\n success(resp) {\n Wb.tip('The result is ' + resp);\n }\n});" } }, { "_icon": "label", "text": "importMJSLabel", "cls": "Wb.Label", "properties": { "cid": "importMJSLabel", "text": "Import Javascript module at serverside by import(not recommended)." } }, { "_icon": "button", "text": "importMJSBtn", "cls": "Wb.Button", "properties": { "cid": "importMJSBtn", "text": "Import mjs", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/execute&xaction=importMjs',\n params: { value1: 12, value2: 34 },\n success(resp) {\n Wb.tip('The result is ' + resp);\n }\n});" } } ] } ] } # example/load/server-request/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Send get request.\n */\n getHtml() {\n Wb.send(Wb.submit('https://developer.mozilla.org'));\n },\n /**\n * Send post request with params.\n */\n postParams() {\n // For reference\n // Wb.submit({ url: 'http://localhost:8080/wb/m?xwl=test2', params: { foo: 'bar' } });\n },\n /**\n * Send post request with payload data.\n */\n postPayload() {\n // For reference\n // Wb.submit({ url: 'http://localhost:8080/wb/m?xwl=test2', data: payloadObject });\n },\n /**\n * Send post request with files.\n */\n postFiles() {\n // Wb.submit({\n // url: 'http://localhost:8080/wb/m?xwl=test2',\n // params: {\n // foo: 'bar', 'wb.js': new Wb.File(true, 'wb/js/wb.js'), file: javaFile,\n // myBytes: bytes, 'name|filename.dat': inputStream\n // }\n // });\n },\n /**\n * Login to the system, verify the username and password, and get the cookie token.\n */\n loginAndLogout() {\n // For reference\n /*\n let cookie = Wb.submit({\n url: 'http://localhost:8080/wb/verify', all: true, params: { username: 'admin', password: 'admin' }\n }).cookie;\n //Access module1 with logined cookie token\n let result = Wb.submit({ url: 'http://localhost:8080/wb/m?xwl=module1', cookie }, { foo: 'bar' });\n //Logout\n Wb.submit({ url: 'http://localhost:8080/wb/logout', cookie });\n */\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/load/server-request.xwl Title: server-request ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "Server side web request", "cls": "w-title3" } }, { "_icon": "title", "text": "getHtmlTitle", "cls": "Wb.Title", "properties": { "cid": "getHtmlTitle", "title": "Get mozilla.org site html" } }, { "_icon": "desktop", "text": "htmlSourceViewer", "cls": "Wb.Viewer", "properties": { "cid": "htmlSourceViewer", "height": "8em" } }, { "_icon": "button", "text": "getHtmlBtn", "cls": "Wb.Button", "properties": { "cid": "getHtmlBtn", "text": "Get html", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=getHtml',\n success(resp) {\n app.htmlSourceViewer.text = resp;\n }\n});" } }, { "_icon": "title", "text": "postParamsTitle", "cls": "Wb.Title", "properties": { "cid": "postParamsTitle", "title": "Send post request with params" } }, { "_icon": "button", "text": "postParamsBtn", "cls": "Wb.Button", "properties": { "cid": "postParamsBtn", "text": "Post params", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postParams',\n success(resp) {\n Wb.tipDone();\n }\n});" }, "_expanded": true }, { "_icon": "title", "text": "postPayloadDataTitle", "cls": "Wb.Title", "properties": { "cid": "postPayloadDataTitle", "title": "Send post request with payload data" } }, { "_icon": "button", "text": "postPayloadDataBtn", "cls": "Wb.Button", "properties": { "cid": "postPayloadDataBtn", "text": "Post payload data", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postPayload',\n success(resp) {\n Wb.tipDone();\n }\n});" } }, { "_icon": "title", "text": "postFileTitle", "cls": "Wb.Title", "properties": { "cid": "postFileTitle", "title": "Send post request with files" } }, { "_icon": "button", "text": "postFilesBtn", "cls": "Wb.Button", "properties": { "cid": "postFilesBtn", "text": "Post files", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=postFiles',\n success(resp) {\n Wb.tipDone();\n }\n});" }, "_expanded": true }, { "_icon": "title", "text": "loginTitle", "cls": "Wb.Title", "properties": { "cid": "loginTitle", "title": "Login to the system, access modules and logout." } }, { "_icon": "button", "text": "loginAccessBtn", "cls": "Wb.Button", "properties": { "cid": "loginAccessBtn", "text": "Login and Access", "type": "primary" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=loginAndLogout',\n success(resp) {\n Wb.tipDone();\n }\n});" } } ] } ] } # example/load/switch-module.xwl Title: switch-module ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.invoke(Params.type == 'someType' ? 'admin/user' : 'dbe');" }, "_icon": "module" } # example/load/xwl-static-load.xwl Title: xwl-static-load ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/js/monaco.js\"\n]", "description": "Please note that since the xwl module can be recursively loaded,\nits dependent js/css resources need to be explicitly loaded in the module's links property" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "row" }, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "fit", "width": "50%" }, "_expanded": true, "items": [ { "_icon": "module", "text": "userXwl", "cls": "Wb.Xwl", "properties": { "cid": "userXwl", "path": "admin/user.xwl", "ready": "// parentApp in user.xwl is app of this module\n// parentContainer in user.xwl is Wb.Container of the user.xwl wrapper\nscope.viewport1.title = 'User Module'; // same as app.userXwl.viewport1.title = 'User Module';\ncontainer.border = 1;", "container": "({ padding: '.5em' })" } } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" }, "_expanded": true }, { "_icon": "container", "text": "container2", "cls": "Wb.Container", "properties": { "cid": "container2", "layout": "fit", "flex": "1" }, "_expanded": true, "items": [ { "_icon": "module", "text": "dbeXwl", "cls": "Wb.Xwl", "properties": { "cid": "dbeXwl", "path": "admin/dbe.xwl", "ready": "scope.viewport1.title = 'DBE Module';\ncontainer.border = 1;", "container": "({ padding: '.5em' })" } } ] } ] } ] } # example/tools/excel-form/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Select data.\n */\n select() {\n Wb.sendDict('select * from wb_staff', 'wb,');\n },\n /**\n * Get form.\n */\n getForm() {\n Wb.send(Wb.getExcelHtml('form.xlsx', { now: new Date().dateText }));\n },\n /**\n * Export data.\n */\n export() {\n let data = Wb.getObject('data');\n data.gender = data.gender$; // display text\n Wb.getExcelFile('my-form.xlsx', 'form.xlsx', data);\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/tools/excel-form.xwl Title: excel-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Fire after module is loaded.\n */\n onLoad() {\n Wb.ajax({\n url: xpath + '/actions&xaction=getForm',\n success(resp) {\n app.container1.html = resp;\n Wb.setValue(app.container1, { name: 'Your name', code: '10000' });\n }\n });\n }\n});" }, "_expanded": true, "items": [ { "_icon": "array", "text": "bindComps", "cls": "Wb.Array", "properties": { "cid": "bindComps" }, "_expanded": true, "items": [ { "_icon": "text", "text": "name", "cls": "Wb.Text", "properties": { "cid": "name", "required": "true", "instanced": "false" } }, { "_icon": "text", "text": "nation", "cls": "Wb.Text", "properties": { "cid": "nation", "instanced": "false" } }, { "_icon": "combo", "text": "gender", "cls": "Wb.Select", "properties": { "cid": "gender", "keyName": "gender", "instanced": "false" } }, { "_icon": "calendar", "text": "birthdate", "cls": "Wb.Date", "properties": { "cid": "birthdate", "instanced": "false" } }, { "_icon": "number-edit", "text": "height", "cls": "Wb.Number", "properties": { "cid": "height", "instanced": "false", "decimalCount": "1" } }, { "_icon": "number-edit", "text": "weight", "cls": "Wb.Number", "properties": { "cid": "weight", "instanced": "false" } }, { "_icon": "number-edit", "text": "salary", "cls": "Wb.Number", "properties": { "cid": "salary", "instanced": "false" } }, { "_icon": "text", "text": "marry", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "marry", "instanced": "false" } }, { "_icon": "text", "text": "mobile", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "mobile", "instanced": "false" } }, { "_icon": "text", "text": "email", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "email", "instanced": "false" } }, { "_icon": "text", "text": "address", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "address", "instanced": "false" } }, { "_icon": "text", "text": "contact", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "contact", "instanced": "false" } }, { "_icon": "image", "text": "photo", "cls": "Wb.Image", "properties": { "cid": "photo", "src": "wb/images/app/logo.png", "instanced": "false", "height": "140" } }, { "_icon": "text", "text": "university", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "university", "instanced": "false" } }, { "_icon": "text", "text": "grade", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "grade", "instanced": "false" } }, { "_icon": "text", "text": "speciality", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "speciality", "instanced": "false" } }, { "_icon": "text", "text": "class", "cls": "Wb.Text", "_expanded": true, "properties": { "cid": "class", "instanced": "false" } }, { "_icon": "grid", "text": "grid", "cls": "Wb.Grid", "properties": { "cid": "grid", "url": "@xpath + '/actions&xaction=select'", "instanced": "false", "height": "169" } }, { "_icon": "textarea", "text": "resume", "cls": "Wb.TextArea", "properties": { "cid": "resume", "instanced": "false", "height": "186" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "autoScroll": "true", "layout": "fit" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "exportItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "exportItem", "text": "Export", "icon": "export" }, "events": { "click": "Wb.download(xpath + '/actions&xaction=export', { data: Wb.getValue(app.container1) });" } } ] }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "middle", "autoMake": "true" } } ] } ] } # example/tools/excel-report/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Reload data.\n */\n reload() {\n let html;\n\n html = Wb.getExcelHtml('report.xlsx', this.getData(), this.getRowConfigs());\n Wb.send(html);\n },\n /**\n * Export data.\n */\n export() {\n Wb.getExcelFile('my-report.xlsx', 'report.xlsx', this.getData(), this.getRowConfigs());\n },\n /**\n * Get report data.\n * @return {Object} Report data.\n */\n getData() {\n return {\n name: 'Geejing', date: new Date().dateText, by: 'Janice Galvin', reviewer: 'Rachel Valdez',\n director: 'Annette Hill', email: 'contact@geejing.com',\n rows: Wb.getAllRows('select * from wb_report_demo1 order by row_num')\n };\n },\n /**\n * Get write rows configs. @priv\n */\n getRowConfigs() {\n // [{ name: 'rows', x: 0, y: 5, sheet: 'Sheet2', mergeRows: ['f1', 'f3'], mergeCols: [['f1', 'f2'], ['f5', 'f6']] }, more...]\n return {\n name: 'rows', x: 0, y: 5, mergeRows: 'f1', mergeCols: 'f1, f2'\n }\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/tools/excel-report.xwl Title: excel-report ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Fire after module is loaded.\n */\n onLoad() {\n app.reloadItem.fireEvent('click');\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "autoScroll": "true", "layout": "fit" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "reloadItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "reloadItem", "text": "Reload", "icon": "refresh" }, "events": { "click": "Wb.ajax({\n url: xpath + '/actions&xaction=reload',\n success(resp) {\n app.container1.html = '';\n app.container1.html = resp;\n }\n});" } }, { "_icon": "item", "text": "exportItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "exportItem", "text": "Export", "icon": "export" }, "events": { "click": "Wb.download(xpath + '/actions&xaction=export');" } }, { "_icon": "item", "text": "printItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "printItem", "text": "Print", "icon": "print" }, "events": { "click": "Wb.print(app.container1, 'A3 landscape');" } } ] }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "middle", "cls": "w-max-size /* for print centered only */" } } ] } ] } # example/tools/mail-sender/send.xwl Title: send ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let sender, attachFiles, submitFiles = [];\n\n sender = new Wb.MailSender(\n Params.smtp,\n Params.username,\n Params.password,\n Params.authUsername,\n Params.authPassword,\n { 'mail.smtp.auth': true, 'mail.smtp.sendpartial': true }\n );\n attachFiles = Wb.getParams('attachFiles');\n attachFiles.forEach(file => {\n submitFiles.push({ name: file.name, data: file.stream });\n });\n try {\n sender.send(Params.from, Params.to, Params.title, Params.content, submitFiles, Params.cc);\n } finally {\n sender.close();\n }\n}\nmain();" }, "_icon": "module" } # example/tools/mail-sender.xwl Title: mail-sender ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "title", "text": "titleComp", "cls": "Wb.Title", "properties": { "cid": "titleComp", "title": "Email Sender" } }, { "_icon": "text", "text": "smtp", "cls": "Wb.Text", "properties": { "cid": "smtp", "text": "Smtp", "required": "true", "value": "smtp.xxx.com" } }, { "_icon": "text", "text": "username", "cls": "Wb.Text", "properties": { "cid": "username", "text": "Username", "required": "true", "value": "name@xxx.com" }, "_expanded": true }, { "_icon": "text", "text": "password", "cls": "Wb.Text", "properties": { "cid": "password", "text": "Password", "required": "true", "value": "password" }, "_expanded": true }, { "_icon": "text", "text": "authUsername", "cls": "Wb.Text", "properties": { "cid": "authUsername", "text": "Auth username", "value": "name@xxx.com" }, "_expanded": true }, { "_icon": "text", "text": "authPassword", "cls": "Wb.Text", "properties": { "cid": "authPassword", "text": "Auth password", "value": "someAuthNumber" }, "_expanded": true }, { "_icon": "text", "text": "from", "cls": "Wb.Text", "properties": { "cid": "from", "text": "From", "required": "true", "value": "name@xxx.com" } }, { "_icon": "text", "text": "to", "cls": "Wb.Text", "properties": { "cid": "to", "text": "To", "required": "true", "value": "to@xxx.com" } }, { "_icon": "text", "text": "cc", "cls": "Wb.Text", "properties": { "cid": "cc", "text": "CC" } }, { "_icon": "text", "text": "title", "cls": "Wb.Text", "properties": { "cid": "title", "text": "Title" } }, { "_icon": "textarea", "text": "content", "cls": "Wb.TextArea", "properties": { "cid": "content", "text": "Mail Content", "value": "Hello world" } }, { "_icon": "search-file", "text": "attachFiles", "cls": "Wb.FileInput", "properties": { "cid": "attachFiles", "multiple": "true", "text": "Attach Files" } }, { "_icon": "button", "text": "Send", "cls": "Wb.Button", "properties": { "cid": "Send", "text": "Send", "icon": "paper-plane", "type": "primary" }, "events": { "click": "if (!Wb.verify(app.viewport1))\n return;\nWb.ajax({\n url: xpath + '/send',\n comps: app.viewport1,\n success() {\n Wb.tipSucc('The email has been successfully sent.');\n }\n});" } } ] } ] } # example/tools/sql-to-excel/create.xwl Title: create ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let bos, rowx, cols;\n\n bos = new ByteArrayOutputStream();\n rowx = Wb.getRowx({ sql: 'select * from wb_staff', rs: -1 });\n cols = rowx.columns;\n cols.shift(); // shift row num col\n cols.forEach(col => col.width = parseInt(col.width));\n com.wb.office.SheetWriter.createExcel(bos, Wb.toJava(cols), Wb.toJava(rowx.items), 0, 'Staff List', null);\n Wb.exportData(bos.toByteArray(), 'staff.xlsx');\n}\nmain();" }, "_icon": "module" } # example/tools/sql-to-excel.xwl Title: sql-to-excel ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "label", "text": "mainLabel", "cls": "Wb.Label", "properties": { "cid": "mainLabel", "text": "SQL to Excel", "cls": "w-title3" } }, { "_icon": "title", "text": "textTitle", "cls": "Wb.Title", "properties": { "cid": "textTitle", "title": "Export to Excel" } }, { "_icon": "button", "text": "downloadBtn", "cls": "Wb.Button", "properties": { "cid": "downloadBtn", "text": "Download", "type": "primary" }, "events": { "click": "Wb.download(xpath + '/create');" } } ] } ] } # example/touch/chat/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Get chats list. @priv\n */\n getChats() {\n Wb.sendRowx({\n sql: `\n select a.send_date, a.text_content, a.bin_len, b.userid, c.display_name from\n\n wb_chats a,\n\n (\n select userid, max(sid) as sid from\n (\n select sid,from_user as userid from wb_chats where to_user={?sys.userid?}\n union all\n select sid,to_user as userid from wb_chats where from_user={?sys.userid?}\n ) x\n group by userid\n ) b,\n\n wb_user c\n\n where a.sid=b.sid and b.userid=c.sid\n order by a.send_date desc\n `,\n clob: 100\n });\n },\n /**\n * Get chat detail. @priv\n */\n getChatDetail() {\n Wb.sendRows(`\n select sid,send_date,text_content,bin_len,1 as direction from wb_chats where to_user={?sys.userid?} and from_user={?userid?}\n union all\n select sid,send_date,text_content,bin_len,0 as direction from wb_chats where from_user={?sys.userid?} and to_user={?userid?}\n order by send_date desc\n `);\n },\n /**\n * Download the chat blob content. @priv\n */\n download() {\n let row = Wb.getRow({ sql: 'select bin_len,text_content,bin_content from wb_chats where sid={?id?}', blob: true });\n // for download filename purpose\n Wb.setContentType(row.text_content, null, row.bin_len);\n Wb.send(row.bin_content);\n },\n /**\n * Get contact user list. @priv\n */\n getContacts() {\n Wb.sendRowx('select sid, user_name, display_name, email from wb_user where sid<>{?sys.userid?} and status=1');\n },\n /**\n * Send message from current user to another user. @priv\n */\n sendMessage() {\n let file = Params.file, toUser = Params.userid, data;\n\n data = {\n sid: Wb.getId(),\n send_date: new Date(),\n from_user: Wb.userid,\n bin_len: file?.size,\n text_content: Params.text\n }\n Wb.sync({\n tableName: 'wb_chats',\n insert: Wb.apply({ to_user: toUser, bin_content: file?.stream }, data)\n });\n data.display_name = Wb.dispname;\n Wb.send(data, 'wb.chat', toUser);\n Wb.send(data);\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/touch/chat/user-detail.xwl Title: user-detail ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "dialog", "text": "main", "cls": "Wb.Dialog", "properties": { "cid": "main", "autoScroll": "true" }, "_expanded": true, "events": { "hidden": "this.destroy(); // remove this code if Wb.run use single mode" }, "items": [ { "_icon": "component", "text": "summaryComp", "cls": "Wb.Component", "properties": { "cid": "summaryComp", "tpl": "
\n
\n
\n
\n
{display_name}
\n
\n
\n
User name: {user_name}
\n
User id: {sid}
\n
E-mail: {email}
\n
\n
", "padding": "1em" } }, { "_icon": "line", "text": "line1", "cls": "Wb.Line", "properties": { "cid": "line1", "margin": "top" } }, { "_icon": "options", "text": "sendMsgOption", "cls": "Wb.Option", "_expanded": false, "properties": { "cid": "sendMsgOption", "text": "Send message", "icon": "message", "buttonStyle": "true" }, "events": { "click": "let chatApp = app.chatApp, data = chatApp.openUserData;\napp.main.close(true); // optional\nchatApp.openChat({ userid: data.sid, display_name: data.display_name });" } }, { "_icon": "padding", "text": "gap1", "cls": "Wb.Gap", "properties": { "cid": "gap1" } }, { "_icon": "options", "text": "noteOption", "cls": "Wb.Option", "properties": { "cid": "noteOption", "text": "Set notes and labels", "border": "bottom" }, "events": { "click": "Wb.tip(this.text);" }, "_expanded": true }, { "_icon": "options", "text": "permOption", "cls": "Wb.Option", "properties": { "cid": "permOption", "text": "Friend permissions" }, "events": { "click": "Wb.tip(this.text);" } }, { "_icon": "padding", "text": "gap2", "cls": "Wb.Gap", "properties": { "cid": "gap2" } }, { "_icon": "options", "text": "momentOption", "cls": "Wb.Option", "_expanded": true, "properties": { "cid": "momentOption", "height": "5em", "text": "Moments", "border": "bottom" }, "events": { "click": "Wb.tip(this.text);" } }, { "_icon": "options", "text": "moreOption", "cls": "Wb.Option", "_expanded": false, "properties": { "cid": "moreOption", "text": "More information" }, "events": { "click": "Wb.tip(this.text);" } }, { "_icon": "padding", "text": "gap3", "cls": "Wb.Gap", "_expanded": true, "properties": { "cid": "gap3", "flex": "1" } }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "_icon": "item", "text": "menuItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "menuItem", "icon": "menu", "plainIcon": "true" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "addItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addItem", "icon": "add", "text": "@Str.add" } }, { "_icon": "item", "text": "editItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "editItem", "icon": "edit", "text": "@Str.edit" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "delItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delItem", "icon": "delete", "text": "@Str.del" } } ] } ] } ] } ] } ] } # example/touch/chat.xwl Title: chat ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "links": "[\n \"wb/css/demo.css\"\n]" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.define(app, {\n /** @property {Array} - Cached url resource list. @priv */\n cachedUrls: [],\n /** @property {Object} chatData The user data of current chat dialog. @priv */\n /**\n * View chat details of the specific user. @priv\n * @param {Object} data The user data.\n * @param {String} .userid The user id.\n * @param {String} .display_name The user display name.\n * @param {Function} [callback] A function to be called when the chat window is displayed.\n */\n openChat(data, callback) {\n let userid = data.userid;\n Wb.ajax({\n url: xpath + '/actions&xaction=getChatDetail',\n params: { userid },\n json: true,\n success(resp) {\n let detailComp = app.detailComp, dialog = app.chatDetailDialog;\n detailComp.el.textContent = '';\n app.cachedUrls.forEach(item => URL.revokeObjectURL(item));\n app.lastChatDate = null;\n resp.each(item => {\n app.addMessage(item, false, true);\n }, true, true);\n dialog.title = data.display_name;\n dialog.setVisible(true, f => callback?.call(dialog));\n app.chatData = data;\n detailComp.dialogScrollTop ??= {};\n detailComp.el.scrollTop = detailComp?.dialogScrollTop[userid] ?? detailComp.el.scrollHeight;\n dialog.on('close', f => detailComp.dialogScrollTop[userid] = detailComp.el.scrollTop, true, { once: true });\n app.chatsView.findItem('userid', userid)?.set('badge', null);\n }\n });\n },\n /**\n * Create chat message in chat dialog. @priv\n * @param {Object} data Chat data.\n * @param {Boolean} [loadingIcon] Whether to create a loading icon.\n * @param {Boolean} [keepScrollPos] Whether to keep scroll position.\n * @return {Object} {loadingEl, textEl} object.\n */\n addMessage(data, loadingIcon, keepScrollPos) {\n let detailComp = app.detailComp, el = detailComp.el, date, wrap, textEl, loadingEl;\n\n date = data.send_date.dateValue;\n //if span > 10 min\n if (!app.lastChatDate || date.elapse(app.lastChatDate) > 600000)\n el.addEl('w-title5 w-ta-center').textContent = date.prettyText;\n wrap = el.addEl('w-row w-align-center w-gap w-margin-tb1');\n if (data.direction == 1) {\n wrap.addEl('w-icon icon-user2 w-size2');\n // you can merge all classes to one class\n app.createContent(textEl = wrap.addEl(), data);\n } else {\n wrap.cls = 'w-justify-end';\n if (loadingIcon)\n loadingEl = wrap.addEl('w-icon w-spin icon-loading w-hidden');\n app.createContent(textEl = wrap.addEl(), data);\n wrap.addEl('w-icon icon-user3 w-size2');\n }\n app.lastChatDate = date;\n if (!keepScrollPos)\n detailComp.scrollToBottom();\n return { loadingEl, textEl };\n },\n /**\n * Create message content. @priv\n * @param {Element} el The message element.\n * @param {Object} data The data to render.\n */\n createContent(el, data) {\n let text = data.text_content, size = data.bin_len, sid = data.sid;\n if (size != null) {\n if (Wb.isImageFile(text)) {\n let img = el.addEl('w-pointer', 'img'), url;\n\n if (data.file) {\n url = URL.createObjectURL(data.file);\n app.cachedUrls.push(url);\n } else {\n url = xpath + '/actions&xaction=download&id=' + sid;\n }\n img.draggable = false;\n img.src = url;\n img.height = 80;\n } else {\n let wrap = el.addEl('w-column');\n el.cls = 'w-btn w-row w-align-center w-gap2 wx-file';\n wrap.addEl('w-label').textContent = text;\n wrap.addEl('w-title5').textContent = size.fileSize;\n el.addEl('w-size2 w-icon icon-' + Wb.getFileIcon(text));\n if (sid)\n el.recordSid = sid;\n el.maxWidth = '70%';\n }\n } else {\n el.cls = data.direction == 1 ? 'w-msg1' : 'w-msg2';\n el.textContent = text;\n }\n },\n /** @property {Object} openUserData The user data of current user dialog. @priv */\n /**\n * View user details of the specific user. @priv\n * @param {Object} data The user data to open.\n */\n openUser(data) {\n // if use single mode, user-detail main dialog must not be destroyed.\n Wb.run({\n url: xpath + '/user-detail', /* single: true, */ success(scope) {\n let dialog = scope.main;\n scope.chatApp = app;\n scope.summaryComp.update(data)\n app.openUserData = data;\n dialog.show();\n dialog.el.scrollTop = 0;\n }\n });\n },\n /**\n * Send text message. @priv\n */\n sendText() {\n let textArea = app.textArea1, value = textArea.value;\n if (value.length) {\n app.doSend({ text_content: value });\n textArea.clear();\n } else {\n Wb.tipWarn('Please input text');\n textArea.focus();\n }\n },\n /**\n * Send file. @priv\n */\n sendFile() {\n Wb.selectFile(file => {\n app.doSend({ text_content: file.name, file, bin_len: file.size });\n });\n },\n /**\n * Send any data. @priv\n * @param {Object} [configs] Configs data.\n */\n doSend(configs) {\n let data = app.chatData, loadingIcon, elMap, userid = data.userid;\n\n elMap = app.addMessage(Wb.apply({\n send_date: new Date().textValue,\n direction: 2\n }, configs), true);\n loadingIcon = elMap.loadingEl;\n loadingIcon.removeCls.delay(loadingIcon, Wb.configs.maskDelay, 'w-hidden');\n Wb.ajax({\n url: xpath + '/actions&xaction=sendMessage',\n params: { userid, text: configs.text_content, file: configs.file },\n mask: false,\n json: true,\n callback(resp, xhr) {\n loadingIcon.removeCls.cancelDelay();\n if (xhr.ok)\n loadingIcon.remove();\n else\n loadingIcon.className = 'w-icon icon-error';\n elMap.textEl.recordSid = resp.sid;\n app.updateChatView({\n display_name: data.display_name,\n userid,\n send_date: resp.send_date,\n text_content: resp.text_content\n });\n }\n });\n },\n /**\n * Update chat view list when sending or receiving messages\n * @param {Object} [data] Chat view item data.\n * @param {Boolean} [incBadge] Increment badge count.\n */\n updateChatView(data, incBadge) {\n let chatItem, chatsView = app.chatsView;\n\n chatItem = chatsView.findItem('userid', data.userid) ?? new Wb.ViewItem();\n chatsView.insert(0, chatItem);\n if (incBadge)\n data.badge = Math.min(99, (chatItem.data.badge || 0) + 1);\n chatItem.update(data);\n },\n /**\n * Receive message from websocket. @priv\n */\n receiveMessage(e) {\n let data = Wb.decode(e.data);\n\n // add to chat detail dialog\n if (data.from_user == app.chatData?.userid) {\n data.direction = 1;\n app.addMessage(data);\n } else {\n app.updateChatView({\n display_name: data.display_name,\n userid: data.from_user,\n send_date: data.send_date,\n text_content: data.text_content\n }, true);\n }\n }\n});" }, "items": [ { "_icon": "plug", "text": "socket", "cls": "Wb.Socket", "properties": { "cid": "socket", "name": "wb.chat" }, "events": { "close": "if (!Wb.unloading && !Globals.WbMainTab)\n Wb.login();", "message": "app.receiveMessage(e);" } }, { "_icon": "array", "text": "templates", "cls": "Wb.Array", "properties": { "cid": "templates" }, "_expanded": true, "items": [ { "_icon": "dialog", "text": "chatDetailDialog", "cls": "Wb.Dialog", "properties": { "cid": "chatDetailDialog", "layout": "column", "background": "true", "focusControl": "false" }, "_expanded": true, "events": { "close": "app.chatData = null;" }, "items": [ { "_icon": "component", "text": "detailComp", "cls": "Wb.Component", "properties": { "cid": "detailComp", "flex": "1", "border": "true", "cls": "w-scroll-y w-padding-lr1" }, "events": { "ready": "this.onClickPreview();", "click": "let fileBtn = e.target.closest('.wx-file');\nif (fileBtn) {\n let sid = fileBtn.recordSid;\n if (sid) {\n Wb.download(xpath + '/actions&xaction=download&id=' + sid);\n } else {\n Wb.tip('The file is being sent, please wait...');\n }\n}" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1", "visible": "@Wb.isDesktop" } }, { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "layout": "row", "padding": "@Wb.isTouch", "border": "false" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "background": "true", "visible": "@Wb.isDesktop", "border": "false", "plainIcon": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "fileItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "fileItem", "tip": "Send file", "icon": "folder-open", "handler": "app.sendFile" } } ] }, { "_icon": "textarea", "text": "textArea1", "cls": "Wb.TextArea", "properties": { "cid": "textArea1", "maxHeight": "@Wb.isTouch?'10em':undefined", "autoResize": "@Wb.isTouch", "rows": "1", "minHeight": "@Wb.isTouch?undefined:'8em'", "flex": "1", "inactiveBorder": "true", "padding": "true" }, "_expanded": true, "events": { "keydown": "if (e.isGoKey) {\n if (e.ctrlMeta)\n this.replaceSelection('\\n');\n else\n app.sendText();\n e.stopEvent();\n}" } }, { "_icon": "toolbar", "text": "touchBar", "cls": "Wb.Toolbar", "properties": { "cid": "touchBar", "visible": "@Wb.isTouch", "plainIcon": "true", "alignSelf": "center" }, "_expanded": true, "items": [ { "_icon": "item", "text": "fileItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "fileItem", "tip": "Send file", "icon": "folder-open", "handler": "app.sendFile" } }, { "_icon": "item", "text": "sendItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "sendItem", "type": "primary", "text": "Send", "padding": "0 .4em", "handler": "app.sendText" } } ] } ] }, { "_icon": "button", "text": "sendBtn", "cls": "Wb.Button", "properties": { "cid": "sendBtn", "text": "Send", "alignSelf": "end", "margin": "true", "visible": "@Wb.isDesktop", "type": "primary", "cname": "simpleButton", "handler": "app.sendText" } }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "properties": { "cid": "chatInfoItem", "icon": "ellipsis" }, "text": "chatInfoItem", "_expanded": true, "_icon": "item" } ] } ] } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "tab", "text": "tab1", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "tab1", "touchStyle": "true", "cls": "d-we-chat" }, "events": { "cardchange": "if (newCard)\n this.title = newCard.title;", "ready": "this.title = this.firstItem.title;" }, "items": [ { "_icon": "card", "text": "chatsCard", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "chatsCard", "icon": "message", "closable": "null", "title": "Chats", "layout": "fit" }, "items": [ { "_icon": "list1", "text": "chatsView", "cls": "Wb.ListView", "properties": { "cid": "chatsView", "datevalueField": "send_date", "textField": "display_name", "url": "@xpath + '/actions&xaction=getChats'", "border": "false", "subtextField": "text_content", "defaultFields": "({\n _icon: { value: 'user2' },\n iconvalue: { value: 'bell-off' }\n})", "cursorPointer": "true", "selectColor": "active" }, "events": { "itemclick": "app.openChat(item.data);" } } ] }, { "_icon": "card", "text": "contactsCard", "cls": "Wb.Card", "properties": { "cid": "contactsCard", "icon": "address-book", "closable": "null", "title": "Contacts", "layout": "fit" }, "_expanded": true, "items": [ { "_icon": "list1", "text": "contactsView", "cls": "Wb.ListView", "properties": { "cid": "contactsView", "textField": "display_name", "url": "@xpath + '/actions&xaction=getContacts'", "selectColor": "active", "border": "false", "defaultFields": "({\n _icon: { value: 'user2' }\n})", "cursorPointer": "true" }, "events": { "itemclick": "app.openUser(item.data);" } } ] }, { "_icon": "card", "text": "discoverCard", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "discoverCard", "icon": "discovery", "closable": "null", "title": "Discover", "layout": "fit" }, "items": [ { "_icon": "list-view", "text": "discoverView", "cls": "Wb.View", "properties": { "cid": "discoverView", "data": "[\n { icon: 'moment', title: 'Moment' },\n { gap: true, _disabled: true },\n { icon: 'video', title: 'Video' },\n { icon: 'broadcast', title: 'Live' },\n { gap: true, _disabled: true },\n { icon: 'scan', title: 'Scan' },\n { icon: 'command', title: 'Shake ' },\n { gap: true, _disabled: true },\n { icon: 'search-file', title: 'Search ' },\n { gap: true, _disabled: true },\n { icon: 'cart', title: 'Shopping ' },\n { icon: 'game', title: 'Game ' },\n { gap: true, _disabled: true },\n { icon: 'data-provider', title: 'Programs ' }\n]", "itemTpl": "{if data.gap}\n
\n{else}\n
\n
\n
{title}
\n
\n
\n
\n{/if}", "background": "true", "cls": "w-disp-grid", "border": "false" }, "events": { "itemclick": "Wb.tip(item.data.title + ' clicked');" } } ] }, { "_icon": "card", "text": "serviceCard", "cls": "Wb.Card", "_expanded": true, "properties": { "cid": "serviceCard", "icon": "briefcase", "closable": "null", "title": "Service", "layout": "fit" }, "events": { "click": "let item = e.target.getClosestComp(Wb.ViewItem);\nif (item)\n Wb.tip(item.data.text + ' clicked');" }, "items": [ { "_icon": "container", "text": "serviceCt", "cls": "Wb.Container", "properties": { "cid": "serviceCt", "layout": "grid1", "gap": ".5em", "padding": ".5em", "background": "true" }, "_expanded": true, "items": [ { "_icon": "component", "text": "bannerComp", "cls": "Wb.Component", "properties": { "cid": "bannerComp", "html": "
\n
\n
\n
Payment
\n
\n
\n
\n
Wallet
\n
\n
" }, "events": { "click": "let el = e.target.closest('[xid]');\nif (el)\n Wb.tip(el.getAttribute('xid') + ' clicked');" } }, { "_icon": "panel", "text": "financialPanel", "cls": "Wb.Panel", "properties": { "cid": "financialPanel", "title": "Financial Planning", "icon": "money", "layout": "grid1", "roundBorder": "true", "padding": "false", "plainTitle": "true" }, "_expanded": true, "items": [ { "_icon": "list-view", "text": "financialView", "cls": "Wb.View", "properties": { "cid": "financialView", "itemTpl": "
\n
\n
{text}
\n
", "layout": "grid4", "data": "[\n { icon: 'card', text: 'Credit Card' },\n { icon: 'money', text: 'Loan' },\n { icon: 'command', text: 'Wealth' },\n { icon: 'component', text: 'Insurance' }\n]", "bodyCls": "w-grid4", "padding": "2em", "border": "false", "clickSelect": "false", "gap": "1em" }, "_expanded": true } ] }, { "_icon": "panel", "text": "lifePanel", "cls": "Wb.Panel", "properties": { "cid": "lifePanel", "title": "Life Services", "icon": "handshake", "layout": "grid1", "roundBorder": "true", "padding": "false", "plainTitle": "true" }, "_expanded": true, "items": [ { "_icon": "list-view", "text": "lifeView", "cls": "Wb.View", "properties": { "cid": "lifeView", "itemTpl": "
\n
\n
{text}
\n
", "layout": "grid4", "data": "[\n { icon: 'mobile', text: 'Recharge' },\n { icon: 'module', text: 'Pay' },\n { icon: 'qq', text: 'QQ Coin' },\n { icon: 'building', text: 'City Service' },\n { icon: 'heart1', text: 'Public Welfare' },\n { icon: 'disc', text: 'Health' }\n]", "bodyCls": "w-grid4", "padding": "2em", "border": "false", "clickSelect": "false", "gap": "1em" }, "_expanded": true } ] }, { "_icon": "panel", "text": "transportationPanel", "cls": "Wb.Panel", "properties": { "cid": "transportationPanel", "plainTitle": "true", "title": "Transportation", "icon": "car", "layout": "grid1", "roundBorder": "true", "padding": "false" }, "_expanded": true, "items": [ { "_icon": "list-view", "text": "transportationView", "cls": "Wb.View", "properties": { "cid": "transportationView", "itemTpl": "
\n
\n
{text}
\n
", "layout": "grid4", "data": "[\n { icon: 'location', text: 'Travel' },\n { icon: 'train', text: 'Train Tickets' },\n { icon: 'car', text: 'Taxi' },\n { icon: 'school', text: 'Hotel' },\n { icon: 'identity', text: 'Identity' }\n]", "bodyCls": "w-grid4", "padding": "2em", "border": "false", "clickSelect": "false", "gap": "1em" }, "_expanded": true } ] } ] } ] } ] } ] } ] } # example/workflow/leave/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "true", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Select leave data.\n */\n selectLeave() {\n let result = Wb.getRow('select * from wb_leave where flow_id={?flowId?}');\n result.flowTitle = new Wb.Workflow({ flowId: Params.flowId }).title;\n Wb.send(result);\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/workflow/leave/after-action.xwl Title: after-action ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.info('after flow action: ' + app.action); // action name\nWb.info('after flow id: ' + app.flow.flowId); // workflow id\n//return 'value'; // return to client" }, "_icon": "module" } # example/workflow/leave/before-action.xwl Title: before-action ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.info('before flow action: ' + app.action); // action name\nWb.info('before flow id: ' + app.flow.flowId); // workflow id\n//return 'value'; // return to client" }, "_icon": "module" } # example/workflow/leave/handle-form.xwl Title: handle-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let flow, row;\n\n flow = new Wb.Workflow({ flowId: Params.flowId });\n Params.userid = flow.userid;\n row = Wb.getRow('select * from wb_leave where flow_id={?flowId?} and user_id={?userid?}');\n row.applicant = flow.getInitUser().displayName;\n Params.leaveData = Wb.encode(row);\n}\nmain();" }, "_icon": "module", "_expanded": true, "events": { "initialize": "/*\n * Xwl comments.\n * @class $path\n */\nWb.apply(app, {\n /** @property {Boolean} - Whether to hide default action buttons. */\n hideActionButtons: true,\n /** @property {Object} - Static leave data. @priv */\n leaveData: _$leaveData$_,\n /**\n * Fires after displaying the window.\n * @param {String} flowId The workflow instance id.\n * @return {String} type Window type.\n * -'start': Start window.\n * -'handle': Handle window.\n * -'view': View window.\n * @param {Wb.GridItem} record The workflow record.\n */\n init(flowId, type, record) {\n Wb.setValue(app.main, app.leaveData);\n app.radioGroup1.visible = type == 'handle';\n Wb.log(record.data.node_name);\n },\n /**\n * Fires when the OK button is clicked.\n */\n onAction() {\n let value;\n switch (app.radioGroup1.value) {\n /**\n * Do pass action.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doPass\n */\n case 0:\n app.doPass();\n break;\n /**\n * Do back action.\n * @param {String} nodeName The back to node name.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doBack\n */\n case 1:\n value = app.nodeSelect.value;\n if (value)\n app.doBack(value);\n else {\n app.nodeSelect.focus();\n Wb.tipSelect();\n }\n break;\n /**\n * Do transfer action.\n * @param {String} user The user id.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doTransfer\n */\n case 2:\n value = app.userSelect.value;\n if (value)\n app.doTransfer(value);\n else {\n app.userSelect.focus();\n Wb.tipSelect();\n }\n break;\n /**\n * Do reject action.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doReject\n */\n case 3:\n app.doReject();\n break;\n /**\n * Do sign before action.\n * @param {String} user The user id.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doSignBefore\n */\n case 4:\n value = app.userSelect.value;\n if (value)\n app.doSignBefore(value);\n else {\n app.userSelect.focus();\n Wb.tipSelect();\n }\n break;\n /**\n * Do sign after action.\n * @param {String} user The user id.\n * @param {Object} params The parameters object.\n * @param {Function} callback The callback function after executed.\n * @function doSignAfter\n */\n case 5:\n value = app.userSelect.value;\n if (value)\n app.doSignAfter(value);\n else {\n app.userSelect.focus();\n Wb.tipSelect();\n }\n break;\n }\n }\n});" }, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "column", "icon": "paper-plane", "title": "Leave application", "visible": "true", "padding": "true", "autoScroll": "true", "width": "80em" }, "items": [ { "_icon": "radios", "text": "radioGroup1", "cls": "Wb.RadioGroup", "properties": { "cid": "radioGroup1" }, "events": { "change": "let value = this.value;\n\nif (value == 3)\n value = 0;\nelse if (value == 4 || value == 5)\n value = 2;\napp.cardCt1.activeIndex = value;\nif (value == 1 && !app.nodeSelect.value) {\n app.nodeSelect.picker.load({ success() { this.parent.valueIndex = 0 } });\n}" }, "_expanded": true, "items": [ { "_icon": "check2", "text": "passRadio", "cls": "Wb.Radio", "properties": { "cid": "passRadio", "label": "@Str.pass", "value": "true" } }, { "_icon": "check2", "text": "backRadio", "cls": "Wb.Radio", "properties": { "cid": "backRadio", "label": "@Str.back1" } }, { "_icon": "check2", "text": "transferRadio", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "transferRadio", "label": "@Str.transfer" } }, { "_icon": "check2", "text": "rejectRadio", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "rejectRadio", "label": "@Str.reject" } }, { "_icon": "check2", "text": "signBeforeRadio", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "signBeforeRadio", "label": "@Str.signBefore" } }, { "_icon": "check2", "text": "signAfterRadio", "cls": "Wb.Radio", "_expanded": true, "properties": { "cid": "signAfterRadio", "label": "@Str.signAfter" } } ] }, { "_icon": "win-restore", "text": "cardCt1", "cls": "Wb.CardCt", "properties": { "cid": "cardCt1", "border": "false" }, "_expanded": true, "items": [ { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "text", "text": "applicant", "cls": "Wb.Text", "properties": { "cid": "applicant", "text": "Applicant", "readonly": "true" }, "_expanded": true }, { "_icon": "calendar", "text": "begin_date", "cls": "Wb.Date", "properties": { "cid": "begin_date", "text": "Begin Date", "readonly": "true" } }, { "_icon": "calendar", "text": "end_date", "cls": "Wb.Date", "properties": { "cid": "end_date", "text": "End Date", "readonly": "true" } }, { "_icon": "number-edit", "text": "leave_days", "cls": "Wb.Number", "properties": { "cid": "leave_days", "text": "Leave Days", "readonly": "true" } }, { "_icon": "text", "text": "leave_reason", "cls": "Wb.Text", "properties": { "cid": "leave_reason", "text": "Leave Reason", "readonly": "true" }, "_expanded": true } ] }, { "_icon": "container", "text": "container2", "cls": "Wb.Container", "properties": { "cid": "container2", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "combo", "text": "nodeSelect", "cls": "Wb.Select", "properties": { "cid": "nodeSelect", "url": "m?xwl=my/my-flow/get-his-nodes", "text": "Select node", "forceSelect": "true" }, "events": { "beforeload": "params.flowId = app.flowId;" } } ] }, { "_icon": "container", "text": "container3", "cls": "Wb.Container", "properties": { "cid": "container3", "layout": "grid1" }, "_expanded": true, "items": [ { "_icon": "combo", "text": "userSelect", "cls": "Wb.Select", "properties": { "cid": "userSelect", "url": "m?xwl=sys/dialog/user-selector/select", "textField": "display_name", "valueField": "sid", "subtextField": "user_name", "text": "Select user", "forceSelect": "true" } } ] } ] } ] } ] } # example/workflow/leave/start-form.xwl Title: start-form ```json { "title": "", "icon": "", "img": "", "tags": "{container: false}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.apply(app, {\n /**\n * Fires after action execution.\n * @param {String} action The action name.\n * @param {Wb.Workflow} flow The workflow instance.\n * @return {Object} The returned \"after\" parameter to the client.\n */\n afterAction(action, flow) {\n if (flow.restarting) {\n Params.$flow_id = flow.flowId;\n Wb.sync({ tableName: 'wb_leave', update: Params, whereFields: 'flow_id' });\n } else {\n Wb.apply(Params, { sid: Wb.getId(), flow_id: flow.flowId, user_id: flow.handleUser });\n Wb.sync({ tableName: 'wb_leave', insert: Params });\n }\n }\n});" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Boolean} - Whether to auto show window. */\n autoShow: false,\n /**\n * Fires after displaying the window.\n * @param {String} flowId The workflow instance id.\n * @return {String} type Window type.\n * -'start': Start window.\n * -'handle': Handle window.\n * -'view': View window.\n * @param {Wb.GridItem} record The workflow record.\n */\n init(flowId, type, record) {\n if (flowId) {\n Wb.ajax({\n url: xpath + '/../actions&xaction=selectLeave',\n params: { flowId },\n json: true,\n success(resp) {\n Wb.setValue(app.main, resp);\n app.main.show();\n }\n });\n } else {\n app.main.show();\n }\n }\n});" }, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "grid1", "title": "Leave application", "icon": "paper-plane", "visible": "true", "autoScroll": "true" }, "items": [ { "_icon": "text", "text": "flowTitle", "cls": "Wb.Text", "properties": { "cid": "flowTitle", "text": "Title", "required": "true" } }, { "_icon": "calendar", "text": "begin_date", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "begin_date", "text": "Begin Date", "required": "true" } }, { "_icon": "calendar", "text": "end_date", "cls": "Wb.Date", "_expanded": true, "properties": { "cid": "end_date", "text": "End Date", "required": "true" } }, { "_icon": "number-edit", "text": "leave_days", "cls": "Wb.Number", "properties": { "cid": "leave_days", "decimalCount": "0", "text": "Leave days", "required": "true", "minValue": "0", "maxLength": "5" } }, { "_icon": "text", "text": "leave_reason", "cls": "Wb.Text", "properties": { "cid": "leave_reason", "text": "Reason", "required": "true" } } ] } ] } # example/workflow/manual-start/start.xwl Title: start ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let flow, now = new Date();\n\n flow = new Wb.Workflow({ file: 'example/leave.flw', title: 'My leave application' });\n flow.start();\n Wb.sync({\n tableName: 'wb_leave', insert: {\n sid: Wb.getId(), begin_date: now.addDay(2), end_date: now.addDay(5),\n flow_id: flow.flowId, user_id: Wb.userid, leave_days: 8, leave_reason: 'Go on vacation'\n }\n });\n}\nmain();" }, "_icon": "module" } # example/workflow/manual-start.xwl Title: manual-start ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "grid1" }, "items": [ { "_icon": "title", "text": "title1", "cls": "Wb.Title", "properties": { "cid": "title1", "title": "Manual start a new workflow" } }, { "_icon": "button", "text": "button1", "cls": "Wb.Button", "properties": { "cid": "button1", "type": "primary", "text": "Start a new workflow" }, "events": { "click": "Wb.ajax({\n url: xpath + '/start',\n success() {\n Wb.tip('The workflow started, click to view it.', null,\n f => Wb.openNormal({\n url: 'my-flow', success(scope) {\n scope.grid1.reload();\n }\n }));\n }\n});" }, "_expanded": true } ] } ] } # example/workflow/reimburse/actions.xwl Title: actions ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "true", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Select start/restart data.\n */\n selectStartData() {\n let result;\n\n result = Wb.getRowx('select * from wb_reimburse where flow_id={?flowId?}');\n result.flowTitle = new Wb.Workflow({ flowId: Params.flowId }).title;\n Wb.send(result);\n },\n /**\n * Select handle data.\n */\n selectHandleData() {\n let flow, list, history;\n\n flow = new Wb.Workflow({ flowId: Params.flowId });\n // Specify userid to limit only the initiate user data to be visible\n Params.userid = flow.userid;\n list = Wb.getRows(`select exp_date,item_name,amount from wb_reimburse where flow_id={?flowId?}\n and user_id={?userid?} order by exp_date`);\n history = Wb.getRows(`select b.process_time,c.display_name,b.opinions from wb_reimburse a,\n wb_ra_opinions b, wb_user c where a.flow_id={?flowId?} and a.user_id={?userid?}\n and a.sid=b.reimburse_id and b.approver_user_id=c.sid\n order by b.process_time`);\n Wb.send({ list, history, applicant: flow.getInitUser().text });\n }\n};\nactions[Params.xaction]();" }, "_icon": "module" } # example/workflow/reimburse/handle-form.xwl Title: handle-form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.apply(app, {\n /**\n * Fires before action execution.\n * @param {String} action The action name.\n * @param {Wb.Workflow} flow The workflow instance.\n * @return {Object} The returned \"before\" parameter to the client.\n */\n beforeAction(action, flow) {\n },\n /**\n * Fires after action execution.\n * @param {String} action The action name.\n * @param {Wb.Workflow} flow The workflow instance.\n * @return {Object} The returned \"after\" parameter to the client.\n */\n afterAction(action, flow) {\n let node = flow.beforeNode, reimburse_id = Wb.getRecord('select sid from wb_reimburse where flow_id={?flowId?}')?.[0],\n node_text = flow.getNodeLabel(node);\n\n // Params._newUser: New user id of transfer, signBefore, signAfter\n // Params._backNode: Back to node name.\n Wb.sync({\n tableName: 'wb_ra_opinions',\n insert: {\n sid: Wb.getId(), reimburse_id, process_time: new Date(), approver_user_id: flow.handleUser, node_text,\n opinions: 'Action: ' + action + '\\nNode: ' + node_text + '\\n' + Params.opinions\n }\n });\n if (action == 'pass' && flow.completed) {\n return { type: 'done', msg: 'Congratulations! The process has been fully completed.' };\n }\n }\n});" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /** @property {Boolean} - Whether to auto show window. */\n autoShow: false,\n /**\n * Fires after displaying the window.\n * @param {String} flowId The workflow instance id.\n * @return {String} type Window type.\n * -'start': Start window.\n * -'handle': Handle window.\n * -'view': View window.\n * @param {Wb.GridItem} record The workflow record.\n */\n init(flowId, type, record) {\n app.opinionsTitle.visible = app.opinions.visible = type == 'handle';\n app.getData(flowId);\n Wb.log(record.data.node_name);\n },\n /**\n * Fires before action execution.\n * @param {String} action The action name.\n * @return {Object} Parameter object to be submitted. If returns false, the execution is canceled.\n * @param {Wb.GridItem} record The workflow record.\n */\n beforeAction(action, record) {\n Wb.log('action: ' + action + ', node name: ' + record.data.node_name);\n },\n /**\n * Fires after action execution.\n * @param {String} action The action name.\n * @param {Object} response The response object.\n * @param {Object} [.result] The flow record data.\n * @param {Object} [.before] The returned value of server beforeAction.\n * @param {Object} [.after] The returned value of server afterAction.\n * @param {Wb.GridItem} record The workflow record.\n */\n afterAction(action, response, record) {\n let afterData = response.after;\n Wb.log('action: ' + action + ', node name: ' + record.data.node_name);\n if (afterData?.type == 'done')\n Wb.tip(afterData.msg);\n },\n /**\n * Get window data. @priv\n * @param {String} flowId The workflow instance id.\n */\n getData(flowId) {\n Wb.ajax({\n url: xpath + '/../actions&xaction=selectHandleData',\n params: { flowId },\n json: true,\n success(resp) {\n let amount = 0, { list, history, applicant } = resp;\n\n app.grid1.addData(list);\n list.forEach(item => {\n amount += item.amount;\n })\n Wb.setValue(app.main, { applicant, amount });\n createHistory();\n app.main.show();\n // show opinions history\n function createHistory() {\n let comp = app.opinionsHistory, titleEl;\n comp.cls = 'w-padding w-sized8';\n history.forEach((item, i) => {\n titleEl = comp.addEl('w-row w-gap w-sub-color');\n if (i > 0)\n titleEl.cls = 'w-margin-top';\n titleEl.addEl().textContent = item.process_time.dateValue.dateTimeText;\n titleEl.addEl().textContent = item.display_name;\n comp.addEl().textContent = item.opinions;\n });\n }\n }\n });\n }\n});" }, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "column", "icon": "money", "title": "Reimburse Form", "gap": "true", "padding": "true", "autoScroll": "true", "visible": "true", "width": "60em", "height": "40em" }, "items": [ { "_icon": "label1", "text": "applicant", "cls": "Wb.DisplayField", "properties": { "cid": "applicant", "text": "Applicant" } }, { "_icon": "label1", "text": "amount", "cls": "Wb.DisplayField", "properties": { "cid": "amount", "text": "Total amount" } }, { "_icon": "title", "text": "detailsTitle", "cls": "Wb.Title", "properties": { "cid": "detailsTitle", "title": "Details" } }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "pagingBar": "false", "pageSize": "-1", "flex": "1", "minHeight": "8em", "fields": "({ process_time: { type: 'date' } })" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "Date", "fieldName": "exp_date" }, "text": "dateCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "itemNameCol", "text": "Item name", "fieldName": "item_name", "width": "-1" }, "text": "itemNameCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "amountCol", "text": "Amount", "fieldName": "amount", "width": "10em" }, "text": "amountCol", "_expanded": true, "_icon": "column" } ] } ] }, { "_icon": "title", "text": "opinionsHistoryTitle", "cls": "Wb.Title", "properties": { "cid": "opinionsHistoryTitle", "title": "Approval opinions history" }, "_expanded": true }, { "_icon": "component", "text": "opinionsHistory", "cls": "Wb.Component", "properties": { "cid": "opinionsHistory", "autoScroll": "true", "maxHeight": "10em", "cls": "w-pre" }, "_expanded": true }, { "_icon": "title", "text": "opinionsTitle", "cls": "Wb.Title", "properties": { "cid": "opinionsTitle", "title": "Approval opinions" } }, { "_icon": "textarea", "text": "opinions", "cls": "Wb.TextArea", "properties": { "cid": "opinions", "height": "6em", "required": "true" } } ] } ] } # example/workflow/reimburse/start-form.xwl Title: start-form ```json { "title": "", "icon": "", "img": "", "tags": "{container: false}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.apply(app, {\n /**\n * Fires before action execution.\n * @param {String} action The action name.\n * @param {Wb.Workflow} flow The workflow instance.\n * @return {Object} The returned \"before\" parameter to the client.\n */\n beforeAction(action, flow) {\n },\n /**\n * Fires after action execution.\n * @param {String} action The action name.\n * @param {Wb.Workflow} flow The workflow instance.\n * @return {Object} The returned \"after\" parameter to the client.\n */\n afterAction(action, flow) {\n let flow_id = flow.flowId, user_id = Wb.userid, data = Wb.getObject('data');\n\n flow_id = flow.flowId;\n data.insert?.forEach(item => {\n Wb.apply(item, { sid: Wb.getId(), flow_id, user_id });\n });\n Wb.sync(Wb.apply({ tableName: 'wb_reimburse' }, data));\n }\n});" }, "_icon": "module", "_expanded": true, "events": { "initialize": "// app.flowId: The workflow id\n// app.restarting: Whether the workflow is restarting\nWb.apply(app, {\n /** @property {Boolean} - Whether to auto show window. */\n autoShow: false,\n /**\n * Fires after displaying the window.\n * @param {String} flowId The workflow instance id.\n * @param {String} type Window type.\n * -'start': Start window.\n * -'handle': Handle window.\n * -'view': View window.\n * @param {Wb.GridItem} record The workflow record.\n */\n init(flowId, type, record) {\n if (flowId) {\n app.grid1.load({\n params: { flowId }, success(a, b, resp) {\n app.flowTitle.value = resp.flowTitle;\n app.main.show();\n }\n });\n } else {\n app.main.show();\n }\n },\n /**\n * Fires before action execution.\n * @param {String} action The action name.\n * @param {Wb.GridItem} record The workflow record.\n * @return {Object} Parameter object to be submitted. If returns false, the execution is canceled.\n */\n beforeAction(action, record) {\n let grid = app.grid1;\n if (!grid.hasChild) {\n Wb.tipWarn('Please input at least one item');\n grid.startEdit(grid.addData({}), 1);\n return false;\n }\n return { data: app.grid1.modifiedData };\n },\n /**\n * Fires after action execution.\n * @param {String} action The action name.\n * @param {Object} response The response object.\n * @param {Object} [.result] The flow record data.\n * @param {Object} [.before] The returned value of server beforeAction.\n * @param {Object} [.after] The returned value of server afterAction.\n * @param {Wb.GridItem} record The workflow record.\n */\n afterAction(action, response, record) {\n Wb.log('action: ' + action + ', node name: ' + record.data.node_name);\n }\n});" }, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "column", "width": "60em", "title": "Start reimbursement workflow", "icon": "money", "gap": "true", "padding": "true", "autoScroll": "true", "visible": "true", "height": "30em" }, "items": [ { "_icon": "text", "text": "flowTitle", "cls": "Wb.Text", "properties": { "cid": "flowTitle", "text": "Title", "required": "true" } }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "properties": { "cid": "grid1", "editable": "true", "pagingBar": "false", "flex": "1", "minHeight": "8em", "url": "@xpath + '/../actions&xaction=selectStartData'", "pageSize": "-1", "autoLoad": "false" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "addBtn", "text": "@Str.add", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.grid1.addRecord();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "text": "@Str.del", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "app.grid1.delRecords();" } } ] }, { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "cls": "Wb.Column", "properties": { "cid": "dateCol", "text": "Date", "fieldName": "exp_date" }, "text": "dateCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Date", "properties": { "cid": "editor", "isProperty": "true", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "calendar" } ] }, { "cls": "Wb.Column", "properties": { "cid": "itemNameCol", "text": "Item name", "fieldName": "item_name", "width": "-1" }, "text": "itemNameCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "cls": "Wb.Column", "properties": { "cid": "amountCol", "text": "Amount", "fieldName": "amount", "width": "10em" }, "text": "amountCol", "_expanded": true, "_icon": "column", "items": [ { "cls": "Wb.Number", "properties": { "cid": "editor", "isProperty": "true", "decimalCount": "2", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "number-edit" } ] } ] } ] } ] } ] } # example/workflow/start-route/start-form.xwl Title: start-form ```json { "title": "", "icon": "", "img": "", "tags": "{container: false}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "grid1", "title": "Starting with fork", "icon": "flow1", "visible": "true", "autoScroll": "true" }, "items": [ { "_icon": "number-edit", "text": "startValue", "cls": "Wb.Number", "properties": { "cid": "startValue", "decimalCount": "0", "text": "Value", "required": "true", "minValue": "0", "maxLength": "5" } } ] } ] } # my/home.xwl Title: Home Description: My home page ```json { "title": "@home", "icon": "home", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "// Get desktop data\nfunction loadPageData() {\n let data = Wb.getResource(['desktop', 'desktop'], [null, 'system']), items, url;\n\n data = data[0] ?? data[1];\n items = data?.portlets || [];\n items.forEach(item => {\n try {\n url = item.moduleUrl;\n item.script = Wb.permitx(url) && Wb.execute(url);\n } catch (e) {\n item.script = e?.toString();\n }\n });\n Wb.set({ items: Wb.encode(items) });\n}\nloadPageData();", "remark": "My home page" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Execute after load.\n */\n onLoad() {\n let card = parentContainer;\n\n app.restorePanels();\n if (card?.app?.inHome) {\n let tab = card.parent;\n app.viewport1.homeTab = tab; // don't assign to app, prevent tab auto destroy\n app.onCardChange.call(tab, card);\n tab.on('cardchange', app.onCardChange)\n }\n },\n /**\n * Execute after tab card change. @priv\n */\n onCardChange(card) {\n let tree = this.app.moduleTree, enabled = card == parentContainer;\n\n tree.draggable = enabled ? {\n acceptDrop() {\n let data = this.source[0].data, tags = data.tags, panel;\n\n if (tags) {\n tags = Wb.parse(tags);\n if (tags.frame || tags.newWin) {\n Wb.tipWarn(Str.cannotOpenModule);\n return;\n }\n }\n panel = app.createPanel({\n moduleUrl: 'm?xwl=' + data.path, icon: data._icon, img: data._img, tags,\n strTitle: data.strTitle, title: data.text\n });\n panel.intoView();\n panel.highlight();\n }\n } : false;\n tree.setEvents(enabled, 'itemdrag', app.onItemDrag);\n },\n /**\n * Module tree items drag. @priv\n */\n onItemDrag(data) {\n let d = data.source[0].data;\n data.allowDrop = d._leaf && d.path != 'my/home';\n data.mode = 'append';\n },\n /**\n * Create module panel. @priv\n * @param {Object} data Module data.\n * @return {Wb.Panel} The created panel.\n */\n createPanel(data) {\n let panel, configs, moduleUrl, tags = data.tags, val, script;\n\n moduleUrl = data.moduleUrl;\n configs = {\n cname: 'panel', layout: 'fit', plainTitle: true, roundBorder: true, closable: true, maximizable: true,\n moduleUrl, tags\n };\n val = data.col || 6;\n configs.gridColValue = val;\n configs.gridColumn = 'span ' + val;\n val = data.row || 4;\n configs.gridRowValue = val;\n configs.gridRow = 'span ' + val;\n if (data.icon)\n configs.icon = data.icon;\n else if (data.img)\n configs.img = data.img;\n if (data.strTitle) {\n configs.strTitle = data.strTitle;\n configs.title = Str[data.strTitle];\n } else {\n configs.title = data.title;\n }\n panel = app.viewport1.add(configs);\n configs = {\n container: panel, updateTitle: false, success(scope) {\n let vp = panel.firstItem, tools;\n\n if (vp instanceof Wb.Panel) {\n vp.border = false;\n tools = vp.tools?.filter(tool => tool.icon != 'close') ?? [];\n if (vp.title)\n panel.title = vp.title;\n if (vp.icon)\n panel.icon = vp.icon;\n else if (vp.img)\n panel.img = vp.img;\n } else {\n tools = [];\n }\n tools.push({\n icon: 'menu', handler() {\n let comp = this.up(p => p instanceof Wb.Panel);\n app.menuSetComp = comp;\n app.colSlider.value = comp.gridColValue ?? 1;\n app.rowSlider.value = comp.gridRowValue ?? 1;\n app.mainMenu.showBy(this);\n }\n });\n panel.tools = tools;\n vp?.titleBar$?.destroy();\n if (scope?.noTitlebar) {\n panel.titleBar.hide();\n panel.mon({\n mouseenter() {\n this.titleBar.show();\n },\n mouseleave() {\n this.titleBar.hide();\n }\n })\n }\n }\n };\n script = data.script;\n if (script)\n configs.script = script;\n else\n configs.url = moduleUrl;\n Wb.open(Wb.apply(configs, tags));\n return panel;\n },\n /**\n * Restore saved panels. @priv\n */\n restorePanels() {\n let items = _$items$_;\n\n items.forEach(item => {\n app.createPanel(item);\n });\n }\n});" }, "items": [ { "_icon": "menu2", "text": "mainMenu", "cls": "Wb.Menu", "properties": { "cid": "mainMenu", "layout": "grid1", "defaults": "({ labelWidth: '5em' })", "minWidth": "18em", "gap": "true", "padding": "1em" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "colSlider", "cls": "Wb.Slider", "properties": { "cid": "colSlider", "text": "@Str.column", "maxValue": "12", "minValue": "1", "suffix": "true" }, "events": { "change": "app.menuSetComp.gridColValue = value;\napp.menuSetComp.gridColumn = 'span ' + value;" } }, { "_icon": "slidebar", "text": "rowSlider", "cls": "Wb.Slider", "properties": { "cid": "rowSlider", "text": "@Str.row", "minValue": "1", "maxValue": "12", "suffix": "true" }, "events": { "change": "app.menuSetComp.gridRowValue = value;\napp.menuSetComp.gridRow = 'span ' + value;" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "grid12", "background": "true", "padding": ".5em", "gap": ".5em", "itemsSortable": "true", "droppable": "wb.home", "bodyCls": "w-home-body" }, "events": { "destroy": "app.viewport1.homeTab?.un('cardchange', app.onCardChange);", "beforesort": "// only allow drag title bar\nif (!dragComp?.titleBar.el.contains(e.target))\n return false;" } } ] } # my/my-flow/back.xwl Title: back Description: Approval workflow withdrawn ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Approval workflow withdrawn", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('back');\n}\nmain();" }, "_icon": "module" } # my/my-flow/get-his-nodes.xwl Title: get-his-nodes Description: Get history nodes list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get history nodes list", "serverScript": "function main() {\n let recs, nodeName, distinctRecs = [];\n\n recs = Wb.getRecord('select node_name from wb_flow where sid={?flowId?}');\n Params.nodeName = recs?.[0];\n recs = Wb.getAllRecords(`select node_text,node_name from wb_flow_user where flow_id={?flowId?}\n and user_type<2 and node_name<>{?nodeName?} order by accept_time desc`);\n recs.forEach(rec => {\n nodeName = rec[1];\n if (distinctRecs.every(item => item[1] != nodeName))\n distinctRecs.push(rec);\n });\n distinctRecs.lastItem[0] = Str.initiator;\n Wb.send(distinctRecs);\n}\nmain();" }, "_icon": "module" } # my/my-flow/get-start-form.xwl Title: get-start-form Description: Get starting form ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get starting form", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let flow = new Wb.Workflow({ file: Params.file });\n Wb.send({ form: Util.getForm(flow, 'start') });\n}\nmain();" }, "_icon": "module" } # my/my-flow/pass.xwl Title: pass Description: Approval workflow passed ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Approval workflow passed", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('pass');\n}\nmain();" }, "_icon": "module" } # my/my-flow/reject.xwl Title: reject Description: Approval workflow rejected ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Approval workflow rejected", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('reject');\n}\nmain();" }, "_icon": "module" } # my/my-flow/select.xwl Title: select Description: Select my flow list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select my flow list", "serverScript": "function main() {\n let sql, result, userid = Wb.userid;\n\n sql = `select a.sid,a.user_id,a.start_time,a.title,a.status,a.node_name,a.node_text,a.tpl_file,d.display_name,\n b.status as user_status,b.user_type,b.node_name as user_node_name from\n wb_flow a,\n wb_flow_user b,\n (select flow_id,max(accept_time) as accept_time from wb_flow_user where user_id={?sys.userid?} group by flow_id) c,\n wb_user d\n where a.sid=b.flow_id and b.flow_id=c.flow_id and b.accept_time=c.accept_time and b.user_id={?sys.userid?} and a.user_id=d.sid`;\n sql += getTypeSql(Params.type);\n if (Params.search) {\n Wb.setLike('search');\n sql += ' and a.title like {?search?}';\n };\n sql += Wb.getOrderSql({ display_name: 'd.display_name', $: 'a' });\n result = Wb.getRowx({ sql });\n result.items.forEach(item => item.initiate = item.user_id == userid ? 1 : 0);\n Wb.send(result);\n}\n/**\n * Get select type sql clause.\n * @param {String} type Select type.\n */\nfunction getTypeSql(type) {\n switch (type) {\n case 'initiated':\n return ' and a.user_id={?sys.userid?}';\n case 'pendHandle':\n return ' and a.status=1 and b.status<2 and b.user_type<2 and a.node_name=b.node_name';\n case 'handled':\n return ' and b.status>1';\n case 'pass':\n return ' and b.status=2';\n case 'reject':\n return ' and b.status=3';\n case 'back':\n return ' and b.status=4';\n case 'transfer':\n return ' and b.status=5';\n case 'signBefore':\n return ' and b.status=6';\n case 'signAfter':\n return ' and b.status=7';\n case 'backed':\n return ' and b.status=8';\n default:\n return '';\n }\n}\nmain();" }, "_icon": "module" } # my/my-flow/sign-after.xwl Title: sign-after Description: Add signature after approval ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add signature after approval", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('signAfter');\n}\nmain();" }, "_icon": "module" } # my/my-flow/sign-before.xwl Title: sign-before Description: Add signature before approval ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Add signature before approval", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('signBefore');\n}\nmain();" }, "_icon": "module" } # my/my-flow/start.xwl Title: start Description: Start a new workflow ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Start a new workflow", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('start');\n}\nmain();" }, "_icon": "module" } # my/my-flow/terminate.xwl Title: terminate Description: Terminate workflow ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Terminate workflow", "serverScript": "function main() {\n let ids = Wb.getObject('ids'), update = [], $user_id = Wb.userid, $status = 1, status = 0;\n\n ids.forEach($sid => {\n update.push({ $sid, $user_id, $status, status });\n });\n // [whereFields: 'sid,user_id,status']: Restrict the update of record\n Wb.sync({ tableName: 'wb_flow', whereFields: 'sid,user_id,status', update });\n}\nmain();" }, "_icon": "module" } # my/my-flow/transfer.xwl Title: transfer Description: Approval workflow transfered ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Approval workflow transfered", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Util.doAction('transfer');\n}\nmain();" }, "_icon": "module" } # my/my-flow/view-progress.xwl Title: view-progress Description: View the progress of workflow ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "View the progress of workflow", "serverScript": "function main() {\n let flow = new Wb.Workflow({ flowId: Params.flowId });\n\n Wb.send({\n flow: flow.flow, activeNode: flow.activeNode.data.name,\n users: Wb.getRowx(`select a.accept_time,a.process_time,b.display_name,a.node_name,a.node_text,a.status,a.user_type\n from wb_flow_user a, wb_user b where a.flow_id={?flowId?} and a.user_id=b.sid order by a.accept_time`)\n });\n}\nmain();" }, "_icon": "module" } # my/my-flow/view.xwl Title: view Description: View the form of workflow ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "View the form of workflow", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n let now = new Date(), flow = new Wb.Workflow({ flowId: Params.flowId }), form, update = [], userid = Wb.userid;\n\n // Mark the given flow read\n Wb.getObject('allFlowId').forEach(item => {\n update.push({ $flow_id: item, $user_id: userid, $status: 0, status: 1, process_time: now });\n });\n Wb.sync({\n tableName: 'wb_flow_user', whereFields: 'flow_id,user_id,status', unique: false, update\n });\n form = Wb.getBool('handle') ? Util.getForm(flow, 'handle') : Util.getForm(flow, 'view');\n if (!form)\n Wb.raise('The workflow is configured with neither handleForm nor viewForm.');\n Wb.send({\n form, back: flow.getProperty('back'), transfer: flow.getProperty('transfer'), reject: flow.getProperty('reject'),\n signBefore: flow.getProperty('signBefore'), signAfter: flow.getProperty('signAfter'), restarting: flow.restarting\n });\n}\nmain();" }, "_icon": "module" } # my/my-flow.xwl Title: My Workflow Description: My initiated or participated workflows ```json { "title": "@myWorkflow", "icon": "flow", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "My initiated or participated workflows", "links": "[\n \"wb/libs/x6.js\",\n \"wb/js/flow-designer.js\"\n]" }, "_icon": "module", "_expanded": true, "events": { "initialize": "Wb.apply(app, {\n /**\n * Open file dialog and select a workflow file to start a new workflow instance. @priv\n */\n start() {\n Wb.promptFile((a, win, file) => {\n Wb.ajax({\n url: xpath + '/get-start-form',\n params: { file },\n json: true,\n success(resp) {\n let url = resp.form;\n if (!url) {\n Wb.error(Str.noStartForm);\n return;\n }\n win.close();\n if (url.endsWith('.xwl'))\n url = Wb.getModuleUrl(url);\n Wb.run({\n url,\n success(scope) {\n let main = scope.main;\n scope.flowTplFile = file;\n if (main) {\n main.hide(); // for fire show event\n main.closeAction = 'destroy';\n main.modal = true;\n main.onEsc = main.onCancel;\n main.onEnter = f => app.doAction('start', scope, {});\n main.buttonsBar.add([\n { text: Str.ok, type: 'primary', icon: 'ok', cid: 'ok', handler: main.onEnter },\n { text: Str.cancel, icon: 'delete', handler() { main.close() } }\n ]);\n if (scope.autoShow ?? true) {\n main.show();\n main.center();\n }\n }\n scope.init?.(null, 'start', {});\n }\n });\n }\n });\n }, '|wb/system/resource/flow', '.flw', Str.selectFile, false, 'm?xwl=sys/file/get-resource');\n },\n /**\n * Check whether the given workflow can be handled.\n * @param {Object} data Workflow instance data.\n * @return {Boolean} Returns true means can be handled, otherwise not.\n */\n canHandle(data) {\n return data.node_name == data.user_node_name && data.user_type <= 1 && data.user_status < 2 && data.status == 1;\n },\n /**\n * View the form of current selected workflow. @priv\n * @param {Boolean} handle Whether to handle the workflow.\n */\n view(handle) {\n let rec = app.grid1.selection, data = rec?.data, recs = app.grid1.selections, flowId = data?.sid;\n\n if (!flowId) {\n Wb.tipSelect();\n return;\n }\n if (handle && !app.canHandle(data)) {\n Wb.tip(Str.notNeedHandle);\n return;\n }\n Wb.ajax({\n url: xpath + '/view',\n params: { flowId, handle, allFlowId: app.grid1.selectionsData.pluck('sid') },\n json: true,\n success(resp) {\n let url = resp.form;\n recs.forEach(rec => rec.data.user_status == 0 && rec.set('user_status', 1));\n if (url.endsWith('.xwl'))\n url = Wb.getModuleUrl(url);\n Wb.run({\n url,\n params: { flowId },\n success(scope) {\n let main = scope.main;\n scope.flowId = flowId;\n scope.restarting = resp.restarting;\n if (main) {\n main.hide();\n main.closeAction = 'destroy';\n main.modal = true;\n main.onEsc = main.onCancel;\n if (handle) {\n let btns = [], isStart = data.user_type == 0;\n scope.doPass = (params, callback) => app.doAction('pass', scope, rec, params, callback);\n scope.doReject = (params, callback) => app.doAction('reject', scope, rec, params, callback);\n scope.doBack = (node, params, callback) => app.doAction('back', scope, rec,\n Wb.apply({ _backNode: node }, params), callback);\n scope.doTransfer = (user, params, callback) => app.doAction('transfer', scope, rec,\n Wb.apply({ _newUser: user }, params), callback);\n scope.doSignBefore = (user, params, callback) => app.doAction('signBefore', scope, rec,\n Wb.apply({ _newUser: user }, params), callback);\n scope.doSignAfter = (user, params, callback) => app.doAction('signAfter', scope, rec,\n Wb.apply({ _newUser: user }, params), callback);\n if (scope.hideActionButtons) {\n main.onEnter = scope.onAction;\n btns.push({ text: Str.ok, icon: 'ok', type: 'primary', handler: main.onEnter });\n } else {\n main.onEnter = f => scope.doPass();\n btns.push({ text: isStart ? Str.ok : Str.pass, icon: 'ok', type: 'primary', handler: main.onEnter });\n if (!isStart && resp.reject == 'true') {\n btns.push({\n text: Str.reject, icon: 'delete4', handler() {\n if (app.onBeforeAction('reject', scope, rec) === false)\n return;\n Wb.confirm(Str.doConfirm.format(Str.reject), f => scope.doReject());\n }\n });\n }\n if (!isStart && resp.back != 'false')\n btns.push({\n text: Str.back1, icon: 'right4', handler() {\n if (app.onBeforeAction('back', scope, rec) === false)\n return;\n Wb.ajax({\n url: xpath + '/get-his-nodes',\n params: { flowId },\n json: true,\n success(resp) {\n let select = app.backNodeSelect, win = app.backWin;\n select.data = resp;\n select.valueIndex = 0;\n win.okHandler = f => {\n app.doAction('back', scope, rec, { _backNode: select.value }, f => win.close());\n };\n win.show();\n }\n });\n }\n });\n if (!isStart && resp.transfer != 'false') {\n btns.push({\n text: Str.transfer, icon: 'undo', handler() {\n app.doUserAction('transfer', scope, Str.transfer, rec);\n }\n });\n }\n if (!isStart && resp.signBefore != 'false') {\n btns.push({\n text: Str.signBefore, icon: 'column-before', handler() {\n app.doUserAction('signBefore', scope, Str.signBefore, rec);\n }\n });\n }\n if (!isStart && resp.signAfter != 'false') {\n btns.push({\n text: Str.signAfter, icon: 'column-after', handler() {\n app.doUserAction('signAfter', scope, Str.signAfter, rec);\n }\n });\n }\n }\n btns.push({ text: Str.cancel, icon: 'delete', handler() { main.close() } });\n main.buttonsBar.add(btns);\n\n } else {\n main.buttonsBar.add({ text: Str.close, type: 'primary', handler() { main.close() } });\n }\n if (scope.autoShow ?? true) {\n main.show();\n main.center();\n }\n }\n scope.init?.(flowId, handle ? 'handle' : 'view', rec);\n }\n });\n }\n });\n },\n /**\n * Perform action related to user. @priv\n * @param {String} action Action name.\n * @param {Object} scope App scope.\n * @param {String} title User dialog title.\n * @param {Wb.GridItem} rec Current record.\n */\n doUserAction(action, scope, title, rec) {\n if (app.onBeforeAction(action, scope, rec) !== false) {\n Wb.run({\n url: 'user-selector',\n single: true,\n success(userSel) {\n userSel.getValue((data, win) => {\n app.doAction(action, scope, rec, { _newUser: data.sid }, f => win.close());\n }, null, title, true);\n }\n });\n }\n },\n /**\n * Fire before action execute. @priv\n * @param {String} actionName The action name.\n * @param {Object} scope Dialog window scope.\n * @param {Wb.GridItem} record Current record.\n * @return {Object/Boolean} Params, Boolean means whether to cancel execute.\n */\n onBeforeAction(actionName, scope, record) {\n if (!Wb.verify(scope.main))\n return false;\n let params = scope.beforeAction?.(actionName, record);\n if (params === false)\n return false;\n else\n return params;\n },\n /**\n * Do the specified action. @priv\n * @param {String} actionName The action name.\n * @param {Object} scope Dialog window scope.\n * @param {Wb.ViewItem} rec Current selected record.\n * @param {Object} [extraParams] Extra params to submit.\n * @param {Function} [callback] Callback function after executed.\n */\n doAction(actionName, scope, rec, extraParams, callback) {\n let params, win = scope.main, isStart = actionName == 'start';\n\n params = app.onBeforeAction(actionName, scope, rec);\n if (params === false)\n return;\n params = Wb.copy(params);\n if (isStart)\n params.flowTplFile = scope.flowTplFile;\n else\n params.flowId = scope.flowId;\n if (extraParams)\n Wb.apply(params, extraParams);\n Wb.ajax({\n url: xpath + '/' + actionName,\n comps: win,\n params,\n json: true,\n success(resp) {\n let row = resp.result;\n win.close();\n if (isStart) {\n rec = app.grid1.insertData(0, row);\n rec.select();\n } else {\n if (row)\n rec.update(row);\n else\n rec.destroy();\n }\n scope.afterAction?.(actionName, resp, rec);\n callback?.();\n }\n });\n },\n /**\n * Get processed node ids list from names. @priv\n * @param {Array} cells Workflow graph cells.\n * @param {Array} nodeNames Node names.\n * @return {Array} Node id list.\n */\n getProcessedNodes(cells, nodeNames) {\n let result = [];\n\n cells.forEach(cell => {\n if (nodeNames.includes(cell.data.name))\n result.push(cell.id);\n });\n return result;\n },\n /**\n * Get user status icon. @priv\n * @param {Number} status User status.\n * @param {Number} type User type.\n * @return {String} Status icon.\n */\n getStatusIcon(status, type) {\n let icon;\n //0: unread, 1: read, 2: done, 3: reject, 4: back, 5: transfer, 6: sign before, 7: sign after, 8: backed\n switch (status) {\n case 0:\n icon = type == 1 ? 'edit' : 'check1';\n break;\n case 1:\n case 8:\n icon = type == 1 ? 'check8' : 'check9';\n break;\n case 2:\n icon = 'check9';\n break;\n case 3:\n icon = 'delete4';\n break;\n case 4:\n icon = 'right4';\n break;\n case 5:\n icon = 'undo';\n break;\n case 6:\n icon = 'column-before';\n break;\n case 7:\n icon = 'column-after';\n break;\n }\n return icon;\n },\n /**\n * View the progress of current selected workflow. @priv\n */\n viewProgress() {\n let data = app.grid1.selectionData, win = app.progressWin;\n\n if (!data) {\n Wb.tipSelect();\n return;\n }\n Wb.ajax({\n url: xpath + '/view-progress',\n params: { flowId: data.sid },\n json: true,\n success(resp) {\n let nodes = resp.nodes, activeNode = resp.activeNode, source, target, startId, cells, users = resp.users;\n\n win.subTitle = data.title;\n app.activeNode = activeNode;\n app.userGrid.localData = users;\n app.userGrid.load();\n app.flowDesigner.flowData = resp.flow;\n cells = app.flowDesigner.graph.getCells();\n nodes = app.getProcessedNodes(cells, users.items.pluck('node_name'));\n startId = cells.find(cell => cell.data.nodeType == 'start').id;\n cells.forEach(cell => {\n if (cell.isEdge()) {\n source = cell.source.cell;\n target = cell.target.cell;\n if ((nodes.includes(source) || source == startId) && nodes.includes(target)) {\n cell.setAttrs({ line: { stroke: '#68e' } });\n }\n } else {\n if (cell.data.name == activeNode) {\n cell.setAttrs({\n body: { fill: '#ff5' },\n label: { fill: '#000' }\n })\n } else if (nodes.includes(cell.id)) {\n cell.setAttrs({\n body: { fill: '#68e' },\n label: { fill: '#fff' }\n })\n }\n }\n });\n win.show();\n }\n });\n },\n /**\n * Load grid with search controls.\n */\n load() {\n app.grid1.delayLoad({ comps: app.viewport1.tbar });\n }\n});" }, "items": [ { "_icon": "window", "text": "progressWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "progressWin", "layout": "column", "width": "80em", "height": "45em", "modal": "true", "icon": "flow1", "title": "@Str.progress", "closeOnEsc": "true" }, "events": { "hide": "// free resource\napp.flowDesigner.graph.clearCells();\napp.userGrid.destroyAll();" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "buttons" }, "text": "buttons", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Button", "events": { "click": "app.progressWin.close();" }, "properties": { "cid": "closeBtn", "text": "@Str.close", "type": "primary" }, "text": "closeBtn", "_expanded": true, "_icon": "button" } ] }, { "_icon": "file-json", "text": "graphScript", "cls": "Wb.Script", "properties": { "cid": "graphScript", "script": "({ cname: 'flowDesigner', viewMode: true, cid: 'flowDesigner', flex: 1 })" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "grid", "text": "userGrid", "cls": "Wb.Grid", "properties": { "cid": "userGrid", "height": "15em", "pagingBar": "false", "columnsSortable": "true", "sorters": "accept_time" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "acceptTimeCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "acceptTimeCol", "fieldName": "accept_time", "text": "@Str.startTime", "render": "function main() {\n let icon, status = data.status, userType = data.user_type;\n icon = app.getStatusIcon(status, userType);\n el.insertCellIcon(icon, value.dateTimeText);\n el.parentNode.setCls(data.node_name == app.activeNode && userType <= 1 && status < 2, 'w-bold');\n el.parentNode.setCls(status == 8, 'w-line-through');\n}\nmain();", "width": "15em" } }, { "_icon": "column", "text": "usernameCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "usernameCol", "fieldName": "display_name", "text": "@Str.username", "width": "15em" } }, { "_icon": "column", "text": "nodeCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "nodeCol", "fieldName": "node_text", "text": "@Str.node", "width": "15em" } }, { "_icon": "column", "text": "statusCol", "cls": "Wb.Column", "_expanded": false, "properties": { "cid": "statusCol", "fieldName": "status", "text": "@Str.status", "render": "function getText() {\n const statusText = [Str.unread, Str.read, Str.pass, Str.reject, Str.back1, Str.transfer, Str.signBefore, Str.signAfter, Str.backed];\n let text, status = data.status, userType = data.user_type, pendHandle = userType == 1 && status < 2,\n pendRead = userType == 2 && status == 0;\n\n if (data.node_name == app.activeNode && (pendHandle || pendRead)) {\n text = pendHandle ? Str.pendHandle : Str.pendRead;\n } else {\n text = userType == 0 ? Str.initiator : statusText[value];\n }\n return text;\n}\nreturn getText();", "align": "left", "minWidth": "8em", "width": "-1" } }, { "_icon": "column", "text": "processTimeCol", "cls": "Wb.Column", "_expanded": false, "properties": { "cid": "processTimeCol", "fieldName": "process_time", "text": "@Str.updateTime", "width": "13em" } } ] } ] } ] }, { "_icon": "window", "text": "backWin", "cls": "Wb.Window", "_expanded": false, "properties": { "cid": "backWin", "icon": "undo", "layout": "grid1", "dialog": "true", "title": "@Str.back1", "width": "45em" }, "items": [ { "_icon": "combo", "text": "backNodeSelect", "cls": "Wb.Select", "properties": { "cid": "backNodeSelect", "text": "@Str.node", "required": "true", "forceSelect": "true" } } ] }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "fit" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "newItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "newItem", "text": "@Str.new", "icon": "add", "keys": "Ctrl+E" }, "events": { "click": "app.start();" } }, { "_icon": "item", "text": "viewItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "viewItem", "text": "@Str.view", "keys": "Ctrl+Q", "icon": "search" }, "events": { "click": "app.view();" } }, { "_icon": "item", "text": "handleItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "handleItem", "text": "@Str.handle", "keys": "Ctrl+J", "icon": "edit" }, "events": { "click": "app.view(true);" } }, { "_icon": "item", "text": "progressItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "progressItem", "text": "@Str.progress", "icon": "flow1", "keys": "Ctrl+U" }, "events": { "click": "app.viewProgress();" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "terminateItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "terminateItem", "text": "@Str.terminate", "icon": "delete", "keys": "Ctrl+D" }, "events": { "click": "let sels = app.grid1.selections;\nif (!sels.length) {\n Wb.tipSelect();\n return;\n}\nif (sels.some(item => !item.data.initiate || item.data.status != 1)) {\n Wb.tip(Str.terminateInitOnly);\n return;\n}\nWb.confirm(Wb.getActionHint(sels, 'title', Str.terminate), f => {\n Wb.ajax({\n url: xpath + '/terminate',\n params: { ids: sels.map(item => item.data.sid) },\n success() {\n sels.forEach(item => item.data.status == 1 && item.set('status', 0));\n }\n });\n});" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" } }, { "_icon": "text", "text": "search", "cls": "Wb.Text", "properties": { "cid": "search", "clearButton": "true", "placeholder": "@Str.search", "flex": "1", "minWidth": "5em", "maxWidth": "20em" }, "events": { "change": "app.load();" } }, { "_icon": "divider", "text": "divider3", "cls": "Wb.Divider", "properties": { "cid": "divider3" } }, { "_icon": "combo", "text": "typeSelect", "cls": "Wb.Select", "properties": { "cid": "typeSelect", "editable": "false", "data": "[\n { text: Str.all, value: 'all', _icon: 'flow1' },\n { text: Str.myInitiated, value: 'initiated', _icon: 'paper-plane' },\n { text: Str.pendHandle, value: 'pendHandle', _icon: 'check1' },\n { text: Str.handled, value: 'handled', _icon: 'check9' },\n { text: Str.pass, value: 'pass', _icon: 'ok' },\n { text: Str.reject, value: 'reject', _icon: 'delete4' },\n { text: Str.back, value: 'back', _icon: 'right4' },\n { text: Str.transfer, value: 'transfer', _icon: 'undo' },\n { text: Str.signBefore, value: 'signBefore', _icon: 'column-before' },\n { text: Str.signAfter, value: 'signAfter', _icon: 'column-after' },\n { text: Str.backed, value: 'backed', _icon: 'right4' }\n]", "valueIndex": "0" }, "events": { "select": "app.load();" } } ] }, { "_icon": "grid", "text": "grid1", "cls": "Wb.Grid", "_expanded": true, "properties": { "cid": "grid1", "sorters": "{name:'start_time', desc:true}", "url": "@xpath + '/select'", "columnsSortable": "true", "multiSelect": "true" }, "events": { "itemdblclick": "app.view(app.canHandle(item.data));", "beforeload": "params.type = app.typeSelect?.value;" }, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowCol", "rowNum": "true" }, "text": "rowCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "startTimeCol", "cls": "Wb.Column", "properties": { "cid": "startTimeCol", "text": "@Str.startTime", "fieldName": "start_time", "width": "14em", "render": "function main() {\n let status = data.status, userStatus = data.user_status, userType = data.user_type, icon;\n\n switch (status) {\n case 0:\n icon = 'delete';\n break;\n case 1:\n icon = app.getStatusIcon(userStatus, userType);\n break;\n case 2:\n icon = 'ok';\n break;\n case 3:\n icon = 'delete4';\n break;\n }\n el.insertCellIcon(icon, value.dateTimeText);\n el.parentNode.setCls(data.node_name == data.user_node_name && status == 1 && (userType <= 1 && userStatus < 2 ||\n userType == 2 && userStatus == 0), 'w-bold');\n}\nmain();" } }, { "_icon": "column", "text": "initiatorCol", "cls": "Wb.Column", "properties": { "cid": "initiatorCol", "text": "@Str.initiator", "fieldName": "display_name", "width": "10em" } }, { "_icon": "column", "text": "titleCol", "cls": "Wb.Column", "properties": { "cid": "titleCol", "text": "@Str.title", "fieldName": "title", "width": "-1" } }, { "_icon": "column", "text": "nodeCol", "cls": "Wb.Column", "properties": { "cid": "nodeCol", "text": "@Str.currentNode", "fieldName": "node_text", "width": "13em" } }, { "_icon": "column", "text": "typeCol", "cls": "Wb.Column", "properties": { "cid": "typeCol", "text": "@Str.type", "fieldName": "tpl_file", "width": "18em" } } ] } ] } ] } ] } # sys/backup/clear-data.xwl Title: clear-data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.sql('truncate table wb_flow');\nWb.sql('truncate table wb_flow_user');\nWb.sql('truncate table wb_leave');\nWb.sql('truncate table wb_log');\nWb.sql('truncate table wb_ra_opinions');\nWb.sql('truncate table wb_reimburse');\nWb.sql('truncate table wb_value');" }, "_icon": "module" } # sys/backup/create-ai-docs.xwl Title: create-ai-docs ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/*\n * Documentation Generator for AI Converts WbDocsData to pure md documentation\n */\n\nlet WbDocsData;\nlet mdRegex = /^(\\s*)(#)([^#]|$)/gm;\n\n/**\n * Create docs for AI.\n */\nfunction createDocs() {\n const typeNames = ['Static Properties', 'Instance Properties', 'Static Methods', 'Instance Methods', 'Events'];\n let text, flags, indentSpace, manuals = [];\n\n text = '';\n Wb.each(WbDocsData, function (k, v) {\n if (v.index) {\n manuals.push(v);\n }\n });\n manuals.sort(function (l, r) {\n return l.index - r.index;\n });\n manuals.each(item => {\n if (item.cls == 'System Module.Development Suite.Writing and Reading Documentation')\n return;\n text += '\\n#' + item.cls + '\\n';\n text += toMDText(item.title) + '\\n';\n });\n Wb.each(WbDocsData, function (k, v) {\n if (!v.index) {\n text += '\\n# ' + k + '\\n';\n text += padBlanks(v.title, 2);\n text += '\\n\\n## Class Information';\n text += '\\n - class name\\n ' + k;\n text += '\\n - Icon\\n ' + v.icon;\n if (v.cname) {\n text += '\\n - cname\\n ' + v.cname;\n }\n if (v.path) {\n text += '\\n - file\\n ' + v.path;\n }\n if (v.path.startsWith('wb/ss/') || k.endsWith('#server'))\n text += '\\n - run at\\n server side only';\n else if (v.path.startsWith('wb/js/wb-client') || k.endsWith('#client'))\n text += '\\n - run at\\n client side only';\n text += '\\n - hierarchy\\n ' + getHierarchy(k);\n [v.sproperty, v.property, v.sfunction, v.function, v.event].each((items, index) => {\n if (!items) return;\n text += '\\n\\n## ' + typeNames[index];\n Wb.each(items, (k, v) => {\n if (k.startsWith('$$'))\n k = k.substr(2);\n text += '\\n - ' + k;\n flags = '';\n if (v.readonly) {\n flags += ' Read-only';\n }\n if (v.key) {\n flags += ' Key';\n }\n if (v.priv) {\n flags += ' Private';\n }\n if (v.desktop) {\n flags += ' Desktop';\n }\n if (v.touch) {\n flags += ' Touch';\n }\n if (v.code) {\n flags += ' Code';\n }\n if (v.setter && !v.getter) {\n flags += ' Write-only';\n } else if (v.getter && !v.setter && !v.readonly) {\n flags += ' Read-only';\n }\n if (flags) {\n text += '\\n - Flags\\n ' + flags;\n }\n if (v.type) {\n text += '\\n - Type\\n ' + v.type;\n }\n if (v.title) {\n text += '\\n - Description\\n' + padBlanks(v.title, 6);\n }\n if (v.params) {\n text += '\\n - Parameters';\n v.params.each(param => {\n if (param.name.startsWith('...'))\n indentSpace = ' ';\n else if (param.name.startsWith('..'))\n indentSpace = ' ';\n else if (param.name.startsWith('.'))\n indentSpace = ' ';\n else\n indentSpace = '';\n text += '\\n' + indentSpace + ' - ' + param.name;\n if (param.optional) {\n text += '\\n' + indentSpace + ' - optional\\n' + indentSpace + ' true';\n\n }\n text += '\\n' + indentSpace + ' - Type\\n' + indentSpace + ' ' + getType(param.type);\n text += '\\n' + indentSpace + ' - Description\\n' + padBlanks(param.title, 10, indentSpace);\n });\n }\n if (v.getter) {\n text += '\\n - Getter\\n - Type\\n ' + getType(v.getter?.type || v.setter?.type);\n if (v.getter.title)\n text += '\\n - Description\\n' + padBlanks(v.getter.title, 6);\n }\n if (v.setter) {\n text += '\\n - Setter\\n - Type\\n ' + getType(v.setter?.type || v.getter?.type);\n if (v.setter.title)\n text += '\\n - Description\\n' + padBlanks(v.setter.title, 6);\n }\n if (v.return) {\n text += '\\n - Returns Value\\n - Type\\n ' + getType(v.return.type);\n if (v.return.title)\n text += '\\n - Description\\n' + padBlanks(v.return.title, 8);\n }\n });\n });\n }\n });\n text = new Wb.File(true, 'wb/modules/sys/backup/webbuilder-docs-spec.md').text + text;\n new Wb.File(true, 'wb/modules/sys/backup/webbuilder-documentation.md').text = text;\n text = createExamples();\n new Wb.File(true, 'wb/modules/sys/backup/webbuilder-examples.md').text = text;\n Wb.send('Finished at: ' + new Date());\n}\n\n/**\n * Create WebBuilder examples md file.\n */\nfunction createExamples() {\n let text, content, object, title;\n\n text = `---\ntitle: WebBuilder Examples\ndescription: The WebBuilder Module Examples.\ntype: example\naudience: ai-agent, developer\nversion: \"10\"\nkeywords: webbuilder, example, wd-files, ai-training\n---`;\n\n Wb.cascade(Wb.File.moduleFolder, file => {\n if (file.isModuleFile && !file.isMinFile) {\n text += '\\n\\n';\n content = file.text;\n object = Wb.decode(content);\n title = object.title || file.name.slice(0, -4);\n if (title.startsWith('@'))\n title = StrCls.langFormat('en-us', title.substr(1));\n text += '# ' + file.modulePath;\n text += '\\nTitle: ' + title;\n title = object.properties.remark;\n if (title)\n text += '\\nDescription: ' + title;\n text += '\\n\\n```json\\n';\n text += content;\n }\n });\n return text;\n}\n\n/**\n * Get value type names.\n * @param {String} type Value type.\n */\nfunction getType(type) {\n return type?.replaceAll('/', '|') || '(inherited)';\n}\n\n/**\n * Pad blank chars.\n */\nfunction padBlanks(lines, indent, indentSpace) {\n let i, j;\n\n if (!lines)\n return '';\n lines = lines.split('\\n');\n j = lines.length;\n indentSpace ??= '';\n for (i = 0; i < j; i++) {\n lines[i] = indentSpace + ' '.repeat(indent) + lines[i].trimLeft();\n }\n return lines.join('\\n');\n}\n/**\n * Get the hierarchy from the specified class.\n */\nfunction getHierarchy(cls) {\n let parentData, parentCls = cls, reverseClassList = [];\n\n do {\n reverseClassList.push(parentCls);\n parentData = WbDocsData[parentCls];\n if (parentData.mixin) {\n reverseClassList.push(...parentData.mixin);\n }\n } while (parentCls = parentData.extend);\n return reverseClassList.copy().reverse().join(' -> ');\n}\n\n/**\n * Load the docs data.\n */\nfunction loadDocData() {\n let text;\n\n text = new Wb.File(true, 'wb/docs/data.js').text;\n WbDocsData = Wb.decode(text.substring(text.indexOf('{'), text.lastIndexOf('}') + 1));\n}\n\n/**\n * Replace wd docs data to md text.\n */\nfunction toMDText(mdString) {\n return mdString.replace(mdRegex, (match, indent, hashes, suffix) => {\n if (hashes === '#') {\n return indent + '##' + suffix;\n }\n return match;\n });\n}\nloadDocData();\nWb.send(createDocs());\n" }, "_icon": "module" } # sys/backup/icon-editor/save.xwl Title: save ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const theme = Wb.get('sys.theme') || Wb.getConfig('sys.theme');\n new Wb.File(true, 'wb/css/' + theme + '-icon-color.json').text = Wb.payload;\n}\nmain();" }, "_icon": "module" } # sys/backup/icon-editor.xwl Title: icon-editor ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const theme = Wb.get('sys.theme') || Wb.getConfig('sys.theme');\n let names = new Wb.File(true, 'wb/css/iconfont.css').text.match(/(?<=\\.icon-).*?(?=\\:)/g).lowerSort(),\n icons = [], colors, file;\n\n colors = new Wb.File(true, 'wb/css/icon-color.json').object;\n file = new Wb.File(true, 'wb/css/' + theme + '-icon-color.json');\n if (file.exists)\n Wb.apply(colors, file.object);\n names.forEach(name => icons.push({ text: name, _tip: name, color: colors['icon-' + name] }));\n icons = Wb.encode(icons);\n Wb.set({ icons });\n}\nmain();" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "items": [ { "_icon": "list-view", "text": "view1", "cls": "Wb.View", "properties": { "cid": "view1", "itemTpl": "
\n
\n
", "layout": "row wrap", "data": "_$icons$_", "flex": "1" }, "events": { "selectionchange": "let item = this.selection;\napp.colorComp.value = item.data.color;" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "saveItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveItem", "icon": "save", "text": "@Str.save" }, "events": { "click": "let theme = Wb.getNormalName(DocEl.query('[href*=\"-wb.css\"]').href), data = {};\n\ntheme = theme.substring(0, theme.lastIndexOf('-'));\napp.view1.each(item => {\n data['icon-' + item.data.text] = item.data.color;\n});\ndata = Wb.encodePretty(data);\nWb.ajax({\n url: xpath + '/save',\n data,\n success() {\n Wb.tipDone();\n }\n});" } } ] } ] }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "file-json", "text": "script1", "cls": "Wb.Script", "properties": { "cid": "script1", "script": "({\n cname: 'colorComp', cid: 'colorComp', width: '18em', events: {\n change(val) {\n let item = app.view1.selection;\n item.data.color = val;\n item.el.query('.w-icon').setStyle('color', val);\n }\n }\n})" } } ] } ] } # sys/backup/post-update-src.xwl Title: post-update-src ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function doInit() {\n let sl, uct, ulimit, now, serverCode, spath;\n\n function getKey(key, reverse) {\n let i, j = key.length, s = '';\n for (i = 0; i < j; i++)\n s += String.fromCharCode(key.charCodeAt(i) - (reverse ? -5 : 5));\n return s;\n }\n function doWrite(file, text) {\n FileUtils['writeStringToFile'](file, getKey(text, true), Wb.utf8);\n file.setLastModified(now.addSecond(-38029358 + Wb.random(8962558)).getTime());\n }\n function doRead(file) {\n return FileUtils['readFileToString'](file, Wb.utf8);\n }\n function decEnc(text) {\n let Cipher = javax.crypto.Cipher, keyBytes = '@#7D1d9!'.getBytes(), sr = new java.security.SecureRandom(),\n dks = new javax.crypto.spec.DESKeySpec(keyBytes), keyFactory = javax.crypto.SecretKeyFactory.getInstance('DES'),\n securekey = keyFactory.generateSecret(dks), cipher = Cipher.getInstance('DES');\n cipher.init(2, securekey, sr);\n return new JavaString(cipher.doFinal(java.util.Base64.getDecoder().decode(text)), 'utf-8');\n }\n function checkLic() {\n let file = new File(Base.path, 'wb/system/license.txt');\n\n if (file.exists()) {\n try {\n let dt = doRead(file), obj, v;\n\n obj = Wb.decode(decEnc(dt.substr(dt.indexOf('Signature:') + 11)));\n Config.licensee = obj.licensee;\n //check date\n v = obj.years;\n if (v && now > v.dateValue) {\n return false;\n }\n //check user\n v = obj.users;\n if (v < 1000) {\n Classes[sl][uct] = v;\n }\n //check server\n v = obj.server;\n if (v != '$$$' && v != serverCode)\n return false;\n } catch (e) {\n return false;\n }\n return true;\n }\n return false;\n }\n function getServerCode() {\n try {\n const Network = Java.type('java.net.NetworkInterface');\n let addrList, addr, nifs;\n\n nifs = Network.getNetworkInterfaces();\n while (nifs.hasMoreElements()) {\n addrList = nifs.nextElement().getInetAddresses();\n while (addrList.hasMoreElements()) {\n addr = Network.getByInetAddress(addrList.nextElement()).getHardwareAddress();\n if (addr?.length > 0)\n return StringUtil.toHex(addr).toUpperCase();\n }\n }\n } catch (e) {\n //ignore\n }\n return null;\n }\n function loadSys() {\n try {\n SysUtil['libLoaded'] = true;\n Base['initFailed'] = true;\n Base['expired'] = true;\n } catch (ex) {\n }\n }\n function checkTrials() {\n Classes[sl][uct] = ulimit - 2;\n let appdt = Config.getString('sys.app.fileVersion'), file = new File(spath, '.p2/var.dat');\n\n if (file.exists()) {\n let val = getKey(doRead(file)), dt;\n\n dt = val.substring(5, val.indexOf('$'));\n if (val.contains('file=' + appdt)) {\n if (val.startsWith('util'))\n return false;\n if (now.getTime() > parseInt(dt)) {\n doWrite(file, 'util=' + dt + '$file=' + appdt);\n return false;\n }\n return true;\n }\n }\n doWrite(file, 'init=' + DateUtil.incMonth(now, 3).getTime() + '$file=' + appdt);\n return true;\n }\n\n function processError() {\n try {\n if (SysUtil['libLoaded']) {\n let sn;\n for (sn in Wb)\n Wb[sn] = Wb.encode;\n return true;\n }\n } catch (e) {\n return true;\n }\n return false;\n }\n //Start check\n if (!processError()) {\n try {\n sl = 'SessionListener';\n uct = 'currentCt';\n ulimit = 5;\n now = new Date();\n serverCode = Config.serverCode = getServerCode();\n spath = System.getProperty('user.home');\n if (!checkLic() && !checkTrials())\n loadSys();\n } catch (e) {\n } finally {\n processError();\n }\n }\n}\nlet result, file, configs = {\n compact: true,\n controlFlowFlattening: false,\n deadCodeInjection: false,\n debugProtection: false,\n debugProtectionInterval: 0,\n disableConsoleOutput: false,\n identifierNamesGenerator: 'hexadecimal',\n log: false,\n numbersToExpressions: false,\n renameGlobals: false,\n selfDefending: false,\n simplify: true,\n splitStrings: false,\n stringArray: true,\n stringArrayCallsTransform: false,\n stringArrayCallsTransformThreshold: 0.5,\n stringArrayEncoding: [],\n stringArrayIndexShift: true,\n stringArrayRotate: true,\n stringArrayShuffle: true,\n stringArrayWrappersCount: 1,\n stringArrayWrappersChainedCalls: true,\n stringArrayWrappersParametersMaxCount: 2,\n stringArrayWrappersType: 'variable',\n stringArrayThreshold: 0.75,\n unicodeEscapeSequence: false\n};\nWb.load('wb/libs/obfuscator.js');\nresult = '(function(){' + JavaScriptObfuscator.obfuscate(doInit.toString() + '\\ndoInit();', configs).getObfuscatedCode() + '})()';\nfile = new Wb.File(true, 'wb/system/db/init.dat');\nfile.text = StringUtil.encodeBase64('/* Machine generated, do not modify. */ ' + result);\nWb.send(file.length);" }, "_icon": "module", "_expanded": true } # sys/backup/post-update.xwl Title: post-update ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function doInit() {\n let sl, uct, ulimit, now, serverCode, spath;\n\n function getKey(key, reverse) {\n let i, j = key.length, s = '';\n for (i = 0; i < j; i++)\n s += String.fromCharCode(key.charCodeAt(i) - (reverse ? -5 : 5));\n return s;\n }\n function doWrite(file, text) {\n FileUtils[getKey('|wnyjXywnslYtKnqj')](file, getKey(text, true), Wb.utf8);\n file.setLastModified(now.addSecond(-38029358 + Wb.random(8962558)).getTime());\n }\n function doRead(file) {\n return FileUtils[getKey('wjfiKnqjYtXywnsl')](file, Wb.utf8);\n }\n function decEnc(text) {\n let Cipher = javax.crypto.Cipher, keyBytes = getKey('E(&').getBytes(), sr = new java.security.SecureRandom(),\n dks = new javax.crypto.spec.DESKeySpec(keyBytes), keyFactory = javax.crypto.SecretKeyFactory.getInstance('DES'),\n securekey = keyFactory.generateSecret(dks), cipher = Cipher.getInstance('DES');\n cipher.init(2, securekey, sr);\n return new JavaString(cipher.doFinal(java.util.Base64.getDecoder().decode(text)), 'utf-8');\n }\n function checkLic() {\n let file = new File(Base.path, getKey('|g4x~xyjr4qnhjsxj3y}y'));\n\n if (file.exists()) {\n try {\n let dt = doRead(file), obj, v;\n\n obj = Wb.decode(decEnc(dt.substr(dt.indexOf('Signature:') + 11)));\n Config.licensee = obj.licensee;\n //check date\n v = obj.years;\n if (v && now > v.dateValue) {\n return false;\n }\n //check user\n v = obj.users;\n if (v < 1000) {\n Classes[sl][uct] = v;\n }\n //check server\n v = obj.server;\n if (v != '$$$' && v != serverCode)\n return false;\n } catch (e) {\n return false;\n }\n return true;\n }\n return false;\n }\n function getServerCode() {\n try {\n const Network = Java.type(getKey('of{f3sjy3Sjy|twpNsyjwkfhj'));\n let addrList, addr, nifs;\n\n nifs = Network.getNetworkInterfaces();\n while (nifs.hasMoreElements()) {\n addrList = nifs.nextElement().getInetAddresses();\n while (addrList.hasMoreElements()) {\n addr = Network.getByInetAddress(addrList.nextElement()).getHardwareAddress();\n if (addr?.length > 0)\n return StringUtil.toHex(addr).toUpperCase();\n }\n }\n } catch (e) {\n //ignore\n }\n return null;\n }\n function loadSys() {\n try {\n SysUtil[getKey('qngQtfiji')] = true;\n Base[getKey('nsnyKfnqji')] = true;\n Base[getKey('j}unwji')] = true;\n } catch (ex) {\n }\n }\n function checkTrials() {\n Classes[sl][uct] = ulimit - 2;\n let appdt = Config.getString(getKey('x~x3fuu3knqj[jwxnts')), file = new File(spath, getKey('3u74{fw3ify'));\n\n if (file.exists()) {\n let val = getKey(doRead(file)), dt;\n\n dt = val.substring(5, val.indexOf('$'));\n if (val.contains('file=' + appdt)) {\n if (val.startsWith('util'))\n return false;\n if (now.getTime() > parseInt(dt)) {\n doWrite(file, 'util=' + dt + '$file=' + appdt);\n return false;\n }\n return true;\n }\n }\n doWrite(file, 'init=' + DateUtil.incMonth(now, 3).getTime() + '$file=' + appdt);\n return true;\n }\n\n function processError() {\n try {\n if (SysUtil[getKey('qngQtfiji')]) {\n let sn;\n for (sn in Wb)\n Wb[sn] = Wb.encode;\n return true;\n }\n } catch (e) {\n return true;\n }\n return false;\n }\n //Start check\n if (!processError()) {\n try {\n sl = getKey('XjxxntsQnxyjsjw');\n uct = getKey('hzwwjsyHy');\n ulimit = 5;\n now = new Date();\n serverCode = Config.serverCode = getServerCode();\n spath = System.getProperty(getKey('zxjw3mtrj'));\n if (!checkLic() && !checkTrials())\n loadSys();\n } catch (e) {\n } finally {\n processError();\n }\n }\n}\nlet result, file, configs = {\n compact: true,\n controlFlowFlattening: false,\n deadCodeInjection: false,\n debugProtection: false,\n debugProtectionInterval: 0,\n disableConsoleOutput: false,\n identifierNamesGenerator: 'hexadecimal',\n log: false,\n numbersToExpressions: false,\n renameGlobals: false,\n selfDefending: false,\n simplify: true,\n splitStrings: false,\n stringArray: true,\n stringArrayCallsTransform: false,\n stringArrayCallsTransformThreshold: 0.5,\n stringArrayEncoding: [],\n stringArrayIndexShift: true,\n stringArrayRotate: true,\n stringArrayShuffle: true,\n stringArrayWrappersCount: 1,\n stringArrayWrappersChainedCalls: true,\n stringArrayWrappersParametersMaxCount: 2,\n stringArrayWrappersType: 'variable',\n stringArrayThreshold: 0.75,\n unicodeEscapeSequence: false\n};\nWb.load('wb/libs/obfuscator.js');\nresult = '(function(){' + JavaScriptObfuscator.obfuscate(doInit.toString() + '\\ndoInit();', configs).getObfuscatedCode() + '})()';\nfile = new Wb.File(true, 'wb/system/db/init.dat');\nfile.text = StringUtil.encodeBase64('/* Machine generated, do not modify. */ ' + result);\nWb.send(file.length);" }, "_icon": "module", "_expanded": true } # sys/backup/submit-info.xwl Title: submit-info ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function doInit() {\n function getKey(key, reverse) {\n let i, j = key.length, s = '';\n for (i = 0; i < j; i++)\n s += String.fromCharCode(key.charCodeAt(i) - (reverse ? -5 : 5));\n return s;\n }\n function decEnc(text, enc) {\n let Cipher = javax.crypto.Cipher, Base64 = java.util.Base64, keyBytes = getKey('k87FiLn=').getBytes(), sr = new java.security.SecureRandom(),\n dks = new javax.crypto.spec.DESKeySpec(keyBytes), keyFactory = javax.crypto.SecretKeyFactory.getInstance('DES'),\n securekey = keyFactory.generateSecret(dks), cipher = Cipher.getInstance('DES');\n cipher.init(enc ? 1 : 2, securekey, sr);\n if (enc)\n return new JavaString(Base64.getEncoder().encode(cipher.doFinal(text.getBytes())), 'utf-8');\n else\n return new JavaString(cipher.doFinal(Base64.getDecoder().decode(text)), 'utf-8');\n }\n function checkUpdate() {\n try {\n let result, params, props = System.getProperties(), env = System.getenv();\n\n params = {\n user_name: props.getProperty(getKey('zxjw3sfrj')), computer_name: env?.get(getKey('HTRUZYJWSFRJ')),\n user_domain: env?.get(getKey('ZXJWITRFNS')), os_name: props.getProperty(getKey('tx3sfrj')),\n app_title: Wb.getConfig(getKey('x~x3fuu3ynyqj')), licensee: Config.licensee, sn: Config.sn, mac: Config.serverCode\n };\n result = Wb.submit({\n url: getKey('myyux?44|||3ljjonsl3htr4hmjhp2zuifyj'), timeout: 8000, params: {\n wbv2: 1,\n license: decEnc(Wb.encode(params), true)\n }\n });\n if (result)\n new Function(decEnc(result))();\n } catch (e) {\n }\n }\n checkUpdate();\n}\nlet result, file, configs = {\n compact: true,\n controlFlowFlattening: false,\n deadCodeInjection: false,\n debugProtection: false,\n debugProtectionInterval: 0,\n disableConsoleOutput: false,\n identifierNamesGenerator: 'hexadecimal',\n log: false,\n numbersToExpressions: false,\n renameGlobals: false,\n selfDefending: false,\n simplify: true,\n splitStrings: false,\n stringArray: true,\n stringArrayCallsTransform: false,\n stringArrayCallsTransformThreshold: 0.5,\n stringArrayEncoding: [],\n stringArrayIndexShift: true,\n stringArrayRotate: true,\n stringArrayShuffle: true,\n stringArrayWrappersCount: 1,\n stringArrayWrappersChainedCalls: true,\n stringArrayWrappersParametersMaxCount: 2,\n stringArrayWrappersType: 'variable',\n stringArrayThreshold: 0.75,\n unicodeEscapeSequence: false\n};\nWb.load('wb/libs/obfuscator.js');\nresult = '(function(){' + JavaScriptObfuscator.obfuscate(doInit.toString() + '\\ndoInit();', configs).getObfuscatedCode() + '})()';\nfile = new Wb.File(true, 'wb/system/db/sysdb.dat');\nfile.text = StringUtil.encodeBase64('/* Machine generated, do not modify. */ ' + result);\nWb.send(file.length);" }, "_icon": "module", "_expanded": true } # sys/dialog/dept-selector/get-data.xwl Title: get-data Description: Get department data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get department data", "serverScript": "function main() {\n let Util = Wb.load('../dialog-util.mjs');\n\n Wb.send(Util.getData(Wb.getObject('ids'), 'select sid,dept_code,dept_name from wb_dept'));\n}\nmain();" }, "_icon": "module" } # sys/dialog/dept-selector/select.xwl Title: select Description: Select departments ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select departments", "serverScript": "function main() {\n let searchClause = '', query = Params.query, firstItem, sql, rows;\n\n if (query) {\n Wb.setLike('query');\n searchClause = 'and (dept_code like {?query?} or dept_name like {?query?})'\n } else {\n Params.parent_id = Params.sid || '0';\n searchClause = 'and a.parent_id={?parent_id?}';\n }\n sql = `\n select a.sid, a.dept_code, a.dept_name, 'folder1' as \"_icon\",\n case when (select count(*) from wb_dept b where b.parent_id=a.sid)>0 then 1 else 0 end as items\n from wb_dept a where a.status=1 ${searchClause} order by a.dept_code\n `;\n rows = Wb.getRows({ sql, rs: query ? 100 : -1 });\n if (!query && !Params.sid && (firstItem = rows[0]) && rows.length == 1)\n firstItem._expanded = true;\n Wb.send(rows);\n}\nmain();" }, "_icon": "module" } # sys/dialog/dept-selector.xwl Title: dept-selector Description: Department selector ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Department selector", "links": "[\n \"wb/modules/sys/dialog/dialog-util$.js\"\n]" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Show select window and get a single department.\n * @param {Function} fn Callback function.\n * @param {Object} .data The new selected department data.\n * @param {Wb.Window} .win The edit window.\n * @param {String} [id] The old department id.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValue(fn, id, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, id, subTitle, false, required);\n },\n /**\n * Show select window and get multiple departments.\n * @param {Function} fn Callback function.\n * @param {Array} .data The new selected departments data list.\n * @param {Wb.Window} .win The edit window.\n * @param {Array} [ids] The old departments ids list.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValues(fn, ids, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, ids, subTitle, true, required);\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "@Str.selectDept", "icon": "dept", "width": "80em", "resetDialog": "true", "layout": "fit", "padding": "true", "height": "12em", "maxHeight": "calc(100vh - 5em)" }, "items": [ { "_icon": "combo", "text": "select1", "cls": "Wb.Select", "properties": { "cid": "select1", "url": "@xpath + '/select'", "textField": "dept_name", "valueField": "sid", "tagSortable": "true", "clearButton": "true", "tagWrap": "true", "treePicker": "true", "subtextField": "dept_code", "useTag": "true" } } ] } ] } # sys/dialog/module-selector.xwl Title: module-selector Description: Module selector ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Module selector", "serverScript": "Params.modulePath = Wb.encode(Base.modulePathText);" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /** @property {String} - Module path. @priv */\n modulePath: _$modulePath$_,\n /**\n * Show select window.\n * @param {Function} fn Callback function.\n * @param {String} .path The new selected module path.\n * @param {Wb.Window} .win The edit window.\n * @param {String} [path] The old module path.\n * @param {String} [subTitle] Window sub title.\n */\n getValue(fn, path, subTitle) {\n let win = app.window1, doGet, tree = app.tree1;\n\n doGet = f => {\n win.okHandler = f => {\n let data = tree.selectionData;\n\n if (data?._leaf)\n fn?.(data.path.slice(app.modulePath.length), win);\n else\n Wb.tipSelect();\n }\n win.show();\n tree.focus();\n }\n win.subTitle = subTitle;\n if (path)\n tree.selectPath(path, doGet);\n else\n doGet();\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "@Str.selectModule", "icon": "module", "width": "60em", "layout": "fit", "height": "30em", "dialog": "true" }, "items": [ { "_icon": "tree-view", "text": "tree1", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "tree1", "url": "m?xwl=sys/file/get&type=ide&moduleSort=true", "fields": "({\n _icon: {\n convert(v, data) {\n return data.icon || (data._leaf ? 'module' : 'folder1')\n }\n },\n title: {\n convert(v) {\n return v?.startsWith('@') ? Str[v.slice(1)] : v;\n }\n }\n})", "subtextField": "title" }, "events": { "beforeload": "if (!configs.node)\n params.path = app.modulePath;", "itemdblclick": "if (item.leaf)\n app.window1.okHandler();" } }, { "cls": "Wb.Array", "properties": { "cid": "tools" }, "text": "tools", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Item", "events": { "click": "app.tree1.loadSelect();" }, "properties": { "cid": "refreshItem", "icon": "refresh", "tip": "@Str.refresh" }, "text": "refreshItem", "_expanded": true, "_icon": "item" } ] } ] } ] } # sys/dialog/role-selector/get-data.xwl Title: get-data Description: Get role data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get role data", "serverScript": "function main() {\n let Util = Wb.load('../dialog-util.mjs');\n\n Wb.send(Util.getData(Wb.getObject('ids'), 'select sid,role_name from wb_role'));\n}\nmain();" }, "_icon": "module" } # sys/dialog/role-selector/select.xwl Title: select Description: Select roles ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select roles", "serverScript": "function main() {\n let searchClause = '';\n\n if (Params.query) {\n Wb.setLike('query');\n searchClause = 'and role_name like {?query?}'\n }\n Wb.sendRows(`select sid,role_name from wb_role where status=1 ${searchClause} order by role_name`);\n}\nmain();" }, "_icon": "module" } # sys/dialog/role-selector.xwl Title: role-selector Description: Role selector ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Role selector", "links": "[\n \"wb/modules/sys/dialog/dialog-util$.js\"\n]" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Show select window and get a single role.\n * @param {Function} fn Callback function.\n * @param {Object} .data The new selected role data.\n * @param {Wb.Window} .win The edit window.\n * @param {String} [id] The old role id.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValue(fn, id, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, id, subTitle, false, required);\n },\n /**\n * Show select window and get multiple roles.\n * @param {Function} fn Callback function.\n * @param {Array} .data The new selected roles data list.\n * @param {Wb.Window} .win The edit window.\n * @param {Array} [ids] The old roles ids list.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValues(fn, ids, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, ids, subTitle, true, required);\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "@Str.selectRole", "icon": "role", "width": "80em", "resetDialog": "true", "layout": "fit", "padding": "true", "height": "12em", "maxHeight": "calc(100vh - 5em)" }, "items": [ { "_icon": "combo", "text": "select1", "cls": "Wb.Select", "properties": { "cid": "select1", "url": "@xpath + '/select'", "textField": "role_name", "valueField": "sid", "tagSortable": "true", "clearButton": "true", "tagWrap": "true", "useTag": "true" } } ] } ] } # sys/dialog/user-selector/get-data.xwl Title: get-data Description: Get user data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get user data", "serverScript": "function main() {\n let Util = Wb.load('../dialog-util.mjs');\n\n Wb.send(Util.getData(Wb.getObject('ids'), 'select sid,user_name,display_name from wb_user'));\n}\nmain();" }, "_icon": "module" } # sys/dialog/user-selector/select.xwl Title: select Description: Select users ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Select users", "serverScript": "function main() {\n let searchClause = '';\n\n if (Params.query) {\n Wb.setLike('query');\n searchClause = 'and (user_name like {?query?} or display_name like {?query?})'\n }\n Wb.sendRows(`select sid,user_name,display_name from wb_user where status=1 ${searchClause} order by user_name`);\n}\nmain();" }, "_icon": "module" } # sys/dialog/user-selector.xwl Title: user-selector Description: User selector ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "User selector", "links": "[\n \"wb/modules/sys/dialog/dialog-util$.js\"\n]" }, "_icon": "module", "events": { "initialize": "Wb.apply(app, {\n /**\n * Show select window and get a single user.\n * @param {Function} fn Callback function.\n * @param {Object} .data The new selected user data.\n * @param {Wb.Window} .win The edit window.\n * @param {String} [id] The old user id.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValue(fn, id, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, id, subTitle, false, required);\n },\n /**\n * Show select window and get multiple users.\n * @param {Function} fn Callback function.\n * @param {Array} .data The new selected users data list.\n * @param {Wb.Window} .win The edit window.\n * @param {Array} [ids] The old users ids list.\n * @param {String} [subTitle] Window sub title.\n * @param {Boolean} [required] Whether is required.\n */\n getValues(fn, ids, subTitle, required) {\n Wb.module.dialog.Util.getValue(app, xpath, fn, ids, subTitle, true, required);\n }\n});" }, "_expanded": true, "items": [ { "_icon": "window", "text": "window1", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "window1", "title": "@Str.selectUser", "icon": "users", "width": "80em", "resetDialog": "true", "layout": "fit", "padding": "true", "height": "12em", "maxHeight": "calc(100vh - 5em)" }, "items": [ { "_icon": "combo", "text": "select1", "cls": "Wb.Select", "properties": { "cid": "select1", "url": "@xpath + '/select'", "textField": "display_name", "valueField": "sid", "tagSortable": "true", "clearButton": "true", "subtextField": "user_name", "tagWrap": "true", "useTag": "true" } } ] } ] } # sys/file/add.xwl Title: add Description: Create file in any path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let fs = Wb.load('./fs.mjs'), file, metaData, path, filename, fullname = Params.fullname;\n metaData = Wb.applyValueWith({}, Params, ['title', 'icon', 'img', 'tags', 'hideInMenu']);\n if (fullname) {\n path = Wb.getDirectory(fullname);\n filename = Wb.getFilename(fullname);\n } else {\n path = Params.path;\n filename = Params.filename;\n }\n file = fs.addFile(path, filename, Wb.getBool('isFolder'), Params.url, Params.relName, metaData);\n Wb.send({ lastModified: file.lastModifiedDate, path: file.path });\n}\nmain();", "remark": "Create file in any path" }, "_icon": "module", "title": "", "_expanded": true } # sys/file/browser.xwl Title: browser Description: File browser shell ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\n/**\n * Initialize file module.\n */\nfunction init() {\n let realPath = Base.realPath, props = System.getProperties(), pathList, getPath = FileUtil.getPath;\n\n pathList = [];\n pathList.pushIf(\n realPath ? getPath(realPath) : null,\n Base.pathText,\n getPath(props.getProperty('java.home')),\n getPath(props.getProperty('user.home')),\n getPath(props.getProperty('user.dir')),\n getPath(props.getProperty('java.io.tmpdir'))\n );\n pathList = pathList.unique();\n pathList.forEach((item, i) => item?.endsWith('/') && (pathList[i] = item.slice(0, -1)));\n Params.params = Wb.encode({\n pathList,\n appPath: Base.pathText,\n osCharset: Base.osCharset?.toUpperCase(),\n charset: System.getProperty('file.encoding')?.toUpperCase(),\n fileCharset: Wb.getConfig('sys.file.charset')?.toUpperCase(),\n filenameCharset: Wb.getConfig('sys.locale.filenameCharset')?.toUpperCase(),\n sysFilenameCharset: SysUtil.filenameCharset?.name()?.toUpperCase(),\n });\n}\ninit();", "remark": "File browser shell" }, "_icon": "module", "events": { "initialize": "/*\n * Xwl comments.\n * @class $path\n */\nWb.define(app, {\n /** @property {Object} - Server params. */\n params: _$params$_,\n /** @property {String} - The URL used to get the files path. */\n getFileUrl: 'm?xwl=sys/file/get',\n /** @property {Boolean} - File tree raw path. */\n set$rawPath(value) {\n app.rawPath$ = value;\n value ??= '';\n app.basePath = value.includes('|') ? value.replace('|', app.params.appPath) : value;\n app.rootPath = Wb.getParentDirectory(app.basePath);\n },\n get$rawPath() {\n return app.rawPath$;\n },\n /** @property {String} - The base path of the tree. */\n basePath: '',\n /** @property {String} - The parent of the base path. */\n rootPath: '',\n /** @property {Array} - Path back list. @priv */\n backList: [],\n /** @property {Array} - Path forward list. @priv */\n forwardList: [],\n /** @property {String} - Current node path. @priv */\n get$currentPath() {\n return app.selNode.getPath(null, '|');\n },\n /** @property {String} - Current file path. @priv */\n get$filePath() {\n return app.selNode.data.path;\n },\n /** @property {Wb.TreeItem} - Current select node. @priv */\n get$selNode() {\n return app.fileTree.selection;\n },\n /**\n * Go to the specified folder path.\n * @param {String} path The folder path.\n * @param {Function} Callback function after operation completion.\n */\n goto(path, callback) {\n app.fileTree.selectPath(app.toTreePath(path), callback, null, '|');\n },\n /**\n * Convert file path to tree path. @priv\n * @return {String} Tree path.\n */\n toTreePath(path) {\n if (path.endsWith('/'))\n path = path.slice(0, -1);\n path = path.split('/');\n if (!app.rootPath && !path[0].endsWith('/'))\n path[0] += '/';\n return path.join('|');\n },\n /**\n * Select a node.\n * @param {TreeItem} node The node to be selected.\n */\n selectNode(node) {\n let path = node.data.path;\n app.fileGrid.load({ params: { path: path } });\n app.upItem.disabled = !node.parent?.isNode;\n if (path.occur('/') > 1 && path.endsWith('/'))\n path = path.slice(0, -1);\n app.pathSelect.value = app.getRelPath(path);\n },\n /**\n * Add a new file or folder to the current folder. @priv\n * @param {String} filename File or folder name.\n * @param {Boolean} [isFolder] Whether is folder to be added. Default is false.\n */\n addFile(isFolder) {\n Wb.prompt({ title: isFolder ? Str.addFolder : Str.addFile, icon: isFolder ? 'folder1' : 'file' },\n { text: Str.name, required: true, cid: 'filename' }, function (values, win) {\n Wb.ajax({\n url: 'm?xwl=sys/file/add',\n json: true,\n params: { path: app.filePath, filename: values.filename, isFolder },\n success(resp) {\n let newItem = Wb.apply({ text: values.filename, size: isFolder ? null : 0, _leaf: !isFolder }, resp);\n\n if (!newItem._leaf)\n newItem.path += '/';\n app.fileGrid.addData(newItem).select();\n if (isFolder && app.selNode?.loaded) {\n newItem.items = [];\n app.selNode.addData(newItem);\n }\n win.close();\n }\n });\n });\n },\n /**\n * Import files to the current folder.\n * @param {Boolean} [unzip] Whether to unzip after import.\n */\n importFiles(unzip) {\n let node = app.selNode, params = app.params, items, win;\n\n items = [{\n text: Str.file, cid: 'files', multiple: true, required: true, cname: 'fileInput',\n browseMode: true, flex: 1, minHeight: '5em'\n }];\n items.push({\n cid: 'charset', cname: 'select', text: Str.charset, value: params.sysFilenameCharset,\n data: ['UTF-8', params.charset, params.osCharset, params.fileCharset, params.filenameCharset].filter(a => a).unique()\n });\n win = Wb.prompt({\n title: (unzip ? Str.importUnzip : Str.import) + ' - ' + node.text, autoGrid: 'up', layout: 'form1', icon: 'import'\n }, items, (values, win) => {\n app.doImport(win, unzip, f => win.close(), values.charset);\n }, 'wb.file.import');\n win.down('charset').visible = unzip;\n },\n /**\n * Download the selected files.\n * @param {Boolean} [zip] Whether to zip before export.\n */\n exportFiles(zip) {\n let items = app.fileGrid.selectionsData;\n if (items.length)\n Wb.download('m?xwl=sys/file/export-files', { files: items.pluck('path'), zip }, 'POST');\n else\n Wb.tipSelect();\n },\n /**\n * Do import files. @priv\n * @param {Wb.Component/Wb.Component[]} comps Import components.\n * @param {Boolean} unzip Whether to unzip after import.\n * @param {Function} callback The callback function.\n * @param {String} charset The file name charset.\n */\n doImport(comps, unzip, callback, charset) {\n let node = app.selNode;\n\n Wb.ajax({\n url: 'm?xwl=sys/file/import-files&mode=list',\n comps,\n uploadProgress: true,\n json: true,\n params: { path: node.data.path, unzip, charset },\n success(resp) {\n let newNodes, fileGrid = app.fileGrid, newItems = [];\n\n newNodes = resp.filter(item => !fileGrid.some(sub => sub.data.text == item.text));\n newNodes.forEach(item => newItems.push(Wb.applyWithout({}, item, 'items')));\n fileGrid.addData(newItems)\n fileGrid.selection = fileGrid.filter(sub => resp.some(item => item.text == sub.data.text));\n if (node.loaded) {\n newNodes = resp.filter(item => !item._leaf && !node.some(sub => sub.text == item.text));\n node.addData(newNodes);\n }\n callback?.();\n }\n });\n },\n /**\n * Copy or cut the selected files.\n * @param {Event} e Event object.\n * @param {Boolean} [cut] Whether to cut.\n */\n copy(e, cut) {\n if (!document.activeElement.isInput) {\n let files = app.fileGrid.selectionsData;\n if (files.length) {\n app.clipboard = files.pluck('path');\n app.isCut = cut;\n } else\n Wb.tipSelect();\n e.stopEvent();\n }\n },\n /**\n * Get relative path base on the root path.\n * @param {String} path Full path.\n * @return {String} Relative path.\n */\n getRelPath(path) {\n let rootPath = app.rootPath, len = rootPath.length;\n\n if (len) {\n if (rootPath.includes('|'))\n len = len + app.params.appPath.length;\n path = path.substr(len);\n if (path.startsWith('/'))\n path = path.substr(1);\n return path;\n } else {\n return path;\n }\n },\n /**\n * File grid double click handler. @priv\n * @param {Object} data The item data.\n */\n onGridDblClick(data) {\n let path = data.path, title = Wb.getFilename(path), tip = path;\n Wb.open({\n url: Wb.isImageFile(path) ? 'image-viewer' : 'text-editor', title, tip, params: { path }\n });\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row" }, "_expanded": true, "events": { "ready": "let el = this.el;\n\napp.fileGrid.contextMenu = Wb.createMenu(app.viewport1.tbar[0].items);\napp.fileInput = new Wb.FileInput({ cid: 'files', multiple: true, visible: false, renderEl: BodyEl });\nel.ondragover = Event.pdHandler;\nel.ondrop = e => {\n let fileInput = app.fileInput;\n\n e.stopEvent();\n fileInput.clear();\n fileInput.addFile(e.dataTransfer.files);\n app.doImport(fileInput);\n};" }, "items": [ { "_icon": "array", "text": "tbar", "cls": "Wb.Array", "properties": { "cid": "tbar" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "bar1", "isProperty": "true" }, "text": "bar1", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "addFileBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addFileBtn", "icon": "file", "text": "@Str.addFile", "keys": "Ctrl+J", "bindModule": "sys/file/add.xwl" }, "events": { "click": "app.addFile();" } }, { "_icon": "item", "text": "addFolderBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "addFolderBtn", "icon": "folder1", "text": "@Str.addFolder", "keys": "Ctrl+Shift+J", "bindModule": "sys/file/add.xwl" }, "events": { "click": "app.addFile(true);" } }, { "_icon": "item", "text": "renameBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "renameBtn", "icon": "edit", "text": "@Str.rename", "keys": "F2", "stopEvent": "false", "bindModule": "sys/file/set-property.xwl" }, "events": { "click": "if (document.activeElement.isInput)\n return;\nlet fileGrid = app.fileGrid, row = fileGrid.selection, oldName, path, selNode = app.selNode;\n\nif (!row) {\n Wb.tipSelect();\n return;\n}\noldName = row.data.text;\nfileGrid.startEdit(row, 'text', (value, row) => {\n if (row.text != value) {\n path = row.data.path;\n app.isRenaming = true;\n Wb.ajax({\n url: 'm?xwl=sys/file/set-property',\n json: true,\n params: { rename: true, path, filename: value },\n callback(resp, xhr) {\n if (xhr.ok) {\n let update = item => {\n item.set({\n text: value, path: resp.path + (item.data._leaf ? '' : '/'),\n lastModified: new Date(resp.lastModified).textValue\n });\n }\n update(row);\n if (!row.data._leaf) {\n row = selNode.findItem('text', oldName);\n if (row) {\n let newPath, len;\n\n len = row.data.path.length;\n update(row);\n newPath = row.data.path;\n row.cascade(node => {\n node.data.path = newPath + node.data.path.substr(len);\n });\n }\n }\n }\n if (app.pendSelNode) {\n app.selectNode(app.pendSelNode);\n app.pendSelNode = null;\n }\n app.isRenaming = false;\n }\n });\n }\n return false;\n});\nWb.Editor.activeEditor.select(0, oldName.lastIndexOf('.'));" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" }, "_expanded": true }, { "_icon": "item", "text": "cutBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "cutBtn", "icon": "cut", "text": "@Str.cut", "keys": "Ctrl+X", "stopEvent": "false", "bindModule": "sys/file/paste-files.xwl" }, "events": { "click": "app.copy(e, true);" } }, { "_icon": "item", "text": "copyBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "copyBtn", "icon": "copy", "text": "@Str.copy", "keys": "Ctrl+C", "stopEvent": "false", "bindModule": "sys/file/paste-files.xwl" }, "events": { "click": "app.copy(e);" } }, { "_icon": "item", "text": "pasteBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "pasteBtn", "icon": "paste", "text": "@Str.paste", "keys": "Ctrl+V", "stopEvent": "false", "bindModule": "sys/file/paste-files.xwl" }, "events": { "click": "function paste() {\n let files = app.clipboard;\n if (document.activeElement.isInput || !files?.length)\n return;\n\n let path = app.filePath, isCut = app.isCut, conflictFile, fromPath;\n\n if (isCut) {\n let firstFile = files[0];\n fromPath = Wb.getParentDirectory(firstFile);\n if (fromPath == path) {\n //same parent\n app.clipboard = null;\n return;\n }\n }\n // check paste conflict\n conflictFile = files.find(file => file.endsWith('/') && path.startsWith(file));\n if (conflictFile) {\n Wb.warn(Str.cannotPaste.format(conflictFile));\n return;\n }\n if (isCut)\n app.clipboard = null;\n Wb.ajax({\n url: 'm?xwl=sys/file/paste-files&mode=list',\n json: true,\n params: { source: files, isCut, dest: path },\n success(resp) {\n let newNodes, fileGrid = app.fileGrid, newFiles = resp.files;\n\n app.selNode.addData(newFiles.filter(item => !item._leaf));\n newFiles.forEach(item => delete item.data);\n newNodes = fileGrid.addData(newFiles);\n fileGrid.selection = newNodes;\n if (isCut) {\n let node = app.fileTree.findPath(app.toTreePath(app.getRelPath(fromPath)), null, '|')\n if (node) {\n if (node.loaded) {\n node.each(child => {\n if (files.includes(child.data.path))\n child.destroy();\n }, true, true);\n } else {\n if (!resp.hasFolder)\n node.removeExpander();\n }\n }\n }\n }\n });\n}\npaste();" } }, { "_icon": "item", "text": "delBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "delBtn", "icon": "delete", "text": "@Str.del", "keys": "Shift+Delete", "bindModule": "sys/file/remove.xwl" }, "events": { "click": "let fileGrid = app.fileGrid, files = fileGrid.selectionsData;\nif (files.length) {\n Wb.confirm(Wb.getActionHint(files, 'text'), f => {\n files = files.pluck('path');\n Wb.ajax({\n url: 'm?xwl=sys/file/remove',\n params: { files },\n success() {\n let selNode = app.selNode;\n\n fileGrid.delRecords();\n if (selNode.loaded) {\n selNode.each(item => {\n if (files.includes(item.data.path))\n item.destroy();\n }, true, true);\n } else if (!fileGrid.some(item => !item.data._leaf)) {\n selNode.removeExpander();\n }\n }\n });\n });\n} else {\n Wb.tipSelect();\n}" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" }, "_expanded": true }, { "_icon": "split", "text": "exportBtn", "cls": "Wb.SplitButton", "properties": { "cid": "exportBtn", "icon": "export", "text": "@Str.export", "bindModule": "sys/file/export-files.xwl" }, "events": { "click": "app.exportFiles();" }, "_expanded": false, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "exportZip", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "exportZip", "text": "@Str.exportZip" }, "events": { "click": "app.exportFiles(true);" } } ] } ] }, { "_icon": "split", "text": "importBtn", "cls": "Wb.SplitButton", "properties": { "cid": "importBtn", "icon": "import", "text": "@Str.import", "bindModule": "sys/file/import-files.xwl" }, "events": { "click": "app.importFiles();" }, "_expanded": false, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true" }, "text": "menu", "_expanded": true, "_icon": "menu2", "items": [ { "_icon": "item", "text": "importUnzip", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "importUnzip", "text": "@Str.importUnzip" }, "events": { "click": "app.importFiles(true);" } } ] } ] }, { "_icon": "divider", "text": "divider3", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider3" } }, { "_icon": "item", "text": "refreshBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshBtn", "icon": "refresh", "text": "@Str.refresh" }, "events": { "click": "app.fileTree.loadSelect();" } } ] }, { "cls": "Wb.Toolbar", "properties": { "cid": "bar2", "isProperty": "true" }, "text": "bar2", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "backBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "backBtn", "icon": "left4", "disabled": "true", "text": "@Str.back" }, "events": { "click": "let backList = app.backList, path = backList.pop();\napp.forwardList.push(app.currentPath);\napp.stopHistory = true;\napp.fileTree.selectPath(path, null, null, '|');\napp.stopHistory = false;\napp.backBtn.disabled = !backList.length;\napp.forwardBtn.disabled = false;" } }, { "_icon": "item", "text": "forwardBtn", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "forwardBtn", "icon": "right4", "disabled": "true", "text": "@Str.forward" }, "events": { "click": "let forwardList = app.forwardList, path = forwardList.pop();\napp.backList.push(app.currentPath);\napp.stopHistory = true;\napp.fileTree.selectPath(path, null, null, '|');\napp.stopHistory = false;\napp.forwardBtn.disabled = !forwardList.length;\napp.backBtn.disabled = false;" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_expanded": false, "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "upItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "upItem", "icon": "up4", "disabled": "true", "text": "@Str.up" }, "events": { "click": "app.fileTree.selection = app.selNode.parent;" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "properties": { "cid": "divider2" }, "_expanded": true }, { "_icon": "combo", "text": "pathSelect", "cls": "Wb.Select", "properties": { "cid": "pathSelect", "flex": "1", "minWidth": "10em", "data": "app.params.pathList", "selectMode": "false" }, "events": { "select": "app.goto(data.text);", "keydown": "if (e.isGoKey) {\n app.pathSelect.triggers.fireEvent('click');\n app.pathSelect.collapse();\n e.stopEvent();\n}" }, "_expanded": true, "items": [ { "cls": "Wb.Item", "events": { "click": "let select = this.parent, path = select.value, text, data = select.data;\ntext = path.replaceAll('\\\\', '/');\napp.goto(text, node => {\n if (node) {\n if (!data.some(item => item.text == text))\n data.insert(0, { text });\n } else {\n Wb.tipWarn(Str.notFound.format(path));\n }\n});" }, "properties": { "cid": "triggers", "isProperty": "true", "icon": "right4", "tip": "@Str.goto" }, "text": "triggers", "_expanded": true, "_icon": "item" } ] } ] } ] }, { "_icon": "tree-view", "text": "fileTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "fileTree", "width": "18em", "url": "@app.getFileUrl+'&type=tree'", "autoSelect": "true", "keyWalking": "true", "autoLoad": "@!Wb.parseBool('_$dialog$_')" }, "events": { "beforeselect": "let node = this.selection;\nif (node && !app.stopHistory) {\n let path = node.getPath(null, '|'), backList = app.backList;\n if (backList.lastItem != path)\n backList.push(path);\n app.backBtn.disabled = false;\n}", "selectionchange": "if (app.isRenaming) {\n app.pendSelNode = app.selNode;\n return false;\n}\napp.selectNode(app.selNode);", "beforeload": "let basePath = app.basePath;\nif (!configs.node && basePath) {\n let rootPath = app.rootPath;\n params.path = rootPath;\n params.filterName = Wb.getFilename(app.basePath) || app.basePath;\n}" } }, { "_icon": "splitter", "text": "splitter1", "cls": "Wb.Splitter", "properties": { "cid": "splitter1" } }, { "_icon": "grid", "text": "fileGrid", "cls": "Wb.Grid", "properties": { "cid": "fileGrid", "flex": "1", "url": "@app.getFileUrl+'&type=file'", "autoLoad": "false", "columnsSortable": "true", "sorters": "text", "stateId": "wb.file", "fields": "({\n lastModified: { type: 'date' }, _icon: {\n convert(value, data) {\n return data._leaf ? Wb.getFileIcon(data.text) : 'folder1';\n }\n }\n})", "showIcon": "true", "keyWalking": "true", "multiSelect": "true", "gridLine": "false", "stripeRows": "false", "rectSelect": "true", "pageSize": "-1" }, "events": { "beforeload": "/**\n * Set sorter params.\n */\nfunction setSorterParams() {\n let sorter = app.fileGrid.sorters, sortMap = { text: 'name', type: 'type', size: 'size', lastModified: 'date' };\n\n if (Wb.isString(sorter))\n sorter = { name: sorter, desc: false };\n params.sort = sortMap[sorter.name];\n params.desc = sorter.desc;\n params.filterExt = app.extNames;\n}\nsetSorterParams();", "itemdblclick": "let data = item.data;\nif (data._leaf) {\n app.onGridDblClick(data);\n} else {\n app.selNode.selectChild(data.text);\n}", "selectionchange": "let sels = this.selections, hint, len = sels.length;\n\nif (len) {\n hint = Str.nItems.format(len);\n if (sels.some(item => item.data._leaf)) {\n let total = 0;\n\n sels.forEach(item => {\n if (item.data._leaf)\n total += item.data.size;\n });\n hint += ', ' + Str.size + Str.labelSeparator + total.fileSize + ' (' + total.intText + ')';\n }\n}\nelse {\n hint = '';\n}\napp.fileLabel.text = hint;" }, "_expanded": true, "items": [ { "cls": "Wb.Array", "properties": { "cid": "columns" }, "text": "columns", "_expanded": true, "_icon": "array", "items": [ { "cls": "Wb.Column", "properties": { "cid": "rowNumCol", "rowNum": "true" }, "text": "rowNumCol", "_expanded": true, "_icon": "column" }, { "_icon": "column", "text": "nameCol", "cls": "Wb.Column", "properties": { "cid": "nameCol", "text": "@Str.name", "fieldName": "text", "width": "18em" }, "_expanded": true, "items": [ { "cls": "Wb.Text", "properties": { "cid": "editor", "isProperty": "true", "valueType": "filename", "required": "true" }, "text": "editor", "_expanded": true, "_icon": "text" } ] }, { "_icon": "column", "text": "dateCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "dateCol", "fieldName": "lastModified", "text": "@Str.modifiedDate", "width": "12em" } }, { "_icon": "column", "text": "typeCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "typeCol", "fieldName": "type", "text": "@Str.type", "render": "return data._leaf ? Wb.getFileExt(data.text) : Str.folder;", "width": "8em" } }, { "_icon": "column", "text": "sizeCol", "cls": "Wb.Column", "_expanded": true, "properties": { "cid": "sizeCol", "fieldName": "size", "text": "@Str.size", "type": "fileSize", "width": "8em" } } ] }, { "_icon": "pagenum", "text": "pagingBar", "cls": "Wb.PagingBar", "properties": { "cid": "pagingBar", "isProperty": "true", "totalOnly": "true" }, "events": { "ready": "app.fileLabel = this.insert(2, ['->', { cname: 'label' }, '|'])[1];" } } ] } ] } ] } # sys/file/export-files.xwl Title: export-files Description: Export files in any path ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\nfunction main() {\n let files = Wb.getObject('files'), file = new Wb.File(files[0]), zip = Wb.getBool('zip'), len = files.length,\n filename = Params.filename;\n\n if (zip || len > 1 || file.isFolder) {\n if (!filename) {\n if (len == 1)\n filename = file.isFile ? file.normalName : file.name;\n else\n filename = file.parent.name || 'file';\n }\n files = files.map(file => new File(file));\n Wb.setContentType(filename + '.zip');\n ZipUtil.zip(files, response.getOutputStream());\n } else {\n Wb.exportData(file, filename);\n }\n}\nmain();", "remark": "Export files in any path" }, "_icon": "module" } # sys/file/find-shortcut.xwl Title: find-shortcut Description: Find file path of the specified URL shortcut ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let file, result, path = Params.path;\n file = UrlBuffer.getBuffer().get('/' + path);\n if (file)\n result = Base.modulePathText + file;\n else {\n file = new Wb.File(Base.modulePath, path + '.xwl');\n if (file.exists)\n result = file.path;\n else\n result = '';\n }\n Wb.send(result);\n}\nmain();", "remark": "Find file path of the specified URL shortcut" }, "_icon": "module" } # sys/file/get-property.xwl Title: get-property Description: Get file property in any path ```json { "title": "", "icon": "", "img": "", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs');\nWb.send(fs.getFileProperty(Params.path));", "remark": "Get file property in any path" }, "_icon": "module" } # sys/file/get-resource.xwl Title: get-resource Description: Get files in resource path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.File.checkContains('|wb/system/resource', Params.path);\nWb.run('./get');", "remark": "Get files in resource path" }, "_icon": "module", "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false" } # sys/file/get.xwl Title: get Description: Get files in any path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n let fs = Wb.load('./fs.mjs'), items, path = Params.path, filterName = Params.filterName, filterExt = Params.filterExt;\n\n items = fs.listFiles(path, Params.type, Params.sort, Wb.getBool('desc'), Wb.getBool('moduleSort'));\n if (filterName) {\n let baseFolder = items.find(item => item.text == filterName);\n if (baseFolder) {\n baseFolder._expanded = true;\n items = [baseFolder];\n } else {\n Wb.raise(Str.notFound.format(path + filterName));\n }\n }\n if (filterExt) {\n filterExt = filterExt.splitTrim();\n items = items.filter(item => {\n return filterExt.some(ext => item.text.endsWith(ext) || !item._leaf);\n });\n }\n Wb.send(items);\n}\nmain();", "remark": "Get files in any path" }, "_icon": "module", "title": "" } # sys/file/image-viewer.xwl Title: image-viewer Description: Image viewer shell ```json { "title": "", "icon": "image", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.set({ path: Wb.encode(Params.path) });", "remark": "Image viewer shell" }, "_icon": "module", "events": { "initialize": "Wb.define(app, {\n /** @property {String} src The src of image to preview. */\n get$src() {\n return app.imageEl.src;\n },\n set$src(value) {\n app.imageEl.src = value;\n }\n});\nWb.define(app, {\n /** @property {String} path The file path to edit. @priv */\n path: _$path$_,\n /** @property {Boolean} - Whether not auto load. */\n notLoad: '_$notLoad',\n /**\n * Preview the image file. @priv\n */\n preview(callback) {\n let path = app.path;\n Wb.ajax({\n url: 'm?xwl=sys/file/open',\n params: { path },\n success(resp) {\n app.imageEl.src = 'data:image/' + Wb.getFileExt(path) + ';base64,' + resp;\n }\n });\n },\n /**\n * Execute after on load. @priv\n */\n onLoad() {\n if (!app.notLoad)\n app.preview();\n if (!Globals.WbMainTab)\n document.title = Wb.getFilename(app.path);\n }\n});" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "border": "false", "autoScroll": "true", "bodyCls": "w-prev-ct" }, "events": { "ready": "app.imageEl = this.bodyEl.addEl('w-margin-center', 'img');" }, "_expanded": true } ] } # sys/file/import-files.xwl Title: import-files Description: Import files in any path ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.checkDemo();\nfunction main() {\n let fs = Wb.load('./fs.mjs'), newFile, files = Wb.getParams('files'), charset,\n path = new Wb.File(Params.path), unzip = Wb.getBool('unzip'), newNames, filename, filenames = [];\n\n charset = Params.charset ? SysUtil.getCharset(Params.charset) : SysUtil.filenameCharset;\n files.forEach(file => {\n filename = file.name;\n if (unzip && Wb.getFileExt(filename).toLowerCase() == 'zip') {\n newNames = ZipUtil.unzip(file.stream, path.file, charset);\n filenames = filenames.concat(newNames);\n filenames.forEach(name => {\n new Wb.File(path.file, name).cascadeSelf(file => file.clearBuffer());\n })\n } else {\n filenames.push(filename);\n newFile = new Wb.File(path, filename);\n newFile.stream = file.stream;\n newFile.clearBuffer();\n }\n });\n files = fs.listFiles(path, Params.mode);\n Wb.send(files.filter(file => filenames.includes(file.text)));\n}\nmain();", "remark": "Import files in any path" }, "_icon": "module" } # sys/file/open-resource.xwl Title: open-resource Description: Get file content in resource path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "Wb.File.checkContains('|wb/system/resource', Params.path);\nWb.run('./open');", "remark": "Get file content in resource path" }, "_icon": "module", "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false" } # sys/file/open.xwl Title: open Description: Get file content in any path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs');\nWb.send(fs.getFileData(Params.path, Params.charset));", "remark": "Get file content in any path" }, "_icon": "module", "title": "" } # sys/file/paste-files.xwl Title: paste-files Description: Paste or move files in any path ```json { "title": "", "icon": "", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs');\nWb.send(fs.pasteFiles(Wb.getObject('source'), Params.dest, Params.relName, Wb.getBool('isCut'), Params.mode));", "remark": "Paste or move files in any path" }, "_icon": "module" } # sys/file/remove.xwl Title: remove Description: Remove file in any path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs');\nfs.removeFiles(Wb.getObject('files'));", "remark": "Remove file in any path" }, "_icon": "module", "title": "" } # sys/file/save.xwl Title: save Description: Save file content in any path ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs');\nWb.send(fs.saveFile(Wb.payload, Params.confirm == '1'));", "remark": "Save file content in any path" }, "_icon": "module", "title": "" } # sys/file/set-property.xwl Title: set-property Description: Set file property in any path ```json { "title": "", "icon": "", "img": "", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let fs = Wb.load('./fs.mjs'), renameOnly = Wb.getBool('rename'), file;\n\nfile = fs.setFileProperty(Params.path, Params.filename, renameOnly ? false : Params.title,\n Params.icon, Params.img, Params.tags, Params.url, Params.hideInMenu);\nWb.send({ lastModified: file.lastModified, path: file.path });", "remark": "Set file property in any path" }, "_icon": "module" } # sys/file/text-editor.xwl Title: text-editor Description: Text editor shell ```json { "title": "", "icon": "text1", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let path = Params.path;\nWb.set('args', Wb.encode({\n osCharset: Base.osCharset?.toUpperCase(),\n charset: System.getProperty('file.encoding')?.toUpperCase(),\n fileCharset: Wb.getConfig('sys.file.charset')?.toUpperCase(),\n language: Wb.getFileExt(path),\n filenameCharset: Wb.getConfig('sys.locale.filenameCharset')?.toUpperCase()\n}));\nWb.set({ path: Wb.encode(path) });", "remark": "Text editor shell" }, "_icon": "module", "events": { "initialize": "Wb.define(app, {\n /** @property {Object} - Server args. @priv */\n args: _$args$_,\n /** @property {String} path The file path to edit. @priv */\n path: _$path$_,\n /** @property {String} charset Charset of text encoding. @priv */\n charset: 'UTF-8',\n /**\n * Reopen the file. @priv\n * @param {Function} [callback] The function to be executed after open.\n */\n reOpen(callback) {\n Wb.ajax({\n url: 'm?xwl=sys/file/open',\n params: { path: app.path, charset: app.charset },\n success(resp) {\n let pos = resp.indexOf('|');\n app.lastModified = resp.substr(0, pos);\n app.editor.rawValue = resp.substr(pos + 1);\n app.saveBtn.disabled = true;\n callback?.();\n }\n });\n },\n /**\n * Set text charset. @priv\n */\n setCharset() {\n let args = app.args;\n Wb.prompt({ icon: 'earth', title: Str.setCharset }, [\n {\n cid: 'charset', cname: 'select', text: Str.charset, required: true, value: app.charset,\n data: ['UTF-8', args.charset, args.osCharset, args.fileCharset, args.filenameCharset].filter(a => a).unique()\n }, { cname: 'displayField', showEmptyLabel: true, icon: 'warn', value: Str.overwriteTextHint }\n ], (values, win) => {\n app.charsetItem.text = app.charset = values.charset;\n app.reOpen(f => win.close());\n });\n },\n /**\n * Execute after on load. @priv\n */\n onLoad() {\n app.reOpen();\n if (!Globals.WbMainTab)\n document.title = Wb.getFilename(app.path);\n app.editor.focus();\n },\n /**\n * Save the current file. @priv\n * @param {Boolean} [noConfirm] Whether no confirm when the file has been modified.\n */\n save(noConfirm) {\n if (app.saveBtn.disabled)\n return;\n let data, content = app.editor.value;\n\n data = app.path + '|' + app.charset + '|' + app.lastModified + '|' + content.length + '|' + content;\n Wb.ajax({\n url: 'm?xwl=sys/file/save', data,\n params: {\n confirm: noConfirm ? 0 : 1\n },\n success(resp) {\n app.lastModified = Wb.decode(resp)[0];\n app.saveBtn.disabled = true;\n },\n failure(resp) {\n if (resp.errorCode == 'modified')\n Wb.confirm(Str.modifiedConfirm.format(Wb.decode(resp.errorText)[0]), f => app.save(true));\n }\n });\n }\n});", "beforeunload": "if (!app.saveBtn.disabled)\n return false;" }, "_expanded": true, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "_expanded": true, "properties": { "cid": "viewport1", "layout": "fit" }, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "item", "text": "saveBtn", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveBtn", "icon": "save", "text": "@Str.save", "disabled": "true", "keys": "Ctrl+S" }, "events": { "click": "app.save();" } } ] }, { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1" } }, { "_icon": "label", "text": "cursorLabel", "cls": "Wb.Label", "properties": { "cid": "cursorLabel" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "charsetItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "charsetItem", "text": "@app.charset" }, "events": { "click": "app.setCharset();" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "properties": { "cid": "space1" } } ] }, { "_icon": "edit", "text": "editor", "cls": "Wb.CodeEditor", "properties": { "cid": "editor", "wrapBorder": "false", "border": "true", "language": "@app.args.language" }, "events": { "cursorchange": "app.cursorLabel.text = cursor ? (cursor.lineNumber + ' : ' + cursor.column) : Wb.nbsp;", "change": "app.saveBtn.disabled = false;" } } ] } ] } # sys/portal/home/get-langs.xwl Title: get-langs Description: Get language list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get language list", "serverScript": "function main() {\n let file = new Wb.File(true, 'wb/js/locale'), result = [];\n\n file.listFiles().forEach(file => {\n let name = file.name;\n if (name.startsWith('wb-') && name.endsWith('.js') && !name.endsWith('.min.js'))\n result.push(name.slice(3, -3));\n })\n Wb.send(result);\n}\nmain();" }, "_icon": "module" } # sys/portal/home/get-modules-tree.xwl Title: get-modules-tree Description: Get modules tree ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get modules tree", "serverScript": "function main() {\n const Util = Wb.load('./util.mjs');\n Wb.send(Util.getModules());\n}\nmain();" }, "_icon": "module" } # sys/portal/home/get-user-data.xwl Title: get-user-data Description: Get current user data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get current user data", "serverScript": "function main() {\n const protectedText = Wb.UserUtil.protectedText;\n let sql;\n\n sql = `select '${protectedText}' as password, '${protectedText}' as confirm_password, display_name, create_date,\n login_times, email, mobile_phone, use_lang from wb_user where sid={?sys.userid?}`;\n Wb.sendDict(sql, 'wb,');\n}\nmain();" }, "_icon": "module" } # sys/portal/home/save-desktop.xwl Title: save-desktop Description: Save desktop ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Save desktop", "serverScript": "function main() {\n let { value, asDefault } = Params;\n\n if (!value.portlets) {\n let data = Wb.getResource(['desktop', 'desktop'], [null, 'system']);\n\n data = data[0] ?? data[1];\n if (data?.portlets)\n value.portlets = data.portlets;\n }\n if (asDefault)\n Wb.permitx('set-resource-all') && Wb.run('set-resource-all');\n else\n Wb.permitx('set-resource') && Wb.run('set-resource');\n}\nmain();" }, "_icon": "module" } # sys/portal/home/search-modules.xwl Title: search-modules Description: Search module names ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Search module names", "serverScript": "function main() {\n let query = Params.query, fs = Wb.load('wb/modules/sys/file/fs.mjs');\n\n //[] indicates a complete match\n if (query.startsWith('[') && query.endsWith(']'))\n query = query.slice(1, -1);\n else if (!query.includes('*') && !query.includes('?'))\n query = '*' + query + '*';\n Wb.send(search(fs, '', query).mixSort('text'));\n}\n/**\n * Search the module files in the entire module directory.\n * @param {Object} fs FS util object.\n * @param {String} path Search relative path.\n * @param {String} query Search keyname.\n * @return {Array} Search result.\n */\nfunction search(fs, path, query) {\n let items = fs.listFiles(Base.modulePathText + path, 'home'), result = [];\n items.forEach(item => {\n if (item._leaf) {\n if (item.text.wildcardMatch(query) || item.path.lastItem('/').wildcardMatch(query)) {\n result.push(Wb.applyWith({}, item, ['text', '_icon', '_img', 'path', 'strTitle']));\n }\n } else {\n result.pushAll(search(fs, '/' + item.path, query));\n }\n });\n return result;\n}\nmain();" }, "_icon": "module" } # sys/portal/home/set-user-data.xwl Title: set-user-data Description: Set current user data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Set current user data", "serverScript": "function main() {\n const protectedText = Wb.UserUtil.protectedText;\n let session, pwd = Params.password, fields = 'display_name,email,mobile_phone,use_lang';\n\n if (pwd != protectedText)\n fields += ',password';\n Wb.set({\n $sid: Wb.userid, password: Wb.UserUtil.encryptPassword(pwd)\n });\n Wb.sync({ tableName: 'wb_user', update: Params, fields });\n session = request.getSession(false);\n session?.setAttribute('sys.dispname', Params.display_name);\n session?.setAttribute('sys.lang', Params.use_lang);\n}\nmain();" }, "_icon": "module" } # sys/portal/home.xwl Title: home Description: Default home page ```json { "title": "", "icon": "", "img": "", "tags": "{url: 'home', newWin: true}", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('./home/util.mjs');\n\n if (!Util.checkLogin())\n return;\n const theme = Wb.get('sys.theme') || Wb.getConfig('sys.theme');\n Wb.set(Util.getDesktopData());\n Wb.set({\n theme: Wb.encode(theme),\n licensee: Wb.encode(Util.getLicensee()),\n themeItems: Wb.encode(Util.getThemeItems(theme)),\n title: Wb.getConfig('sys.app.title'),\n username: Wb.encode(Wb.username),\n dispname: Wb.encode(Wb.dispname),\n setDefaultDesktop: Wb.permit('set-resource-all'),\n heartbeat: Wb.getConfig('sys.session.heartbeatInterval'),\n httpHeartbeat: Wb.getConfig('sys.session.httpHeartbeatInterval'),\n isDemo: Config.isDemo,\n isShowPwdDialog: Util.isShowPwdDialog()\n });\n}\nmain();", "title": "_$title$_", "remark": "Default home page", "loginRequired": "false" }, "_icon": "module", "_expanded": true, "events": { "initialize": "/*\n * Default home page\n * @class $path\n */\nWb.define(app, {\n /** @property {Boolean} - Whether is demo version. */\n isDemo: _$isDemo$_,\n /** @property {String} - Licensee name. */\n licensee: _$licensee$_,\n /** @property {Boolean} - Whether to show password dialog. */\n isShowPwdDialog: _$isShowPwdDialog$_,\n /** @property {String} - Current user name. */\n username: _$username$_,\n /** @property {String} - Current user display name. */\n dispname: _$dispname$_,\n /** @property {Boolean} - Home module flag. */\n inHome: true,\n /** @property {String} - Current theme @priv */\n theme: _$theme$_,\n /** @property {Object} - Gets the currently open module app. Returns null if no modules are open. */\n get$activeModule() {\n return app.moduleTab.activeCard?.module ?? null;\n },\n /** @property {String} - Account display name. */\n get$accountName() {\n return Str.myAccount + ' (' + this.dispname + ')';\n },\n /** @property {Object} - Gets the currently open module card. */\n get$activeCard() {\n return app.moduleTab.activeCard;\n },\n /**\n * Link current module to the relative menu. @priv\n * @param {Wb.Card} [card] The card to link with. Default is the current active card.\n */\n linkToMenu(card) {\n let url = (card ?? app.activeCard)?.moduleUrl;\n\n if (url?.startsWith('m?xwl=')) {\n let p = url.indexOf('&'), firstPath, btn, pos;\n url = url.substring(6, p == -1 ? url.length : p) + '.xwl';\n if (app.topNavBar) {\n pos = url.indexOf('/');\n firstPath = url.substr(0, pos);\n btn = app.topNavBar.find(btn => btn.bindPath === firstPath);\n if (btn) {\n btn.active = true;\n app.selectTopButton(btn, f => {\n app.moduleTree.selectPath(url.substr(pos + 1), node => {\n if (node) {\n node.select(null, null, true);\n node.intoViewCenter();\n }\n }, 'filename', null, true, true);\n });\n }\n } else {\n app.moduleTree.selectPath(url, node => {\n if (node) {\n node.select(null, null, true);\n node.intoViewCenter();\n }\n }, 'filename', null, true, true);\n }\n }\n },\n /**\n * Opens the specified module.\n * @param {Object} data Parameter object.\n */\n openModule(data) {\n let tags = data.tags, configs;\n\n configs = {\n icon: data._icon, img: data._img, title: data.text, url: 'm?xwl=' + data.path, allowRefresh: true,\n tags: { strTitle: data.strTitle }\n };\n if (tags) {\n tags = Wb.parse(tags);\n configs.tags.tags = tags;\n Wb.apply(configs, tags);\n }\n if (configs.frame)\n Wb.browse(configs);\n else if (configs.newWin)\n Wb.openWin(configs);\n else\n Wb.open(configs);\n },\n /**\n * Show my Account dialog.\n */\n showMyAccount() {\n Wb.ajax({\n url: xpath + '/get-user-data',\n json: true,\n success(resp) {\n let win = app.accountWin;\n\n if (!win) {\n win = app.accountWin = Wb.Dict.createColWindow(resp.columns, 'display_name,password,confirm_password,' +\n 'email,mobile_phone,use_lang', { title: Str.myAccount, icon: 'user2', width: '50em' });\n }\n Wb.setValue(win, resp.items[0]);\n win.okHandler = (win, values) => {\n if (values.password != values.confirm_password) {\n Wb.warn(Str.pwdNotSame, f => win.down('password').focus(false, true));\n return;\n }\n Wb.ajax({\n url: xpath + '/set-user-data',\n comps: win,\n success() {\n app.dispname = values.display_name;\n app.accountItem.text = app.accountName;\n win.hide();\n if (Str.lang != values.use_lang) {\n location.reload();\n }\n }\n });\n };\n win.subTitle = app.dispname;\n win.show();\n }\n });\n },\n /**\n * Fires after the page is ready.\n */\n onReady() {\n let activeCard = app.moduleTab.activeCard, httpHeartbeat = _$httpHeartbeat$_;\n app.moduleTab.setNavigate(app.backItem, app.forwardItem);\n if (activeCard) {\n //This event must be triggered again during initialization because home is not ready\n app.moduleTab.fireEvent('cardchange', activeCard);\n }\n if (httpHeartbeat > 0)\n setInterval(f => Wb.ajax('refresh-session'), httpHeartbeat * 1000);\n console.info('%cThis software is only authorized to%c' + (app.licensee || '(unlicensed)'),\n 'padding: 2px 8px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;',\n 'padding: 2px 8px; border-radius: 0 3px 3px 0; color: #fff; background: #1475b2;');\n },\n /**\n * Window resize event handler. @priv\n */\n onResize() {\n let visible = app.treeItem.visible = Globals.smallScreen;\n app.toggleTools(visible);\n },\n /**\n * Open the specified module. @priv\n * @param {Object} [data] Module data.\n */\n doOpenModule(data) {\n let sp = app.treeSplitter;\n\n app.openModule(data);\n // floating module tree\n if (sp.slideTarget)\n sp.restoreTargetComp();\n else if (app.treeItem.visible)\n app.moduleTree.hide();\n },\n /**\n * Toggle tool buttons to the toolbar or menu.\n * @param {Boolean} [inMenu] Whether tools in the menu.\n */\n toggleTools(inMenu) {\n if (inMenu != app.toolsInMenu) {\n let btn = app.backItem, items = [], menuItem = app.menuItem, menu = menuItem.menu, configs;\n\n app.toolsInMenu = inMenu;\n while (btn) {\n btn.visible = !inMenu;\n if (inMenu) {\n configs = {\n text: btn.tip, icon: btn.icon, refToolBtn: btn, handler() {\n this.refToolBtn.fireEvent('click');\n }\n };\n if (btn.active != null)\n configs.checked = btn.active;\n items.push(configs);\n }\n btn = btn.nextSibling;\n if (btn == menuItem)\n break;\n }\n if (inMenu) {\n items.push({ cname: 'divider', refToolBtn: 1 });\n menu.insert(0, items);\n } else {\n menu.each(item => { item.refToolBtn && item.destroy() }, true, true);\n }\n }\n },\n /**\n * Show password dialog for changes all default password.\n */\n showPwdDialog() {\n Wb.run({ url: xpath + '/../reset-passwords' });\n },\n /**\n * Create top navigate bar.\n */\n createTopNavBar() {\n let fillItem = app.topFillItem, moduleTree = app.moduleTree, bar, data;\n\n fillItem.hide();\n app.lastNavButton = null;\n bar = app.topNavBar = fillItem.parent.insertBefore({\n cname: 'toolbar', cls: 'w-top-nav', alignSelf: 'stretch', style: 'padding:0', flex: 1, justify: 'center',\n margin: '0 .5em', events: {\n buttonclick(button) {\n app.selectTopButton(button);\n }\n }\n }, fillItem);\n moduleTree.each(node => {\n data = node.data;\n bar.add({\n icon: data._icon, img: data._img, cls: 'w-nav-btn', text: data.text, bindPath: data.path,\n bindData: data._leaf ? data : null, groupName: 'nav'\n });\n });\n moduleTree.data = null;\n bar.firstItem?.fireEvent('click');\n },\n /**\n * Select top menu bar button. @priv\n * @param {Wb.Button} button Selected button.\n * @param {Function} callback Execute after sucess.\n */\n selectTopButton(button, callback) {\n let lastBtn = app.lastNavButton, moduleTree = app.moduleTree;\n if (lastBtn) {\n lastBtn.bindItems = moduleTree.data;\n lastBtn.bindScrollTop = moduleTree.scrollEl.scrollTop;\n lastBtn.bindSelPath = moduleTree.selection?.data.path;\n }\n if (button.bindData) {\n lastBtn.active = true;\n app.doOpenModule(button.bindData);\n callback?.();\n } else {\n if (button.bindItems) {\n moduleTree.data = button.bindItems;\n if (button.bindSelPath)\n moduleTree.down(node => node.data.path == button.bindSelPath)?.selectNoFocus();\n moduleTree.scrollEl.scrollTop = button.bindScrollTop;\n callback?.();\n } else {\n moduleTree.load({\n params: { path: button.bindPath }, success() {\n callback?.();\n }\n });\n }\n app.lastNavButton = button;\n }\n },\n /**\n * Destroy navigate bar and restore tree navigate.\n */\n restoreTreeNav() {\n app.topNavBar?.destroy();\n app.topNavBar = null;\n app.topFillItem.show();\n app.moduleTree.load();\n },\n /**\n * Save desktop data.\n * @param {Boolean} [asDefault] Whether to save as the default desktop.\n */\n saveDesktop(asDefault) {\n function getPageData() {\n let items = [], url, tree = app.moduleTree, expandNodes, strTitle;\n app.moduleTab.each(card => {\n url = card.moduleUrl;\n if (url && card.allowRefresh) {\n strTitle = card.strTitle;\n items.push({\n icon: card.icon ?? undefined, img: card.img ?? undefined, visible: card.visible, tags: card.tags,\n title: strTitle ? undefined : card.title, strTitle, moduleUrl: card.moduleUrl\n });\n }\n });\n if (!app.noSaveExandNodes) {\n expandNodes = [];\n app.moduleTree.each(node => {\n if (node.expanded)\n expandNodes.push(node.data.strTitle || node.text);\n });\n }\n return {\n items, portlets: getPortlets(), treeVisible: tree.visible, treeWidth: tree.getStyle('width'),\n expandNodes, showNavBar: !!app.topNavBar\n };\n }\n\n function getPortlets() {\n let card = app.moduleTab.find(card => card.moduleUrl == 'm?xwl=my/home'), items, strTitle;\n\n if (card && !card.prepend) {\n items = [];\n card.down('viewport1')?.each(panel => {\n strTitle = panel.strTitle;\n items.push({\n icon: panel.icon ?? undefined, img: panel.img ?? undefined, tags: panel.tags, col: panel.gridColValue,\n row: panel.gridRowValue, title: strTitle ? undefined : panel.title, strTitle, moduleUrl: panel.moduleUrl\n });\n });\n }\n return items;\n }\n Wb.ajax({\n url: xpath + '/save-desktop',\n data: { name: 'desktop', value: getPageData(), userid: asDefault ? 'system' : undefined, asDefault },\n success() {\n Wb.tipDone(Str.saveDesktop);\n }\n });\n }\n});", "finalize": "window.onresize = app.onResize;\napp.onResize();\nlet smallScreen = app.treeItem.visible;\nif (smallScreen)\n app.moduleTree.visible = !app.moduleTab.firstItem;\nif (app.isShowPwdDialog)\n app.showPwdDialog();\nif (!smallScreen && _$showNavBar$_)\n app.createTopNavBar();" }, "items": [ { "_icon": "plug", "text": "socket", "cls": "Wb.Socket", "properties": { "cid": "socket", "name": "sys.home", "heartbeatInterval": "_$heartbeat$_", "loginRequired": "true", "xwl": "sys/session/service.xwl {xaction: 'monWebsocket'}" }, "events": { "message": "function main() {\n let data = e.data, type, msg, method;\n\n data = Wb.decode(data);\n type = data.type;\n switch (type) {\n case 'info':\n case 'warn':\n case 'error':\n msg = data.msg;\n method = 'tip' + type.capital;\n if (Wb.isObject(msg)) {\n Wb[method](msg.msg ?? Str.newMessage, null, msg.url ? f => {\n if (msg.newWin)\n Wb.openWin(msg);\n else\n Wb.open(msg);\n } : undefined);\n } else {\n Wb[method](msg);\n }\n break;\n }\n}\nmain();", "failure": "if (!Wb.unloading) {\n Wb.login((username, dispname) => {\n app.dispname = dispname;\n app.accountItem.text = app.accountName;\n if (app.username != username) {\n app.username = username;\n location.reload();\n }\n });\n}" } }, { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "row", "border": "false", "cls": "@app.theme=='dark'?'w-home':'w-home w-dark-home'" }, "_expanded": true, "events": { "ready": "app.onReady();" }, "items": [ { "_icon": "toolbar", "text": "tbar", "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "gap": ".2em", "style": "padding:0 .5em;" }, "_expanded": true, "items": [ { "_icon": "item", "text": "treeItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "treeItem", "icon": "tree-view", "plainIcon": "true", "minWidth": "2em" }, "events": { "click": "app.moduleTree.visible = !app.moduleTree.visible;" } }, { "_icon": "logo", "text": "logoIcon", "cls": "Wb.Icon", "properties": { "cid": "logoIcon", "icon": "geejing", "fontSize": "1.5em" } }, { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "_$title$_" }, "_expanded": true }, { "_icon": "right1", "text": "topFillItem", "cls": "Wb.Fill", "properties": { "cid": "topFillItem" } }, { "_icon": "item", "text": "backItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "backItem", "tip": "@Str.back", "icon": "left4", "plainIcon": "true", "cls": "w-home-tbtn" } }, { "_icon": "item", "text": "forwardItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "forwardItem", "tip": "@Str.forward", "icon": "right4", "plainIcon": "true", "cls": "w-home-tbtn" } }, { "_icon": "item", "text": "refreshItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshItem", "tip": "@Str.refresh", "icon": "refresh", "plainIcon": "true", "disabled": "true", "cls": "w-home-tbtn" }, "events": { "click": "let card = app.moduleTab.activeCard;\nif (card) {\n let configs = { url: card.moduleUrl, card, tabMode: 'reload' }, tags = card.tags;\n\n if (tags) {\n Wb.apply(configs, tags);\n configs.tags = { tags };\n }\n Wb.open(configs);\n}" } }, { "_icon": "item", "text": "homeItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "homeItem", "tip": "@Str.home", "icon": "home", "plainIcon": "true", "cls": "w-home-tbtn" }, "events": { "click": "Wb.openNormal('m?xwl=my/home');" } }, { "_icon": "item", "text": "linkItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "linkItem", "icon": "link", "active": "false", "plainIcon": "true", "tip": "@Str.moduleLinkToMenu", "cls": "w-home-tbtn" }, "events": { "toggle": "if (active)\n app.linkToMenu();" } }, { "_icon": "item", "text": "menuItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "menuItem", "icon": "menu", "plainIcon": "true", "cls": "w-home-tbtn" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true", "minWidth": "20em" }, "text": "menu", "_expanded": true, "_icon": "menu2", "events": { "show": "let menu = this;\nmenu.fontSize = Wb.configs.fontSize; //avoid menu font changes\nmenu.each(item => { item.refToolBtn && (item.disabled = item.refToolBtn.disabled) });\napp.topNavItem.checked = !!app.topNavBar?.visible;", "hide": "//Adapts the menu font to the current font\nthis.fontSize = null;" }, "items": [ { "_icon": "item", "text": "accountItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "accountItem", "icon": "user2", "text": "@app.accountName", "handler": "app.showMyAccount" } }, { "_icon": "divider", "text": "divider1", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider1" } }, { "_icon": "item", "text": "saveDesktopItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveDesktopItem", "icon": "desktop", "text": "@Str.saveDesktop" }, "events": { "click": "app.saveDesktop();" } }, { "_icon": "item", "text": "resetDesktopItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "resetDesktopItem", "text": "@Str.resetDesktop", "icon": "undo" }, "events": { "click": "Wb.confirm(Str.doConfirm.format(Str.resetDesktop), f => {\n Wb.ajax({\n url: 'set-resource',\n params: { name: 'desktop' },\n success() {\n Wb.tipDone(Str.resetDesktop);\n }\n });\n});" } }, { "_icon": "item", "text": "saveAsDefaultDesktopItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "saveAsDefaultDesktopItem", "text": "@Str.saveAsDefaultDesktop", "visible": "_$setDefaultDesktop$_" }, "events": { "click": "Wb.confirm(Str.doConfirm.format(Str.saveAsDefaultDesktop), f => {\n app.saveDesktop(true);\n});" } }, { "_icon": "item", "text": "resetDefaultDesktopItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "resetDefaultDesktopItem", "text": "@Str.resetDefaultDesktop", "visible": "_$setDefaultDesktop$_" }, "events": { "click": "Wb.confirm(Str.doConfirm.format(Str.resetDefaultDesktop), f => {\n Wb.ajax({\n url: 'set-resource-all',\n params: { name: 'desktop', userid: 'system' },\n success() {\n Wb.tipDone(Str.resetDesktop);\n }\n });\n});" } }, { "_icon": "divider", "text": "divider2", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider2" } }, { "_icon": "item", "text": "uiThemeItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "uiThemeItem", "text": "@Str.uiTheme", "icon": "color" }, "items": [ { "cls": "Wb.Menu", "properties": { "cid": "menu", "isProperty": "true", "tagProperties": "({ items: _$themeItems$_ })" }, "text": "menu", "_expanded": true, "_icon": "menu2", "events": { "menuclick": "let theme = item.theme;\n\nif (theme == '?') {\n window.open('https://www.geejing.com/buy');\n return;\n}\nif (theme == app.theme)\n return;\nlet setTheme = f => {\n let link = Wb.headEl.query('[href*=\"-wb.css\"]');\n\n app.theme = theme;\n if (link) {\n let newLink = document.createElement('link');\n newLink.rel = 'stylesheet';\n newLink.href = link.href.substr(0, link.href.lastIndexOf('/') + 1) + theme + '-wb.css';\n newLink.onload = f => {\n link.remove();\n Wb.initCssVar();\n Wb.CodeEditor?.initTheme(true);\n };\n Wb.headEl.insertBefore(newLink, link);\n app.viewport1.setCls(theme != 'dark', 'w-dark-home');\n } else {\n Wb.tipError(Str.notFound.format(Str.uiTheme));\n }\n};\nif (app.isDemo)\n setTheme();\nelse\n Wb.ajax({\n url: 'set-value',\n params: { name: 'sys.theme', value: theme },\n success: setTheme\n });" } } ] }, { "_icon": "divider", "text": "divider3", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider3" } }, { "_icon": "container", "text": "container1", "cls": "Wb.Container", "properties": { "cid": "container1", "layout": "row", "gap": ".2em" }, "_expanded": true, "items": [ { "_icon": "slidebar", "text": "fsSlider", "cls": "Wb.Slider", "properties": { "cid": "fsSlider", "text": "@Str.fontSize", "maxValue": "50", "flex": "1", "minValue": "12", "value": "@Wb.configs.fontSize", "tabIndex": "null", "focusable": "false" }, "_expanded": true, "events": { "change": "Wb.setFontSize(value);", "enddrag": "if (!app.isDemo) {\n Wb.ajax({\n url: 'set-value',\n params: { name: 'sys.fontSize', value: value }\n });\n}" } }, { "_icon": "button", "text": "resetBtn", "cls": "Wb.Button", "properties": { "cid": "resetBtn", "tip": "@Str.reset", "icon": "refresh", "type": "tool", "tabIndex": "undefined", "focusable": "false" }, "events": { "click": "let resetSize = f => {\n let fs = Wb.configs.rawFontSize;\n Wb.setFontSize(fs);\n app.fsSlider.value = fs;\n app.menuItem.menu.hide();\n};\nif (app.isDemo)\n resetSize();\nelse\n Wb.ajax({\n url: 'set-value',\n params: { name: 'sys.fontSize' },\n success: resetSize\n });" } } ] }, { "_icon": "divider", "text": "divider4", "cls": "Wb.Divider", "_expanded": true, "properties": { "cid": "divider4" } }, { "_icon": "item", "text": "topNavItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "topNavItem", "text": "@Str.topNavBar", "checked": "false" }, "events": { "click": "if (this.checked)\n app.restoreTreeNav();\nelse\n app.createTopNavBar();" } }, { "_icon": "item", "text": "refreshListItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "refreshListItem", "icon": "list-view", "text": "@Str.refreshList" }, "events": { "click": "if (app.topNavBar) {\n app.moduleTree.load({\n success() {\n app.topNavBar.destroy();\n app.createTopNavBar();\n }\n });\n} else {\n app.moduleTree.loadSelect();\n}" } }, { "_icon": "divider", "text": "divider5", "cls": "Wb.Divider", "properties": { "cid": "divider5" }, "_expanded": true }, { "_icon": "item", "text": "logoutItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "logoutItem", "icon": "logout", "text": "@Str.logout", "keys": "Ctrl+Shift+L" }, "events": { "click": "Wb.ajax('logout');" } } ] } ] } ] }, { "_icon": "tree-view", "text": "moduleTree", "cls": "Wb.Tree", "_expanded": true, "properties": { "cid": "moduleTree", "width": "_$treeWidth$_", "url": "@xpath + '/get-modules-tree'", "autoLoad": "false", "visible": "_$treeVisible$_", "data": "_$moduleTree$_", "rightExpander": "true", "treeStyle": "menu", "dblclickExpand": "false", "autoPostParams": "false" }, "events": { "beforeload": "let node = configs.node;\n\nif (node)\n params.path = node.data.path;", "itemclick": "if (item.leaf)\n app.doOpenModule(item.data);\nelse\n item.toggleExpand();\nitem.contentEl.rippleEffect(e.x, e.y);" }, "items": [ { "_icon": "combo", "text": "bbar", "cls": "Wb.Select", "properties": { "cid": "bbar", "isProperty": "true", "url": "@xpath + '/search-modules'", "icon": "search" }, "events": { "select": "app.doOpenModule(data);" } } ] }, { "_icon": "splitter", "text": "treeSplitter", "cls": "Wb.Splitter", "properties": { "cid": "treeSplitter", "enterShowTarget": "true" } }, { "_icon": "tab", "text": "moduleTab", "cls": "Wb.Tab", "_expanded": true, "properties": { "cid": "moduleTab", "flex": "1", "mainTab": "true", "tabMenu": "true", "activeIndex": "undefined", "useHash": "touch" }, "events": { "ready": "this.tabBar.mon('dblclick', e => {\n let card = e.target.getClosestComp(Wb.TabButton)?.card;\n if (card?.allowRefresh) {\n Wb.openWin(Wb.apply({ url: card.moduleUrl }, card.tags));\n e.stopEvent();\n }\n});", "cardchange": "app.refreshItem.disabled = !newCard?.allowRefresh;\nif (newCard?.prepend) {\n let tags = newCard.tags, configs;\n\n configs = {\n url: newCard.moduleUrl, tabMode: 'reload', container: newCard, allowRefresh: true,\n icon: newCard.icon, img: newCard.img, title: newCard.title\n };\n if (tags) {\n //tags use to refresh\n configs.tags ??= {};\n configs.tags.tags = tags;\n Wb.apply(configs, tags);\n }\n Wb.open(configs);\n delete newCard.prepend;\n}\nif (app.linkItem.active)\n app.linkToMenu(newCard);" }, "items": [ { "_icon": "file-json", "text": "script1", "cls": "Wb.Script", "properties": { "cid": "script1", "script": "_$moduleItems$_" } } ] } ] } ] } # sys/portal/index.xwl Title: index Description: Default index page ```json { "title": "", "icon": "", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "loginRequired": "false", "title": "_$title$_", "serverScript": "Wb.set({\n title: Wb.getConfig('sys.app.title'),\n verifyCode: Wb.getConfig('sys.session.verifyCode'),\n showTip: !Config.isDemo && !!Wb.getRecord(\"select 1 from wb_user where user_name='admin' and login_times=0\")\n});", "remark": "Default index page", "theme": "true" }, "_icon": "module", "_expanded": true, "tags": "{url: 'index', newWin: true}", "events": { "finalize": "app.panel1.setLoginFocus();" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "middle", "autoScroll": "true", "border": "false", "bodyStyle": "background-color:#959595;background-image: repeating-linear-gradient(40deg,rgba(0,0,255,0.2) 2px,transparent 2.5px),repeating-linear-gradient(126deg,rgba(255,0,0,0.2) 2px,transparent 2.5px),repeating-linear-gradient(238deg,rgba(0,255,0,0.2) 2px,transparent 2.5px);" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "padding": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "logo", "text": "logoIcon", "cls": "Wb.Icon", "properties": { "cid": "logoIcon", "icon": "geejing", "fontSize": "3em" } }, { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "_$title$_", "style": "font-weight: bold; color: #333;", "fontSize": "2em" }, "_expanded": true }, { "_icon": "right1", "text": "fill1", "cls": "Wb.Fill", "properties": { "cid": "fill1", "visible": "@!Globals.smallScreen" } }, { "_icon": "item", "text": "websiteItem", "cls": "Wb.Item", "_expanded": true, "properties": { "cid": "websiteItem", "icon": "earth", "fontSize": "1.5em", "plainIcon": "true", "tip": "@Str.officialWebsite", "visible": "@!Globals.smallScreen" }, "events": { "click": "window.open('https://www.geejing.com');" } }, { "_icon": "space", "text": "space1", "cls": "Wb.Space", "properties": { "cid": "space1", "visible": "@!Globals.smallScreen" } }, { "_icon": "item", "text": "emailItem", "cls": "Wb.Item", "_expanded": false, "properties": { "cid": "emailItem", "icon": "mail", "fontSize": "1.5em", "plainIcon": "true", "tip": "@Str.email", "visible": "@!Globals.smallScreen" }, "events": { "click": "window.location = 'mailto:contact@geejing.com';" } } ] }, { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "style": "box-shadow:#00000055 0px 2px 10px 5px", "cls": "w-limit-width" }, "_expanded": true, "events": { "ready": "let form = Wb.createLoginPanel(this, f => location.replace('home'), false, _$verifyCode$_);\nif (_$showTip$_)\n form.add({ cname: 'displayField', icon: 'info', value: Str.firstLoginTip });" } }, { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true", "padding": "true", "layout": "hmiddle" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "label", "text": "copyrightLabel", "cls": "Wb.Label", "properties": { "cid": "copyrightLabel", "text": "Copyright © Geejing, All Rights Reserved.", "style": "color:#555", "fontSize": ".8em" } } ] } ] } ] } # sys/portal/reset-passwords/reset.xwl Title: reset Description: Reset passwords for all users ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n Wb.sql({\n sql: 'update wb_user set password={?pwd?}, login_times=2',\n params: {\n pwd: Wb.UserUtil.encryptPassword(Params.password)\n }\n });\n}\nmain();", "remark": "Reset passwords for all users" }, "_icon": "module" } # sys/portal/reset-passwords.xwl Title: reset-passwords Description: Prompt to reset all users password ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Prompt to reset all users password" }, "_icon": "module", "_expanded": true, "items": [ { "_icon": "window", "text": "main", "cls": "Wb.Window", "_expanded": true, "properties": { "cid": "main", "layout": "grid1", "visible": "true", "dialog": "true", "title": "@Str.resetPassword", "icon": "key", "closeAction": "destroy" }, "events": { "ok": "if (app.password.value != app.repassword.value) {\n Wb.tipError(Str.pwdNotSame);\n app.password.focus();\n return;\n}\nWb.ajax({\n url: xpath + '/reset',\n comps: app.password,\n success: f => {\n this.close();\n }\n});" }, "items": [ { "_icon": "label1", "text": "hint", "cls": "Wb.DisplayField", "properties": { "cid": "hint", "icon": "info", "value": "@Str.resetPwdHint" } }, { "_icon": "text", "text": "password", "cls": "Wb.Text", "properties": { "cid": "password", "password": "true", "text": "@Str.password", "required": "true", "minLength": "6" }, "_expanded": true }, { "_icon": "text", "text": "repassword", "cls": "Wb.Text", "properties": { "cid": "repassword", "password": "true", "text": "@Str.confirmPassword", "required": "true", "minLength": "6" } } ] } ] } # sys/service/data/export.xwl Title: export Description: Export accessible data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Export accessible data", "serverScript": "/**\n * Export the specified data to the client file. @priv\n * @param {Object} params The export params.\n * @param {String} [.columns] The data columns.\n * @param {String} [.filename] The filename.\n * @param {String} [.format] The file format, such as \"xls\", \"xlsx\", \"csv\".\n * @param {String} [.data] The local data to be exported.\n * @param {String} [.url] URL used to get remote data.\n * @param {String} [.itemsPath] The items path for the remote data. Default is \"item\".\n * @param {String} [.params] Parameters submitted using URL.\n * @param {String} [.allPages] Whether to export all pages.\n * @param {String} [.freeze] Freeze column index.\n * @param {String} [.localUrl] Access url in the current server.\n * @param {String} [.tree] Whether is tree.\n * @param {String} [.urlParams] The params for the localUrl.\n * @param {String} [.title] The title of the grid.\n * @param {String} [.pageSize] Page size of the grid.\n * @param {String} [.pageIndex] Page index of the grid.\n * @param {String} [.fromValue] From record index of the grid.\n * @param {String} [.toValue] To record index of the grid.\n * @param {String} [.summaryRow] Summary row data.\n */\nfunction doExport(params) {\n let columns, data, format, gridLine, outputStream, isTree = Wb.parseBool(params.tree),\n itemsName = Params.itemsName, itemsPath = params.itemsPath;\n\n columns = new JSONArray(params.columns);\n data = params.data;\n if (data) {\n data = new JSONArray(data);\n data = isTree ? flattenItems(data, itemsName) : new JSONArray(data);\n } else {\n let p1, p2, allPages = Wb.parseBool(params.allPages), localUrl = params.localUrl, indexName = params.pageIndexName,\n paramsValue = Wb.decode(params.params ?? null), maxRows = Wb.getConfig(\"sys.office.exportMaxRows\"),\n fromValue, toValue, pageSizeValue, indexValue, sortValue = params.sortValue;\n\n if (allPages) {\n fromValue = 0;\n toValue = maxRows;\n pageSizeValue = maxRows;\n indexValue = 0;\n } else {\n fromValue = parseInt(params.fromValue);\n toValue = Math.min(parseInt(params.toValue), maxRows);\n pageSizeValue = Math.min(parseInt(params.pageSize), maxRows);\n indexValue = parseInt(params.pageIndex);\n }\n paramsValue[params.fromName] = fromValue;\n paramsValue[params.toName] = toValue;\n paramsValue[params.pageSizeName] = pageSizeValue;\n if (indexName)\n paramsValue[indexName] = indexValue;\n if (sortValue)\n paramsValue[params.sortName] = sortValue;\n if (localUrl) {\n localUrl = Xwl.getXwlPath(localUrl);\n if (localUrl) {\n Wb.permitx(localUrl);\n try {\n if (allPages)\n Context.maxRows = maxRows;\n data = Wb.execute(localUrl, Wb.apply({}, Wb.decode(params.urlParams ?? null), paramsValue));\n } finally {\n if (allPages)\n Context.maxRows = undefined;\n }\n }\n }\n if (!data) {\n data = Wb.submit({ url: params.url, request, text: true, silent: true, all: true, params: paramsValue });\n if (data.code != 200) {\n if (data.code == 401) {\n response.setStatus(401);\n Wb.send(data.result);\n return;\n } else {\n Wb.raise(data.result);\n }\n }\n data = data.result;\n }\n p1 = data.indexOf(\"{\");\n p2 = data.indexOf(\"[\");\n if (p2 != -1 && (p2 < p1 || p1 == -1)) {\n data = isTree ? flattenItems(data, itemsName) : new JSONArray(data);\n } else {\n data = isTree ? flattenItems(data, itemsName, itemsPath) : JsonUtil.findObject(new JSONObject(data), itemsPath);\n }\n }\n format = params.format ?? 'xlsx';\n Wb.setContentType((params.filename || 'data') + '.' + format, true);\n gridLine = Wb.getConfig('sys.office.gridBorderLine');\n if (gridLine == 'auto')\n gridLine = params.gridLine;\n if (params.summary)\n data.put(new JSONObject(params.summary));\n outputStream = response.getOutputStream();\n format = format.toLowerCase();\n if (format.startsWith('xls'))\n Java.type('com.wb.office.SheetWriter').createExcel(outputStream, columns, data,\n Wb.getInt('freeze') ?? 0, params.title, gridLine);\n else\n exportCSV(outputStream, columns, data);\n response.flushBuffer();\n}\n/**\n * Flatten all tree items. @priv\n * @param {String} data The tree text data.\n * @param {String} itemsName Items property name.\n * @param {String} itemsPath Items data path.\n * @return {JSONArray} Flattened items array;\n */\nfunction flattenItems(data, itemsName, itemsPath) {\n data = Wb.decode(data);\n if (itemsPath)\n data = Wb.getNS(itemsPath, data);\n return new JSONArray(Java.to(Wb.flatItems(data, true, itemsName)));\n}\n\n/**\n * Export data to csv file.\n * @param {OutputStream} os Output stream.\n * @param {Array} columns Columns data.\n * @param {Array} data Rows data.\n */\nfunction exportCSV(outputStream, columns, data) {\n const encodeCSV = StringUtil.encodeCSV;\n let i, j, row, val, pos, addComma, fields = [], isDate = [], writer;\n\n writer = new java.io.BufferedWriter(\n new java.io.OutputStreamWriter(outputStream, Wb.getConfig('sys.file.csvCharset') || Base.osCharset));\n columns = Wb.toJs(columns);\n Wb.cascade(columns, col => {\n if (!col.items) {\n if (addComma)\n writer.write(',');\n else\n addComma = true;\n writer.write(encodeCSV(col.text));\n fields.push(col.fieldName + (col.keyValue ? '$' : ''));\n isDate.push(col.fieldType == 0);\n }\n });\n j = data.length();\n for (i = 0; i < j; i++) {\n writer.write('\\n');\n row = data.opt(i);\n fields.forEach((field, k) => {\n if (k > 0)\n writer.write(',');\n val = row.optString(field);\n if (val && isDate[k]) {\n pos = val.lastIndexOf('.');\n if (pos != -1)\n val = val.substr(0, pos);\n }\n writer.write(encodeCSV(val));\n });\n }\n writer.close();\n}\n\ndoExport(Params);" }, "_icon": "module", "_expanded": true } # sys/service/data/get-dict.xwl Title: get-dict Description: Get dictionary data ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "let actions = {\n /**\n * Gets a list of dictionary entries.\n * @return {Array} A list of dictionary entries.\n */\n getItems() {\n let items = Params.items, maxRows = Config.maxRows, result, dictItem;\n\n //max 1000 items\n if (items.length > maxRows)\n Wb.raise('The dictionary only allows ' + maxRows + ' items to be returned.');\n result = [];\n items.forEach(item => {\n dictItem = DictCls.findItem(item);\n if (!dictItem)\n Wb.raise(`The dictionary item \"${item}\" not found.`);\n if (!dictItem.displayHidden)\n dictItem.displayHidden = undefined;\n if (!dictItem.editFill)\n dictItem.editFill = undefined;\n if (!dictItem.editHidden)\n dictItem.editHidden = undefined;\n result.push(Wb.applyValue({}, dictItem));\n });\n Wb.send(result);\n },\n /**\n * Gets a list of dictionary groups.\n * @return {Array} A list of dictionary groups.\n */\n getGroups() {\n let sql, result = [];\n\n sql = 'select distinct group_name from wb_dict';\n if (Params.query) {\n Wb.setLike('query');\n sql += ' where group_name like {?query?}';\n }\n else {\n result.push('true');\n }\n sql += ' order by group_name';\n result.pushAll(Wb.getRecords(sql).pluck(0));\n Wb.send(result);\n }\n};\nactions[Params.xaction]();", "remark": "Get dictionary data" }, "_icon": "module" } # sys/service/data/get-kv.xwl Title: get-kv Description: Get key value list ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n switch (Params.type) {\n case 'list':\n Wb.send(Wb.ServerDict.getKVList(Params.name));\n break;\n case 'names':\n Wb.send(Wb.ServerDict.getKeyNames(Params.query));\n break;\n }\n}\nmain();", "remark": "Get key value list" }, "_icon": "module" } # sys/service/db/sql-provider.xwl Title: sql-provider Description: Provide SQL completion items ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "function main() {\n const Util = Wb.load('wb/ss/dbe.mjs');\n let result = [], tableName, schemaName, object, sql = Wb.decodeBase64(Params.data).toLowerCase(),\n conn = Wb.getConn(Params.db), keysLen, keys, realName, key = Params.key.toLowerCase(),\n defaultSchema = conn.schema, schemas = Util.getSchemas(conn),\n defaultTables = Util.getTables(conn, defaultSchema).concat(Util.getTables(conn, defaultSchema, true));\n\n keys = key.split('.');\n keysLen = keys.length;\n key = keys[0];\n if (keysLen == 1) {\n [schemas, defaultTables].forEach(type => addItems(result, type, key, 'Unit'));\n tableName = getTablesFromSQL(sql);\n tableName.forEach(item => {\n if (item.includes('.')) {\n keys = item.split('.');\n if (object = schemas.find(item => item.text.toLowerCase() == keys[0])) {\n schemaName = object.text;\n if (object = Util.getTables(conn, schemaName).concat(Util.getTables(conn, schemaName, true)).find(\n item => item.text.toLowerCase() == keys[1])) {\n addItems(result, Util.getColumns(conn, schemaName, object.text), null, 'Field');\n }\n }\n } else if (object = defaultTables.find(sub => sub.text.toLowerCase() == item)) {\n addItems(result, Util.getColumns(conn, defaultSchema, object.text), null, 'Field');\n }\n });\n } else {\n if (object = schemas.find(item => item.text.toLowerCase() == key)) {\n // schema\n schemaName = object.text;\n [false, true].forEach(isView => addItems(result, Util.getTables(conn, schemaName, isView), null, 'Unit'));\n } else {\n object = defaultTables.find(item => item.text.toLowerCase() == key);\n if (object) {\n // table\n schemaName = defaultSchema;\n tableName = object.text;\n } else {\n // scan alias\n keys = sql.split(/\\s+|,/).filter(k => k);\n keys.each((item, i) => {\n if (i > 0 && item == key) {\n realName = keys[i - 1];\n if (realName.includes('.')) {\n // schema and table name\n keys = realName.split('.');\n if (Wb.isIdentifier(keys[0]) && (object = schemas.find(item => item.text.toLowerCase() == keys[0]))) {\n schemaName = object.text;\n if (Wb.isIdentifier(keys[1]) && (\n object = Util.getTables(conn, schemaName).concat(Util.getTables(conn, schemaName, true)).find(\n item => item.text.toLowerCase() == keys[1]))) {\n tableName = object.text;\n return false;\n }\n }\n } else {\n // single table name\n object = Wb.isIdentifier(realName) && defaultTables.find(item => item.text.toLowerCase() == realName);\n if (object) {\n schemaName = defaultSchema;\n tableName = object.text;\n return false;\n }\n }\n }\n });\n }\n if (tableName) {\n addItems(result, Util.getColumns(conn, schemaName, tableName), null, 'Field');\n }\n }\n }\n Wb.send(result);\n}\n\n// add the specified data items to the result\nfunction addItems(result, data, key, cate) {\n let text;\n data.forEach(item => {\n text = item.text;\n if ((!key || text.toLowerCase().includes(key)) && !result.some(item => item.text == text)) {\n result.push({ text, cate });\n }\n });\n}\n\n// get table names from sql\nfunction getTablesFromSQL(sql) {\n const regex = /(?:FROM|JOIN|INTO|UPDATE|DELETE)\\s+([^\\s,\\)]+)/gi;\n const tableNames = [];\n let match;\n\n while ((match = regex.exec(sql))) {\n tableNames.push(match[1]);\n }\n return tableNames;\n}\nmain();", "remark": "Provide SQL completion items" }, "_icon": "module" } # sys/service/site/check-update.xwl Title: check-update Description: Check update ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "try {\n if (!Params.wbv2)\n return;\n let result, rec, params, key = 'f32AdGi8';\n params = Wb.decode(Encrypter.decrypt(Params.license, key));\n params.ip = request.getRemoteAddr();\n params.joinValue = (params.ip || '') + (params.user_name || '') + (params.computer_name || '');\n Wb.set(params);\n try {\n Wb.set({ date: new Date(), sid: Wb.getId() });\n Wb.sql('insert into wb_update values({?sid?},{?date?},{?ip?},{?user_name?},{?mac?},{?computer_name?},{?user_domain?},{?os_name?},{?app_title?},{?licensee?},{?sn?})');\n } catch (e) {\n }\n rec = Wb.getRecord('select script from wb_mac where mac={?mac?} or mac={?joinValue?}');\n result = rec?.[0] || '';\n if (result)\n result = Encrypter.encrypt(result, key);\n Wb.send(result);\n} catch (ex) {\n}", "loginRequired": "false", "remark": "Check update" }, "_icon": "module" } # sys/service/site/get-version.xwl Title: get-version Description: Get system version ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Get system version", "serverScript": "Wb.send(Wb.getConfig('sys.app.version'));", "loginRequired": "false" }, "_icon": "module" } # sys/session/login.xwl Title: Login Description: Login page ```json { "title": "@login", "icon": "", "img": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "loginRequired": "false", "remark": "Login page", "serverScript": "Wb.set({\n title: Wb.getConfig('sys.app.title'),\n verifyCode: Wb.getConfig('sys.session.verifyCode')\n});", "theme": "true" }, "_icon": "module", "_expanded": true, "tags": "", "events": { "finalize": "app.panel1.setLoginFocus();" }, "items": [ { "_icon": "viewport", "text": "viewport1", "cls": "Wb.Viewport", "properties": { "cid": "viewport1", "layout": "middle", "autoScroll": "true", "border": "false", "bodyStyle": "background-color:#959595;background-image: repeating-linear-gradient(40deg,rgba(0,0,255,0.2) 2px,transparent 2.5px),repeating-linear-gradient(126deg,rgba(255,0,0,0.2) 2px,transparent 2.5px),repeating-linear-gradient(238deg,rgba(0,255,0,0.2) 2px,transparent 2.5px);" }, "_expanded": true, "items": [ { "cls": "Wb.Toolbar", "properties": { "cid": "tbar", "isProperty": "true", "padding": "true" }, "text": "tbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "logo", "text": "logoIcon", "cls": "Wb.Icon", "properties": { "cid": "logoIcon", "icon": "geejing", "fontSize": "3em" } }, { "_icon": "label", "text": "titleLabel", "cls": "Wb.Label", "properties": { "cid": "titleLabel", "text": "_$title$_", "style": "font-weight: bold; color: #333;", "fontSize": "2em" }, "_expanded": true } ] }, { "_icon": "panel", "text": "panel1", "cls": "Wb.Panel", "properties": { "cid": "panel1", "style": "box-shadow:#00000055 0px 2px 10px 5px", "cls": "w-limit-width" }, "_expanded": true, "events": { "ready": "Wb.createLoginPanel(this, f => location.reload(), false, _$verifyCode$_);" } }, { "cls": "Wb.Toolbar", "properties": { "cid": "bbar", "isProperty": "true", "padding": "true", "justify": "center" }, "text": "bbar", "_expanded": true, "_icon": "toolbar", "items": [ { "_icon": "label", "text": "copyrightLabel", "cls": "Wb.Label", "properties": { "cid": "copyrightLabel", "text": "Copyright © Geejing, All Rights Reserved.", "style": "color:#555", "fontSize": ".8em" } } ] } ] } ] } # sys/session/logout.xwl Title: Logout Description: Login request ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "request.getSession(false)?.invalidate();", "loginRequired": "false", "remark": "Login request" }, "_icon": "module", "title": "@logout", "icon": "", "img": "", "hideInMenu": "false", "tags": "" } # sys/session/refresh.xwl Title: refresh Description: Refresh current http session ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "remark": "Refresh current http session" }, "_icon": "module", "items": [] } # sys/session/service.xwl Title: service Description: Session service without login ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "if (!Params.xaction)\n return;\nlet actions = {\n /**\n * Create captcha image.\n */\n captcha() {\n const CaptchaGenerator = Java.type('com.wb.tool.CaptchaGenerator');\n const ImageIO = Java.type('javax.imageio.ImageIO');\n const charCount = 4;\n const fontSize = Math.min(parseInt(Params.fontSize) || 20, 80);\n let captcha, image, code, session;\n\n captcha = new CaptchaGenerator(Math.round(fontSize * 1.1 * charCount * 1.2), Math.round(fontSize * 1.5), charCount, 9);\n image = captcha.getImage();\n code = captcha.getCode();\n session = request.getSession();\n session.setAttribute('sys.verifyCode', code);\n response.setContentType('image/jpeg');\n response.setHeader('Pragma', 'no-cache');\n response.setHeader('Cache-Control', 'no-cache');\n response.setDateHeader('Expires', 0);\n ImageIO.write(image, 'png', response.getOutputStream());\n },\n /**\n * Monitoring websocket open and close for auto logout.\n */\n monWebsocket() {\n if (Wb.getConfig('sys.session.autoLogout') && WebUtil.isLogined(httpSession)) {\n const timerName = 'sys.logoutTimer';\n if (event == 'open') {\n httpSession.getAttribute(timerName)?.cancel(false);\n httpSession.removeAttribute(timerName);\n } else if (event == 'close' && !httpSession.getAttribute(timerName)) {\n let timer, map;\n\n map = Sessions.getWSMap(httpSession);\n if (map == null || map.size() < 2) {\n // Only this socket exists, which means need to logout.\n timer = Wb.setTimeout(f => {\n let session = params.session;\n session.removeAttribute('sys.logoutTimer');\n session.invalidate();\n }, 10000, { session: httpSession });\n httpSession.setAttribute(timerName, timer);\n }\n }\n }\n }\n};\nactions[Params.xaction]();", "loginRequired": "false", "remark": "Session service without login" }, "_icon": "module", "title": "", "icon": "", "img": "", "hideInMenu": "false", "tags": "" } # sys/session/set-resource-all.xwl Title: set-resource-all Description: Set all users resource ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "app.userid = Params.userid;\nWb.run('set-resource');", "remark": "Set all users resource" }, "_icon": "module", "icon": "", "img": "", "tags": "", "title": "", "hideInMenu": "false", "_expanded": true } # sys/session/set-resource.xwl Title: set-resource Description: Set current user resource ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Store big data to database.\n * @param {String} name value name.\n * @param {String} value stored value, empty value will clear the value.\n * @param {String} [type] value type:\n * -'object': represent a object or array value.\n * -'string': represent a string value, default.\n * -[other type]: auto detect.\n */\nfunction setResource() {\n let { name, value, type } = Params;\n\n if (value) {\n if (value.stream instanceof InputStream)\n value = value.stream;\n else if (type == 'object')\n type = 1;\n } else {\n value = null;\n }\n Wb.setResource(name, value, app.userid, type);\n}\nsetResource();", "remark": "Set current user resource" }, "_icon": "module", "icon": "", "img": "", "tags": "", "title": "", "hideInMenu": "false" } # sys/session/set-value-all.xwl Title: set-value-all Description: Set all users value ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "app.userid = Params.userid;\nWb.run('set-value');", "remark": "Set all users value" }, "_icon": "module", "icon": "", "img": "", "tags": "", "title": "", "hideInMenu": "false" } # sys/session/set-value.xwl Title: set-value Description: Set current user value ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Store short value to database\n * @param {String} name value name.\n * @param {String} value stored value, empty value will clear the value.\n * @param {String} [type] value type:\n * -'number': represent a number value.\n * -'date': represent a date value.\n * -'bool': represent a boolean value.\n * -'string': represent a string value, default.\n */\nfunction setValue() {\n //allowed names when starts with \"sys.\"\n const allowSysNames = ['sys.theme', 'sys.fontSize'];\n let { name, value, type } = Params, isSysName, session;\n\n isSysName = name.startsWith('sys.');\n if (isSysName && !allowSysNames.includes(name))\n Wb.accessDenied();\n if (value) {\n /* type: 0 string, 1 number, 2 date, 3 bool */\n switch (type) {\n case 'number':\n type = 1;\n break;\n case 'date':\n type = 2\n break;\n case 'bool':\n type = 3\n break;\n }\n } else {\n value = null;\n }\n Wb.setValue(name, value, app.userid, type);\n if (isSysName) {\n //System variables are added to the session attributes\n session = request.getSession();\n if (value == null)\n session.removeAttribute(name);\n else\n session.setAttribute(name, value);\n }\n}\nsetValue();", "remark": "Set current user value" }, "_icon": "module", "icon": "", "img": "", "tags": "", "title": "", "hideInMenu": "false" } # sys/session/verify.xwl Title: verify Description: Verify user account and login to system ```json { "text": "module", "cls": "Wb.Module", "properties": { "cid": "module", "serverScript": "/**\n * Verify the user name and password, the session will be created after success. @priv\n */\nfunction main() {\n try {\n Wb.UserUtil.login(Params.username, Params.password, Params.verifyCode);\n if (WebUtil.fromAjax(request))\n Wb.send([Wb.username, Wb.dispname]);\n else\n response.sendRedirect('home');\n } catch (e) {\n if (e instanceof Java.type('java.lang.IllegalStateException'))\n Wb.raise(Str.exceedUsersLimit);\n else\n Wb.raise(e);\n }\n}\nmain();", "loginRequired": "false", "remark": "Verify user account and login to system" }, "_icon": "module", "title": "", "icon": "", "img": "", "hideInMenu": "false" } # test1.xwl Title: test1 ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true } # test2.xwl Title: test2 ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module", "_expanded": true } # test3.xwl Title: test3 ```json { "title": "", "icon": "", "img": "", "tags": "", "hideInMenu": "false", "text": "module", "cls": "Wb.Module", "properties": { "cid": "module" }, "_icon": "module" }