Updated JS stuffs.
This commit is contained in:
parent
1363bf5bca
commit
452eeb22d6
21 changed files with 267 additions and 412 deletions
assets
build.jssrc
templates
|
@ -1,108 +0,0 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const readline = require('readline');
|
||||
const utils = require('./utils.js');
|
||||
|
||||
exports.process = async function(root, options) {
|
||||
const macroPrefix = options.prefix || '#';
|
||||
const entryPoint = options.entry || '';
|
||||
|
||||
root = fs.realpathSync(root);
|
||||
|
||||
const included = [];
|
||||
|
||||
const processFile = async function(fileName) {
|
||||
const fullPath = path.join(root, fileName);
|
||||
if(included.includes(fullPath))
|
||||
return '';
|
||||
included.push(fullPath);
|
||||
|
||||
if(!fullPath.startsWith(root))
|
||||
return '/* *** INVALID PATH: ' + fullPath + ' */';
|
||||
if(!fs.existsSync(fullPath))
|
||||
return '/* *** FILE NOT FOUND: ' + fullPath + ' */';
|
||||
|
||||
const lines = readline.createInterface({
|
||||
input: fs.createReadStream(fullPath),
|
||||
crlfDelay: Infinity,
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let lastWasEmpty = false;
|
||||
|
||||
if(options.showPath)
|
||||
output += "/* *** PATH: " + fullPath + " */\n";
|
||||
|
||||
for await(const line of lines) {
|
||||
const lineTrimmed = utils.trim(line);
|
||||
if(lineTrimmed === '')
|
||||
continue;
|
||||
|
||||
if(line.startsWith(macroPrefix)) {
|
||||
const args = lineTrimmed.split(' ');
|
||||
const macro = utils.trim(utils.trimStart(args.shift(), macroPrefix));
|
||||
|
||||
switch(macro) {
|
||||
case 'comment':
|
||||
break;
|
||||
|
||||
case 'include': {
|
||||
const includePath = utils.trimEnd(args.join(' '), ';');
|
||||
output += utils.trim(await processFile(includePath));
|
||||
output += "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case 'buildvars':
|
||||
if(typeof options.buildVars === 'object') {
|
||||
const bvTarget = options.buildVarsTarget || 'window';
|
||||
const bvProps = [];
|
||||
|
||||
for(const bvName in options.buildVars)
|
||||
bvProps.push(`${bvName}: { value: ${JSON.stringify(options.buildVars[bvName])} }`);
|
||||
|
||||
if(Object.keys(bvProps).length > 0)
|
||||
output += `Object.defineProperties(${bvTarget}, { ${bvProps.join(', ')} });\n`;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
output += line;
|
||||
output += "\n";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
output += line;
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
return await processFile(entryPoint);
|
||||
};
|
||||
|
||||
exports.housekeep = function(assetsPath) {
|
||||
const files = fs.readdirSync(assetsPath).map(fileName => {
|
||||
const stats = fs.statSync(path.join(assetsPath, fileName));
|
||||
return {
|
||||
name: fileName,
|
||||
lastMod: stats.mtimeMs,
|
||||
};
|
||||
}).sort((a, b) => b.lastMod - a.lastMod).map(info => info.name);
|
||||
|
||||
const regex = /^(.+)[\-\.]([a-f0-9]+)\.(.+)$/i;
|
||||
const counts = {};
|
||||
|
||||
for(const fileName of files) {
|
||||
const match = fileName.match(regex);
|
||||
if(match) {
|
||||
const name = match[1] + '-' + match[3];
|
||||
counts[name] = (counts[name] || 0) + 1;
|
||||
|
||||
if(counts[name] > 5)
|
||||
fs.unlinkSync(path.join(assetsPath, fileName));
|
||||
} else console.log(`Encountered file name in assets folder with unexpected format: ${fileName}`);
|
||||
}
|
||||
};
|
24
assets/makai.js/csrf.js
Normal file
24
assets/makai.js/csrf.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include html.js
|
||||
|
||||
const $csrf = (() => {
|
||||
let elem;
|
||||
const getElement = () => {
|
||||
if(elem === undefined)
|
||||
elem = $query('meta[name="csrf-token"]');
|
||||
return elem;
|
||||
};
|
||||
|
||||
return {
|
||||
get token() {
|
||||
return getElement()?.content ?? '';
|
||||
},
|
||||
set token(token) {
|
||||
if(typeof token !== 'string')
|
||||
throw 'token must be a string';
|
||||
|
||||
const elem = getElement();
|
||||
if(elem instanceof HTMLMetaElement)
|
||||
elem.content = token;
|
||||
},
|
||||
};
|
||||
})();
|
|
@ -1,111 +0,0 @@
|
|||
const $t = document.createTextNode.bind(document);
|
||||
const $er = (type, props, ...children) => $e({ tag: type, attrs: props, child: children });
|
||||
|
||||
const $e = function(info, attrs, child, created) {
|
||||
info = info || {};
|
||||
|
||||
if(typeof info === 'string') {
|
||||
info = {tag: info};
|
||||
if(attrs)
|
||||
info.attrs = attrs;
|
||||
if(child)
|
||||
info.child = child;
|
||||
if(created)
|
||||
info.created = created;
|
||||
}
|
||||
|
||||
const elem = document.createElement(info.tag || 'div');
|
||||
|
||||
if(info.attrs) {
|
||||
const attrs = info.attrs;
|
||||
|
||||
for(let key in attrs) {
|
||||
const attr = attrs[key];
|
||||
if(attr === undefined || attr === null)
|
||||
continue;
|
||||
|
||||
switch(typeof attr) {
|
||||
case 'function':
|
||||
if(key.substring(0, 2) === 'on')
|
||||
key = key.substring(2).toLowerCase();
|
||||
elem.addEventListener(key, attr);
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if(attr instanceof Array) {
|
||||
if(key === 'class')
|
||||
key = 'classList';
|
||||
|
||||
const prop = elem[key];
|
||||
let addFunc = null;
|
||||
|
||||
if(prop instanceof Array)
|
||||
addFunc = prop.push.bind(prop);
|
||||
else if(prop instanceof DOMTokenList)
|
||||
addFunc = prop.add.bind(prop);
|
||||
|
||||
if(addFunc !== null) {
|
||||
for(let j = 0; j < attr.length; ++j)
|
||||
addFunc(attr[j]);
|
||||
} else {
|
||||
if(key === 'classList')
|
||||
key = 'class';
|
||||
elem.setAttribute(key, attr.toString());
|
||||
}
|
||||
} else {
|
||||
for(const attrKey in attr)
|
||||
elem[key][attrKey] = attr[attrKey];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
if(attr)
|
||||
elem.setAttribute(key, '');
|
||||
break;
|
||||
|
||||
default:
|
||||
if(key === 'className')
|
||||
key = 'class';
|
||||
elem.setAttribute(key, attr.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(info.child) {
|
||||
let children = info.child;
|
||||
|
||||
if(!Array.isArray(children))
|
||||
children = [children];
|
||||
|
||||
for(const child of children) {
|
||||
switch(typeof child) {
|
||||
case 'string':
|
||||
elem.appendChild($t(child));
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if(child instanceof Element)
|
||||
elem.appendChild(child);
|
||||
else if(child.getElement) {
|
||||
const childElem = child.getElement();
|
||||
if(childElem instanceof Element)
|
||||
elem.appendChild(childElem);
|
||||
else
|
||||
elem.appendChild($e(child));
|
||||
} else
|
||||
elem.appendChild($e(child));
|
||||
break;
|
||||
|
||||
default:
|
||||
elem.appendChild($t(child.toString()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(info.created)
|
||||
info.created(elem);
|
||||
|
||||
return elem;
|
||||
};
|
|
@ -1,13 +1,10 @@
|
|||
#include elem.js
|
||||
#include xhr.js
|
||||
|
||||
const MakaiSiteHeaderImages = function() {
|
||||
const url = '/header-bgs.json';
|
||||
|
||||
let headers;
|
||||
const all = async () => {
|
||||
if(!Array.isArray(headers))
|
||||
headers = (await $x.get('/header-bgs.json')).json();
|
||||
headers = (await $xhr.get('/header-bgs.json', { type: 'json' })).body;
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
@ -59,18 +56,19 @@ const MakaiSiteHeader = function(element) {
|
|||
if(t < 1)
|
||||
requestAnimationFrame(updateTransition);
|
||||
else {
|
||||
$r(prevImage);
|
||||
prevImage.remove();
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
prevImage.style.zIndex = '2';
|
||||
|
||||
const nextImage = $e({
|
||||
tag: 'img',
|
||||
attrs: {
|
||||
const nextImage = $element(
|
||||
'img',
|
||||
{
|
||||
alt: url,
|
||||
src: url,
|
||||
style: { zIndex: '1' },
|
||||
onerror: () => {
|
||||
prevImage.style.opacity = null;
|
||||
prevImage.style.zIndex = null;
|
||||
|
@ -81,8 +79,7 @@ const MakaiSiteHeader = function(element) {
|
|||
requestAnimationFrame(updateTransition);
|
||||
},
|
||||
},
|
||||
style: { zIndex: '1' },
|
||||
});
|
||||
);
|
||||
bgElem.appendChild(nextImage);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -105,7 +105,7 @@ const MakaiSideListElement = function(element) {
|
|||
};
|
||||
|
||||
const clearBody = insertEmpty => {
|
||||
$rc(bodyElem);
|
||||
$removeChildren(bodyElem);
|
||||
insertEmptyElement();
|
||||
};
|
||||
|
||||
|
|
139
assets/makai.js/html.js
Normal file
139
assets/makai.js/html.js
Normal file
|
@ -0,0 +1,139 @@
|
|||
const $id = document.getElementById.bind(document);
|
||||
const $query = document.querySelector.bind(document);
|
||||
const $queryAll = document.querySelectorAll.bind(document);
|
||||
const $text = document.createTextNode.bind(document);
|
||||
|
||||
const $insertBefore = function(target, element) {
|
||||
target.parentNode.insertBefore(element, target);
|
||||
};
|
||||
|
||||
const $appendChild = function(element, child) {
|
||||
switch(typeof child) {
|
||||
case 'undefined':
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
element.appendChild($text(child));
|
||||
break;
|
||||
|
||||
case 'function':
|
||||
$appendChild(element, child());
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if(child === null)
|
||||
break;
|
||||
|
||||
if(child instanceof Node)
|
||||
element.appendChild(child);
|
||||
else if(child?.element instanceof Node)
|
||||
element.appendChild(child.element);
|
||||
else if(typeof child?.toString === 'function')
|
||||
element.appendChild($text(child.toString()));
|
||||
break;
|
||||
|
||||
default:
|
||||
element.appendChild($text(child.toString()));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const $appendChildren = function(element, ...children) {
|
||||
for(const child of children)
|
||||
$appendChild(element, child);
|
||||
};
|
||||
|
||||
const $removeChildren = function(element) {
|
||||
while(element.lastChild)
|
||||
element.removeChild(element.lastChild);
|
||||
};
|
||||
|
||||
const $fragment = function(props, ...children) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
$appendChildren(fragment, ...children);
|
||||
return fragment;
|
||||
};
|
||||
|
||||
const $element = function(type, props, ...children) {
|
||||
if(typeof type === 'function')
|
||||
return new type(props ?? {}, ...children);
|
||||
|
||||
const element = document.createElement(type ?? 'div');
|
||||
|
||||
if(props)
|
||||
for(let key in props) {
|
||||
const prop = props[key];
|
||||
if(prop === undefined || prop === null)
|
||||
continue;
|
||||
|
||||
switch(typeof prop) {
|
||||
case 'function':
|
||||
if(key.substring(0, 2) === 'on')
|
||||
key = key.substring(2).toLowerCase();
|
||||
element.addEventListener(key, prop);
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if(prop instanceof Array) {
|
||||
if(key === 'class')
|
||||
key = 'classList';
|
||||
|
||||
const attr = element[key];
|
||||
let addFunc = null;
|
||||
|
||||
if(attr instanceof Array)
|
||||
addFunc = attr.push.bind(attr);
|
||||
else if(attr instanceof DOMTokenList)
|
||||
addFunc = attr.add.bind(attr);
|
||||
|
||||
if(addFunc !== null) {
|
||||
for(let j = 0; j < prop.length; ++j)
|
||||
addFunc(prop[j]);
|
||||
} else {
|
||||
if(key === 'classList')
|
||||
key = 'class';
|
||||
element.setAttribute(key, prop.toString());
|
||||
}
|
||||
} else {
|
||||
if(key === 'class' || key === 'className')
|
||||
key = 'classList';
|
||||
|
||||
let setFunc = null;
|
||||
if(element[key] instanceof DOMTokenList)
|
||||
setFunc = (ak, av) => { if(av) element[key].add(ak); };
|
||||
else if(element[key] instanceof CSSStyleDeclaration)
|
||||
setFunc = (ak, av) => {
|
||||
if(ak.includes('-'))
|
||||
element[key].setProperty(ak, av);
|
||||
else
|
||||
element[key][ak] = av;
|
||||
};
|
||||
else
|
||||
setFunc = (ak, av) => { element[key][ak] = av; };
|
||||
|
||||
for(const attrKey in prop) {
|
||||
const attrValue = prop[attrKey];
|
||||
if(attrValue)
|
||||
setFunc(attrKey, attrValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
if(prop)
|
||||
element.setAttribute(key, '');
|
||||
break;
|
||||
|
||||
default:
|
||||
if(key === 'className')
|
||||
key = 'class';
|
||||
|
||||
element.setAttribute(key, prop.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$appendChildren(element, ...children);
|
||||
|
||||
return element;
|
||||
};
|
|
@ -1,11 +1,14 @@
|
|||
#include elem.js
|
||||
#include csrf.js
|
||||
#include html.js
|
||||
#include xhr.js
|
||||
|
||||
#include elems/head.js
|
||||
#include np/init.js
|
||||
#include tools/ascii.js
|
||||
#include tools/whois.js
|
||||
|
||||
const makai = (() => {
|
||||
const header = new MakaiSiteHeader($q('.js-header'));
|
||||
const header = new MakaiSiteHeader($query('.js-header'));
|
||||
|
||||
const runIfPathStartsWith = (prefix, func, ...args) => {
|
||||
if(location.pathname === prefix || location.pathname.startsWith(`${prefix}/`))
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include xhr.js
|
||||
|
||||
const MakaiNowPlaying = function(userName) {
|
||||
const noCoverUrl = 'https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png';
|
||||
const fetchTarget = `https://now.flash.moe/get.php?u=${userName}`;
|
||||
|
@ -31,15 +29,14 @@ const MakaiNowPlaying = function(userName) {
|
|||
|
||||
return {
|
||||
fetch: async () => {
|
||||
const result = await $x.get(fetchTarget);
|
||||
if(result.status !== 200)
|
||||
throw `http ${result.status}`;
|
||||
const { status, body } = await $xhr.get(fetchTarget, { type: 'json' });
|
||||
if(status !== 200)
|
||||
throw `http ${status}`;
|
||||
|
||||
let info = result.json();
|
||||
if(info.length < 1)
|
||||
if(body.length < 1)
|
||||
throw 'no data';
|
||||
|
||||
return format(info[0]);
|
||||
return format(body[0]);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include utility.js
|
||||
#include np/client.js
|
||||
#include np/element.jsx
|
||||
|
||||
const MakaiNowPlayingInit = siteHeader => {
|
||||
const target = $q('.js-np-target');
|
||||
const target = $query('.js-np-target');
|
||||
if(!(target instanceof Element))
|
||||
return;
|
||||
|
||||
|
@ -13,7 +12,7 @@ const MakaiNowPlayingInit = siteHeader => {
|
|||
|
||||
const client = new MakaiNowPlaying(userName);
|
||||
const element = new MakaiNowPlayingElement;
|
||||
$rp(target, element.element);
|
||||
target.replaceWith(element.element);
|
||||
|
||||
const update = () => {
|
||||
client.fetch().then(result => {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include utility.js
|
||||
|
||||
const MakaiASCII = () => {
|
||||
const chars = $qa('.js-ascii-char');
|
||||
const search = $q('.js-ascii-search');
|
||||
const chars = $queryAll('.js-ascii-char');
|
||||
const search = $query('.js-ascii-search');
|
||||
|
||||
const charsFilter = (filter) => {
|
||||
if(!filter) {
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
#include utility.js
|
||||
#include xhr.js
|
||||
#include elems/sidelist.jsx
|
||||
|
||||
const MakaiWHOIS = () => {
|
||||
let locked = false;
|
||||
const input = $q('.js-whois-input');
|
||||
const submit = $q('.js-whois-submit');
|
||||
const result = $q('.js-whois-body');
|
||||
const tabs = $q('.js-whois-tabs');
|
||||
const input = $query('.js-whois-input');
|
||||
const submit = $query('.js-whois-submit');
|
||||
const result = $query('.js-whois-body');
|
||||
const tabs = $query('.js-whois-tabs');
|
||||
|
||||
const historic = [];
|
||||
const history = (() => {
|
||||
const element = $q('.js-whois-sidelist');
|
||||
const element = $query('.js-whois-sidelist');
|
||||
if(element instanceof Element)
|
||||
return new MakaiSideListElement(element);
|
||||
})();
|
||||
|
@ -40,18 +38,17 @@ const MakaiWHOIS = () => {
|
|||
if(!lock())
|
||||
return;
|
||||
|
||||
$x.post('/tools/whois/lookup', {}, { _csrfp: $csrfp.get(), target: target }).then(output => {
|
||||
let headers = output.headers();
|
||||
if(headers.has('x-csrfp'))
|
||||
$csrfp.set(headers.get('x-csrfp'));
|
||||
$xhr.post('/tools/whois/lookup', { type: 'json' }, { _csrfp: $csrf.token, target: target }).then(output => {
|
||||
if(output.headers.has('x-csrfp'))
|
||||
$csrf.token = output.headers.get('x-csrfp');
|
||||
|
||||
let resp = output.json();
|
||||
let resp = output.body;
|
||||
if(resp.error)
|
||||
alert(resp.text);
|
||||
|
||||
let count = 0;
|
||||
|
||||
$rc(tabs);
|
||||
$removeChildren(tabs);
|
||||
|
||||
if(resp.result && Array.isArray(resp.result.responses) && resp.result.responses.length > 0) {
|
||||
if(!historic.includes(resp.result.target)) {
|
||||
|
@ -60,16 +57,16 @@ const MakaiWHOIS = () => {
|
|||
}
|
||||
|
||||
for(const response of resp.result.responses) {
|
||||
const tab = $e({tag: 'a'});
|
||||
const tabHeader = $e();
|
||||
const tabServer = $e();
|
||||
const tab = $element('a');
|
||||
const tabHeader = $element();
|
||||
const tabServer = $element();
|
||||
|
||||
tab.href = 'javascript:;';
|
||||
tab.className = 'whois-result-tab';
|
||||
if(count === 0) tab.className += ' whois-result-tab-active';
|
||||
|
||||
tab.onclick = () => {
|
||||
const active = $q('.whois-result-tab-active');
|
||||
const active = $query('.whois-result-tab-active');
|
||||
if(active) active.classList.remove('whois-result-tab-active');
|
||||
tab.classList.add('whois-result-tab-active');
|
||||
result.textContent = response.lines.join("\r\n").trim();
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
const $i = document.getElementById.bind(document);
|
||||
const $c = document.getElementsByClassName.bind(document);
|
||||
const $q = document.querySelector.bind(document);
|
||||
const $qa = document.querySelectorAll.bind(document);
|
||||
|
||||
const $r = function(element) {
|
||||
if(element && element.parentNode)
|
||||
element.parentNode.removeChild(element);
|
||||
};
|
||||
|
||||
const $ri = function(name) {
|
||||
$r($i(name));
|
||||
};
|
||||
|
||||
const $ib = function(ref, elem) {
|
||||
ref.parentNode.insertBefore(elem, ref);
|
||||
};
|
||||
|
||||
const $rc = function(element) {
|
||||
while(element.lastChild)
|
||||
element.removeChild(element.lastChild);
|
||||
};
|
||||
|
||||
const $rp = function(target, replace) {
|
||||
$ib(target, replace);
|
||||
$r(target);
|
||||
};
|
||||
|
||||
const $ar = function(array, index) {
|
||||
array.splice(index, 1);
|
||||
};
|
||||
const $ari = function(array, item) {
|
||||
let index;
|
||||
while(array.length > 0 && (index = array.indexOf(item)) >= 0)
|
||||
$ar(array, index);
|
||||
};
|
||||
const $arf = function(array, predicate) {
|
||||
let index;
|
||||
while(array.length > 0 && (index = array.findIndex(predicate)) >= 0)
|
||||
$ar(array, index);
|
||||
};
|
||||
|
||||
const $as = function(array) {
|
||||
if(array.length < 2)
|
||||
return;
|
||||
|
||||
for(let i = array.length - 1; i > 0; --i) {
|
||||
let j = Math.floor(Math.random() * (i + 1)),
|
||||
tmp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
const $csrfp = (function() {
|
||||
const elem = $q('meta[name="csrfp-token"]');
|
||||
|
||||
return {
|
||||
get: () => elem?.content ?? '',
|
||||
set: token => {
|
||||
if(elem != null)
|
||||
elem.content = token?.toString() ?? '';
|
||||
},
|
||||
};
|
||||
})();
|
|
@ -1,15 +1,24 @@
|
|||
const $x = (function() {
|
||||
#include csrf.js
|
||||
|
||||
const $xhr = (function() {
|
||||
const send = function(method, url, options, body) {
|
||||
options ??= {};
|
||||
if(options === undefined)
|
||||
options = {};
|
||||
else if(typeof options !== 'object')
|
||||
throw 'options must be undefined or an object';
|
||||
|
||||
Object.freeze(options);
|
||||
|
||||
const xhr = new XMLHttpRequest;
|
||||
const requestHeadersRaw = options?.headers ?? {};
|
||||
const requestHeaders = new Map;
|
||||
|
||||
if(typeof requestHeadersRaw === 'object')
|
||||
for(const name in requestHeadersRaw)
|
||||
if(requestHeadersRaw.hasOwnProperty(name))
|
||||
requestHeaders.set(name.toLowerCase(), requestHeadersRaw[name]);
|
||||
if('headers' in options && typeof options.headers === 'object')
|
||||
for(const name in options.headers)
|
||||
if(options.headers.hasOwnProperty(name))
|
||||
requestHeaders.set(name.toLowerCase(), options.headers[name]);
|
||||
|
||||
if(options.csrf)
|
||||
requestHeaders.set('x-csrf-token', $csrf.token);
|
||||
|
||||
if(typeof options.download === 'function') {
|
||||
xhr.onloadstart = ev => options.download(ev);
|
||||
|
@ -29,6 +38,9 @@ const $x = (function() {
|
|||
if(typeof options.timeout === 'number')
|
||||
xhr.timeout = options.timeout;
|
||||
|
||||
if(typeof options.type === 'string')
|
||||
xhr.responseType = options.type;
|
||||
|
||||
if(typeof options.abort === 'function')
|
||||
options.abort(() => xhr.abort());
|
||||
|
||||
|
@ -39,7 +51,7 @@ const $x = (function() {
|
|||
if(body instanceof URLSearchParams) {
|
||||
requestHeaders.set('content-type', 'application/x-www-form-urlencoded');
|
||||
} else if(body instanceof FormData) {
|
||||
requestHeaders.set('content-type', 'multipart/form-data');
|
||||
// content-type is implicitly set
|
||||
} else if(body instanceof Blob || body instanceof ArrayBuffer || body instanceof DataView) {
|
||||
if(!requestHeaders.has('content-type'))
|
||||
requestHeaders.set('content-type', 'application/octet-stream');
|
||||
|
@ -54,30 +66,33 @@ const $x = (function() {
|
|||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let responseHeaders = undefined;
|
||||
xhr.onload = ev => {
|
||||
const headers = (headersString => {
|
||||
const headers = new Map;
|
||||
|
||||
xhr.onload = ev => resolve({
|
||||
status: xhr.status,
|
||||
body: () => xhr.responseText,
|
||||
json: () => JSON.parse(xhr.responseText),
|
||||
headers: () => {
|
||||
if(responseHeaders !== undefined)
|
||||
return responseHeaders;
|
||||
|
||||
responseHeaders = new Map;
|
||||
|
||||
const raw = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/);
|
||||
const raw = headersString.trim().split(/[\r\n]+/);
|
||||
for(const name in raw)
|
||||
if(raw.hasOwnProperty(name)) {
|
||||
const parts = raw[name].split(': ');
|
||||
responseHeaders.set(parts.shift(), parts.join(': '));
|
||||
headers.set(parts.shift(), parts.join(': '));
|
||||
}
|
||||
|
||||
return responseHeaders;
|
||||
},
|
||||
xhr: xhr,
|
||||
ev: ev,
|
||||
});
|
||||
return headers;
|
||||
})(xhr.getAllResponseHeaders());
|
||||
|
||||
if(headers.has('x-csrf-token'))
|
||||
$csrf.token = headers.get('x-csrf-token');
|
||||
|
||||
resolve({
|
||||
get ev() { return ev; },
|
||||
get xhr() { return xhr; },
|
||||
|
||||
get status() { return xhr.status; },
|
||||
get headers() { return headers; },
|
||||
get body() { return xhr.response; },
|
||||
get text() { return xhr.responseText; },
|
||||
});
|
||||
};
|
||||
|
||||
xhr.onerror = ev => reject({
|
||||
xhr: xhr,
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
const crypto = require('crypto');
|
||||
|
||||
exports.strtr = (str, replacements) => str.toString().replace(
|
||||
/{([^}]+)}/g, (match, key) => replacements[key] || match
|
||||
);
|
||||
|
||||
const trim = function(str, chars, flags) {
|
||||
if(chars === undefined)
|
||||
chars = " \n\r\t\v\0";
|
||||
|
||||
let start = 0,
|
||||
end = str.length;
|
||||
|
||||
if(flags & 0x01)
|
||||
while(start < end && chars.indexOf(str[start]) >= 0)
|
||||
++start;
|
||||
|
||||
if(flags & 0x02)
|
||||
while(end > start && chars.indexOf(str[end - 1]) >= 0)
|
||||
--end;
|
||||
|
||||
return (start > 0 || end < str.length)
|
||||
? str.substring(start, end)
|
||||
: str;
|
||||
};
|
||||
|
||||
exports.trimStart = (str, chars) => trim(str, chars, 0x01);
|
||||
exports.trimEnd = (str, chars) => trim(str, chars, 0x02);
|
||||
exports.trim = (str, chars) => trim(str, chars, 0x03);
|
||||
|
||||
exports.shortHash = function(text) {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(text);
|
||||
return hash.digest('hex').substring(0, 8);
|
||||
};
|
4
build.js
4
build.js
|
@ -11,7 +11,9 @@ const fs = require('fs');
|
|||
public: pathJoin(__dirname, 'public'),
|
||||
debug: isDebug,
|
||||
swc: {
|
||||
es: 'es2020',
|
||||
es: 'es2021',
|
||||
jsx: '$element',
|
||||
jsxf: '$fragment',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Makai;
|
||||
|
||||
use Index\Http\HttpResponseBuilder;
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
use Index\Templating\TplEnvironment;
|
||||
|
@ -17,7 +18,7 @@ class DeveloperRoutes implements RouteHandler {
|
|||
) {}
|
||||
|
||||
#[ExactRoute('GET', '/')]
|
||||
public function getIndex($response, $request) {
|
||||
public function getIndex() {
|
||||
$projectInfos = $this->projects->getProjects(
|
||||
featuredOnly: true,
|
||||
deleted: false,
|
||||
|
@ -54,12 +55,12 @@ class DeveloperRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/tools')]
|
||||
public function temporaryRedirect($response): void {
|
||||
public function temporaryRedirect(HttpResponseBuilder $response): void {
|
||||
$response->redirect('/');
|
||||
}
|
||||
|
||||
#[ExactRoute('GET', '/contact')]
|
||||
public function permanentRedirect($response): void {
|
||||
public function permanentRedirect(HttpResponseBuilder $response): void {
|
||||
$response->redirect('/', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace Makai\SSHKeys;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Index\Http\{HttpRequest,HttpResponseBuilder};
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
|
||||
|
@ -13,7 +14,7 @@ class SSHKeysRoutes implements RouteHandler {
|
|||
) {}
|
||||
|
||||
#[ExactRoute('GET', '/ssh_keys')]
|
||||
public function getSshKeys($response, $request): array|string {
|
||||
public function getSshKeys(HttpResponseBuilder $response, HttpRequest $request): array|string {
|
||||
$minLevel = (int)$request->getParam('l', FILTER_SANITIZE_NUMBER_INT);
|
||||
$includeComment = $request->hasParam('c');
|
||||
$json = $request->hasParam('j');
|
||||
|
@ -47,7 +48,7 @@ class SSHKeysRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/authorized_keys')]
|
||||
public function getAuthorisedKeys($response, $request): string {
|
||||
public function getAuthorisedKeys(HttpResponseBuilder $response): string {
|
||||
$response->setTypePlain();
|
||||
$body = '';
|
||||
|
||||
|
@ -59,7 +60,7 @@ class SSHKeysRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/git_keys_ro')]
|
||||
public function getGitKeysReadOnly($response, $request): string {
|
||||
public function getGitKeysReadOnly(HttpResponseBuilder $response): string {
|
||||
$response->setTypePlain();
|
||||
$body = '';
|
||||
|
||||
|
@ -71,7 +72,7 @@ class SSHKeysRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/git_keys_rw')]
|
||||
public function getGitKeysReadWrite($response, $request): string {
|
||||
public function getGitKeysReadWrite(HttpResponseBuilder $response): string {
|
||||
$response->setTypePlain();
|
||||
$body = '';
|
||||
|
||||
|
@ -83,7 +84,7 @@ class SSHKeysRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/ssh.php')]
|
||||
public function getSshPhp($response, $request): void {
|
||||
public function getSshPhp(HttpResponseBuilder $response, HttpRequest $request): void {
|
||||
$query = [];
|
||||
|
||||
$minLevel = (int)$request->getParam('l', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Makai\Tools\Ascii;
|
||||
|
||||
use Index\Http\HttpResponseBuilder;
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
use Index\Templating\TplEnvironment;
|
||||
|
@ -13,7 +14,7 @@ class AsciiRoutes implements RouteHandler {
|
|||
) {}
|
||||
|
||||
#[ExactRoute('GET', '/tools/ascii')]
|
||||
public function getAsciiTable($response, $request): string {
|
||||
public function getAsciiTable(HttpResponseBuilder $response): string {
|
||||
return $this->templating->render('tools/ascii/index', [
|
||||
'chars' => AsciiCharacter::all(),
|
||||
]);
|
||||
|
@ -21,7 +22,7 @@ class AsciiRoutes implements RouteHandler {
|
|||
|
||||
#[ExactRoute('GET', '/ascii')]
|
||||
#[ExactRoute('GET', '/ascii.php')]
|
||||
public function getAsciiPHP($response, $request): void {
|
||||
public function getAsciiPHP(HttpResponseBuilder $response): void {
|
||||
$response->redirect('/tools/ascii', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace Makai\Tools;
|
||||
|
||||
use Index\XString;
|
||||
use Index\Http\{HttpRequest,HttpResponseBuilder};
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
|
||||
|
@ -9,7 +10,7 @@ class ToolsRoutes implements RouteHandler {
|
|||
use RouteHandlerCommon;
|
||||
|
||||
#[ExactRoute('GET', '/tools/random')]
|
||||
public function getRandomString($response, $request): string {
|
||||
public function getRandomString(HttpResponseBuilder $response, HttpRequest $request): string {
|
||||
$response->setTypePlain();
|
||||
|
||||
$length = (int)$request->getParam('length', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
@ -27,7 +28,7 @@ class ToolsRoutes implements RouteHandler {
|
|||
|
||||
#[ExactRoute('GET', '/tools/hajime-hash')]
|
||||
#[ExactRoute('GET', '/tools/hidoi-hash')]
|
||||
public function getHajimeHash($response, $request): string {
|
||||
public function getHajimeHash(HttpResponseBuilder $response, HttpRequest $request): string {
|
||||
$response->setTypePlain();
|
||||
if(!$request->hasParam('text'))
|
||||
return 'text param is empty';
|
||||
|
@ -37,7 +38,7 @@ class ToolsRoutes implements RouteHandler {
|
|||
|
||||
#[ExactRoute('GET', '/key.php')]
|
||||
#[ExactRoute('GET', '/rngstr')]
|
||||
public function getRedirect($response, $request): void {
|
||||
public function getRedirect(HttpResponseBuilder $response, HttpRequest $request): void {
|
||||
$url = '/tools/random';
|
||||
|
||||
$length = (int)$request->getParam('length', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
|
|
@ -4,7 +4,10 @@ namespace Makai\Tools\Whois;
|
|||
use Exception;
|
||||
use Memcached;
|
||||
use Index\Cache\CacheBackends;
|
||||
use Index\Http\HttpResponseBuilder;
|
||||
use Index\Http\Content\FormContent;
|
||||
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
|
||||
use Index\Http\Routing\Processors\Before;
|
||||
use Index\Http\Routing\Routes\ExactRoute;
|
||||
use Index\Templating\TplEnvironment;
|
||||
use Makai\CSRFPContainer;
|
||||
|
@ -23,17 +26,13 @@ class WhoisRoutes implements RouteHandler {
|
|||
}
|
||||
|
||||
#[ExactRoute('GET', '/whois')]
|
||||
public function getWhoisPHP($response, $request): void {
|
||||
public function getWhoisPHP(HttpResponseBuilder $response): void {
|
||||
$response->redirect('/tools/whois', true);
|
||||
}
|
||||
|
||||
#[ExactRoute('POST', '/tools/whois/lookup')]
|
||||
public function postLookup($response, $request) {
|
||||
if(!$request->isFormContent())
|
||||
return 400;
|
||||
|
||||
$content = $request->getContent();
|
||||
|
||||
#[Before('input:urlencoded')]
|
||||
public function postLookup(HttpResponseBuilder $response, FormContent $content) {
|
||||
if(!$this->csrfp->verifyToken((string)$content->getParam('_csrfp')))
|
||||
return [
|
||||
'error' => true,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="{{ master_charset|default('utf-8') }}">
|
||||
{% if master_title is defined and master_title is not empty %}<title>{{ master_title }}</title>{% endif %}
|
||||
{% block master_head %}{% endblock %}
|
||||
{% if csrfp_available() %}<meta name="csrfp-token" content="{{ csrfp_token() }}">{% endif %}
|
||||
{% if csrfp_available() %}<meta name="csrf-token" content="{{ csrfp_token() }}">{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
{% block master_body %}{% endblock %}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue