474 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!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>
 | 
						|
 | 
						|
td {
 | 
						|
    padding: 5px;
 | 
						|
}
 | 
						|
 | 
						|
            table {
 | 
						|
                border: 2px solid;
 | 
						|
            }
 | 
						|
 | 
						|
            thead {
 | 
						|
                background-color: orange;
 | 
						|
            }
 | 
						|
 | 
						|
            h1.page-title {
 | 
						|
                background-color: orange;
 | 
						|
            }
 | 
						|
 | 
						|
            h3 {
 | 
						|
                text-align: center;
 | 
						|
            }
 | 
						|
 | 
						|
            .outer {
 | 
						|
                display: flex;
 | 
						|
                justify-content: center;
 | 
						|
                background: grey;
 | 
						|
            }
 | 
						|
 | 
						|
            .inner {
 | 
						|
                display: flex;
 | 
						|
                flex-direction: column;
 | 
						|
                align-items: center;
 | 
						|
                border: 2px solid;
 | 
						|
                background-color: lightyellow;
 | 
						|
                padding: 10px;
 | 
						|
                justify-content: space-around;
 | 
						|
                margin: 10px;
 | 
						|
                width: 1200px;
 | 
						|
            }
 | 
						|
            .m41-box {
 | 
						|
                display: grid;
 | 
						|
                grid-template-columns: 1fr 3fr;
 | 
						|
                margin: 10px;
 | 
						|
                // background-color: lightblue;
 | 
						|
            }
 | 
						|
 | 
						|
            .multiline {
 | 
						|
                text-align: left;
 | 
						|
                padding: 5px;
 | 
						|
                padding-left: 15px;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            #web-cfg-matches {
 | 
						|
                width: 90%;
 | 
						|
                text-align: center;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-matches tbody tr:nth-of-type(odd) {
 | 
						|
                background: lightblue;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-matches tbody tr:nth-of-type(even) {
 | 
						|
                background: lightgrey;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes {
 | 
						|
                text-align: center;
 | 
						|
                width: 90%;
 | 
						|
                // display: grid;
 | 
						|
                // grid-template-columns: 1fr ;
 | 
						|
                //justify-content: space-around;
 | 
						|
                // justify-content: flex-start;
 | 
						|
                // background-color: blue;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:nth-of-type(odd) {
 | 
						|
                background: lightblue;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:nth-of-type(even) {
 | 
						|
                background: lightgrey;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody tr td div.dummy{
 | 
						|
                display: none;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody tr td div button.dummy {
 | 
						|
                display: none;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:first-of-type tr td.box div button.up.dummy {
 | 
						|
                display: block;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:first-of-type tr td.box div button.up.real {
 | 
						|
                display: none;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:last-of-type tr td.box div button.down.dummy {
 | 
						|
                display: block;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:last-of-type tr td.box div button.down.real {
 | 
						|
                display: none;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:only-of-type tr td.box div.real {
 | 
						|
                display: none;
 | 
						|
            }
 | 
						|
 | 
						|
            #web-cfg-boxes tbody:only-of-type tr td.box div.dummy {
 | 
						|
                display: flex;
 | 
						|
            }
 | 
						|
 | 
						|
            td.box {
 | 
						|
                display: flex;
 | 
						|
                justify-content: center;
 | 
						|
            }
 | 
						|
 | 
						|
            .button-group {
 | 
						|
                display: flex;
 | 
						|
                justify-content: center;
 | 
						|
            }
 | 
						|
 | 
						|
        </style>
 | 
						|
        <script type="application/javascript">
 | 
						|
            "use strict"
 | 
						|
 | 
						|
            // Globals
 | 
						|
            let server_config
 | 
						|
            let matches_table
 | 
						|
            let match_row_template
 | 
						|
            let boxes_table
 | 
						|
            let box_template
 | 
						|
            // let rule_template
 | 
						|
 | 
						|
            function initGlobals() {
 | 
						|
 | 
						|
                server_config = JSON.parse(document.getElementById('m41config').text)
 | 
						|
                matches_table = document.getElementById("web-cfg-matches")
 | 
						|
                match_row_template = document.getElementById("web-cfg-matches-row")
 | 
						|
                boxes_table = document.getElementById("web-cfg-boxes")
 | 
						|
                box_template = document.getElementById("web-cfg-box")
 | 
						|
                // 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 tbody = boxes_table.lastElementChild
 | 
						|
                    const box = tbody.firstElementChild
 | 
						|
                    // console.log(box)
 | 
						|
                    const [, 
 | 
						|
                        {children: [box_text, ]},
 | 
						|
                        ,
 | 
						|
                        {firstElementChild: match_select},
 | 
						|
                        {firstElementChild: negate_check},
 | 
						|
                        {firstElementChild: stop_check},
 | 
						|
                    ] = box.children
 | 
						|
 | 
						|
                    box_text.value = box_name
 | 
						|
 | 
						|
                    const [first_rule, ...rest] = rules
 | 
						|
 | 
						|
                    const {match_name, negate = false, stop = false} = first_rule
 | 
						|
 | 
						|
                    match_select.value = match_name
 | 
						|
                    negate_check.checked = negate
 | 
						|
                    stop_check.checked = stop
 | 
						|
 | 
						|
                    for (const {match_name, negate = false, stop_check = false} of rest ) {
 | 
						|
 | 
						|
                        addRule(box)
 | 
						|
                        const rule = tbody.lastElementChild
 | 
						|
                        const [, 
 | 
						|
                            {firstElementChild: match_select}, 
 | 
						|
                            {firstElementChild: negateCheck}, 
 | 
						|
                            {firstElementChild: stopCheck} 
 | 
						|
                        ] = rule.children
 | 
						|
                        match_select.value = match_name
 | 
						|
                        negate_check.checked = negate
 | 
						|
                        stop_check.checked = stop
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            function addRule(box) {
 | 
						|
                box.parentElement.appendChild(box.cloneNode(true))
 | 
						|
                box.children[0].rowSpan++;
 | 
						|
                box.children[1].rowSpan++;
 | 
						|
                const newrule = box.parentElement.lastElementChild
 | 
						|
                newrule.removeClass("fist-tr")
 | 
						|
                newrule.firstElementChild.remove()
 | 
						|
                newrule.firstElementChild.remove()
 | 
						|
            }
 | 
						|
 | 
						|
            function addBox() {
 | 
						|
                let box_clone = box_template.content.cloneNode(true)
 | 
						|
                boxes_table.appendChild(box_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(server_config["matches"])
 | 
						|
                save()
 | 
						|
                document.getElementById("before").innerText = JSON.stringify(server_config["matches"], null, 2)
 | 
						|
                populate_boxes_list(server_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 class="multiline"></td>
 | 
						|
            </tr>
 | 
						|
        </template>
 | 
						|
        <template id="web-cfg-box">
 | 
						|
            <tbody>
 | 
						|
                <tr>
 | 
						|
                    <td class="box">
 | 
						|
                        <div class="button-group dummy">
 | 
						|
                            <button disabled>✗</button>
 | 
						|
                            <button disabled>↑</button>
 | 
						|
                            <button disabled>↓</button>
 | 
						|
                        </div>
 | 
						|
                        <div class="button-group real">
 | 
						|
                            <button onClick="this.parentElement.parentElement.parentElement.parentElement.remove()">✗</button>
 | 
						|
                            <button onClick="moveBoxUp(this)" class="real up">↑</button>
 | 
						|
                            <button disabled class="dummy up">↑</button>
 | 
						|
                            <button onClick="moveBoxDown(this)" class="real down">↓</button>
 | 
						|
                            <button disabled class="dummy down">↓</button>
 | 
						|
                        </div>
 | 
						|
                        <button onClick="addRule(this.parentElement.parentElement)">+</button>
 | 
						|
                    </td>
 | 
						|
                    <td contentEditable>
 | 
						|
                        <input type="text" contentEditable>
 | 
						|
                    </td>
 | 
						|
                    <td class="rule">
 | 
						|
                        <div class="button-group dummy">
 | 
						|
                            <button disabled>✗</button>
 | 
						|
                            <button disabled>↑</button>
 | 
						|
                            <button disabled>↓</button>
 | 
						|
                        </div>
 | 
						|
                        <div class="button-group real">
 | 
						|
                            <button onClick="this.parentElement.parentElement.parentElement.remove()">✗</button>
 | 
						|
                            <button onClick="moveRuleUp(this)" class="real up">↑</button>
 | 
						|
                            <button disabled class="dummy up">↑</button>
 | 
						|
                            <button onClick="moveRuleDown(this)" class="real down">↓</button>
 | 
						|
                            <button disabled class="dummy down">↓</button>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                    <td>
 | 
						|
                        <select></select>
 | 
						|
                    </td>
 | 
						|
                    <td>
 | 
						|
                        <input type=checkbox>
 | 
						|
                    </td>
 | 
						|
                    <td>
 | 
						|
                        <input type=checkbox>
 | 
						|
                    </td>
 | 
						|
                </tr>
 | 
						|
            </tbody>
 | 
						|
        </template>
 | 
						|
        <div class="outer">
 | 
						|
            <div class="inner">
 | 
						|
                <h1 class="page-title">Mail4one Web config</h1>
 | 
						|
                <div id="top-menu">
 | 
						|
                    <button onClick="save()">Previous</button>
 | 
						|
                    <button onClick="save()">Matches</button>
 | 
						|
                    <button onClick="save()">Boxes</button>
 | 
						|
                    <button onClick="save()">Users</button>
 | 
						|
                    <button onClick="save()">JSON</button>
 | 
						|
                    <button onClick="save()">Next</button>
 | 
						|
                </div>
 | 
						|
                <div id="match-page">
 | 
						|
                    <h3> Matches </h3>
 | 
						|
                    <table id="web-cfg-matches">
 | 
						|
                        <thead>
 | 
						|
                            <tr>
 | 
						|
                                <th>
 | 
						|
                                    <button onClick="addMatchRow()">+</button>
 | 
						|
                                </th>
 | 
						|
                                <th>Match</th>
 | 
						|
                                <th>Type</th>
 | 
						|
                                <th>Values</th>
 | 
						|
                            </tr>
 | 
						|
                        </thead>
 | 
						|
                        <tbody>
 | 
						|
                        </tbody>
 | 
						|
                    </table>
 | 
						|
                </div>
 | 
						|
 | 
						|
                <div id=box-page">
 | 
						|
                    <h3>Boxes</h3>
 | 
						|
 | 
						|
                    <table id="web-cfg-boxes">
 | 
						|
                        <thead>
 | 
						|
                            <tr>
 | 
						|
                                <th><button onClick="addBox()">+</button></th>
 | 
						|
                                <th>Mailbox</th>
 | 
						|
                                <th></th>
 | 
						|
                                <th>Match</th>
 | 
						|
                                <th>Invert</th>
 | 
						|
                                <th>Stop</th>
 | 
						|
                            </tr>
 | 
						|
                        </thead>
 | 
						|
                    </table>
 | 
						|
                </div>
 | 
						|
 | 
						|
                <hr>
 | 
						|
 | 
						|
                <h3>Before</h3>
 | 
						|
                <pre id="before"></pre>
 | 
						|
                <hr>
 | 
						|
                <h3>After</h3>
 | 
						|
                <pre id="after"></pre>
 | 
						|
                <hr>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </body>
 | 
						|
</html>
 |