<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:;base64,iVBORw0KGgo="> <title>Mail4one Web config</title> <script type="application/json" id="m41config"> { "matches": [ { "name": "mydomain", "addr_rexs": [ ".*@mydomain.com", ".*@m.mydomain.com" ] }, { "name": "personal", "addrs": [ "first.last@mydomain.com", "secret.name@mydomain.com" ] } ], "boxes": [ { "name": "spam", "rules": [ { "match_name": "mydomain", "negate": true, "stop_check": true } ] }, { "name": "important", "rules": [ { "match_name": "personal" } ] }, { "name": "all", "rules": [ { "match_name": "default_match_all" } ] } ], "users": [ { "username": "mymobile", "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF", "mbox": "important" }, { "username": "mydesk", "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF", "mbox": "all" } ] } </script> <style> .outer { display: flex; justify-content: center; background: grey; } .inner { border: 1px solid; background: white; padding: 5px; // flex: 1 0 0; // max-width: 700px; } .m41-box { display: grid; grid-template-columns: 1fr 3fr; margin: 10px; // background-color: lightblue; } #web-cfg-boxes { // display: grid; // grid-template-columns: 1fr ; width: 100%; //justify-content: space-around; // justify-content: flex-start; // background-color: blue; } .m41-box:nth-of-type(odd) { background: lightblue; } .m41-box:nth-of-type(even) { background: lightgrey; } .m41-box-info { display: grid; grid-template-columns: 4fr 2fr 5fr; // align-items: stretch; // justify-content: space-around; // background-color: grey; } .button-group { display: flex; justify-content: center; // grid-template-columns: 1fr 1fr 1fr; // align-items: stretch; // display: inline-flex; } .m41-box-rule:only-child div.button-group button{ // display: none; visibility: hidden; } .m41-box:only-child div div.button-group button{ // display: none; visibility: hidden; } .m41-box-rule { display: flex; // grid-template-columns: 1fr 3fr 1fr 1fr; align-items: center; justify-items: center; // background-color: lightblue; } </style> <script type="application/javascript"> "use strict" // Globals let matches_table let match_row_template let config let boxes_ul let box_template let rule_template function initGlobals() { matches_table = document.getElementById("web-cfg-matches") match_row_template = document.getElementById("web-cfg-matches-row") config = JSON.parse(document.getElementById('m41config').text) boxes_ul = document.getElementById("web-cfg-boxes") box_template = document.getElementById("web-cfg-boxes-li") rule_template = document.getElementById("web-cfg-boxes-rule-li") } function populate_match_table(matches_config) { for (const { name: match_name, addrs, addr_rexs } of matches_config) { const [match_type, match_values] = (() => { if (addrs != undefined) { return ["addrs", addrs] } else { return ["addr_rexs", addr_rexs] } })() addMatchRow() const last_row = matches_table.tBodies[0].lastElementChild const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = last_row.cells name_cell.innerText = match_name type_select.value = match_type value_cell.innerText = match_values.join("\n") } } function extract_match_table() { let matches = [] for (let row of matches_table.tBodies[0].rows) { const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = row.cells let m = {"name" : name_cell.innerText} switch (type_select.value) { case "addrs": m["addrs"] = value_cell.innerText.split("\n") break case "addr_rexs": m["addr_rexs"] = value_cell.innerText.split("\n") break } matches.push(m) } return matches } function addMatchRow() { let row_clone = match_row_template.content.cloneNode(true) matches_table.tBodies[0].appendChild(row_clone) } function populate_boxes_list(boxes_config) { for (const {name:box_name, rules} of boxes_config) { addBox() const box = boxes_ul.lastElementChild const [{children: [,, header]}, rule_list ] = box.children header.innerText = box_name for (const {match_name, negate = false, stop_check = false} of rules ) { addRule(rule_list) const rule = rule_list.lastElementChild const [, {firstElementChild: match_select}, {firstElementChild: negateCheck}, {firstElementChild: stopCheck} ] = rule.children negateCheck.checked = negate stopCheck.checked = stop_check } } } function addBox() { let box_clone = box_template.content.cloneNode(true) boxes_ul.appendChild(box_clone) } function addRule(rules_list) { let rule_clone = rule_template.content.cloneNode(true) rules_list.appendChild(rule_clone) } function moveUp(button) { const li = button.parentElement.parentElement.parentElement if (li.previousElementSibling != null) { li.parentNode.insertBefore(li, li.previousElementSibling) } } function moveDown(button) { const li = button.parentElement.parentElement.parentElement if (li.nextElementSibling != null) { li.parentNode.insertBefore(li.nextElementSibling, li) } } function main() { initGlobals() populate_match_table(config["matches"]) save() document.getElementById("before").innerText = JSON.stringify(config["matches"], null, 2) populate_boxes_list(config["boxes"]) } function save() { const matches = extract_match_table() document.getElementById("after").innerText = JSON.stringify(matches, null, 2) } </script> </head> <body onload="main()"> <template id="web-cfg-matches-row"> <tr> <td><button onClick="this.parentElement.parentElement.remove()">✗</button></td> <td contentEditable></td> <td> <select> <option value="addrs">List of addresses</option> <option value="addr_rexs">List of regexes for addresses</option> </select> </td> <td contentEditable></td> </tr> </template> <template id="web-cfg-boxes-rule-li"> <div class="m41-box-rule"> <div class="button-group"> <button onClick="this.parentElement.parentElement.remove()">✗</button> <button onClick="moveUp(this)">↑</button> <button onClick="moveDown(this)">↓</button> </div> <label> Match Name <select></select> </label> <label> Negate <input type=checkbox> </label> <label> Stop check <input type=checkbox> </label> </div> </template> <template id="web-cfg-boxes-li"> <div class="m41-box"> <div class="m41-box-info"> <div class="button-group"> <button onClick="this.parentElement.parentElement.parentElement.remove()">✗</button> <button onClick="moveUp(this)">↑</button> <button onClick="moveDown(this)">↓</button> </div> <button onClick="addRule(this.parentElement.nextElementSibling)">+</button> <span></span> </div> <div class="m41-box-rules"> </div> </div> </template> <div class="outer"> <div class="inner"> <h1>Mail4one Web config</h1> <table border id="web-cfg-matches"> <thead> <tr> <th></th> <th>Name</th> <th>Type</th> <th>Values</th> </tr> </thead> <tbody> </tbody> </table> <div> <button onClick="addMatchRow()">Add Match</button> <button onClick="save()">Save</button> </div> <h3>Boxes <button onClick="addBox()">+</button></h3> <div id="web-cfg-boxes"> </div> <hr> <h3>Before</h3> <pre id="before"></pre> <hr> <h3>After</h3> <pre id="after"></pre> <hr> </div> </div> </body> </html>