(function () { 'use strict'; var cache = { recordsMap: {} }; var myZone; window.ADNS = { cache: cache, $qs: $qs }; if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector; } function $qs(qs, el) { return (el||document).querySelector(qs); } function $qsa(qs, el) { return Array.prototype.slice.call((el||document).querySelectorAll(qs)); } function $on(selector, eventname, cb) { if (!$on._events[eventname]) { $on._events[eventname] = $on._dispatcher(eventname); document.addEventListener(eventname, $on._events[eventname]); } if (!$on._handlers[eventname]) { $on._handlers[eventname] = {}; } if (!$on._handlers[eventname][selector]) { $on._handlers[eventname][selector] = []; } $on._handlers[eventname][selector].push(cb); } $on._events = {}; $on._handlers = {}; $on._dispatcher = function (eventname) { return function (ev) { //console.log('event: ' + ev.type); if (!$on._handlers[eventname]) { console.warn('no handlers for event'); return; } var matches = Object.keys($on._handlers[eventname]).some(function (selector) { if (ev.target.matches(selector)) { $on._handlers[eventname][selector].forEach(function (cb) { cb(ev); }); return true; } }); if (matches) { console.warn("no handlers for selector"); } }; }; function verifyAuth(/*ev*/) { auth = $qs('input.js-jwt').value; return window.fetch( '/api/verify-auth' , { method: 'GET' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth }) } ).then(function (resp) { return resp.json().then(function (data) { if (data.error) { localStorage.removeItem('auth'); console.error(data.error); window.alert('Bad HTTP Response: ' + data.error.message); throw new Error('Bad HTTP Response: ' + data.error.message); } console.log('verify-auth:'); console.log(data); localStorage.setItem('auth', auth); return fetchPeers(auth).then(function () { return fetchZones(auth); }); }); }); } function fetchPeers(auth) { return window.fetch('/api/peers', { method: 'GET' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth }) }).then(function (resp) { return resp.json().then(function (data) { var tpl = ''; var el; if (!tpls.peer) { tpls.peer = $qs('.js-peer-tpl').innerHTML; } cache.peers = data.peers; cache.peers.forEach(function (peer) { el = document.createElement('div'); el.innerHTML = tpls.peer; console.log(el); console.log($qs('.js-peer-name', el)); $qs('.js-peer-name', el).innerText = peer.name; $qs('.js-peer-name', el).dataset.id = peer.name; $qs('.js-peer', el).dataset.id = peer.name; $qs('.js-peer-address', el).innerText = peer.address || ''; console.log(el.innerHTML); tpl += el.innerHTML; console.log(tpl); }); $qs('.js-peer-tpl').innerHTML = tpl; console.log($qs('.js-peer-tpl').innerHTML); }); }); } function renderZones() { var tpl = ''; var el; cache.zones.forEach(function (zone) { el = document.createElement('div'); el.innerHTML = tpls.zone; console.log(el); console.log($qs('.js-zone', el)); $qs('.js-zone-name', el).innerText = zone.name; $qs('.js-zone', el).dataset.id = zone.id; $qs('.js-zone', el).dataset.name = zone.name; console.log(el.innerHTML); tpl += el.innerHTML; console.log(tpl); }); $qs('.js-zone-tpl').innerHTML = tpl; console.log($qs('.js-zone-tpl').innerHTML); } function fetchZones(auth) { return window.fetch('/api/zones', { method: 'GET' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth }) }).then(function (resp) { return resp.json().then(function (data) { if (!tpls.zone) { tpls.zone = $qs('.js-zone-tpl').innerHTML; } cache.zones = data.zones; renderZones(); }); }); } function renderRecords() { var tpl = ''; var el; if (!tpls.recordsMap) { //tpls.recordTypes = Array.prototype.slice.call($qsa('.js-record-tpl li')); //.innerHTML; tpls.recordsMap = {}; tpls.recordsMap.soa = $qs('.js-record-soa').outerHTML; tpls.recordsMap.ns = $qs('.js-record-ns').outerHTML; tpls.recordsMap.a = $qs('.js-record-a').outerHTML; tpls.recordsMap.aaaa = $qs('.js-record-aaaa').outerHTML; tpls.recordsMap.aname = $qs('.js-record-aname').outerHTML; tpls.recordsMap.cname = $qs('.js-record-cname').outerHTML; tpls.recordsMap.caa = $qs('.js-record-caa').outerHTML; tpls.recordsMap.ptr = $qs('.js-record-ptr').outerHTML; tpls.recordsMap.mx = $qs('.js-record-mx').outerHTML; tpls.recordsMap.txt = $qs('.js-record-txt').outerHTML; tpls.recordsMap.srv = $qs('.js-record-srv').outerHTML; //tpls.recordsMap.typex = $qs('.js-record-typex').outerHTML; } console.log('tpls.recordsMap:'); console.log(tpls.recordsMap); cache.records.forEach(function (record) { el = document.createElement('div'); console.log('record.type:', record.type); el.innerHTML = tpls.recordsMap[record.type.toLowerCase()]; console.log(el); console.log($qs('.js-record-name', el)); Object.keys(record).sort().forEach(function (key) { if ('id' === key) { return; } var x = $qs('.js-record-' + key, el); if (x) { x.innerText = record[key]; } }); el.dataset.recordId = record.id; $qs('input.js-record-id', el).value = record.id; cache.recordsMap[record.id] = record; //$qs('.js-record-type', el).innerText = record.type; //$qs('.js-record-name', el).innerText = record.name; //$qs('.js-record-address', el).innerText = record.address; console.log('el.innerHTML:'); console.log(el.innerHTML); tpl += el.innerHTML; console.log(tpl); }); $qs('.js-record-tpl').innerHTML = tpl; console.log($qs('.js-record-tpl').innerHTML); } function fetchRecords(zone) { return window.fetch('/api/zones/' + zone + '/records', { method: 'GET' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth }) }).then(function (resp) { return resp.json().then(function (data) { cache.records = data.records; renderRecords(); }); }); } // BEGIN var tpls = {}; var auth = localStorage.getItem('auth'); if (auth) { $qs('input.js-jwt').value = auth; verifyAuth(); } $on('body', 'click', function () { console.log('woo-hoo, that tickles my body!'); }); $on('button.js-jwt', 'click', verifyAuth); $on('input.js-zone', 'keyup', function (ev) { $qs('code.js-zone').innerHTML = ev.target.value || ':zone'; // $qs('a.js-zone').setAttribute('data-href', ...) $qs('a.js-zone').href = $qs('a.js-zone').dataset.href.replace(/:zone/, ev.target.value || ':zone'); }); $on('input.js-name', 'keyup', function (ev) { $qs('code.js-name').innerHTML = ev.target.value || ':name'; $qs('a.js-name').href = $qs('a.js-name').dataset.href.replace(/:name/, ev.target.value || ':name'); }); $on('button.js-zone-view', 'click', function (ev) { var zone = ev.target.parentElement.dataset.name; myZone = zone; return fetchRecords(zone);/*.then(function () { });*/ }); function setZoneNs(zone) { cache.peers.forEach(function (p, i) { var $vns = $qsa('.js-zone-form-tpl .js-zone-form-vns')[i]; $qs('.js-record-zone', $vns).innerText = zone; if (p.address) { $qs('.js-record-address', $vns).value = p.address; } }); $qs('.js-zone-form-tpl .js-recordx-primary').value = 'nsx.' + zone; } function openZoneForm() { var d = new Date(); myZone = $qs('.js-zone-form-name').value; $qs('.js-zone-form-tpl').innerHTML = tpls.newZone; cache.peers.forEach(function () { $qs('.js-zone-form-vns-tpl').innerHTML += tpls.newNs; }); cache.peers.forEach(function (p, i) { var $vns = $qsa('.js-zone-form-tpl .js-zone-form-vns')[i]; $qs('.js-record-host', $vns).value = 'ns' + (i + 1); //$qs('.js-record-name', $vns).value = 'ns' + (i + 1) + '.' + myZone; $qs('.js-record-zone', $vns).innerText = myZone; if (p.address) { $qs('.js-record-address', $vns).value = p.address; } $qs('.js-record-ttl', $vns).value = 7200; }); $qs('.js-zone-form-tpl .js-record-name').value = myZone; $qs('.js-zone-form-tpl .js-record-admin').value = 'admin.' + myZone; $qs('.js-zone-form-tpl .js-record-expiration').value = 2419200; // 4 weeks $qs('.js-zone-form-tpl .js-record-minimum').value = 5; $qs('.js-zone-form-tpl .js-recordx-serial').value = d.getFullYear() + '' + (d.getMonth() + 1) + '' + d.getDate() + '' + (Math.round(Math.random() * 99)) ; $qs('.js-zone-form-tpl .js-record-retry').value = 1800; $qs('.js-zone-form-tpl .js-record-refresh').value = 7200; $qs('.js-zone-form-tpl .js-record-ttl').value = 300; $qs('input.js-zone-form-vanityns').dispatchEvent(new Event('change', { bubbles: true })); console.log('val:', $qs('.js-zone-form-tpl .js-record-ttl').value); console.log('x', $qs('.js-zone-form-tpl')); console.log('val:', $qs('.js-zone-form-tpl .js-record-ttl').value); } $on('input.js-zone-form-vanityns', 'change', function (ev) { console.log('checked:', ev.target.checked); if (ev.target.checked) { setZoneNs(myZone); } else { setZoneNs(cache.peers[0].name.split('.').slice(1).join('.')); } }); $on('form.js-zone-form-create', 'submit', function (ev) { ev.preventDefault(); ev.stopPropagation(); console.log('form submit enter'); openZoneForm(); }); $on('button.js-zone-new', 'click', function (/*ev*/) { //$qs('select.js-record-form-type').value = 'SOA'; //$qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true })); console.log('form submit click'); openZoneForm(); }); $on('button.js-zone-edit', 'click', function (/*ev*/) { openZoneForm(); }); $on('button.js-zone-save', 'click', function (/*ev*/) { var zone = {}; var nss = []; [ 'id', 'name', 'admin', 'expiration', 'minimum', 'retry', 'refresh', 'ttl' ].forEach(function (key) { zone[key] = $qs('.js-zone-form-tpl .js-record-' + key).value; }); $qsa('.js-zone-form-tpl .js-zone-form-vns').forEach(function ($el) { console.log('$el:'); console.log($el); var ns = {}; [ 'id', 'host'/*, 'name'*/, 'ttl', 'address' ].forEach(function (key) { ns[key] = $qs('.js-record-' + key, $el).value; }); nss.push(ns); }); console.log('zone:'); console.log(zone); console.log('nss:'); console.log(nss); zone.vanity = false; if ($qs('input.js-zone-form-vanityns').checked) { zone.vanity = true; zone.vanityNs = nss; } $qs('.js-zone-form-tpl').innerHTML = ''; return window.fetch( '/api/zones/' //+ zone.name , { method: 'POST' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth , 'Content-Type': 'application/json;charset=UTF-8' }) , body: JSON.stringify(zone) } ).then(function (resp) { return resp.json().then(function (data) { if (data.error) { console.error(data); window.alert(data.error.message); return; } console.log('result:', data); if (!zone.id) { zone.id = data.id; cache.zones.push(data); renderZones(); } }); }); }); $on('select.js-record-form-type', 'change', function (ev) { var type = ev.target.value; var $tpl; console.log("form type:", type); if (!tpls.formsMap) { tpls.formsMap = {}; tpls.formsMap.SOA = $qs('.js-record-form-soa').outerHTML; tpls.formsMap.NS = $qs('.js-record-form-ns').outerHTML; tpls.formsMap.A = $qs('.js-record-form-a').outerHTML; tpls.formsMap.AAAA = $qs('.js-record-form-aaaa').outerHTML; tpls.formsMap.ANAME = $qs('.js-record-form-aname').outerHTML; tpls.formsMap.CAA = $qs('.js-record-form-caa').outerHTML; tpls.formsMap.CNAME = $qs('.js-record-form-cname').outerHTML; tpls.formsMap.MX = $qs('.js-record-form-mx').outerHTML; tpls.formsMap.PTR = $qs('.js-record-form-ptr').outerHTML; tpls.formsMap.SRV = $qs('.js-record-form-srv').outerHTML; tpls.formsMap.TXT = $qs('.js-record-form-txt').outerHTML; tpls.formsMap.typeX = $qs('.js-record-form-typex').outerHTML; } $tpl = $qs('.js-record-form-tpl'); $tpl.innerHTML = tpls.formsMap[type] || ''; if (!tpls.formsMap[type]) { console.warn("no tpl for type '" + type + "'"); return; } $qs('.js-record-type', $tpl).innerText = type; $qs('.js-record-zone', $tpl).innerText = myZone; }); $on('button.js-record-form-new', 'click', function (/*ev*/) { var type = $qs('select.js-record-form-type').value; if (!type) { $qs('select.js-record-form-type').value = 'A'; } $qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true })); }); $on('button.js-record-edit', 'click', function (ev) { var id = ev.target.parentElement.querySelector('.js-record-id').value; var record = cache.recordsMap[id]; var formTpl = tpls.formsMap[record.type]; var $tpl; if (!formTpl) { formTpl = tpls.formsMap.typeX; } console.log(ev.target); console.log(id); console.log(record); formTpl = tpls.formsMap[(record.type||'typeX')]; $qs('select.js-record-form-type').value = (record.type||'typeX'); $qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true })); $tpl = $qs('.js-record-form-tpl'); $tpl.innerHTML = formTpl || ''; record.host = record.name.replace(new RegExp('\\.?' + (record.zone || record.name).replace(/\./g, '\\.') + '$'), ''); console.log('record.type:'); console.log(record.type); Object.keys(record).forEach(function (key) { var $el = $qs('.js-record-' + key, $tpl); if (!$el) { return; } $el.value = record[key]; }); if ('SOA' === record.type) { $qs('.js-record-name').disabled = 'disabled'; } else { if (!record.host) { $qs('.js-record-host', $tpl).placeholder = '@'; } } $qs('.js-record-type', $tpl).innerHTML = record.type; $qs('.js-record-zone', $tpl).innerText = myZone; }); $on('button.js-record-save', 'click', function (ev) { console.log('save'); var $pel = ev.target.parentElement; var id = $qs('.js-record-id', $pel).value; var existingRecord = cache.recordsMap[id]; var record = {}; var change; $qsa('input[class*="js-record-"]', $pel).forEach(function ($el) { var key; Array.prototype.some.call($el.classList, function (str) { if (/^js-record-/.test(str)) { key = str.replace(/^js-record-(.*)/, '$1'); return true; } }); if (!key) { return; } if ('undefined' === typeof $el.value || 'INPUT' !== $el.tagName) { return; } record[key] = $el.value; }); if (!record.id) { record.id = ''; } if (!record.zone) { record.zone = myZone; } if (!record.name) { if (record.host) { record.name = record.host + '.' + myZone; } else { record.name = myZone; } } record.type = record.type || $qs('.js-record-type', $pel).innerHTML || $qs('.js-record-type', $pel).value; console.log('record.type:', record.type); /* if (!tpls.recordsMap[record.type.toLowerCase()]) { record.typex = 'typex'; } */ if (!existingRecord) { change = true; cache.recordsMap[record.id] = record; cache.records.push(record); } else { console.log('keys:', Object.keys(record)); Object.keys(record).forEach(function (key) { console.log('key:', key); //if ('SOA' === record.type && 'zone' === key) { return; } if (existingRecord[key].toString() !== record[key].toString()) { change = true; existingRecord[key] = record[key]; } }); } if (!change) { return; } renderRecords(); return window.fetch( '/api/records/' + record.id , { method: 'POST' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth , 'Content-Type': 'application/json;charset=UTF-8' }) , body: JSON.stringify(record) } ).then(function (resp) { return resp.json().then(function (data) { if (data.error) { console.error(data); window.alert(data.error.message); return; } console.log('result:', data); if (!record.id) { record.id = data.id; renderRecords(); } }); }); }); $on('button.js-record-destroy', 'click', function (ev) { console.log('destroy'); var $pel = ev.target.parentElement; var id = $qs('.js-record-id', $pel).value; var existingRecord = cache.recordsMap[id]; return window.fetch( '/api/records/' + id , { method: 'DELETE' , headers: new window.Headers({ 'Authorization': 'Bearer ' + auth , 'Content-Type': 'application/json;charset=UTF-8' }) } ).then(function (resp) { return resp.json().then(function (data) { if (data.error) { console.error(data); window.alert(data.error.message); return; } delete cache.recordsMap[id]; cache.records.some(function (r, i) { if (r === existingRecord) { cache.records.splice(i, 1); return true; } }); renderRecords(); console.log('result:', data); }); }); }); $qs('select.js-record-form-type').value = ''; // Create a new 'change' event and dispatch it. $qs('select.js-record-form-type').dispatchEvent(new Event('change', { bubbles: true })); tpls.newNs = $qs('.js-zone-form-tpl .js-zone-form-vns-tpl').innerHTML; $qs('.js-zone-form-tpl .js-zone-form-vns-tpl').innerHTML = ''; tpls.newZone = $qs('.js-zone-form-tpl').innerHTML; $qs('.js-zone-form-tpl').innerHTML = ''; }());