6.2.0 - 重新设计及编写项目文档; 新增多语言适配; 丰富控件选择器功能; 优化夜间模式适配等
This commit is contained in:
697
app/src/main/assets/modules/__globals__.js
Normal file
697
app/src/main/assets/modules/__globals__.js
Normal file
@@ -0,0 +1,697 @@
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
/* Overwritten protection. */
|
||||
|
||||
let { autojs, console, device, pickup, ui, util, Numberx } = global;
|
||||
|
||||
/* Here, importClass() is not recommended for intelligent code completion in IDE like WebStorm. */
|
||||
/* The same is true of destructuring assignment syntax (like `let {Uri} = android.net`). */
|
||||
|
||||
let ScriptRuntime = org.autojs.autojs.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
* @param {org.autojs.autojs.runtime.ScriptRuntime} runtime
|
||||
* @param {org.mozilla.javascript.Scriptable | global} scope
|
||||
*/
|
||||
module.exports = function (runtime, scope) {
|
||||
let _ = {
|
||||
scale: {
|
||||
base: {
|
||||
x: 720,
|
||||
y: 1280,
|
||||
},
|
||||
baseState: {
|
||||
x: false,
|
||||
y: false,
|
||||
},
|
||||
ensureBase(o) {
|
||||
if (!(o > 0 && Number.isInteger(o))) {
|
||||
throw RangeError(`Scale base "${o}" must be a positive integer.`);
|
||||
}
|
||||
},
|
||||
ensureBaseXSetOnlyOnce(x) {
|
||||
if (this.baseState.x === x) {
|
||||
throw Error(`Scale base X could be set only once, ${this.base.x} has been set as the base.`);
|
||||
}
|
||||
},
|
||||
ensureBaseYSetOnlyOnce(y) {
|
||||
if (this.baseState.y === y) {
|
||||
throw Error(`Scale base Y could be set only once, ${this.base.y} has been set as the base.`);
|
||||
}
|
||||
},
|
||||
ensureBasesConsistent() {
|
||||
if (this.baseState.x !== this.baseState.y) {
|
||||
throw Error(`Scale bases must be consistent, { x: ${this.baseState.x}, y: ${this.baseState.y} }.`);
|
||||
}
|
||||
},
|
||||
},
|
||||
uiHandler: runtime.getUiHandler(),
|
||||
buildTypes: {
|
||||
release: 100, beta: 50, alpha: 0,
|
||||
},
|
||||
toasts: {
|
||||
/**
|
||||
* @type {Set<android.widget.Toast>}
|
||||
*/
|
||||
pool: new Set(),
|
||||
lock: new ReentrantLock(),
|
||||
add(t) {
|
||||
if (t instanceof Toast) {
|
||||
this.lock.lock();
|
||||
this.pool.add(t);
|
||||
this.addCallback(t);
|
||||
this.lock.unlock();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {android.widget.Toast} t
|
||||
*/
|
||||
addCallback(t) {
|
||||
const remove = () => _.toasts.remove(t);
|
||||
|
||||
if (util.version.sdkInt >= util.versionCodes.R) {
|
||||
t.addCallback(new JavaAdapter(Toast.Callback, {
|
||||
onToastShown: () => void 0,
|
||||
onToastHidden: remove,
|
||||
}));
|
||||
} else {
|
||||
_.uiHandler.postDelayed(new JavaAdapter(java.lang.Runnable, {
|
||||
run: remove,
|
||||
}), this.getDuration(t) + 1e3 /* As toast may show with some delay. */);
|
||||
}
|
||||
},
|
||||
remove(t) {
|
||||
if (this.pool.has(t)) {
|
||||
this.lock.lock();
|
||||
this.pool.delete(t);
|
||||
this.lock.unlock();
|
||||
}
|
||||
},
|
||||
dismissAll() {
|
||||
if (this.pool.size > 0) {
|
||||
this.lock.lock();
|
||||
this.pool.forEach((t) => t.cancel());
|
||||
this.pool.clear();
|
||||
this.lock.unlock();
|
||||
}
|
||||
},
|
||||
getDuration(t) {
|
||||
let du = {
|
||||
SHORT_DELAY: 2e3,
|
||||
LONG_DELAY: 3.5e3,
|
||||
};
|
||||
switch (t.getDuration()) {
|
||||
case Toast.LENGTH_SHORT:
|
||||
return du.SHORT_DELAY;
|
||||
case Toast.LENGTH_LONG:
|
||||
return du.LONG_DELAY;
|
||||
default:
|
||||
return Math.max.apply(null, Object.values(du));
|
||||
}
|
||||
},
|
||||
},
|
||||
extensions: {
|
||||
/** @global */
|
||||
get WIDTH() {
|
||||
return ScreenMetrics.getDeviceScreenWidth();
|
||||
},
|
||||
/** @global */
|
||||
get HEIGHT() {
|
||||
return ScreenMetrics.getDeviceScreenHeight();
|
||||
},
|
||||
// @Caution by SuperMonster003 on Oct 11, 2022.
|
||||
// ! android.widget.Toast.makeText() doesn't work well on Android API Level 28 (Android 9) [P].
|
||||
// ! There hasn't been a solution for this so far.
|
||||
// ! Tested devices:
|
||||
// ! 1. SONY XPERIA XZ1 Compact (G8441)
|
||||
// ! 2. Android Studio AVD (Android 9.0 x86)
|
||||
/** @global */
|
||||
toast(msg, isLong, isForcible) {
|
||||
let $ = {
|
||||
rex: {
|
||||
long: /^l(ong)?$/i,
|
||||
short: /^s(hort)?$/i,
|
||||
forcible: /^f(orcible)?$/i,
|
||||
},
|
||||
toast() {
|
||||
this.init(arguments);
|
||||
this.show();
|
||||
},
|
||||
init() {
|
||||
this.message = isNullish(msg) ? '' : String(msg);
|
||||
this.isForcible = this.parseIsForcible(isForcible);
|
||||
this.isLong = this.parseIsLong(isLong);
|
||||
},
|
||||
parseIsLong(isLong) {
|
||||
if (typeof isLong === 'boolean') {
|
||||
return isLong;
|
||||
}
|
||||
if (typeof isLong === 'number') {
|
||||
return Boolean(isLong);
|
||||
}
|
||||
if (typeof isLong === 'string') {
|
||||
if (this.rex.long.test(isLong)) {
|
||||
return true;
|
||||
}
|
||||
if (this.rex.short.test(isLong)) {
|
||||
return false;
|
||||
}
|
||||
if (this.rex.forcible.test(isLong)) {
|
||||
this.isForcible = true;
|
||||
return false;
|
||||
}
|
||||
throw Error(`Invalid param: {name: isLong, value: ${isLong}, type: ${species(isLong)}.`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
parseIsForcible(isForcible) {
|
||||
if (typeof isForcible === 'boolean') {
|
||||
return isForcible;
|
||||
}
|
||||
if (typeof isForcible === 'number') {
|
||||
return Boolean(isForcible);
|
||||
}
|
||||
if (typeof isForcible === 'string') {
|
||||
if (this.rex.forcible.test(isForcible)) {
|
||||
return true;
|
||||
}
|
||||
throw Error(`Invalid param: {name: isForcible, value: ${isForcible}, type: ${species(isForcible)}.`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
show() {
|
||||
_.uiHandler.post(() => {
|
||||
if ($.isForcible) {
|
||||
_.toasts.dismissAll();
|
||||
}
|
||||
let len = $.isLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
|
||||
let o = Toast.makeText(_.uiHandler.getContext(), $.message, len);
|
||||
_.toasts.add(o);
|
||||
o.show();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
$.toast();
|
||||
},
|
||||
/** @global */
|
||||
toastLog(msg, isLong, isForcible) {
|
||||
this.toast.apply(this, arguments);
|
||||
console.log(msg);
|
||||
},
|
||||
/** @global */
|
||||
sleep(millisMin, millisMax) {
|
||||
let $ = {
|
||||
rexNum: /[+-]?(\d+(\.\d+)?(e\d+)?)/,
|
||||
set min(v) {
|
||||
this._min = Number(v);
|
||||
},
|
||||
get min() {
|
||||
return Math.max(this._min, 0);
|
||||
},
|
||||
set max(v) {
|
||||
this._max = Number(v);
|
||||
},
|
||||
get max() {
|
||||
return Math.min(this._max, Number.MAX_SAFE_INTEGER);
|
||||
},
|
||||
sleep(min, max) {
|
||||
if (this.trigger()) {
|
||||
this.parseArgs(min, max);
|
||||
try {
|
||||
runtime.sleep(this.min + this.randBound);
|
||||
} catch (e) {
|
||||
if (!(e.javaException instanceof ScriptInterruptedException)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
trigger() {
|
||||
if (ui.isUiThread()) {
|
||||
throw Error('不能在ui线程执行阻塞操作,请使用setTimeout代替.');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
parseArgs(min, max) {
|
||||
this.parseMin(min);
|
||||
this.parseMax(max);
|
||||
this.parseRandBound();
|
||||
},
|
||||
parseMin(min) {
|
||||
if (typeof min !== 'number') {
|
||||
throw TypeError('Type of millisMin must be a number.');
|
||||
}
|
||||
this.min = min;
|
||||
},
|
||||
parseMax(max) {
|
||||
if (typeof max === 'number') {
|
||||
this.max = max;
|
||||
} else if (typeof max === 'string') {
|
||||
let matched = max.match(this.rexNum);
|
||||
if (matched === null) {
|
||||
throw TypeError('String millisMax must have a number contained.');
|
||||
}
|
||||
let delta = Number(matched[0]);
|
||||
this.max = this.min + delta;
|
||||
this.min = this.min - delta;
|
||||
} else {
|
||||
this.max = this.min;
|
||||
}
|
||||
},
|
||||
parseRandBound() {
|
||||
this.randBound = Math.ceil(Math.random() * (this.max - this.min));
|
||||
},
|
||||
};
|
||||
|
||||
$.sleep(millisMin, millisMax);
|
||||
},
|
||||
/** @global */
|
||||
isStopped() {
|
||||
return runtime.isStopped();
|
||||
},
|
||||
/** @global */
|
||||
isShuttingDown() {
|
||||
return isStopped();
|
||||
},
|
||||
/** @global */
|
||||
notStopped() {
|
||||
return !this.isStopped();
|
||||
},
|
||||
/** @global */
|
||||
isRunning() {
|
||||
return !this.isStopped();
|
||||
},
|
||||
/** @global */
|
||||
exit(e) {
|
||||
if (typeof e === 'undefined') {
|
||||
runtime.exit();
|
||||
} else if (typeof e === 'string') {
|
||||
runtime.exit(new java.lang.Exception(e));
|
||||
} else if (typeof e instanceof java.lang.Throwable) {
|
||||
runtime.exit(e);
|
||||
} else {
|
||||
throw TypeError(`Unknown type of argument "e" with value ${e}} for exit()`);
|
||||
}
|
||||
},
|
||||
/** @global */
|
||||
stop() {
|
||||
this.exit();
|
||||
},
|
||||
/** @global */
|
||||
setClip(text) {
|
||||
return runtime.setClip(text);
|
||||
},
|
||||
/** @global */
|
||||
getClip() {
|
||||
return runtime.getClip();
|
||||
},
|
||||
/** @global */
|
||||
currentPackage() {
|
||||
auto();
|
||||
return runtime.info.getLatestPackage();
|
||||
},
|
||||
/** @global */
|
||||
currentActivity() {
|
||||
auto();
|
||||
return runtime.info.getLatestActivity();
|
||||
},
|
||||
/**
|
||||
* @global
|
||||
* @param {Wait.Condition} condition
|
||||
* @param {?number|Wait.Callback} [limit=10e3]
|
||||
* @param {?number|Wait.Callback} [interval=200]
|
||||
* @param {Wait.Callback} [callback]
|
||||
* @return {any}
|
||||
*/
|
||||
wait(condition, limit, interval, callback) {
|
||||
if (isObjectSpecies(arguments[1])) {
|
||||
// @Overload wait(condition, callback): any
|
||||
return this.wait(condition, /* limit = */ null, /* interval = */ null, /* callback = */ arguments[1]);
|
||||
}
|
||||
|
||||
if (isObjectSpecies(arguments[2])) {
|
||||
// @Overload wait(condition, limit, callback): any
|
||||
return this.wait(condition, limit, /* interval = */ null, /* callback = */ arguments[2]);
|
||||
}
|
||||
|
||||
let $ = {
|
||||
result: false,
|
||||
start: Date.now(),
|
||||
callback: callback || {},
|
||||
parseArgs() {
|
||||
let lmt = typeof limit === 'number' ? limit : limit === null ? NaN : Number(limit);
|
||||
if (isNaN(lmt)) {
|
||||
lmt = 10e3;
|
||||
}
|
||||
if (lmt < 0) {
|
||||
throw Error(`Limitation (${lmt}) cannot be negative for wait().`);
|
||||
}
|
||||
if (lmt < 100) {
|
||||
this.times = lmt;
|
||||
this.timeout = Infinity;
|
||||
} else {
|
||||
this.times = Infinity;
|
||||
this.timeout = lmt;
|
||||
}
|
||||
|
||||
let itv = typeof interval === 'number' ? interval : interval === null ? NaN : Number(interval);
|
||||
if (isNaN(itv)) {
|
||||
itv = 200;
|
||||
}
|
||||
if (!isFinite(itv)) {
|
||||
throw Error(`Interval cannot be Infinity for wait().`);
|
||||
}
|
||||
if (itv < 0) {
|
||||
throw Error(`Interval (${itv}) cannot be negative for wait().`);
|
||||
}
|
||||
this.interval = itv;
|
||||
|
||||
if (this.interval >= this.timeout) {
|
||||
this.times = Math.min(this.times, 1);
|
||||
}
|
||||
},
|
||||
check() {
|
||||
if (condition instanceof UiObject) {
|
||||
throw TypeError('UiObject cannot be used as the condition for wait().');
|
||||
}
|
||||
return typeof condition === 'function' ? condition() : pickup(condition);
|
||||
},
|
||||
wait() {
|
||||
if (!this.times) {
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
let checked = this.checked = this.check();
|
||||
|
||||
// Some falsy values [ 0, 0n, -0, "" (empty string) ] should pass the check.
|
||||
this.result = !(isNullish(checked) || Number.isNaN(checked) || checked === false);
|
||||
|
||||
this.times -= 1;
|
||||
|
||||
if (this.result || !this.times) {
|
||||
break;
|
||||
}
|
||||
if (Date.now() - this.start > this.timeout) {
|
||||
break;
|
||||
}
|
||||
sleep(this.interval);
|
||||
}
|
||||
},
|
||||
callbackIFN() {
|
||||
let fn = this.result ? this.callback.then : this.callback.else;
|
||||
if (fn !== undefined) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw TypeError(`Callback must be function type for wait().`);
|
||||
}
|
||||
let res = fn(this.checked);
|
||||
if (res !== undefined) {
|
||||
this.result = res;
|
||||
}
|
||||
}
|
||||
},
|
||||
getResult() {
|
||||
this.parseArgs();
|
||||
this.wait();
|
||||
this.callbackIFN();
|
||||
|
||||
return this.result;
|
||||
},
|
||||
};
|
||||
|
||||
return $.getResult();
|
||||
},
|
||||
/** @global */
|
||||
waitForActivity(activityName, limit, interval, callback) {
|
||||
_.ensureNonUiThread();
|
||||
let condition = () => currentActivity() === activityName;
|
||||
return wait.apply(scope, [ condition ].concat(Array.from(arguments).slice(1)));
|
||||
},
|
||||
/** @global */
|
||||
waitForPackage(packageName, limit, interval, callback) {
|
||||
_.ensureNonUiThread();
|
||||
let condition = () => currentPackage() === packageName;
|
||||
return wait.apply(scope, [ condition ].concat(Array.from(arguments).slice(1)));
|
||||
},
|
||||
/** @global */
|
||||
random(min, max) {
|
||||
if (arguments.length === 0) {
|
||||
return Math.random();
|
||||
}
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
},
|
||||
/** @global */
|
||||
setScreenMetrics(width, height) {
|
||||
runtime.setScreenMetrics(width, height);
|
||||
},
|
||||
/** @global */
|
||||
requiresApi(requiresApi) {
|
||||
ScriptRuntime.requiresApi(requiresApi);
|
||||
},
|
||||
/** @global */
|
||||
requiresAutojsVersion(version) {
|
||||
if (typeof version === 'number') {
|
||||
if (_.compare(version, autojs.versionCode) > 0) {
|
||||
throw Error(`AutoJs6 版本号需不低于 ${version}.`);
|
||||
}
|
||||
} else {
|
||||
if (_.compareVersion(version, autojs.versionName) > 0) {
|
||||
throw Error(`AutoJs6 版本需不低于 ${version}.`);
|
||||
}
|
||||
}
|
||||
},
|
||||
getScaleBases() {
|
||||
return _.scale.base;
|
||||
},
|
||||
getScaleBaseX() {
|
||||
return _.scale.base.x;
|
||||
},
|
||||
getScaleBaseY() {
|
||||
return _.scale.base.y;
|
||||
},
|
||||
setScaleBases(baseX, baseY) {
|
||||
this.setScaleBaseX(baseX);
|
||||
this.setScaleBaseY(baseY);
|
||||
},
|
||||
setScaleBaseX(baseX) {
|
||||
_.scale.ensureBaseXSetOnlyOnce(baseX);
|
||||
_.scale.ensureBase(baseX);
|
||||
_.scale.base.x = baseX;
|
||||
_.scale.baseState.x = true;
|
||||
},
|
||||
setScaleBaseY(baseY) {
|
||||
_.scale.ensureBaseYSetOnlyOnce(baseY);
|
||||
_.scale.ensureBase(baseY);
|
||||
_.scale.base.y = baseY;
|
||||
_.scale.baseState.y = true;
|
||||
},
|
||||
/** @global */
|
||||
cX(num, base, isRatio) {
|
||||
let W = device.width;
|
||||
if (arguments.length === 0) {
|
||||
return W;
|
||||
}
|
||||
// @Overload
|
||||
if (typeof base === 'boolean') {
|
||||
return this.cX(num, null, base);
|
||||
}
|
||||
if (Math.abs(num) < 1 && isRatio !== false || isRatio) {
|
||||
return Math.round(W * num);
|
||||
}
|
||||
if (typeof base === 'number') {
|
||||
_.scale.ensureBase(base);
|
||||
} else {
|
||||
base = _.scale.base.x;
|
||||
}
|
||||
return Math.round(W * num / base);
|
||||
},
|
||||
/** @global */
|
||||
cY(num, base, isRatio) {
|
||||
let H = device.height;
|
||||
if (arguments.length === 0) {
|
||||
return H;
|
||||
}
|
||||
// @Overload
|
||||
if (typeof base === 'boolean') {
|
||||
return this.cY(num, null, base);
|
||||
}
|
||||
if (Math.abs(num) < 1 && isRatio !== false || isRatio) {
|
||||
return Math.round(H * num);
|
||||
}
|
||||
if (typeof base === 'number') {
|
||||
_.scale.ensureBase(base);
|
||||
} else {
|
||||
base = _.scale.base.y;
|
||||
}
|
||||
return Math.round(H * num / base);
|
||||
},
|
||||
/** @global */
|
||||
cYx(num, base, isRatio) {
|
||||
_.scale.ensureBasesConsistent();
|
||||
// @Overload
|
||||
if (typeof base === 'boolean') {
|
||||
return this.cYx(num, null, base);
|
||||
}
|
||||
// @Overload
|
||||
if (typeof base === 'string') {
|
||||
return this.cYx(num, Numberx.parseRatio(base), true);
|
||||
}
|
||||
let W = device.width;
|
||||
if (Math.abs(num) < 1 || isRatio) {
|
||||
if (isNullish(base)) {
|
||||
base = _.scale.base.y / _.scale.base.x;
|
||||
}
|
||||
if (typeof base === 'number') {
|
||||
return Numberx.check(0, '<', base, '<=', 1)
|
||||
? Math.round(num * W / base)
|
||||
: Math.round(num * W * base);
|
||||
}
|
||||
throw Error('Base of cYx() must be a valid number.');
|
||||
}
|
||||
if (isNullish(base)) {
|
||||
base = _.scale.base.x;
|
||||
}
|
||||
return Math.round(num * W / base);
|
||||
},
|
||||
/** @global */
|
||||
cXy(num, base, isRatio) {
|
||||
_.scale.ensureBasesConsistent();
|
||||
// @Overload
|
||||
if (typeof base === 'boolean') {
|
||||
return this.cXy(num, null, base);
|
||||
}
|
||||
// @Overload
|
||||
if (typeof base === 'string') {
|
||||
return this.cXy(num, Numberx.parseRatio(base), true);
|
||||
}
|
||||
let H = device.height;
|
||||
if (Math.abs(num) < 1 || isRatio) {
|
||||
if (isNullish(base)) {
|
||||
base = _.scale.base.y / _.scale.base.x;
|
||||
}
|
||||
if (typeof base === 'number') {
|
||||
return Numberx.check(0, '<', base, '<=', 1)
|
||||
? Math.round(num * H * base)
|
||||
: Math.round(num * H / base);
|
||||
}
|
||||
throw Error('Base of cXy() must be a valid number.');
|
||||
}
|
||||
if (isNullish(base)) {
|
||||
base = _.scale.base.y;
|
||||
}
|
||||
return Math.round(num * H / base);
|
||||
},
|
||||
$bind() {
|
||||
this.toast.dismissAll = () => {
|
||||
_.uiHandler.post(() => {
|
||||
_.toasts.dismissAll();
|
||||
});
|
||||
};
|
||||
delete this.$bind;
|
||||
return this;
|
||||
},
|
||||
// $selfProtect() {
|
||||
// /* Protection of global properties from being modified or deleted. */
|
||||
// ( /* @IIFE */ () => [
|
||||
// [ 'auto', 'colors' ],
|
||||
//
|
||||
// [ 'android', 'com', 'edu', 'java', 'javax', 'net', 'org' ],
|
||||
//
|
||||
// [ 'Array', 'BigInt', 'Boolean', 'Error', 'Function', 'JSON', 'Map', 'Math' ],
|
||||
// [ 'Module', 'Number', 'Object', 'Promise', 'RegExp', 'Set', 'String', 'Symbol' ],
|
||||
//
|
||||
// [ 'clearImmediate', 'clearInterval', 'clearTimeout', 'decodeURI', 'decodeURIComponent' ],
|
||||
// [ 'encodeURI', 'encodeURIComponent', 'escape', 'eval', 'isFinite', 'isNaN', 'parseFloat' ],
|
||||
// [ 'parseInt', 'setImmediate', 'setInterval', 'setTimeout', 'unescape' ],
|
||||
//
|
||||
// [ 'Packages', 'alert', 'confirm', 'click', 'err', 'log', 'pickup', 'detect', 'prompt' ],
|
||||
// ]
|
||||
// .flat()
|
||||
// .filter((name) => {
|
||||
// return Object.prototype.hasOwnProperty.call(scope, name)
|
||||
// && Object.getOwnPropertyDescriptor(scope, name).writable;
|
||||
// })
|
||||
// .forEach((key) => {
|
||||
// Object.defineProperty(scope, key, {
|
||||
// configurable: false,
|
||||
// writable: false,
|
||||
// });
|
||||
// }))();
|
||||
//
|
||||
// delete this.$selfProtect;
|
||||
// },
|
||||
$appropriateProtect() {
|
||||
[
|
||||
'continuation', 'selector',
|
||||
].forEach((key) => {
|
||||
Object.defineProperty(scope, key, {
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
});
|
||||
});
|
||||
|
||||
delete this.$appropriateProtect;
|
||||
},
|
||||
},
|
||||
ensureNonUiThread() {
|
||||
if (ui.isUiThread()) {
|
||||
throw Error('不能在ui线程执行阻塞操作,请在子线程或子脚本执行,或者使用setInterval循环检测当前activity和package.');
|
||||
}
|
||||
},
|
||||
compareVersion(v1, v2) {
|
||||
v1 = this.parseVersion(v1);
|
||||
v2 = this.parseVersion(v2);
|
||||
if (v1.major !== v2.major) {
|
||||
return this.compare(v1.major, v2.major);
|
||||
}
|
||||
if (v1.minor !== v2.minor) {
|
||||
return this.compare(v1.minor, v2.minor);
|
||||
}
|
||||
if (v1.revision !== v2.revision) {
|
||||
return this.compare(v1.revision, v2.revision);
|
||||
}
|
||||
if (v1.buildType !== v2.buildType) {
|
||||
return this.compare(v1.buildType, v2.buildType);
|
||||
}
|
||||
return this.compare(v1.build, v2.build);
|
||||
},
|
||||
compare(a, b) {
|
||||
return a > b ? 1 : a < b ? -1 : 0;
|
||||
},
|
||||
parseVersion(v) {
|
||||
const m = /(\d+)\.(\d+)\.(\d+)\s*(A(lpha)?|B(eta)?)?(\d*)/i.exec(v);
|
||||
if (!m) {
|
||||
throw Error(`版本格式不合法: ${v}.`);
|
||||
}
|
||||
return {
|
||||
major: parseInt(m[1]),
|
||||
minor: parseInt(m[2]),
|
||||
revision: parseInt(m[3]),
|
||||
buildType: _.buildType(m[4]),
|
||||
build: m[5] ? parseInt(m[5]) : 1,
|
||||
};
|
||||
},
|
||||
buildType(str) {
|
||||
if (str === 'Alpha') {
|
||||
return this.buildTypes.alpha;
|
||||
}
|
||||
if (str === 'Beta') {
|
||||
return this.buildTypes.beta;
|
||||
}
|
||||
return this.buildTypes.release;
|
||||
},
|
||||
};
|
||||
|
||||
Object.assign(scope, _.extensions.$bind());
|
||||
|
||||
// Object.keys(_.extensions)
|
||||
// .filter(key => !key.startsWith('$'))
|
||||
// .forEach((key) => {
|
||||
// Object.defineProperty(scope, key, {
|
||||
// enumerable: true,
|
||||
// configurable: false,
|
||||
// writable: false,
|
||||
// });
|
||||
// });
|
||||
};
|
||||
Reference in New Issue
Block a user