WebBuilder module examples:
File name: get-new-version.xwl
{
"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"
}
File name: about.xwl
{
"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": "<div cid='lang-en' class='w-html' style='line-height:2;display:none;'>\n <h2>About WebBuilder</h2>\n <hr class=\"w-hr\">\n <table>\n <tr>\n <td rowspan=\"6\">\n <div class=\"w-icon icon-geejing\" style=\"margin:.3em;font-size:3em;\"></div>\n </td>\n <td>WebBuilder _$type$_, Date: _$date$_</td>\n </tr>\n <tr>\n <td>Version:\n _$version$_\n (<span cid=\"newVersion\"><div class=\"w-icon w-spin icon-loading w-block\"></div> Detecting new version...</span>)\n </td>\n </tr>\n <tr>\n <td>_$lic$_</td>\n </tr>\n <tr>\n <td>Powerful rapid application development and runtime platform</td>\n </tr>\n <tr>\n <td>Server Code: _$serverCode$_</td>\n </tr>\n <tr>\n <td class='w-padding-tb'>\n <div cid='buy'></div>\n </td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <h3>Buy WebBuilder</h3>\n <p>\n WebBuilder is released under commercial license, and unauthorized commercial use is illegal.<br>\n Buy Now: <a href=\"https://www.geejing.com/buy\" target=\"_blank\">https://www.geejing.com/buy</a><br>\n If you have any question please contact our sales team: <a href=\"mailto:contact@geejing.com\">contact@geejing.com</a>\n </p>\n <hr class=\"w-hr\">\n <h3>Development Team</h3>\n <div style=\"height:8em;overflow:hidden;\">\n <div cid=\"team-list\">\n <p>Amy Liu</p>\n <p>Andy Williams</p>\n <p>Bing Xia</p>\n <p>Brian Galvin</p>\n <p>Changxing Chen</p>\n <p>Duncan Soman</p>\n <p>Eric Kane</p>\n <p>Fred Gibson</p>\n <p>Fuming Guo</p>\n <p>Hongyu Zhang</p>\n <p>Jiadong Wu</p>\n <p>Jie Chen</p>\n <p>Kevin Zhao</p>\n <p>Lindsey Su</p>\n <p>Ming Zhao</p>\n <p>Muran Xiao</p>\n <p>Olinda Ray</p>\n <p>Owen Wang</p>\n <p>Rena Jiang</p>\n <p>Ruiyang Li</p>\n <p>Sariya Diamond</p>\n <p>Terry Sam</p>\n <p>Tianen Wang</p>\n <p>Wenhao Jin</p>\n <p>Wilt Austin</p>\n </div>\n </div>\n <hr class=\"w-hr\">\n <h3>System Requirements</h3>\n <table class=\"w-table\">\n <tr>\n <th>Items</th>\n <th>Requirements</th>\n </tr>\n <tr>\n <td>Operating System</td>\n <td>Windows, Linux, MacOS</td>\n </tr>\n <tr>\n <td>Web Application Servers</td>\n <td>Any Standard Server(Tomcat, Jetty, Resin, WebLogic etc.)</td>\n </tr>\n <tr>\n <td>Memory</td>\n <td>800 MB</td>\n </tr>\n <tr>\n <td>Disk Space</td>\n <td>1 GB(Contains JRE and Tomcat)</td>\n </tr>\n <tr>\n <td>Desktop & Mobile Browser</td>\n <td>Modern Browsers(Chrome, Edge, Firefox, WebView etc.)</td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <h3>The Third Party Software</h3>\n <p>WebBuilder requires these third-party software, all of which use friendly licenses and are open source and free.\n </p>\n <table class=\"w-table\">\n <tr>\n <th>Software Name</th>\n <th>License</th>\n </tr>\n <tr>\n <td>Apache Softwares</td>\n <td>Apache</td>\n </tr>\n <tr>\n <td>GraalVM</td>\n <td>UPL</td>\n </tr>\n <tr>\n <td>JSON.org</td>\n <td>Public</td>\n </tr>\n <tr>\n <td>SLF4J</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Quartz</td>\n <td>Apache</td>\n </tr>\n <tr>\n <td>Terser</td>\n <td>BSD</td>\n </tr>\n <tr>\n <td>Javascript Obfuscator</td>\n <td>BSD 2-Clause</td>\n </tr>\n <tr>\n <td>CSSO</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Monaco Editor</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>X6</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Quill</td>\n <td>BSD 3-Clause</td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <div>Warning: WebBuilder has legal copyright registrations in the world. Unauthorized use will result in severe civil\n and criminal penalties and will be prosecuted to the maximum extent possible under the law.</div>\n <div>For more information please visit: <a href=\"https://www.geejing.com\" target=\"_blank\">https://www.geejing.com</a>\n </div>\n <div>Copyright © Geejing, All Rights Reserved.</div>\n <div>Contact us: <a href=\"mailto:contact@geejing.com\">contact@geejing.com</a></div>\n</div>\n<div cid='lang-zh-cn' class='w-html' style='line-height:2;display:none;'>\n <h2>关于 WebBuilder</h2>\n <hr class=\"w-hr\">\n <table>\n <tr>\n <td rowspan=\"6\">\n <div class=\"w-icon icon-geejing\" style=\"margin:.3em;font-size:3em;\"></div>\n </td>\n <td>WebBuilder _$type$_,发布日期:_$date$_</td>\n </tr>\n <tr>\n <td>\n 版本:_$version$_\n (<span cid=\"newVersion\"><div class=\"w-icon w-spin icon-loading w-block\"></div> 正在检测新版本...</span>)\n </td>\n </tr>\n <tr>\n <td>_$lic$_</td>\n </tr>\n <tr>\n <td>强大的快速应用开发和运行平台</td>\n </tr>\n <tr>\n <td>服务器编号:_$serverCode$_</td>\n </tr>\n <tr>\n <td class='w-padding-tb'>\n <div cid='buy'></div>\n </td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <h3>购买 WebBuilder</h3>\n <p>\n WebBuilder 在商业许可证下发布,未授权的商用是违法的。<br>\n 立即购买:<a href=\"https://www.geejing.com/buy\" target=\"_blank\">https://www.geejing.com/buy</a><br>\n 如果您有任何问题请联系我们的销售团队:<a href=\"mailto:contact@geejing.com\">contact@geejing.com</a>\n </p>\n <hr class=\"w-hr\">\n <h3>开发人员</h3>\n <div style=\"height:8em;overflow:hidden;\">\n <div cid=\"team-list\">\n <p>Amy Liu</p>\n <p>Andy Williams</p>\n <p>Bing Xia</p>\n <p>Brian Galvin</p>\n <p>Changxing Chen</p>\n <p>Duncan Soman</p>\n <p>Eric Kane</p>\n <p>Fred Gibson</p>\n <p>Fuming Guo</p>\n <p>Hongyu Zhang</p>\n <p>Jiadong Wu</p>\n <p>Jie Chen</p>\n <p>Kevin Zhao</p>\n <p>Lindsey Su</p>\n <p>Ming Zhao</p>\n <p>Muran Xiao</p>\n <p>Olinda Ray</p>\n <p>Owen Wang</p>\n <p>Rena Jiang</p>\n <p>Ruiyang Li</p>\n <p>Sariya Diamond</p>\n <p>Terry Sam</p>\n <p>Tianen Wang</p>\n <p>Wenhao Jin</p>\n <p>Wilt Austin</p>\n </div>\n </div>\n <hr class=\"w-hr\">\n <h3>系统运行要求</h3>\n <table class=\"w-table\">\n <tr>\n <th>条目</th>\n <th>需求</th>\n </tr>\n <tr>\n <td>操作系统</td>\n <td>Windows, Linux, MacOS</td>\n </tr>\n <tr>\n <td>Web 应用服务器</td>\n <td>任何符合工业标准的服务器(Tomcat,Jetty,Resin,WebLogic 等)</td>\n </tr>\n <tr>\n <td>内存</td>\n <td>800 MB</td>\n </tr>\n <tr>\n <td>磁盘空间</td>\n <td>1 GB(包含 JRE and Tomcat)</td>\n </tr>\n <tr>\n <td>桌面和移动端浏览器</td>\n <td>现代浏览器(Chrome, Edge, Firefox, WebView 等)</td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <h3>第三方软件</h3>\n <p>WebBuilder 是自主研发的软件,完全符合信创要求。运行 WebBuilder 需要这些第三方软件,这些软件都使用了友好的授权并且是开源和免费的。</p>\n <table class=\"w-table\">\n <tr>\n <th>软件名称</th>\n <th>授权协议</th>\n </tr>\n <tr>\n <td>Apache Softwares</td>\n <td>Apache</td>\n </tr>\n <tr>\n <td>GraalVM</td>\n <td>UPL</td>\n </tr>\n <tr>\n <td>JSON.org</td>\n <td>Public</td>\n </tr>\n <tr>\n <td>SLF4J</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Quartz</td>\n <td>Apache</td>\n </tr>\n <tr>\n <td>Terser</td>\n <td>BSD</td>\n </tr>\n <tr>\n <td>Javascript Obfuscator</td>\n <td>BSD 2-Clause</td>\n </tr>\n <tr>\n <td>CSSO</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Monaco Editor</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>X6</td>\n <td>MIT</td>\n </tr>\n <tr>\n <td>Quill</td>\n <td>BSD 3-Clause</td>\n </tr>\n </table>\n <hr class=\"w-hr\">\n <div>警告:WebBuilder 拥有合法的版权注册,未经授权使用将导致严重的民事后果以及刑事处罚,并将在法律允许的最大范围内受到起诉。</div>\n <div>更多信息请访问:<a href=\"https://www.geejing.com\" target=\"_blank\">https://www.geejing.com</a>\n </div>\n <div>版权所有 © 北京技景科技有限公司,保留所有权利。</div>\n <div>联系我们:<a href=\"mailto:contact@geejing.com\">contact@geejing.com</a></div>\n</div>",
"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
}
]
}
File name: set-actions.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Set block actions",
"serverScript": "let actions = {\n /**\n * Get IPs.\n */\n getIPs() {\n var file = new Wb.File(Base.path, 'site/ips.txt'), result;\n if (!file.exists) {\n file = new Wb.File(Base.path, 'wb/system/ips.txt');\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 = new Wb.File(Base.path, 'site/ips.txt'), text = Wb.payload;\n if (!file.exists) {\n file = new Wb.File(Base.path, 'wb/system/ips.txt');\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"
}
File name: blocked-ip.xwl
{
"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",
"hasDupCid": 0,
"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"
},
"events": {
"ready": "app.reload();",
"change": "app.saveItem.disabled = false;"
}
}
]
}
]
}
File name: buy.xwl
{
"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"
}
File name: select-by-date.xwl
{
"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"
}
File name: select-by-ip.xwl
{
"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"
}
File name: select-by-url.xwl
{
"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"
}
File name: select-down-count.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: access-log.xwl
{
"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",
"hasDupCid": 0,
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_icon": "column",
"text": "dateCol",
"cls": "Wb.Column",
"properties": {
"cid": "dateCol",
"text": "日期",
"fieldName": "sdate",
"width": "13em"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ipCol",
"cls": "Wb.Column",
"properties": {
"cid": "ipCol",
"text": "IP地址",
"fieldName": "ip_addr"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "urlCol",
"cls": "Wb.Column",
"properties": {
"cid": "urlCol",
"text": "URL地址",
"fieldName": "url",
"width": "20em"
},
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_icon": "column",
"text": "dateCol",
"cls": "Wb.Column",
"properties": {
"cid": "dateCol",
"text": "日期",
"fieldName": "date",
"width": "7em"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ctCol",
"cls": "Wb.Column",
"properties": {
"cid": "ctCol",
"text": "IP 数量",
"fieldName": "ct",
"width": "6em"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_icon": "column",
"text": "dateCol",
"cls": "Wb.Column",
"properties": {
"cid": "dateCol",
"text": "日期",
"fieldName": "date",
"width": "7em"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ctCol",
"cls": "Wb.Column",
"properties": {
"cid": "ctCol",
"text": "下载数量",
"fieldName": "ct",
"width": "6em"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ipCol",
"cls": "Wb.Column",
"properties": {
"cid": "ipCol",
"text": "IP 地址",
"fieldName": "ip_addr",
"width": "10em"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ctCol",
"cls": "Wb.Column",
"properties": {
"cid": "ctCol",
"text": "访问次数",
"fieldName": "ct",
"width": "6em"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_icon": "column",
"text": "urlCol",
"cls": "Wb.Column",
"properties": {
"cid": "urlCol",
"text": "URL 地址",
"fieldName": "url",
"width": "10em"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "ctCol",
"cls": "Wb.Column",
"properties": {
"cid": "ctCol",
"text": "访问次数",
"fieldName": "ct",
"width": "6em"
},
"hasDupCid": 1
}
]
}
]
}
]
}
]
}
File name: add.xwl
{
"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"
}
File name: buy.xwl
{
"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": []
}
File name: del.xwl
{
"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"
}
File name: download.xwl
{
"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": []
}
File name: edit.xwl
{
"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"
}
File name: get-page.xwl
{
"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"
}
File name: search-page.xwl
{
"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"
}
File name: search.xwl
{
"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": []
}
File name: select.xwl
{
"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"
}
File name: submit.xwl
{
"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": []
}
File name: view.xwl
{
"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 = `<!DOCTYPE html>\n<html class=\"w-x w-y w-z\" lang=\"${lang}\">\n<head>\n<meta charset=\"UTF-8\"/>\n<meta name=\"viewport\" content=\"width=device-width, user-scalable=0\"/>\n<meta name=\"description\" content=\"${desc}\"/>\n<title>${title}</title>\n<link rel=\"icon\" href=\"wb/images/app/favicon.ico\"/>\n<link rel=\"stylesheet\" href=\"wb/css/iconfont.css\"/>\n<link rel=\"stylesheet\" href=\"wb/css/classic-wb.css\"/>\n<script src=\"wb/js/locale/wb-${lang}.js\"></script>\n<script src=\"wb/js/wb.js\"></script>\n<script src=\"wb/js/wb-client.js\"></script>\n<script src=\"wb/js/cms.js\"></script>\n</head>\n<body style=\"font-size:14px\" class=\"w-disp-none\">\n<div cid=\"viewport1\" class=\"w-column w-full w-scroll-y w-no-shrink\" id='x-viewport'>\n${header}\n${content}\n${footer}\n</div>\n</body>\n</html>`;\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 += '<a class=\"' + (wrapMode ? 'w-news-witem' : 'w-news-item') + '\" target=\"_blank\" href=\"view?id=' +\n rs.getString(1) + '\">';\n html += '<div class=\"w-row\"><div class=\"w-tt-marker w-margin\"></div><div class=\"w-bold w-ftext\">' +\n rs.getString(2).substr(0, 80) + '</div></div><div class=\"w-margin-l\">';\n summary = rs.getString(4).trimLeft();\n if (summary.startsWith('[')) {\n summary = summary.substring(1, summary.indexOf(']')).trimRight();\n html += summary;\n }\n html += '</div></a>';\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 = `<div class=\"w-center w-flex\">\n<div class=\"w-center w-padding2 w-lh w-gap1\">\n<div class=\"w-icon icon-error w-size3\"></div>\n<div class=\"w-column\">\n<div>HTTP 404</div>\n<div>${Str.e404}</div>\n<a class=\"w-btn w-btn-primary\" style=\"margin-top:1.5em;\" href=\"/\">${Str.home}</a>\n</div>\n</div>\n</div>`;\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",
"items": []
}
File name: cms.xwl
{
"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",
"hasDupCid": 0,
"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": "<span>{title}</span> <span class=\"w-sub-color\">({url})</span>",
"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;"
}
}
]
}
]
}
File name: create.xwl
{
"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"
}
File name: get-ips.xwl
{
"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.tipSucc();\n }\n });\n}"
}
}
]
}
]
}
]
}
File name: create-license.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: order.xwl
{
"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": "被授权人"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "number-edit",
"text": "years",
"cls": "Wb.Number",
"properties": {
"cid": "years",
"text": "使用年限",
"maxValue": "6",
"minValue": "1",
"decimalCount": "0",
"upDownKey": "true"
},
"_expanded": true,
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "number-edit",
"text": "years",
"cls": "Wb.Number",
"properties": {
"cid": "years",
"text": "使用年限",
"maxValue": "6",
"minValue": "1",
"decimalCount": "0",
"upDownKey": "true",
"readonly": "true"
},
"_expanded": true,
"hasDupCid": 1
}
]
},
{
"_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",
"hasDupCid": 0,
"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"
}
}
]
}
]
}
]
}
]
}
File name: select-ip-count.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: run-log.xwl
{
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_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"
}
}
]
}
]
}
]
}
]
}
File name: webbuilder.xwl
{
"title": "WebBuilder Examples",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"serverScript": "let html;\n\nhtml = '<p>WebBuilder module examples:</p>\\n'\nWb.cascade(Wb.File.moduleFolder, file => {\n if (file.isModuleFile && !file.isMinFile) {\n html += '<p>File name: ' + file.name + '</p>\\n';\n html += '<pre style=\"background:#eee\"><code>\\n' + file.text.html + '\\n</code></pre>\\n';\n }\n});\nWb.send(html);",
"remark": "WebBuilder examples",
"loginRequired": "false"
},
"_icon": "module",
"items": []
}
File name: add.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select-list.xwl
{
"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"
}
File name: select-tree.xwl
{
"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"
}
File name: config.xwl
{
"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",
"hasDupCid": 0,
"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"
}
]
}
]
}
]
}
]
}
File name: config.xwl
{
"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 * Check if the name is valid.\n */\n function checkName(name) {\n if (configs[name])\n Wb.raise(Str.alreadyExists.format(name));\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 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;\n checkName(newName);\n configs[newName] = configs[name];\n file.text = Wb.encodePretty(configs);\n DataSource.setSource(newName, Wb.toJava(configs));\n break;\n case 'save':\n //Save configs\n let oldName = Params.oldName, deferName = oldName != name;\n if (deferName)\n checkName(name);\n data = Wb.decode(Params.data);\n delete data.text;\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 break;\n case 'test':\n Wb.getConn(name).close();\n break;\n }\n }\n //Start execute\n file.lock();\n try {\n service();\n } finally {\n file.unlock();\n }\n}\nmain();"
},
"_icon": "module"
}
File name: set-default.xwl
{
"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 //ignore\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 return;\n }\n rs.copyTo(tableName, dest);\n rs.close();\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;\n\n try {\n rs = Wb.sqlRS('select * from ' + tableName + ' where 1=0', db);\n } catch (e) {\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, i) => {\n if (i <= colCount) {\n fieldName = fieldName.trimLeft();\n fieldName = fieldName.substr(0, fieldName.indexOf(' '));\n if (!fieldName.equalsIC(meta.getColumnLabel(i + 1)))\n Wb.raise(Str.tableInconsistent.format(tableName, fieldName));\n }\n });\n if (colCount != oldFields.length)\n Wb.raise(Str.tableInconsistent.format(tableName, colCount));\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"
}
File name: dbc.xwl
{
"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 * Fired 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] Fired 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});",
"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": "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",
"hasDupCid": 0,
"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 });\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": "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"
}
}
]
}
]
}
]
}
File name: execute-sql.xwl
{
"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"
}
File name: export.xwl
{
"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"
}
File name: import.xwl
{
"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');\n switch (Wb.getFileExt(Params.file.name)) {\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();\n break;\n }\n}\nmain();"
},
"_icon": "module"
}
File name: select-table.xwl
{
"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 });\n }\n}\nmain();"
},
"_icon": "module"
}
File name: select-tree.xwl
{
"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"
}
File name: dbe.xwl
{
"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 * Fired before the grid loads.\n */\n onGridBeforeLoad() {\n let grid = this, card = grid.parent;\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 },\n /**\n * Fired 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 enterAsTab: true,\n arrowDownAppend: true,\n events: {\n beforeload: app.onGridBeforeLoad,\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 * Fired 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] Fired 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",
"hasDupCid": 1,
"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": true,
"_icon": "toolbar",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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();"
}
}
]
}
]
},
{
"_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",
"hasDupCid": 0,
"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": "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",
"hasDupCid": 1,
"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",
"hasDupCid": 0
}
]
}
]
},
{
"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();"
}
}
]
}
]
}
File name: add.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Add department",
"serverScript": "function main() {\n let rec = { sid: 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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: move.xwl
{
"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"
}
File name: select-manager.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: dept.xwl
{
"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').hide();\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_dept_dept_code', app.tree1.dictWin.down('dept_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",
"hasDupCid": 0,
"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').show();"
}
},
{
"_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});"
}
}
]
}
]
}
File name: file.xwl
{
"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"
}
}
]
}
]
}
File name: flow.xwl
{
"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 method 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 method 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",
"hasDupCid": 0,
"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);"
}
}
]
}
]
}
File name: select.xwl
{
"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"
}
File name: log.xwl
{
"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",
"hasDupCid": 0,
"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"
}
}
]
}
]
}
File name: remove-sessions.xwl
{
"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"
}
File name: select-sessions.xwl
{
"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"
}
File name: select-users.xwl
{
"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"
}
File name: online-users.xwl
{
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"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",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "createTimeCol",
"fieldName": "createTime",
"width": "13em",
"text": "@Str.createTime"
},
"text": "createTimeCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "lastAccessTimeCol",
"fieldName": "lastAccessTime",
"width": "13em",
"text": "@Str.lastAccessTime"
},
"text": "lastAccessTimeCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
},
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "tbar",
"isProperty": "true"
},
"text": "tbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "ipCol",
"fieldName": "ip",
"width": "18em",
"text": "@Str.ip"
},
"text": "ipCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "createTimeCol",
"fieldName": "createTime",
"width": "13em",
"text": "@Str.createTime"
},
"text": "createTimeCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "lastAccessTimeCol",
"fieldName": "lastAccessTime",
"width": "13em",
"text": "@Str.lastAccessTime"
},
"text": "lastAccessTimeCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
}
]
}
]
}
]
}
File name: clean-invalid.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Clean up invalid permissions",
"serverScript": "function main() {\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}\nmain();"
},
"_icon": "module"
}
File name: select-modules.xwl
{
"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"
}
File name: select-roles.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Select roles",
"serverScript": "function main() {\n Wb.sendRows(`select sid,role_name as text` + (Params.check ? `,0 as \"_checked\"` : '') +\n `,'true' as \"_leaf\" from wb_role where sid<>'admin' order by role_name`);\n}\nmain();"
},
"_icon": "module"
}
File name: set-permissions.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Set permissions",
"serverScript": "function main() {\n let modules = Params.modules, oldModules, file, roleId = Params.roleId, checked = Wb.getBool('checked');\n\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 file = new Wb.File(Wb.File.moduleFolder, item + '.xwl');\n if (!file.exists)\n throw Str.notExists.format(item);\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 modules.forEach(item => {\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}\nmain();"
},
"_icon": "module"
}
File name: perm.xwl
{
"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] Fired 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] Fired 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-permissions',\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.selected = true;\n else\n tree.on('success', f =>\n tree.firstItem.selected = 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": "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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "permitItem",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "permitItem",
"icon": "ok",
"text": "@Str.permit",
"keys": "Ctrl+E"
},
"events": {
"click": "app.setPerm(app.moduleTree.topSelections, app.roleId, true);"
}
},
{
"_icon": "item",
"text": "forbidItem",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "forbidItem",
"icon": "cancel",
"text": "@Str.forbid",
"keys": "Ctrl+D"
},
"events": {
"click": "app.setPerm(app.moduleTree.topSelections, app.roleId, false);"
}
},
{
"_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.ajax({\n url: xpath + '/clean-invalid',\n success() {\n Wb.tipDone(Str.clear);\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);"
}
}
]
}
]
}
File name: add.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Add role",
"serverScript": "function main() {\n let sid = 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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: get-modules-by-role.xwl
{
"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"
}
File name: get-users-by-role.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: set-module-roles.xwl
{
"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"
}
File name: set-user-roles.xwl
{
"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"
}
File name: role.xwl
{
"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 * Fired after insert or update fails.\n */\n onFailure(resp) {\n Wb.checkExists(resp, 'wb_role_role_name', app.grid1.dictWin.down('role_name'));\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",
"hasDupCid": 0,
"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').hide();"
}
},
{
"_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').show();"
}
},
{
"_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"
},
"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"
},
"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",
"hasDupCid": 0
},
{
"cls": "Wb.Grid",
"properties": {
"cid": "destGridConfigs",
"isProperty": "true",
"title": "@Str.selectedUsers"
},
"text": "destGridConfigs",
"_expanded": true,
"_icon": "grid",
"hasDupCid": 0
},
{
"cls": "Wb.Array",
"properties": {
"cid": "columnsx"
},
"text": "columnsx",
"_expanded": true,
"_icon": "array",
"hasDupCid": 0,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowNumCol",
"rowNum": "true"
},
"text": "rowNumCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"cls": "Wb.Column",
"properties": {
"cid": "userNameCol",
"fieldName": "user_name",
"width": "-1"
},
"text": "userNameCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
}
]
}
]
},
{
"_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",
"hasDupCid": 0
},
{
"cls": "Wb.Grid",
"properties": {
"cid": "destGridConfigs",
"isProperty": "true",
"title": "@Str.selectedModules",
"showIcon": "true"
},
"text": "destGridConfigs",
"_expanded": true,
"_icon": "grid",
"hasDupCid": 0
}
]
}
]
}
]
}
File name: select.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Select system information",
"serverScript": "Wb.checkDemo();\nfunction main() {\n let items = [], rt = Runtime.getRuntime(), props = System.getProperties(), env = System.getenv(),\n addr = Classes.InetAddress.getLocalHost(), total = rt.totalMemory(), free = rt.freeMemory();\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: 'Total Memory',\n value: total.mb\n }, {\n name: 'Used Memory',\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: 'Available Processors',\n value: rt.availableProcessors().intText\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: '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 Wb.send(items);\n}\nmain();"
},
"_icon": "module"
}
File name: sysinfo.xwl
{
"title": "@sysinfo",
"icon": "system",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "View system information"
},
"_icon": "module",
"_expanded": true,
"items": [
{
"_icon": "grid",
"text": "grid1",
"cls": "Wb.Grid",
"properties": {
"cid": "grid1",
"full": "true",
"url": "@xpath + '/select'",
"textSelectable": "true",
"reserveScrollbar": "true",
"pagingBar": "false"
},
"_expanded": true,
"events": {
"destroy": "clearInterval(app.autoRefreshTimer);"
},
"items": [
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "tbar",
"isProperty": "true"
},
"text": "tbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "refreshItem",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "refreshItem",
"icon": "refresh",
"text": "@Str.refresh"
},
"events": {
"click": "app.grid1.reload();"
}
},
{
"_icon": "divider",
"text": "divider1",
"cls": "Wb.Divider",
"properties": {
"cid": "divider1"
}
},
{
"_icon": "switcher-on",
"text": "toggle1",
"cls": "Wb.Toggle",
"properties": {
"cid": "toggle1",
"tip": "@Str.autoRefresh"
},
"events": {
"change": "if (value) {\n app.autoRefreshTimer = setInterval(f => {\n let grid = app.grid1;\n\n if (!grid.loading)\n grid.reload();\n }, 2000)\n} else {\n clearInterval(app.autoRefreshTimer);\n}"
}
}
]
},
{
"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": "@Str.name",
"width": "16em"
},
"text": "nameCol",
"_expanded": true,
"_icon": "column"
},
{
"cls": "Wb.Column",
"properties": {
"cid": "valueCol",
"text": "@Str.value",
"fieldName": "value",
"width": "-1",
"autoWrap": "break-all"
},
"text": "valueCol",
"_expanded": true,
"_icon": "column"
}
]
}
]
}
]
}
File name: add.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: set-status.xwl
{
"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"
}
File name: start-stop-task.xwl
{
"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"
}
File name: task.xwl
{
"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});\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",
"hasDupCid": 0,
"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"
}
]
}
]
}
]
}
]
}
File name: add.xwl
{
"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 = 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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select-roles.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: user.xwl
{
"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 * Fired after insert or update fails.\n */\n onFailure(resp) {\n Wb.checkExists(resp, 'wb_user_user_name', app.grid1.dictWin.down('user_name'));\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",
"hasDupCid": 0,
"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').hide();\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').show();\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');"
}
}
]
}
]
}
File name: save.xwl
{
"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"
}
File name: controls.xwl
{
"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",
"hasDupCid": 0,
"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;"
}
}
]
}
]
}
File name: add.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: dict.xwl
{
"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",
"hasDupCid": 0,
"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');"
}
}
]
}
]
}
File name: docs.xwl
{
"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",
"loginRequired": "false"
},
"events": {
"initialize": "Wb.docs.App.initDocs(app);"
},
"_icon": "module",
"title": "@docs",
"icon": "book1",
"img": "",
"hideInMenu": "false"
}
File name: actions.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "IDE server side common 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};\nactions[Params.xaction]();"
},
"_icon": "module"
}
File name: checkin.xwl
{
"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"
}
File name: compress.xwl
{
"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, 'sys.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"
}
File name: create-docs.xwl
{
"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 const DocsCreator = Wb.load('./docs-creator.mjs');\n creator = new DocsCreator();\n processFile(new Wb.File(Wb.File.wbFolder, 'js/wb.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'))\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": ""
}
File name: reload-system.xwl
{
"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": ""
}
File name: replace.xwl
{
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"serverScript": "Wb.checkDemo();\nfunction main() {\n let result, fileSearcher, FileSearcher = Wb.load('./file-searcher.mjs');\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": ""
}
File name: search.xwl
{
"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 let result, fileSearcher, FileSearcher = Wb.load('./file-searcher.mjs');\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": ""
}
File name: select-debug.xwl
{
"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": ""
}
File name: set-debug.xwl
{
"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": ""
}
File name: view-source.xwl
{
"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>', '<\\\\/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",
"hasDupCid": 0,
"items": [
{
"_icon": "label",
"text": "cursorLabel",
"cls": "Wb.Label",
"properties": {
"cid": "cursorLabel",
"text": "1 : 1"
}
}
]
}
]
}
]
}
File name: ide.xwl
{
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"serverScript": "function main() {\n const Util = Wb.load('./ide/util.mjs');\n const 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 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 username: Wb.username,\n openExample: Params.openExample,\n openModule: Params.openModule,\n imgs: Util.getImgs(),\n icons: Util.getIcons(),\n ssList: Util.getSsList(),\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}"
}
File name: add-type.xwl
{
"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"
}
File name: del-types.xwl
{
"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"
}
File name: edit-type.xwl
{
"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"
}
File name: save-list.xwl
{
"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"
}
File name: select-list.xwl
{
"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"
}
File name: select-type.xwl
{
"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"
}
File name: kve.xwl
{
"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 * Fired 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 method 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,
"hasDupCid": 0
},
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "tbar",
"isProperty": "true"
},
"text": "tbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"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);"
},
"hasDupCid": 1
},
{
"_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);"
},
"hasDupCid": 1
},
{
"_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 });"
},
"hasDupCid": 0
}
]
}
]
},
{
"_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,
"hasDupCid": 0
},
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "tbar",
"isProperty": "true"
},
"text": "tbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"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();"
},
"hasDupCid": 1
},
{
"_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();"
},
"hasDupCid": 1
},
{
"_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();"
},
"hasDupCid": 0
}
]
}
]
}
]
}
]
}
File name: check-out.xwl
{
"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'));\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"
}
File name: del.xwl
{
"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"
}
File name: rollback.xwl
{
"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"
}
File name: select-version.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: version.xwl
{
"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",
"hasDupCid": 0,
"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();"
},
"hasDupCid": 0
}
]
},
{
"_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
}
]
}
]
}
File name: welcome.xwl
{
"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": "<div cid='lang-en' class='w-html' style='line-height:2;display:none;'>\n <p>\n <div>Welcome to use WebBuilder!</div>\n <div>WebBuilder is a powerful rapid web application development and runtime platform, with WebBuilder you can\n develop unparalleled applications.</div>\n <div>Please follow these steps below to start WebBuilder:</div>\n </p>\n <ul>\n <li>\n <span cid='demos' class='w-key-color w-link'>Open Examples</span><br>\n <span>Classic examples to help you get started quickly.</span>\n </li>\n <li>\n <span cid='docs' class='w-key-color w-link'>Open Docs For Help</span><br>\n <span>View development manuals and API documents.</span>\n </li>\n <li>\n <span cid='ide' class='w-key-color w-link'>Open Integrated Development Environment</span><br>\n <span>A powerful development tool for developing awesome applications.</span>\n </li>\n <li>\n <span cid='dbc' class='w-key-color w-link'>Open Database Configuration</span><br>\n <span>Add your databases and click the [Default] button to set it as the default database.</span>\n </li>\n <li>\n <span cid='user' class='w-key-color w-link'>Open User Management</span><br>\n <span>Add users and change your password in time.</span>\n </li>\n </ul>\n <p>\n <div>If you have any questions please contact: <a class='w-key-color w-link'\n href='mailto:contact@geejing.com'>contact@geejing.com</a></div>\n <div>Download update: <a class='w-key-color w-link' href=\"https://www.geejing.com/download\"\n target=\"_blank\">https://www.geejing.com/download</a>\n </div>\n <div>For more information please visit: <a class='w-key-color w-link' href=\"https://www.geejing.com\"\n target=\"_blank\">https://www.geejing.com</a>\n </div>\n </p>\n</div>\n<div cid='lang-zh-cn' class='w-html' style='line-height:2;display:none;'>\n <p>\n <div>欢迎使用 WebBuilder!</div>\n <div>WebBuilder 是一款强大的快速Web应用开发和运行平台,使用 WebBuilder 您可以开发出无与伦比的应用系统。</div>\n <div>请按下列步骤开始使用 WebBuilder:</div>\n </p>\n <ul>\n <li>\n <span cid='demos' class='w-key-color w-link'>打开示例</span><br>\n <span>一些经典的示例帮助您快速学习和掌握。</span>\n </li>\n <li>\n <span cid='docs' class='w-key-color w-link'>打开文档</span><br>\n <span>查看开发手册和API文档。</span>\n </li>\n <li>\n <span cid='ide' class='w-key-color w-link'>打开集成开发环境</span><br>\n <span>用于开发应用系统的强大开发工具。</span>\n </li>\n <li>\n <span cid='dbc' class='w-key-color w-link'>打开数据库配置</span><br>\n <span>添加您的数据库,并点击[默认]按钮,设置该数据库为默认数据库。</span>\n </li>\n <li>\n <span cid='user' class='w-key-color w-link'>打开用户管理</span><br>\n <span>添加用户并及时修改您的密码。</span>\n </li>\n </ul>\n <p>\n <div>如果您有任何问题请联系:<a class='w-key-color w-link' href='mailto:contact@geejing.com'>contact@geejing.com</a></div>\n <div>下载更新:<a class='w-key-color w-link' href=\"https://www.geejing.com/download\"\n target=\"_blank\">https://www.geejing.com/download</a>\n </div>\n <div>更多信息请访问:<a class='w-key-color w-link' href=\"https://www.geejing.com\" target=\"_blank\">https://www.geejing.com</a>\n </div>\n </p>\n</div>",
"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"
}
}
]
}
]
}
]
}
File name: home.xwl
{
"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": "<span style=\"color:#fff;font-size:32px;font-weight:bold;font-style:italic;padding:.5em\">My Office System</span>"
}
}
]
},
{
"_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",
"hasDupCid": 0,
"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": "<div class='w-row w-align-center w-justify-around w-padding1' style='background:#c0f9cb'>\n <div class='w-column w-gap2'>\n <div><span class='w-bold w-size1d5'>9.5%</span> Increase</div>\n <div><span class='w-bold w-size1d5'>387</span> Amount</div>\n </div>\n <div class='w-icon icon-table w-size4'></div>\n</div>",
"frame": "true"
},
"_expanded": true
},
{
"_icon": "component",
"text": "data2",
"cls": "Wb.Component",
"properties": {
"cid": "data2",
"html": "<div class='w-row w-align-center w-justify-around w-padding1' style='background:#fde0f8'>\n <div class='w-column w-gap2'>\n <div><span class='w-bold w-size1d5'>$3,259</span> Total</div>\n <div><span class='w-bold w-size1d5'>2,328</span> Visits</div>\n </div>\n <div class='w-icon icon-dt-picker w-size4'></div>\n</div>",
"frame": "true"
}
},
{
"_icon": "component",
"text": "data3",
"cls": "Wb.Component",
"properties": {
"cid": "data3",
"html": "<div class='w-row w-align-center w-justify-around w-padding1' style='background:#f6efbd'>\n <div class='w-column w-gap2'>\n <div><span class='w-bold w-size1d5'>165</span> Items</div>\n <div><span class='w-bold w-size1d5'>5.2%</span> Percent</div>\n </div>\n <div class='w-icon icon-list w-size4'></div>\n</div>",
"frame": "true"
}
},
{
"_icon": "component",
"text": "data4",
"cls": "Wb.Component",
"properties": {
"cid": "data4",
"html": "<div class='w-row w-align-center w-justify-around w-padding1' style='background:#f1fffd'>\n <div class='w-column w-gap2'>\n <div><span class='w-bold w-size1d5'>629</span> Users</div>\n <div><span class='w-bold w-size1d5'>9,185</span> Count</div>\n </div>\n <div class='w-icon icon-cluster w-size4'></div>\n</div>",
"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');"
}
}
]
}
]
}
]
}
]
}
File name: add.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: leave.xwl
{
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 0
},
{
"_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');"
}
}
]
}
]
}
]
}
]
}
]
}
]
}
File name: add.xwl
{
"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"
}
File name: del.xwl
{
"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"
}
File name: edit.xwl
{
"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"
}
File name: get-photo.xwl
{
"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"
}
File name: select-dept.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: person.xwl
{
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 0
},
{
"_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"
}
]
}
]
}
]
}
]
}
File name: add-tab-card.xwl
{
"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",
"hasDupCid": 0,
"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();"
}
}
]
}
]
}
]
}
File name: create-page.xwl
{
"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": "<div class=\"w-grid2\" style=\"grid-template-columns: 8em 1fr;\">\n <div>Code:</div>\n <div>10001</div>\n <div>Name:</div>\n <div>Terri Duffy</div>\n <div>Birth Date:</div>\n <div>2002/07/01</div>\n <div>Email:</div>\n <div>terri0@geejing.com</div>\n</div>"
}
},
{
"_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": "<div class=\"w-padding\">\n <div cid=\"title\" class=\"w-title2\"></div>\n <div cid=\"subTitle\"></div>\n <div cid=\"list\" class=\"w-grid2\" style=\"grid-template-columns: 8em 1fr;\">\n </div>\n</div>"
},
"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 = '<span>' + new Date().dateText + '</span>';\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": "<div class=\"w-grid2\" style=\"grid-template-columns: 8em 1fr;\">\n <div>Code:</div>\n <div>{code}</div>\n <div>Name:</div>\n <div>{full_name}</div>\n <div>Birth Date:</div>\n <div>{birth_date}</div>\n <div>Email:</div>\n <div>{email}</div>\n</div>"
},
"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});"
}
}
]
}
]
}
File name: custom-style.xwl
{
"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<ol>\n <li>Set \"links\" property of the \"module\" to [\"wb/css/demo.css\"].</li>\n <li>Set \"cls\" property of the \"tab1\" to \"w-tab1\".</li>\n <li>Define the CSS style for \"w-tab1\" in the file \"wb/css/demo.css\".</li>\n</ol>",
"flex": "1"
}
}
]
}
]
}
File name: dashboard.xwl
{
"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",
"hasDupCid": 0,
"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} <br/>{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
}
]
}
]
}
File name: drag-drop.xwl
{
"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,
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Array",
"properties": {
"cid": "columns"
},
"text": "columns",
"_expanded": true,
"_icon": "array",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "column1",
"rowNum": "true"
},
"text": "column1",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column2",
"text": "code",
"fieldName": "code",
"width": "6em"
},
"text": "column2",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column3",
"fieldName": "full_name",
"text": "Full name",
"width": "-1"
},
"text": "column3",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "column1",
"rowNum": "true"
},
"text": "column1",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column2",
"text": "code",
"fieldName": "code",
"width": "6em"
},
"text": "column2",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column3",
"fieldName": "full_name",
"text": "Full name",
"width": "-1"
},
"text": "column3",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
}
]
}
]
},
{
"_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"
},
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Array",
"properties": {
"cid": "columns"
},
"text": "columns",
"_expanded": true,
"_icon": "array",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "column1",
"rowNum": "true"
},
"text": "column1",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column2",
"text": "code",
"fieldName": "code",
"width": "6em"
},
"text": "column2",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column3",
"fieldName": "full_name",
"text": "Full name",
"width": "-1"
},
"text": "column3",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "column1",
"rowNum": "true"
},
"text": "column1",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column2",
"text": "code",
"fieldName": "code",
"width": "6em"
},
"text": "column2",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"cls": "Wb.Column",
"properties": {
"cid": "column3",
"fieldName": "full_name",
"text": "Full name",
"width": "-1"
},
"text": "column3",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
}
]
}
]
}
]
}
]
}
File name: geejing-link.xwl
{
"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": []
}
File name: grid1-form.xwl
{
"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",
"hasDupCid": 0,
"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}"
}
}
]
}
]
}
File name: grid3-form.xwl
{
"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});"
}
}
]
}
]
}
File name: layout.xwl
{
"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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "setWidthBtn",
"cls": "Wb.Button",
"properties": {
"cid": "setWidthBtn",
"text": "Set Width",
"width": "10em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "flex1Btn",
"cls": "Wb.Button",
"properties": {
"cid": "flex1Btn",
"text": "Flex1",
"flex": "1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "flex2Btn",
"cls": "Wb.Button",
"properties": {
"cid": "flex2Btn",
"text": "Flex2",
"flex": "2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "customFlexBtn",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "customFlexBtn",
"flex": "2 0 12em",
"text": "Custom Flex"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2",
"width": "20em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button3",
"text": "Button3",
"width": "30em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button4",
"text": "Button4",
"width": "40em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button5",
"text": "Button5"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "setWidthBtn",
"cls": "Wb.Button",
"properties": {
"cid": "setWidthBtn",
"text": "Set Width",
"width": "10em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "flex1Btn",
"cls": "Wb.Button",
"properties": {
"cid": "flex1Btn",
"text": "Flex1",
"flex": "1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "flex2Btn",
"cls": "Wb.Button",
"properties": {
"cid": "flex2Btn",
"text": "Flex2",
"flex": "2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "customFlexBtn",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "customFlexBtn",
"flex": "2 0 12em",
"text": "Custom Flex"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button3",
"text": "Button3"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button3",
"text": "Button3",
"alignSelf": "end"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button4",
"text": "Button4",
"alignSelf": "stretch"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button3",
"text": "Button3",
"alignSelf": "end"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button4",
"text": "Button4",
"alignSelf": "stretch"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button3",
"text": "Button3",
"alignSelf": "end"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": false,
"properties": {
"cid": "button4",
"text": "Button4",
"alignSelf": "stretch"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "right1",
"text": "fill1",
"cls": "Wb.Fill",
"_expanded": false,
"properties": {
"cid": "fill1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button3",
"text": "Button3"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "customFlexBtn",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "customFlexBtn",
"flex": "2 0 1em",
"text": "Custom Flex"
},
"hasDupCid": 1
}
]
},
{
"_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,
"hasDupCid": 1,
"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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2",
"width": "20em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Button3",
"width": "30em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Button4"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"properties": {
"cid": "button5",
"text": "Button5"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button6",
"cls": "Wb.Button",
"properties": {
"cid": "button6",
"text": "Button6"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button7",
"cls": "Wb.Button",
"properties": {
"cid": "button7",
"text": "Button7",
"width": "25em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button8",
"cls": "Wb.Button",
"properties": {
"cid": "button8",
"text": "Button8"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button9",
"cls": "Wb.Button",
"properties": {
"cid": "button9",
"text": "Button9"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2",
"width": "20em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Button3",
"width": "30em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Button4"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"properties": {
"cid": "button5",
"text": "Button5"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button6",
"cls": "Wb.Button",
"properties": {
"cid": "button6",
"text": "Button6"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button7",
"cls": "Wb.Button",
"properties": {
"cid": "button7",
"text": "Button7",
"width": "25em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button8",
"cls": "Wb.Button",
"properties": {
"cid": "button8",
"text": "Button8"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button9",
"cls": "Wb.Button",
"properties": {
"cid": "button9",
"text": "Button9"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "textarea",
"text": "textArea1",
"cls": "Wb.TextArea",
"properties": {
"cid": "textArea1",
"text": "textArea",
"flex": "1",
"minHeight": "3em"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text2",
"cls": "Wb.Text",
"properties": {
"cid": "text2",
"text": "text2"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Button3"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Button4"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"properties": {
"cid": "button5",
"text": "Button5"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button6",
"cls": "Wb.Button",
"properties": {
"cid": "button6",
"text": "Button6"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button7",
"cls": "Wb.Button",
"properties": {
"cid": "button7",
"text": "Button7"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button8",
"cls": "Wb.Button",
"properties": {
"cid": "button8",
"text": "Button8"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button9",
"cls": "Wb.Button",
"properties": {
"cid": "button9",
"text": "Button9"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Button3"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Button4"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"properties": {
"cid": "button5",
"text": "Button5"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button6",
"cls": "Wb.Button",
"properties": {
"cid": "button6",
"text": "Button6"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button7",
"cls": "Wb.Button",
"properties": {
"cid": "button7",
"text": "Button7"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button8",
"cls": "Wb.Button",
"properties": {
"cid": "button8",
"text": "Button8"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button9",
"cls": "Wb.Button",
"properties": {
"cid": "button9",
"text": "Button9"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Button3"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Span 3",
"gridColumn": "span 3"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Button4"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"properties": {
"cid": "button5",
"text": "Span 3 / 2",
"gridColumn": "span 3",
"gridRow": "span 2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button6",
"cls": "Wb.Button",
"properties": {
"cid": "button6",
"text": "Button6"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button7",
"cls": "Wb.Button",
"properties": {
"cid": "button7",
"text": "Button7"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button8",
"cls": "Wb.Button",
"properties": {
"cid": "button8",
"text": "Button8"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button9",
"cls": "Wb.Button",
"properties": {
"cid": "button9",
"text": "Button9"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text2",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text2",
"text": "text2"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text3",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text3",
"text": "text3"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text4",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text4",
"text": "text4"
},
"hasDupCid": 1
},
{
"_icon": "right1",
"text": "fill1",
"cls": "Wb.Fill",
"properties": {
"cid": "fill1"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text2",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text2",
"text": "text2"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text3",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text3",
"text": "text3"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text4",
"cls": "Wb.Text",
"_expanded": true,
"properties": {
"cid": "text4",
"text": "text4"
},
"hasDupCid": 1
},
{
"_icon": "textarea",
"text": "textArea1",
"cls": "Wb.TextArea",
"properties": {
"cid": "textArea1",
"gridColumn": "span 2"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
}
]
},
{
"_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,
"hasDupCid": 1,
"items": [
{
"_icon": "button",
"text": "button1",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button1",
"text": "Center",
"width": "20em",
"height": "3em"
},
"hasDupCid": 1
}
]
},
{
"_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,
"hasDupCid": 1,
"items": [
{
"_icon": "button",
"text": "button1",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button1",
"text": "Middle",
"width": "20em",
"height": "3em"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
}
]
}
]
}
]
}
File name: module-bind-ui.xwl
{
"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": "<div>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.</div>\n<ul>\n <li>addBtn is binded to example/crud/dict-edit-dialog/add.xwl</li>\n <li>editBtn is binded to example/crud/dict-edit-dialog/edit.xwl</li>\n <li>delBtn \"disabled\" property is binded to \"delDisabled\" which set in serverScript.</li>\n</ul>",
"padding": "true"
},
"_expanded": true,
"items": [
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "tbar",
"isProperty": "true"
},
"text": "tbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"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$_"
}
}
]
}
]
}
]
}
File name: no-container.xwl
{
"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": "<p>\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</p>\n<p>\n The module has parameters: {container: false}.\n Please click the [Properties] button to view the module parameters on the IDE.\n</p>",
"padding": "true",
"autoScroll": "true"
},
"events": {
"destroy": "Wb.tip('The module is destroyed.');"
}
}
]
}
File name: performance.xwl
{
"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": "<div class='w-html'>\n <p>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.</p>\n <div>Client applications:</div>\n <ul>\n <li>Efficient algorithms and refined code are used in JavaScript.</li>\n <li>The construction of the page uses effective methods to prevent page redraw and reflow.</li>\n <li>Only uses the native CSS on the page layout without using JavaScript to calculate the layout.</li>\n <li>Advanced component library allows users to experience smooth and live effects.</li>\n <li>Modern JS and CSS are used in the client application.</li>\n </ul>\n <div>Server applications:</div>\n <ul>\n <li>Efficient algorithms and refined code enable programs to run faster with fewer resources.</li>\n <li>JavaScript on the sytem leverages the compiler to provided unparalleled performance.</li>\n <li>The system caches multiple optimized and preloaded execution contexts to support high concurrency.</li>\n <li>Share data and code with other languages like Java, Ruby, Python, LLVM, R, and others.</li>\n <li>JavaScript compatible with the latest ECMAScript specification.</li>\n </ul>\n</div>"
}
}
]
}
File name: chart.xwl
{
"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"
}
}
]
}
]
}
File name: hint.xwl
{
"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": "<ul>\n <li>Drag the left tree node to here to create a new module panel.</li>\n <li>Drag the panel to adjust its position.</li>\n <li>Set [app.noTitlebar = true] in module to auto hide title bar.</li>\n <li>Click panel \"menu button\" to set panel row and column span.</li>\n <li>Click panel \"maximize button\" to maximize panel.</li>\n <li>Click home menu \"save desktop\" to save these panels.</li>\n</ul>",
"textSelectable": "false",
"cls": "w-lh",
"autoScroll": "true"
}
}
]
}
File name: mailbox.xwl
{
"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"
}
}
]
}
]
}
]
}
]
}
File name: todo.xwl
{
"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": "<div class=\"w-row w-align-center w-gapd5 w-padding\">\n <div class=\"w-icon icon-{if data.done}check9{else}check1{/if}\"></div>\n <div class=\"w-name\">{text}</div>\n</div>",
"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
}
]
}
]
}
File name: render-to-html.xwl
{
"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": "<table class=\"w-table w-frame\">\n <tr>\n <td>text1</td>\n <td>\n <div obj='text1'>\n </td>\n </tr>\n <tr>\n <td>number1</td>\n <td>\n <div obj='{cname: \"number\", cid: \"number1\"}'></div>\n </td>\n </tr>\n <tr>\n <td>date1</td>\n <td>\n <div obj='date1'></div>\n </td>\n </tr>\n <tr>\n <td>Manual make</td>\n <td>\n <div obj='makeBtn'></div>\n </td>\n </tr>\n <tr>\n <td>Set Value</td>\n <td>\n <div\n obj=\"{ cname: 'button', text: 'Set', handler(){Wb.setValue(this.app.renderComp, { text1: 'foo', number1: 123, date1: new Date() }); }}\">\n </div>\n </td>\n </tr>\n <tr>\n <td>Get Value</td>\n <td>\n <div obj=\"{ cname: 'button', text: 'Get', handler(){Wb.tip(Wb.encode(Wb.getValue(this.app.renderComp))); }}\">\n </div>\n </td>\n </tr>\n</table>",
"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": "<div class=\"w-row-center w-gap w-margin-bottom\">\n <div class=\"w-icon icon-info1\"></div>\n <div>Please click \"Create Date Comp\" button to create a new Date component below.</div>\n</div>\n<div class=\"my-date w-justifys-start\" style=\"width:15em\"></div>"
}
},
{
"_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 "
}
}
]
}
]
}
File name: scrollbar.xwl
{
"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<br>\nand overflow content will be displayed<br>\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<br>\nand overflow content will be hidden<br>\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<br>\nscrollbar is auto<br>\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<br>\ndisplay scrollbars only when hovering<br>\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<br>\nalways hide scroll bars<br>\n(overflow content)",
"height": "3em",
"frame": "true",
"padding": "true",
"autoScroll": "hide"
}
}
]
}
]
}
File name: search-form.xwl
{
"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",
"hasDupCid": 0,
"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"
}
}
]
}
]
}
]
}
]
}
File name: table-form.xwl
{
"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"
}
}
]
}
]
}
]
}
]
}
File name: template.xwl
{
"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": "<div class='w-row w-gap w-lh w-justify-between w-padding'>\n <div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{p1}</span>\n <br><span>Growth</span>\n </div>\n <div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{[data.p2.usd]}</span>\n <br><span>Income</span>\n </div>\n <div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{p3}</span>\n <br><span>Market</span>\n </div>\n <div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{[data.p4.timeText12]}</span>\n <br><span>Datetime</span>\n </div>\n <div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{[data.p5.intText]}</span>\n <br><span>Total</span>\n </div>\n</div>",
"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": "<div class='w-items w-row w-gap w-lh w-justify-between w-padding'>\n</div>",
"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": "<div class='w-frame w-padding'>\n <span class='w-active-color w-bold w-size1d2'>{value}</span>\n <br><span>{name}</span>\n</div>",
"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]"
}
}
]
}
]
}
File name: visual-design.xwl
{
"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": "<ol>\n <li>Select container control that requires visual design, such as click viewport1 node.</li>\n <li>Click the [UI Designer] button on the toolbar to launch the visual layout designer.</li>\n <li>Drag the control(or double click/Ctrl + double click) from the control tree to the designer.</li>\n <li>Drag the control to adjust its position.</li>\n</ol>"
}
}
]
}
]
}
File name: vue-el.xwl
{
"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: `<el-select v-model=\"value\" ref=\"select\" placeholder=\"Select\" @visible-change=\"handleVisibleChange\">\n <el-option\n v-for=\"item in items\"\n :key=\"item.value\"\n :label=\"item.text\"\n :value=\"item.value\">\n </el-option>\n </el-select>`,\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: `<el-select v-model=\"value\" placeholder=\"Select\">\n <el-option\n v-for=\"item in options\"\n :key=\"item.value\"\n :label=\"item.label\"\n :value=\"item.value\">\n </el-option>\n </el-select>`,\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: `<el-select v-model=\"value\" ref=\"select\" placeholder=\"Select\" @visible-change=\"handleVisibleChange\">\n <el-option\n v-for=\"item in items\"\n :key=\"item.value\"\n :label=\"item.text\"\n :value=\"item.value\">\n </el-option>\n </el-select>`,\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
}
]
}
]
}
File name: wizard.xwl
{
"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"
}
]
}
]
}
]
}
]
}
File name: common-usage.xwl
{
"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 method. 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('<span style=\"color:red\">Hello</span>', 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('<span style=\"color:red\">Hello</span>', 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('<span style=\"color:red\">Hello</span>', 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"
}
}
]
}
File name: control.xwl
{
"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"
}
}
]
}
File name: dom-element.xwl
{
"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', '<div>abc</div>') //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')); //Determine 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')); //Determine 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')); //Determine 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"
}
}
]
}
File name: array-set.xwl
{
"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]); //Determine 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"
}
}
]
}
File name: common-usage.xwl
{
"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); //Determine 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({}); //Determine 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//Determine whether some members meet test condition\nWb.some({ foo: { name: 'Allen' }, bar: { name: 'Linda' } }, (k, v) => v.name == 'Linda');\n//Determine 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"
}
}
]
}
File name: date.xwl
{
"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; //Determine 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"
}
}
]
}
File name: map.xwl
{
"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"
}
}
]
}
File name: number.xwl
{
"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\n(123.4).hasDecimal; //Whether include decimals",
"wrapBorder": "0",
"readonly": "true"
}
}
]
}
File name: string.xwl
{
"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'<div>'.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'<div>'.htmlText; //to HTML text, output: \"<div>\"\n'<div>\\n</span>'.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"
}
}
]
}
File name: call-python.xwl
{
"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"
}
File name: common-usage.xwl
{
"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); //Determine whether it is a Java object\nisCls = Java.isType(HashMap); //Determine 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"
}
}
]
}
File name: database-access.xwl
{
"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"
}
}
]
}
File name: devtools-debug.xwl
{
"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": "<div cid='lang-en' class='w-html' style='line-height:2;display:none;'>\n <div>This example demonstrates how to remotely debug server-side code using the browser \"devtools\":</div>\n <ol>\n <li>Add the module file \"test.xwl\" and write arbitrary code in the serverScript property, such as \"Wb.log('test')\".\n </li>\n <li>Select the \"test.xwl\" module and click IDE menu [Run] ->[Toggle Debugging Status].</li>\n <li>Click the IDE menu [Run] -> [Run] to run \"test.xwl\".</li>\n <li>Click the \"Debugging\" tab card at the bottom of the IDE, and double-click the \"test1.xwl\" debugging item to open\n new window.</li>\n <li>Click the address bar in the new window, press \"Ctrl+V\" to paste the debugging address, and press Enter to open\n the \"devtools\" debugging page.</li>\n <li>After adding the keyword \"debugger\" anywhere in the script, the code will pause and wait for debugging there.\n </li>\n <li>The debugging URL is the same in the same session and the same module, debugging multiple times only requires\n refreshing the \"devtools\" debugging page after running the module.</li>\n <li>When debugging remotely, due to security reasons, the browser may block access to the debugging page and prompt\n that the page was not found. In this case, you can press [F12] key to open \"devtools\" and then press Enter key in\n the browser address bar.</li>\n </ol>\n</div>\n<div cid='lang-zh-cn' class='w-html' style='line-height:2;display:none;'>\n <div>该示例演示了如何使用浏览器\"devtools\"远程调试服务器端代码:</div>\n <ol>\n <li>添加模块文件\"test.xwl\",并在serverScript属性中编写任意代码,如:\"Wb.log('test')\"。</li>\n <li>选择\"test.xwl\"模块,并点击IDE菜单[运行]->[切换调试状态]。</li>\n <li>点击IDE菜单[运行]->[运行],运行\"test.xwl\"。</li>\n <li>点击IDE底部的\"调试\"选项卡,并双击\"test1.xwl\"调试项打开新窗口。</li>\n <li>在新窗口中点击地址栏,按\"Ctrl+V\"粘贴调试地址,并按回车键打开\"devtools\"调试页面。</li>\n <li>在脚本任意处添加关键字\"debugger\"后,代码将在该处暂停运行并等待调试。</li>\n <li>同一个模块文件在同一个HTTP会话内调试的URL地址不变,多次调试只需运行模块后刷新\"devtools\"调试页面即可。</li>\n <li>当远程调试时,基于安全原因,浏览器可能阻止对调试页面的访问并提示页面未找到,此时可以按[F12]键打开\"devtools\"并在浏览器地址栏按回车键即可。</li>\n </ol>\n</div>",
"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');"
}
}
]
}
File name: file-access.xwl
{
"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; //Determine whether the file exists\nlastModified = file.lastModified; //Last modified date as a numeric value\nlastModifiedDate = file.lastModifiedDate; //Last modified date\nisEqual = file1.equals(file1); //Whether the paths are the same\nisFile = file.isFile; //Determine whether it is a file\nisFolder = file.isFolder; //Determine whether it is a folder\nlength = file.length; //File size\nparent = file.parent; //File parent directory",
"wrapBorder": "0",
"readonly": "true"
}
}
]
}
File name: load-modules.xwl
{
"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"
}
}
]
}
File name: logs.xwl
{
"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 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 console of admin user\nWb.log('all-log', true); //Output log message to IDE 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 console of the current user\nWb.table([{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }], true); //Output table to IDE console of all users\nWb.debug('debug');\nWb.debug('all-debug', true); //Output \"debug\" to IDE 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 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 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"
}
}
]
}
File name: multi-threads.xwl
{
"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\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}",
"wrapBorder": "0",
"readonly": "true"
}
}
]
}
File name: session.xwl
{
"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//Determine whether the current user can access dbe.xwl\nlet result = Wb.permit('admin/dbe.xwl');\n//Determine whether the current user contains a role\nlet hasRole = Wb.hasRole('admin');\n//Determine 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', 'sys.ide');",
"wrapBorder": "0",
"readonly": "true"
}
}
]
}
File name: web-access.xwl
{
"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'); //Determine 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' }, 'sys.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"
}
}
]
}
File name: demo-source.xwl
{
"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 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"
}
File name: button.xwl
{
"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 <a href=\"ide?openExample=1\" target=\"_blank\">WebBuilder IDE</a>"
}
},
{
"_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,
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "item 1",
"icon": "calendar"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"text": "item 3"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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,
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "item 1",
"icon": "calendar"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"text": "item 3"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"groupName": "group1",
"text": "Button 2",
"active": "false"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button3",
"groupName": "group1",
"text": "Button 3",
"active": "false"
},
"hasDupCid": 1
},
{
"_icon": "divider",
"text": "divider1",
"cls": "Wb.Divider",
"properties": {
"cid": "divider1"
},
"_expanded": true,
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button4",
"groupName": "group2",
"text": "Button 4",
"active": "false"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"properties": {
"cid": "button2",
"text": "Button 2",
"icon": "gift",
"fontSize": "1.5em"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"properties": {
"cid": "button3",
"text": "Big icon only",
"icon": "gift",
"iconSize": "2em",
"iconAlign": "top"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"properties": {
"cid": "button4",
"text": "Big icon only",
"icon": "gift",
"iconSize": "2.5em",
"iconAlign": "top"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "container",
"text": "container1",
"cls": "Wb.Container",
"properties": {
"cid": "container1",
"layout": "row"
},
"_expanded": true,
"hasDupCid": 1,
"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"
},
"hasDupCid": 1,
"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"
},
"hasDupCid": 1,
"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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "Item 1"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "Item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item3",
"text": "Item 3"
},
"hasDupCid": 1
}
]
}
]
}
]
},
{
"_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');"
},
"hasDupCid": 1
},
{
"_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);"
},
"hasDupCid": 1
}
]
},
{
"_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)');"
}
}
]
}
]
}
]
}
]
}
File name: create-chart.xwl
{
"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"
}
File name: get-chart-data.xwl
{
"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"
}
File name: chart.xwl
{
"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});"
}
}
]
}
]
}
File name: check-slider.xwl
{
"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));"
}
}
]
}
]
}
]
}
File name: code-editor.xwl
{
"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": "<!DOCTYPE html>\n<head>\n<meta charset=\"UTF-8\"/>\n<title>html</title>\n<link rel=\"icon\" href=\"wb/images/app/favicon.ico\"/>\n<link rel=\"stylesheet\" href=\"wb/css/iconfont.css\"/>\n<link rel=\"stylesheet\" href=\"wb/css/dark-wb.css\"/>\n<script src=\"wb/js/locale/wb-zh-cn.js\"></script>\n<script src=\"wb/js/wb.js\"></script>\n<script src=\"wb/js/wb-client.js\"></script>\n</head>\n<body>\n<script type=\"module\">\nWb.onLoad(f => {\n});\n</script>\n</body>\n</html>",
"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."
}
}
]
}
]
}
File name: container.xwl
{
"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": "dockedBarsPanel",
"cls": "Wb.Panel",
"_expanded": true,
"properties": {
"cid": "dockedBarsPanel",
"frame": "true",
"title": "Panel with docked bars",
"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"
}
]
}
]
}
]
},
{
"_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<br>\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"
}
}
]
}
]
}
]
}
]
}
File name: date.xwl
{
"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});"
}
}
]
}
]
}
]
}
File name: decoration.xwl
{
"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 <span class=\"w-error-color\">label</span>"
}
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "divider",
"text": "divider1",
"cls": "Wb.Divider",
"_expanded": true,
"properties": {
"cid": "divider1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button 2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button3",
"text": "Button 3"
},
"hasDupCid": 1
},
{
"_icon": "space",
"text": "space1",
"cls": "Wb.Space",
"_expanded": false,
"properties": {
"cid": "space1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button4",
"text": "Button 4"
},
"hasDupCid": 1
},
{
"_icon": "right1",
"text": "fill1",
"cls": "Wb.Fill",
"properties": {
"cid": "fill1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button5",
"text": "Button 5"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "divider",
"text": "divider1",
"cls": "Wb.Divider",
"_expanded": true,
"properties": {
"cid": "divider1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button2",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button2",
"text": "Button 2"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button3",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button3",
"text": "Button 3"
},
"hasDupCid": 1
},
{
"_icon": "space",
"text": "space1",
"cls": "Wb.Space",
"_expanded": false,
"properties": {
"cid": "space1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button4",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button4",
"text": "Button 4"
},
"hasDupCid": 1
},
{
"_icon": "right1",
"text": "fill1",
"cls": "Wb.Fill",
"properties": {
"cid": "fill1"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "button5",
"cls": "Wb.Button",
"_expanded": true,
"properties": {
"cid": "button5",
"text": "Button 5"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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: '<div>Custom script</div>' })"
}
}
]
}
]
}
]
}
File name: sync-select.xwl
{
"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"
}
File name: dual-box.xwl
{
"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]\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",
"hasDupCid": 0
},
{
"cls": "Wb.Grid",
"properties": {
"cid": "destGridConfigs",
"isProperty": "true",
"title": "Admin Users"
},
"text": "destGridConfigs",
"_expanded": true,
"_icon": "grid",
"hasDupCid": 0
}
]
},
{
"_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"
}
]
}
]
}
]
}
File name: grid.xwl
{
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 0
}
]
},
{
"_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": true,
"_icon": "array",
"hasDupCid": 1,
"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": "<span class='w-error-color'>Full name</span>",
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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": "<div>Feature List:</div>\n<ul>\n <li>Columns sortable, resizable, draggable and freezable.</li>\n <li>Arbitrary multi-Level Headers.</li>\n <li>Customize cell rendering.</li>\n <li>Rows and columns highlighing.</li>\n <li>Local data pagination.</li>\n <li>Bind buttons or any controls to cells.</li>\n <li>Multiple styles of check columns.</li>\n <li>Customize columns and persistence to the database.</li>\n <li>Summary row.</li>\n</ul>",
"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",
"hasDupCid": 0,
"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": false,
"items": [
{
"cls": "Wb.Array",
"properties": {
"cid": "columns"
},
"text": "columns",
"_expanded": true,
"_icon": "array",
"hasDupCid": 1,
"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",
"hasDupCid": 1,
"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"
}
]
}
]
}
]
}
]
}
File name: html-editor.xwl
{
"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": "<p>\n <strong class=\"ql-font-Arial ql-size-p16\" style=\"color: fuchsia;\">Rich</strong>\n <u class=\"ql-font-Impact ql-size-p28\" style=\"color: lime;\">Text</u>\n <em class=\"ql-size-p36 ql-font-Times-New-Roman\" style=\"color: blue;\">Editor</em>\n</p>"
}
}
]
}
]
}
File name: input.xwl
{
"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": "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']"
}
}
]
}
]
}
]
}
File name: misc-comps.xwl
{
"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"
}
}
]
}
]
}
]
}
File name: option.xwl
{
"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"
}
]
}
]
}
]
}
]
}
File name: select.xwl
{
"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": "<div class=\"w-row w-align-center\">\n <div style=\"width: 3em\" class=\"w-cell w-rownum\"></div>\n <div class=\"w-icon icon-user2\"></div>\n <div class=\"w-cell w-flex\">{code}</div>\n <div class=\"w-cell w-flex3\">{full_name}</div>\n</div>",
"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 `<div class=\"w-row w-align-center\">\n <div style=\"width: 3em\" class=\"w-cell w-rownum\"></div>\n <div class=\"w-icon icon-user2\"></div>\n <div class=\"w-cell w-flex\">${data.code}</div>\n <div class=\"w-cell w-flex3\">${data.full_name}</div>\n</div>`;"
},
"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",
"hasDupCid": 1
}
]
},
{
"_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",
"hasDupCid": 1
}
]
},
{
"_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",
"hasDupCid": 1
}
]
},
{
"_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",
"hasDupCid": 1,
"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",
"hasDupCid": 1
},
{
"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",
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"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",
"hasDupCid": 1
},
{
"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",
"hasDupCid": 1
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"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",
"hasDupCid": 1
},
{
"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",
"hasDupCid": 1
}
]
}
]
}
]
},
{
"_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",
"hasDupCid": 1,
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 0
}
]
},
{
"_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}"
},
"hasDupCid": 0
}
]
},
{
"_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"
},
"hasDupCid": 0
}
]
},
{
"_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"
}
}
]
}
]
}
]
}
]
}
File name: slot.xwl
{
"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"
}
}
]
}
]
}
]
}
File name: toolbar-menu.xwl
{
"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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "@Str.add",
"icon": "add"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "@Str.edit",
"icon": "edit"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"text": "@Str.del",
"icon": "delete"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "Menu item 1"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "Menu item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"text": "Menu item 3"
},
"hasDupCid": 1
}
]
}
]
},
{
"_icon": "divider",
"text": "divider1",
"cls": "Wb.Divider",
"properties": {
"cid": "divider1"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 0
},
{
"_icon": "right1",
"text": "fill1",
"cls": "Wb.Fill",
"properties": {
"cid": "fill1"
}
},
{
"_icon": "item",
"text": "fillRightItem",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "fillRightItem",
"icon": "calendar"
},
"hasDupCid": 0
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "item 2",
"icon": "add1"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item4",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item4",
"text": "item 4",
"icon": "lantern"
},
"hasDupCid": 0
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "card",
"text": "Item2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"icon": "cube",
"text": "Item3"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "card",
"text": "Item2 Card"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"icon": "cube",
"text": "Item3"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "card",
"text": "Item2 Card"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"icon": "cube",
"text": "Item3"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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": false,
"properties": {
"cid": "item1",
"text": "Menu Item"
},
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Menu",
"properties": {
"cid": "menu",
"isProperty": "true"
},
"text": "menu",
"_expanded": true,
"_icon": "menu2",
"hasDupCid": 0,
"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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "disabledItem",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "disabledItem",
"disabled": "true",
"icon": "download",
"text": "Disabled"
},
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item1",
"text": "Item 1"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item2",
"text": "Item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item3",
"text": "Item 3"
},
"hasDupCid": 1
}
]
}
]
}
]
}
]
}
]
},
{
"_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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"text": "Menu item 1",
"icon": "book1"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"text": "Menu item 2"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"text": "Menu item 3"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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
}
]
}
]
}
]
}
File name: tree.xwl
{
"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",
"hasDupCid": 1,
"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",
"hasDupCid": 0
},
{
"_icon": "column",
"text": "landAreasCol",
"cls": "Wb.Column",
"properties": {
"cid": "landAreasCol",
"text": "Land Areas"
},
"_expanded": true,
"hasDupCid": 0,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "percentageCol",
"fieldName": "percentage",
"text": "Percentage",
"type": "percent",
"titleAlign": "right"
},
"text": "percentageCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"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",
"hasDupCid": 0
}
]
},
{
"cls": "Wb.Column",
"properties": {
"cid": "remarkCol",
"fieldName": "remark",
"text": "Remark",
"width": "-1"
},
"text": "remarkCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"_icon": "column",
"text": "checkCol1",
"cls": "Wb.Column",
"_expanded": true,
"properties": {
"cid": "checkCol1",
"checkBox": "int",
"fieldName": "myCheck",
"checkRefresh": "true",
"menuText": "Check"
},
"hasDupCid": 0
},
{
"_icon": "column",
"text": "checkCol2",
"cls": "Wb.Column",
"_expanded": true,
"properties": {
"cid": "checkCol2",
"checkBox": "roTrue",
"fieldName": "myCheck"
},
"hasDupCid": 0
},
{
"_icon": "column",
"text": "checkCol3",
"cls": "Wb.Column",
"_expanded": true,
"properties": {
"cid": "checkCol3",
"checkBox": "roAll",
"fieldName": "myCheck"
},
"hasDupCid": 0
},
{
"_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"
},
"hasDupCid": 0
},
{
"_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"
},
"hasDupCid": 0
},
{
"_icon": "column",
"text": "actionsCol",
"cls": "Wb.Column",
"_expanded": true,
"properties": {
"cid": "actionsCol",
"text": "Actions",
"width": "8em"
},
"hasDupCid": 0,
"items": [
{
"cls": "Wb.Array",
"properties": {
"cid": "buttons"
},
"text": "buttons",
"_expanded": true,
"_icon": "array",
"hasDupCid": 0,
"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);"
},
"hasDupCid": 0
},
{
"_icon": "item",
"text": "shareItem",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "shareItem",
"icon": "share2",
"tip": "Add"
},
"events": {
"click": "Wb.tip('Share ' + this.data.text);"
},
"hasDupCid": 0
}
]
}
]
}
]
}
]
},
{
"_icon": "component",
"text": "miscDescComp",
"cls": "Wb.Component",
"properties": {
"cid": "miscDescComp",
"html": "<div>Feature List:</div>\n<ul>\n <li>Columns sortable, resizable, draggable and freezable.</li>\n <li>Arbitrary multi-Level Headers.</li>\n <li>Customize cell rendering.</li>\n <li>Rows and columns highlighing.</li>\n <li>Local data pagination.</li>\n <li>Bind buttons or any controls to cells.</li>\n <li>Multiple styles of check columns.</li>\n <li>Customize columns and persistence to the database.</li>\n</ul>",
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "nameCol",
"fieldName": "name",
"expander": "true",
"text": "Name",
"width": "18em",
"sortable": "false"
},
"text": "nameCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"cls": "Wb.Column",
"properties": {
"cid": "departmentCol",
"fieldName": "department",
"text": "Department",
"width": "18em"
},
"text": "departmentCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"cls": "Wb.Column",
"properties": {
"cid": "jobTitleCol",
"fieldName": "jobTitle",
"text": "Job Title",
"width": "18em"
},
"text": "jobTitleCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
},
{
"cls": "Wb.Column",
"properties": {
"cid": "countryCol",
"fieldName": "country",
"text": "Country",
"width": "-1"
},
"text": "countryCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 0
}
]
}
]
},
{
"_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",
"hasDupCid": 0,
"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",
"hasDupCid": 1,
"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",
"hasDupCid": 0
}
]
},
{
"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",
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
}
]
}
]
}
]
}
]
}
File name: view.xwl
{
"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": "<div class=\"w-row w-align-center w-gapd5 w-padding\">\n <div class=\"w-icon icon-{icon}\"></div>\n <div class=\"w-name\">{text}</div>\n</div>",
"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 `<div class=\"w-row w-align-center w-gapd5 w-padding\">\n <div class=\"w-icon icon-${Wb.toHTML(data.icon)}\"></div>\n <div class=\"w-name\">${Wb.toHTML(data.text)}</div>\n</div>`;"
},
"_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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-label w-ta-center\">{text}</div>\n</div>",
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5\" style=\"width:10em\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-name w-ta-center w-aligns-stretch\">{text}</div>\n</div>",
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5 w-no-shrink\" style=\"width:10em\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-name w-ta-center w-aligns-stretch\">{text}</div>\n</div>",
"data": "app.viewData",
"multiSelect": "true",
"resizable": "true",
"frame": "true",
"bodyCls": "w-row w-padding w-gapd5 w-visible-all",
"stickSelect": "true"
}
},
{
"_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": "<!-- Tip: For complex templates, it is recommended to use itemTplFn to define custom function -->\n<div class=\"w-item w-border\" style=\"display:grid;grid-template-columns:2em 8em 16em 1fr;padding:1em;gap:.5em\">\n <div>{num}</div>\n <div>{[data.money.usd]}</div>\n <div>{[data.date.dateTimeText12]}</div>\n <div>{for data.array}{if index > 0}<span>, </span>{/if}<span>{[index + 1]}: </span><span>{[value]}</span>{/for}</div>\n</div>",
"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 += '<span>, </span>';\n arrayText += '<span>' + (i + 1) + ': </span><span>' + Wb.toHTML(item) + '</span>';\n});\nreturn `<div class=\"w-item w-border\" style=\"display:grid;grid-template-columns:2em 8em 16em 1fr;padding:1em;gap:.5em\">\n <div>${Wb.toHTML(data.num)}</div>\n <div>${Wb.toHTML(data.money.usd)}</div>\n <div>${Wb.toHTML(data.date.dateTimeText12)}</div>\n <div>${arrayText}</div>\n</div>`;",
"html": "<div class=\"w-fixed-bgcolor\" style=\"display:grid;grid-template-columns:2em 8em 16em 1fr;padding:1em;gap:.5em\">\n <div></div>\n <div>Money</div>\n <div>Date</div>\n <div>Content</div>\n</div>\n<div class=\"w-items w-flex\">\n</div>",
"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": "<div class=\"w-item w-border w-row w-padding w-align-center w-gapd5\">\n <div class=\"w-icon icon-user2 w-size2\"></div>\n <div class=\"w-column w-gapd2\">\n <div class=\"w-name\">{full_name}</div>\n <div class=\"w-name w-sub-color w-sized8\">{code}</div>\n </div>\n <div class=\"w-flex\"></div>\n <div class=\"w-column w-sized8 w-gapd2\">\n <div class=\"w-name\">{[new Date().format('HH:mm')]}</div>\n <div class=\"w-icon icon-flag4 w-sub-color w-aligns-end\"></div>\n </div>\n</div>",
"resizable": "true",
"frame": "true",
"url": "demo-source?xaction=staffDict",
"height": "20em",
"pagingBar": "true",
"pageSize": "10"
},
"_expanded": true
},
{
"_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": "<div class=\"w-item w-row w-padding w-align-center w-gapd5\">\n <div class=\"w-icon icon-tag\"></div>\n <div class=\"w-name\">{full_name}</div>\n <div class=\"w-btn w-close-btn w-btn-light\">\n <div class=\"w-icon icon-close\"></div>\n </div>\n</div>",
"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": "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": "<div class=\"w-padding\">{code} - {full_name}</div>",
"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": "<div class=\"w-padding\">{code} - {full_name}</div>",
"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": "<div class=\"w-padding\">{text}</div>"
},
"_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": "<div class=\"w-item w-padding1\">{code} - {full_name}</div>",
"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": "<div class=\"w-item w-padding1\">{code} - {full_name}</div>",
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-label w-ta-center\">{text}</div>\n</div>",
"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",
"hasDupCid": 0,
"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": "<div>Feature List:</div>\n<ul>\n <li>Drag to draw a rectangle to select items.</li>\n <li>Press key to enter name in the view can navigate to the specified item.</li>\n <li>Maintain scrollbar position after reloading data.</li>\n <li>Intelligent navigate to specified item based on arrow key direction.</li>\n <li>Drag-and-Drop support.</li>\n</ul>",
"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",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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));"
}
}
]
}
]
}
]
}
]
}
File name: visual.xwl
{
"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": "🎭"
}
}
]
}
]
}
]
}
]
}
File name: actions.xwl
{
"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 //session: websocket session\n //httpSession: http session\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};\nactions[Params.xaction]();"
},
"_icon": "module"
}
File name: web-socket.xwl
{
"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('<img src=\"data:image/png;base64,' + value + '\">', 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);"
}
}
]
}
]
}
File name: window.xwl
{
"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": "no instanced items",
"cls": "Wb.Array",
"properties": {
"cid": "no instanced items"
},
"_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"
},
"hasDupCid": 1
},
{
"_icon": "calendar",
"text": "date1",
"cls": "Wb.Date",
"properties": {
"cid": "date1",
"text": "Birth date"
},
"_expanded": true,
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "calendar",
"text": "date1",
"cls": "Wb.Date",
"properties": {
"cid": "date1",
"text": "Birth date"
},
"_expanded": true,
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Your name"
},
"_expanded": true,
"hasDupCid": 1
},
{
"_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,
"hasDupCid": 1
}
]
},
{
"_icon": "dialog",
"text": "normalDialog",
"cls": "Wb.Dialog",
"_expanded": true,
"properties": {
"cid": "normalDialog",
"title": "Normal Dialog",
"layout": "grid1"
}
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "calendar",
"text": "date1",
"cls": "Wb.Date",
"properties": {
"cid": "date1",
"text": "Birth date"
},
"_expanded": true,
"hasDupCid": 1
},
{
"_icon": "button",
"text": "newDialog",
"cls": "Wb.Button",
"properties": {
"cid": "newDialog",
"text": "New Dialog",
"type": "primary"
},
"events": {
"click": "app.newDialog.show();"
},
"hasDupCid": 1
},
{
"cls": "Wb.Array",
"properties": {
"cid": "tools"
},
"text": "tools",
"_expanded": true,
"_icon": "array",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Item",
"events": {
"click": "Wb.tip(Str.set);"
},
"properties": {
"cid": "item1",
"icon": "gear"
},
"text": "item1",
"_expanded": true,
"_icon": "item",
"hasDupCid": 1
}
]
},
{
"cls": "Wb.Menu",
"properties": {
"cid": "menu",
"isProperty": "true"
},
"text": "menu",
"_expanded": true,
"_icon": "menu2",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"icon": "add",
"text": "@Str.add"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "edit",
"text": "@Str.edit"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": false,
"properties": {
"cid": "item3",
"icon": "delete",
"text": "@Str.del"
},
"hasDupCid": 1
}
]
}
]
},
{
"_icon": "dialog",
"text": "newDialog",
"cls": "Wb.Dialog",
"_expanded": true,
"properties": {
"cid": "newDialog",
"title": "New Dialog",
"layout": "grid1"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"icon": "add",
"text": "Item1",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "edit",
"text": "Item2",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item3",
"icon": "delete",
"text": "Item3",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item4",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item4",
"icon": "book1",
"text": "Item4",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item5",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item5",
"icon": "discovery",
"text": "Item5",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item6",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item6",
"icon": "comment2",
"text": "Item6",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item7",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item7",
"icon": "flow1",
"text": "Item7",
"iconAlign": "top",
"iconSize": "2em"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Input text",
"gridColumn": "span 5"
},
"_expanded": true,
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Item",
"properties": {
"cid": "item1",
"icon": "gear"
},
"text": "item1",
"_expanded": true,
"_icon": "item",
"hasDupCid": 1
},
{
"cls": "Wb.Item",
"properties": {
"cid": "item2",
"icon": "share"
},
"text": "item2",
"_expanded": true,
"_icon": "item",
"hasDupCid": 1
}
]
}
]
},
{
"_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,
"hasDupCid": 1,
"items": [
{
"_icon": "item",
"text": "item1",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item1",
"icon": "favorite",
"text": "Favorite Pages"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item2",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item2",
"icon": "gear",
"text": "Setting"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item3",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item3",
"icon": "command",
"text": "Command"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item4",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item4",
"icon": "word",
"text": "Export to Word"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item5",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item5",
"icon": "excel",
"text": "Export to Excel"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "item",
"text": "item7",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "item7",
"icon": "table",
"text": "Show Table"
},
"hasDupCid": 1
}
]
}
]
}
]
},
{
"_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": true,
"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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Your name"
},
"hasDupCid": 1
}
]
}
]
},
{
"_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'));"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "htmlInfoBtn",
"cls": "Wb.Button",
"properties": {
"cid": "htmlInfoBtn",
"text": "HTML Info"
},
"events": {
"click": "Wb.info('<span class=\"w-error-color\">HTML information</span>', null, true);"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "succBtn",
"cls": "Wb.Button",
"properties": {
"cid": "succBtn",
"text": "Succ"
},
"events": {
"click": "Wb.succ('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "warnBtn",
"cls": "Wb.Button",
"properties": {
"cid": "warnBtn",
"text": "Warn"
},
"events": {
"click": "Wb.warn('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "errorBtn",
"cls": "Wb.Button",
"properties": {
"cid": "errorBtn",
"text": "Error"
},
"events": {
"click": "Wb.error('Some information');"
},
"hasDupCid": 1
},
{
"_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');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "htmlInfoBtn",
"cls": "Wb.Button",
"properties": {
"cid": "htmlInfoBtn",
"text": "HTML tip"
},
"events": {
"click": "Wb.tip('<span class=\"w-error-color\">HTML information</span>', true);"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "succBtn",
"cls": "Wb.Button",
"properties": {
"cid": "succBtn",
"text": "Succ"
},
"events": {
"click": "Wb.tipSucc('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "warnBtn",
"cls": "Wb.Button",
"properties": {
"cid": "warnBtn",
"text": "Warn"
},
"events": {
"click": "Wb.tipWarn('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "errorBtn",
"cls": "Wb.Button",
"properties": {
"cid": "errorBtn",
"text": "Error"
},
"events": {
"click": "Wb.tipError('Some information');"
},
"hasDupCid": 1
},
{
"_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');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "htmlInfoBtn",
"cls": "Wb.Button",
"properties": {
"cid": "htmlInfoBtn",
"text": "HTML tip"
},
"events": {
"click": "Wb.toast('<span class=\"w-error-color\">HTML information</span>', true);"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "succBtn",
"cls": "Wb.Button",
"properties": {
"cid": "succBtn",
"text": "Succ"
},
"events": {
"click": "Wb.toastSucc('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "warnBtn",
"cls": "Wb.Button",
"properties": {
"cid": "warnBtn",
"text": "Warn"
},
"events": {
"click": "Wb.toastWarn('Some information');"
},
"hasDupCid": 1
},
{
"_icon": "button",
"text": "errorBtn",
"cls": "Wb.Button",
"properties": {
"cid": "errorBtn",
"text": "Error"
},
"events": {
"click": "Wb.toastError('Some information');"
},
"hasDupCid": 1
}
]
},
{
"_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": "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, 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": true,
"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,
"hasDupCid": 0,
"items": [
{
"_icon": "label",
"text": "label1",
"cls": "Wb.Label",
"properties": {
"cid": "label1",
"titleType": "title4",
"text": "Some descriptions"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Text"
},
"hasDupCid": 1
},
{
"_icon": "number-edit",
"text": "number1",
"cls": "Wb.Number",
"properties": {
"cid": "number1",
"text": "Number"
},
"hasDupCid": 0
},
{
"_icon": "label1",
"text": "displayField1",
"cls": "Wb.DisplayField",
"properties": {
"cid": "displayField1",
"text": "Display Field",
"value": "Some value"
},
"hasDupCid": 0
},
{
"_icon": "button",
"text": "button1",
"cls": "Wb.Button",
"properties": {
"cid": "button1",
"text": "Button",
"icon": "button"
},
"hasDupCid": 0
}
]
}
]
},
{
"_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);"
}
}
]
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: dict-edit-dialog.xwl
{
"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",
"hasDupCid": 0,
"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);"
}
}
]
}
]
}
File name: dict-edit-grid.xwl
{
"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 * Fired 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",
"hasDupCid": 0,
"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);"
}
}
]
}
]
}
File name: edit-dialog.xwl
{
"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",
"hasDupCid": 0,
"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"
}
]
}
]
}
]
}
]
}
File name: edit-grid.xwl
{
"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 * Fired 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",
"hasDupCid": 0,
"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",
"hasDupCid": 0
}
]
},
{
"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",
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 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",
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
},
{
"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"
},
"hasDupCid": 0
}
]
}
]
}
]
}
]
}
]
}
File name: select-staff.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "true",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"serverScript": "Wb.sendRowx('select * from wb_staff');"
},
"_icon": "module"
}
File name: staff.xwl
{
"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'"
}
}
]
}
]
}
File name: card.xwl
{
"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"
}
}
]
}
File name: common-window.xwl
{
"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"
}
}
]
}
File name: panel.xwl
{
"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"
}
}
]
}
File name: single-window.xwl
{
"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"
}
}
]
}
]
}
File name: client-load-module.xwl
{
"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)));"
}
}
]
}
]
}
File name: actions.xwl
{
"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": []
}
File name: client-request.xwl
{
"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'});"
}
}
]
}
]
}
File name: code-static-load.xwl
{
"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"
}
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: file-updownload.xwl
{
"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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Other control"
},
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "text",
"text": "text1",
"cls": "Wb.Text",
"properties": {
"cid": "text1",
"text": "Other control"
},
"hasDupCid": 1
},
{
"_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});"
}
}
]
}
]
}
]
}
File name: execute.xwl
{
"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"
}
File name: query.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"serverScript": "Wb.sendRows('select * from wb_staff');"
},
"_icon": "module"
}
File name: util.xwl
{
"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"
}
File name: server-load-module.xwl
{
"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});"
}
}
]
}
]
}
File name: actions.xwl
{
"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",
"items": []
}
File name: server-request.xwl
{
"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});"
}
}
]
}
]
}
File name: switch-module.xwl
{
"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"
}
File name: xwl-static-load.xwl
{
"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' })"
}
}
]
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: excel-form.xwl
{
"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",
"hasDupCid": 0,
"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"
}
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: excel-report.xwl
{
"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",
"hasDupCid": 0,
"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 */"
}
}
]
}
]
}
File name: send.xwl
{
"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"
}
File name: mail-sender.xwl
{
"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});"
}
}
]
}
]
}
File name: create.xwl
{
"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"
}
File name: sql-to-excel.xwl
{
"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');"
}
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: chat.xwl
{
"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 let dialog = app.userDetailDialog;\n app.summaryComp.update(data)\n app.openUserData = data;\n dialog.show();\n dialog.el.scrollTop = 0;\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",
"hasDupCid": 0,
"items": [
{
"_icon": "item",
"text": "fileItem",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "fileItem",
"tip": "Send file",
"icon": "folder-open",
"handler": "app.sendFile"
},
"hasDupCid": 1
}
]
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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": "dialog",
"text": "userDetailDialog",
"cls": "Wb.Dialog",
"properties": {
"cid": "userDetailDialog",
"autoScroll": "true"
},
"_expanded": true,
"items": [
{
"_icon": "component",
"text": "summaryComp",
"cls": "Wb.Component",
"properties": {
"cid": "summaryComp",
"tpl": "<div class=\"w-row w-gap1\">\n <div class=\"w-icon icon-user2 w-size3 w-aligns-center\"></div>\n <div class=\"w-column w-gap\">\n <div class=\"w-row w-gap\">\n <div class=\"w-title4\">{display_name}</div>\n <div class=\"w-icon icon-user3 w-aligns-center\"></div>\n </div>\n <div>User name: {user_name}</div>\n <div>User id: {sid}</div>\n <div>E-mail: {email}</div>\n </div>\n</div>",
"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 data = app.openUserData;\napp.userDetailDialog.close(true); // optional\napp.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"
}
}
]
}
]
},
{
"_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<div class=\"w-item w-fixed-bgcolor-x\" style=\"height:.6em\"></div>\n{else}\n<div class=\"w-item w-border w-row w-padding1 w-align-center w-gapd5 w-main-bgcolor w-pointer\">\n <div class=\"w-icon icon-{icon} w-size1d5\"></div>\n <div class=\"w-name\">{title}</div>\n <div class=\"w-flex\"></div>\n <div class=\"w-icon icon-right2 w-sub-color\"></div>\n</div>\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": "<div class=\"w-row w-justify-around w-padding2\" style=\"background:#4caf50\">\n <div class=\"w-column w-padding w-gap w-align-center w-pointer w-unselect\" xid=\"payment\">\n <div class=\"w-icon icon-check9 w-size2\" style=\"color:#fff;\"></div>\n <div style=\"color: #fff;\">Payment</div>\n </div>\n <div class=\"w-column w-padding w-gap w-align-center w-pointer w-unselect\" xid=\"wallet\">\n <div class=\"w-icon icon-card w-size2\" style=\"color:#fff;\"></div>\n <div style=\"color: #fff;\">Wallet</div>\n </div>\n</div>"
},
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5 w-pointer\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-label w-ta-center\">{text}</div>\n</div>",
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5 w-pointer\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-label w-ta-center\">{text}</div>\n</div>",
"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": "<div class=\"w-item w-column w-align-center w-padding w-gapd5 w-pointer\">\n <div class=\"w-size2 w-icon icon-{icon}\"></div>\n <div class=\"w-label w-ta-center\">{text}</div>\n</div>",
"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
}
]
}
]
}
]
}
]
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: after-action.xwl
{
"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"
}
File name: before-action.xwl
{
"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"
}
File name: handle-form.xwl
{
"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"
}
}
]
}
]
}
]
}
]
}
File name: start-form.xwl
{
"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"
}
}
]
}
]
}
File name: start.xwl
{
"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"
}
File name: manual-start.xwl
{
"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
}
]
}
]
}
File name: actions.xwl
{
"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"
}
File name: handle-form.xwl
{
"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"
}
}
]
}
]
}
File name: start-form.xwl
{
"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 * @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 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",
"hasDupCid": 0,
"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",
"hasDupCid": 0
}
]
},
{
"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",
"hasDupCid": 0
}
]
},
{
"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",
"hasDupCid": 0
}
]
}
]
}
]
}
]
}
]
}
File name: start-form.xwl
{
"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"
}
}
]
}
]
}
File name: home.xwl
{
"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;"
}
}
]
}
File name: back.xwl
{
"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"
}
File name: get-his-nodes.xwl
{
"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"
}
File name: get-start-form.xwl
{
"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"
}
File name: pass.xwl
{
"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"
}
File name: reject.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: sign-after.xwl
{
"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"
}
File name: sign-before.xwl
{
"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"
}
File name: start.xwl
{
"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"
}
File name: terminate.xwl
{
"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"
}
File name: transfer.xwl
{
"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"
}
File name: view-progress.xwl
{
"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"
}
File name: view.xwl
{
"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"
}
File name: my-flow.xwl
{
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0,
"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",
"hasDupCid": 1,
"items": [
{
"cls": "Wb.Column",
"properties": {
"cid": "rowCol",
"rowNum": "true"
},
"text": "rowCol",
"_expanded": true,
"_icon": "column",
"hasDupCid": 1
},
{
"_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"
},
"hasDupCid": 1
},
{
"_icon": "column",
"text": "typeCol",
"cls": "Wb.Column",
"properties": {
"cid": "typeCol",
"text": "@Str.type",
"fieldName": "tpl_file",
"width": "18em"
}
}
]
}
]
}
]
}
]
}
File name: get-data.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: dept-selector.xwl
{
"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"
}
}
]
}
]
}
File name: module-selector.xwl
{
"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"
}
]
}
]
}
]
}
File name: get-data.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: role-selector.xwl
{
"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"
}
}
]
}
]
}
File name: get-data.xwl
{
"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"
}
File name: select.xwl
{
"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"
}
File name: user-selector.xwl
{
"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"
}
}
]
}
]
}
File name: add.xwl
{
"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
}
File name: browser.xwl
{
"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 {Function} 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",
"hasDupCid": 0,
"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,
"hasDupCid": 1
},
{
"_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,
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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"
},
"hasDupCid": 1
},
{
"_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,
"hasDupCid": 1
},
{
"_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",
"hasDupCid": 0
}
]
}
]
}
]
},
{
"_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",
"hasDupCid": 0
}
]
},
{
"_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];"
},
"hasDupCid": 0
}
]
}
]
}
]
}
File name: export-files.xwl
{
"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\n if (zip || len > 1 || file.isFolder) {\n let filename;\n\n if (len == 1)\n filename = file.isFile ? file.normalName : file.name;\n else\n filename = file.parent.name || 'file';\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);\n }\n}\nmain();",
"remark": "Export files in any path"
},
"_icon": "module"
}
File name: find-shortcut.xwl
{
"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"
}
File name: get-property.xwl
{
"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"
}
File name: get-resource.xwl
{
"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"
}
File name: get.xwl
{
"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": ""
}
File name: image-viewer.xwl
{
"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 /**\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 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
}
]
}
File name: import-files.xwl
{
"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"
}
File name: open-resource.xwl
{
"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"
}
File name: open.xwl
{
"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": ""
}
File name: paste-files.xwl
{
"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"
}
File name: remove.xwl
{
"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": ""
}
File name: save.xwl
{
"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": ""
}
File name: set-property.xwl
{
"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"
}
File name: text-editor.xwl
{
"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",
"hasDupCid": 0,
"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",
"hasDupCid": 0,
"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;"
}
}
]
}
]
}
File name: get-langs.xwl
{
"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"
}
File name: get-modules-tree.xwl
{
"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"
}
File name: get-user-data.xwl
{
"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"
}
File name: save-desktop.xwl
{
"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"
}
File name: search-modules.xwl
{
"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, Wb.File.moduleFolder.path, 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 path.\n * @param {String} query Search keyname.\n * @return {Array} Search result.\n */\nfunction search(fs, path, query) {\n let itemPath, items = fs.listFiles(path, 'home'), result = [];\n items.forEach(item => {\n itemPath = item.path;\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, itemPath, query));\n }\n });\n return result;\n}\nmain();"
},
"_icon": "module"
}
File name: set-user-data.xwl
{
"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"
}
File name: home.xwl
{
"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 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 }\n });\n };\n win.subTitle = app.dispname;\n win.show();\n }\n });\n },\n /**\n * Fired after the page is ready.\n */\n onReady() {\n let activeCard = app.moduleTab.activeCard;\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 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$_",
"autoReconnect": "true"
},
"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": false,
"hasDupCid": 0,
"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": true,
"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;"
},
"hasDupCid": 0,
"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": "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": "resetDesktopItem",
"cls": "Wb.Item",
"_expanded": true,
"properties": {
"cid": "resetDesktopItem",
"text": "@Str.resetDesktop"
},
"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": "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 });"
},
"hasDupCid": 0
}
]
},
{
"_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);"
},
"hasDupCid": 0
}
]
},
{
"_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$_"
}
}
]
}
]
}
]
}
File name: index.xwl
{
"title": "",
"icon": "",
"img": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"loginRequired": "false",
"title": "_$title$_",
"serverScript": "Wb.set('title', Wb.getConfig('sys.app.title'));\nWb.set('showTip', !Config.isDemo && !!Wb.getRecord(\"select 1 from wb_user where user_name='admin' and login_times=0\"));",
"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",
"hasDupCid": 0,
"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'));\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",
"hasDupCid": 0,
"items": [
{
"_icon": "label",
"text": "copyrightLabel",
"cls": "Wb.Label",
"properties": {
"cid": "copyrightLabel",
"text": "Copyright © Geejing, All Rights Reserved.",
"style": "color:#555",
"fontSize": ".8em"
}
}
]
}
]
}
]
}
File name: reset.xwl
{
"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"
}
File name: reset-passwords.xwl
{
"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"
}
}
]
}
]
}
File name: export.xwl
{
"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 Globals.maxRows = maxRows;\n data = Wb.execute(localUrl, Wb.apply({}, Wb.decode(params.urlParams ?? null), paramsValue));\n } finally {\n if (allPages)\n Globals.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 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(StringUtil.escapeCSV(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(StringUtil.escapeCSV(val));\n });\n }\n writer.close();\n}\n\ndoExport(Params);"
},
"_icon": "module",
"_expanded": true
}
File name: get-dict.xwl
{
"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"
}
File name: get-kv.xwl
{
"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());\n break;\n }\n}\nmain();",
"remark": "Get key value list"
},
"_icon": "module"
}
File name: sql-provider.xwl
{
"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.isAlphaNum(keys[0]) && (object = schemas.find(item => item.text.toLowerCase() == keys[0]))) {\n schemaName = object.text;\n if (Wb.isAlphaNum(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.isAlphaNum(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"
}
File name: check-update.xwl
{
"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 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?}');\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"
}
File name: get-version.xwl
{
"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"
}
File name: login.xwl
{
"title": "@login",
"icon": "",
"img": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"loginRequired": "false",
"remark": "Login page",
"serverScript": "Wb.set('title', Wb.getConfig('sys.app.title'));",
"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",
"hasDupCid": 0,
"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());"
}
},
{
"cls": "Wb.Toolbar",
"properties": {
"cid": "bbar",
"isProperty": "true",
"padding": "true",
"justify": "center"
},
"text": "bbar",
"_expanded": true,
"_icon": "toolbar",
"hasDupCid": 0,
"items": [
{
"_icon": "label",
"text": "copyrightLabel",
"cls": "Wb.Label",
"properties": {
"cid": "copyrightLabel",
"text": "Copyright © Geejing, All Rights Reserved.",
"style": "color:#555",
"fontSize": ".8em"
}
}
]
}
]
}
]
}
File name: logout.xwl
{
"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": ""
}
File name: refresh.xwl
{
"title": "",
"icon": "",
"img": "",
"tags": "",
"hideInMenu": "false",
"text": "module",
"cls": "Wb.Module",
"properties": {
"cid": "module",
"remark": "Refresh current http session"
},
"_icon": "module",
"items": []
}
File name: set-resource-all.xwl
{
"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
}
File name: set-resource.xwl
{
"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"
}
File name: set-value-all.xwl
{
"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"
}
File name: set-value.xwl
{
"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"
}
File name: verify.xwl
{
"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);\n Wb.send([Wb.username, Wb.dispname]);\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"
}