434 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			434 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (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;
 | |
|         }
 | |
|         data.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;
 | |
|           console.log(el.innerHTML);
 | |
|           tpl += el.innerHTML;
 | |
|           console.log(tpl);
 | |
|         });
 | |
|         $qs('.js-peer-tpl').innerHTML = tpl;
 | |
|         console.log($qs('.js-peer-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) {
 | |
|         var tpl = '';
 | |
|         var el;
 | |
|         if (!tpls.zone) {
 | |
|           tpls.zone = $qs('.js-zone-tpl').innerHTML;
 | |
|         }
 | |
|         data.zones.forEach(function (zone) {
 | |
|           el = document.createElement('div');
 | |
|           el.innerHTML = tpls.zone;
 | |
|           console.log(el);
 | |
|           console.log($qs('.js-zone-name', el));
 | |
|           $qs('.js-zone-name', el).innerText = zone.name;
 | |
|           $qs('.js-zone-name', el).dataset.id = zone.id;
 | |
|           $qs('.js-zone-name', 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 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-name', 'click', function (ev) {
 | |
|     var zone = ev.target.dataset.name;
 | |
|     myZone = zone;
 | |
|     return fetchRecords(zone);/*.then(function () {
 | |
|     });*/
 | |
|   });
 | |
|   $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 }));
 | |
|   });
 | |
| 
 | |
|   $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] || '';
 | |
|     $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 }));
 | |
| 
 | |
| }());
 |