Update.
This commit is contained in:
parent
a556a2be50
commit
d81d8a9298
10 changed files with 111 additions and 110 deletions
|
@ -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`)
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = Object.assign({},
|
||||
require('./lo'),
|
||||
require('./dom'),
|
||||
require('./naturalCmp'),
|
||||
require('./natural_cmp'),
|
||||
require('./misc')
|
||||
);
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
63
src/_h5ai/public/js/lib/util/natural_cmp.js
Normal file
63
src/_h5ai/public/js/lib/util/natural_cmp.js
Normal 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
|
||||
};
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue