This commit is contained in:
Lars Jung 2020-07-26 22:45:36 +02:00
parent a556a2be50
commit d81d8a9298
10 changed files with 111 additions and 110 deletions

View File

@ -1,6 +1,7 @@
# Changelog
* now require PHP 7.0.0+
* fix archive-single-item problem
* add header/footer search stop condition
* update languages (`id`, `it`, `pt-br`, `pt-pt`)

View File

@ -1,7 +1,7 @@
<?php
define('H5AI_VERSION', '{{VERSION}}');
define('MIN_PHP_VERSION', '5.5.0');
define('MIN_PHP_VERSION', '7.0.0');
if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<')) {
header('Content-type: text/plain;charset=utf-8');

View File

@ -4,7 +4,7 @@ const XHR = global.window.XMLHttpRequest;
const request = data => {
return new Promise(resolve => {
const xhr = new XHR();
const onReadyStateChange = () => {
const on_ready_state_change = () => {
if (xhr.readyState === XHR.DONE) {
try {
resolve(JSON.parse(xhr.responseText));
@ -15,7 +15,7 @@ const request = data => {
};
xhr.open('POST', '?', true);
xhr.onreadystatechange = onReadyStateChange;
xhr.onreadystatechange = on_ready_state_change;
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
xhr.send(JSON.stringify(data));
});

View File

@ -3,7 +3,7 @@ const {each, filter, hasLength, is, isStr, map, isInstanceOf, toArray} = require
const win = global.window;
const doc = win.document;
const parseHtml = (() => {
const parse_html = (() => {
const create = name => doc.createElement(name);
const rules = [
[/^<t(head|body|foot)|^<c(ap|olg)/i, create('table')],
@ -32,7 +32,7 @@ const parseHtml = (() => {
};
})();
const queryAll = (selector, context = doc) => {
const query_all = (selector, context = doc) => {
try {
return toArray(context.querySelectorAll(selector));
} catch (err) {
@ -40,27 +40,27 @@ const queryAll = (selector, context = doc) => {
}
};
const isElement = x => isInstanceOf(x, win.Element);
const isDocument = x => isInstanceOf(x, win.Document);
const isWindow = x => is(x) && x.window === x && isDocument(x.document);
const isElDocWin = x => isElement(x) || isDocument(x) || isWindow(x);
const is_el = x => isInstanceOf(x, win.Element);
const is_doc = x => isInstanceOf(x, win.Document);
const is_win = x => is(x) && x.window === x && is_doc(x.document);
const is_el_doc_win = x => is_el(x) || is_doc(x) || is_win(x);
const addListener = (el, type, fn) => el.addEventListener(type, fn);
const removeListener = (el, type, fn) => el.removeEventListener(type, fn);
const add_listener = (el, type, fn) => el.addEventListener(type, fn);
const remove_listener = (el, type, fn) => el.removeEventListener(type, fn);
const readyPromise = new Promise(resolve => {
const ready_promise = new Promise(resolve => {
if ((/^(i|c|loade)/).test(doc.readyState)) {
resolve();
} else {
addListener(doc, 'DOMContentLoaded', () => resolve());
add_listener(doc, 'DOMContentLoaded', () => resolve());
}
});
const awaitReady = () => readyPromise;
const await_ready = () => ready_promise;
const loadPromise = new Promise(resolve => {
addListener(win, 'load', () => resolve());
const load_promise = new Promise(resolve => {
add_listener(win, 'load', () => resolve());
});
const awaitLoad = () => loadPromise;
const await_load = () => load_promise;
const dom = arg => {
if (isInstanceOf(arg, dom)) {
@ -70,13 +70,13 @@ const dom = arg => {
let els;
if (isStr(arg)) {
arg = arg.trim();
els = arg[0] === '<' ? parseHtml(arg) : queryAll(arg);
} else if (isElDocWin(arg)) {
els = arg[0] === '<' ? parse_html(arg) : query_all(arg);
} else if (is_el_doc_win(arg)) {
els = [arg];
} else {
els = hasLength(arg) ? arg : [arg];
}
els = filter(els, isElDocWin);
els = filter(els, is_el_doc_win);
return Object.assign(Object.create(dom.prototype), els, {length: els.length});
};
@ -94,15 +94,15 @@ dom.prototype = {
},
find(selector) {
return dom([].concat(...this.map(el => queryAll(selector, el))));
return dom([].concat(...this.map(el => query_all(selector, el))));
},
on(type, fn) {
return this.each(el => addListener(el, type, fn));
return this.each(el => add_listener(el, type, fn));
},
off(type, fn) {
return this.each(el => removeListener(el, type, fn));
return this.each(el => remove_listener(el, type, fn));
},
attr(key, value) {
@ -271,7 +271,7 @@ dom.prototype = {
};
module.exports = {
awaitReady,
awaitLoad,
awaitReady: await_ready,
awaitLoad: await_load,
dom
};

View File

@ -1,6 +1,6 @@
module.exports = Object.assign({},
require('./lo'),
require('./dom'),
require('./naturalCmp'),
require('./natural_cmp'),
require('./misc')
);

View File

@ -1,10 +1,10 @@
const escapePattern = sequence => {
const esc_pattern = sequence => {
return sequence.replace(/[\-\[\]{}()*+?.,\\$\^|#\s]/g, '\\$&');
};
const parsePattern = (sequence, advanced) => {
const parse_pattern = (sequence, advanced) => {
if (!advanced) {
return escapePattern(sequence);
return esc_pattern(sequence);
}
if (sequence.substr(0, 3) === 're:') {
@ -12,10 +12,10 @@ const parsePattern = (sequence, advanced) => {
}
return sequence.trim().split(/\s+/).map(part => {
return part.split('').map(char => escapePattern(char)).join('.*?');
return part.split('').map(char => esc_pattern(char)).join('.*?');
}).join('|');
};
module.exports = {
parsePattern
parsePattern: parse_pattern
};

View File

@ -1,63 +0,0 @@
// Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
// Author: Jim Palmer (based on chunking idea from Dave Koelle)
// Modified to make it work with h5ai
const reToken = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi;
const reDate = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
const reHex = /^0x[0-9a-f]+$/i;
const reLeadingZero = /^0/;
/* eslint-disable complexity */
const naturalCmp = (a, b) => {
// convert all to strings strip whitespace
const x = String(a).trim();
const y = String(b).trim();
// chunk/tokenize
const xTokens = x.replace(reToken, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
const yTokens = y.replace(reToken, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
// first try and sort Hex codes or Dates
const xDate = parseInt(x.match(reHex), 16) || xTokens.length !== 1 && x.match(reDate) && Date.parse(x);
const yDate = parseInt(y.match(reHex), 16) || xDate && y.match(reDate) && Date.parse(y) || null;
if (yDate) {
if (xDate < yDate) {
return -1;
}
if (xDate > yDate) {
return 1;
}
}
// natural sorting through split numeric strings and default strings
for (let idx = 0, len = Math.max(xTokens.length, yTokens.length); idx < len; idx += 1) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
let xToken = !(xTokens[idx] || '').match(reLeadingZero) && parseFloat(xTokens[idx]) || xTokens[idx] || 0;
let yToken = !(yTokens[idx] || '').match(reLeadingZero) && parseFloat(yTokens[idx]) || yTokens[idx] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(xToken) !== isNaN(yToken)) {
return isNaN(xToken) ? 1 : -1;
}
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
if (typeof xToken !== typeof yToken) {
xToken = String(xToken);
yToken = String(yToken);
}
if (xToken < yToken) {
return -1;
}
if (xToken > yToken) {
return 1;
}
}
return 0;
};
/* eslint-enable */
module.exports = {
naturalCmp
};

View File

@ -0,0 +1,63 @@
// Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
// Author: Jim Palmer (based on chunking idea from Dave Koelle)
// Modified to make it work with h5ai
const RE_TOKEN = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi;
const RE_DATE = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
const RE_HEX = /^0x[0-9a-f]+$/i;
const RE_LEADING_ZERO = /^0/;
/* eslint-disable complexity */
const natural_cmp = (a, b) => {
// convert all to strings strip whitespace
const x = String(a).trim();
const y = String(b).trim();
// chunk/tokenize
const x_toks = x.replace(RE_TOKEN, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
const y_toks = y.replace(RE_TOKEN, '\0$1\0').replace(/\0$/, '').replace(/^\0/, '').split('\0');
// first try and sort Hex codes or Dates
const x_date = parseInt(x.match(RE_HEX), 16) || x_toks.length !== 1 && x.match(RE_DATE) && Date.parse(x);
const y_date = parseInt(y.match(RE_HEX), 16) || x_date && y.match(RE_DATE) && Date.parse(y) || null;
if (y_date) {
if (x_date < y_date) {
return -1;
}
if (x_date > y_date) {
return 1;
}
}
// natural sorting through split numeric strings and default strings
for (let idx = 0, len = Math.max(x_toks.length, y_toks.length); idx < len; idx += 1) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
let x_tok = !(x_toks[idx] || '').match(RE_LEADING_ZERO) && parseFloat(x_toks[idx]) || x_toks[idx] || 0;
let y_tok = !(y_toks[idx] || '').match(RE_LEADING_ZERO) && parseFloat(y_toks[idx]) || y_toks[idx] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(x_tok) !== isNaN(y_tok)) {
return isNaN(x_tok) ? 1 : -1;
}
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
if (typeof x_tok !== typeof y_tok) {
x_tok = String(x_tok);
y_tok = String(y_tok);
}
if (x_tok < y_tok) {
return -1;
}
if (x_tok > y_tok) {
return 1;
}
}
return 0;
};
/* eslint-enable */
module.exports = {
naturalCmp: natural_cmp
};

View File

@ -1,7 +1,7 @@
const {dom} = require('../util');
const rootSelector = 'body';
const topbarTpl =
const SEL_ROOT = 'body';
const TPL_TOPBAR =
`<div id="topbar">
<div id="toolbar"></div>
<div id="flowbar"></div>
@ -10,17 +10,17 @@ const topbarTpl =
<div>by h5ai</div>
</a>
</div>`;
const mainrowTpl =
const TPL_MAINROW =
`<div id="mainrow">
<div id="content"></div>
</div>`;
const init = () => {
const $root = dom(rootSelector)
const $root = dom(SEL_ROOT)
.attr('id', 'root')
.clr()
.app(topbarTpl)
.app(mainrowTpl);
.app(TPL_TOPBAR)
.app(TPL_MAINROW);
return {
$root,

View File

@ -4,25 +4,25 @@
throw new Error('no-window');
}
var noBrowser = 'no-browser';
var docEl = win.document.documentElement;
docEl.className = '';
var no_browser = 'no-browser';
var doc_el = win.document.documentElement;
doc_el.className = '';
function assert(msg, expr) {
if (!expr) {
docEl.className = noBrowser;
throw new Error(noBrowser + ': ' + msg);
doc_el.className = no_browser;
throw new Error(no_browser + ': ' + msg);
}
}
function isFn(x) {
function is_fn(x) {
return typeof x === 'function';
}
assert('console', win.console && isFn(win.console.log));
assert('assign', win.Object && isFn(win.Object.assign));
assert('promise', isFn(win.Promise));
// assert('xhr', isFn(win.XMLHttpRequest)); // is object in safari
assert('console', win.console && is_fn(win.console.log));
assert('assign', win.Object && is_fn(win.Object.assign));
assert('promise', is_fn(win.Promise));
// assert('xhr', is_fn(win.XMLHttpRequest)); // is object in safari
assert('xhr', win.XMLHttpRequest);
}(this));
/* eslint-enable */