28599 lines
1.1 MiB
28599 lines
1.1 MiB
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __typeError = (msg) => {
|
|
throw TypeError(msg);
|
|
};
|
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
var __commonJS = (cb, mod) => function __require() {
|
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
};
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to2, from2, except, desc) => {
|
|
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
|
|
for (let key of __getOwnPropNames(from2))
|
|
if (!__hasOwnProp.call(to2, key) && key !== except)
|
|
__defProp(to2, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
|
|
}
|
|
return to2;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
|
|
// node_modules/.pnpm/moment@2.30.1/node_modules/moment/moment.js
|
|
var require_moment = __commonJS({
|
|
"node_modules/.pnpm/moment@2.30.1/node_modules/moment/moment.js"(exports, module2) {
|
|
(function(global, factory) {
|
|
typeof exports === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global.moment = factory();
|
|
})(exports, function() {
|
|
"use strict";
|
|
var hookCallback;
|
|
function hooks() {
|
|
return hookCallback.apply(null, arguments);
|
|
}
|
|
function setHookCallback(callback2) {
|
|
hookCallback = callback2;
|
|
}
|
|
function isArray2(input) {
|
|
return input instanceof Array || Object.prototype.toString.call(input) === "[object Array]";
|
|
}
|
|
function isObject2(input) {
|
|
return input != null && Object.prototype.toString.call(input) === "[object Object]";
|
|
}
|
|
function hasOwnProp(a2, b2) {
|
|
return Object.prototype.hasOwnProperty.call(a2, b2);
|
|
}
|
|
function isObjectEmpty(obj) {
|
|
if (Object.getOwnPropertyNames) {
|
|
return Object.getOwnPropertyNames(obj).length === 0;
|
|
} else {
|
|
var k;
|
|
for (k in obj) {
|
|
if (hasOwnProp(obj, k)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
function isUndefined(input) {
|
|
return input === void 0;
|
|
}
|
|
function isNumber2(input) {
|
|
return typeof input === "number" || Object.prototype.toString.call(input) === "[object Number]";
|
|
}
|
|
function isDate(input) {
|
|
return input instanceof Date || Object.prototype.toString.call(input) === "[object Date]";
|
|
}
|
|
function map3(arr, fn2) {
|
|
var res = [], i2, arrLen = arr.length;
|
|
for (i2 = 0; i2 < arrLen; ++i2) {
|
|
res.push(fn2(arr[i2], i2));
|
|
}
|
|
return res;
|
|
}
|
|
function extend(a2, b2) {
|
|
for (var i2 in b2) {
|
|
if (hasOwnProp(b2, i2)) {
|
|
a2[i2] = b2[i2];
|
|
}
|
|
}
|
|
if (hasOwnProp(b2, "toString")) {
|
|
a2.toString = b2.toString;
|
|
}
|
|
if (hasOwnProp(b2, "valueOf")) {
|
|
a2.valueOf = b2.valueOf;
|
|
}
|
|
return a2;
|
|
}
|
|
function createUTC(input, format2, locale3, strict) {
|
|
return createLocalOrUTC(input, format2, locale3, strict, true).utc();
|
|
}
|
|
function defaultParsingFlags() {
|
|
return {
|
|
empty: false,
|
|
unusedTokens: [],
|
|
unusedInput: [],
|
|
overflow: -2,
|
|
charsLeftOver: 0,
|
|
nullInput: false,
|
|
invalidEra: null,
|
|
invalidMonth: null,
|
|
invalidFormat: false,
|
|
userInvalidated: false,
|
|
iso: false,
|
|
parsedDateParts: [],
|
|
era: null,
|
|
meridiem: null,
|
|
rfc2822: false,
|
|
weekdayMismatch: false
|
|
};
|
|
}
|
|
function getParsingFlags(m2) {
|
|
if (m2._pf == null) {
|
|
m2._pf = defaultParsingFlags();
|
|
}
|
|
return m2._pf;
|
|
}
|
|
var some;
|
|
if (Array.prototype.some) {
|
|
some = Array.prototype.some;
|
|
} else {
|
|
some = function(fun) {
|
|
var t3 = Object(this), len = t3.length >>> 0, i2;
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
if (i2 in t3 && fun.call(this, t3[i2], i2, t3)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
function isValid(m2) {
|
|
var flags = null, parsedParts = false, isNowValid = m2._d && !isNaN(m2._d.getTime());
|
|
if (isNowValid) {
|
|
flags = getParsingFlags(m2);
|
|
parsedParts = some.call(flags.parsedDateParts, function(i2) {
|
|
return i2 != null;
|
|
});
|
|
isNowValid = flags.overflow < 0 && !flags.empty && !flags.invalidEra && !flags.invalidMonth && !flags.invalidWeekday && !flags.weekdayMismatch && !flags.nullInput && !flags.invalidFormat && !flags.userInvalidated && (!flags.meridiem || flags.meridiem && parsedParts);
|
|
if (m2._strict) {
|
|
isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === void 0;
|
|
}
|
|
}
|
|
if (Object.isFrozen == null || !Object.isFrozen(m2)) {
|
|
m2._isValid = isNowValid;
|
|
} else {
|
|
return isNowValid;
|
|
}
|
|
return m2._isValid;
|
|
}
|
|
function createInvalid(flags) {
|
|
var m2 = createUTC(NaN);
|
|
if (flags != null) {
|
|
extend(getParsingFlags(m2), flags);
|
|
} else {
|
|
getParsingFlags(m2).userInvalidated = true;
|
|
}
|
|
return m2;
|
|
}
|
|
var momentProperties = hooks.momentProperties = [], updateInProgress = false;
|
|
function copyConfig(to3, from3) {
|
|
var i2, prop, val, momentPropertiesLen = momentProperties.length;
|
|
if (!isUndefined(from3._isAMomentObject)) {
|
|
to3._isAMomentObject = from3._isAMomentObject;
|
|
}
|
|
if (!isUndefined(from3._i)) {
|
|
to3._i = from3._i;
|
|
}
|
|
if (!isUndefined(from3._f)) {
|
|
to3._f = from3._f;
|
|
}
|
|
if (!isUndefined(from3._l)) {
|
|
to3._l = from3._l;
|
|
}
|
|
if (!isUndefined(from3._strict)) {
|
|
to3._strict = from3._strict;
|
|
}
|
|
if (!isUndefined(from3._tzm)) {
|
|
to3._tzm = from3._tzm;
|
|
}
|
|
if (!isUndefined(from3._isUTC)) {
|
|
to3._isUTC = from3._isUTC;
|
|
}
|
|
if (!isUndefined(from3._offset)) {
|
|
to3._offset = from3._offset;
|
|
}
|
|
if (!isUndefined(from3._pf)) {
|
|
to3._pf = getParsingFlags(from3);
|
|
}
|
|
if (!isUndefined(from3._locale)) {
|
|
to3._locale = from3._locale;
|
|
}
|
|
if (momentPropertiesLen > 0) {
|
|
for (i2 = 0; i2 < momentPropertiesLen; i2++) {
|
|
prop = momentProperties[i2];
|
|
val = from3[prop];
|
|
if (!isUndefined(val)) {
|
|
to3[prop] = val;
|
|
}
|
|
}
|
|
}
|
|
return to3;
|
|
}
|
|
function Moment3(config) {
|
|
copyConfig(this, config);
|
|
this._d = new Date(config._d != null ? config._d.getTime() : NaN);
|
|
if (!this.isValid()) {
|
|
this._d = /* @__PURE__ */ new Date(NaN);
|
|
}
|
|
if (updateInProgress === false) {
|
|
updateInProgress = true;
|
|
hooks.updateOffset(this);
|
|
updateInProgress = false;
|
|
}
|
|
}
|
|
function isMoment(obj) {
|
|
return obj instanceof Moment3 || obj != null && obj._isAMomentObject != null;
|
|
}
|
|
function warn(msg) {
|
|
if (hooks.suppressDeprecationWarnings === false && typeof console !== "undefined" && console.warn) {
|
|
console.warn("Deprecation warning: " + msg);
|
|
}
|
|
}
|
|
function deprecate(msg, fn2) {
|
|
var firstTime = true;
|
|
return extend(function() {
|
|
if (hooks.deprecationHandler != null) {
|
|
hooks.deprecationHandler(null, msg);
|
|
}
|
|
if (firstTime) {
|
|
var args = [], arg, i2, key, argLen = arguments.length;
|
|
for (i2 = 0; i2 < argLen; i2++) {
|
|
arg = "";
|
|
if (typeof arguments[i2] === "object") {
|
|
arg += "\n[" + i2 + "] ";
|
|
for (key in arguments[0]) {
|
|
if (hasOwnProp(arguments[0], key)) {
|
|
arg += key + ": " + arguments[0][key] + ", ";
|
|
}
|
|
}
|
|
arg = arg.slice(0, -2);
|
|
} else {
|
|
arg = arguments[i2];
|
|
}
|
|
args.push(arg);
|
|
}
|
|
warn(
|
|
msg + "\nArguments: " + Array.prototype.slice.call(args).join("") + "\n" + new Error().stack
|
|
);
|
|
firstTime = false;
|
|
}
|
|
return fn2.apply(this, arguments);
|
|
}, fn2);
|
|
}
|
|
var deprecations = {};
|
|
function deprecateSimple(name, msg) {
|
|
if (hooks.deprecationHandler != null) {
|
|
hooks.deprecationHandler(name, msg);
|
|
}
|
|
if (!deprecations[name]) {
|
|
warn(msg);
|
|
deprecations[name] = true;
|
|
}
|
|
}
|
|
hooks.suppressDeprecationWarnings = false;
|
|
hooks.deprecationHandler = null;
|
|
function isFunction2(input) {
|
|
return typeof Function !== "undefined" && input instanceof Function || Object.prototype.toString.call(input) === "[object Function]";
|
|
}
|
|
function set2(config) {
|
|
var prop, i2;
|
|
for (i2 in config) {
|
|
if (hasOwnProp(config, i2)) {
|
|
prop = config[i2];
|
|
if (isFunction2(prop)) {
|
|
this[i2] = prop;
|
|
} else {
|
|
this["_" + i2] = prop;
|
|
}
|
|
}
|
|
}
|
|
this._config = config;
|
|
this._dayOfMonthOrdinalParseLenient = new RegExp(
|
|
(this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + "|" + /\d{1,2}/.source
|
|
);
|
|
}
|
|
function mergeConfigs(parentConfig, childConfig) {
|
|
var res = extend({}, parentConfig), prop;
|
|
for (prop in childConfig) {
|
|
if (hasOwnProp(childConfig, prop)) {
|
|
if (isObject2(parentConfig[prop]) && isObject2(childConfig[prop])) {
|
|
res[prop] = {};
|
|
extend(res[prop], parentConfig[prop]);
|
|
extend(res[prop], childConfig[prop]);
|
|
} else if (childConfig[prop] != null) {
|
|
res[prop] = childConfig[prop];
|
|
} else {
|
|
delete res[prop];
|
|
}
|
|
}
|
|
}
|
|
for (prop in parentConfig) {
|
|
if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject2(parentConfig[prop])) {
|
|
res[prop] = extend({}, res[prop]);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
function Locale(config) {
|
|
if (config != null) {
|
|
this.set(config);
|
|
}
|
|
}
|
|
var keys;
|
|
if (Object.keys) {
|
|
keys = Object.keys;
|
|
} else {
|
|
keys = function(obj) {
|
|
var i2, res = [];
|
|
for (i2 in obj) {
|
|
if (hasOwnProp(obj, i2)) {
|
|
res.push(i2);
|
|
}
|
|
}
|
|
return res;
|
|
};
|
|
}
|
|
var defaultCalendar = {
|
|
sameDay: "[Today at] LT",
|
|
nextDay: "[Tomorrow at] LT",
|
|
nextWeek: "dddd [at] LT",
|
|
lastDay: "[Yesterday at] LT",
|
|
lastWeek: "[Last] dddd [at] LT",
|
|
sameElse: "L"
|
|
};
|
|
function calendar(key, mom, now3) {
|
|
var output = this._calendar[key] || this._calendar["sameElse"];
|
|
return isFunction2(output) ? output.call(mom, now3) : output;
|
|
}
|
|
function zeroFill(number, targetLength, forceSign) {
|
|
var absNumber = "" + Math.abs(number), zerosToFill = targetLength - absNumber.length, sign3 = number >= 0;
|
|
return (sign3 ? forceSign ? "+" : "" : "-") + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
|
|
}
|
|
var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, formatFunctions = {}, formatTokenFunctions = {};
|
|
function addFormatToken(token2, padded, ordinal2, callback2) {
|
|
var func = callback2;
|
|
if (typeof callback2 === "string") {
|
|
func = function() {
|
|
return this[callback2]();
|
|
};
|
|
}
|
|
if (token2) {
|
|
formatTokenFunctions[token2] = func;
|
|
}
|
|
if (padded) {
|
|
formatTokenFunctions[padded[0]] = function() {
|
|
return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
|
|
};
|
|
}
|
|
if (ordinal2) {
|
|
formatTokenFunctions[ordinal2] = function() {
|
|
return this.localeData().ordinal(
|
|
func.apply(this, arguments),
|
|
token2
|
|
);
|
|
};
|
|
}
|
|
}
|
|
function removeFormattingTokens(input) {
|
|
if (input.match(/\[[\s\S]/)) {
|
|
return input.replace(/^\[|\]$/g, "");
|
|
}
|
|
return input.replace(/\\/g, "");
|
|
}
|
|
function makeFormatFunction(format2) {
|
|
var array = format2.match(formattingTokens), i2, length;
|
|
for (i2 = 0, length = array.length; i2 < length; i2++) {
|
|
if (formatTokenFunctions[array[i2]]) {
|
|
array[i2] = formatTokenFunctions[array[i2]];
|
|
} else {
|
|
array[i2] = removeFormattingTokens(array[i2]);
|
|
}
|
|
}
|
|
return function(mom) {
|
|
var output = "", i3;
|
|
for (i3 = 0; i3 < length; i3++) {
|
|
output += isFunction2(array[i3]) ? array[i3].call(mom, format2) : array[i3];
|
|
}
|
|
return output;
|
|
};
|
|
}
|
|
function formatMoment(m2, format2) {
|
|
if (!m2.isValid()) {
|
|
return m2.localeData().invalidDate();
|
|
}
|
|
format2 = expandFormat(format2, m2.localeData());
|
|
formatFunctions[format2] = formatFunctions[format2] || makeFormatFunction(format2);
|
|
return formatFunctions[format2](m2);
|
|
}
|
|
function expandFormat(format2, locale3) {
|
|
var i2 = 5;
|
|
function replaceLongDateFormatTokens(input) {
|
|
return locale3.longDateFormat(input) || input;
|
|
}
|
|
localFormattingTokens.lastIndex = 0;
|
|
while (i2 >= 0 && localFormattingTokens.test(format2)) {
|
|
format2 = format2.replace(
|
|
localFormattingTokens,
|
|
replaceLongDateFormatTokens
|
|
);
|
|
localFormattingTokens.lastIndex = 0;
|
|
i2 -= 1;
|
|
}
|
|
return format2;
|
|
}
|
|
var defaultLongDateFormat = {
|
|
LTS: "h:mm:ss A",
|
|
LT: "h:mm A",
|
|
L: "MM/DD/YYYY",
|
|
LL: "MMMM D, YYYY",
|
|
LLL: "MMMM D, YYYY h:mm A",
|
|
LLLL: "dddd, MMMM D, YYYY h:mm A"
|
|
};
|
|
function longDateFormat(key) {
|
|
var format2 = this._longDateFormat[key], formatUpper = this._longDateFormat[key.toUpperCase()];
|
|
if (format2 || !formatUpper) {
|
|
return format2;
|
|
}
|
|
this._longDateFormat[key] = formatUpper.match(formattingTokens).map(function(tok) {
|
|
if (tok === "MMMM" || tok === "MM" || tok === "DD" || tok === "dddd") {
|
|
return tok.slice(1);
|
|
}
|
|
return tok;
|
|
}).join("");
|
|
return this._longDateFormat[key];
|
|
}
|
|
var defaultInvalidDate = "Invalid date";
|
|
function invalidDate() {
|
|
return this._invalidDate;
|
|
}
|
|
var defaultOrdinal = "%d", defaultDayOfMonthOrdinalParse = /\d{1,2}/;
|
|
function ordinal(number) {
|
|
return this._ordinal.replace("%d", number);
|
|
}
|
|
var defaultRelativeTime = {
|
|
future: "in %s",
|
|
past: "%s ago",
|
|
s: "a few seconds",
|
|
ss: "%d seconds",
|
|
m: "a minute",
|
|
mm: "%d minutes",
|
|
h: "an hour",
|
|
hh: "%d hours",
|
|
d: "a day",
|
|
dd: "%d days",
|
|
w: "a week",
|
|
ww: "%d weeks",
|
|
M: "a month",
|
|
MM: "%d months",
|
|
y: "a year",
|
|
yy: "%d years"
|
|
};
|
|
function relativeTime(number, withoutSuffix, string, isFuture) {
|
|
var output = this._relativeTime[string];
|
|
return isFunction2(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
|
|
}
|
|
function pastFuture(diff2, output) {
|
|
var format2 = this._relativeTime[diff2 > 0 ? "future" : "past"];
|
|
return isFunction2(format2) ? format2(output) : format2.replace(/%s/i, output);
|
|
}
|
|
var aliases = {
|
|
D: "date",
|
|
dates: "date",
|
|
date: "date",
|
|
d: "day",
|
|
days: "day",
|
|
day: "day",
|
|
e: "weekday",
|
|
weekdays: "weekday",
|
|
weekday: "weekday",
|
|
E: "isoWeekday",
|
|
isoweekdays: "isoWeekday",
|
|
isoweekday: "isoWeekday",
|
|
DDD: "dayOfYear",
|
|
dayofyears: "dayOfYear",
|
|
dayofyear: "dayOfYear",
|
|
h: "hour",
|
|
hours: "hour",
|
|
hour: "hour",
|
|
ms: "millisecond",
|
|
milliseconds: "millisecond",
|
|
millisecond: "millisecond",
|
|
m: "minute",
|
|
minutes: "minute",
|
|
minute: "minute",
|
|
M: "month",
|
|
months: "month",
|
|
month: "month",
|
|
Q: "quarter",
|
|
quarters: "quarter",
|
|
quarter: "quarter",
|
|
s: "second",
|
|
seconds: "second",
|
|
second: "second",
|
|
gg: "weekYear",
|
|
weekyears: "weekYear",
|
|
weekyear: "weekYear",
|
|
GG: "isoWeekYear",
|
|
isoweekyears: "isoWeekYear",
|
|
isoweekyear: "isoWeekYear",
|
|
w: "week",
|
|
weeks: "week",
|
|
week: "week",
|
|
W: "isoWeek",
|
|
isoweeks: "isoWeek",
|
|
isoweek: "isoWeek",
|
|
y: "year",
|
|
years: "year",
|
|
year: "year"
|
|
};
|
|
function normalizeUnits(units) {
|
|
return typeof units === "string" ? aliases[units] || aliases[units.toLowerCase()] : void 0;
|
|
}
|
|
function normalizeObjectUnits(inputObject) {
|
|
var normalizedInput = {}, normalizedProp, prop;
|
|
for (prop in inputObject) {
|
|
if (hasOwnProp(inputObject, prop)) {
|
|
normalizedProp = normalizeUnits(prop);
|
|
if (normalizedProp) {
|
|
normalizedInput[normalizedProp] = inputObject[prop];
|
|
}
|
|
}
|
|
}
|
|
return normalizedInput;
|
|
}
|
|
var priorities = {
|
|
date: 9,
|
|
day: 11,
|
|
weekday: 11,
|
|
isoWeekday: 11,
|
|
dayOfYear: 4,
|
|
hour: 13,
|
|
millisecond: 16,
|
|
minute: 14,
|
|
month: 8,
|
|
quarter: 7,
|
|
second: 15,
|
|
weekYear: 1,
|
|
isoWeekYear: 1,
|
|
week: 5,
|
|
isoWeek: 5,
|
|
year: 1
|
|
};
|
|
function getPrioritizedUnits(unitsObj) {
|
|
var units = [], u2;
|
|
for (u2 in unitsObj) {
|
|
if (hasOwnProp(unitsObj, u2)) {
|
|
units.push({ unit: u2, priority: priorities[u2] });
|
|
}
|
|
}
|
|
units.sort(function(a2, b2) {
|
|
return a2.priority - b2.priority;
|
|
});
|
|
return units;
|
|
}
|
|
var match1 = /\d/, match2 = /\d\d/, match3 = /\d{3}/, match4 = /\d{4}/, match6 = /[+-]?\d{6}/, match1to2 = /\d\d?/, match3to4 = /\d\d\d\d?/, match5to6 = /\d\d\d\d\d\d?/, match1to3 = /\d{1,3}/, match1to4 = /\d{1,4}/, match1to6 = /[+-]?\d{1,6}/, matchUnsigned = /\d+/, matchSigned = /[+-]?\d+/, matchOffset = /Z|[+-]\d\d:?\d\d/gi, matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, match1to2NoLeadingZero = /^[1-9]\d?/, match1to2HasZero = /^([1-9]\d|\d)/, regexes;
|
|
regexes = {};
|
|
function addRegexToken(token2, regex, strictRegex) {
|
|
regexes[token2] = isFunction2(regex) ? regex : function(isStrict, localeData2) {
|
|
return isStrict && strictRegex ? strictRegex : regex;
|
|
};
|
|
}
|
|
function getParseRegexForToken(token2, config) {
|
|
if (!hasOwnProp(regexes, token2)) {
|
|
return new RegExp(unescapeFormat(token2));
|
|
}
|
|
return regexes[token2](config._strict, config._locale);
|
|
}
|
|
function unescapeFormat(s2) {
|
|
return regexEscape(
|
|
s2.replace("\\", "").replace(
|
|
/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,
|
|
function(matched, p1, p2, p3, p4) {
|
|
return p1 || p2 || p3 || p4;
|
|
}
|
|
)
|
|
);
|
|
}
|
|
function regexEscape(s2) {
|
|
return s2.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
}
|
|
function absFloor(number) {
|
|
if (number < 0) {
|
|
return Math.ceil(number) || 0;
|
|
} else {
|
|
return Math.floor(number);
|
|
}
|
|
}
|
|
function toInt(argumentForCoercion) {
|
|
var coercedNumber = +argumentForCoercion, value = 0;
|
|
if (coercedNumber !== 0 && isFinite(coercedNumber)) {
|
|
value = absFloor(coercedNumber);
|
|
}
|
|
return value;
|
|
}
|
|
var tokens = {};
|
|
function addParseToken(token2, callback2) {
|
|
var i2, func = callback2, tokenLen;
|
|
if (typeof token2 === "string") {
|
|
token2 = [token2];
|
|
}
|
|
if (isNumber2(callback2)) {
|
|
func = function(input, array) {
|
|
array[callback2] = toInt(input);
|
|
};
|
|
}
|
|
tokenLen = token2.length;
|
|
for (i2 = 0; i2 < tokenLen; i2++) {
|
|
tokens[token2[i2]] = func;
|
|
}
|
|
}
|
|
function addWeekParseToken(token2, callback2) {
|
|
addParseToken(token2, function(input, array, config, token3) {
|
|
config._w = config._w || {};
|
|
callback2(input, config._w, config, token3);
|
|
});
|
|
}
|
|
function addTimeToArrayFromToken(token2, input, config) {
|
|
if (input != null && hasOwnProp(tokens, token2)) {
|
|
tokens[token2](input, config._a, config, token2);
|
|
}
|
|
}
|
|
function isLeapYear(year) {
|
|
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
}
|
|
var YEAR = 0, MONTH = 1, DATE = 2, HOUR = 3, MINUTE = 4, SECOND = 5, MILLISECOND = 6, WEEK = 7, WEEKDAY = 8;
|
|
addFormatToken("Y", 0, 0, function() {
|
|
var y2 = this.year();
|
|
return y2 <= 9999 ? zeroFill(y2, 4) : "+" + y2;
|
|
});
|
|
addFormatToken(0, ["YY", 2], 0, function() {
|
|
return this.year() % 100;
|
|
});
|
|
addFormatToken(0, ["YYYY", 4], 0, "year");
|
|
addFormatToken(0, ["YYYYY", 5], 0, "year");
|
|
addFormatToken(0, ["YYYYYY", 6, true], 0, "year");
|
|
addRegexToken("Y", matchSigned);
|
|
addRegexToken("YY", match1to2, match2);
|
|
addRegexToken("YYYY", match1to4, match4);
|
|
addRegexToken("YYYYY", match1to6, match6);
|
|
addRegexToken("YYYYYY", match1to6, match6);
|
|
addParseToken(["YYYYY", "YYYYYY"], YEAR);
|
|
addParseToken("YYYY", function(input, array) {
|
|
array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
|
|
});
|
|
addParseToken("YY", function(input, array) {
|
|
array[YEAR] = hooks.parseTwoDigitYear(input);
|
|
});
|
|
addParseToken("Y", function(input, array) {
|
|
array[YEAR] = parseInt(input, 10);
|
|
});
|
|
function daysInYear(year) {
|
|
return isLeapYear(year) ? 366 : 365;
|
|
}
|
|
hooks.parseTwoDigitYear = function(input) {
|
|
return toInt(input) + (toInt(input) > 68 ? 1900 : 2e3);
|
|
};
|
|
var getSetYear = makeGetSet("FullYear", true);
|
|
function getIsLeapYear() {
|
|
return isLeapYear(this.year());
|
|
}
|
|
function makeGetSet(unit, keepTime) {
|
|
return function(value) {
|
|
if (value != null) {
|
|
set$1(this, unit, value);
|
|
hooks.updateOffset(this, keepTime);
|
|
return this;
|
|
} else {
|
|
return get(this, unit);
|
|
}
|
|
};
|
|
}
|
|
function get(mom, unit) {
|
|
if (!mom.isValid()) {
|
|
return NaN;
|
|
}
|
|
var d2 = mom._d, isUTC = mom._isUTC;
|
|
switch (unit) {
|
|
case "Milliseconds":
|
|
return isUTC ? d2.getUTCMilliseconds() : d2.getMilliseconds();
|
|
case "Seconds":
|
|
return isUTC ? d2.getUTCSeconds() : d2.getSeconds();
|
|
case "Minutes":
|
|
return isUTC ? d2.getUTCMinutes() : d2.getMinutes();
|
|
case "Hours":
|
|
return isUTC ? d2.getUTCHours() : d2.getHours();
|
|
case "Date":
|
|
return isUTC ? d2.getUTCDate() : d2.getDate();
|
|
case "Day":
|
|
return isUTC ? d2.getUTCDay() : d2.getDay();
|
|
case "Month":
|
|
return isUTC ? d2.getUTCMonth() : d2.getMonth();
|
|
case "FullYear":
|
|
return isUTC ? d2.getUTCFullYear() : d2.getFullYear();
|
|
default:
|
|
return NaN;
|
|
}
|
|
}
|
|
function set$1(mom, unit, value) {
|
|
var d2, isUTC, year, month, date;
|
|
if (!mom.isValid() || isNaN(value)) {
|
|
return;
|
|
}
|
|
d2 = mom._d;
|
|
isUTC = mom._isUTC;
|
|
switch (unit) {
|
|
case "Milliseconds":
|
|
return void (isUTC ? d2.setUTCMilliseconds(value) : d2.setMilliseconds(value));
|
|
case "Seconds":
|
|
return void (isUTC ? d2.setUTCSeconds(value) : d2.setSeconds(value));
|
|
case "Minutes":
|
|
return void (isUTC ? d2.setUTCMinutes(value) : d2.setMinutes(value));
|
|
case "Hours":
|
|
return void (isUTC ? d2.setUTCHours(value) : d2.setHours(value));
|
|
case "Date":
|
|
return void (isUTC ? d2.setUTCDate(value) : d2.setDate(value));
|
|
// case 'Day': // Not real
|
|
// return void (isUTC ? d.setUTCDay(value) : d.setDay(value));
|
|
// case 'Month': // Not used because we need to pass two variables
|
|
// return void (isUTC ? d.setUTCMonth(value) : d.setMonth(value));
|
|
case "FullYear":
|
|
break;
|
|
// See below ...
|
|
default:
|
|
return;
|
|
}
|
|
year = value;
|
|
month = mom.month();
|
|
date = mom.date();
|
|
date = date === 29 && month === 1 && !isLeapYear(year) ? 28 : date;
|
|
void (isUTC ? d2.setUTCFullYear(year, month, date) : d2.setFullYear(year, month, date));
|
|
}
|
|
function stringGet(units) {
|
|
units = normalizeUnits(units);
|
|
if (isFunction2(this[units])) {
|
|
return this[units]();
|
|
}
|
|
return this;
|
|
}
|
|
function stringSet(units, value) {
|
|
if (typeof units === "object") {
|
|
units = normalizeObjectUnits(units);
|
|
var prioritized = getPrioritizedUnits(units), i2, prioritizedLen = prioritized.length;
|
|
for (i2 = 0; i2 < prioritizedLen; i2++) {
|
|
this[prioritized[i2].unit](units[prioritized[i2].unit]);
|
|
}
|
|
} else {
|
|
units = normalizeUnits(units);
|
|
if (isFunction2(this[units])) {
|
|
return this[units](value);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
function mod(n2, x2) {
|
|
return (n2 % x2 + x2) % x2;
|
|
}
|
|
var indexOf;
|
|
if (Array.prototype.indexOf) {
|
|
indexOf = Array.prototype.indexOf;
|
|
} else {
|
|
indexOf = function(o2) {
|
|
var i2;
|
|
for (i2 = 0; i2 < this.length; ++i2) {
|
|
if (this[i2] === o2) {
|
|
return i2;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
}
|
|
function daysInMonth(year, month) {
|
|
if (isNaN(year) || isNaN(month)) {
|
|
return NaN;
|
|
}
|
|
var modMonth = mod(month, 12);
|
|
year += (month - modMonth) / 12;
|
|
return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
|
|
}
|
|
addFormatToken("M", ["MM", 2], "Mo", function() {
|
|
return this.month() + 1;
|
|
});
|
|
addFormatToken("MMM", 0, 0, function(format2) {
|
|
return this.localeData().monthsShort(this, format2);
|
|
});
|
|
addFormatToken("MMMM", 0, 0, function(format2) {
|
|
return this.localeData().months(this, format2);
|
|
});
|
|
addRegexToken("M", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("MM", match1to2, match2);
|
|
addRegexToken("MMM", function(isStrict, locale3) {
|
|
return locale3.monthsShortRegex(isStrict);
|
|
});
|
|
addRegexToken("MMMM", function(isStrict, locale3) {
|
|
return locale3.monthsRegex(isStrict);
|
|
});
|
|
addParseToken(["M", "MM"], function(input, array) {
|
|
array[MONTH] = toInt(input) - 1;
|
|
});
|
|
addParseToken(["MMM", "MMMM"], function(input, array, config, token2) {
|
|
var month = config._locale.monthsParse(input, token2, config._strict);
|
|
if (month != null) {
|
|
array[MONTH] = month;
|
|
} else {
|
|
getParsingFlags(config).invalidMonth = input;
|
|
}
|
|
});
|
|
var defaultLocaleMonths = "January_February_March_April_May_June_July_August_September_October_November_December".split(
|
|
"_"
|
|
), defaultLocaleMonthsShort = "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, defaultMonthsShortRegex = matchWord, defaultMonthsRegex = matchWord;
|
|
function localeMonths(m2, format2) {
|
|
if (!m2) {
|
|
return isArray2(this._months) ? this._months : this._months["standalone"];
|
|
}
|
|
return isArray2(this._months) ? this._months[m2.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format2) ? "format" : "standalone"][m2.month()];
|
|
}
|
|
function localeMonthsShort(m2, format2) {
|
|
if (!m2) {
|
|
return isArray2(this._monthsShort) ? this._monthsShort : this._monthsShort["standalone"];
|
|
}
|
|
return isArray2(this._monthsShort) ? this._monthsShort[m2.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format2) ? "format" : "standalone"][m2.month()];
|
|
}
|
|
function handleStrictParse(monthName, format2, strict) {
|
|
var i2, ii, mom, llc = monthName.toLocaleLowerCase();
|
|
if (!this._monthsParse) {
|
|
this._monthsParse = [];
|
|
this._longMonthsParse = [];
|
|
this._shortMonthsParse = [];
|
|
for (i2 = 0; i2 < 12; ++i2) {
|
|
mom = createUTC([2e3, i2]);
|
|
this._shortMonthsParse[i2] = this.monthsShort(
|
|
mom,
|
|
""
|
|
).toLocaleLowerCase();
|
|
this._longMonthsParse[i2] = this.months(mom, "").toLocaleLowerCase();
|
|
}
|
|
}
|
|
if (strict) {
|
|
if (format2 === "MMM") {
|
|
ii = indexOf.call(this._shortMonthsParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else {
|
|
ii = indexOf.call(this._longMonthsParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
}
|
|
} else {
|
|
if (format2 === "MMM") {
|
|
ii = indexOf.call(this._shortMonthsParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._longMonthsParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else {
|
|
ii = indexOf.call(this._longMonthsParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._shortMonthsParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
}
|
|
}
|
|
}
|
|
function localeMonthsParse(monthName, format2, strict) {
|
|
var i2, mom, regex;
|
|
if (this._monthsParseExact) {
|
|
return handleStrictParse.call(this, monthName, format2, strict);
|
|
}
|
|
if (!this._monthsParse) {
|
|
this._monthsParse = [];
|
|
this._longMonthsParse = [];
|
|
this._shortMonthsParse = [];
|
|
}
|
|
for (i2 = 0; i2 < 12; i2++) {
|
|
mom = createUTC([2e3, i2]);
|
|
if (strict && !this._longMonthsParse[i2]) {
|
|
this._longMonthsParse[i2] = new RegExp(
|
|
"^" + this.months(mom, "").replace(".", "") + "$",
|
|
"i"
|
|
);
|
|
this._shortMonthsParse[i2] = new RegExp(
|
|
"^" + this.monthsShort(mom, "").replace(".", "") + "$",
|
|
"i"
|
|
);
|
|
}
|
|
if (!strict && !this._monthsParse[i2]) {
|
|
regex = "^" + this.months(mom, "") + "|^" + this.monthsShort(mom, "");
|
|
this._monthsParse[i2] = new RegExp(regex.replace(".", ""), "i");
|
|
}
|
|
if (strict && format2 === "MMMM" && this._longMonthsParse[i2].test(monthName)) {
|
|
return i2;
|
|
} else if (strict && format2 === "MMM" && this._shortMonthsParse[i2].test(monthName)) {
|
|
return i2;
|
|
} else if (!strict && this._monthsParse[i2].test(monthName)) {
|
|
return i2;
|
|
}
|
|
}
|
|
}
|
|
function setMonth(mom, value) {
|
|
if (!mom.isValid()) {
|
|
return mom;
|
|
}
|
|
if (typeof value === "string") {
|
|
if (/^\d+$/.test(value)) {
|
|
value = toInt(value);
|
|
} else {
|
|
value = mom.localeData().monthsParse(value);
|
|
if (!isNumber2(value)) {
|
|
return mom;
|
|
}
|
|
}
|
|
}
|
|
var month = value, date = mom.date();
|
|
date = date < 29 ? date : Math.min(date, daysInMonth(mom.year(), month));
|
|
void (mom._isUTC ? mom._d.setUTCMonth(month, date) : mom._d.setMonth(month, date));
|
|
return mom;
|
|
}
|
|
function getSetMonth(value) {
|
|
if (value != null) {
|
|
setMonth(this, value);
|
|
hooks.updateOffset(this, true);
|
|
return this;
|
|
} else {
|
|
return get(this, "Month");
|
|
}
|
|
}
|
|
function getDaysInMonth() {
|
|
return daysInMonth(this.year(), this.month());
|
|
}
|
|
function monthsShortRegex(isStrict) {
|
|
if (this._monthsParseExact) {
|
|
if (!hasOwnProp(this, "_monthsRegex")) {
|
|
computeMonthsParse.call(this);
|
|
}
|
|
if (isStrict) {
|
|
return this._monthsShortStrictRegex;
|
|
} else {
|
|
return this._monthsShortRegex;
|
|
}
|
|
} else {
|
|
if (!hasOwnProp(this, "_monthsShortRegex")) {
|
|
this._monthsShortRegex = defaultMonthsShortRegex;
|
|
}
|
|
return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
|
|
}
|
|
}
|
|
function monthsRegex(isStrict) {
|
|
if (this._monthsParseExact) {
|
|
if (!hasOwnProp(this, "_monthsRegex")) {
|
|
computeMonthsParse.call(this);
|
|
}
|
|
if (isStrict) {
|
|
return this._monthsStrictRegex;
|
|
} else {
|
|
return this._monthsRegex;
|
|
}
|
|
} else {
|
|
if (!hasOwnProp(this, "_monthsRegex")) {
|
|
this._monthsRegex = defaultMonthsRegex;
|
|
}
|
|
return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
|
|
}
|
|
}
|
|
function computeMonthsParse() {
|
|
function cmpLenRev(a2, b2) {
|
|
return b2.length - a2.length;
|
|
}
|
|
var shortPieces = [], longPieces = [], mixedPieces = [], i2, mom, shortP, longP;
|
|
for (i2 = 0; i2 < 12; i2++) {
|
|
mom = createUTC([2e3, i2]);
|
|
shortP = regexEscape(this.monthsShort(mom, ""));
|
|
longP = regexEscape(this.months(mom, ""));
|
|
shortPieces.push(shortP);
|
|
longPieces.push(longP);
|
|
mixedPieces.push(longP);
|
|
mixedPieces.push(shortP);
|
|
}
|
|
shortPieces.sort(cmpLenRev);
|
|
longPieces.sort(cmpLenRev);
|
|
mixedPieces.sort(cmpLenRev);
|
|
this._monthsRegex = new RegExp("^(" + mixedPieces.join("|") + ")", "i");
|
|
this._monthsShortRegex = this._monthsRegex;
|
|
this._monthsStrictRegex = new RegExp(
|
|
"^(" + longPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
this._monthsShortStrictRegex = new RegExp(
|
|
"^(" + shortPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
}
|
|
function createDate(y2, m2, d2, h6, M2, s2, ms) {
|
|
var date;
|
|
if (y2 < 100 && y2 >= 0) {
|
|
date = new Date(y2 + 400, m2, d2, h6, M2, s2, ms);
|
|
if (isFinite(date.getFullYear())) {
|
|
date.setFullYear(y2);
|
|
}
|
|
} else {
|
|
date = new Date(y2, m2, d2, h6, M2, s2, ms);
|
|
}
|
|
return date;
|
|
}
|
|
function createUTCDate(y2) {
|
|
var date, args;
|
|
if (y2 < 100 && y2 >= 0) {
|
|
args = Array.prototype.slice.call(arguments);
|
|
args[0] = y2 + 400;
|
|
date = new Date(Date.UTC.apply(null, args));
|
|
if (isFinite(date.getUTCFullYear())) {
|
|
date.setUTCFullYear(y2);
|
|
}
|
|
} else {
|
|
date = new Date(Date.UTC.apply(null, arguments));
|
|
}
|
|
return date;
|
|
}
|
|
function firstWeekOffset(year, dow, doy) {
|
|
var fwd = 7 + dow - doy, fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
|
|
return -fwdlw + fwd - 1;
|
|
}
|
|
function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
|
|
var localWeekday = (7 + weekday - dow) % 7, weekOffset = firstWeekOffset(year, dow, doy), dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, resYear, resDayOfYear;
|
|
if (dayOfYear <= 0) {
|
|
resYear = year - 1;
|
|
resDayOfYear = daysInYear(resYear) + dayOfYear;
|
|
} else if (dayOfYear > daysInYear(year)) {
|
|
resYear = year + 1;
|
|
resDayOfYear = dayOfYear - daysInYear(year);
|
|
} else {
|
|
resYear = year;
|
|
resDayOfYear = dayOfYear;
|
|
}
|
|
return {
|
|
year: resYear,
|
|
dayOfYear: resDayOfYear
|
|
};
|
|
}
|
|
function weekOfYear(mom, dow, doy) {
|
|
var weekOffset = firstWeekOffset(mom.year(), dow, doy), week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, resWeek, resYear;
|
|
if (week < 1) {
|
|
resYear = mom.year() - 1;
|
|
resWeek = week + weeksInYear(resYear, dow, doy);
|
|
} else if (week > weeksInYear(mom.year(), dow, doy)) {
|
|
resWeek = week - weeksInYear(mom.year(), dow, doy);
|
|
resYear = mom.year() + 1;
|
|
} else {
|
|
resYear = mom.year();
|
|
resWeek = week;
|
|
}
|
|
return {
|
|
week: resWeek,
|
|
year: resYear
|
|
};
|
|
}
|
|
function weeksInYear(year, dow, doy) {
|
|
var weekOffset = firstWeekOffset(year, dow, doy), weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
|
|
return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
|
|
}
|
|
addFormatToken("w", ["ww", 2], "wo", "week");
|
|
addFormatToken("W", ["WW", 2], "Wo", "isoWeek");
|
|
addRegexToken("w", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("ww", match1to2, match2);
|
|
addRegexToken("W", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("WW", match1to2, match2);
|
|
addWeekParseToken(
|
|
["w", "ww", "W", "WW"],
|
|
function(input, week, config, token2) {
|
|
week[token2.substr(0, 1)] = toInt(input);
|
|
}
|
|
);
|
|
function localeWeek(mom) {
|
|
return weekOfYear(mom, this._week.dow, this._week.doy).week;
|
|
}
|
|
var defaultLocaleWeek = {
|
|
dow: 0,
|
|
// Sunday is the first day of the week.
|
|
doy: 6
|
|
// The week that contains Jan 6th is the first week of the year.
|
|
};
|
|
function localeFirstDayOfWeek() {
|
|
return this._week.dow;
|
|
}
|
|
function localeFirstDayOfYear() {
|
|
return this._week.doy;
|
|
}
|
|
function getSetWeek(input) {
|
|
var week = this.localeData().week(this);
|
|
return input == null ? week : this.add((input - week) * 7, "d");
|
|
}
|
|
function getSetISOWeek(input) {
|
|
var week = weekOfYear(this, 1, 4).week;
|
|
return input == null ? week : this.add((input - week) * 7, "d");
|
|
}
|
|
addFormatToken("d", 0, "do", "day");
|
|
addFormatToken("dd", 0, 0, function(format2) {
|
|
return this.localeData().weekdaysMin(this, format2);
|
|
});
|
|
addFormatToken("ddd", 0, 0, function(format2) {
|
|
return this.localeData().weekdaysShort(this, format2);
|
|
});
|
|
addFormatToken("dddd", 0, 0, function(format2) {
|
|
return this.localeData().weekdays(this, format2);
|
|
});
|
|
addFormatToken("e", 0, 0, "weekday");
|
|
addFormatToken("E", 0, 0, "isoWeekday");
|
|
addRegexToken("d", match1to2);
|
|
addRegexToken("e", match1to2);
|
|
addRegexToken("E", match1to2);
|
|
addRegexToken("dd", function(isStrict, locale3) {
|
|
return locale3.weekdaysMinRegex(isStrict);
|
|
});
|
|
addRegexToken("ddd", function(isStrict, locale3) {
|
|
return locale3.weekdaysShortRegex(isStrict);
|
|
});
|
|
addRegexToken("dddd", function(isStrict, locale3) {
|
|
return locale3.weekdaysRegex(isStrict);
|
|
});
|
|
addWeekParseToken(["dd", "ddd", "dddd"], function(input, week, config, token2) {
|
|
var weekday = config._locale.weekdaysParse(input, token2, config._strict);
|
|
if (weekday != null) {
|
|
week.d = weekday;
|
|
} else {
|
|
getParsingFlags(config).invalidWeekday = input;
|
|
}
|
|
});
|
|
addWeekParseToken(["d", "e", "E"], function(input, week, config, token2) {
|
|
week[token2] = toInt(input);
|
|
});
|
|
function parseWeekday(input, locale3) {
|
|
if (typeof input !== "string") {
|
|
return input;
|
|
}
|
|
if (!isNaN(input)) {
|
|
return parseInt(input, 10);
|
|
}
|
|
input = locale3.weekdaysParse(input);
|
|
if (typeof input === "number") {
|
|
return input;
|
|
}
|
|
return null;
|
|
}
|
|
function parseIsoWeekday(input, locale3) {
|
|
if (typeof input === "string") {
|
|
return locale3.weekdaysParse(input) % 7 || 7;
|
|
}
|
|
return isNaN(input) ? null : input;
|
|
}
|
|
function shiftWeekdays(ws, n2) {
|
|
return ws.slice(n2, 7).concat(ws.slice(0, n2));
|
|
}
|
|
var defaultLocaleWeekdays = "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), defaultLocaleWeekdaysShort = "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), defaultLocaleWeekdaysMin = "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), defaultWeekdaysRegex = matchWord, defaultWeekdaysShortRegex = matchWord, defaultWeekdaysMinRegex = matchWord;
|
|
function localeWeekdays(m2, format2) {
|
|
var weekdays = isArray2(this._weekdays) ? this._weekdays : this._weekdays[m2 && m2 !== true && this._weekdays.isFormat.test(format2) ? "format" : "standalone"];
|
|
return m2 === true ? shiftWeekdays(weekdays, this._week.dow) : m2 ? weekdays[m2.day()] : weekdays;
|
|
}
|
|
function localeWeekdaysShort(m2) {
|
|
return m2 === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m2 ? this._weekdaysShort[m2.day()] : this._weekdaysShort;
|
|
}
|
|
function localeWeekdaysMin(m2) {
|
|
return m2 === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m2 ? this._weekdaysMin[m2.day()] : this._weekdaysMin;
|
|
}
|
|
function handleStrictParse$1(weekdayName, format2, strict) {
|
|
var i2, ii, mom, llc = weekdayName.toLocaleLowerCase();
|
|
if (!this._weekdaysParse) {
|
|
this._weekdaysParse = [];
|
|
this._shortWeekdaysParse = [];
|
|
this._minWeekdaysParse = [];
|
|
for (i2 = 0; i2 < 7; ++i2) {
|
|
mom = createUTC([2e3, 1]).day(i2);
|
|
this._minWeekdaysParse[i2] = this.weekdaysMin(
|
|
mom,
|
|
""
|
|
).toLocaleLowerCase();
|
|
this._shortWeekdaysParse[i2] = this.weekdaysShort(
|
|
mom,
|
|
""
|
|
).toLocaleLowerCase();
|
|
this._weekdaysParse[i2] = this.weekdays(mom, "").toLocaleLowerCase();
|
|
}
|
|
}
|
|
if (strict) {
|
|
if (format2 === "dddd") {
|
|
ii = indexOf.call(this._weekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else if (format2 === "ddd") {
|
|
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else {
|
|
ii = indexOf.call(this._minWeekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
}
|
|
} else {
|
|
if (format2 === "dddd") {
|
|
ii = indexOf.call(this._weekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._minWeekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else if (format2 === "ddd") {
|
|
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._weekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._minWeekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
} else {
|
|
ii = indexOf.call(this._minWeekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._weekdaysParse, llc);
|
|
if (ii !== -1) {
|
|
return ii;
|
|
}
|
|
ii = indexOf.call(this._shortWeekdaysParse, llc);
|
|
return ii !== -1 ? ii : null;
|
|
}
|
|
}
|
|
}
|
|
function localeWeekdaysParse(weekdayName, format2, strict) {
|
|
var i2, mom, regex;
|
|
if (this._weekdaysParseExact) {
|
|
return handleStrictParse$1.call(this, weekdayName, format2, strict);
|
|
}
|
|
if (!this._weekdaysParse) {
|
|
this._weekdaysParse = [];
|
|
this._minWeekdaysParse = [];
|
|
this._shortWeekdaysParse = [];
|
|
this._fullWeekdaysParse = [];
|
|
}
|
|
for (i2 = 0; i2 < 7; i2++) {
|
|
mom = createUTC([2e3, 1]).day(i2);
|
|
if (strict && !this._fullWeekdaysParse[i2]) {
|
|
this._fullWeekdaysParse[i2] = new RegExp(
|
|
"^" + this.weekdays(mom, "").replace(".", "\\.?") + "$",
|
|
"i"
|
|
);
|
|
this._shortWeekdaysParse[i2] = new RegExp(
|
|
"^" + this.weekdaysShort(mom, "").replace(".", "\\.?") + "$",
|
|
"i"
|
|
);
|
|
this._minWeekdaysParse[i2] = new RegExp(
|
|
"^" + this.weekdaysMin(mom, "").replace(".", "\\.?") + "$",
|
|
"i"
|
|
);
|
|
}
|
|
if (!this._weekdaysParse[i2]) {
|
|
regex = "^" + this.weekdays(mom, "") + "|^" + this.weekdaysShort(mom, "") + "|^" + this.weekdaysMin(mom, "");
|
|
this._weekdaysParse[i2] = new RegExp(regex.replace(".", ""), "i");
|
|
}
|
|
if (strict && format2 === "dddd" && this._fullWeekdaysParse[i2].test(weekdayName)) {
|
|
return i2;
|
|
} else if (strict && format2 === "ddd" && this._shortWeekdaysParse[i2].test(weekdayName)) {
|
|
return i2;
|
|
} else if (strict && format2 === "dd" && this._minWeekdaysParse[i2].test(weekdayName)) {
|
|
return i2;
|
|
} else if (!strict && this._weekdaysParse[i2].test(weekdayName)) {
|
|
return i2;
|
|
}
|
|
}
|
|
}
|
|
function getSetDayOfWeek(input) {
|
|
if (!this.isValid()) {
|
|
return input != null ? this : NaN;
|
|
}
|
|
var day = get(this, "Day");
|
|
if (input != null) {
|
|
input = parseWeekday(input, this.localeData());
|
|
return this.add(input - day, "d");
|
|
} else {
|
|
return day;
|
|
}
|
|
}
|
|
function getSetLocaleDayOfWeek(input) {
|
|
if (!this.isValid()) {
|
|
return input != null ? this : NaN;
|
|
}
|
|
var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
|
|
return input == null ? weekday : this.add(input - weekday, "d");
|
|
}
|
|
function getSetISODayOfWeek(input) {
|
|
if (!this.isValid()) {
|
|
return input != null ? this : NaN;
|
|
}
|
|
if (input != null) {
|
|
var weekday = parseIsoWeekday(input, this.localeData());
|
|
return this.day(this.day() % 7 ? weekday : weekday - 7);
|
|
} else {
|
|
return this.day() || 7;
|
|
}
|
|
}
|
|
function weekdaysRegex(isStrict) {
|
|
if (this._weekdaysParseExact) {
|
|
if (!hasOwnProp(this, "_weekdaysRegex")) {
|
|
computeWeekdaysParse.call(this);
|
|
}
|
|
if (isStrict) {
|
|
return this._weekdaysStrictRegex;
|
|
} else {
|
|
return this._weekdaysRegex;
|
|
}
|
|
} else {
|
|
if (!hasOwnProp(this, "_weekdaysRegex")) {
|
|
this._weekdaysRegex = defaultWeekdaysRegex;
|
|
}
|
|
return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
|
|
}
|
|
}
|
|
function weekdaysShortRegex(isStrict) {
|
|
if (this._weekdaysParseExact) {
|
|
if (!hasOwnProp(this, "_weekdaysRegex")) {
|
|
computeWeekdaysParse.call(this);
|
|
}
|
|
if (isStrict) {
|
|
return this._weekdaysShortStrictRegex;
|
|
} else {
|
|
return this._weekdaysShortRegex;
|
|
}
|
|
} else {
|
|
if (!hasOwnProp(this, "_weekdaysShortRegex")) {
|
|
this._weekdaysShortRegex = defaultWeekdaysShortRegex;
|
|
}
|
|
return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
|
|
}
|
|
}
|
|
function weekdaysMinRegex(isStrict) {
|
|
if (this._weekdaysParseExact) {
|
|
if (!hasOwnProp(this, "_weekdaysRegex")) {
|
|
computeWeekdaysParse.call(this);
|
|
}
|
|
if (isStrict) {
|
|
return this._weekdaysMinStrictRegex;
|
|
} else {
|
|
return this._weekdaysMinRegex;
|
|
}
|
|
} else {
|
|
if (!hasOwnProp(this, "_weekdaysMinRegex")) {
|
|
this._weekdaysMinRegex = defaultWeekdaysMinRegex;
|
|
}
|
|
return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
|
|
}
|
|
}
|
|
function computeWeekdaysParse() {
|
|
function cmpLenRev(a2, b2) {
|
|
return b2.length - a2.length;
|
|
}
|
|
var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [], i2, mom, minp, shortp, longp;
|
|
for (i2 = 0; i2 < 7; i2++) {
|
|
mom = createUTC([2e3, 1]).day(i2);
|
|
minp = regexEscape(this.weekdaysMin(mom, ""));
|
|
shortp = regexEscape(this.weekdaysShort(mom, ""));
|
|
longp = regexEscape(this.weekdays(mom, ""));
|
|
minPieces.push(minp);
|
|
shortPieces.push(shortp);
|
|
longPieces.push(longp);
|
|
mixedPieces.push(minp);
|
|
mixedPieces.push(shortp);
|
|
mixedPieces.push(longp);
|
|
}
|
|
minPieces.sort(cmpLenRev);
|
|
shortPieces.sort(cmpLenRev);
|
|
longPieces.sort(cmpLenRev);
|
|
mixedPieces.sort(cmpLenRev);
|
|
this._weekdaysRegex = new RegExp("^(" + mixedPieces.join("|") + ")", "i");
|
|
this._weekdaysShortRegex = this._weekdaysRegex;
|
|
this._weekdaysMinRegex = this._weekdaysRegex;
|
|
this._weekdaysStrictRegex = new RegExp(
|
|
"^(" + longPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
this._weekdaysShortStrictRegex = new RegExp(
|
|
"^(" + shortPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
this._weekdaysMinStrictRegex = new RegExp(
|
|
"^(" + minPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
}
|
|
function hFormat() {
|
|
return this.hours() % 12 || 12;
|
|
}
|
|
function kFormat() {
|
|
return this.hours() || 24;
|
|
}
|
|
addFormatToken("H", ["HH", 2], 0, "hour");
|
|
addFormatToken("h", ["hh", 2], 0, hFormat);
|
|
addFormatToken("k", ["kk", 2], 0, kFormat);
|
|
addFormatToken("hmm", 0, 0, function() {
|
|
return "" + hFormat.apply(this) + zeroFill(this.minutes(), 2);
|
|
});
|
|
addFormatToken("hmmss", 0, 0, function() {
|
|
return "" + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
|
|
});
|
|
addFormatToken("Hmm", 0, 0, function() {
|
|
return "" + this.hours() + zeroFill(this.minutes(), 2);
|
|
});
|
|
addFormatToken("Hmmss", 0, 0, function() {
|
|
return "" + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
|
|
});
|
|
function meridiem(token2, lowercase) {
|
|
addFormatToken(token2, 0, 0, function() {
|
|
return this.localeData().meridiem(
|
|
this.hours(),
|
|
this.minutes(),
|
|
lowercase
|
|
);
|
|
});
|
|
}
|
|
meridiem("a", true);
|
|
meridiem("A", false);
|
|
function matchMeridiem(isStrict, locale3) {
|
|
return locale3._meridiemParse;
|
|
}
|
|
addRegexToken("a", matchMeridiem);
|
|
addRegexToken("A", matchMeridiem);
|
|
addRegexToken("H", match1to2, match1to2HasZero);
|
|
addRegexToken("h", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("k", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("HH", match1to2, match2);
|
|
addRegexToken("hh", match1to2, match2);
|
|
addRegexToken("kk", match1to2, match2);
|
|
addRegexToken("hmm", match3to4);
|
|
addRegexToken("hmmss", match5to6);
|
|
addRegexToken("Hmm", match3to4);
|
|
addRegexToken("Hmmss", match5to6);
|
|
addParseToken(["H", "HH"], HOUR);
|
|
addParseToken(["k", "kk"], function(input, array, config) {
|
|
var kInput = toInt(input);
|
|
array[HOUR] = kInput === 24 ? 0 : kInput;
|
|
});
|
|
addParseToken(["a", "A"], function(input, array, config) {
|
|
config._isPm = config._locale.isPM(input);
|
|
config._meridiem = input;
|
|
});
|
|
addParseToken(["h", "hh"], function(input, array, config) {
|
|
array[HOUR] = toInt(input);
|
|
getParsingFlags(config).bigHour = true;
|
|
});
|
|
addParseToken("hmm", function(input, array, config) {
|
|
var pos = input.length - 2;
|
|
array[HOUR] = toInt(input.substr(0, pos));
|
|
array[MINUTE] = toInt(input.substr(pos));
|
|
getParsingFlags(config).bigHour = true;
|
|
});
|
|
addParseToken("hmmss", function(input, array, config) {
|
|
var pos1 = input.length - 4, pos2 = input.length - 2;
|
|
array[HOUR] = toInt(input.substr(0, pos1));
|
|
array[MINUTE] = toInt(input.substr(pos1, 2));
|
|
array[SECOND] = toInt(input.substr(pos2));
|
|
getParsingFlags(config).bigHour = true;
|
|
});
|
|
addParseToken("Hmm", function(input, array, config) {
|
|
var pos = input.length - 2;
|
|
array[HOUR] = toInt(input.substr(0, pos));
|
|
array[MINUTE] = toInt(input.substr(pos));
|
|
});
|
|
addParseToken("Hmmss", function(input, array, config) {
|
|
var pos1 = input.length - 4, pos2 = input.length - 2;
|
|
array[HOUR] = toInt(input.substr(0, pos1));
|
|
array[MINUTE] = toInt(input.substr(pos1, 2));
|
|
array[SECOND] = toInt(input.substr(pos2));
|
|
});
|
|
function localeIsPM(input) {
|
|
return (input + "").toLowerCase().charAt(0) === "p";
|
|
}
|
|
var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, getSetHour = makeGetSet("Hours", true);
|
|
function localeMeridiem(hours2, minutes2, isLower) {
|
|
if (hours2 > 11) {
|
|
return isLower ? "pm" : "PM";
|
|
} else {
|
|
return isLower ? "am" : "AM";
|
|
}
|
|
}
|
|
var baseConfig = {
|
|
calendar: defaultCalendar,
|
|
longDateFormat: defaultLongDateFormat,
|
|
invalidDate: defaultInvalidDate,
|
|
ordinal: defaultOrdinal,
|
|
dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
|
|
relativeTime: defaultRelativeTime,
|
|
months: defaultLocaleMonths,
|
|
monthsShort: defaultLocaleMonthsShort,
|
|
week: defaultLocaleWeek,
|
|
weekdays: defaultLocaleWeekdays,
|
|
weekdaysMin: defaultLocaleWeekdaysMin,
|
|
weekdaysShort: defaultLocaleWeekdaysShort,
|
|
meridiemParse: defaultLocaleMeridiemParse
|
|
};
|
|
var locales = {}, localeFamilies = {}, globalLocale;
|
|
function commonPrefix(arr1, arr2) {
|
|
var i2, minl = Math.min(arr1.length, arr2.length);
|
|
for (i2 = 0; i2 < minl; i2 += 1) {
|
|
if (arr1[i2] !== arr2[i2]) {
|
|
return i2;
|
|
}
|
|
}
|
|
return minl;
|
|
}
|
|
function normalizeLocale(key) {
|
|
return key ? key.toLowerCase().replace("_", "-") : key;
|
|
}
|
|
function chooseLocale(names2) {
|
|
var i2 = 0, j2, next, locale3, split;
|
|
while (i2 < names2.length) {
|
|
split = normalizeLocale(names2[i2]).split("-");
|
|
j2 = split.length;
|
|
next = normalizeLocale(names2[i2 + 1]);
|
|
next = next ? next.split("-") : null;
|
|
while (j2 > 0) {
|
|
locale3 = loadLocale(split.slice(0, j2).join("-"));
|
|
if (locale3) {
|
|
return locale3;
|
|
}
|
|
if (next && next.length >= j2 && commonPrefix(split, next) >= j2 - 1) {
|
|
break;
|
|
}
|
|
j2--;
|
|
}
|
|
i2++;
|
|
}
|
|
return globalLocale;
|
|
}
|
|
function isLocaleNameSane(name) {
|
|
return !!(name && name.match("^[^/\\\\]*$"));
|
|
}
|
|
function loadLocale(name) {
|
|
var oldLocale = null, aliasedRequire;
|
|
if (locales[name] === void 0 && typeof module2 !== "undefined" && module2 && module2.exports && isLocaleNameSane(name)) {
|
|
try {
|
|
oldLocale = globalLocale._abbr;
|
|
aliasedRequire = require;
|
|
aliasedRequire("./locale/" + name);
|
|
getSetGlobalLocale(oldLocale);
|
|
} catch (e2) {
|
|
locales[name] = null;
|
|
}
|
|
}
|
|
return locales[name];
|
|
}
|
|
function getSetGlobalLocale(key, values) {
|
|
var data;
|
|
if (key) {
|
|
if (isUndefined(values)) {
|
|
data = getLocale(key);
|
|
} else {
|
|
data = defineLocale(key, values);
|
|
}
|
|
if (data) {
|
|
globalLocale = data;
|
|
} else {
|
|
if (typeof console !== "undefined" && console.warn) {
|
|
console.warn(
|
|
"Locale " + key + " not found. Did you forget to load it?"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
return globalLocale._abbr;
|
|
}
|
|
function defineLocale(name, config) {
|
|
if (config !== null) {
|
|
var locale3, parentConfig = baseConfig;
|
|
config.abbr = name;
|
|
if (locales[name] != null) {
|
|
deprecateSimple(
|
|
"defineLocaleOverride",
|
|
"use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."
|
|
);
|
|
parentConfig = locales[name]._config;
|
|
} else if (config.parentLocale != null) {
|
|
if (locales[config.parentLocale] != null) {
|
|
parentConfig = locales[config.parentLocale]._config;
|
|
} else {
|
|
locale3 = loadLocale(config.parentLocale);
|
|
if (locale3 != null) {
|
|
parentConfig = locale3._config;
|
|
} else {
|
|
if (!localeFamilies[config.parentLocale]) {
|
|
localeFamilies[config.parentLocale] = [];
|
|
}
|
|
localeFamilies[config.parentLocale].push({
|
|
name,
|
|
config
|
|
});
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
locales[name] = new Locale(mergeConfigs(parentConfig, config));
|
|
if (localeFamilies[name]) {
|
|
localeFamilies[name].forEach(function(x2) {
|
|
defineLocale(x2.name, x2.config);
|
|
});
|
|
}
|
|
getSetGlobalLocale(name);
|
|
return locales[name];
|
|
} else {
|
|
delete locales[name];
|
|
return null;
|
|
}
|
|
}
|
|
function updateLocale(name, config) {
|
|
if (config != null) {
|
|
var locale3, tmpLocale, parentConfig = baseConfig;
|
|
if (locales[name] != null && locales[name].parentLocale != null) {
|
|
locales[name].set(mergeConfigs(locales[name]._config, config));
|
|
} else {
|
|
tmpLocale = loadLocale(name);
|
|
if (tmpLocale != null) {
|
|
parentConfig = tmpLocale._config;
|
|
}
|
|
config = mergeConfigs(parentConfig, config);
|
|
if (tmpLocale == null) {
|
|
config.abbr = name;
|
|
}
|
|
locale3 = new Locale(config);
|
|
locale3.parentLocale = locales[name];
|
|
locales[name] = locale3;
|
|
}
|
|
getSetGlobalLocale(name);
|
|
} else {
|
|
if (locales[name] != null) {
|
|
if (locales[name].parentLocale != null) {
|
|
locales[name] = locales[name].parentLocale;
|
|
if (name === getSetGlobalLocale()) {
|
|
getSetGlobalLocale(name);
|
|
}
|
|
} else if (locales[name] != null) {
|
|
delete locales[name];
|
|
}
|
|
}
|
|
}
|
|
return locales[name];
|
|
}
|
|
function getLocale(key) {
|
|
var locale3;
|
|
if (key && key._locale && key._locale._abbr) {
|
|
key = key._locale._abbr;
|
|
}
|
|
if (!key) {
|
|
return globalLocale;
|
|
}
|
|
if (!isArray2(key)) {
|
|
locale3 = loadLocale(key);
|
|
if (locale3) {
|
|
return locale3;
|
|
}
|
|
key = [key];
|
|
}
|
|
return chooseLocale(key);
|
|
}
|
|
function listLocales() {
|
|
return keys(locales);
|
|
}
|
|
function checkOverflow(m2) {
|
|
var overflow, a2 = m2._a;
|
|
if (a2 && getParsingFlags(m2).overflow === -2) {
|
|
overflow = a2[MONTH] < 0 || a2[MONTH] > 11 ? MONTH : a2[DATE] < 1 || a2[DATE] > daysInMonth(a2[YEAR], a2[MONTH]) ? DATE : a2[HOUR] < 0 || a2[HOUR] > 24 || a2[HOUR] === 24 && (a2[MINUTE] !== 0 || a2[SECOND] !== 0 || a2[MILLISECOND] !== 0) ? HOUR : a2[MINUTE] < 0 || a2[MINUTE] > 59 ? MINUTE : a2[SECOND] < 0 || a2[SECOND] > 59 ? SECOND : a2[MILLISECOND] < 0 || a2[MILLISECOND] > 999 ? MILLISECOND : -1;
|
|
if (getParsingFlags(m2)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
|
|
overflow = DATE;
|
|
}
|
|
if (getParsingFlags(m2)._overflowWeeks && overflow === -1) {
|
|
overflow = WEEK;
|
|
}
|
|
if (getParsingFlags(m2)._overflowWeekday && overflow === -1) {
|
|
overflow = WEEKDAY;
|
|
}
|
|
getParsingFlags(m2).overflow = overflow;
|
|
}
|
|
return m2;
|
|
}
|
|
var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, isoDates = [
|
|
["YYYYYY-MM-DD", /[+-]\d{6}-\d\d-\d\d/],
|
|
["YYYY-MM-DD", /\d{4}-\d\d-\d\d/],
|
|
["GGGG-[W]WW-E", /\d{4}-W\d\d-\d/],
|
|
["GGGG-[W]WW", /\d{4}-W\d\d/, false],
|
|
["YYYY-DDD", /\d{4}-\d{3}/],
|
|
["YYYY-MM", /\d{4}-\d\d/, false],
|
|
["YYYYYYMMDD", /[+-]\d{10}/],
|
|
["YYYYMMDD", /\d{8}/],
|
|
["GGGG[W]WWE", /\d{4}W\d{3}/],
|
|
["GGGG[W]WW", /\d{4}W\d{2}/, false],
|
|
["YYYYDDD", /\d{7}/],
|
|
["YYYYMM", /\d{6}/, false],
|
|
["YYYY", /\d{4}/, false]
|
|
], isoTimes = [
|
|
["HH:mm:ss.SSSS", /\d\d:\d\d:\d\d\.\d+/],
|
|
["HH:mm:ss,SSSS", /\d\d:\d\d:\d\d,\d+/],
|
|
["HH:mm:ss", /\d\d:\d\d:\d\d/],
|
|
["HH:mm", /\d\d:\d\d/],
|
|
["HHmmss.SSSS", /\d\d\d\d\d\d\.\d+/],
|
|
["HHmmss,SSSS", /\d\d\d\d\d\d,\d+/],
|
|
["HHmmss", /\d\d\d\d\d\d/],
|
|
["HHmm", /\d\d\d\d/],
|
|
["HH", /\d\d/]
|
|
], aspNetJsonRegex = /^\/?Date\((-?\d+)/i, rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, obsOffsets = {
|
|
UT: 0,
|
|
GMT: 0,
|
|
EDT: -4 * 60,
|
|
EST: -5 * 60,
|
|
CDT: -5 * 60,
|
|
CST: -6 * 60,
|
|
MDT: -6 * 60,
|
|
MST: -7 * 60,
|
|
PDT: -7 * 60,
|
|
PST: -8 * 60
|
|
};
|
|
function configFromISO(config) {
|
|
var i2, l2, string = config._i, match5 = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), allowTime, dateFormat, timeFormat, tzFormat, isoDatesLen = isoDates.length, isoTimesLen = isoTimes.length;
|
|
if (match5) {
|
|
getParsingFlags(config).iso = true;
|
|
for (i2 = 0, l2 = isoDatesLen; i2 < l2; i2++) {
|
|
if (isoDates[i2][1].exec(match5[1])) {
|
|
dateFormat = isoDates[i2][0];
|
|
allowTime = isoDates[i2][2] !== false;
|
|
break;
|
|
}
|
|
}
|
|
if (dateFormat == null) {
|
|
config._isValid = false;
|
|
return;
|
|
}
|
|
if (match5[3]) {
|
|
for (i2 = 0, l2 = isoTimesLen; i2 < l2; i2++) {
|
|
if (isoTimes[i2][1].exec(match5[3])) {
|
|
timeFormat = (match5[2] || " ") + isoTimes[i2][0];
|
|
break;
|
|
}
|
|
}
|
|
if (timeFormat == null) {
|
|
config._isValid = false;
|
|
return;
|
|
}
|
|
}
|
|
if (!allowTime && timeFormat != null) {
|
|
config._isValid = false;
|
|
return;
|
|
}
|
|
if (match5[4]) {
|
|
if (tzRegex.exec(match5[4])) {
|
|
tzFormat = "Z";
|
|
} else {
|
|
config._isValid = false;
|
|
return;
|
|
}
|
|
}
|
|
config._f = dateFormat + (timeFormat || "") + (tzFormat || "");
|
|
configFromStringAndFormat(config);
|
|
} else {
|
|
config._isValid = false;
|
|
}
|
|
}
|
|
function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
|
|
var result = [
|
|
untruncateYear(yearStr),
|
|
defaultLocaleMonthsShort.indexOf(monthStr),
|
|
parseInt(dayStr, 10),
|
|
parseInt(hourStr, 10),
|
|
parseInt(minuteStr, 10)
|
|
];
|
|
if (secondStr) {
|
|
result.push(parseInt(secondStr, 10));
|
|
}
|
|
return result;
|
|
}
|
|
function untruncateYear(yearStr) {
|
|
var year = parseInt(yearStr, 10);
|
|
if (year <= 49) {
|
|
return 2e3 + year;
|
|
} else if (year <= 999) {
|
|
return 1900 + year;
|
|
}
|
|
return year;
|
|
}
|
|
function preprocessRFC2822(s2) {
|
|
return s2.replace(/\([^()]*\)|[\n\t]/g, " ").replace(/(\s\s+)/g, " ").replace(/^\s\s*/, "").replace(/\s\s*$/, "");
|
|
}
|
|
function checkWeekday(weekdayStr, parsedInput, config) {
|
|
if (weekdayStr) {
|
|
var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), weekdayActual = new Date(
|
|
parsedInput[0],
|
|
parsedInput[1],
|
|
parsedInput[2]
|
|
).getDay();
|
|
if (weekdayProvided !== weekdayActual) {
|
|
getParsingFlags(config).weekdayMismatch = true;
|
|
config._isValid = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function calculateOffset(obsOffset, militaryOffset, numOffset) {
|
|
if (obsOffset) {
|
|
return obsOffsets[obsOffset];
|
|
} else if (militaryOffset) {
|
|
return 0;
|
|
} else {
|
|
var hm = parseInt(numOffset, 10), m2 = hm % 100, h6 = (hm - m2) / 100;
|
|
return h6 * 60 + m2;
|
|
}
|
|
}
|
|
function configFromRFC2822(config) {
|
|
var match5 = rfc2822.exec(preprocessRFC2822(config._i)), parsedArray;
|
|
if (match5) {
|
|
parsedArray = extractFromRFC2822Strings(
|
|
match5[4],
|
|
match5[3],
|
|
match5[2],
|
|
match5[5],
|
|
match5[6],
|
|
match5[7]
|
|
);
|
|
if (!checkWeekday(match5[1], parsedArray, config)) {
|
|
return;
|
|
}
|
|
config._a = parsedArray;
|
|
config._tzm = calculateOffset(match5[8], match5[9], match5[10]);
|
|
config._d = createUTCDate.apply(null, config._a);
|
|
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
|
|
getParsingFlags(config).rfc2822 = true;
|
|
} else {
|
|
config._isValid = false;
|
|
}
|
|
}
|
|
function configFromString(config) {
|
|
var matched = aspNetJsonRegex.exec(config._i);
|
|
if (matched !== null) {
|
|
config._d = /* @__PURE__ */ new Date(+matched[1]);
|
|
return;
|
|
}
|
|
configFromISO(config);
|
|
if (config._isValid === false) {
|
|
delete config._isValid;
|
|
} else {
|
|
return;
|
|
}
|
|
configFromRFC2822(config);
|
|
if (config._isValid === false) {
|
|
delete config._isValid;
|
|
} else {
|
|
return;
|
|
}
|
|
if (config._strict) {
|
|
config._isValid = false;
|
|
} else {
|
|
hooks.createFromInputFallback(config);
|
|
}
|
|
}
|
|
hooks.createFromInputFallback = deprecate(
|
|
"value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",
|
|
function(config) {
|
|
config._d = /* @__PURE__ */ new Date(config._i + (config._useUTC ? " UTC" : ""));
|
|
}
|
|
);
|
|
function defaults3(a2, b2, c2) {
|
|
if (a2 != null) {
|
|
return a2;
|
|
}
|
|
if (b2 != null) {
|
|
return b2;
|
|
}
|
|
return c2;
|
|
}
|
|
function currentDateArray(config) {
|
|
var nowValue = new Date(hooks.now());
|
|
if (config._useUTC) {
|
|
return [
|
|
nowValue.getUTCFullYear(),
|
|
nowValue.getUTCMonth(),
|
|
nowValue.getUTCDate()
|
|
];
|
|
}
|
|
return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
|
|
}
|
|
function configFromArray(config) {
|
|
var i2, date, input = [], currentDate, expectedWeekday, yearToUse;
|
|
if (config._d) {
|
|
return;
|
|
}
|
|
currentDate = currentDateArray(config);
|
|
if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
|
|
dayOfYearFromWeekInfo(config);
|
|
}
|
|
if (config._dayOfYear != null) {
|
|
yearToUse = defaults3(config._a[YEAR], currentDate[YEAR]);
|
|
if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
|
|
getParsingFlags(config)._overflowDayOfYear = true;
|
|
}
|
|
date = createUTCDate(yearToUse, 0, config._dayOfYear);
|
|
config._a[MONTH] = date.getUTCMonth();
|
|
config._a[DATE] = date.getUTCDate();
|
|
}
|
|
for (i2 = 0; i2 < 3 && config._a[i2] == null; ++i2) {
|
|
config._a[i2] = input[i2] = currentDate[i2];
|
|
}
|
|
for (; i2 < 7; i2++) {
|
|
config._a[i2] = input[i2] = config._a[i2] == null ? i2 === 2 ? 1 : 0 : config._a[i2];
|
|
}
|
|
if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
|
|
config._nextDay = true;
|
|
config._a[HOUR] = 0;
|
|
}
|
|
config._d = (config._useUTC ? createUTCDate : createDate).apply(
|
|
null,
|
|
input
|
|
);
|
|
expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
|
|
if (config._tzm != null) {
|
|
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
|
|
}
|
|
if (config._nextDay) {
|
|
config._a[HOUR] = 24;
|
|
}
|
|
if (config._w && typeof config._w.d !== "undefined" && config._w.d !== expectedWeekday) {
|
|
getParsingFlags(config).weekdayMismatch = true;
|
|
}
|
|
}
|
|
function dayOfYearFromWeekInfo(config) {
|
|
var w2, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek;
|
|
w2 = config._w;
|
|
if (w2.GG != null || w2.W != null || w2.E != null) {
|
|
dow = 1;
|
|
doy = 4;
|
|
weekYear = defaults3(
|
|
w2.GG,
|
|
config._a[YEAR],
|
|
weekOfYear(createLocal(), 1, 4).year
|
|
);
|
|
week = defaults3(w2.W, 1);
|
|
weekday = defaults3(w2.E, 1);
|
|
if (weekday < 1 || weekday > 7) {
|
|
weekdayOverflow = true;
|
|
}
|
|
} else {
|
|
dow = config._locale._week.dow;
|
|
doy = config._locale._week.doy;
|
|
curWeek = weekOfYear(createLocal(), dow, doy);
|
|
weekYear = defaults3(w2.gg, config._a[YEAR], curWeek.year);
|
|
week = defaults3(w2.w, curWeek.week);
|
|
if (w2.d != null) {
|
|
weekday = w2.d;
|
|
if (weekday < 0 || weekday > 6) {
|
|
weekdayOverflow = true;
|
|
}
|
|
} else if (w2.e != null) {
|
|
weekday = w2.e + dow;
|
|
if (w2.e < 0 || w2.e > 6) {
|
|
weekdayOverflow = true;
|
|
}
|
|
} else {
|
|
weekday = dow;
|
|
}
|
|
}
|
|
if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
|
|
getParsingFlags(config)._overflowWeeks = true;
|
|
} else if (weekdayOverflow != null) {
|
|
getParsingFlags(config)._overflowWeekday = true;
|
|
} else {
|
|
temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
|
|
config._a[YEAR] = temp.year;
|
|
config._dayOfYear = temp.dayOfYear;
|
|
}
|
|
}
|
|
hooks.ISO_8601 = function() {
|
|
};
|
|
hooks.RFC_2822 = function() {
|
|
};
|
|
function configFromStringAndFormat(config) {
|
|
if (config._f === hooks.ISO_8601) {
|
|
configFromISO(config);
|
|
return;
|
|
}
|
|
if (config._f === hooks.RFC_2822) {
|
|
configFromRFC2822(config);
|
|
return;
|
|
}
|
|
config._a = [];
|
|
getParsingFlags(config).empty = true;
|
|
var string = "" + config._i, i2, parsedInput, tokens2, token2, skipped, stringLength = string.length, totalParsedInputLength = 0, era, tokenLen;
|
|
tokens2 = expandFormat(config._f, config._locale).match(formattingTokens) || [];
|
|
tokenLen = tokens2.length;
|
|
for (i2 = 0; i2 < tokenLen; i2++) {
|
|
token2 = tokens2[i2];
|
|
parsedInput = (string.match(getParseRegexForToken(token2, config)) || [])[0];
|
|
if (parsedInput) {
|
|
skipped = string.substr(0, string.indexOf(parsedInput));
|
|
if (skipped.length > 0) {
|
|
getParsingFlags(config).unusedInput.push(skipped);
|
|
}
|
|
string = string.slice(
|
|
string.indexOf(parsedInput) + parsedInput.length
|
|
);
|
|
totalParsedInputLength += parsedInput.length;
|
|
}
|
|
if (formatTokenFunctions[token2]) {
|
|
if (parsedInput) {
|
|
getParsingFlags(config).empty = false;
|
|
} else {
|
|
getParsingFlags(config).unusedTokens.push(token2);
|
|
}
|
|
addTimeToArrayFromToken(token2, parsedInput, config);
|
|
} else if (config._strict && !parsedInput) {
|
|
getParsingFlags(config).unusedTokens.push(token2);
|
|
}
|
|
}
|
|
getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
|
|
if (string.length > 0) {
|
|
getParsingFlags(config).unusedInput.push(string);
|
|
}
|
|
if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
|
|
getParsingFlags(config).bigHour = void 0;
|
|
}
|
|
getParsingFlags(config).parsedDateParts = config._a.slice(0);
|
|
getParsingFlags(config).meridiem = config._meridiem;
|
|
config._a[HOUR] = meridiemFixWrap(
|
|
config._locale,
|
|
config._a[HOUR],
|
|
config._meridiem
|
|
);
|
|
era = getParsingFlags(config).era;
|
|
if (era !== null) {
|
|
config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
|
|
}
|
|
configFromArray(config);
|
|
checkOverflow(config);
|
|
}
|
|
function meridiemFixWrap(locale3, hour, meridiem2) {
|
|
var isPm;
|
|
if (meridiem2 == null) {
|
|
return hour;
|
|
}
|
|
if (locale3.meridiemHour != null) {
|
|
return locale3.meridiemHour(hour, meridiem2);
|
|
} else if (locale3.isPM != null) {
|
|
isPm = locale3.isPM(meridiem2);
|
|
if (isPm && hour < 12) {
|
|
hour += 12;
|
|
}
|
|
if (!isPm && hour === 12) {
|
|
hour = 0;
|
|
}
|
|
return hour;
|
|
} else {
|
|
return hour;
|
|
}
|
|
}
|
|
function configFromStringAndArray(config) {
|
|
var tempConfig, bestMoment, scoreToBeat, i2, currentScore, validFormatFound, bestFormatIsValid = false, configfLen = config._f.length;
|
|
if (configfLen === 0) {
|
|
getParsingFlags(config).invalidFormat = true;
|
|
config._d = /* @__PURE__ */ new Date(NaN);
|
|
return;
|
|
}
|
|
for (i2 = 0; i2 < configfLen; i2++) {
|
|
currentScore = 0;
|
|
validFormatFound = false;
|
|
tempConfig = copyConfig({}, config);
|
|
if (config._useUTC != null) {
|
|
tempConfig._useUTC = config._useUTC;
|
|
}
|
|
tempConfig._f = config._f[i2];
|
|
configFromStringAndFormat(tempConfig);
|
|
if (isValid(tempConfig)) {
|
|
validFormatFound = true;
|
|
}
|
|
currentScore += getParsingFlags(tempConfig).charsLeftOver;
|
|
currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
|
|
getParsingFlags(tempConfig).score = currentScore;
|
|
if (!bestFormatIsValid) {
|
|
if (scoreToBeat == null || currentScore < scoreToBeat || validFormatFound) {
|
|
scoreToBeat = currentScore;
|
|
bestMoment = tempConfig;
|
|
if (validFormatFound) {
|
|
bestFormatIsValid = true;
|
|
}
|
|
}
|
|
} else {
|
|
if (currentScore < scoreToBeat) {
|
|
scoreToBeat = currentScore;
|
|
bestMoment = tempConfig;
|
|
}
|
|
}
|
|
}
|
|
extend(config, bestMoment || tempConfig);
|
|
}
|
|
function configFromObject(config) {
|
|
if (config._d) {
|
|
return;
|
|
}
|
|
var i2 = normalizeObjectUnits(config._i), dayOrDate = i2.day === void 0 ? i2.date : i2.day;
|
|
config._a = map3(
|
|
[i2.year, i2.month, dayOrDate, i2.hour, i2.minute, i2.second, i2.millisecond],
|
|
function(obj) {
|
|
return obj && parseInt(obj, 10);
|
|
}
|
|
);
|
|
configFromArray(config);
|
|
}
|
|
function createFromConfig(config) {
|
|
var res = new Moment3(checkOverflow(prepareConfig(config)));
|
|
if (res._nextDay) {
|
|
res.add(1, "d");
|
|
res._nextDay = void 0;
|
|
}
|
|
return res;
|
|
}
|
|
function prepareConfig(config) {
|
|
var input = config._i, format2 = config._f;
|
|
config._locale = config._locale || getLocale(config._l);
|
|
if (input === null || format2 === void 0 && input === "") {
|
|
return createInvalid({ nullInput: true });
|
|
}
|
|
if (typeof input === "string") {
|
|
config._i = input = config._locale.preparse(input);
|
|
}
|
|
if (isMoment(input)) {
|
|
return new Moment3(checkOverflow(input));
|
|
} else if (isDate(input)) {
|
|
config._d = input;
|
|
} else if (isArray2(format2)) {
|
|
configFromStringAndArray(config);
|
|
} else if (format2) {
|
|
configFromStringAndFormat(config);
|
|
} else {
|
|
configFromInput(config);
|
|
}
|
|
if (!isValid(config)) {
|
|
config._d = null;
|
|
}
|
|
return config;
|
|
}
|
|
function configFromInput(config) {
|
|
var input = config._i;
|
|
if (isUndefined(input)) {
|
|
config._d = new Date(hooks.now());
|
|
} else if (isDate(input)) {
|
|
config._d = new Date(input.valueOf());
|
|
} else if (typeof input === "string") {
|
|
configFromString(config);
|
|
} else if (isArray2(input)) {
|
|
config._a = map3(input.slice(0), function(obj) {
|
|
return parseInt(obj, 10);
|
|
});
|
|
configFromArray(config);
|
|
} else if (isObject2(input)) {
|
|
configFromObject(config);
|
|
} else if (isNumber2(input)) {
|
|
config._d = new Date(input);
|
|
} else {
|
|
hooks.createFromInputFallback(config);
|
|
}
|
|
}
|
|
function createLocalOrUTC(input, format2, locale3, strict, isUTC) {
|
|
var c2 = {};
|
|
if (format2 === true || format2 === false) {
|
|
strict = format2;
|
|
format2 = void 0;
|
|
}
|
|
if (locale3 === true || locale3 === false) {
|
|
strict = locale3;
|
|
locale3 = void 0;
|
|
}
|
|
if (isObject2(input) && isObjectEmpty(input) || isArray2(input) && input.length === 0) {
|
|
input = void 0;
|
|
}
|
|
c2._isAMomentObject = true;
|
|
c2._useUTC = c2._isUTC = isUTC;
|
|
c2._l = locale3;
|
|
c2._i = input;
|
|
c2._f = format2;
|
|
c2._strict = strict;
|
|
return createFromConfig(c2);
|
|
}
|
|
function createLocal(input, format2, locale3, strict) {
|
|
return createLocalOrUTC(input, format2, locale3, strict, false);
|
|
}
|
|
var prototypeMin = deprecate(
|
|
"moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",
|
|
function() {
|
|
var other = createLocal.apply(null, arguments);
|
|
if (this.isValid() && other.isValid()) {
|
|
return other < this ? this : other;
|
|
} else {
|
|
return createInvalid();
|
|
}
|
|
}
|
|
), prototypeMax = deprecate(
|
|
"moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",
|
|
function() {
|
|
var other = createLocal.apply(null, arguments);
|
|
if (this.isValid() && other.isValid()) {
|
|
return other > this ? this : other;
|
|
} else {
|
|
return createInvalid();
|
|
}
|
|
}
|
|
);
|
|
function pickBy(fn2, moments) {
|
|
var res, i2;
|
|
if (moments.length === 1 && isArray2(moments[0])) {
|
|
moments = moments[0];
|
|
}
|
|
if (!moments.length) {
|
|
return createLocal();
|
|
}
|
|
res = moments[0];
|
|
for (i2 = 1; i2 < moments.length; ++i2) {
|
|
if (!moments[i2].isValid() || moments[i2][fn2](res)) {
|
|
res = moments[i2];
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
function min() {
|
|
var args = [].slice.call(arguments, 0);
|
|
return pickBy("isBefore", args);
|
|
}
|
|
function max() {
|
|
var args = [].slice.call(arguments, 0);
|
|
return pickBy("isAfter", args);
|
|
}
|
|
var now2 = function() {
|
|
return Date.now ? Date.now() : +/* @__PURE__ */ new Date();
|
|
};
|
|
var ordering = [
|
|
"year",
|
|
"quarter",
|
|
"month",
|
|
"week",
|
|
"day",
|
|
"hour",
|
|
"minute",
|
|
"second",
|
|
"millisecond"
|
|
];
|
|
function isDurationValid(m2) {
|
|
var key, unitHasDecimal = false, i2, orderLen = ordering.length;
|
|
for (key in m2) {
|
|
if (hasOwnProp(m2, key) && !(indexOf.call(ordering, key) !== -1 && (m2[key] == null || !isNaN(m2[key])))) {
|
|
return false;
|
|
}
|
|
}
|
|
for (i2 = 0; i2 < orderLen; ++i2) {
|
|
if (m2[ordering[i2]]) {
|
|
if (unitHasDecimal) {
|
|
return false;
|
|
}
|
|
if (parseFloat(m2[ordering[i2]]) !== toInt(m2[ordering[i2]])) {
|
|
unitHasDecimal = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function isValid$1() {
|
|
return this._isValid;
|
|
}
|
|
function createInvalid$1() {
|
|
return createDuration(NaN);
|
|
}
|
|
function Duration(duration) {
|
|
var normalizedInput = normalizeObjectUnits(duration), years2 = normalizedInput.year || 0, quarters = normalizedInput.quarter || 0, months2 = normalizedInput.month || 0, weeks2 = normalizedInput.week || normalizedInput.isoWeek || 0, days2 = normalizedInput.day || 0, hours2 = normalizedInput.hour || 0, minutes2 = normalizedInput.minute || 0, seconds2 = normalizedInput.second || 0, milliseconds2 = normalizedInput.millisecond || 0;
|
|
this._isValid = isDurationValid(normalizedInput);
|
|
this._milliseconds = +milliseconds2 + seconds2 * 1e3 + // 1000
|
|
minutes2 * 6e4 + // 1000 * 60
|
|
hours2 * 1e3 * 60 * 60;
|
|
this._days = +days2 + weeks2 * 7;
|
|
this._months = +months2 + quarters * 3 + years2 * 12;
|
|
this._data = {};
|
|
this._locale = getLocale();
|
|
this._bubble();
|
|
}
|
|
function isDuration(obj) {
|
|
return obj instanceof Duration;
|
|
}
|
|
function absRound(number) {
|
|
if (number < 0) {
|
|
return Math.round(-1 * number) * -1;
|
|
} else {
|
|
return Math.round(number);
|
|
}
|
|
}
|
|
function compareArrays(array1, array2, dontConvert) {
|
|
var len = Math.min(array1.length, array2.length), lengthDiff = Math.abs(array1.length - array2.length), diffs = 0, i2;
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
if (dontConvert && array1[i2] !== array2[i2] || !dontConvert && toInt(array1[i2]) !== toInt(array2[i2])) {
|
|
diffs++;
|
|
}
|
|
}
|
|
return diffs + lengthDiff;
|
|
}
|
|
function offset(token2, separator) {
|
|
addFormatToken(token2, 0, 0, function() {
|
|
var offset2 = this.utcOffset(), sign3 = "+";
|
|
if (offset2 < 0) {
|
|
offset2 = -offset2;
|
|
sign3 = "-";
|
|
}
|
|
return sign3 + zeroFill(~~(offset2 / 60), 2) + separator + zeroFill(~~offset2 % 60, 2);
|
|
});
|
|
}
|
|
offset("Z", ":");
|
|
offset("ZZ", "");
|
|
addRegexToken("Z", matchShortOffset);
|
|
addRegexToken("ZZ", matchShortOffset);
|
|
addParseToken(["Z", "ZZ"], function(input, array, config) {
|
|
config._useUTC = true;
|
|
config._tzm = offsetFromString(matchShortOffset, input);
|
|
});
|
|
var chunkOffset = /([\+\-]|\d\d)/gi;
|
|
function offsetFromString(matcher, string) {
|
|
var matches = (string || "").match(matcher), chunk, parts, minutes2;
|
|
if (matches === null) {
|
|
return null;
|
|
}
|
|
chunk = matches[matches.length - 1] || [];
|
|
parts = (chunk + "").match(chunkOffset) || ["-", 0, 0];
|
|
minutes2 = +(parts[1] * 60) + toInt(parts[2]);
|
|
return minutes2 === 0 ? 0 : parts[0] === "+" ? minutes2 : -minutes2;
|
|
}
|
|
function cloneWithOffset(input, model) {
|
|
var res, diff2;
|
|
if (model._isUTC) {
|
|
res = model.clone();
|
|
diff2 = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
|
|
res._d.setTime(res._d.valueOf() + diff2);
|
|
hooks.updateOffset(res, false);
|
|
return res;
|
|
} else {
|
|
return createLocal(input).local();
|
|
}
|
|
}
|
|
function getDateOffset(m2) {
|
|
return -Math.round(m2._d.getTimezoneOffset());
|
|
}
|
|
hooks.updateOffset = function() {
|
|
};
|
|
function getSetOffset(input, keepLocalTime, keepMinutes) {
|
|
var offset2 = this._offset || 0, localAdjust;
|
|
if (!this.isValid()) {
|
|
return input != null ? this : NaN;
|
|
}
|
|
if (input != null) {
|
|
if (typeof input === "string") {
|
|
input = offsetFromString(matchShortOffset, input);
|
|
if (input === null) {
|
|
return this;
|
|
}
|
|
} else if (Math.abs(input) < 16 && !keepMinutes) {
|
|
input = input * 60;
|
|
}
|
|
if (!this._isUTC && keepLocalTime) {
|
|
localAdjust = getDateOffset(this);
|
|
}
|
|
this._offset = input;
|
|
this._isUTC = true;
|
|
if (localAdjust != null) {
|
|
this.add(localAdjust, "m");
|
|
}
|
|
if (offset2 !== input) {
|
|
if (!keepLocalTime || this._changeInProgress) {
|
|
addSubtract(
|
|
this,
|
|
createDuration(input - offset2, "m"),
|
|
1,
|
|
false
|
|
);
|
|
} else if (!this._changeInProgress) {
|
|
this._changeInProgress = true;
|
|
hooks.updateOffset(this, true);
|
|
this._changeInProgress = null;
|
|
}
|
|
}
|
|
return this;
|
|
} else {
|
|
return this._isUTC ? offset2 : getDateOffset(this);
|
|
}
|
|
}
|
|
function getSetZone(input, keepLocalTime) {
|
|
if (input != null) {
|
|
if (typeof input !== "string") {
|
|
input = -input;
|
|
}
|
|
this.utcOffset(input, keepLocalTime);
|
|
return this;
|
|
} else {
|
|
return -this.utcOffset();
|
|
}
|
|
}
|
|
function setOffsetToUTC(keepLocalTime) {
|
|
return this.utcOffset(0, keepLocalTime);
|
|
}
|
|
function setOffsetToLocal(keepLocalTime) {
|
|
if (this._isUTC) {
|
|
this.utcOffset(0, keepLocalTime);
|
|
this._isUTC = false;
|
|
if (keepLocalTime) {
|
|
this.subtract(getDateOffset(this), "m");
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
function setOffsetToParsedOffset() {
|
|
if (this._tzm != null) {
|
|
this.utcOffset(this._tzm, false, true);
|
|
} else if (typeof this._i === "string") {
|
|
var tZone = offsetFromString(matchOffset, this._i);
|
|
if (tZone != null) {
|
|
this.utcOffset(tZone);
|
|
} else {
|
|
this.utcOffset(0, true);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
function hasAlignedHourOffset(input) {
|
|
if (!this.isValid()) {
|
|
return false;
|
|
}
|
|
input = input ? createLocal(input).utcOffset() : 0;
|
|
return (this.utcOffset() - input) % 60 === 0;
|
|
}
|
|
function isDaylightSavingTime() {
|
|
return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
|
|
}
|
|
function isDaylightSavingTimeShifted() {
|
|
if (!isUndefined(this._isDSTShifted)) {
|
|
return this._isDSTShifted;
|
|
}
|
|
var c2 = {}, other;
|
|
copyConfig(c2, this);
|
|
c2 = prepareConfig(c2);
|
|
if (c2._a) {
|
|
other = c2._isUTC ? createUTC(c2._a) : createLocal(c2._a);
|
|
this._isDSTShifted = this.isValid() && compareArrays(c2._a, other.toArray()) > 0;
|
|
} else {
|
|
this._isDSTShifted = false;
|
|
}
|
|
return this._isDSTShifted;
|
|
}
|
|
function isLocal() {
|
|
return this.isValid() ? !this._isUTC : false;
|
|
}
|
|
function isUtcOffset() {
|
|
return this.isValid() ? this._isUTC : false;
|
|
}
|
|
function isUtc() {
|
|
return this.isValid() ? this._isUTC && this._offset === 0 : false;
|
|
}
|
|
var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
|
|
function createDuration(input, key) {
|
|
var duration = input, match5 = null, sign3, ret, diffRes;
|
|
if (isDuration(input)) {
|
|
duration = {
|
|
ms: input._milliseconds,
|
|
d: input._days,
|
|
M: input._months
|
|
};
|
|
} else if (isNumber2(input) || !isNaN(+input)) {
|
|
duration = {};
|
|
if (key) {
|
|
duration[key] = +input;
|
|
} else {
|
|
duration.milliseconds = +input;
|
|
}
|
|
} else if (match5 = aspNetRegex.exec(input)) {
|
|
sign3 = match5[1] === "-" ? -1 : 1;
|
|
duration = {
|
|
y: 0,
|
|
d: toInt(match5[DATE]) * sign3,
|
|
h: toInt(match5[HOUR]) * sign3,
|
|
m: toInt(match5[MINUTE]) * sign3,
|
|
s: toInt(match5[SECOND]) * sign3,
|
|
ms: toInt(absRound(match5[MILLISECOND] * 1e3)) * sign3
|
|
// the millisecond decimal point is included in the match
|
|
};
|
|
} else if (match5 = isoRegex.exec(input)) {
|
|
sign3 = match5[1] === "-" ? -1 : 1;
|
|
duration = {
|
|
y: parseIso(match5[2], sign3),
|
|
M: parseIso(match5[3], sign3),
|
|
w: parseIso(match5[4], sign3),
|
|
d: parseIso(match5[5], sign3),
|
|
h: parseIso(match5[6], sign3),
|
|
m: parseIso(match5[7], sign3),
|
|
s: parseIso(match5[8], sign3)
|
|
};
|
|
} else if (duration == null) {
|
|
duration = {};
|
|
} else if (typeof duration === "object" && ("from" in duration || "to" in duration)) {
|
|
diffRes = momentsDifference(
|
|
createLocal(duration.from),
|
|
createLocal(duration.to)
|
|
);
|
|
duration = {};
|
|
duration.ms = diffRes.milliseconds;
|
|
duration.M = diffRes.months;
|
|
}
|
|
ret = new Duration(duration);
|
|
if (isDuration(input) && hasOwnProp(input, "_locale")) {
|
|
ret._locale = input._locale;
|
|
}
|
|
if (isDuration(input) && hasOwnProp(input, "_isValid")) {
|
|
ret._isValid = input._isValid;
|
|
}
|
|
return ret;
|
|
}
|
|
createDuration.fn = Duration.prototype;
|
|
createDuration.invalid = createInvalid$1;
|
|
function parseIso(inp, sign3) {
|
|
var res = inp && parseFloat(inp.replace(",", "."));
|
|
return (isNaN(res) ? 0 : res) * sign3;
|
|
}
|
|
function positiveMomentsDifference(base, other) {
|
|
var res = {};
|
|
res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
|
|
if (base.clone().add(res.months, "M").isAfter(other)) {
|
|
--res.months;
|
|
}
|
|
res.milliseconds = +other - +base.clone().add(res.months, "M");
|
|
return res;
|
|
}
|
|
function momentsDifference(base, other) {
|
|
var res;
|
|
if (!(base.isValid() && other.isValid())) {
|
|
return { milliseconds: 0, months: 0 };
|
|
}
|
|
other = cloneWithOffset(other, base);
|
|
if (base.isBefore(other)) {
|
|
res = positiveMomentsDifference(base, other);
|
|
} else {
|
|
res = positiveMomentsDifference(other, base);
|
|
res.milliseconds = -res.milliseconds;
|
|
res.months = -res.months;
|
|
}
|
|
return res;
|
|
}
|
|
function createAdder(direction, name) {
|
|
return function(val, period) {
|
|
var dur, tmp;
|
|
if (period !== null && !isNaN(+period)) {
|
|
deprecateSimple(
|
|
name,
|
|
"moment()." + name + "(period, number) is deprecated. Please use moment()." + name + "(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."
|
|
);
|
|
tmp = val;
|
|
val = period;
|
|
period = tmp;
|
|
}
|
|
dur = createDuration(val, period);
|
|
addSubtract(this, dur, direction);
|
|
return this;
|
|
};
|
|
}
|
|
function addSubtract(mom, duration, isAdding, updateOffset) {
|
|
var milliseconds2 = duration._milliseconds, days2 = absRound(duration._days), months2 = absRound(duration._months);
|
|
if (!mom.isValid()) {
|
|
return;
|
|
}
|
|
updateOffset = updateOffset == null ? true : updateOffset;
|
|
if (months2) {
|
|
setMonth(mom, get(mom, "Month") + months2 * isAdding);
|
|
}
|
|
if (days2) {
|
|
set$1(mom, "Date", get(mom, "Date") + days2 * isAdding);
|
|
}
|
|
if (milliseconds2) {
|
|
mom._d.setTime(mom._d.valueOf() + milliseconds2 * isAdding);
|
|
}
|
|
if (updateOffset) {
|
|
hooks.updateOffset(mom, days2 || months2);
|
|
}
|
|
}
|
|
var add = createAdder(1, "add"), subtract = createAdder(-1, "subtract");
|
|
function isString(input) {
|
|
return typeof input === "string" || input instanceof String;
|
|
}
|
|
function isMomentInput(input) {
|
|
return isMoment(input) || isDate(input) || isString(input) || isNumber2(input) || isNumberOrStringArray(input) || isMomentInputObject(input) || input === null || input === void 0;
|
|
}
|
|
function isMomentInputObject(input) {
|
|
var objectTest = isObject2(input) && !isObjectEmpty(input), propertyTest = false, properties = [
|
|
"years",
|
|
"year",
|
|
"y",
|
|
"months",
|
|
"month",
|
|
"M",
|
|
"days",
|
|
"day",
|
|
"d",
|
|
"dates",
|
|
"date",
|
|
"D",
|
|
"hours",
|
|
"hour",
|
|
"h",
|
|
"minutes",
|
|
"minute",
|
|
"m",
|
|
"seconds",
|
|
"second",
|
|
"s",
|
|
"milliseconds",
|
|
"millisecond",
|
|
"ms"
|
|
], i2, property, propertyLen = properties.length;
|
|
for (i2 = 0; i2 < propertyLen; i2 += 1) {
|
|
property = properties[i2];
|
|
propertyTest = propertyTest || hasOwnProp(input, property);
|
|
}
|
|
return objectTest && propertyTest;
|
|
}
|
|
function isNumberOrStringArray(input) {
|
|
var arrayTest = isArray2(input), dataTypeTest = false;
|
|
if (arrayTest) {
|
|
dataTypeTest = input.filter(function(item) {
|
|
return !isNumber2(item) && isString(input);
|
|
}).length === 0;
|
|
}
|
|
return arrayTest && dataTypeTest;
|
|
}
|
|
function isCalendarSpec(input) {
|
|
var objectTest = isObject2(input) && !isObjectEmpty(input), propertyTest = false, properties = [
|
|
"sameDay",
|
|
"nextDay",
|
|
"lastDay",
|
|
"nextWeek",
|
|
"lastWeek",
|
|
"sameElse"
|
|
], i2, property;
|
|
for (i2 = 0; i2 < properties.length; i2 += 1) {
|
|
property = properties[i2];
|
|
propertyTest = propertyTest || hasOwnProp(input, property);
|
|
}
|
|
return objectTest && propertyTest;
|
|
}
|
|
function getCalendarFormat(myMoment, now3) {
|
|
var diff2 = myMoment.diff(now3, "days", true);
|
|
return diff2 < -6 ? "sameElse" : diff2 < -1 ? "lastWeek" : diff2 < 0 ? "lastDay" : diff2 < 1 ? "sameDay" : diff2 < 2 ? "nextDay" : diff2 < 7 ? "nextWeek" : "sameElse";
|
|
}
|
|
function calendar$1(time, formats) {
|
|
if (arguments.length === 1) {
|
|
if (!arguments[0]) {
|
|
time = void 0;
|
|
formats = void 0;
|
|
} else if (isMomentInput(arguments[0])) {
|
|
time = arguments[0];
|
|
formats = void 0;
|
|
} else if (isCalendarSpec(arguments[0])) {
|
|
formats = arguments[0];
|
|
time = void 0;
|
|
}
|
|
}
|
|
var now3 = time || createLocal(), sod = cloneWithOffset(now3, this).startOf("day"), format2 = hooks.calendarFormat(this, sod) || "sameElse", output = formats && (isFunction2(formats[format2]) ? formats[format2].call(this, now3) : formats[format2]);
|
|
return this.format(
|
|
output || this.localeData().calendar(format2, this, createLocal(now3))
|
|
);
|
|
}
|
|
function clone3() {
|
|
return new Moment3(this);
|
|
}
|
|
function isAfter(input, units) {
|
|
var localInput = isMoment(input) ? input : createLocal(input);
|
|
if (!(this.isValid() && localInput.isValid())) {
|
|
return false;
|
|
}
|
|
units = normalizeUnits(units) || "millisecond";
|
|
if (units === "millisecond") {
|
|
return this.valueOf() > localInput.valueOf();
|
|
} else {
|
|
return localInput.valueOf() < this.clone().startOf(units).valueOf();
|
|
}
|
|
}
|
|
function isBefore(input, units) {
|
|
var localInput = isMoment(input) ? input : createLocal(input);
|
|
if (!(this.isValid() && localInput.isValid())) {
|
|
return false;
|
|
}
|
|
units = normalizeUnits(units) || "millisecond";
|
|
if (units === "millisecond") {
|
|
return this.valueOf() < localInput.valueOf();
|
|
} else {
|
|
return this.clone().endOf(units).valueOf() < localInput.valueOf();
|
|
}
|
|
}
|
|
function isBetween(from3, to3, units, inclusivity) {
|
|
var localFrom = isMoment(from3) ? from3 : createLocal(from3), localTo = isMoment(to3) ? to3 : createLocal(to3);
|
|
if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
|
|
return false;
|
|
}
|
|
inclusivity = inclusivity || "()";
|
|
return (inclusivity[0] === "(" ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ")" ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
|
|
}
|
|
function isSame(input, units) {
|
|
var localInput = isMoment(input) ? input : createLocal(input), inputMs;
|
|
if (!(this.isValid() && localInput.isValid())) {
|
|
return false;
|
|
}
|
|
units = normalizeUnits(units) || "millisecond";
|
|
if (units === "millisecond") {
|
|
return this.valueOf() === localInput.valueOf();
|
|
} else {
|
|
inputMs = localInput.valueOf();
|
|
return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
|
|
}
|
|
}
|
|
function isSameOrAfter(input, units) {
|
|
return this.isSame(input, units) || this.isAfter(input, units);
|
|
}
|
|
function isSameOrBefore(input, units) {
|
|
return this.isSame(input, units) || this.isBefore(input, units);
|
|
}
|
|
function diff(input, units, asFloat) {
|
|
var that, zoneDelta, output;
|
|
if (!this.isValid()) {
|
|
return NaN;
|
|
}
|
|
that = cloneWithOffset(input, this);
|
|
if (!that.isValid()) {
|
|
return NaN;
|
|
}
|
|
zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
|
|
units = normalizeUnits(units);
|
|
switch (units) {
|
|
case "year":
|
|
output = monthDiff(this, that) / 12;
|
|
break;
|
|
case "month":
|
|
output = monthDiff(this, that);
|
|
break;
|
|
case "quarter":
|
|
output = monthDiff(this, that) / 3;
|
|
break;
|
|
case "second":
|
|
output = (this - that) / 1e3;
|
|
break;
|
|
// 1000
|
|
case "minute":
|
|
output = (this - that) / 6e4;
|
|
break;
|
|
// 1000 * 60
|
|
case "hour":
|
|
output = (this - that) / 36e5;
|
|
break;
|
|
// 1000 * 60 * 60
|
|
case "day":
|
|
output = (this - that - zoneDelta) / 864e5;
|
|
break;
|
|
// 1000 * 60 * 60 * 24, negate dst
|
|
case "week":
|
|
output = (this - that - zoneDelta) / 6048e5;
|
|
break;
|
|
// 1000 * 60 * 60 * 24 * 7, negate dst
|
|
default:
|
|
output = this - that;
|
|
}
|
|
return asFloat ? output : absFloor(output);
|
|
}
|
|
function monthDiff(a2, b2) {
|
|
if (a2.date() < b2.date()) {
|
|
return -monthDiff(b2, a2);
|
|
}
|
|
var wholeMonthDiff = (b2.year() - a2.year()) * 12 + (b2.month() - a2.month()), anchor = a2.clone().add(wholeMonthDiff, "months"), anchor2, adjust;
|
|
if (b2 - anchor < 0) {
|
|
anchor2 = a2.clone().add(wholeMonthDiff - 1, "months");
|
|
adjust = (b2 - anchor) / (anchor - anchor2);
|
|
} else {
|
|
anchor2 = a2.clone().add(wholeMonthDiff + 1, "months");
|
|
adjust = (b2 - anchor) / (anchor2 - anchor);
|
|
}
|
|
return -(wholeMonthDiff + adjust) || 0;
|
|
}
|
|
hooks.defaultFormat = "YYYY-MM-DDTHH:mm:ssZ";
|
|
hooks.defaultFormatUtc = "YYYY-MM-DDTHH:mm:ss[Z]";
|
|
function toString() {
|
|
return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
|
|
}
|
|
function toISOString(keepOffset) {
|
|
if (!this.isValid()) {
|
|
return null;
|
|
}
|
|
var utc = keepOffset !== true, m2 = utc ? this.clone().utc() : this;
|
|
if (m2.year() < 0 || m2.year() > 9999) {
|
|
return formatMoment(
|
|
m2,
|
|
utc ? "YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]" : "YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"
|
|
);
|
|
}
|
|
if (isFunction2(Date.prototype.toISOString)) {
|
|
if (utc) {
|
|
return this.toDate().toISOString();
|
|
} else {
|
|
return new Date(this.valueOf() + this.utcOffset() * 60 * 1e3).toISOString().replace("Z", formatMoment(m2, "Z"));
|
|
}
|
|
}
|
|
return formatMoment(
|
|
m2,
|
|
utc ? "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]" : "YYYY-MM-DD[T]HH:mm:ss.SSSZ"
|
|
);
|
|
}
|
|
function inspect() {
|
|
if (!this.isValid()) {
|
|
return "moment.invalid(/* " + this._i + " */)";
|
|
}
|
|
var func = "moment", zone = "", prefix, year, datetime, suffix;
|
|
if (!this.isLocal()) {
|
|
func = this.utcOffset() === 0 ? "moment.utc" : "moment.parseZone";
|
|
zone = "Z";
|
|
}
|
|
prefix = "[" + func + '("]';
|
|
year = 0 <= this.year() && this.year() <= 9999 ? "YYYY" : "YYYYYY";
|
|
datetime = "-MM-DD[T]HH:mm:ss.SSS";
|
|
suffix = zone + '[")]';
|
|
return this.format(prefix + year + datetime + suffix);
|
|
}
|
|
function format(inputString) {
|
|
if (!inputString) {
|
|
inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
|
|
}
|
|
var output = formatMoment(this, inputString);
|
|
return this.localeData().postformat(output);
|
|
}
|
|
function from2(time, withoutSuffix) {
|
|
if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
|
|
return createDuration({ to: this, from: time }).locale(this.locale()).humanize(!withoutSuffix);
|
|
} else {
|
|
return this.localeData().invalidDate();
|
|
}
|
|
}
|
|
function fromNow(withoutSuffix) {
|
|
return this.from(createLocal(), withoutSuffix);
|
|
}
|
|
function to2(time, withoutSuffix) {
|
|
if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
|
|
return createDuration({ from: this, to: time }).locale(this.locale()).humanize(!withoutSuffix);
|
|
} else {
|
|
return this.localeData().invalidDate();
|
|
}
|
|
}
|
|
function toNow(withoutSuffix) {
|
|
return this.to(createLocal(), withoutSuffix);
|
|
}
|
|
function locale2(key) {
|
|
var newLocaleData;
|
|
if (key === void 0) {
|
|
return this._locale._abbr;
|
|
} else {
|
|
newLocaleData = getLocale(key);
|
|
if (newLocaleData != null) {
|
|
this._locale = newLocaleData;
|
|
}
|
|
return this;
|
|
}
|
|
}
|
|
var lang = deprecate(
|
|
"moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",
|
|
function(key) {
|
|
if (key === void 0) {
|
|
return this.localeData();
|
|
} else {
|
|
return this.locale(key);
|
|
}
|
|
}
|
|
);
|
|
function localeData() {
|
|
return this._locale;
|
|
}
|
|
var MS_PER_SECOND = 1e3, MS_PER_MINUTE = 60 * MS_PER_SECOND, MS_PER_HOUR = 60 * MS_PER_MINUTE, MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;
|
|
function mod$1(dividend, divisor) {
|
|
return (dividend % divisor + divisor) % divisor;
|
|
}
|
|
function localStartOfDate(y2, m2, d2) {
|
|
if (y2 < 100 && y2 >= 0) {
|
|
return new Date(y2 + 400, m2, d2) - MS_PER_400_YEARS;
|
|
} else {
|
|
return new Date(y2, m2, d2).valueOf();
|
|
}
|
|
}
|
|
function utcStartOfDate(y2, m2, d2) {
|
|
if (y2 < 100 && y2 >= 0) {
|
|
return Date.UTC(y2 + 400, m2, d2) - MS_PER_400_YEARS;
|
|
} else {
|
|
return Date.UTC(y2, m2, d2);
|
|
}
|
|
}
|
|
function startOf(units) {
|
|
var time, startOfDate;
|
|
units = normalizeUnits(units);
|
|
if (units === void 0 || units === "millisecond" || !this.isValid()) {
|
|
return this;
|
|
}
|
|
startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
|
|
switch (units) {
|
|
case "year":
|
|
time = startOfDate(this.year(), 0, 1);
|
|
break;
|
|
case "quarter":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month() - this.month() % 3,
|
|
1
|
|
);
|
|
break;
|
|
case "month":
|
|
time = startOfDate(this.year(), this.month(), 1);
|
|
break;
|
|
case "week":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month(),
|
|
this.date() - this.weekday()
|
|
);
|
|
break;
|
|
case "isoWeek":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month(),
|
|
this.date() - (this.isoWeekday() - 1)
|
|
);
|
|
break;
|
|
case "day":
|
|
case "date":
|
|
time = startOfDate(this.year(), this.month(), this.date());
|
|
break;
|
|
case "hour":
|
|
time = this._d.valueOf();
|
|
time -= mod$1(
|
|
time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
|
|
MS_PER_HOUR
|
|
);
|
|
break;
|
|
case "minute":
|
|
time = this._d.valueOf();
|
|
time -= mod$1(time, MS_PER_MINUTE);
|
|
break;
|
|
case "second":
|
|
time = this._d.valueOf();
|
|
time -= mod$1(time, MS_PER_SECOND);
|
|
break;
|
|
}
|
|
this._d.setTime(time);
|
|
hooks.updateOffset(this, true);
|
|
return this;
|
|
}
|
|
function endOf(units) {
|
|
var time, startOfDate;
|
|
units = normalizeUnits(units);
|
|
if (units === void 0 || units === "millisecond" || !this.isValid()) {
|
|
return this;
|
|
}
|
|
startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
|
|
switch (units) {
|
|
case "year":
|
|
time = startOfDate(this.year() + 1, 0, 1) - 1;
|
|
break;
|
|
case "quarter":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month() - this.month() % 3 + 3,
|
|
1
|
|
) - 1;
|
|
break;
|
|
case "month":
|
|
time = startOfDate(this.year(), this.month() + 1, 1) - 1;
|
|
break;
|
|
case "week":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month(),
|
|
this.date() - this.weekday() + 7
|
|
) - 1;
|
|
break;
|
|
case "isoWeek":
|
|
time = startOfDate(
|
|
this.year(),
|
|
this.month(),
|
|
this.date() - (this.isoWeekday() - 1) + 7
|
|
) - 1;
|
|
break;
|
|
case "day":
|
|
case "date":
|
|
time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
|
|
break;
|
|
case "hour":
|
|
time = this._d.valueOf();
|
|
time += MS_PER_HOUR - mod$1(
|
|
time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
|
|
MS_PER_HOUR
|
|
) - 1;
|
|
break;
|
|
case "minute":
|
|
time = this._d.valueOf();
|
|
time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
|
|
break;
|
|
case "second":
|
|
time = this._d.valueOf();
|
|
time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
|
|
break;
|
|
}
|
|
this._d.setTime(time);
|
|
hooks.updateOffset(this, true);
|
|
return this;
|
|
}
|
|
function valueOf() {
|
|
return this._d.valueOf() - (this._offset || 0) * 6e4;
|
|
}
|
|
function unix() {
|
|
return Math.floor(this.valueOf() / 1e3);
|
|
}
|
|
function toDate() {
|
|
return new Date(this.valueOf());
|
|
}
|
|
function toArray() {
|
|
var m2 = this;
|
|
return [
|
|
m2.year(),
|
|
m2.month(),
|
|
m2.date(),
|
|
m2.hour(),
|
|
m2.minute(),
|
|
m2.second(),
|
|
m2.millisecond()
|
|
];
|
|
}
|
|
function toObject() {
|
|
var m2 = this;
|
|
return {
|
|
years: m2.year(),
|
|
months: m2.month(),
|
|
date: m2.date(),
|
|
hours: m2.hours(),
|
|
minutes: m2.minutes(),
|
|
seconds: m2.seconds(),
|
|
milliseconds: m2.milliseconds()
|
|
};
|
|
}
|
|
function toJSON() {
|
|
return this.isValid() ? this.toISOString() : null;
|
|
}
|
|
function isValid$2() {
|
|
return isValid(this);
|
|
}
|
|
function parsingFlags() {
|
|
return extend({}, getParsingFlags(this));
|
|
}
|
|
function invalidAt() {
|
|
return getParsingFlags(this).overflow;
|
|
}
|
|
function creationData() {
|
|
return {
|
|
input: this._i,
|
|
format: this._f,
|
|
locale: this._locale,
|
|
isUTC: this._isUTC,
|
|
strict: this._strict
|
|
};
|
|
}
|
|
addFormatToken("N", 0, 0, "eraAbbr");
|
|
addFormatToken("NN", 0, 0, "eraAbbr");
|
|
addFormatToken("NNN", 0, 0, "eraAbbr");
|
|
addFormatToken("NNNN", 0, 0, "eraName");
|
|
addFormatToken("NNNNN", 0, 0, "eraNarrow");
|
|
addFormatToken("y", ["y", 1], "yo", "eraYear");
|
|
addFormatToken("y", ["yy", 2], 0, "eraYear");
|
|
addFormatToken("y", ["yyy", 3], 0, "eraYear");
|
|
addFormatToken("y", ["yyyy", 4], 0, "eraYear");
|
|
addRegexToken("N", matchEraAbbr);
|
|
addRegexToken("NN", matchEraAbbr);
|
|
addRegexToken("NNN", matchEraAbbr);
|
|
addRegexToken("NNNN", matchEraName);
|
|
addRegexToken("NNNNN", matchEraNarrow);
|
|
addParseToken(
|
|
["N", "NN", "NNN", "NNNN", "NNNNN"],
|
|
function(input, array, config, token2) {
|
|
var era = config._locale.erasParse(input, token2, config._strict);
|
|
if (era) {
|
|
getParsingFlags(config).era = era;
|
|
} else {
|
|
getParsingFlags(config).invalidEra = input;
|
|
}
|
|
}
|
|
);
|
|
addRegexToken("y", matchUnsigned);
|
|
addRegexToken("yy", matchUnsigned);
|
|
addRegexToken("yyy", matchUnsigned);
|
|
addRegexToken("yyyy", matchUnsigned);
|
|
addRegexToken("yo", matchEraYearOrdinal);
|
|
addParseToken(["y", "yy", "yyy", "yyyy"], YEAR);
|
|
addParseToken(["yo"], function(input, array, config, token2) {
|
|
var match5;
|
|
if (config._locale._eraYearOrdinalRegex) {
|
|
match5 = input.match(config._locale._eraYearOrdinalRegex);
|
|
}
|
|
if (config._locale.eraYearOrdinalParse) {
|
|
array[YEAR] = config._locale.eraYearOrdinalParse(input, match5);
|
|
} else {
|
|
array[YEAR] = parseInt(input, 10);
|
|
}
|
|
});
|
|
function localeEras(m2, format2) {
|
|
var i2, l2, date, eras = this._eras || getLocale("en")._eras;
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
switch (typeof eras[i2].since) {
|
|
case "string":
|
|
date = hooks(eras[i2].since).startOf("day");
|
|
eras[i2].since = date.valueOf();
|
|
break;
|
|
}
|
|
switch (typeof eras[i2].until) {
|
|
case "undefined":
|
|
eras[i2].until = Infinity;
|
|
break;
|
|
case "string":
|
|
date = hooks(eras[i2].until).startOf("day").valueOf();
|
|
eras[i2].until = date.valueOf();
|
|
break;
|
|
}
|
|
}
|
|
return eras;
|
|
}
|
|
function localeErasParse(eraName, format2, strict) {
|
|
var i2, l2, eras = this.eras(), name, abbr, narrow;
|
|
eraName = eraName.toUpperCase();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
name = eras[i2].name.toUpperCase();
|
|
abbr = eras[i2].abbr.toUpperCase();
|
|
narrow = eras[i2].narrow.toUpperCase();
|
|
if (strict) {
|
|
switch (format2) {
|
|
case "N":
|
|
case "NN":
|
|
case "NNN":
|
|
if (abbr === eraName) {
|
|
return eras[i2];
|
|
}
|
|
break;
|
|
case "NNNN":
|
|
if (name === eraName) {
|
|
return eras[i2];
|
|
}
|
|
break;
|
|
case "NNNNN":
|
|
if (narrow === eraName) {
|
|
return eras[i2];
|
|
}
|
|
break;
|
|
}
|
|
} else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
|
|
return eras[i2];
|
|
}
|
|
}
|
|
}
|
|
function localeErasConvertYear(era, year) {
|
|
var dir = era.since <= era.until ? 1 : -1;
|
|
if (year === void 0) {
|
|
return hooks(era.since).year();
|
|
} else {
|
|
return hooks(era.since).year() + (year - era.offset) * dir;
|
|
}
|
|
}
|
|
function getEraName() {
|
|
var i2, l2, val, eras = this.localeData().eras();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
val = this.clone().startOf("day").valueOf();
|
|
if (eras[i2].since <= val && val <= eras[i2].until) {
|
|
return eras[i2].name;
|
|
}
|
|
if (eras[i2].until <= val && val <= eras[i2].since) {
|
|
return eras[i2].name;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
function getEraNarrow() {
|
|
var i2, l2, val, eras = this.localeData().eras();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
val = this.clone().startOf("day").valueOf();
|
|
if (eras[i2].since <= val && val <= eras[i2].until) {
|
|
return eras[i2].narrow;
|
|
}
|
|
if (eras[i2].until <= val && val <= eras[i2].since) {
|
|
return eras[i2].narrow;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
function getEraAbbr() {
|
|
var i2, l2, val, eras = this.localeData().eras();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
val = this.clone().startOf("day").valueOf();
|
|
if (eras[i2].since <= val && val <= eras[i2].until) {
|
|
return eras[i2].abbr;
|
|
}
|
|
if (eras[i2].until <= val && val <= eras[i2].since) {
|
|
return eras[i2].abbr;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
function getEraYear() {
|
|
var i2, l2, dir, val, eras = this.localeData().eras();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
dir = eras[i2].since <= eras[i2].until ? 1 : -1;
|
|
val = this.clone().startOf("day").valueOf();
|
|
if (eras[i2].since <= val && val <= eras[i2].until || eras[i2].until <= val && val <= eras[i2].since) {
|
|
return (this.year() - hooks(eras[i2].since).year()) * dir + eras[i2].offset;
|
|
}
|
|
}
|
|
return this.year();
|
|
}
|
|
function erasNameRegex(isStrict) {
|
|
if (!hasOwnProp(this, "_erasNameRegex")) {
|
|
computeErasParse.call(this);
|
|
}
|
|
return isStrict ? this._erasNameRegex : this._erasRegex;
|
|
}
|
|
function erasAbbrRegex(isStrict) {
|
|
if (!hasOwnProp(this, "_erasAbbrRegex")) {
|
|
computeErasParse.call(this);
|
|
}
|
|
return isStrict ? this._erasAbbrRegex : this._erasRegex;
|
|
}
|
|
function erasNarrowRegex(isStrict) {
|
|
if (!hasOwnProp(this, "_erasNarrowRegex")) {
|
|
computeErasParse.call(this);
|
|
}
|
|
return isStrict ? this._erasNarrowRegex : this._erasRegex;
|
|
}
|
|
function matchEraAbbr(isStrict, locale3) {
|
|
return locale3.erasAbbrRegex(isStrict);
|
|
}
|
|
function matchEraName(isStrict, locale3) {
|
|
return locale3.erasNameRegex(isStrict);
|
|
}
|
|
function matchEraNarrow(isStrict, locale3) {
|
|
return locale3.erasNarrowRegex(isStrict);
|
|
}
|
|
function matchEraYearOrdinal(isStrict, locale3) {
|
|
return locale3._eraYearOrdinalRegex || matchUnsigned;
|
|
}
|
|
function computeErasParse() {
|
|
var abbrPieces = [], namePieces = [], narrowPieces = [], mixedPieces = [], i2, l2, erasName, erasAbbr, erasNarrow, eras = this.eras();
|
|
for (i2 = 0, l2 = eras.length; i2 < l2; ++i2) {
|
|
erasName = regexEscape(eras[i2].name);
|
|
erasAbbr = regexEscape(eras[i2].abbr);
|
|
erasNarrow = regexEscape(eras[i2].narrow);
|
|
namePieces.push(erasName);
|
|
abbrPieces.push(erasAbbr);
|
|
narrowPieces.push(erasNarrow);
|
|
mixedPieces.push(erasName);
|
|
mixedPieces.push(erasAbbr);
|
|
mixedPieces.push(erasNarrow);
|
|
}
|
|
this._erasRegex = new RegExp("^(" + mixedPieces.join("|") + ")", "i");
|
|
this._erasNameRegex = new RegExp("^(" + namePieces.join("|") + ")", "i");
|
|
this._erasAbbrRegex = new RegExp("^(" + abbrPieces.join("|") + ")", "i");
|
|
this._erasNarrowRegex = new RegExp(
|
|
"^(" + narrowPieces.join("|") + ")",
|
|
"i"
|
|
);
|
|
}
|
|
addFormatToken(0, ["gg", 2], 0, function() {
|
|
return this.weekYear() % 100;
|
|
});
|
|
addFormatToken(0, ["GG", 2], 0, function() {
|
|
return this.isoWeekYear() % 100;
|
|
});
|
|
function addWeekYearFormatToken(token2, getter) {
|
|
addFormatToken(0, [token2, token2.length], 0, getter);
|
|
}
|
|
addWeekYearFormatToken("gggg", "weekYear");
|
|
addWeekYearFormatToken("ggggg", "weekYear");
|
|
addWeekYearFormatToken("GGGG", "isoWeekYear");
|
|
addWeekYearFormatToken("GGGGG", "isoWeekYear");
|
|
addRegexToken("G", matchSigned);
|
|
addRegexToken("g", matchSigned);
|
|
addRegexToken("GG", match1to2, match2);
|
|
addRegexToken("gg", match1to2, match2);
|
|
addRegexToken("GGGG", match1to4, match4);
|
|
addRegexToken("gggg", match1to4, match4);
|
|
addRegexToken("GGGGG", match1to6, match6);
|
|
addRegexToken("ggggg", match1to6, match6);
|
|
addWeekParseToken(
|
|
["gggg", "ggggg", "GGGG", "GGGGG"],
|
|
function(input, week, config, token2) {
|
|
week[token2.substr(0, 2)] = toInt(input);
|
|
}
|
|
);
|
|
addWeekParseToken(["gg", "GG"], function(input, week, config, token2) {
|
|
week[token2] = hooks.parseTwoDigitYear(input);
|
|
});
|
|
function getSetWeekYear(input) {
|
|
return getSetWeekYearHelper.call(
|
|
this,
|
|
input,
|
|
this.week(),
|
|
this.weekday() + this.localeData()._week.dow,
|
|
this.localeData()._week.dow,
|
|
this.localeData()._week.doy
|
|
);
|
|
}
|
|
function getSetISOWeekYear(input) {
|
|
return getSetWeekYearHelper.call(
|
|
this,
|
|
input,
|
|
this.isoWeek(),
|
|
this.isoWeekday(),
|
|
1,
|
|
4
|
|
);
|
|
}
|
|
function getISOWeeksInYear() {
|
|
return weeksInYear(this.year(), 1, 4);
|
|
}
|
|
function getISOWeeksInISOWeekYear() {
|
|
return weeksInYear(this.isoWeekYear(), 1, 4);
|
|
}
|
|
function getWeeksInYear() {
|
|
var weekInfo = this.localeData()._week;
|
|
return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
|
|
}
|
|
function getWeeksInWeekYear() {
|
|
var weekInfo = this.localeData()._week;
|
|
return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy);
|
|
}
|
|
function getSetWeekYearHelper(input, week, weekday, dow, doy) {
|
|
var weeksTarget;
|
|
if (input == null) {
|
|
return weekOfYear(this, dow, doy).year;
|
|
} else {
|
|
weeksTarget = weeksInYear(input, dow, doy);
|
|
if (week > weeksTarget) {
|
|
week = weeksTarget;
|
|
}
|
|
return setWeekAll.call(this, input, week, weekday, dow, doy);
|
|
}
|
|
}
|
|
function setWeekAll(weekYear, week, weekday, dow, doy) {
|
|
var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
|
|
this.year(date.getUTCFullYear());
|
|
this.month(date.getUTCMonth());
|
|
this.date(date.getUTCDate());
|
|
return this;
|
|
}
|
|
addFormatToken("Q", 0, "Qo", "quarter");
|
|
addRegexToken("Q", match1);
|
|
addParseToken("Q", function(input, array) {
|
|
array[MONTH] = (toInt(input) - 1) * 3;
|
|
});
|
|
function getSetQuarter(input) {
|
|
return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
|
|
}
|
|
addFormatToken("D", ["DD", 2], "Do", "date");
|
|
addRegexToken("D", match1to2, match1to2NoLeadingZero);
|
|
addRegexToken("DD", match1to2, match2);
|
|
addRegexToken("Do", function(isStrict, locale3) {
|
|
return isStrict ? locale3._dayOfMonthOrdinalParse || locale3._ordinalParse : locale3._dayOfMonthOrdinalParseLenient;
|
|
});
|
|
addParseToken(["D", "DD"], DATE);
|
|
addParseToken("Do", function(input, array) {
|
|
array[DATE] = toInt(input.match(match1to2)[0]);
|
|
});
|
|
var getSetDayOfMonth = makeGetSet("Date", true);
|
|
addFormatToken("DDD", ["DDDD", 3], "DDDo", "dayOfYear");
|
|
addRegexToken("DDD", match1to3);
|
|
addRegexToken("DDDD", match3);
|
|
addParseToken(["DDD", "DDDD"], function(input, array, config) {
|
|
config._dayOfYear = toInt(input);
|
|
});
|
|
function getSetDayOfYear(input) {
|
|
var dayOfYear = Math.round(
|
|
(this.clone().startOf("day") - this.clone().startOf("year")) / 864e5
|
|
) + 1;
|
|
return input == null ? dayOfYear : this.add(input - dayOfYear, "d");
|
|
}
|
|
addFormatToken("m", ["mm", 2], 0, "minute");
|
|
addRegexToken("m", match1to2, match1to2HasZero);
|
|
addRegexToken("mm", match1to2, match2);
|
|
addParseToken(["m", "mm"], MINUTE);
|
|
var getSetMinute = makeGetSet("Minutes", false);
|
|
addFormatToken("s", ["ss", 2], 0, "second");
|
|
addRegexToken("s", match1to2, match1to2HasZero);
|
|
addRegexToken("ss", match1to2, match2);
|
|
addParseToken(["s", "ss"], SECOND);
|
|
var getSetSecond = makeGetSet("Seconds", false);
|
|
addFormatToken("S", 0, 0, function() {
|
|
return ~~(this.millisecond() / 100);
|
|
});
|
|
addFormatToken(0, ["SS", 2], 0, function() {
|
|
return ~~(this.millisecond() / 10);
|
|
});
|
|
addFormatToken(0, ["SSS", 3], 0, "millisecond");
|
|
addFormatToken(0, ["SSSS", 4], 0, function() {
|
|
return this.millisecond() * 10;
|
|
});
|
|
addFormatToken(0, ["SSSSS", 5], 0, function() {
|
|
return this.millisecond() * 100;
|
|
});
|
|
addFormatToken(0, ["SSSSSS", 6], 0, function() {
|
|
return this.millisecond() * 1e3;
|
|
});
|
|
addFormatToken(0, ["SSSSSSS", 7], 0, function() {
|
|
return this.millisecond() * 1e4;
|
|
});
|
|
addFormatToken(0, ["SSSSSSSS", 8], 0, function() {
|
|
return this.millisecond() * 1e5;
|
|
});
|
|
addFormatToken(0, ["SSSSSSSSS", 9], 0, function() {
|
|
return this.millisecond() * 1e6;
|
|
});
|
|
addRegexToken("S", match1to3, match1);
|
|
addRegexToken("SS", match1to3, match2);
|
|
addRegexToken("SSS", match1to3, match3);
|
|
var token, getSetMillisecond;
|
|
for (token = "SSSS"; token.length <= 9; token += "S") {
|
|
addRegexToken(token, matchUnsigned);
|
|
}
|
|
function parseMs(input, array) {
|
|
array[MILLISECOND] = toInt(("0." + input) * 1e3);
|
|
}
|
|
for (token = "S"; token.length <= 9; token += "S") {
|
|
addParseToken(token, parseMs);
|
|
}
|
|
getSetMillisecond = makeGetSet("Milliseconds", false);
|
|
addFormatToken("z", 0, 0, "zoneAbbr");
|
|
addFormatToken("zz", 0, 0, "zoneName");
|
|
function getZoneAbbr() {
|
|
return this._isUTC ? "UTC" : "";
|
|
}
|
|
function getZoneName() {
|
|
return this._isUTC ? "Coordinated Universal Time" : "";
|
|
}
|
|
var proto = Moment3.prototype;
|
|
proto.add = add;
|
|
proto.calendar = calendar$1;
|
|
proto.clone = clone3;
|
|
proto.diff = diff;
|
|
proto.endOf = endOf;
|
|
proto.format = format;
|
|
proto.from = from2;
|
|
proto.fromNow = fromNow;
|
|
proto.to = to2;
|
|
proto.toNow = toNow;
|
|
proto.get = stringGet;
|
|
proto.invalidAt = invalidAt;
|
|
proto.isAfter = isAfter;
|
|
proto.isBefore = isBefore;
|
|
proto.isBetween = isBetween;
|
|
proto.isSame = isSame;
|
|
proto.isSameOrAfter = isSameOrAfter;
|
|
proto.isSameOrBefore = isSameOrBefore;
|
|
proto.isValid = isValid$2;
|
|
proto.lang = lang;
|
|
proto.locale = locale2;
|
|
proto.localeData = localeData;
|
|
proto.max = prototypeMax;
|
|
proto.min = prototypeMin;
|
|
proto.parsingFlags = parsingFlags;
|
|
proto.set = stringSet;
|
|
proto.startOf = startOf;
|
|
proto.subtract = subtract;
|
|
proto.toArray = toArray;
|
|
proto.toObject = toObject;
|
|
proto.toDate = toDate;
|
|
proto.toISOString = toISOString;
|
|
proto.inspect = inspect;
|
|
if (typeof Symbol !== "undefined" && Symbol.for != null) {
|
|
proto[Symbol.for("nodejs.util.inspect.custom")] = function() {
|
|
return "Moment<" + this.format() + ">";
|
|
};
|
|
}
|
|
proto.toJSON = toJSON;
|
|
proto.toString = toString;
|
|
proto.unix = unix;
|
|
proto.valueOf = valueOf;
|
|
proto.creationData = creationData;
|
|
proto.eraName = getEraName;
|
|
proto.eraNarrow = getEraNarrow;
|
|
proto.eraAbbr = getEraAbbr;
|
|
proto.eraYear = getEraYear;
|
|
proto.year = getSetYear;
|
|
proto.isLeapYear = getIsLeapYear;
|
|
proto.weekYear = getSetWeekYear;
|
|
proto.isoWeekYear = getSetISOWeekYear;
|
|
proto.quarter = proto.quarters = getSetQuarter;
|
|
proto.month = getSetMonth;
|
|
proto.daysInMonth = getDaysInMonth;
|
|
proto.week = proto.weeks = getSetWeek;
|
|
proto.isoWeek = proto.isoWeeks = getSetISOWeek;
|
|
proto.weeksInYear = getWeeksInYear;
|
|
proto.weeksInWeekYear = getWeeksInWeekYear;
|
|
proto.isoWeeksInYear = getISOWeeksInYear;
|
|
proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear;
|
|
proto.date = getSetDayOfMonth;
|
|
proto.day = proto.days = getSetDayOfWeek;
|
|
proto.weekday = getSetLocaleDayOfWeek;
|
|
proto.isoWeekday = getSetISODayOfWeek;
|
|
proto.dayOfYear = getSetDayOfYear;
|
|
proto.hour = proto.hours = getSetHour;
|
|
proto.minute = proto.minutes = getSetMinute;
|
|
proto.second = proto.seconds = getSetSecond;
|
|
proto.millisecond = proto.milliseconds = getSetMillisecond;
|
|
proto.utcOffset = getSetOffset;
|
|
proto.utc = setOffsetToUTC;
|
|
proto.local = setOffsetToLocal;
|
|
proto.parseZone = setOffsetToParsedOffset;
|
|
proto.hasAlignedHourOffset = hasAlignedHourOffset;
|
|
proto.isDST = isDaylightSavingTime;
|
|
proto.isLocal = isLocal;
|
|
proto.isUtcOffset = isUtcOffset;
|
|
proto.isUtc = isUtc;
|
|
proto.isUTC = isUtc;
|
|
proto.zoneAbbr = getZoneAbbr;
|
|
proto.zoneName = getZoneName;
|
|
proto.dates = deprecate(
|
|
"dates accessor is deprecated. Use date instead.",
|
|
getSetDayOfMonth
|
|
);
|
|
proto.months = deprecate(
|
|
"months accessor is deprecated. Use month instead",
|
|
getSetMonth
|
|
);
|
|
proto.years = deprecate(
|
|
"years accessor is deprecated. Use year instead",
|
|
getSetYear
|
|
);
|
|
proto.zone = deprecate(
|
|
"moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",
|
|
getSetZone
|
|
);
|
|
proto.isDSTShifted = deprecate(
|
|
"isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",
|
|
isDaylightSavingTimeShifted
|
|
);
|
|
function createUnix(input) {
|
|
return createLocal(input * 1e3);
|
|
}
|
|
function createInZone() {
|
|
return createLocal.apply(null, arguments).parseZone();
|
|
}
|
|
function preParsePostFormat(string) {
|
|
return string;
|
|
}
|
|
var proto$1 = Locale.prototype;
|
|
proto$1.calendar = calendar;
|
|
proto$1.longDateFormat = longDateFormat;
|
|
proto$1.invalidDate = invalidDate;
|
|
proto$1.ordinal = ordinal;
|
|
proto$1.preparse = preParsePostFormat;
|
|
proto$1.postformat = preParsePostFormat;
|
|
proto$1.relativeTime = relativeTime;
|
|
proto$1.pastFuture = pastFuture;
|
|
proto$1.set = set2;
|
|
proto$1.eras = localeEras;
|
|
proto$1.erasParse = localeErasParse;
|
|
proto$1.erasConvertYear = localeErasConvertYear;
|
|
proto$1.erasAbbrRegex = erasAbbrRegex;
|
|
proto$1.erasNameRegex = erasNameRegex;
|
|
proto$1.erasNarrowRegex = erasNarrowRegex;
|
|
proto$1.months = localeMonths;
|
|
proto$1.monthsShort = localeMonthsShort;
|
|
proto$1.monthsParse = localeMonthsParse;
|
|
proto$1.monthsRegex = monthsRegex;
|
|
proto$1.monthsShortRegex = monthsShortRegex;
|
|
proto$1.week = localeWeek;
|
|
proto$1.firstDayOfYear = localeFirstDayOfYear;
|
|
proto$1.firstDayOfWeek = localeFirstDayOfWeek;
|
|
proto$1.weekdays = localeWeekdays;
|
|
proto$1.weekdaysMin = localeWeekdaysMin;
|
|
proto$1.weekdaysShort = localeWeekdaysShort;
|
|
proto$1.weekdaysParse = localeWeekdaysParse;
|
|
proto$1.weekdaysRegex = weekdaysRegex;
|
|
proto$1.weekdaysShortRegex = weekdaysShortRegex;
|
|
proto$1.weekdaysMinRegex = weekdaysMinRegex;
|
|
proto$1.isPM = localeIsPM;
|
|
proto$1.meridiem = localeMeridiem;
|
|
function get$1(format2, index, field, setter) {
|
|
var locale3 = getLocale(), utc = createUTC().set(setter, index);
|
|
return locale3[field](utc, format2);
|
|
}
|
|
function listMonthsImpl(format2, index, field) {
|
|
if (isNumber2(format2)) {
|
|
index = format2;
|
|
format2 = void 0;
|
|
}
|
|
format2 = format2 || "";
|
|
if (index != null) {
|
|
return get$1(format2, index, field, "month");
|
|
}
|
|
var i2, out = [];
|
|
for (i2 = 0; i2 < 12; i2++) {
|
|
out[i2] = get$1(format2, i2, field, "month");
|
|
}
|
|
return out;
|
|
}
|
|
function listWeekdaysImpl(localeSorted, format2, index, field) {
|
|
if (typeof localeSorted === "boolean") {
|
|
if (isNumber2(format2)) {
|
|
index = format2;
|
|
format2 = void 0;
|
|
}
|
|
format2 = format2 || "";
|
|
} else {
|
|
format2 = localeSorted;
|
|
index = format2;
|
|
localeSorted = false;
|
|
if (isNumber2(format2)) {
|
|
index = format2;
|
|
format2 = void 0;
|
|
}
|
|
format2 = format2 || "";
|
|
}
|
|
var locale3 = getLocale(), shift = localeSorted ? locale3._week.dow : 0, i2, out = [];
|
|
if (index != null) {
|
|
return get$1(format2, (index + shift) % 7, field, "day");
|
|
}
|
|
for (i2 = 0; i2 < 7; i2++) {
|
|
out[i2] = get$1(format2, (i2 + shift) % 7, field, "day");
|
|
}
|
|
return out;
|
|
}
|
|
function listMonths(format2, index) {
|
|
return listMonthsImpl(format2, index, "months");
|
|
}
|
|
function listMonthsShort(format2, index) {
|
|
return listMonthsImpl(format2, index, "monthsShort");
|
|
}
|
|
function listWeekdays(localeSorted, format2, index) {
|
|
return listWeekdaysImpl(localeSorted, format2, index, "weekdays");
|
|
}
|
|
function listWeekdaysShort(localeSorted, format2, index) {
|
|
return listWeekdaysImpl(localeSorted, format2, index, "weekdaysShort");
|
|
}
|
|
function listWeekdaysMin(localeSorted, format2, index) {
|
|
return listWeekdaysImpl(localeSorted, format2, index, "weekdaysMin");
|
|
}
|
|
getSetGlobalLocale("en", {
|
|
eras: [
|
|
{
|
|
since: "0001-01-01",
|
|
until: Infinity,
|
|
offset: 1,
|
|
name: "Anno Domini",
|
|
narrow: "AD",
|
|
abbr: "AD"
|
|
},
|
|
{
|
|
since: "0000-12-31",
|
|
until: -Infinity,
|
|
offset: 1,
|
|
name: "Before Christ",
|
|
narrow: "BC",
|
|
abbr: "BC"
|
|
}
|
|
],
|
|
dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
|
|
ordinal: function(number) {
|
|
var b2 = number % 10, output = toInt(number % 100 / 10) === 1 ? "th" : b2 === 1 ? "st" : b2 === 2 ? "nd" : b2 === 3 ? "rd" : "th";
|
|
return number + output;
|
|
}
|
|
});
|
|
hooks.lang = deprecate(
|
|
"moment.lang is deprecated. Use moment.locale instead.",
|
|
getSetGlobalLocale
|
|
);
|
|
hooks.langData = deprecate(
|
|
"moment.langData is deprecated. Use moment.localeData instead.",
|
|
getLocale
|
|
);
|
|
var mathAbs = Math.abs;
|
|
function abs() {
|
|
var data = this._data;
|
|
this._milliseconds = mathAbs(this._milliseconds);
|
|
this._days = mathAbs(this._days);
|
|
this._months = mathAbs(this._months);
|
|
data.milliseconds = mathAbs(data.milliseconds);
|
|
data.seconds = mathAbs(data.seconds);
|
|
data.minutes = mathAbs(data.minutes);
|
|
data.hours = mathAbs(data.hours);
|
|
data.months = mathAbs(data.months);
|
|
data.years = mathAbs(data.years);
|
|
return this;
|
|
}
|
|
function addSubtract$1(duration, input, value, direction) {
|
|
var other = createDuration(input, value);
|
|
duration._milliseconds += direction * other._milliseconds;
|
|
duration._days += direction * other._days;
|
|
duration._months += direction * other._months;
|
|
return duration._bubble();
|
|
}
|
|
function add$1(input, value) {
|
|
return addSubtract$1(this, input, value, 1);
|
|
}
|
|
function subtract$1(input, value) {
|
|
return addSubtract$1(this, input, value, -1);
|
|
}
|
|
function absCeil(number) {
|
|
if (number < 0) {
|
|
return Math.floor(number);
|
|
} else {
|
|
return Math.ceil(number);
|
|
}
|
|
}
|
|
function bubble() {
|
|
var milliseconds2 = this._milliseconds, days2 = this._days, months2 = this._months, data = this._data, seconds2, minutes2, hours2, years2, monthsFromDays;
|
|
if (!(milliseconds2 >= 0 && days2 >= 0 && months2 >= 0 || milliseconds2 <= 0 && days2 <= 0 && months2 <= 0)) {
|
|
milliseconds2 += absCeil(monthsToDays(months2) + days2) * 864e5;
|
|
days2 = 0;
|
|
months2 = 0;
|
|
}
|
|
data.milliseconds = milliseconds2 % 1e3;
|
|
seconds2 = absFloor(milliseconds2 / 1e3);
|
|
data.seconds = seconds2 % 60;
|
|
minutes2 = absFloor(seconds2 / 60);
|
|
data.minutes = minutes2 % 60;
|
|
hours2 = absFloor(minutes2 / 60);
|
|
data.hours = hours2 % 24;
|
|
days2 += absFloor(hours2 / 24);
|
|
monthsFromDays = absFloor(daysToMonths(days2));
|
|
months2 += monthsFromDays;
|
|
days2 -= absCeil(monthsToDays(monthsFromDays));
|
|
years2 = absFloor(months2 / 12);
|
|
months2 %= 12;
|
|
data.days = days2;
|
|
data.months = months2;
|
|
data.years = years2;
|
|
return this;
|
|
}
|
|
function daysToMonths(days2) {
|
|
return days2 * 4800 / 146097;
|
|
}
|
|
function monthsToDays(months2) {
|
|
return months2 * 146097 / 4800;
|
|
}
|
|
function as(units) {
|
|
if (!this.isValid()) {
|
|
return NaN;
|
|
}
|
|
var days2, months2, milliseconds2 = this._milliseconds;
|
|
units = normalizeUnits(units);
|
|
if (units === "month" || units === "quarter" || units === "year") {
|
|
days2 = this._days + milliseconds2 / 864e5;
|
|
months2 = this._months + daysToMonths(days2);
|
|
switch (units) {
|
|
case "month":
|
|
return months2;
|
|
case "quarter":
|
|
return months2 / 3;
|
|
case "year":
|
|
return months2 / 12;
|
|
}
|
|
} else {
|
|
days2 = this._days + Math.round(monthsToDays(this._months));
|
|
switch (units) {
|
|
case "week":
|
|
return days2 / 7 + milliseconds2 / 6048e5;
|
|
case "day":
|
|
return days2 + milliseconds2 / 864e5;
|
|
case "hour":
|
|
return days2 * 24 + milliseconds2 / 36e5;
|
|
case "minute":
|
|
return days2 * 1440 + milliseconds2 / 6e4;
|
|
case "second":
|
|
return days2 * 86400 + milliseconds2 / 1e3;
|
|
// Math.floor prevents floating point math errors here
|
|
case "millisecond":
|
|
return Math.floor(days2 * 864e5) + milliseconds2;
|
|
default:
|
|
throw new Error("Unknown unit " + units);
|
|
}
|
|
}
|
|
}
|
|
function makeAs(alias) {
|
|
return function() {
|
|
return this.as(alias);
|
|
};
|
|
}
|
|
var asMilliseconds = makeAs("ms"), asSeconds = makeAs("s"), asMinutes = makeAs("m"), asHours = makeAs("h"), asDays = makeAs("d"), asWeeks = makeAs("w"), asMonths = makeAs("M"), asQuarters = makeAs("Q"), asYears = makeAs("y"), valueOf$1 = asMilliseconds;
|
|
function clone$1() {
|
|
return createDuration(this);
|
|
}
|
|
function get$2(units) {
|
|
units = normalizeUnits(units);
|
|
return this.isValid() ? this[units + "s"]() : NaN;
|
|
}
|
|
function makeGetter(name) {
|
|
return function() {
|
|
return this.isValid() ? this._data[name] : NaN;
|
|
};
|
|
}
|
|
var milliseconds = makeGetter("milliseconds"), seconds = makeGetter("seconds"), minutes = makeGetter("minutes"), hours = makeGetter("hours"), days = makeGetter("days"), months = makeGetter("months"), years = makeGetter("years");
|
|
function weeks() {
|
|
return absFloor(this.days() / 7);
|
|
}
|
|
var round2 = Math.round, thresholds = {
|
|
ss: 44,
|
|
// a few seconds to seconds
|
|
s: 45,
|
|
// seconds to minute
|
|
m: 45,
|
|
// minutes to hour
|
|
h: 22,
|
|
// hours to day
|
|
d: 26,
|
|
// days to month/week
|
|
w: null,
|
|
// weeks to month
|
|
M: 11
|
|
// months to year
|
|
};
|
|
function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale3) {
|
|
return locale3.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
|
|
}
|
|
function relativeTime$1(posNegDuration, withoutSuffix, thresholds2, locale3) {
|
|
var duration = createDuration(posNegDuration).abs(), seconds2 = round2(duration.as("s")), minutes2 = round2(duration.as("m")), hours2 = round2(duration.as("h")), days2 = round2(duration.as("d")), months2 = round2(duration.as("M")), weeks2 = round2(duration.as("w")), years2 = round2(duration.as("y")), a2 = seconds2 <= thresholds2.ss && ["s", seconds2] || seconds2 < thresholds2.s && ["ss", seconds2] || minutes2 <= 1 && ["m"] || minutes2 < thresholds2.m && ["mm", minutes2] || hours2 <= 1 && ["h"] || hours2 < thresholds2.h && ["hh", hours2] || days2 <= 1 && ["d"] || days2 < thresholds2.d && ["dd", days2];
|
|
if (thresholds2.w != null) {
|
|
a2 = a2 || weeks2 <= 1 && ["w"] || weeks2 < thresholds2.w && ["ww", weeks2];
|
|
}
|
|
a2 = a2 || months2 <= 1 && ["M"] || months2 < thresholds2.M && ["MM", months2] || years2 <= 1 && ["y"] || ["yy", years2];
|
|
a2[2] = withoutSuffix;
|
|
a2[3] = +posNegDuration > 0;
|
|
a2[4] = locale3;
|
|
return substituteTimeAgo.apply(null, a2);
|
|
}
|
|
function getSetRelativeTimeRounding(roundingFunction) {
|
|
if (roundingFunction === void 0) {
|
|
return round2;
|
|
}
|
|
if (typeof roundingFunction === "function") {
|
|
round2 = roundingFunction;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function getSetRelativeTimeThreshold(threshold, limit) {
|
|
if (thresholds[threshold] === void 0) {
|
|
return false;
|
|
}
|
|
if (limit === void 0) {
|
|
return thresholds[threshold];
|
|
}
|
|
thresholds[threshold] = limit;
|
|
if (threshold === "s") {
|
|
thresholds.ss = limit - 1;
|
|
}
|
|
return true;
|
|
}
|
|
function humanize(argWithSuffix, argThresholds) {
|
|
if (!this.isValid()) {
|
|
return this.localeData().invalidDate();
|
|
}
|
|
var withSuffix = false, th = thresholds, locale3, output;
|
|
if (typeof argWithSuffix === "object") {
|
|
argThresholds = argWithSuffix;
|
|
argWithSuffix = false;
|
|
}
|
|
if (typeof argWithSuffix === "boolean") {
|
|
withSuffix = argWithSuffix;
|
|
}
|
|
if (typeof argThresholds === "object") {
|
|
th = Object.assign({}, thresholds, argThresholds);
|
|
if (argThresholds.s != null && argThresholds.ss == null) {
|
|
th.ss = argThresholds.s - 1;
|
|
}
|
|
}
|
|
locale3 = this.localeData();
|
|
output = relativeTime$1(this, !withSuffix, th, locale3);
|
|
if (withSuffix) {
|
|
output = locale3.pastFuture(+this, output);
|
|
}
|
|
return locale3.postformat(output);
|
|
}
|
|
var abs$1 = Math.abs;
|
|
function sign2(x2) {
|
|
return (x2 > 0) - (x2 < 0) || +x2;
|
|
}
|
|
function toISOString$1() {
|
|
if (!this.isValid()) {
|
|
return this.localeData().invalidDate();
|
|
}
|
|
var seconds2 = abs$1(this._milliseconds) / 1e3, days2 = abs$1(this._days), months2 = abs$1(this._months), minutes2, hours2, years2, s2, total = this.asSeconds(), totalSign, ymSign, daysSign, hmsSign;
|
|
if (!total) {
|
|
return "P0D";
|
|
}
|
|
minutes2 = absFloor(seconds2 / 60);
|
|
hours2 = absFloor(minutes2 / 60);
|
|
seconds2 %= 60;
|
|
minutes2 %= 60;
|
|
years2 = absFloor(months2 / 12);
|
|
months2 %= 12;
|
|
s2 = seconds2 ? seconds2.toFixed(3).replace(/\.?0+$/, "") : "";
|
|
totalSign = total < 0 ? "-" : "";
|
|
ymSign = sign2(this._months) !== sign2(total) ? "-" : "";
|
|
daysSign = sign2(this._days) !== sign2(total) ? "-" : "";
|
|
hmsSign = sign2(this._milliseconds) !== sign2(total) ? "-" : "";
|
|
return totalSign + "P" + (years2 ? ymSign + years2 + "Y" : "") + (months2 ? ymSign + months2 + "M" : "") + (days2 ? daysSign + days2 + "D" : "") + (hours2 || minutes2 || seconds2 ? "T" : "") + (hours2 ? hmsSign + hours2 + "H" : "") + (minutes2 ? hmsSign + minutes2 + "M" : "") + (seconds2 ? hmsSign + s2 + "S" : "");
|
|
}
|
|
var proto$2 = Duration.prototype;
|
|
proto$2.isValid = isValid$1;
|
|
proto$2.abs = abs;
|
|
proto$2.add = add$1;
|
|
proto$2.subtract = subtract$1;
|
|
proto$2.as = as;
|
|
proto$2.asMilliseconds = asMilliseconds;
|
|
proto$2.asSeconds = asSeconds;
|
|
proto$2.asMinutes = asMinutes;
|
|
proto$2.asHours = asHours;
|
|
proto$2.asDays = asDays;
|
|
proto$2.asWeeks = asWeeks;
|
|
proto$2.asMonths = asMonths;
|
|
proto$2.asQuarters = asQuarters;
|
|
proto$2.asYears = asYears;
|
|
proto$2.valueOf = valueOf$1;
|
|
proto$2._bubble = bubble;
|
|
proto$2.clone = clone$1;
|
|
proto$2.get = get$2;
|
|
proto$2.milliseconds = milliseconds;
|
|
proto$2.seconds = seconds;
|
|
proto$2.minutes = minutes;
|
|
proto$2.hours = hours;
|
|
proto$2.days = days;
|
|
proto$2.weeks = weeks;
|
|
proto$2.months = months;
|
|
proto$2.years = years;
|
|
proto$2.humanize = humanize;
|
|
proto$2.toISOString = toISOString$1;
|
|
proto$2.toString = toISOString$1;
|
|
proto$2.toJSON = toISOString$1;
|
|
proto$2.locale = locale2;
|
|
proto$2.localeData = localeData;
|
|
proto$2.toIsoString = deprecate(
|
|
"toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",
|
|
toISOString$1
|
|
);
|
|
proto$2.lang = lang;
|
|
addFormatToken("X", 0, 0, "unix");
|
|
addFormatToken("x", 0, 0, "valueOf");
|
|
addRegexToken("x", matchSigned);
|
|
addRegexToken("X", matchTimestamp);
|
|
addParseToken("X", function(input, array, config) {
|
|
config._d = new Date(parseFloat(input) * 1e3);
|
|
});
|
|
addParseToken("x", function(input, array, config) {
|
|
config._d = new Date(toInt(input));
|
|
});
|
|
hooks.version = "2.30.1";
|
|
setHookCallback(createLocal);
|
|
hooks.fn = proto;
|
|
hooks.min = min;
|
|
hooks.max = max;
|
|
hooks.now = now2;
|
|
hooks.utc = createUTC;
|
|
hooks.unix = createUnix;
|
|
hooks.months = listMonths;
|
|
hooks.isDate = isDate;
|
|
hooks.locale = getSetGlobalLocale;
|
|
hooks.invalid = createInvalid;
|
|
hooks.duration = createDuration;
|
|
hooks.isMoment = isMoment;
|
|
hooks.weekdays = listWeekdays;
|
|
hooks.parseZone = createInZone;
|
|
hooks.localeData = getLocale;
|
|
hooks.isDuration = isDuration;
|
|
hooks.monthsShort = listMonthsShort;
|
|
hooks.weekdaysMin = listWeekdaysMin;
|
|
hooks.defineLocale = defineLocale;
|
|
hooks.updateLocale = updateLocale;
|
|
hooks.locales = listLocales;
|
|
hooks.weekdaysShort = listWeekdaysShort;
|
|
hooks.normalizeUnits = normalizeUnits;
|
|
hooks.relativeTimeRounding = getSetRelativeTimeRounding;
|
|
hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
|
|
hooks.calendarFormat = getCalendarFormat;
|
|
hooks.prototype = proto;
|
|
hooks.HTML5_FMT = {
|
|
DATETIME_LOCAL: "YYYY-MM-DDTHH:mm",
|
|
// <input type="datetime-local" />
|
|
DATETIME_LOCAL_SECONDS: "YYYY-MM-DDTHH:mm:ss",
|
|
// <input type="datetime-local" step="1" />
|
|
DATETIME_LOCAL_MS: "YYYY-MM-DDTHH:mm:ss.SSS",
|
|
// <input type="datetime-local" step="0.001" />
|
|
DATE: "YYYY-MM-DD",
|
|
// <input type="date" />
|
|
TIME: "HH:mm",
|
|
// <input type="time" />
|
|
TIME_SECONDS: "HH:mm:ss",
|
|
// <input type="time" step="1" />
|
|
TIME_MS: "HH:mm:ss.SSS",
|
|
// <input type="time" step="0.001" />
|
|
WEEK: "GGGG-[W]WW",
|
|
// <input type="week" />
|
|
MONTH: "YYYY-MM"
|
|
// <input type="month" />
|
|
};
|
|
return hooks;
|
|
});
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/pagerank.js@1.0.2/node_modules/pagerank.js/lib/index.js
|
|
var require_lib = __commonJS({
|
|
"node_modules/.pnpm/pagerank.js@1.0.2/node_modules/pagerank.js/lib/index.js"(exports, module2) {
|
|
"use strict";
|
|
function forOwn(object, callback2) {
|
|
if (typeof object === "object" && typeof callback2 === "function") {
|
|
for (var key in object) {
|
|
if (object.hasOwnProperty(key) === true) {
|
|
if (callback2(key, object[key]) === false) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
module2.exports = function() {
|
|
var self = {
|
|
count: 0,
|
|
edges: {},
|
|
nodes: {}
|
|
};
|
|
self.link = function(source, target, weight) {
|
|
if (isFinite(weight) !== true || weight === null) {
|
|
weight = 1;
|
|
}
|
|
weight = parseFloat(weight);
|
|
if (self.nodes.hasOwnProperty(source) !== true) {
|
|
self.count++;
|
|
self.nodes[source] = {
|
|
weight: 0,
|
|
outbound: 0
|
|
};
|
|
}
|
|
self.nodes[source].outbound += weight;
|
|
if (self.nodes.hasOwnProperty(target) !== true) {
|
|
self.count++;
|
|
self.nodes[target] = {
|
|
weight: 0,
|
|
outbound: 0
|
|
};
|
|
}
|
|
if (self.edges.hasOwnProperty(source) !== true) {
|
|
self.edges[source] = {};
|
|
}
|
|
if (self.edges[source].hasOwnProperty(target) !== true) {
|
|
self.edges[source][target] = 0;
|
|
}
|
|
self.edges[source][target] += weight;
|
|
};
|
|
self.rank = function(alpha2, epsilon, callback2) {
|
|
var delta = 1, inverse = 1 / self.count;
|
|
forOwn(self.edges, function(source) {
|
|
if (self.nodes[source].outbound > 0) {
|
|
forOwn(self.edges[source], function(target) {
|
|
self.edges[source][target] /= self.nodes[source].outbound;
|
|
});
|
|
}
|
|
});
|
|
forOwn(self.nodes, function(key) {
|
|
self.nodes[key].weight = inverse;
|
|
});
|
|
while (delta > epsilon) {
|
|
var leak = 0, nodes = {};
|
|
forOwn(self.nodes, function(key, value) {
|
|
nodes[key] = value.weight;
|
|
if (value.outbound === 0) {
|
|
leak += value.weight;
|
|
}
|
|
self.nodes[key].weight = 0;
|
|
});
|
|
leak *= alpha2;
|
|
forOwn(self.nodes, function(source) {
|
|
forOwn(self.edges[source], function(target, weight) {
|
|
self.nodes[target].weight += alpha2 * nodes[source] * weight;
|
|
});
|
|
self.nodes[source].weight += (1 - alpha2) * inverse + leak * inverse;
|
|
});
|
|
delta = 0;
|
|
forOwn(self.nodes, function(key, value) {
|
|
delta += Math.abs(value.weight - nodes[key]);
|
|
});
|
|
}
|
|
forOwn(self.nodes, function(key) {
|
|
return callback2(key, self.nodes[key].weight);
|
|
});
|
|
};
|
|
self.reset = function() {
|
|
self.count = 0;
|
|
self.edges = {};
|
|
self.nodes = {};
|
|
};
|
|
return self;
|
|
}();
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/balanced-match@1.0.2/node_modules/balanced-match/index.js
|
|
var require_balanced_match = __commonJS({
|
|
"node_modules/.pnpm/balanced-match@1.0.2/node_modules/balanced-match/index.js"(exports, module2) {
|
|
"use strict";
|
|
module2.exports = balanced;
|
|
function balanced(a2, b2, str) {
|
|
if (a2 instanceof RegExp) a2 = maybeMatch(a2, str);
|
|
if (b2 instanceof RegExp) b2 = maybeMatch(b2, str);
|
|
var r2 = range(a2, b2, str);
|
|
return r2 && {
|
|
start: r2[0],
|
|
end: r2[1],
|
|
pre: str.slice(0, r2[0]),
|
|
body: str.slice(r2[0] + a2.length, r2[1]),
|
|
post: str.slice(r2[1] + b2.length)
|
|
};
|
|
}
|
|
function maybeMatch(reg, str) {
|
|
var m2 = str.match(reg);
|
|
return m2 ? m2[0] : null;
|
|
}
|
|
balanced.range = range;
|
|
function range(a2, b2, str) {
|
|
var begs, beg, left, right, result;
|
|
var ai = str.indexOf(a2);
|
|
var bi = str.indexOf(b2, ai + 1);
|
|
var i2 = ai;
|
|
if (ai >= 0 && bi > 0) {
|
|
if (a2 === b2) {
|
|
return [ai, bi];
|
|
}
|
|
begs = [];
|
|
left = str.length;
|
|
while (i2 >= 0 && !result) {
|
|
if (i2 == ai) {
|
|
begs.push(i2);
|
|
ai = str.indexOf(a2, i2 + 1);
|
|
} else if (begs.length == 1) {
|
|
result = [begs.pop(), bi];
|
|
} else {
|
|
beg = begs.pop();
|
|
if (beg < left) {
|
|
left = beg;
|
|
right = bi;
|
|
}
|
|
bi = str.indexOf(b2, i2 + 1);
|
|
}
|
|
i2 = ai < bi && ai >= 0 ? ai : bi;
|
|
}
|
|
if (begs.length) {
|
|
result = [left, right];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/brace-expansion@2.0.1/node_modules/brace-expansion/index.js
|
|
var require_brace_expansion = __commonJS({
|
|
"node_modules/.pnpm/brace-expansion@2.0.1/node_modules/brace-expansion/index.js"(exports, module2) {
|
|
var balanced = require_balanced_match();
|
|
module2.exports = expandTop;
|
|
var escSlash = "\0SLASH" + Math.random() + "\0";
|
|
var escOpen = "\0OPEN" + Math.random() + "\0";
|
|
var escClose = "\0CLOSE" + Math.random() + "\0";
|
|
var escComma = "\0COMMA" + Math.random() + "\0";
|
|
var escPeriod = "\0PERIOD" + Math.random() + "\0";
|
|
function numeric(str) {
|
|
return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);
|
|
}
|
|
function escapeBraces(str) {
|
|
return str.split("\\\\").join(escSlash).split("\\{").join(escOpen).split("\\}").join(escClose).split("\\,").join(escComma).split("\\.").join(escPeriod);
|
|
}
|
|
function unescapeBraces(str) {
|
|
return str.split(escSlash).join("\\").split(escOpen).join("{").split(escClose).join("}").split(escComma).join(",").split(escPeriod).join(".");
|
|
}
|
|
function parseCommaParts(str) {
|
|
if (!str)
|
|
return [""];
|
|
var parts = [];
|
|
var m2 = balanced("{", "}", str);
|
|
if (!m2)
|
|
return str.split(",");
|
|
var pre = m2.pre;
|
|
var body = m2.body;
|
|
var post = m2.post;
|
|
var p2 = pre.split(",");
|
|
p2[p2.length - 1] += "{" + body + "}";
|
|
var postParts = parseCommaParts(post);
|
|
if (post.length) {
|
|
p2[p2.length - 1] += postParts.shift();
|
|
p2.push.apply(p2, postParts);
|
|
}
|
|
parts.push.apply(parts, p2);
|
|
return parts;
|
|
}
|
|
function expandTop(str) {
|
|
if (!str)
|
|
return [];
|
|
if (str.substr(0, 2) === "{}") {
|
|
str = "\\{\\}" + str.substr(2);
|
|
}
|
|
return expand2(escapeBraces(str), true).map(unescapeBraces);
|
|
}
|
|
function embrace(str) {
|
|
return "{" + str + "}";
|
|
}
|
|
function isPadded(el) {
|
|
return /^-?0\d/.test(el);
|
|
}
|
|
function lte(i2, y2) {
|
|
return i2 <= y2;
|
|
}
|
|
function gte(i2, y2) {
|
|
return i2 >= y2;
|
|
}
|
|
function expand2(str, isTop) {
|
|
var expansions = [];
|
|
var m2 = balanced("{", "}", str);
|
|
if (!m2) return [str];
|
|
var pre = m2.pre;
|
|
var post = m2.post.length ? expand2(m2.post, false) : [""];
|
|
if (/\$$/.test(m2.pre)) {
|
|
for (var k = 0; k < post.length; k++) {
|
|
var expansion = pre + "{" + m2.body + "}" + post[k];
|
|
expansions.push(expansion);
|
|
}
|
|
} else {
|
|
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m2.body);
|
|
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m2.body);
|
|
var isSequence = isNumericSequence || isAlphaSequence;
|
|
var isOptions = m2.body.indexOf(",") >= 0;
|
|
if (!isSequence && !isOptions) {
|
|
if (m2.post.match(/,.*\}/)) {
|
|
str = m2.pre + "{" + m2.body + escClose + m2.post;
|
|
return expand2(str);
|
|
}
|
|
return [str];
|
|
}
|
|
var n2;
|
|
if (isSequence) {
|
|
n2 = m2.body.split(/\.\./);
|
|
} else {
|
|
n2 = parseCommaParts(m2.body);
|
|
if (n2.length === 1) {
|
|
n2 = expand2(n2[0], false).map(embrace);
|
|
if (n2.length === 1) {
|
|
return post.map(function(p2) {
|
|
return m2.pre + n2[0] + p2;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
var N2;
|
|
if (isSequence) {
|
|
var x2 = numeric(n2[0]);
|
|
var y2 = numeric(n2[1]);
|
|
var width = Math.max(n2[0].length, n2[1].length);
|
|
var incr = n2.length == 3 ? Math.abs(numeric(n2[2])) : 1;
|
|
var test = lte;
|
|
var reverse = y2 < x2;
|
|
if (reverse) {
|
|
incr *= -1;
|
|
test = gte;
|
|
}
|
|
var pad = n2.some(isPadded);
|
|
N2 = [];
|
|
for (var i2 = x2; test(i2, y2); i2 += incr) {
|
|
var c2;
|
|
if (isAlphaSequence) {
|
|
c2 = String.fromCharCode(i2);
|
|
if (c2 === "\\")
|
|
c2 = "";
|
|
} else {
|
|
c2 = String(i2);
|
|
if (pad) {
|
|
var need = width - c2.length;
|
|
if (need > 0) {
|
|
var z2 = new Array(need + 1).join("0");
|
|
if (i2 < 0)
|
|
c2 = "-" + z2 + c2.slice(1);
|
|
else
|
|
c2 = z2 + c2;
|
|
}
|
|
}
|
|
}
|
|
N2.push(c2);
|
|
}
|
|
} else {
|
|
N2 = [];
|
|
for (var j2 = 0; j2 < n2.length; j2++) {
|
|
N2.push.apply(N2, expand2(n2[j2], false));
|
|
}
|
|
}
|
|
for (var j2 = 0; j2 < N2.length; j2++) {
|
|
for (var k = 0; k < post.length; k++) {
|
|
var expansion = pre + N2[j2] + post[k];
|
|
if (!isTop || isSequence || expansion)
|
|
expansions.push(expansion);
|
|
}
|
|
}
|
|
}
|
|
return expansions;
|
|
}
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/utils.js
|
|
var require_utils = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/utils.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.simpleFormatter = exports.htmlFormatter = exports.escapeRegexString = void 0;
|
|
function escapeRegexString(str) {
|
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
exports.escapeRegexString = escapeRegexString;
|
|
var htmlFormatter = class {
|
|
asking(answer, hint) {
|
|
return `<span style='color:#2196f3'>${!hint ? "[...]" : `[${hint}]`}</span>`;
|
|
}
|
|
showingAnswer(answer, hint) {
|
|
return `<span style='color:#2196f3'>${answer}</span>`;
|
|
}
|
|
hiding(answer, hint) {
|
|
return `${!hint ? "..." : `[${hint}]`} `;
|
|
}
|
|
};
|
|
exports.htmlFormatter = htmlFormatter;
|
|
var simpleFormatter = class {
|
|
asking(answer, hint) {
|
|
return `${!hint ? "[...]" : `[${hint}]`}`;
|
|
}
|
|
showingAnswer(answer, hint) {
|
|
return answer;
|
|
}
|
|
hiding(answer, hint) {
|
|
return `...`;
|
|
}
|
|
};
|
|
exports.simpleFormatter = simpleFormatter;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeFieldEnum.js
|
|
var require_ClozeFieldEnum = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeFieldEnum.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeFieldEnum = void 0;
|
|
var ClozeFieldEnum;
|
|
(function(ClozeFieldEnum2) {
|
|
ClozeFieldEnum2["seq"] = "seq";
|
|
ClozeFieldEnum2["answer"] = "answer";
|
|
ClozeFieldEnum2["hint"] = "hint";
|
|
})(ClozeFieldEnum || (exports.ClozeFieldEnum = ClozeFieldEnum = {}));
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeRegExp.js
|
|
var require_ClozeRegExp = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeRegExp.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeRegExp = void 0;
|
|
var ClozeFieldEnum_1 = require_ClozeFieldEnum();
|
|
var ClozeRegExp = class {
|
|
constructor(pattern, clozeFieldsOrder, flags) {
|
|
this.regex = new RegExp(pattern, flags);
|
|
this.clozeFieldsOrder = clozeFieldsOrder;
|
|
}
|
|
exec(str) {
|
|
let match2 = this.regex.exec(str);
|
|
if (!match2) {
|
|
return null;
|
|
}
|
|
if (this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.answer) == -1) {
|
|
throw new Error("Cloze text not found in clozeFieldsOrder");
|
|
}
|
|
if (this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.hint) == -1) {
|
|
throw new Error("Cloze hint not found in clozeFieldsOrder");
|
|
}
|
|
if (this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.seq) == -1) {
|
|
match2.seq = null;
|
|
} else {
|
|
match2.seq = match2[this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.seq) + 1];
|
|
}
|
|
match2.raw = match2[0];
|
|
match2.answer = match2[this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.answer) + 1];
|
|
match2.hint = match2[this.clozeFieldsOrder.indexOf(ClozeFieldEnum_1.ClozeFieldEnum.hint) + 1];
|
|
return match2;
|
|
}
|
|
test(str) {
|
|
return this.regex.test(str);
|
|
}
|
|
};
|
|
exports.ClozeRegExp = ClozeRegExp;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNote.js
|
|
var require_ClozeNote = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNote.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeNote = void 0;
|
|
var ClozeNote = class {
|
|
/**
|
|
* Creates a new ClozeNote instance.
|
|
*
|
|
* @param raw The raw text of the cloze note before processing.
|
|
*/
|
|
constructor(raw, patterns) {
|
|
this._raw = raw;
|
|
const { clozeDeletions, numCards } = this.initParsing(raw, patterns);
|
|
this._clozeDeletions = clozeDeletions;
|
|
this._numCards = numCards;
|
|
}
|
|
get raw() {
|
|
return this._raw;
|
|
}
|
|
get numCards() {
|
|
return this._numCards;
|
|
}
|
|
};
|
|
exports.ClozeNote = ClozeNote;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteClassic.js
|
|
var require_ClozeNoteClassic = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteClassic.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeNoteClassic = void 0;
|
|
var ClozeNote_1 = require_ClozeNote();
|
|
var utils_1 = require_utils();
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
var ClozeNoteClassic = class extends ClozeNote_1.ClozeNote {
|
|
constructor(raw, patterns) {
|
|
super(raw, patterns);
|
|
}
|
|
get clozeType() {
|
|
return ClozeTypeEnum_1.ClozeTypeEnum.CLASSIC;
|
|
}
|
|
initParsing(rawNote, patterns) {
|
|
let clozeDeletions = [];
|
|
let numCards = 0;
|
|
patterns.forEach((pattern) => {
|
|
const regex = pattern.getClozeRegex(ClozeTypeEnum_1.ClozeTypeEnum.CLASSIC);
|
|
let match2;
|
|
while (match2 = regex.exec(rawNote)) {
|
|
if (!match2.seq) {
|
|
break;
|
|
}
|
|
let newCloze = {
|
|
raw: match2.raw,
|
|
answer: match2.answer,
|
|
seq: parseInt(match2.seq),
|
|
hint: match2.hint
|
|
};
|
|
clozeDeletions.push(newCloze);
|
|
if (numCards < newCloze.seq) {
|
|
numCards = newCloze.seq;
|
|
}
|
|
}
|
|
});
|
|
return { clozeDeletions, numCards };
|
|
}
|
|
getCardFront(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let frontText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
if (deletion.seq !== cardIndex + 1) {
|
|
frontText = frontText.replace(deletion.raw, deletion.answer);
|
|
continue;
|
|
}
|
|
frontText = frontText.replace(deletion.raw, formatter.asking(deletion.answer, deletion.hint));
|
|
}
|
|
return frontText;
|
|
}
|
|
getCardBack(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let backText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
if (deletion.seq === cardIndex + 1) {
|
|
backText = backText.replace(deletion.raw, formatter.showingAnswer(deletion.answer, deletion.hint));
|
|
} else {
|
|
backText = backText.replace(deletion.raw, deletion.answer);
|
|
}
|
|
}
|
|
return backText;
|
|
}
|
|
};
|
|
exports.ClozeNoteClassic = ClozeNoteClassic;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteOL.js
|
|
var require_ClozeNoteOL = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteOL.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeNoteOL = void 0;
|
|
var ClozeNote_1 = require_ClozeNote();
|
|
var utils_1 = require_utils();
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
var ClozeNoteOL = class extends ClozeNote_1.ClozeNote {
|
|
constructor(raw, patterns) {
|
|
super(raw, patterns);
|
|
}
|
|
get clozeType() {
|
|
return ClozeTypeEnum_1.ClozeTypeEnum.OVERLAPPING;
|
|
}
|
|
initParsing(rawNote, patterns) {
|
|
let clozeDeletions = [];
|
|
let numCards = 0;
|
|
patterns.forEach((pattern) => {
|
|
const regex = pattern.getClozeRegex(ClozeTypeEnum_1.ClozeTypeEnum.OVERLAPPING);
|
|
let match2;
|
|
while (match2 = regex.exec(rawNote)) {
|
|
if (!match2.seq) {
|
|
break;
|
|
}
|
|
let newCloze = {
|
|
raw: match2.raw,
|
|
answer: match2.answer,
|
|
seq: match2.seq,
|
|
hint: match2.hint
|
|
};
|
|
clozeDeletions.push(newCloze);
|
|
if (numCards < newCloze.seq.length) {
|
|
numCards = newCloze.seq.length;
|
|
}
|
|
}
|
|
});
|
|
return { clozeDeletions, numCards };
|
|
}
|
|
getCardFront(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let frontText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
let clozeAction = "s";
|
|
if (cardIndex < deletion.seq.length) {
|
|
clozeAction = deletion.seq[cardIndex];
|
|
}
|
|
switch (clozeAction) {
|
|
case "a":
|
|
frontText = frontText.replace(deletion.raw, formatter.asking(deletion.answer, deletion.hint));
|
|
break;
|
|
case "h":
|
|
frontText = frontText.replace(deletion.raw, formatter.hiding(deletion.answer, deletion.hint));
|
|
break;
|
|
case "s":
|
|
frontText = frontText.replace(deletion.raw, deletion.answer);
|
|
break;
|
|
}
|
|
}
|
|
return frontText;
|
|
}
|
|
getCardBack(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let backText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
let clozeAction = "s";
|
|
if (cardIndex < deletion.seq.length) {
|
|
clozeAction = deletion.seq[cardIndex];
|
|
}
|
|
switch (clozeAction) {
|
|
case "a":
|
|
backText = backText.replace(deletion.raw, formatter.showingAnswer(deletion.answer, deletion.hint));
|
|
break;
|
|
case "h":
|
|
backText = backText.replace(deletion.raw, formatter.hiding(deletion.answer, deletion.hint));
|
|
break;
|
|
case "s":
|
|
backText = backText.replace(deletion.raw, deletion.answer);
|
|
break;
|
|
}
|
|
}
|
|
return backText;
|
|
}
|
|
};
|
|
exports.ClozeNoteOL = ClozeNoteOL;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteSimple.js
|
|
var require_ClozeNoteSimple = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeNoteSimple.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeNoteSimple = void 0;
|
|
var ClozeNote_1 = require_ClozeNote();
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
var utils_1 = require_utils();
|
|
var ClozeNoteSimple = class extends ClozeNote_1.ClozeNote {
|
|
constructor(raw, patterns) {
|
|
super(raw, patterns);
|
|
}
|
|
get clozeType() {
|
|
return ClozeTypeEnum_1.ClozeTypeEnum.SIMPLE;
|
|
}
|
|
initParsing(rawNote, patterns) {
|
|
let clozeDeletions = [];
|
|
let numCards = 0;
|
|
patterns.forEach((pattern) => {
|
|
const regex = pattern.getClozeRegex(ClozeTypeEnum_1.ClozeTypeEnum.SIMPLE);
|
|
let match2;
|
|
while (match2 = regex.exec(rawNote)) {
|
|
numCards++;
|
|
let newCloze = {
|
|
raw: match2.raw,
|
|
answer: match2.answer,
|
|
seq: numCards,
|
|
hint: match2.hint
|
|
};
|
|
clozeDeletions.push(newCloze);
|
|
}
|
|
});
|
|
return { clozeDeletions, numCards };
|
|
}
|
|
getCardFront(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let frontText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
if (deletion.seq !== cardIndex + 1) {
|
|
frontText = frontText.replace(deletion.raw, deletion.answer);
|
|
continue;
|
|
}
|
|
frontText = frontText.replace(deletion.raw, formatter.asking(deletion.answer, deletion.hint));
|
|
}
|
|
return frontText;
|
|
}
|
|
getCardBack(cardIndex, formatter) {
|
|
if (cardIndex >= this._numCards || cardIndex < 0) {
|
|
throw new Error(`Card ${cardIndex} does not exist`);
|
|
}
|
|
if (!formatter) {
|
|
formatter = new utils_1.simpleFormatter();
|
|
}
|
|
let backText = this.raw;
|
|
for (const deletion of this._clozeDeletions) {
|
|
if (deletion.seq === cardIndex + 1) {
|
|
backText = backText.replace(deletion.raw, formatter.showingAnswer(deletion.answer, deletion.hint));
|
|
} else {
|
|
backText = backText.replace(deletion.raw, deletion.answer);
|
|
}
|
|
}
|
|
return backText;
|
|
}
|
|
};
|
|
exports.ClozeNoteSimple = ClozeNoteSimple;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeTypeEnum.js
|
|
var require_ClozeTypeEnum = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeTypeEnum.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.NoteClassByClozeType = exports.ClozeTypesPriority = exports.ClozeTypeEnum = void 0;
|
|
var ClozeNoteClassic_1 = require_ClozeNoteClassic();
|
|
var ClozeNoteOL_1 = require_ClozeNoteOL();
|
|
var ClozeNoteSimple_1 = require_ClozeNoteSimple();
|
|
var ClozeTypeEnum;
|
|
(function(ClozeTypeEnum2) {
|
|
ClozeTypeEnum2["CLASSIC"] = "classic";
|
|
ClozeTypeEnum2["OVERLAPPING"] = "overlapping";
|
|
ClozeTypeEnum2["SIMPLE"] = "simple";
|
|
})(ClozeTypeEnum || (exports.ClozeTypeEnum = ClozeTypeEnum = {}));
|
|
exports.ClozeTypesPriority = [
|
|
ClozeTypeEnum.CLASSIC,
|
|
ClozeTypeEnum.OVERLAPPING,
|
|
ClozeTypeEnum.SIMPLE
|
|
// Cloze Simple must be the last one because it is a subset of Cloze Classic and Cloze Overlapping
|
|
];
|
|
exports.NoteClassByClozeType = {
|
|
[ClozeTypeEnum.CLASSIC]: ClozeNoteClassic_1.ClozeNoteClassic,
|
|
[ClozeTypeEnum.OVERLAPPING]: ClozeNoteOL_1.ClozeNoteOL,
|
|
[ClozeTypeEnum.SIMPLE]: ClozeNoteSimple_1.ClozeNoteSimple
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozePattern.js
|
|
var require_ClozePattern = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozePattern.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozePattern = void 0;
|
|
var utils_1 = require_utils();
|
|
var ClozeRegExp_1 = require_ClozeRegExp();
|
|
var ClozeFieldEnum_1 = require_ClozeFieldEnum();
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
var numPatternRegex = new RegExp(`\\[(?:(?:\\\\\\])?[^\\]]?)+?\\d+(?:(?:\\\\\\])?[^\\]]?)+?\\]`);
|
|
var hintPatternRegex = new RegExp(`\\[(?:(?:\\\\\\])?[^\\]]?)+?hint(?:(?:\\\\\\])?[^\\]]?)+?\\]`);
|
|
var answerKeyword = `answer`;
|
|
var ClozePattern = class _ClozePattern {
|
|
constructor(raw) {
|
|
this.clozeRegexByType = {
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.CLASSIC]: void 0,
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.OVERLAPPING]: void 0,
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.SIMPLE]: void 0
|
|
};
|
|
this.generateClozeRegexByType = {
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.CLASSIC]: this.generateClozeClassicRegex,
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.OVERLAPPING]: this.generateClozeOLRegex,
|
|
[ClozeTypeEnum_1.ClozeTypeEnum.SIMPLE]: this.generateClozeSimpleRegex
|
|
};
|
|
this._raw = raw;
|
|
let _numMatch = numPatternRegex.exec(raw);
|
|
let _hintMatch = hintPatternRegex.exec(raw);
|
|
if (!_numMatch) {
|
|
throw new Error("No cloze number pattern found");
|
|
}
|
|
if (!_hintMatch) {
|
|
throw new Error("No cloze hint pattern found");
|
|
}
|
|
if (raw.indexOf(answerKeyword) == -1) {
|
|
throw new Error(`No answer keyword (${answerKeyword}) found in the pattern.`);
|
|
}
|
|
this.numPattern = _numMatch;
|
|
this.hintPattern = _hintMatch;
|
|
this.numRegex = _ClozePattern.processPattern(_numMatch[0], (text) => text.replace(/\d+/g, "(\\d+)"));
|
|
this.seqRegex = _ClozePattern.processPattern(_numMatch[0], (text) => text.replace(/\d+/g, "([ash]+)"));
|
|
this.hintRegex = _ClozePattern.processPattern(_hintMatch[0], (text) => text.replace(/hint/g, "(.+?)"));
|
|
this.hintRegex = "(?:" + this.hintRegex + ")?";
|
|
this._clozeFieldOrder = [ClozeFieldEnum_1.ClozeFieldEnum.answer, ClozeFieldEnum_1.ClozeFieldEnum.hint, ClozeFieldEnum_1.ClozeFieldEnum.seq];
|
|
let positions2 = {
|
|
[ClozeFieldEnum_1.ClozeFieldEnum.answer]: raw.indexOf(answerKeyword),
|
|
[ClozeFieldEnum_1.ClozeFieldEnum.hint]: this.hintPattern.index,
|
|
[ClozeFieldEnum_1.ClozeFieldEnum.seq]: this.numPattern.index
|
|
};
|
|
this._clozeFieldOrder.sort((a2, b2) => positions2[a2] - positions2[b2]);
|
|
}
|
|
static processPattern(text, rplc) {
|
|
let ans = text.substring(1, text.length - 1);
|
|
ans = ans.replace(/\\\[/g, "[").replace(/\\]/g, "]");
|
|
ans = (0, utils_1.escapeRegexString)(ans);
|
|
ans = rplc(ans);
|
|
return ans;
|
|
}
|
|
generateClozeRegexStr(first, firstReplace, second, secondReplace) {
|
|
let begin = this._raw.slice(0, first.index);
|
|
let middle = this._raw.slice(first.index + first[0].length, second.index);
|
|
let ending = this._raw.slice(second.index + second[0].length, this._raw.length);
|
|
let regexStr = (0, utils_1.escapeRegexString)(begin) + firstReplace + (0, utils_1.escapeRegexString)(middle) + secondReplace + (0, utils_1.escapeRegexString)(ending);
|
|
regexStr = regexStr.replace(answerKeyword, "(.+?)");
|
|
return regexStr;
|
|
}
|
|
generateClozeSimpleRegex(pattern) {
|
|
let regexStr;
|
|
if (pattern.numPattern.index < pattern.hintPattern.index) {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.numPattern, "", pattern.hintPattern, pattern.hintRegex);
|
|
} else {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.hintPattern, pattern.hintRegex, pattern.numPattern, "");
|
|
}
|
|
let clozeFieldsOrderWithoutSeq = pattern._clozeFieldOrder.filter((x2) => x2 != ClozeFieldEnum_1.ClozeFieldEnum.seq);
|
|
return new ClozeRegExp_1.ClozeRegExp(regexStr, clozeFieldsOrderWithoutSeq, "g");
|
|
}
|
|
generateClozeClassicRegex(pattern) {
|
|
let regexStr;
|
|
if (pattern.numPattern.index < pattern.hintPattern.index) {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.numPattern, pattern.numRegex, pattern.hintPattern, pattern.hintRegex);
|
|
} else {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.hintPattern, pattern.hintRegex, pattern.numPattern, pattern.numRegex);
|
|
}
|
|
return new ClozeRegExp_1.ClozeRegExp(regexStr, pattern._clozeFieldOrder, "g");
|
|
}
|
|
generateClozeOLRegex(pattern) {
|
|
let regexStr;
|
|
if (pattern.numPattern.index < pattern.hintPattern.index) {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.numPattern, pattern.seqRegex, pattern.hintPattern, pattern.hintRegex);
|
|
} else {
|
|
regexStr = pattern.generateClozeRegexStr(pattern.hintPattern, pattern.hintRegex, pattern.numPattern, pattern.seqRegex);
|
|
}
|
|
return new ClozeRegExp_1.ClozeRegExp(regexStr, pattern._clozeFieldOrder, "g");
|
|
}
|
|
get clozeFieldsOrder() {
|
|
return this._clozeFieldOrder;
|
|
}
|
|
getClozeRegex(clozeType) {
|
|
let clozeRegex = this.clozeRegexByType[clozeType];
|
|
if (clozeRegex != void 0) {
|
|
clozeRegex.regex.lastIndex = 0;
|
|
return clozeRegex;
|
|
}
|
|
clozeRegex = this.generateClozeRegexByType[clozeType](this);
|
|
this.clozeRegexByType[clozeType] = clozeRegex;
|
|
return clozeRegex;
|
|
}
|
|
hasClozeType(text, clozeType) {
|
|
for (const priorityType of ClozeTypeEnum_1.ClozeTypesPriority) {
|
|
if (this.getClozeRegex(priorityType).test(text)) {
|
|
return clozeType == priorityType;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
getClozeTypes(text) {
|
|
const clozeTypes = [];
|
|
for (const priorityType of ClozeTypeEnum_1.ClozeTypesPriority) {
|
|
if (this.getClozeRegex(priorityType).test(text)) {
|
|
clozeTypes.push(priorityType);
|
|
}
|
|
}
|
|
return clozeTypes;
|
|
}
|
|
getMainClozeType(text) {
|
|
for (const priorityType of ClozeTypeEnum_1.ClozeTypesPriority) {
|
|
if (this.getClozeRegex(priorityType).test(text)) {
|
|
return priorityType;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
exports.ClozePattern = ClozePattern;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeCrafter.js
|
|
var require_ClozeCrafter = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/implementation/ClozeCrafter.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeCrafter = void 0;
|
|
var ClozePattern_1 = require_ClozePattern();
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
var ClozeCrafter3 = class {
|
|
constructor(patterns) {
|
|
this.patterns = patterns.map((patternStr) => new ClozePattern_1.ClozePattern(patternStr));
|
|
}
|
|
createClozeNote(text) {
|
|
const noteType = this.getNoteType(text);
|
|
if (noteType === null) {
|
|
return null;
|
|
}
|
|
const selectedClass = ClozeTypeEnum_1.NoteClassByClozeType[noteType];
|
|
const clozeNote = new selectedClass(text, this.patterns);
|
|
return clozeNote;
|
|
}
|
|
getNoteType(text) {
|
|
let noteType = null;
|
|
for (const pattern of this.patterns) {
|
|
const currentType = pattern.getMainClozeType(text);
|
|
if (currentType !== null && (noteType === null || ClozeTypeEnum_1.ClozeTypesPriority.indexOf(currentType) < ClozeTypeEnum_1.ClozeTypesPriority.indexOf(noteType))) {
|
|
noteType = currentType;
|
|
}
|
|
}
|
|
return noteType;
|
|
}
|
|
isClozeNote(text) {
|
|
return this.getNoteType(text) !== null;
|
|
}
|
|
};
|
|
exports.ClozeCrafter = ClozeCrafter3;
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/index.js
|
|
var require_dist = __commonJS({
|
|
"node_modules/.pnpm/clozecraft@0.4.0/node_modules/clozecraft/dist/index.js"(exports) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ClozeTypesPriority = exports.ClozeTypeEnum = exports.ClozeCrafter = void 0;
|
|
var ClozeCrafter_1 = require_ClozeCrafter();
|
|
Object.defineProperty(exports, "ClozeCrafter", { enumerable: true, get: function() {
|
|
return ClozeCrafter_1.ClozeCrafter;
|
|
} });
|
|
var ClozeTypeEnum_1 = require_ClozeTypeEnum();
|
|
Object.defineProperty(exports, "ClozeTypeEnum", { enumerable: true, get: function() {
|
|
return ClozeTypeEnum_1.ClozeTypeEnum;
|
|
} });
|
|
Object.defineProperty(exports, "ClozeTypesPriority", { enumerable: true, get: function() {
|
|
return ClozeTypeEnum_1.ClozeTypesPriority;
|
|
} });
|
|
}
|
|
});
|
|
|
|
// node_modules/.pnpm/vhtml@2.2.0/node_modules/vhtml/dist/vhtml.js
|
|
var require_vhtml = __commonJS({
|
|
"node_modules/.pnpm/vhtml@2.2.0/node_modules/vhtml/dist/vhtml.js"(exports, module2) {
|
|
(function(global, factory) {
|
|
typeof exports === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global.vhtml = factory();
|
|
})(exports, function() {
|
|
"use strict";
|
|
var emptyTags = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
|
|
var esc = function esc2(str) {
|
|
return String(str).replace(/[&<>"']/g, function(s2) {
|
|
return "&" + map3[s2] + ";";
|
|
});
|
|
};
|
|
var map3 = { "&": "amp", "<": "lt", ">": "gt", '"': "quot", "'": "apos" };
|
|
var setInnerHTMLAttr = "dangerouslySetInnerHTML";
|
|
var DOMAttributeNames = {
|
|
className: "class",
|
|
htmlFor: "for"
|
|
};
|
|
var sanitized = {};
|
|
function h6(name, attrs) {
|
|
var stack = [], s2 = "";
|
|
attrs = attrs || {};
|
|
for (var i2 = arguments.length; i2-- > 2; ) {
|
|
stack.push(arguments[i2]);
|
|
}
|
|
if (typeof name === "function") {
|
|
attrs.children = stack.reverse();
|
|
return name(attrs);
|
|
}
|
|
if (name) {
|
|
s2 += "<" + name;
|
|
if (attrs) for (var _i in attrs) {
|
|
if (attrs[_i] !== false && attrs[_i] != null && _i !== setInnerHTMLAttr) {
|
|
s2 += " " + (DOMAttributeNames[_i] ? DOMAttributeNames[_i] : esc(_i)) + '="' + esc(attrs[_i]) + '"';
|
|
}
|
|
}
|
|
s2 += ">";
|
|
}
|
|
if (emptyTags.indexOf(name) === -1) {
|
|
if (attrs[setInnerHTMLAttr]) {
|
|
s2 += attrs[setInnerHTMLAttr].__html;
|
|
} else while (stack.length) {
|
|
var child = stack.pop();
|
|
if (child) {
|
|
if (child.pop) {
|
|
for (var _i2 = child.length; _i2--; ) {
|
|
stack.push(child[_i2]);
|
|
}
|
|
} else {
|
|
s2 += sanitized[child] === true ? child : esc(child);
|
|
}
|
|
}
|
|
}
|
|
s2 += name ? "</" + name + ">" : "";
|
|
}
|
|
sanitized[s2] = true;
|
|
return s2;
|
|
}
|
|
return h6;
|
|
});
|
|
}
|
|
});
|
|
|
|
// src/main.ts
|
|
var main_exports = {};
|
|
__export(main_exports, {
|
|
default: () => SRPlugin
|
|
});
|
|
module.exports = __toCommonJS(main_exports);
|
|
var import_obsidian14 = require("obsidian");
|
|
|
|
// src/algorithms/base/repetition-item.ts
|
|
var RepetitionItem = class {
|
|
// scheduling
|
|
get hasSchedule() {
|
|
return this.scheduleInfo != null;
|
|
}
|
|
get isNew() {
|
|
return !this.hasSchedule;
|
|
}
|
|
get isDue() {
|
|
return this.hasSchedule && this.scheduleInfo.isDue();
|
|
}
|
|
};
|
|
|
|
// src/algorithms/base/srs-algorithm.ts
|
|
var SrsAlgorithm = class _SrsAlgorithm {
|
|
static getInstance() {
|
|
if (!_SrsAlgorithm.instance) {
|
|
throw new Error("there is no SrsAlgorithm instance.");
|
|
}
|
|
return _SrsAlgorithm.instance;
|
|
}
|
|
};
|
|
|
|
// src/algorithms/osr/obsidian-vault-notelink-info-finder.ts
|
|
var ObsidianVaultNoteLinkInfoFinder = class {
|
|
constructor(metadataCache) {
|
|
this.metadataCache = metadataCache;
|
|
}
|
|
getResolvedTargetLinksForNotePath(path3) {
|
|
return this.metadataCache.resolvedLinks[path3];
|
|
}
|
|
};
|
|
|
|
// src/algorithms/osr/srs-algorithm-osr.ts
|
|
var import_moment2 = __toESM(require_moment());
|
|
|
|
// src/constants.ts
|
|
var SCHEDULING_INFO_REGEX = /^---\r?\n((?:.*\r?\n)*)sr-due: (.+)\r?\nsr-interval: (\d+)\r?\nsr-ease: (\d+)\r?\n((?:.*\r?\n)?)---/;
|
|
var YAML_FRONT_MATTER_REGEX = /^---\r?\n((?:.*\r?\n)*?)---/;
|
|
var MULTI_SCHEDULING_EXTRACTOR = /!([\d-]+),(\d+),(\d+)/gm;
|
|
var LEGACY_SCHEDULING_EXTRACTOR = /<!--SR:([\d-]+),(\d+),(\d+)-->/gm;
|
|
var OBSIDIAN_TAG_AT_STARTOFLINE_REGEX = /^#[^\s#]+/gi;
|
|
var OBSIDIAN_BLOCK_ID_ENDOFLINE_REGEX = / (\^[a-zA-Z0-9-]+)$/;
|
|
var PREFERRED_DATE_FORMAT = "YYYY-MM-DD";
|
|
var ALLOWED_DATE_FORMATS = [PREFERRED_DATE_FORMAT, "DD-MM-YYYY", "ddd MMM DD YYYY"];
|
|
var IMAGE_FORMATS = [
|
|
"jpg",
|
|
"jpeg",
|
|
"gif",
|
|
"png",
|
|
"svg",
|
|
"webp",
|
|
"apng",
|
|
"avif",
|
|
"jfif",
|
|
"pjpeg",
|
|
"pjp",
|
|
"bmp"
|
|
];
|
|
var AUDIO_FORMATS = ["mp3", "webm", "m4a", "wav", "ogg"];
|
|
var VIDEO_FORMATS = ["mp4", "mkv", "avi", "mov"];
|
|
var COLLAPSE_ICON = '<svg viewBox="0 0 100 100" width="8" height="8" class="svg-icon right-triangle"><path fill="currentColor" stroke="currentColor" d="M94.9,20.8c-1.4-2.5-4.1-4.1-7.1-4.1H12.2c-3,0-5.7,1.6-7.1,4.1c-1.3,2.4-1.2,5.2,0.2,7.6L43.1,88c1.5,2.3,4,3.7,6.9,3.7 s5.4-1.4,6.9-3.7l37.8-59.6C96.1,26,96.2,23.2,94.9,20.8L94.9,20.8z"></path></svg>';
|
|
var TICKS_PER_DAY = 24 * 3600 * 1e3;
|
|
var SR_HTML_COMMENT_BEGIN = "<!--SR:";
|
|
var SR_HTML_COMMENT_END = "-->";
|
|
|
|
// src/lang/helpers.ts
|
|
var import_obsidian = require("obsidian");
|
|
|
|
// src/lang/locale/af.ts
|
|
var af_default = {};
|
|
|
|
// src/lang/locale/ar.ts
|
|
var ar_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\u0627\u0644\u0631\u064F\u0632\u0645\u064E\u0627\u062A",
|
|
DUE_CARDS: "\u0628\u0637\u0627\u0642\u0627\u062A \u0645\u064F\u0633\u062A\u062D\u0642\u0629",
|
|
NEW_CARDS: "\u0628\u0637\u0627\u0642\u0627\u062A \u062C\u062F\u064A\u062F\u0629",
|
|
TOTAL_CARDS: "\u0625\u062C\u0645\u0627\u0644\u064A \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
BACK: "\u0631\u062C\u0648\u0639",
|
|
SKIP: "Skip",
|
|
EDIT_CARD: "\u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0629",
|
|
RESET_CARD_PROGRESS: "\u0625\u0639\u0627\u062F\u0629 \u062A\u0639\u064A\u064A\u0646 \u062A\u0642\u062F\u0651\u064F\u0645\u0652 \u0627\u0644\u0628\u0637\u0627\u0642\u0629",
|
|
HARD: "\u0635\u0639\u0628",
|
|
GOOD: "\u062C\u064A\u062F",
|
|
EASY: "\u0633\u0647\u0644",
|
|
SHOW_ANSWER: "\u0623\u0638\u0647\u0650\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
|
|
CARD_PROGRESS_RESET: ".\u062A\u0645\u0651\u064E\u062A \u0625\u0639\u0627\u062F\u0629 \u062A\u0639\u064A\u064A\u0646 \u062A\u0642\u062F\u0651\u064F\u0645 \u0627\u0644\u0628\u0637\u0627\u0642\u0629",
|
|
SAVE: "\u062D\u0641\u0638",
|
|
CANCEL: "\u0625\u0644\u063A\u0627\u0621",
|
|
NO_INPUT: ".\u0644\u0645 \u064A\u062A\u0650\u0645 \u062A\u0642\u062F\u064A\u0645 \u0623\u064A \u0645\u064F\u062F\u062E\u0644\u0627\u062A",
|
|
CURRENT_EASE_HELP_TEXT: ":\u0627\u0644\u0633\u0647\u0648\u0644\u0629 \u0627\u0644\u062D\u0627\u0644\u064A\u0629",
|
|
CURRENT_INTERVAL_HELP_TEXT: ":\u0627\u0644\u0641\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A \u0627\u0644\u062D\u0627\u0644\u064A",
|
|
CARD_GENERATED_FROM: "${notePath} :\u062A\u0645 \u0625\u0646\u0634\u0627\u0624\u0647\u0627 \u0645\u0646",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\u0627\u0641\u062A\u062D \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u0644\u0644\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
REVIEW_CARDS: "\u0645\u0631\u0627\u062C\u0639\u0629 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "${difficulty} :\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "${difficulty} \u0645\u0631\u0627\u062C\u0639\u0629 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u0643\u0640",
|
|
CRAM_ALL_CARDS: "\u062D\u062F\u062F \u0631\u064F\u0632\u0645\u064E\u0629 \u0644\u0644\u062D\u0634\u0631",
|
|
REVIEW_ALL_CARDS: "\u0645\u0631\u0627\u062C\u0639\u0629 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0645\u0646 \u062C\u0645\u064A\u0639 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A",
|
|
REVIEW_CARDS_IN_NOTE: "\u0645\u0631\u0627\u062C\u0639\u0629 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629",
|
|
CRAM_CARDS_IN_NOTE: "\u0623\u062D\u0634\u0631 \u062C\u0645\u064A\u0639 \u0628\u0637\u0627\u0642\u0627\u062A \u0647\u0630\u0647 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629",
|
|
VIEW_STATS: "\u0639\u0631\u0636 \u0627\u0644\u0625\u062D\u0635\u0627\u0626\u064A\u0627\u062A",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "\u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0645\u0633\u062A\u062D\u0642\u0629 ${dueFlashcardsCount},\u0645\u0644\u0627\u062D\u0638\u0627\u062A ${dueNotesCount}:\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
SYNC_TIME_TAKEN: "${t}ms \u0627\u0633\u062A\u063A\u0631\u0627\u0642 \u0627\u0644\u0645\u0632\u0627\u0645\u0646\u0629",
|
|
NOTE_IN_IGNORED_FOLDER: ".\u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u064A\u062A\u0645 \u062D\u0641\u0638\u0647\u0627 \u0636\u0645\u0646 \u0627\u0644\u0645\u062C\u0644\u062F \u0627\u0644\u0630\u064A \u062A\u0645 \u062A\u062C\u0627\u0647\u0644\u0647 (\u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A)",
|
|
PLEASE_TAG_NOTE: ".\u064A\u0631\u062C\u0649 \u0648\u0636\u0639 \u0648\u0633\u0645 \u0639\u0644\u0649 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u0628\u0634\u0643\u0644 \u0645\u0646\u0627\u0633\u0628 \u0644\u0644\u0645\u0631\u0627\u062C\u0639\u0629 (\u0641\u064A \u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A)",
|
|
RESPONSE_RECEIVED: ".\u0627\u0633\u062A\u064F\u0644\u0645\u062A \u0627\u0644\u0627\u0633\u062A\u062C\u0627\u0628\u0629",
|
|
NO_DECK_EXISTS: "${deckName} \u0644\u0627 \u064A\u0648\u062C\u062F \u0631\u064F\u0632\u0645\u064E\u0629",
|
|
ALL_CAUGHT_UP: "\u{1F606} \u0644\u0642\u062F \u062A\u0645 \u0627\u0644\u0642\u0628\u0636 \u0639\u0644\u064A\u0643\u0645 \u062C\u0645\u064A\u0639\u0627 \u0627\u0644\u0622\u0646",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "\u064A\u0648\u0645/\u0623\u064A\u0627\u0645 ${interval}",
|
|
MONTHS_STR_IVL: "\u0634\u0647\u0631/\u0623\u0634\u0647\u0631 ${interval}",
|
|
YEARS_STR_IVL: "\u0633\u0646\u0629/\u0633\u0646\u0648\u0627\u062A ${interval}",
|
|
DAYS_STR_IVL_MOBILE: "\u064A${interval}",
|
|
MONTHS_STR_IVL_MOBILE: "\u0634${interval}",
|
|
YEARS_STR_IVL_MOBILE: "\u0633${interval}",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '.<a href="${wikiUrl}">wiki</a> \u0644\u0645\u0632\u064A\u062F \u0645\u0646 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062A \u060C \u062A\u062D\u0642\u0642 \u0645\u0646',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\u0645\u062C\u0644\u062F\u0627\u062A \u0644\u062A\u062C\u0627\u0647\u0644\u0647\u0627",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
FLASHCARD_EASY_LABEL: "\u0646\u0635 \u0627\u0644\u0632\u0631 \u0633\u0647\u0644",
|
|
FLASHCARD_GOOD_LABEL: "\u0646\u0635 \u0627\u0644\u0632\u0631 \u062C\u064A\u062F",
|
|
FLASHCARD_HARD_LABEL: "\u0646\u0635 \u0627\u0644\u0632\u0631 \u0635\u0639\u0628",
|
|
FLASHCARD_EASY_DESC: '"\u062A\u062E\u0635\u064A\u0635 \u0627\u0644\u062A\u0633\u0645\u064A\u0629 \u0644\u0644\u0632\u0631 "\u0633\u0647\u0644',
|
|
FLASHCARD_GOOD_DESC: '"\u062A\u062E\u0635\u064A\u0635 \u0627\u0644\u062A\u0633\u0645\u064A\u0629 \u0644\u0644\u0632\u0631 "\u062C\u064A\u062F',
|
|
FLASHCARD_HARD_DESC: '"\u062A\u062E\u0635\u064A\u0635 \u0627\u0644\u062A\u0633\u0645\u064A\u0629 \u0644\u0644\u0632\u0631 "\u0635\u0639\u0628',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\u0648\u064F\u0633\u0648\u0645 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
FLASHCARD_TAGS_DESC: "#2\u0623\u062F\u062E\u0644 \u0627\u0644\u0648\u064F\u0633\u0648\u0645 \u0645\u0641\u0635\u0648\u0644\u0629 \u0628\u0645\u0633\u0627\u0641\u0627\u062A \u0623\u0648 \u0623\u0633\u0637\u0631 \u062C\u062F\u064A\u062F\u0629 \u060C \u0623\u064A \u0628\u0637\u0627\u0642\u0627\u062A# \u0631\u0632\u0645\u06293# \u0631\u0632\u0645\u0629",
|
|
CONVERT_FOLDERS_TO_DECKS: "\u062A\u062D\u0648\u064A\u0644 \u0627\u0644\u0645\u062C\u0644\u062F\u0627\u062A \u0625\u0644\u0649 \u0645\u0644\u0641\u0627\u062A \u0623\u0635\u0644\u064A\u0629 \u0648 \u0645\u0644\u0641\u0627\u062A \u0627\u0644\u0641\u0631\u0639\u064A\u0629\u061F",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: ".\u0647\u0630\u0627 \u0647\u0648 \u0628\u062F\u064A\u0644 \u0644\u062E\u064A\u0627\u0631 \u0648\u0633\u0648\u0645 \u0627\u0644\u0628\u0637\u0627\u0642\u0629 \u0623\u0639\u0644\u0627\u0647",
|
|
INLINE_SCHEDULING_COMMENTS: "\u062D\u0641\u0638 \u062A\u0639\u0644\u064A\u0642 \u0627\u0644\u062C\u062F\u0648\u0644\u0629 \u0639\u0644\u0649 \u0646\u0641\u0633 \u0627\u0644\u0633\u0637\u0631 \u0645\u062B\u0644 \u0627\u0644\u0633\u0637\u0631 \u0627\u0644\u0623\u062E\u064A\u0631 \u0644\u0644\u0628\u0637\u0627\u0642\u0629 \u061F",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "\u0644\u0627 \u062A\u0643\u0633\u0631 \u062A\u0646\u0633\u064A\u0642 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 HTML \u0633\u064A\u0624\u062F\u064A \u062A\u0634\u063A\u064A\u0644 \u0647\u0630\u0627 \u0625\u0644\u0649 \u062C\u0639\u0644 \u062A\u0639\u0644\u064A\u0642\u0627\u062A",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\u0623\u062E\u0641\u064A \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0634\u0642\u064A\u0642\u0629 \u062D\u062A\u0649 \u0627\u0644\u064A\u0648\u0645 \u0627\u0644\u062A\u0627\u0644\u064A",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "cloze deletions : \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0634\u0642\u064A\u0642\u0629 \u0647\u064A \u0628\u0637\u0627\u0642\u0627\u062A \u062A\u0645 \u0625\u0646\u0634\u0627\u0624\u0647\u0627 \u0645\u0646 \u0646\u0641\u0633 \u0646\u0635 \u0627\u0644\u0628\u0637\u0627\u0642\u0629 \u0643\u0640",
|
|
SHOW_CARD_CONTEXT: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u0633\u064A\u0627\u0642 \u0641\u064A \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A\u061F",
|
|
SHOW_CARD_CONTEXT_DESC: "i.e. Title > Heading 1 > Subheading > ... > Subheading",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\u0646\u0633\u0628\u0629 \u0627\u0631\u062A\u0641\u0627\u0639 \u0627\u0644\u0628\u0637\u0627\u0642\u0629",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\u064A\u062C\u0628 \u0636\u0628\u0637\u0647\u0627 \u0639\u0644\u0649 100 \u066A \u0639\u0644\u0649 \u0627\u0644\u0647\u0627\u062A\u0641 \u0627\u0644\u0645\u062D\u0645\u0648\u0644 \u0623\u0648 \u0625\u0630\u0627 \u0643\u0627\u0646 \u0644\u062F\u064A\u0643 \u0635\u0648\u0631 \u0643\u0628\u064A\u0631\u0629 \u062C\u062F\u064B\u0627",
|
|
RESET_DEFAULT: "\u0625\u0639\u0627\u062F\u0629 \u062A\u0639\u064A\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u0627\u0641\u062A\u0631\u0627\u0636\u064A",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u0646\u0633\u0628\u0629 \u0639\u0631\u0636 \u0627\u0644\u0628\u0637\u0627\u0642\u0629",
|
|
RANDOMIZE_CARD_ORDER: "\u062A\u0631\u062A\u064A\u0628 \u0628\u0637\u0627\u0642\u0629 \u0639\u0634\u0648\u0627\u0626\u064A \u0623\u062B\u0646\u0627\u0621 \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0629\u061F",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "\u061Fcloze \u062A\u0639\u0637\u064A\u0644 \u0628\u0637\u0627\u0642\u0627\u062A",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Convert ==highlights== to clozes",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Convert **bolded text** to clozes",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Convert {{curly brackets}} to clozes",
|
|
CLOZE_PATTERNS: "Cloze Patterns",
|
|
CLOZE_PATTERNS_DESC: 'Enter cloze patterns separated by newlines. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\u0641\u0627\u0635\u0644 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0645\u0636\u0645\u0646\u0629",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\u0636\u0639 \u0641\u064A \u062D\u0633\u0627\u0628\u0643 \u0623\u0646\u0647 \u0628\u0639\u062F \u062A\u063A\u064A\u064A\u0631 \u0647\u0630\u0627 \u060C \u064A\u062C\u0628 \u0639\u0644\u064A\u0643 \u062A\u0639\u062F\u064A\u0644 \u0623\u064A \u0628\u0637\u0627\u0642\u0627\u062A \u0644\u062F\u064A\u0643 \u0628\u0627\u0644\u0641\u0639\u0644 \u064A\u062F\u0648\u064A\u064B\u0627",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\u0641\u0627\u0635\u0644 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0639\u0643\u0633\u064A\u0629 \u0627\u0644\u0645\u0636\u0645\u0646\u0629",
|
|
MULTILINE_CARDS_SEPARATOR: "\u0641\u0627\u0635\u0644 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0645\u062A\u0639\u062F\u062F\u0629",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\u0641\u0627\u0635\u0644 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0639\u0643\u0633\u064A\u0629 \u0627\u0644\u0645\u062A\u0639\u062F\u062F\u0629",
|
|
MULTILINE_CARDS_END_MARKER: "\u0627\u0644\u0623\u062D\u0631\u0641 \u0627\u0644\u062A\u064A \u062A\u062F\u0644 \u0639\u0644\u0649 \u0646\u0647\u0627\u064A\u0629 \u0627\u0644\u0643\u0644\u0648\u0632\u0627\u062A \u0648\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u062A\u0639\u0644\u0645 \u0627\u0644\u0645\u062A\u0639\u062F\u062F\u0629 \u0627\u0644\u0623\u0633\u0637\u0631",
|
|
NOTES: "\u0645\u0644\u0627\u062D\u0638\u0627\u062A",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "\u062A\u0645\u0643\u064A\u0646 \u062C\u0632\u0621 \u0645\u0631\u0627\u062C\u0639\u0629 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A \u0639\u0646\u062F \u0628\u062F\u0621 \u0627\u0644\u062A\u0634\u063A\u064A\u0644",
|
|
TAGS_TO_REVIEW: "\u0648\u0633\u0648\u0645 \u0644\u0644\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
TAGS_TO_REVIEW_DESC: "#\u0623\u062F\u062E\u0644 \u0627\u0644\u0648\u0633\u0648\u0645 \u0645\u0641\u0635\u0648\u0644\u0629 \u0628\u0645\u0633\u0627\u0641\u0627\u062A \u0623\u0648 \u062E\u0637\u0648\u0637 \u062C\u062F\u064A\u062F\u0629 \u060C \u0623\u064A : \u0645\u0631\u0627\u062C\u0639\u0629# \u0648\u0633\u06452# \u0648\u0633\u06453",
|
|
OPEN_RANDOM_NOTE: "\u0627\u0641\u062A\u062D \u0645\u0644\u0627\u062D\u0638\u0629 \u0639\u0634\u0648\u0627\u0626\u064A\u0629 \u0644\u0644\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
OPEN_RANDOM_NOTE_DESC: "(Pagerank) \u0639\u0646\u062F \u062A\u0639\u0637\u064A\u0644 \u0647\u0630\u0627 \u0627\u0644\u062E\u064A\u0627\u0631 \u060C\u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A \u0633\u064A\u062A\u0645 \u062A\u0631\u062A\u064A\u0628\u064F\u0647\u0627 \u062D\u0633\u0628 \u0627\u0644\u0623\u0647\u0645\u064A\u0629",
|
|
AUTO_NEXT_NOTE: "\u0627\u0641\u062A\u062D \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u064B\u0627 \u0628\u0639\u062F \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\u0641\u0639\u0651\u0644 \u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0629 \u0641\u064A \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0644\u0641 (\u0645\u062B\u0627\u0644: \u0645\u0631\u0627\u062C\u0639\u0629: \u0633\u0647\u0644\u060C \u062C\u064A\u062F\u060C \u0635\u0639\u0628)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\u0625\u0630\u0627 \u0642\u0645\u062A \u0628\u062A\u0639\u0637\u064A\u0644 \u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0629 \u0641\u064A \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0644\u0641\u060C \u064A\u0645\u0643\u0646\u0643 \u0645\u0631\u0627\u062C\u0639\u0629 \u0645\u0644\u0627\u062D\u0638\u0627\u062A\u0643 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0623\u0648\u0627\u0645\u0631 \u0627\u0644\u0625\u0636\u0627\u0641\u0629 \u0648\u0625\u0630\u0627 \u0643\u0646\u062A \u0642\u062F \u062D\u062F\u062F\u062A\u0647\u0627\u060C \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0645\u0641\u0627\u062A\u064A\u062D \u0627\u0644\u0627\u062E\u062A\u0635\u0627\u0631 \u0627\u0644\u0645\u0631\u062A\u0628\u0637\u0629.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0644\u0639\u062F\u062F \u0627\u0644\u0623\u064A\u0627\u0645 \u0627\u0644\u062A\u064A \u064A\u062C\u0628 \u0639\u0631\u0636\u0647\u0627 \u0639\u0644\u0649 \u0627\u0644\u0644\u0648\u062D\u0629 \u0627\u0644\u064A\u0645\u0646\u0649",
|
|
MIN_ONE_DAY: "\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u062F\u062F \u0627\u0644\u0623\u064A\u0627\u0645 1 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644",
|
|
VALID_NUMBER_WARNING: "\u064A\u0631\u062C\u0649 \u062A\u0642\u062F\u064A\u0645 \u0631\u0642\u0645 \u0635\u0627\u0644\u062D",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u0639\u0631\u0636 \u0627\u0644\u0634\u062C\u0631\u064A \u0644\u0644\u0631\u064F\u0632\u0645 \u0645\u0648\u0633\u0639 \u0628\u062D\u064A\u062B \u062A\u0637\u0647\u0631 \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u0641\u0631\u0639\u064A\u0629 \u0643\u0644\u0647\u0627",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: " \u0639\u0637\u0644 \u0647\u0630\u0627 \u0627\u0644\u062E\u064A\u0627\u0631 \u0644\u0637\u064A \u0627\u0644\u0631\u064F\u0632\u0645 \u0627\u0644\u0645\u062A\u062F\u0627\u062E\u0644\u0629 \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0628\u0637\u0627\u0642\u0629 , \u0645\u0641\u064A\u062F \u0625\u0630\u0627 \u0643\u0627\u0646 \u0644\u062F\u064A\u0643 \u0628\u0637\u0627\u0642\u0627\u062A \u062A\u0646\u062A\u0645\u064A \u0625\u0644\u0649 \u0627\u0644\u0639\u062F\u064A\u062F \u0645\u0646 \u0627\u0644\u0631\u064F\u0632\u0645 \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0645\u0644\u0641",
|
|
ALGORITHM: "\u062E\u0648\u0627\u0631\u0632\u0645\u064A\u0629",
|
|
CHECK_ALGORITHM_WIKI: '<a href="${algoUrl}">algorithm details</a> :\u0644\u0645\u0632\u064A\u062F \u0645\u0646 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062A \u062A\u062D\u0642\u0642 \u0645\u0646',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\u0633\u0647\u0648\u0644\u0629 \u0627\u0644\u0642\u0627\u0639\u062F\u0629",
|
|
BASE_EASE_DESC: "\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u062F\u0646\u0649 = 130 \u060C \u0648\u064A\u0641\u0636\u0644 \u062D\u0648\u0627\u0644\u064A 250.",
|
|
BASE_EASE_MIN_WARNING: "\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0633\u0647\u0648\u0644\u0629 \u0627\u0644\u0642\u0627\u0639\u062F\u0629 130 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644.",
|
|
LAPSE_INTERVAL_CHANGE: "\u0627\u0644\u0641\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A \u064A\u062A\u063A\u064A\u0631 \u0639\u0646\u062F \u0645\u0631\u0627\u062C\u0639\u0629 \u0628\u0637\u0627\u0642\u0629/\u0645\u0644\u0627\u062D\u0638\u0629 \u0635\u0639\u0628\u0629",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "newInterval = oldInterval * intervalChange / 100.",
|
|
EASY_BONUS: "\u0645\u0643\u0627\u0641\u0623\u0629 \u0633\u0647\u0644\u0629",
|
|
EASY_BONUS_DESC: "\u062A\u062A\u064A\u062D \u0644\u0643 \u0627\u0644\u0645\u0643\u0627\u0641\u0623\u0629 \u0627\u0644\u0633\u0647\u0644\u0629 \u0636\u0628\u0637 \u0627\u0644\u0641\u0631\u0642 \u0641\u064A \u0627\u0644\u0641\u0648\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A\u0629 \u0628\u064A\u0646 \u0627\u0644\u0631\u062F \u0627\u0644\u062C\u064A\u062F \u0648\u0627\u0644\u0633\u0647\u0644 \u0639\u0644\u0649 \u0628\u0637\u0627\u0642\u0629/\u0645\u0644\u0627\u062D\u0638\u0629 (\u0627\u0644\u062D\u062F \u0627\u0644\u0623\u062F\u0646\u0649 = 100 \u066A).",
|
|
EASY_BONUS_MIN_WARNING: "\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0645\u0643\u0627\u0641\u0623\u0629 \u0627\u0644\u0633\u0647\u0644\u0629 100 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximum interval in days",
|
|
MAX_INTERVAL_DESC: "\u064A\u062A\u064A\u062D \u0644\u0643 \u0648\u0636\u0639 \u062D\u062F \u0623\u0639\u0644\u0649 \u0644\u0644\u0641\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A (\u0627\u0641\u062A\u0631\u0627\u0636\u064A = 100 \u0639\u0627\u0645).",
|
|
MAX_INTERVAL_MIN_WARNING: "\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0644\u0644\u0641\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A \u0644\u0645\u062F\u0629 \u064A\u0648\u0645 \u0648\u0627\u062D\u062F \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644.",
|
|
MAX_LINK_CONTRIB: "\u0623\u0642\u0635\u0649 \u0645\u0633\u0627\u0647\u0645\u0629 \u0627\u0631\u062A\u0628\u0627\u0637",
|
|
MAX_LINK_CONTRIB_DESC: "\u0623\u0642\u0635\u0649 \u0645\u0633\u0627\u0647\u0645\u0629 \u0644\u0644\u0633\u0647\u0648\u0644\u0629 \u0627\u0644\u0645\u0631\u062C\u062D\u0629 \u0644\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A \u0627\u0644\u0645\u0631\u062A\u0628\u0637\u0629 \u0628\u0627\u0644\u0633\u0647\u0648\u0644\u0629 \u0627\u0644\u0623\u0648\u0644\u064A\u0629.",
|
|
LOGGING: "\u062A\u0633\u062C\u064A\u0644",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\u0639\u0631\u0636 \u0645\u0639\u0644\u0648\u0645\u0627\u062A \u0627\u0644\u062A\u0635\u062D\u064A\u062D \u0639\u0644\u0649 \u0648\u062D\u062F\u0629 \u062A\u062D\u0643\u0645 \u0627\u0644\u0645\u0637\u0648\u0631",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\u0645\u0644\u0627\u062D\u0638\u0627\u062A \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0629",
|
|
CLOSE: "\u0623\u063A\u0644\u0642",
|
|
NEW: "\u062C\u062F\u064A\u062F",
|
|
YESTERDAY: "\u0627\u0644\u0628\u0627\u0631\u062D\u0629",
|
|
TODAY: "\u0627\u0644\u064A\u0648\u0645",
|
|
TOMORROW: "\u0627\u0644\u063A\u062F",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u0625\u062D\u0635\u0627\u0626\u064A\u0627\u062A",
|
|
MONTH: "\u0634\u0647\u0631",
|
|
QUARTER: "\u0631\u0628\u0639 \u0627\u0644\u0633\u0646\u0629",
|
|
YEAR: "\u0633\u0646\u0629",
|
|
LIFETIME: "",
|
|
FORECAST: "",
|
|
FORECAST_DESC: "\u0639\u062F\u062F \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0645\u0633\u062A\u062D\u0642\u0629 \u0641\u064A \u0627\u0644\u0645\u0633\u062A\u0642\u0628\u0644",
|
|
SCHEDULED: "\u0627\u0644\u0645\u0642\u0631\u0631",
|
|
DAYS: "\u0623\u064A\u0627\u0645",
|
|
NUMBER_OF_CARDS: "\u0639\u062F\u062F \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
REVIEWS_PER_DAY: "\u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0627\u062A/\u0627\u0644\u064A\u0648\u0645 ${avg} :\u0645\u062A\u0648\u0633\u0637",
|
|
INTERVALS: "\u0641\u0648\u0627\u0635\u0644 \u0632\u0645\u0646\u064A\u0629",
|
|
INTERVALS_DESC: "\u0627\u0644\u062A\u0623\u062E\u064A\u0631 \u062D\u062A\u0649 \u064A\u062A\u0645 \u0639\u0631\u0636 \u0627\u0644\u0645\u0631\u0627\u062C\u0639\u0627\u062A \u0645\u0631\u0629 \u0623\u062E\u0631\u0649",
|
|
COUNT: "\u0639\u062F\u062F",
|
|
INTERVALS_SUMMARY: "${longest} : \u0623\u0637\u0648\u0644 \u0641\u0627\u0635\u0644 \u0632\u0645\u0646\u064A ,${avg} :\u0645\u062A\u0648\u0633\u0637 \u0627\u0644\u0641\u0627\u0635\u0644 \u0627\u0644\u0632\u0645\u0646\u064A",
|
|
EASES: "\u0627\u0644\u0633\u0647\u0648\u0644\u0629",
|
|
EASES_SUMMARY: "${avgEase} :\u0645\u062A\u0648\u0633\u0637 \u0627\u0644\u0633\u0647\u0648\u0644\u0629",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\u0623\u0646\u0648\u0627\u0639 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
CARD_TYPES_DESC: "\u0648\u0647\u0630\u0627 \u064A\u0634\u0645\u0644 \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0645\u062E\u0641\u064A\u0629 \u0643\u0630\u0644\u0643 \u060C \u0625\u0646 \u0648\u062C\u062F\u062A",
|
|
CARD_TYPE_NEW: "\u062C\u062F\u064A\u062F\u0629",
|
|
CARD_TYPE_YOUNG: "\u0635\u063A\u064A\u0631\u0629",
|
|
CARD_TYPE_MATURE: "\u0646\u0627\u0636\u062C\u0629",
|
|
CARD_TYPES_SUMMARY: " ${totalCardsCount} :\u0625\u062C\u0645\u0627\u0644\u064A \u0639\u062F\u062F \u0627\u0644\u0628\u0637\u0627\u0642\u0627\u062A",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/bn.ts
|
|
var bn_default = {};
|
|
|
|
// src/lang/locale/cz.ts
|
|
var cz_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Bal\xED\u010Dky",
|
|
DUE_CARDS: "Karti\u010Dky po term\xEDnu",
|
|
NEW_CARDS: "Nov\xE9 karti\u010Dky",
|
|
TOTAL_CARDS: "Karti\u010Dek celkem",
|
|
BACK: "Back",
|
|
SKIP: "Skip",
|
|
EDIT_CARD: "Edit Card",
|
|
RESET_CARD_PROGRESS: "Vynulovat pokrok karti\u010Dky",
|
|
HARD: "T\u011B\u017Ek\xE9",
|
|
GOOD: "Dobr\xE9",
|
|
EASY: "Jednoduch\xE9",
|
|
SHOW_ANSWER: "Uk\xE1zat odpov\u011B\u010F",
|
|
CARD_PROGRESS_RESET: "Pokrok karti\u010Dky byl vynulov\xE1n.",
|
|
SAVE: "Save",
|
|
CANCEL: "Cancel",
|
|
NO_INPUT: "No input provided.",
|
|
CURRENT_EASE_HELP_TEXT: "Current Ease: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Current Interval: ",
|
|
CARD_GENERATED_FROM: "Generated from: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Otev\u0159\xEDt pozn\xE1mku k revizi",
|
|
REVIEW_CARDS: "Pozn\xE1mek k revizi",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Revize: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Ozna\u010Dit pozn\xE1mku jako ${difficulty}",
|
|
REVIEW_ALL_CARDS: "Revidovat karti\u010Dky ve v\u0161ech pozn\xE1mk\xE1ch",
|
|
CRAM_ALL_CARDS: "Select a deck to cram",
|
|
REVIEW_CARDS_IN_NOTE: "Revidovat karti\u010Dky v t\xE9to pozn\xE1mce.",
|
|
CRAM_CARDS_IN_NOTE: "Cram karti\u010Dky v t\xE9to pozn\xE1mce.",
|
|
VIEW_STATS: "Uk\xE1zat statistiky",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Revize: ${dueNotesCount} pozn\xE1mek, ${dueFlashcardsCount} karti\u010Dek po term\xEDnu",
|
|
SYNC_TIME_TAKEN: "Synchronizace trvala ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "Pozn\xE1mka je ulo\u017Eena v ignorovan\xE9 slo\u017Ece (zkontrolujte nastaven\xED).",
|
|
PLEASE_TAG_NOTE: "Pros\xEDm ozna\u010Dne pozn\xE1mku odpov\xEDdaj\xEDc\xEDm tagem pro revizi (v nastaven\xED).",
|
|
RESPONSE_RECEIVED: "Odpov\u011B\u010F p\u0159ijata.",
|
|
NO_DECK_EXISTS: "Neexistuje \u017E\xE1dn\xFD bal\xED\u010Dek pro ${deckName}",
|
|
ALL_CAUGHT_UP: "V\u0161e zrevidov\xE1no",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} den/dn\xED",
|
|
MONTHS_STR_IVL: "${interval} m\u011Bs\xEDc(\u016F)",
|
|
YEARS_STR_IVL: "${interval} rok(\u016F)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}r",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Pro v\xEDce informac\xED jd\u011Bte na <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Ignorovan\xE9 slo\u017Eky",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Karti\u010Dky",
|
|
FLASHCARD_EASY_LABEL: "Easy Button Text",
|
|
FLASHCARD_GOOD_LABEL: "Good Button Text",
|
|
FLASHCARD_HARD_LABEL: "Hard Button Text",
|
|
FLASHCARD_EASY_DESC: 'Customize the label for the "Easy" Button',
|
|
FLASHCARD_GOOD_DESC: 'Customize the label for the "Good" Button',
|
|
FLASHCARD_HARD_DESC: 'Customize the label for the "Hard" Button',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Tag pro karti\u010Dky",
|
|
FLASHCARD_TAGS_DESC: "Zadete tagy ood\u011Blen\xE9 mezerou nebo od\u0159\xE1dkov\xE1n\xEDm nap\u0159\xEDklad. #karti\u010Dky #bal\xED\u010Dke2 #bal\xED\u010Dek3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "P\u0159ev\xE9st slo\u017Eky na bal\xED\u010Dky a podbal\xED\u010Dky?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Toto je alternativa k tag\u016Fm karti\u010Dek viz nastaven\xED v\xFD\u0161e.",
|
|
INLINE_SCHEDULING_COMMENTS: "Ulo\u017Eit pl\xE1novac\xED koment\xE1\u0159 na stejn\xFD \u0159\xE1dek jako posledn\xED polo\u017Eka karti\u010Dky?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Zapnut\xED t\xE9to volby zp\u016Fsob\xED, \u017Ee HTML koment\xE1\u0159e nebudou rozb\xEDjet form\xE1tov\xE1n\xED list\u016F.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Odlo\u017Eit p\u0159\xEDbuzn\xE9 karti\u010Dky na dal\u0161\xED den?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "P\u0159\xEDbuzn\xE9 karti\u010Dky jsou karti\u010Dky generovan\xE9 z textu stejn\xE9 pozn\xE1mky nap\u0159\xEDklad cloze smaz\xE1n\xED",
|
|
SHOW_CARD_CONTEXT: "Uk\xE1zat kontext v karti\u010Dce?",
|
|
SHOW_CARD_CONTEXT_DESC: "nap\u0159\xEDklad Titulek > Nadpis1 > Podnadpis > ... > Podnadpis",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "V\xFD\u0161ka karti\u010Dek v procentech",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "M\u011Blo by b\xFDt nastaveno na 100% na mobilu nebo kdy\u017E pou\u017E\xEDv\xE1te velk\xE9 obr\xE1zky",
|
|
RESET_DEFAULT: "Resetovat v\xFDchoz\xED nastaven\xED",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u0160\xED\u0159ka karti\u010Dek v procentech",
|
|
RANDOMIZE_CARD_ORDER: "N\xE1hodn\u011B zm\u011Bnit po\u0159ad\xED karti\u010Dek b\u011Bhem revize?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "Vypnout cloze karti\u010Dky?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "P\u0159ev\xE9st ==zv\xFDrazn\u011Bn\xED== na clozes?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "P\u0159ev\xE9st **tu\u010Dn\xFD text** na clozes?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "P\u0159ev\xE9st {{slo\u017Een\xE9 z\xE1vorky}} na clozes?",
|
|
CLOZE_PATTERNS: "Cloze vzory",
|
|
CLOZE_PATTERNS_DESC: 'Zadejte cloze vzory odd\u011Blen\xE9 od\u0159\xE1dkov\xE1n\xEDm. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Odd\u011Blova\u010D pro inline karti\u010Dky",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Pozor. Jakmile toto zm\u011Bn\xEDte, budete muset ru\u010Dn\u011B upravit v\u0161echny existuj\xEDc\xED karti\u010Dky.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Odd\u011Blova\u010D pro oto\u010Den\xE9 inline karti\u010Dky",
|
|
MULTILINE_CARDS_SEPARATOR: "Odd\u011Blova\u010D pro v\xEDce\u0159\xE1dkov\xE9 karti\u010Dky",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Odd\u011Blova\u010D pro v\xEDce\u0159\xE1dkove oto\u010Den\xE9 karti\u010Dky",
|
|
MULTILINE_CARDS_END_MARKER: "Znaky ozna\u010Duj\xEDc\xED konec clozes a v\xEDce\u0159\xE1dkov\xFDch flash karet",
|
|
NOTES: "Pozn\xE1mky",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Enable note review pane on startup",
|
|
TAGS_TO_REVIEW: "Tag pro revizi",
|
|
TAGS_TO_REVIEW_DESC: "Zadejte tagy odd\u011Blen\xE9 mezerami nebo od\u0159\xE1dkov\xE1n\xEDm nap\u0159\xEDklad #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "Otev\u0159\xEDt n\xE1hodnou pozn\xE1mku pro revizi",
|
|
OPEN_RANDOM_NOTE_DESC: "Pokud toto vypnete, pozn\xE1mky budou \u0159azeny dle d\u016Fle\u017Eitosti (PageRank).",
|
|
AUTO_NEXT_NOTE: "Otev\u0159\xEDt automaticky dal\u0161\xED pozn\xE1mku po dokon\u010Den\xED revize",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Povolte mo\u017Enosti revize v nab\xEDdce souboru (nap\u0159. Revize: Jednoduch\xE9, Dobr\xE9, T\u011B\u017Ek\xE9)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Pokud v nab\xEDdce souboru zak\xE1\u017Eete mo\u017Enosti revize, m\u016F\u017Eete sv\xE9 pozn\xE1mky revidovat pomoc\xED p\u0159\xEDkaz\u016F pluginu a, pokud jste je definovali, pomoc\xED p\u0159i\u0159azen\xFDch kl\xE1vesov\xFDch zkratek.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Maxim\xE1ln\xED po\u010Det dn\xED zobrazen\xFDch v prav\xE9m panelu",
|
|
MIN_ONE_DAY: "Po\u010Det dn\xED mus\xED b\xFDt minim\xE1ln\u011B 1.",
|
|
VALID_NUMBER_WARNING: "Pros\xEDm zadejte validn\xED \u010D\xEDslo.",
|
|
UI: "P\u0159edvolby u\u017Eivatelsk\xE9ho rozhran\xED",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Stromy bal\xED\u010Dky by m\u011Bly b\xFDt zpo\u010D\xE1tku zobrazeny jako rozbalen\xE9",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Vypn\u011Bte toto, chcete-li sbalit vno\u0159en\xE9 bal\xED\u010Dky na stejn\xE9 kart\u011B. To je u\u017Eite\u010Dn\xE9, pokud m\xE1te karti\u010Dky, kter\xE9 pat\u0159\xED k mnoha bal\xED\u010Dk\u016Fm ve stejn\xE9m souboru.",
|
|
ALGORITHM: "Algoritmus",
|
|
CHECK_ALGORITHM_WIKI: 'Pro v\xEDce informac\xED jd\u011Bte na <a href="${algoUrl}">popis algoritmu</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Z\xE1kladn\xED slo\u017Eitost",
|
|
BASE_EASE_DESC: "minimum = 130, nejl\xE9pe p\u0159ibli\u017En\u011B 250.",
|
|
BASE_EASE_MIN_WARNING: "Z\xE1kladn\xED slo\u017Eitost mus\xED b\xFDt minim\xE1ln\u011B 130.",
|
|
LAPSE_INTERVAL_CHANGE: "Zm\u011Bna intervalu pokud karti\u010Dku/pozn\xE1mku ozna\u010D\xEDte jako slo\u017Eitou",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "nov\xFD_inteval = star\xFD_interval * zm\u011Bna_intevalu / 100.",
|
|
EASY_BONUS: "Bonus pro jednoduch\xE9",
|
|
EASY_BONUS_DESC: "Tento bonus umo\u017E\u0148uje nastavit rozd\xEDl intervalu mezi jednoduch\xFDmi a dobr\xFDmi karti\u010Dkami/pozn\xE1mkami (minimum = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "Bonus pro jednoduchost mus\xED b\xFDt minim\xE1ln\u011B 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximum interval in days",
|
|
MAX_INTERVAL_DESC: "Umo\u017E\u0148uje nastavit horn\xED limit pro interval (defaultn\u011B = 100 let).",
|
|
MAX_INTERVAL_MIN_WARNING: "Maxim\xE1ln\xED interval mus\xED b\xFDt alespo\u0148 1 den.",
|
|
MAX_LINK_CONTRIB: "Maxim\xE1ln\xED p\u0159\xEDsp\u011Bv\u011Bk prolinkov\xE1n\xED",
|
|
MAX_LINK_CONTRIB_DESC: "Maxim\xE1ln\xED p\u0159\xEDsp\u011Bvek v\xE1\u017Een\xE9 slo\u017Eitosti prolinkovan\xFDch pozn\xE1mek pou\u017Eit\xFD pro ur\u010Den\xED po\u010D\xE1te\u010Dn\xED slo\u017Eitosti.",
|
|
LOGGING: "Zaznamen\xE1v\xE1m",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Zobrazit informace pro lad\u011Bn\xED na v\xFDvoj\xE1\u0159sk\xE9 konzoli",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Fronta pozn\xE1mek k revizi",
|
|
CLOSE: "Uzav\u0159en\xE9",
|
|
NEW: "Nov\xE9",
|
|
YESTERDAY: "V\u010Dera",
|
|
TODAY: "Dnes",
|
|
TOMORROW: "Z\xEDtra",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statistiky",
|
|
MONTH: "M\u011Bs\xEDc",
|
|
QUARTER: "\u010Ctvrtlet\xED",
|
|
YEAR: "Rok",
|
|
LIFETIME: "Celkov\u011B",
|
|
FORECAST: "P\u0159edpov\u011B\u010F",
|
|
FORECAST_DESC: "Celkov\xFD po\u010Det karti\u010Dek, kter\xFDm vypr\u0161\xED term\xEDn",
|
|
SCHEDULED: "Napl\xE1nov\xE1no",
|
|
DAYS: "Dn\xED",
|
|
NUMBER_OF_CARDS: "Po\u010Det karti\u010Dek",
|
|
REVIEWS_PER_DAY: "Pr\u016Fm\u011Br: ${avg} revize/den",
|
|
INTERVALS: "Intervaly",
|
|
INTERVALS_DESC: "Doba, za kterou bude znovu zobrazeno k revize",
|
|
COUNT: "Po\u010Det",
|
|
INTERVALS_SUMMARY: "Pr\u016Fm\u011Brn\xFD interval: ${avg}, Nejdel\u0161\xED interval: ${longest}",
|
|
EASES: "Slo\u017Eitost",
|
|
EASES_SUMMARY: "Pr\u016Fm\u011Brn\xE1 slo\u017Eitost: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Typy karti\u010Dek",
|
|
CARD_TYPES_DESC: "Obsahuje i odlo\u017Een\xE9 karti\u010Dky (pokud existuj\xED)",
|
|
CARD_TYPE_NEW: "Nov\xE1",
|
|
CARD_TYPE_YOUNG: "Mlad\xE1",
|
|
CARD_TYPE_MATURE: "Dosp\u011Bl\xE1",
|
|
CARD_TYPES_SUMMARY: "Karti\u010Dek celkem: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/da.ts
|
|
var da_default = {};
|
|
|
|
// src/lang/locale/de.ts
|
|
var de_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Stapel",
|
|
DUE_CARDS: "Anstehende Karten",
|
|
NEW_CARDS: "Neue Karten",
|
|
TOTAL_CARDS: "Alle Karten",
|
|
BACK: "Zur\xFCck",
|
|
SKIP: "\xDCberspringen",
|
|
EDIT_CARD: "Karte bearbeiten",
|
|
RESET_CARD_PROGRESS: "Kartenfortschritt zur\xFCcksetzten",
|
|
HARD: "Schwer",
|
|
GOOD: "Gut",
|
|
EASY: "Einfach",
|
|
SHOW_ANSWER: "Zeige Antwort",
|
|
CARD_PROGRESS_RESET: "Kartenfortschritt wurde zur\xFCckgesetzt.",
|
|
SAVE: "Speichern",
|
|
CANCEL: "Abbrechen",
|
|
NO_INPUT: "Keine Eingabe erhalten.",
|
|
CURRENT_EASE_HELP_TEXT: "Aktuelle Schwierigkeit: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Aktueller Intervall: ",
|
|
CARD_GENERATED_FROM: "Erstellt von: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Notiz zur Wiederholung \xF6ffnen",
|
|
REVIEW_CARDS: "Lernkarten wiederholen",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Notizen wiederholen als: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Notizen wiederholen als: ${difficulty}",
|
|
REVIEW_ALL_CARDS: "Alle Lernkarten wiederholen",
|
|
CRAM_ALL_CARDS: "W\xE4hle ein Stapel zum pauken",
|
|
REVIEW_CARDS_IN_NOTE: "Lernkarten in dieser Notiz wiederholen",
|
|
CRAM_CARDS_IN_NOTE: "Lernkarten in dieser Notiz pauken.",
|
|
VIEW_STATS: "Statistiken anzeigen",
|
|
OPEN_REVIEW_QUEUE_VIEW: "\xD6ffne \xDCberpr\xFCfungswarteschlage in der Seitenleiste",
|
|
STATUS_BAR: "Wiederholung: ${dueNotesCount} Notiz(en), ${dueFlashcardsCount} Karte(n) anstehend",
|
|
SYNC_TIME_TAKEN: "Synchronisierung dauerte ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "Notiz befindet sich in einem ausgeschlossenen Ordner (siehe Einstellungen).",
|
|
PLEASE_TAG_NOTE: "Bitte die Notiz f\xFCr Wiederholungen entsprechend taggen (siehe Einstellungen).",
|
|
RESPONSE_RECEIVED: "Antwort erhalten.",
|
|
NO_DECK_EXISTS: "Kein Stapel f\xFCr ${deckName} gefunden.",
|
|
ALL_CAUGHT_UP: "Yuhu! Alles geschafft! :D.",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} Tag(e)",
|
|
MONTHS_STR_IVL: "${interval} Monat(e)",
|
|
YEARS_STR_IVL: "${interval} Jahr(e)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}t",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}j",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Weitere Informationen gibt es im <a href="${wikiUrl}">Wiki</a> (english).',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Ausgeschlossene Ordner",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Lernkarten",
|
|
FLASHCARD_EASY_LABEL: "Einfach Knopf Text",
|
|
FLASHCARD_GOOD_LABEL: "Gut Knopf Text",
|
|
FLASHCARD_HARD_LABEL: "Schwer Knopf Text",
|
|
FLASHCARD_GOOD_DESC: 'Passe die Beschriftung f\xFCr "Gut" Knopf an',
|
|
FLASHCARD_EASY_DESC: 'Passe die Beschriftung f\xFCr "Einfach" Knopf an',
|
|
FLASHCARD_HARD_DESC: 'Passe die Beschriftung f\xFCr "Schwer" Knopf an',
|
|
REVIEW_BUTTON_DELAY: "Druckknopfverz\xF6gerung (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "F\xFCgt den \xDCberpr\xFCfungsschaltfl\xE4chen (\u201EEinfach\u201C, \u201EGut\u201C, \u201ESchwer\u201C, \u201EAntwort anzeigen\u201C) eine Verz\xF6gerung hinzu, bevor sie erneut gedr\xFCckt werden k\xF6nnen.",
|
|
FLASHCARD_TAGS: "Lernkarten Tags",
|
|
FLASHCARD_TAGS_DESC: "Mehrere Tags mit Leerzeichen oder Zeilenumbr\xFCchen getrennt angeben. Bsp. #karte #stapel2 #stapel3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Ordner in Stapel und Substapel umwandeln?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: 'Eine Alternative zur oberen "Lernkarten Tags" Option.',
|
|
INLINE_SCHEDULING_COMMENTS: "Den Fortschritt in der gleichen Zeile wie die letzte Zeile einer Lernkartei speichern?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Wenn aktiviert, wird der HTML Kommentar die umgebende Liste nicht aufbrechen.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Verwandte Karten auf den n\xE4chsten Tag verlegen?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Verwandte Karten sind aus der gleichen Karte generiert worden (z.B. L\xFCckentextkarten oder beidseitige Karten).",
|
|
SHOW_CARD_CONTEXT: "Kontext in den Karten anzeigen?",
|
|
SHOW_CARD_CONTEXT_DESC: "Bsp. Titel > \xDCberschrift 1 > Sektion > ... > Untersektion",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "H\xF6he der Lernkartei in Prozent",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Auf kleinen Bildschirmen (z.B. Smartphones) oder bei sehr grossen Bildern sollte dieser Wert auf 100% gesetzt werden.",
|
|
RESET_DEFAULT: "Standardeinstellung wiederherstellen",
|
|
CARD_MODAL_WIDTH_PERCENT: "Breite einer Lernkarte in Prozent",
|
|
RANDOMIZE_CARD_ORDER: "W\xE4hrend der Wiederhoung die Reihenfolge zuf\xE4llig mischen?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Reihenfolge der Karten innerhalb eines Stapels w\xE4hrend der Wiederholung",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentielle Reihenfolge innerhalb eines Stapels (Alle neuen Karten zuerst)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentielle Reihenfolge innerhalb eines Stapels (Alle f\xE4lligen Karten zuerst)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Zuf\xE4llige Reihenfolge innerhalb eines Stapels (Alle neuen Karten zuerst)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Zuf\xE4llige Reihenfolge innerhalb eines Stapels (Alle f\xE4lligen Karten zuerst)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Zuf\xE4llige Karte von zuf\xE4lligem Stapel",
|
|
REVIEW_DECK_ORDER: "Reihenfolge der Stapel w\xE4hrend der Wiederholung",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentielle Reihenfolge (sobald alle Karten im vorherigen Stapel wiederholt wurden)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Zuf\xE4llige Reihenfolge (sobald alle Karten im vorherigen Stapel wiederholt wurden)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Zuf\xE4llige Karte von zuf\xE4lligem Stapel",
|
|
DISABLE_CLOZE_CARDS: "L\xFCckentextkarten deaktivieren?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "==Hervorgehobenen== Text in L\xFCckentextkarten umwandeln?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "**Fettgedruckten** Text in L\xFCckentextkarten umwandeln?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "{{Geschweifte Klammern}} Text in L\xFCckentextkarten umwandeln?",
|
|
CLOZE_PATTERNS: "L\xFCckentextmuster",
|
|
CLOZE_PATTERNS_DESC: 'Geben Sie L\xFCckentextmuster durch Zeilenumbr\xFCche getrennt ein. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Trennzeichen f\xFCr einzeilige Lernkarten",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Wenn diese Einstellung ge\xE4ndert wird, dann m\xFCssen die entsprechenden Lernkarten manuell angepasst werden.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Trennzeichen f\xFCr einzeilige beidseitige Lernkarten",
|
|
MULTILINE_CARDS_SEPARATOR: "Trennzeichen f\xFCr mehrzeilige Lernkarten",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Trennzeichen f\xFCr mehrzeilige beidseitige Lernkarten",
|
|
MULTILINE_CARDS_END_MARKER: "Zeichen, die das Ende von L\xFCckentexten und mehrzeiligen Flashcards kennzeichnen",
|
|
NOTES: "Notizen",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "\xD6ffne \xDCberpr\xFCfungswarteschlage beim start",
|
|
TAGS_TO_REVIEW: "Zu wiederholende Tags",
|
|
TAGS_TO_REVIEW_DESC: "Mehrere Tags k\xF6nnen mit Leerzeichen oder Zeilenumbr\xFCchen getrennt angegeben werden. Bsp. #karte #tag1 #tag2.",
|
|
OPEN_RANDOM_NOTE: "Zuf\xE4llige Karten wiederholen",
|
|
OPEN_RANDOM_NOTE_DESC: "Wenn dies deaktiviert wird, dann werden die Notizen nach Wichtigkeit wiederholt (PageRank).",
|
|
AUTO_NEXT_NOTE: "Nach einer Wiederholung automatisch die n\xE4chste Karte \xF6ffnen",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Aktiviere die \xDCberpr\xFCfungsoptionen im Dateimen\xFC (z. B. Notizen wiederholen als: Einfach, Gut, Schwer)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Wenn du die \xDCberpr\xFCfungsoptionen im Dateimen\xFC deaktivierst, kannst du deine Notizen mit den Plugin-Befehlen und, falls definiert, den zugeh\xF6rigen Tastenkombinationen \xFCberpr\xFCfen.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Maximale Anzahl anstehender Notizen, die im rechten Fensterbereich angezeigt werden",
|
|
MIN_ONE_DAY: "Anzahl der Tage muss mindestens 1 sein.",
|
|
VALID_NUMBER_WARNING: "Bitte eine g\xFCltige Zahl eingeben.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Stapelverzeichnis soll beim \xF6ffnen erweitert angezeigt werden",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Deaktivieren Sie dies, um verschachtelte Stapel in derselben Karte zu reduzieren. N\xFCtzlich, wenn Sie Karten haben, die zu vielen Stapeln in derselben Datei geh\xF6ren.",
|
|
ALGORITHM: "Algorithmus",
|
|
CHECK_ALGORITHM_WIKI: 'Weiterf\xFChrende Informationen: <a href="${algoUrl}">Implementierung des Algorithmus</a> (english).',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Basis der Schwierigkeit",
|
|
BASE_EASE_DESC: "Minimum ist 130. Empfohlen wird ca. 250.",
|
|
BASE_EASE_MIN_WARNING: "Basis der Schwierigkeit muss mindestens 130 sein.",
|
|
LAPSE_INTERVAL_CHANGE: "Anpassungsfaktor des Intervalls wenn eine Notiz / Karte 'Schwer' abgeschlossen wird",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "neuesIntervall = altesIntervall * anpassungsfaktor / 100.",
|
|
EASY_BONUS: "Einfachheit-Bonus",
|
|
EASY_BONUS_DESC: "Der Einfachheit-Bonus gibt an um welchen Faktor (in Prozent) das Intervall l\xE4nger sein soll, wenn eine Notiz / Karte 'Einfach' statt 'Gut' abgeschlossen wird. Minimum ist 100%.",
|
|
EASY_BONUS_MIN_WARNING: "Der Einfachheit-Bonus muss mindestens 100 sein.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximale Intervall in Tagen",
|
|
MAX_INTERVAL_DESC: "Das maximale Intervall (in Tagen) f\xFCr Wiederholungen. Standard sind 100 Jahre.",
|
|
MAX_INTERVAL_MIN_WARNING: "Das maximale Interall muss mindestens ein Tag sein.",
|
|
MAX_LINK_CONTRIB: "Maximaler Einfluss von Links",
|
|
MAX_LINK_CONTRIB_DESC: "Maximaler Einfluss der Einfachheiten verlinkter Notizen zur gewichteten initialen Einfachheit einer neuen Lernkarte.",
|
|
LOGGING: "Protokollierung",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Informationen zum Debugging in der Entwicklerkonsole anzeigen",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Informationen zum parser Debugging in der Entwicklerkonsole anzeigen",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Anstehende Notizen zur Wiederholung",
|
|
CLOSE: "Schliessen",
|
|
NEW: "Neu",
|
|
YESTERDAY: "Gestern",
|
|
TODAY: "Heute",
|
|
TOMORROW: "Morgen",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statistiken",
|
|
MONTH: "Monat",
|
|
QUARTER: "Quartal",
|
|
YEAR: "Jahr",
|
|
LIFETIME: "Lebenslang",
|
|
FORECAST: "Prognose",
|
|
FORECAST_DESC: "Anzahl der k\xFCnftig anstehenden Karten",
|
|
SCHEDULED: "Anstehend",
|
|
DAYS: "Tage",
|
|
NUMBER_OF_CARDS: "Anzahl der Karten",
|
|
REVIEWS_PER_DAY: "Durchschnitt: ${avg} Wiederholungen/Tag",
|
|
INTERVALS: "Intervalle",
|
|
INTERVALS_DESC: "Intervalle bis Wiederholungen anstehen",
|
|
COUNT: "Anzahl",
|
|
INTERVALS_SUMMARY: "Durchschnittliches Intervall: ${avg}, L\xE4ngstes Intervall: ${longest}",
|
|
EASES: "Schwierigkeit",
|
|
EASES_SUMMARY: "Durchschnittliche Schwierigkeit: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Kategorisierung",
|
|
CARD_TYPES_DESC: "Verlegte Karten eingeschlossen",
|
|
CARD_TYPE_NEW: "Neu",
|
|
CARD_TYPE_YOUNG: "Jung",
|
|
CARD_TYPE_MATURE: "Ausgereift",
|
|
CARD_TYPES_SUMMARY: "Insgesamt ${totalCardsCount} Karten",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/en.ts
|
|
var en_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Decks",
|
|
DUE_CARDS: "Due Cards",
|
|
NEW_CARDS: "New Cards",
|
|
TOTAL_CARDS: "Total Cards",
|
|
BACK: "Back",
|
|
SKIP: "Skip",
|
|
EDIT_CARD: "Edit Card",
|
|
RESET_CARD_PROGRESS: "Reset card's progress",
|
|
HARD: "Hard",
|
|
GOOD: "Good",
|
|
EASY: "Easy",
|
|
SHOW_ANSWER: "Show Answer",
|
|
CARD_PROGRESS_RESET: "Card's progress has been reset.",
|
|
SAVE: "Save",
|
|
CANCEL: "Cancel",
|
|
NO_INPUT: "No input provided.",
|
|
CURRENT_EASE_HELP_TEXT: "Current Ease: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Current Interval: ",
|
|
CARD_GENERATED_FROM: "Generated from: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Open a note for review",
|
|
REVIEW_CARDS: "Review flashcards",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Review: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Review note as ${difficulty}",
|
|
CRAM_ALL_CARDS: "Select a deck to cram",
|
|
REVIEW_ALL_CARDS: "Review flashcards from all notes",
|
|
REVIEW_CARDS_IN_NOTE: "Review flashcards in this note",
|
|
CRAM_CARDS_IN_NOTE: "Cram flashcards in this note",
|
|
VIEW_STATS: "View statistics",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Review: ${dueNotesCount} note(s), ${dueFlashcardsCount} card(s) due",
|
|
SYNC_TIME_TAKEN: "Sync took ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "Note is saved under ignored folder (check settings).",
|
|
PLEASE_TAG_NOTE: "Please tag the note appropriately for reviewing (in settings).",
|
|
RESPONSE_RECEIVED: "Response received.",
|
|
NO_DECK_EXISTS: "No deck exists for ${deckName}",
|
|
ALL_CAUGHT_UP: "You're all caught up now :D.",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} day(s)",
|
|
MONTHS_STR_IVL: "${interval} month(s)",
|
|
YEARS_STR_IVL: "${interval} year(s)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}y",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'For more information, check the <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Folders to ignore",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Flashcards",
|
|
FLASHCARD_EASY_LABEL: "Easy Button Text",
|
|
FLASHCARD_GOOD_LABEL: "Good Button Text",
|
|
FLASHCARD_HARD_LABEL: "Hard Button Text",
|
|
FLASHCARD_EASY_DESC: 'Customize the label for the "Easy" Button',
|
|
FLASHCARD_GOOD_DESC: 'Customize the label for the "Good" Button',
|
|
FLASHCARD_HARD_DESC: 'Customize the label for the "Hard" Button',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Flashcard tags",
|
|
FLASHCARD_TAGS_DESC: "Enter tags separated by spaces or newlines i.e. #flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Convert folders to decks and subdecks",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "This is an alternative to the Flashcard tags option above.",
|
|
INLINE_SCHEDULING_COMMENTS: "Save scheduling comment on the same line as the flashcard's last line?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Turning this on will make the HTML comments not break list formatting.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Bury sibling cards until the next day",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Siblings are cards generated from the same card text i.e. cloze deletions",
|
|
SHOW_CARD_CONTEXT: "Show context in cards",
|
|
SHOW_CARD_CONTEXT_DESC: "i.e. Title > Heading 1 > Subheading > ... > Subheading",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Flashcard Height Percentage",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Should be set to 100% on mobile or if you have very large images",
|
|
RESET_DEFAULT: "Reset to default",
|
|
CARD_MODAL_WIDTH_PERCENT: "Flashcard Width Percentage",
|
|
RANDOMIZE_CARD_ORDER: "Randomize card order during review?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "Disable cloze cards?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Convert ==highlights== to clozes",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Convert **bolded text** to clozes",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Convert {{curly brackets}} to clozes",
|
|
CLOZE_PATTERNS: "Cloze Patterns",
|
|
CLOZE_PATTERNS_DESC: 'Enter cloze patterns separated by newlines. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Separator for inline flashcards",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Note that after changing this you have to manually edit any flashcards you already have.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Separator for inline reversed flashcards",
|
|
MULTILINE_CARDS_SEPARATOR: "Separator for multiline flashcards",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Separator for multiline reversed flashcards",
|
|
MULTILINE_CARDS_END_MARKER: "Characters denoting the end of clozes and multiline flashcards",
|
|
NOTES: "Notes",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Enable note review pane on startup",
|
|
TAGS_TO_REVIEW: "Tags to review",
|
|
TAGS_TO_REVIEW_DESC: "Enter tags separated by spaces or newlines i.e. #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "Open a random note for review",
|
|
OPEN_RANDOM_NOTE_DESC: "When you turn this off, notes are ordered by importance (PageRank).",
|
|
AUTO_NEXT_NOTE: "Open next note automatically after a review",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Maximum number of days to display on note review panel",
|
|
MIN_ONE_DAY: "The number of days must be at least 1.",
|
|
VALID_NUMBER_WARNING: "Please provide a valid number.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Enable the review options in the file menu (e.g. Review: Easy, Good, Hard)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "If you disable the review options in the file menu, you can review your notes using the plugin commands and, if you defined them, the associated command hotkeys.",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Deck trees should be initially displayed as expanded",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Turn this off to collapse nested decks in the same card. Useful if you have cards which belong to many decks in the same file.",
|
|
ALGORITHM: "Algorithm",
|
|
CHECK_ALGORITHM_WIKI: 'For more information, check the <a href="${algoUrl}">algorithm details</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Base ease",
|
|
BASE_EASE_DESC: "minimum = 130, preferrably approximately 250.",
|
|
BASE_EASE_MIN_WARNING: "The base ease must be at least 130.",
|
|
LAPSE_INTERVAL_CHANGE: "Interval change when you review a flashcard/note as hard",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "newInterval = oldInterval * intervalChange / 100.",
|
|
EASY_BONUS: "Easy Bonus",
|
|
EASY_BONUS_DESC: "The easy bonus allows you to set the difference in intervals between answering Good and Easy on a flashcard/note (minimum = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "The easy bonus must be at least 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximum interval in days",
|
|
MAX_INTERVAL_DESC: "Allows you to place an upper limit on the interval (default = 100 years).",
|
|
MAX_INTERVAL_MIN_WARNING: "The maximum interval must be at least 1 day.",
|
|
MAX_LINK_CONTRIB: "Maximum link contribution",
|
|
MAX_LINK_CONTRIB_DESC: "Maximum contribution of the weighted ease of linked notes to the initial ease.",
|
|
LOGGING: "Logging",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Show the scheduler's debugging information on the developer console",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Notes Review Queue",
|
|
CLOSE: "Close",
|
|
NEW: "New",
|
|
YESTERDAY: "Yesterday",
|
|
TODAY: "Today",
|
|
TOMORROW: "Tomorrow",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statistics",
|
|
MONTH: "Month",
|
|
QUARTER: "Quarter",
|
|
YEAR: "Year",
|
|
LIFETIME: "Lifetime",
|
|
FORECAST: "Forecast",
|
|
FORECAST_DESC: "The number of cards due in the future",
|
|
SCHEDULED: "Scheduled",
|
|
DAYS: "Days",
|
|
NUMBER_OF_CARDS: "Number of cards",
|
|
REVIEWS_PER_DAY: "Average: ${avg} reviews/day",
|
|
INTERVALS: "Intervals",
|
|
INTERVALS_DESC: "Delays until reviews are shown again",
|
|
COUNT: "Count",
|
|
INTERVALS_SUMMARY: "Average interval: ${avg}, Longest interval: ${longest}",
|
|
EASES: "Eases",
|
|
EASES_SUMMARY: "Average ease: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Card Types",
|
|
CARD_TYPES_DESC: "This includes buried cards as well, if any",
|
|
CARD_TYPE_NEW: "New",
|
|
CARD_TYPE_YOUNG: "Young",
|
|
CARD_TYPE_MATURE: "Mature",
|
|
CARD_TYPES_SUMMARY: "Total cards: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/en-gb.ts
|
|
var en_gb_default = {};
|
|
|
|
// src/lang/locale/es.ts
|
|
var es_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Mazos",
|
|
DUE_CARDS: "Tarjetas Vencidas",
|
|
NEW_CARDS: "Tarjetas Nuevas",
|
|
TOTAL_CARDS: "Tarjetas Totales",
|
|
BACK: "Atr\xE1s",
|
|
SKIP: "Saltar",
|
|
EDIT_CARD: "Editar Tarjeta",
|
|
RESET_CARD_PROGRESS: "Reiniciar progreso de la tarjeta",
|
|
HARD: "Dif\xEDcil",
|
|
GOOD: "Bien",
|
|
EASY: "F\xE1cil",
|
|
SHOW_ANSWER: "Mostrar Respuesta",
|
|
CARD_PROGRESS_RESET: "El progreso de la tarjeta se ha reiniciado.",
|
|
SAVE: "Guardar",
|
|
CANCEL: "Cancelar",
|
|
NO_INPUT: "Se ha prove\xEDdo entrada.",
|
|
CURRENT_EASE_HELP_TEXT: "Facilidad Actual: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Intervalo Actual: ",
|
|
CARD_GENERATED_FROM: "Generado Desde: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Abrir nota para revisi\xF3n",
|
|
REVIEW_CARDS: "Revisar Tarjetas",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Revisar: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Revisar nota como ${difficulty}",
|
|
CRAM_ALL_CARDS: "Selecciona un mazo a memorizar",
|
|
REVIEW_ALL_CARDS: "Revisar tarjetas de todas las notas",
|
|
REVIEW_CARDS_IN_NOTE: "Revisar tarjetas en esta nota",
|
|
CRAM_CARDS_IN_NOTE: "Memorizar tarjetas en esta nota",
|
|
VIEW_STATS: "Ver estad\xEDsticas",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Revisar: ${dueNotesCount} nota(s), ${dueFlashcardsCount} tarjetas vencidas",
|
|
SYNC_TIME_TAKEN: "La sincronizaci\xF3n tom\xF3 ${t} milisegundos",
|
|
NOTE_IN_IGNORED_FOLDER: "La nota est\xE1 guardada en un directorio ignorado (revisa los ajustes).",
|
|
PLEASE_TAG_NOTE: "Por favor etiquete apropiadamente la nota para revisi\xF3n (en los ajustes).",
|
|
RESPONSE_RECEIVED: "Respuesta Recibida",
|
|
NO_DECK_EXISTS: "No existen mazos para: ${deckName}",
|
|
ALL_CAUGHT_UP: "\xA1Est\xE1s al d\xEDa! \u{1F603}",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} d\xEDa(s)",
|
|
MONTHS_STR_IVL: "${interval} mes(es)",
|
|
YEARS_STR_IVL: "${interval} a\xF1o(s)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}a",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Extensi\xF3n de Repetici\xF3n Espaciada",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Para m\xE1s informaci\xF3n revisa la <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Directorios a ignorar",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Tarjetas de Memorizaci\xF3n",
|
|
FLASHCARD_EASY_LABEL: "Texto del bot\xF3n: F\xE1cil",
|
|
FLASHCARD_GOOD_LABEL: "Texto del bot\xF3n: Bien",
|
|
FLASHCARD_HARD_LABEL: "Texto del bot\xF3n: Dif\xEDcil",
|
|
FLASHCARD_EASY_DESC: "Personalize la etiqueta para el bot\xF3n: F\xE1cil",
|
|
FLASHCARD_GOOD_DESC: "Personalize la etiqueta para el bot\xF3n: Bien",
|
|
FLASHCARD_HARD_DESC: "Personalize la etiqueta para el bot\xF3n: Dif\xEDcil",
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Etiquetas de las Tarjetas de Memorizaci\xF3n",
|
|
FLASHCARD_TAGS_DESC: "Escriba las etiquetas separadas por espacios o saltos de l\xEDnea, por ejemplo, #memorizar #mazo2 #mazo3",
|
|
CONVERT_FOLDERS_TO_DECKS: "\xBFConvertir directorios a mazos y submazos?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Esta es una opci\xF3n alternativa a las etiquetas de las Tarjetas de Memorizaci\xF3n.",
|
|
INLINE_SCHEDULING_COMMENTS: "\xBFGuardar el comentario para programaci\xF3n de las tarjetas en la \xFAltima l\xEDnea?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Activar esto har\xE1 que los comentarios HTML no rompan el formato de las listas.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\xBFEnterrar tarjetas hermanas hasta el siguiente d\xEDa?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Los hermanos son tarjetas generadas del mismo texto de la tarjeta, por ejemplo, deletreos de huecos (cloze deletions en ingl\xE9s)",
|
|
SHOW_CARD_CONTEXT: "\xBFMostrar contexto en las tarjetas?",
|
|
SHOW_CARD_CONTEXT_DESC: "Por Ejemplo: T\xEDtulo > Cabecera > Sub-Cabecera > ... > Sub-Cabecera",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Porcentaje de la altura de las tarjetas de memoria",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Deber\xEDa ser establecido en 100% si tienes im\xE1genes grandes",
|
|
RESET_DEFAULT: "Reiniciar a la configuraci\xF3n por defecto",
|
|
CARD_MODAL_WIDTH_PERCENT: "Porcentaje del ancho de las tarjetas de memoria",
|
|
RANDOMIZE_CARD_ORDER: "\xBFAleatorizar el orden de las tarjetas para revisi\xF3n?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "\xBFDeshabilitar deletreo de huecos en las tarjetas?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "\xBFConvertir ==resaltados== a deletreo de huecos?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "\xBFConvertir **texto en negrita** a deletreo de huecos?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "\xBFConvertir {{llaves rizadas}} a deletreo de huecos?",
|
|
CLOZE_PATTERNS: "Patrones de deletreo de huecos",
|
|
CLOZE_PATTERNS_DESC: 'Escriba los patrones de deletreo de huecos separados por saltos de l\xEDnea. . Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Separador de tarjetas de memorizaci\xF3n en l\xEDnea",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Note que despu\xE9s de cambiar este ajuste, tendr\xE1 que cambiar manualmente todas las notas que tenga.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Separador de tarjetas de memorizaci\xF3n para tarjetas de notas invertidas",
|
|
MULTILINE_CARDS_SEPARATOR: "Separador para tarjetas de memorizaci\xF3n multil\xEDnea",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Separador para tarjetas de memorizaci\xF3n multil\xEDnea invertidas",
|
|
MULTILINE_CARDS_END_MARKER: "Caracteres que denotan el fin de los clozes y tarjetas did\xE1cticas de varias l\xEDneas",
|
|
NOTES: "Notes",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Activar panel de revisi\xF3n de notas al arrancar",
|
|
TAGS_TO_REVIEW: "Etiquetas a revisar",
|
|
TAGS_TO_REVIEW_DESC: "Escriba las etiquetas separadas por espacios o saltos de l\xEDneas, por ejemplo, #revisi\xF3n #etiqueta2 #etiqueta3.",
|
|
OPEN_RANDOM_NOTE: "Abrir una nota al azar para revisar",
|
|
OPEN_RANDOM_NOTE_DESC: "Cuando deshabilita esto, las notas son ordenadas por importancia (Algoritmo PageRank).",
|
|
AUTO_NEXT_NOTE: "Abrir la siguiente nota autom\xE1ticamente despu\xE9s de una revisi\xF3n",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Habilita las opciones de revisi\xF3n en el men\xFA Archivo (por ejemplo: Revisar: F\xE1cil, Bien, Dif\xEDcil)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Si desactivas las opciones de revisi\xF3n en el men\xFA Archivo, puedes revisar tus notas usando los comandos del plugin y, si los definiste, las teclas r\xE1pidas asociadas.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "N\xFAmero m\xE1ximo de d\xEDas a mostrar en el panel derecho.",
|
|
MIN_ONE_DAY: "El n\xFAmero de d\xEDas debe ser al menos uno.",
|
|
VALID_NUMBER_WARNING: "Por favor especifique un n\xFAmero v\xE1lido.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Los \xE1rboles de mazos deber\xEDan ser expandidos al inicio.",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Desactiva esto para contraer mazos anidados en la misma tarjeta. \xDAtil si tienes tarjetas que pertenecen a muchos mazos en el mismo archivo.",
|
|
ALGORITHM: "Algoritmo",
|
|
CHECK_ALGORITHM_WIKI: 'Para m\xE1s informaci\xF3n, revisa la <a href="${algoUrl}">implementaci\xF3n del algoritmo</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Base ease",
|
|
BASE_EASE_DESC: "El m\xEDnimo es 130, es preferible que est\xE9 aproximado a 250.",
|
|
BASE_EASE_MIN_WARNING: "La facilidad base de las tarjetas debe ser al menos 130.",
|
|
LAPSE_INTERVAL_CHANGE: "El intervalo cambiar\xE1 cuando se revise una tarjeta o nota como Dif\xEDcil.",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "NuevoInterval = ViejoIntervalo * CambioDeIntervalo / 100.",
|
|
EASY_BONUS: "Bonificaci\xF3n para F\xE1cil",
|
|
EASY_BONUS_DESC: "La bonificaci\xF3n para F\xE1cil te permite establecer la diferencia entre intervalos al responder Bien y F\xE1cil en las tarjetas o notas (m\xEDnimo = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "El bono de facilidad debe ser al menos 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Intervalo m\xE1ximo en d\xEDas",
|
|
MAX_INTERVAL_DESC: "Te permite establecer un l\xEDmite mayor en el intervalo (por defecto es de 100 a\xF1os).",
|
|
MAX_INTERVAL_MIN_WARNING: "El intervalo m\xE1ximo debe ser de al menos un d\xEDa.",
|
|
MAX_LINK_CONTRIB: "Contribuci\xF3n m\xE1xima de las notas vinculadas.",
|
|
MAX_LINK_CONTRIB_DESC: "Contribuci\xF3n m\xE1xima de la facilidad ponderada de las notas vinculadas a la facilidad inicial.",
|
|
LOGGING: "Registro",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\xBFMostrar informaci\xF3n de depuraci\xF3n en la consola de desarrollador",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Cola de notas a revisar",
|
|
CLOSE: "Cerrar",
|
|
NEW: "Nuevo",
|
|
YESTERDAY: "Ayer",
|
|
TODAY: "Hoy",
|
|
TOMORROW: "Ma\xF1ana",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Estad\xEDsticas",
|
|
MONTH: "Mes",
|
|
QUARTER: "Trimestre o Cuatrimestre",
|
|
// En Inglés: Quarter.
|
|
YEAR: "A\xF1o",
|
|
LIFETIME: "Tiempo de Vida",
|
|
FORECAST: "Pron\xF3stico",
|
|
FORECAST_DESC: "El n\xFAmero de tarjetas vencidas en el futuro",
|
|
SCHEDULED: "Programado",
|
|
DAYS: "D\xEDas",
|
|
NUMBER_OF_CARDS: "N\xFAmero de tarjetas",
|
|
REVIEWS_PER_DAY: "Carga: ${avg} Revisiones por d\xEDa",
|
|
INTERVALS: "Intervalos",
|
|
INTERVALS_DESC: "Retrasos hasta que las revisiones se muestren de nuevo",
|
|
COUNT: "Conteo",
|
|
INTERVALS_SUMMARY: "Intervalo de carga: ${avg}, Intervalo mayor: ${longest}",
|
|
EASES: "Facilidad",
|
|
EASES_SUMMARY: "Carga de Facilidad: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Tipos de tarjetas",
|
|
CARD_TYPES_DESC: "Esto incluye tambi\xE9n a las tarjetas enterradas, si las hay",
|
|
CARD_TYPE_NEW: "Nueva",
|
|
CARD_TYPE_YOUNG: "Joven",
|
|
CARD_TYPE_MATURE: "Madura",
|
|
CARD_TYPES_SUMMARY: "Tarjetas Totales: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/fr.ts
|
|
var fr_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Paquets",
|
|
DUE_CARDS: "Cartes dues",
|
|
NEW_CARDS: "Nouvelles cartes",
|
|
TOTAL_CARDS: "Total de cartes",
|
|
BACK: "Pr\xE9c\xE9dent",
|
|
SKIP: "Sauter",
|
|
EDIT_CARD: "Modifier la carte",
|
|
RESET_CARD_PROGRESS: "Remettre \xE0 z\xE9ro le niveau de cette carte",
|
|
HARD: "Difficile",
|
|
GOOD: "Correct",
|
|
EASY: "Facile",
|
|
SHOW_ANSWER: "Montrer la r\xE9ponse",
|
|
CARD_PROGRESS_RESET: "Le niveau de la carte a \xE9t\xE9 remis \xE0 z\xE9ro.",
|
|
SAVE: "Sauvegarder",
|
|
CANCEL: "Annuler",
|
|
NO_INPUT: "Pas de contenu.",
|
|
CURRENT_EASE_HELP_TEXT: "Facilit\xE9 actuelle : ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Intervalle actuel : ",
|
|
CARD_GENERATED_FROM: "G\xE9n\xE9r\xE9 depuis : ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Ouvrir une note \xE0 apprendre",
|
|
REVIEW_CARDS: "Apprendre les flashcards",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Apprentissage : ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Difficult\xE9 de la r\xE9vision : ${difficulty}",
|
|
CRAM_ALL_CARDS: "Choisir un deck \xE0 r\xE9viser",
|
|
REVIEW_ALL_CARDS: "Apprendre les flashcards dans toutes les notes",
|
|
REVIEW_CARDS_IN_NOTE: "Apprendre les flashcards dans cette note",
|
|
CRAM_CARDS_IN_NOTE: "R\xE9viser les flashcards dans cette note",
|
|
VIEW_STATS: "Voir les statistiques",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Ouvrir la file d'attente des notes \xE0 apprendre dans la barre verticale",
|
|
STATUS_BAR: "Apprentissage : ${dueNotesCount} note(s), ${dueFlashcardsCount} carte(s) dues",
|
|
SYNC_TIME_TAKEN: "Synchronis\xE9 en ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "La note est dans un dossier ignor\xE9 (voir param\xE8tres).",
|
|
PLEASE_TAG_NOTE: "Ajoutez le bon tag \xE0 la note pour l'apprendre (dans les param\xE8tres).",
|
|
RESPONSE_RECEIVED: "R\xE9ponse enregistr\xE9e.",
|
|
NO_DECK_EXISTS: "Pas de paquet sous le nom ${deckName}",
|
|
ALL_CAUGHT_UP: "Bravo, vous \xEAtes \xE0 jour !",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} jour(s)",
|
|
MONTHS_STR_IVL: "${interval} mois(s)",
|
|
YEARS_STR_IVL: "${interval} an(s)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}j",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}a",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Dossiers",
|
|
GROUP_FLASHCARD_REVIEW: "Apprentissage des flashcards",
|
|
GROUP_FLASHCARD_SEPARATORS: "S\xE9parateurs de flashcards",
|
|
GROUP_DATA_STORAGE: "Stockage des informations de planification",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contribuer",
|
|
CHECK_WIKI: 'Pour plus d\'informations, visitez le <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visitez les <a href="${discussionsUrl}">discussions</a> pour des questions-r\xE9ponses, des retours ou une discussion g\xE9n\xE9raliste.',
|
|
GITHUB_ISSUES: 'Cr\xE9ez un ticket <a href="${issuesUrl}">sur GitHub</a> si vous trouvez un bug ou voulez demander une fonctionnalit\xE9.',
|
|
GITHUB_SOURCE_CODE: 'Code source du projet disponible sur <a href="${githubProjectUrl}">GitHub</a>',
|
|
CODE_CONTRIBUTION_INFO: 'Information sur les <a href="${codeContributionUrl}">contributions au code</a>',
|
|
TRANSLATION_CONTRIBUTION_INFO: 'Informations sur la <a href="${translationContributionUrl}">traduction du plugin</a> dans votre langue',
|
|
FOLDERS_TO_IGNORE: "Dossiers \xE0 ignorer",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Flashcards",
|
|
FLASHCARD_EASY_LABEL: "Bouton Facile",
|
|
FLASHCARD_GOOD_LABEL: "Bouton Correct",
|
|
FLASHCARD_HARD_LABEL: "Bouton Difficile",
|
|
FLASHCARD_EASY_DESC: "Changez le texte du bouton Facile",
|
|
FLASHCARD_GOOD_DESC: "Changez le texte du bouton Correct",
|
|
FLASHCARD_HARD_DESC: "Changez le texte du bouton Difficile",
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Tags des flashcards",
|
|
FLASHCARD_TAGS_DESC: "Entrez les tags s\xE9par\xE9s par un espace ou une ligne i.e. #flashcards #paquet2 #paquet3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Convertir les dossiers en paquets et sous-paquets ?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Ceci est une alternative aux tags de flashcards pr\xE9sent\xE9s ci-dessus.",
|
|
INLINE_SCHEDULING_COMMENTS: "Sauvegarder le commentaire de planification dans la derni\xE8re ligne de la flashcard ?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Activer ceci emp\xEAche les commentaires HTML de casser la mise en page des listes.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Enterrer les cartes s\u0153urs jusqu'au lendemain ?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Les cartes s\u0153urs sont les cartes g\xE9n\xE9r\xE9es depuis le m\xEAme texte, par exemple pour les textes \xE0 trous",
|
|
SHOW_CARD_CONTEXT: "Montrer le contexte dans les cartes ?",
|
|
SHOW_CARD_CONTEXT_DESC: "ex. Titre de la note > Titre 1 > Sous-titre > ... > Sous-titre",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Pourcentage de hauteur de la flashcard",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Devrait \xEAtre 100% sur mobile ou en cas de grandes images",
|
|
RESET_DEFAULT: "R\xE9initialiser les param\xE8tres",
|
|
CARD_MODAL_WIDTH_PERCENT: "Pourcentage de largeur de la flashcard",
|
|
RANDOMIZE_CARD_ORDER: "Apprendre les cartes dans un ordre al\xE9atoire ?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Ordre d'affichage des cartes d'un paquet pendant les r\xE9visions",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Dans l'ordre du paquet (Nouvelles cartes d'abord)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Dans l'ordre du paquet (Cartes dues d'abord)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Al\xE9atoirement dans le paquet (Nouvelles cartes d'abord)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Al\xE9atoirement dans le paquet (Cartes dues d'abord)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Carte au hasard dans un paquet au hasard",
|
|
REVIEW_DECK_ORDER: "Ordre d'affichage des paquets pendant les r\xE9visions",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "S\xE9quentiel (quand toutes les cartes du paquet pr\xE9c\xE9dent sont apprises)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Al\xE9atoire (quand toutes les cartes du paquet pr\xE9c\xE9dent sont apprises)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Carte au hasard dans un paquet au hasard",
|
|
DISABLE_CLOZE_CARDS: "D\xE9sactiver les textes \xE0 trous ?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Convertir ==soulignages== en trous ?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Convertir **gras** en trous ?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Convertir {{crochets}} en trous ?",
|
|
CLOZE_PATTERNS: "Cloze Patterns",
|
|
CLOZE_PATTERNS_DESC: 'Enter cloze patterns separated by newlines. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "S\xE9parateur pour flashcards en une ligne",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Apr\xE8s avoir chang\xE9 ce r\xE9glage, vous devrez manuellement mettre \xE0 jour toutes vos flashcards.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "S\xE9parateur pour flashcards invers\xE9es en une ligne",
|
|
MULTILINE_CARDS_SEPARATOR: "S\xE9parateur pour flashcards en plusieurs lignes",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "S\xE9parateur pour flashcards invers\xE9es en plusieurs lignes",
|
|
MULTILINE_CARDS_END_MARKER: "Caract\xE8res de fin de textes \xE0 trous ou de flashcards en plusieurs lignes",
|
|
NOTES: "Notes",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Montrer le module d'apprentissage des notes au d\xE9marrage",
|
|
TAGS_TO_REVIEW: "Tags \xE0 apprendre",
|
|
TAGS_TO_REVIEW_DESC: "Entrez les tags s\xE9par\xE9s par un espace ou une ligne i.e. #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "Ouvrir une note \xE0 apprendre au hasard",
|
|
OPEN_RANDOM_NOTE_DESC: "Si vous d\xE9sactivez cette option, les notes sont tri\xE9es par importance (PageRank).",
|
|
AUTO_NEXT_NOTE: "Ouvrir la prochaine note automatiquement apr\xE8s un apprentissage",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Jours maximum affich\xE9s dans la barre de droite",
|
|
MIN_ONE_DAY: "Le nombre de jours doit \xEAtre au moins 1.",
|
|
VALID_NUMBER_WARNING: "Entrez un nombre valide.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Enable the review options in the file menu (e.g. Review: Easy, Good, Hard)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "If you disable the review options in the file menu, you can review your notes using the plugin commands and, if you defined them, the associated command hotkeys.",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Les dossiers de paquets devraient initialement tous \xEAtre ouverts",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "D\xE9sactivez pour r\xE9duire les paquets dans la m\xEAme carte. Ce r\xE9glage est utile si vous avez des cartes qui appartiennent \xE0 beaucoup de paquets \xE0 la fois.",
|
|
ALGORITHM: "Algorithme",
|
|
CHECK_ALGORITHM_WIKI: `Pour en savoir plus, lisez l'<a href="\${algoUrl}">impl\xE9mentation de l'algorithme</a>.`,
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Facilit\xE9 de base",
|
|
BASE_EASE_DESC: "minimum = 130, recommand\xE9 = vers 250.",
|
|
BASE_EASE_MIN_WARNING: "La facilit\xE9 de base doit \xEAtre sup\xE9rieure \xE0 130.",
|
|
LAPSE_INTERVAL_CHANGE: "Changement d'intervalle quand vous indiquez qu'une flashcard/note a \xE9t\xE9 difficile",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "nouvelIntervalle = ancienIntervalle * changementIntervalle / 100.",
|
|
EASY_BONUS: "Bonus Facile",
|
|
EASY_BONUS_DESC: "Le bonus Facile vous permet d'augmenter l'intervalle entre une r\xE9ponse Correct et une r\xE9ponse Facile sur une flashcard/note (minimum = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "Le bonus Facile doit \xEAtre au moins 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Intervalle maximum (en jours)",
|
|
MAX_INTERVAL_DESC: "Vous permet de mettre une limite maximale sur l'intervalle (par d\xE9faut, 100 ans).",
|
|
MAX_INTERVAL_MIN_WARNING: "L'intervalle maximum doit \xEAtre au moins 1 jour.",
|
|
MAX_LINK_CONTRIB: "Contribution maximum des liens",
|
|
MAX_LINK_CONTRIB_DESC: "Contribution maximum de la facilit\xE9 pond\xE9r\xE9e des notes li\xE9es \xE0 la facilit\xE9 initiale.",
|
|
LOGGING: "Logging",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Afficher les informations de d\xE9bogage dans la console de d\xE9veloppement",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Afficher les informations de d\xE9bogage pour le parser dans la console de d\xE9veloppement",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Cartes \xE0 apprendre",
|
|
CLOSE: "Fermer",
|
|
NEW: "Nouveau",
|
|
YESTERDAY: "Hier",
|
|
TODAY: "Aujourd'hui",
|
|
TOMORROW: "Demain",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statistiques",
|
|
MONTH: "Mois",
|
|
QUARTER: "Trimestre",
|
|
YEAR: "Ann\xE9e",
|
|
LIFETIME: "Toujours",
|
|
FORECAST: "Pr\xE9visions",
|
|
FORECAST_DESC: "Le nombre de cartes dues dans le futur",
|
|
SCHEDULED: "Planifi\xE9",
|
|
DAYS: "Jours",
|
|
NUMBER_OF_CARDS: "Nombre de cartes",
|
|
REVIEWS_PER_DAY: "Moyenne : ${avg} apprentissages / jour",
|
|
INTERVALS: "Intervalles",
|
|
INTERVALS_DESC: "Dur\xE9e avant de remontrer une carte",
|
|
COUNT: "Total",
|
|
INTERVALS_SUMMARY: "Intervalle moyen : ${avg}. Intervalle maximum: ${longest}",
|
|
EASES: "Facilit\xE9",
|
|
EASES_SUMMARY: "Facilit\xE9 moyenne : ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Types de cartes",
|
|
CARD_TYPES_DESC: "Ceci inclut les cartes enterr\xE9es, s'il y en a",
|
|
CARD_TYPE_NEW: "Nouvelles",
|
|
CARD_TYPE_YOUNG: "En cours d'apprentissage",
|
|
CARD_TYPE_MATURE: "Matures",
|
|
CARD_TYPES_SUMMARY: "Total de cartes : ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/hi.ts
|
|
var hi_default = {};
|
|
|
|
// src/lang/locale/id.ts
|
|
var id_default = {};
|
|
|
|
// src/lang/locale/it.ts
|
|
var it_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Mazzi",
|
|
DUE_CARDS: "Schede da fare",
|
|
NEW_CARDS: "Schede nuove",
|
|
TOTAL_CARDS: "Schede totali",
|
|
BACK: "Indietro",
|
|
SKIP: "Salta",
|
|
EDIT_CARD: "Modifica scheda",
|
|
RESET_CARD_PROGRESS: "Ripristina i progressi della scheda",
|
|
HARD: "Difficile",
|
|
GOOD: "Buono",
|
|
EASY: "Facile",
|
|
SHOW_ANSWER: "Mostra risposta",
|
|
CARD_PROGRESS_RESET: "I progressi della scheda sono stati ripristinati",
|
|
SAVE: "Salva",
|
|
CANCEL: "Cancella",
|
|
NO_INPUT: "Non \xE8 stato provvisto alcun input",
|
|
CURRENT_EASE_HELP_TEXT: "Difficolt\xE0 attuale: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Intervallo attuale: ",
|
|
CARD_GENERATED_FROM: "Generato da: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Apri una nota per rivisita",
|
|
REVIEW_CARDS: "Rivisita schede",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Rivisita: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Revisita note come ${difficulty}",
|
|
CRAM_ALL_CARDS: "Seleziona un mazzo da memorizzare",
|
|
REVIEW_ALL_CARDS: "Seleziona schede da rivedere",
|
|
REVIEW_CARDS_IN_NOTE: "Rivedi schede in questa nota",
|
|
CRAM_CARDS_IN_NOTE: "Memorizza schede in questa nota",
|
|
VIEW_STATS: "Vedi statistiche",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Da rivedere: ${dueNotesCount} scheda/e, ${dueFlashcardsCount} schede in ritardo",
|
|
SYNC_TIME_TAKEN: "Sincronizzato in ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "La nota \xE8 salvata in una cartella ignorata (rivedi le impostazioni).",
|
|
PLEASE_TAG_NOTE: "Per favore etichetta la nota appropriatamente per la revisione (nelle impostazioni).",
|
|
RESPONSE_RECEIVED: "Risposta ricevuta.",
|
|
NO_DECK_EXISTS: "Non esistono mazzi per ${deckName}",
|
|
ALL_CAUGHT_UP: "Sei al passo! :D.",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} giorno/i",
|
|
MONTHS_STR_IVL: "${interval} mese/i",
|
|
YEARS_STR_IVL: "${interval} anno/i",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}y",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Plugin per ripetizione spaziata",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Per maggiori informazioni, rivolgersi alla <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Cartelle da ignorare",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Schede",
|
|
FLASHCARD_EASY_LABEL: "Testo del bottone facile",
|
|
FLASHCARD_GOOD_LABEL: "Testo del bottone buono",
|
|
FLASHCARD_HARD_LABEL: "Testo del bottone difficile",
|
|
FLASHCARD_EASY_DESC: 'Personalizza il testo per il pulsante "Facile"',
|
|
FLASHCARD_GOOD_DESC: 'Personalizza il testo per il pulsante "Buono"',
|
|
FLASHCARD_HARD_DESC: 'Personalizza il testo per il pulsante "Difficile"',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Etichette delle schede",
|
|
FLASHCARD_TAGS_DESC: "Inserire etichette separate da spazi o a capi, per esempio #flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Trasformare cartelle in mazzi e sotto-mazzi?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Questa \xE8 un'alternativa all'opzione delle etichette delle schede sopra.",
|
|
INLINE_SCHEDULING_COMMENTS: "Salvare il commento per l'orario sulla stessa linea dell'ultimna linea della scheda?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Attivando quest'impostazione far\xF2 s\xEC che i commento HTML non rompino la formattazione delle liste.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Sotterrare schede sorelle fino al giorno dopo?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Le schede sorelle sono schede generate dallo stesso testo della scheda, per esempio i.e. cloze deletions",
|
|
SHOW_CARD_CONTEXT: "Mostrare contesto nelle schede?",
|
|
SHOW_CARD_CONTEXT_DESC: "per esempio, Titolo > Intestazione 1 > Sottotitolo 1 > ... > Sottotitolo",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Percentuale altezza schede",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Dovrebbe essere 100% se sei su telefono o se hai immagini molto grandi",
|
|
RESET_DEFAULT: "Reimposta alle impostazioni iniziali",
|
|
CARD_MODAL_WIDTH_PERCENT: "Percentuale di larghezza delle schede",
|
|
RANDOMIZE_CARD_ORDER: "Rendere casuale l'ordine delle schede durante la revisione?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "L'ordine in cui le schede saranno visualizzate all'interno del mazzo",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequenzialmente dentro il mazzo (prima schede nuove)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequenzialmente dentro il mazzo (prima schede in ritardo)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "A caso dentro il mazzo (prima schede nuove)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "A caso dentro il mazzo (prima schede in ritardo)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Scheda a caso da mazzo a caso",
|
|
REVIEW_DECK_ORDER: "L'ordine in cui i mazzi vengono mostrati durante la revisione",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequenzialmente (quando le schede nel mazzo precedente saranno state riviste)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "A caso (quando le schede nel mazzo precedente saranno state riviste)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Scheda a caso da mazzo a caso",
|
|
DISABLE_CLOZE_CARDS: "Disabilita schede con spazi da riempire?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Convertire ==testo evidenziato== in spazi da riempire?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Convertire **testo in grassetto** in spazi da riempire",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Convertire {{parentesi graffe}} in spazi da riempire?",
|
|
CLOZE_PATTERNS: "Modelli di spazi da riempire",
|
|
CLOZE_PATTERNS_DESC: 'Inserisci i modelli di spazi da riempire separati da a capo. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Separatore per schede sulla stessa riga",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Si avvisa che dopo aver cambiato questo dovrai manualmente modificare le schede che hai gi\xE0.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Separatore per schede all'incontrario sulla stessa riga",
|
|
MULTILINE_CARDS_SEPARATOR: "Separatore per schede su pi\xF9 righe",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Separatore per schede all'incontrario su pi\xF9 righe",
|
|
MULTILINE_CARDS_END_MARKER: "Caratteri che denotano la fine di carte con spazi da riempiere e carte multilinea",
|
|
NOTES: "Note",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Abilita il pannello di revisione note all'avvio",
|
|
TAGS_TO_REVIEW: "Etichette da rivedere",
|
|
TAGS_TO_REVIEW_DESC: "Inserisci le etichette separate da spazi o a capi, tipo #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "Apri una nota a caso per revisione",
|
|
OPEN_RANDOM_NOTE_DESC: "Quando lo disabiliti, le note saranno ordinate per importanza (PageRank).",
|
|
AUTO_NEXT_NOTE: "Apri la prossima nota automaticamente dopo la revisione",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Abilita le opzioni di revisione nel menu File (es.: Rivisita: Facile, Buono, Difficile)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Se disabiliti le opzioni di revisione nel menu File, puoi rivedere le tue note utilizzando i comandi del plugin e, se li hai definiti, le scorciatoie da tastiera associate.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Numero di giorni massimi da visualizzare nel pannello di destra",
|
|
MIN_ONE_DAY: "Il numero di giorni deve essere almeno 1.",
|
|
VALID_NUMBER_WARNING: "Per favore, mettere un numero valido.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Alberti di mazzi dovrebbero essere inizialmente visualizzate come espansi",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Disabilitami per collassare mazzi annidati nella stessa scheda. Utile se hai schede che appartengono a pi\xF9 mazzi nello stesso file.",
|
|
ALGORITHM: "Algoritmo",
|
|
CHECK_ALGORITHM_WIKI: "Per maggiori informazioni, visita <a href='${algoUrl}'>l'implementazione dell'algoritmo</a>.",
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Difficolt\xE0 base",
|
|
BASE_EASE_DESC: "mino = 130, preferibilmente circa 250.",
|
|
BASE_EASE_MIN_WARNING: "La difficolt\xE0 base deve essere di almeno 130.",
|
|
LAPSE_INTERVAL_CHANGE: "L'intervallo cambier\xE0 segnando una scheda / nota come difficile",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "Intervallo nuovo = intervallo vecchio * cambio intervallo / 100.",
|
|
EASY_BONUS: "Bonus facilit\xE0",
|
|
EASY_BONUS_DESC: "Il bonus facilit\xE0 ti permette di impostare le differenze negli intervalli tra il rispondere Buono e Facile su una scheda o nota (minimo 100%).",
|
|
EASY_BONUS_MIN_WARNING: "Il bonus facilit\xE0 deve essere di almeno 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Intervallo massimo in giorni",
|
|
MAX_INTERVAL_DESC: "Ti permette di mettere un limite massimo all'intervallo (default 100 anni).",
|
|
MAX_INTERVAL_MIN_WARNING: "L'intervallo massimo deve essere di almeno 1 giorno.",
|
|
MAX_LINK_CONTRIB: "Contributo massimo delle note collegate",
|
|
MAX_LINK_CONTRIB_DESC: "Contributo massimo della difficolt\xE0 pasata delle note collegate alla difficolt\xE0 iniziale.",
|
|
LOGGING: "Registrando",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Visualizza informazione di debug sulla console per sviluppatori",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Visualizza informazione di debug riguardanti il parser sulla console per sviluppatori",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Coda di note da rivedere",
|
|
CLOSE: "Chiusi",
|
|
NEW: "Nuovo/a",
|
|
YESTERDAY: "Ieri",
|
|
TODAY: "Oggi",
|
|
TOMORROW: "Domani",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statistiche",
|
|
MONTH: "Mese",
|
|
QUARTER: "Trimestre",
|
|
YEAR: "Anno",
|
|
LIFETIME: "Per tutta la vita",
|
|
FORECAST: "Previsione",
|
|
FORECAST_DESC: "Il numero di schede che saranno in ritardo in futuro",
|
|
SCHEDULED: "Programmate",
|
|
DAYS: "Giorni",
|
|
NUMBER_OF_CARDS: "Numero di schede",
|
|
REVIEWS_PER_DAY: "Media: ${avg} revisioni/giorno",
|
|
INTERVALS: "Intervalli",
|
|
INTERVALS_DESC: "Ritardi finch\xE9 le revisioni saranno visualizzate di nuovo",
|
|
COUNT: "Conta",
|
|
INTERVALS_SUMMARY: "Intervallo medio: ${avg}, Intervallo massimo: ${longest}",
|
|
EASES: "Difficolt\xE0",
|
|
EASES_SUMMARY: "Difficolt\xE0 media: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Tipi di schede",
|
|
CARD_TYPES_DESC: "Include eventuali schede sepolte",
|
|
CARD_TYPE_NEW: "Nuove",
|
|
CARD_TYPE_YOUNG: "Giovani",
|
|
CARD_TYPE_MATURE: "Mature",
|
|
CARD_TYPES_SUMMARY: "Schede tottali: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/ja.ts
|
|
var ja_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\u30C7\u30C3\u30AD",
|
|
DUE_CARDS: "\u671F\u65E5\u306E\u30AB\u30FC\u30C9",
|
|
NEW_CARDS: "\u65B0\u898F\u306E\u30AB\u30FC\u30C9",
|
|
TOTAL_CARDS: "\u30AB\u30FC\u30C9\u5408\u8A08",
|
|
BACK: "Back",
|
|
SKIP: "Skip",
|
|
EDIT_CARD: "Edit Card",
|
|
RESET_CARD_PROGRESS: "\u30AB\u30FC\u30C9\u306E\u9032\u6357\u3092\u30EA\u30BB\u30C3\u30C8",
|
|
HARD: "Hard",
|
|
GOOD: "Good",
|
|
EASY: "Easy",
|
|
SHOW_ANSWER: "\u89E3\u7B54\u3092\u8868\u793A",
|
|
CARD_PROGRESS_RESET: "\u30AB\u30FC\u30C9\u306E\u9032\u6357\u304C\u30EA\u30BB\u30C3\u30C8\u3055\u308C\u307E\u3057\u305F\u3002",
|
|
SAVE: "Save",
|
|
CANCEL: "Cancel",
|
|
NO_INPUT: "No input provided.",
|
|
CURRENT_EASE_HELP_TEXT: "Current Ease: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Current Interval: ",
|
|
CARD_GENERATED_FROM: "Generated from: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\u30EC\u30D3\u30E5\u30FC\u3059\u308B\u30CE\u30FC\u30C8\u3092\u958B\u304F",
|
|
REVIEW_CARDS: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306E\u30EC\u30D3\u30E5\u30FC",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "\u30EC\u30D3\u30E5\u30FC: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "\u30CE\u30FC\u30C8\u3092${difficulty}\u3068\u3057\u3066\u30EC\u30D3\u30E5\u30FC\u3059\u308B",
|
|
REVIEW_ALL_CARDS: "\u3059\u3079\u3066\u306E\u30CE\u30FC\u30C8\u304B\u3089\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u3092\u30EC\u30D3\u30E5\u30FC\u3059\u308B",
|
|
CRAM_ALL_CARDS: "Select a deck to cram",
|
|
REVIEW_CARDS_IN_NOTE: "\u3053\u306E\u30CE\u30FC\u30C8\u306E\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u3092\u30EC\u30D3\u30E5\u30FC\u3059\u308B",
|
|
CRAM_CARDS_IN_NOTE: "\u3053\u306E\u30CE\u30FC\u30C8\u306E\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u3092\u8A70\u3081\u8FBC\u307F\u5B66\u7FD2\u3059\u308B",
|
|
VIEW_STATS: "\u7D71\u8A08\u3092\u95B2\u89A7\u3059\u308B",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "\u30EC\u30D3\u30E5\u30FC: ${dueNotesCount}\u30CE\u30FC\u30C8, ${dueFlashcardsCount}\u30AB\u30FC\u30C9\u304C\u671F\u65E5",
|
|
SYNC_TIME_TAKEN: "\u540C\u671F\u306B${t}ms\u304B\u304B\u308A\u307E\u3057\u305F\u3002",
|
|
NOTE_IN_IGNORED_FOLDER: "\u30CE\u30FC\u30C8\u304C\u7121\u8996\u3059\u308B\u30D5\u30A9\u30EB\u30C0\u306B\u4FDD\u5B58\u3055\u308C\u3066\u3044\u307E\u3059(\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044)\u3002",
|
|
PLEASE_TAG_NOTE: "\u30EC\u30D3\u30E5\u30FC\u3092\u884C\u3046\u306B\u306F\u30CE\u30FC\u30C8\u306B\u5BFE\u3057\u3066\u6B63\u3057\u304F\u30BF\u30B0\u4ED8\u3051\u3057\u3066\u304F\u3060\u3055\u3044(\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044)\u3002",
|
|
RESPONSE_RECEIVED: "\u7B54\u3048\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002",
|
|
NO_DECK_EXISTS: "${deckName}\u306B\u306F\u30C7\u30C3\u30AD\u304C\u5B58\u5728\u3057\u307E\u305B\u3093\u3002",
|
|
ALL_CAUGHT_UP: "\u4ECA\u65E5\u306E\u8AB2\u984C\u3092\u3059\u3079\u3066\u9054\u6210\u3057\u307E\u3057\u305F :D",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval}\u65E5\u5F8C",
|
|
MONTHS_STR_IVL: "${interval}\u6708\u5F8C",
|
|
YEARS_STR_IVL: "${interval}\u5E74\u5F8C",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}y",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '\u8A73\u7D30\u306B\u3064\u3044\u3066\u306F<a href="${wikiUrl}">wiki</a>\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\u7121\u8996\u3059\u308B\u30D5\u30A9\u30EB\u30C0",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9",
|
|
FLASHCARD_EASY_LABEL: "Easy Button Text",
|
|
FLASHCARD_GOOD_LABEL: "Good Button Text",
|
|
FLASHCARD_HARD_LABEL: "Hard Button Text",
|
|
FLASHCARD_EASY_DESC: 'Customize the label for the "Easy" Button',
|
|
FLASHCARD_GOOD_DESC: 'Customize the label for the "Good" Button',
|
|
FLASHCARD_HARD_DESC: 'Customize the label for the "Hard" Button',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u30BF\u30B0",
|
|
FLASHCARD_TAGS_DESC: '\u30BF\u30B0\u3092\u30B9\u30DA\u30FC\u30B9\u307E\u305F\u306F\u6539\u884C\u3067\u533A\u5207\u3063\u3066\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B: "#flashcards #deck2 #deck3"',
|
|
CONVERT_FOLDERS_TO_DECKS: "\u30D5\u30A9\u30EB\u30C0\u3092\u30C7\u30C3\u30AD\u3068\u30B5\u30D6\u30C7\u30C3\u30AD\u3068\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u304B\uFF1F",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "\u3053\u308C\u306F\u4E0A\u8A18\u306E\u30BF\u30B0\u3092\u4F7F\u7528\u3057\u305F\u30C7\u30C3\u30AD\u69CB\u7BC9\u306E\u4EE3\u66FF\u3068\u306A\u308B\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u3059\u3002",
|
|
INLINE_SCHEDULING_COMMENTS: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306E\u6700\u7D42\u884C\u3068\u540C\u4E00\u306E\u884C\u306B\u30B9\u30B1\u30B8\u30E5\u30FC\u30EA\u30F3\u30B0\u30B3\u30E1\u30F3\u30C8\u3092\u4FDD\u5B58\u3057\u307E\u3059\u304B\uFF1F",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "\u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u6709\u52B9\u5316\u3059\u308B\u3068\u3001HTML\u30B3\u30E1\u30F3\u30C8\u306B\u3088\u3063\u3066Markdown\u306E\u30EA\u30B9\u30C8\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u304C\u5D29\u308C\u306A\u304F\u306A\u308A\u307E\u3059\u3002",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\u6B21\u306E\u30EC\u30D3\u30E5\u30FC\u307E\u3067\u30B7\u30D6\u30EA\u30F3\u30B0\u3092\u5EF6\u671F\u3057\u307E\u3059\u304B\uFF1F",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "\u30B7\u30D6\u30EA\u30F3\u30B0\u306F\u540C\u4E00\u306E\u30AB\u30FC\u30C9\u30C6\u30AD\u30B9\u30C8\u304B\u3089\u751F\u6210\u3055\u308C\u305F\u30AB\u30FC\u30C9\u3001\u3064\u307E\u308A\u7A74\u57CB\u3081\u554F\u984C\u306E\u6D3E\u751F\u30AB\u30FC\u30C9\u3067\u3059\u3002",
|
|
SHOW_CARD_CONTEXT: "\u30AB\u30FC\u30C9\u306B\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u8868\u793A\u3057\u307E\u3059\u304B\uFF1F",
|
|
SHOW_CARD_CONTEXT_DESC: "\uFF62\u30BF\u30A4\u30C8\u30EB > \u898B\u51FA\u3057 1 > \u526F\u898B\u51FA\u3057 > ... > \u526F\u898B\u51FA\u3057\uFF63\u306E\u8868\u793A\u3092\u884C\u3046\u304B\u3069\u3046\u304B\u3092\u6C7A\u3081\u307E\u3059\u3002",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306E\u7E26\u30B5\u30A4\u30BA\u306E\u30D1\u30FC\u30BB\u30F3\u30C6\u30FC\u30B8",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\u30E2\u30D0\u30A4\u30EB\u7248\u3001\u307E\u305F\u306F\u975E\u5E38\u306B\u5927\u304D\u306A\u30B5\u30A4\u30BA\u306E\u753B\u50CF\u304C\u3042\u308B\u5834\u5408\u306B\u306F100%\u306B\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
RESET_DEFAULT: "\u30C7\u30D5\u30A9\u30EB\u30C8\u5024\u306B\u30EA\u30BB\u30C3\u30C8\u3059\u308B",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306E\u6A2A\u30B5\u30A4\u30BA\u306E\u30D1\u30FC\u30BB\u30F3\u30C6\u30FC\u30B8",
|
|
RANDOMIZE_CARD_ORDER: "\u30EC\u30D3\u30E5\u30FC\u4E2D\u306E\u30AB\u30FC\u30C9\u306E\u9806\u756A\u3092\u30E9\u30F3\u30C0\u30E0\u306B\u3057\u307E\u3059\u304B\uFF1F",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "\u7A74\u57CB\u3081\u30AB\u30FC\u30C9\u3092\u7121\u52B9\u5316\u3057\u307E\u3059\u304B\uFF1F",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "==\u30CF\u30A4\u30E9\u30A4\u30C8==\u3092\u7A74\u57CB\u3081\u3068\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u304B\uFF1F",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "**\u30DC\u30FC\u30EB\u30C9\u4F53**\u3092\u7A74\u57CB\u3081\u3068\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u304B\uFF1F",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "{{\u4E2D\u62EC\u5F27}}\u3092\u7A74\u57CB\u3081\u3068\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u304B\uFF1F",
|
|
CLOZE_PATTERNS: "\u7A74\u57CB\u3081\u30D1\u30BF\u30FC\u30F3",
|
|
CLOZE_PATTERNS_DESC: '\u6539\u884C\u3067\u533A\u5207\u3063\u3066\u7A74\u57CB\u3081\u30D1\u30BF\u30FC\u30F3\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\u30A4\u30F3\u30E9\u30A4\u30F3\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u30BB\u30D1\u30EC\u30FC\u30BF\u30FC",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u5909\u66F4\u3059\u308B\u5834\u5408\u306B\u306F\u3001\u4F5C\u6210\u6E08\u307F\u306E\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u3092\u624B\u52D5\u3067\u7DE8\u96C6\u3057\u76F4\u3059\u5FC5\u8981\u304C\u3042\u308B\u3053\u3068\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\u30A4\u30F3\u30E9\u30A4\u30F3\u306E\u8868\u88CF\u53CD\u8EE2\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u30BB\u30D1\u30EC\u30FC\u30BF\u30FC",
|
|
MULTILINE_CARDS_SEPARATOR: "\u8907\u6570\u884C\u306E\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u30BB\u30D1\u30EC\u30FC\u30BF\u30FC",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\u8907\u6570\u884C\u306E\u8868\u88CF\u53CD\u8EE2\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u30BB\u30D1\u30EC\u30FC\u30BF\u30FC",
|
|
MULTILINE_CARDS_END_MARKER: "\u30AF\u30ED\u30FC\u30BA\u3068\u8907\u6570\u884C\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9\u306E\u7D42\u308F\u308A\u3092\u793A\u3059\u6587\u5B57",
|
|
NOTES: "\u30CE\u30FC\u30C8",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Enable note review pane on startup",
|
|
TAGS_TO_REVIEW: "\u30EC\u30D3\u30E5\u30FC\u306B\u4F7F\u7528\u3059\u308B\u30BF\u30B0",
|
|
TAGS_TO_REVIEW_DESC: '\u30BF\u30B0\u3092\u30B9\u30DA\u30FC\u30B9\u307E\u305F\u306F\u6539\u884C\u3067\u533A\u5207\u3063\u3066\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B: "#review #tag2 #tag3"',
|
|
OPEN_RANDOM_NOTE: "\u30E9\u30F3\u30C0\u30E0\u306B\u30CE\u30FC\u30C8\u3092\u958B\u3044\u3066\u30EC\u30D3\u30E5\u30FC\u3059\u308B",
|
|
OPEN_RANDOM_NOTE_DESC: "\u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u308B\u72B6\u614B\u3067\u306F\u3001\u30CE\u30FC\u30C8\u306F\u91CD\u8981\u5EA6(\u30DA\u30FC\u30B8\u30E9\u30F3\u30AF)\u306B\u3088\u308B\u9806\u756A\u3067\u8868\u793A\u3055\u308C\u307E\u3059\u3002",
|
|
AUTO_NEXT_NOTE: "\u30EC\u30D3\u30E5\u30FC\u5F8C\u306B\u6B21\u306E\u30CE\u30FC\u30C8\u3092\u81EA\u52D5\u7684\u306B\u958B\u304F",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\u30D5\u30A1\u30A4\u30EB\u30E1\u30CB\u30E5\u30FC\u3067\u30EC\u30D3\u30E5\u30FC\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u6709\u52B9\u306B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: Easy, Good, Hard\uFF09",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\u30D5\u30A1\u30A4\u30EB\u30E1\u30CB\u30E5\u30FC\u3067\u30EC\u30D3\u30E5\u30FC\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u7121\u52B9\u306B\u3057\u305F\u5834\u5408\u3001\u30D7\u30E9\u30B0\u30A4\u30F3\u30B3\u30DE\u30F3\u30C9\u3084\u3001\u8A2D\u5B9A\u3057\u3066\u3044\u308B\u5834\u5408\u306F\u5BFE\u5FDC\u3059\u308B\u30DB\u30C3\u30C8\u30AD\u30FC\u3092\u4F7F\u7528\u3057\u3066\u30E1\u30E2\u3092\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u3059\u3002",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\u53F3\u30D1\u30CD\u30EB\u306B\u8868\u793A\u3059\u308B\u6700\u5927\u306E\u65E5\u6570",
|
|
MIN_ONE_DAY: "\u65E5\u6570\u306B\u306F1\u4EE5\u4E0A\u306E\u6570\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
VALID_NUMBER_WARNING: "\u6709\u52B9\u306A\u6570\u5B57\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\u30C7\u30C3\u30AD \u30C4\u30EA\u30FC\u306F\u6700\u521D\u306F\u5C55\u958B\u3057\u3066\u8868\u793A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "\u3053\u308C\u3092\u30AA\u30D5\u306B\u3059\u308B\u3068\u3001\u540C\u3058\u30AB\u30FC\u30C9\u5185\u306E\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30C7\u30C3\u30AD\u304C\u6298\u308A\u305F\u305F\u307E\u308C\u307E\u3059\u3002\u540C\u3058\u30D5\u30A1\u30A4\u30EB\u306B\u591A\u304F\u306E\u30C7\u30C3\u30AD\u306B\u5C5E\u3059\u308B\u30AB\u30FC\u30C9\u304C\u3042\u308B\u5834\u5408\u306B\u4FBF\u5229\u3067\u3059\u3002",
|
|
ALGORITHM: "\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0",
|
|
CHECK_ALGORITHM_WIKI: '\u8A73\u7D30\u306B\u3064\u3044\u3066\u306F<a href="${algoUrl}">\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0\u306E\u5B9F\u88C5</a>\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\u30D9\u30FC\u30B9\u306E\u6613\u3057\u3055",
|
|
BASE_EASE_DESC: "\u6700\u5C0F\u5024\u306F130\u3067\u3059\u304C\u3001 \u9069\u6B63\u5024\u306F\u304A\u304A\u3088\u305D250\u3067\u3059\u3002",
|
|
BASE_EASE_MIN_WARNING: "\u30D9\u30FC\u30B9\u306E\u6613\u3057\u3055\u306B\u306F130\u4EE5\u4E0A\u306E\u6570\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
LAPSE_INTERVAL_CHANGE: "\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9/\u30CE\u30FC\u30C8\u3092Hard\u3068\u3057\u3066\u30EC\u30D3\u30E5\u30FC\u3057\u305F\u969B\u306E\u9593\u9694\u5909\u66F4",
|
|
LAPSE_INTERVAL_CHANGE_DESC: '"\u65B0\u3057\u3044\u9593\u9694 = \u4EE5\u524D\u306E\u9593\u9694 * \u9593\u9694\u5909\u66F4 / 100" \u3068\u3057\u3066\u8A08\u7B97\u3055\u308C\u307E\u3059\u3002',
|
|
EASY_BONUS: "Easy\u30DC\u30FC\u30CA\u30B9",
|
|
EASY_BONUS_DESC: "Easy\u30DC\u30FC\u30CA\u30B9\u306B\u3088\u3063\u3066\u30D5\u30E9\u30C3\u30B7\u30E5\u30AB\u30FC\u30C9/\u30CE\u30FC\u30C8\u306B\u304A\u3051\u308B\u9593\u9694\u306E\u5DEE\u5206\u3092\u8A2D\u5B9A\u3067\u304D\u307E\u3059(\u6700\u5C0F\u5024 = 100%)\u3002",
|
|
EASY_BONUS_MIN_WARNING: "Easy\u30DC\u30FC\u30CA\u30B9\u306B\u306F100\u4EE5\u4E0A\u306E\u6570\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximum interval in days",
|
|
MAX_INTERVAL_DESC: "\u9593\u9694\u306B\u4E0A\u9650\u5024\u3092\u8A2D\u5B9A\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059(\u30C7\u30D5\u30A9\u30EB\u30C8\u5024 = 100\u5E74)\u3002",
|
|
MAX_INTERVAL_MIN_WARNING: "\u9593\u9694\u306E\u6700\u5927\u5024\u306B\u306F1\u4EE5\u4E0A\u306E\u6570\u5B57\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
MAX_LINK_CONTRIB: "\u30EA\u30F3\u30AF\u30B3\u30F3\u30C8\u30EA\u30D3\u30E5\u30FC\u30B7\u30E7\u30F3\u306E\u6700\u5927\u5024",
|
|
MAX_LINK_CONTRIB_DESC: "\u6700\u521D\u306E\u6613\u3057\u3055\u306B\u5BFE\u3057\u3066\u3001\u30EA\u30F3\u30AF\u3055\u308C\u305F\u30CE\u30FC\u30C8\u306E\u91CD\u307F\u4ED8\u3051\u3055\u308C\u305F\u6613\u3057\u3055\u304C\u5BC4\u4E0E\u3059\u308B\u6700\u5927\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
LOGGING: "\u30ED\u30B0\u7BA1\u7406",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\u30C7\u30D9\u30ED\u30C3\u30D1\u30FC\u30B3\u30F3\u30BD\u30FC\u30EB\u306B\u3066\u30C7\u30D0\u30C3\u30B0\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\u304B",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\u30CE\u30FC\u30C8\u30EC\u30D3\u30E5\u30FC\u306E\u30AD\u30E5\u30FC",
|
|
CLOSE: "\u9589\u3058\u308B",
|
|
NEW: "\u65B0\u898F",
|
|
YESTERDAY: "\u6628\u65E5",
|
|
TODAY: "\u4ECA\u65E5",
|
|
TOMORROW: "\u660E\u65E5",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u7D71\u8A08",
|
|
MONTH: "Month",
|
|
QUARTER: "Quarter",
|
|
YEAR: "Year",
|
|
LIFETIME: "Lifetime",
|
|
FORECAST: "\u4E88\u6E2C",
|
|
FORECAST_DESC: "\u5FA9\u7FD2\u671F\u65E5\u304C\u6765\u308B\u30AB\u30FC\u30C9\u306E\u679A\u6570",
|
|
SCHEDULED: "\u30B9\u30B1\u30B8\u30E5\u30FC\u30EA\u30F3\u30B0\u6E08\u307F",
|
|
DAYS: "\u65E5",
|
|
NUMBER_OF_CARDS: "\u30AB\u30FC\u30C9\u6570",
|
|
REVIEWS_PER_DAY: "\u5E73\u5747: ${avg}\u30EC\u30D3\u30E5\u30FC/\u65E5",
|
|
INTERVALS: "\u9593\u9694",
|
|
INTERVALS_DESC: "\u6B21\u306E\u30EC\u30D3\u30E5\u30FC\u4E88\u5B9A\u65E5",
|
|
COUNT: "\u30AB\u30A6\u30F3\u30C8",
|
|
INTERVALS_SUMMARY: "\u9593\u9694\u306E\u5E73\u5747\u5024: ${avg}, \u6700\u9577\u306E\u9593\u9694: ${longest}",
|
|
EASES: "\u6613\u3057\u3055",
|
|
EASES_SUMMARY: "\u6613\u3057\u3055\u306E\u5E73\u5747\u5024: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\u30AB\u30FC\u30C9\u30BF\u30A4\u30D7",
|
|
CARD_TYPES_DESC: "\u5EF6\u671F\u306E\u30AB\u30FC\u30C9\u304C\u3042\u308B\u5834\u5408\u306B\u306F\u3053\u308C\u306B\u542B\u307E\u308C\u307E\u3059",
|
|
CARD_TYPE_NEW: "\u65B0\u898F",
|
|
CARD_TYPE_YOUNG: "\u5FA9\u7FD2(\u521D\u671F)",
|
|
CARD_TYPE_MATURE: "\u5FA9\u7FD2(\u5F8C\u671F)",
|
|
CARD_TYPES_SUMMARY: "\u30AB\u30FC\u30C9\u306E\u5408\u8A08: ${totalCardsCount}\u679A",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/ko.ts
|
|
var ko_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\uB371",
|
|
DUE_CARDS: "\uB2E4\uC2DC \uBCFC \uCE74\uB4DC\uB4E4",
|
|
NEW_CARDS: "\uC0C8\uB85C\uC6B4 \uCE74\uB4DC\uB4E4",
|
|
TOTAL_CARDS: "\uC804\uCCB4 \uCE74\uB4DC\uB4E4",
|
|
BACK: "Back",
|
|
SKIP: "Skip",
|
|
EDIT_CARD: "Edit Card",
|
|
RESET_CARD_PROGRESS: "\uCE74\uB4DC\uC758 \uC9C4\uD589\uC0C1\uD669\uC744 \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.",
|
|
HARD: "\uC5B4\uB824\uC6C0(Hard)",
|
|
GOOD: "\uC88B\uC74C(Good)",
|
|
EASY: "\uC26C\uC6C0(Easy)",
|
|
SHOW_ANSWER: "\uC815\uB2F5 \uD655\uC778\uD558\uAE30",
|
|
CARD_PROGRESS_RESET: "\uCE74\uB4DC\uC758 \uC9C4\uD589\uC0C1\uD669\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
SAVE: "Save",
|
|
CANCEL: "Cancel",
|
|
NO_INPUT: "No input provided.",
|
|
CURRENT_EASE_HELP_TEXT: "Current Ease: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Current Interval: ",
|
|
CARD_GENERATED_FROM: "Generated from: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\uB9AC\uBDF0\uD560 \uB178\uD2B8 \uC5F4\uAE30",
|
|
REVIEW_CARDS: "\uD50C\uB798\uC2DC\uCE74\uB4DC \uB9AC\uBDF0",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "\uB9AC\uBDF0: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "\uB178\uD2B8\uB97C ${difficulty}\uC73C\uB85C \uB9AC\uBDF0\uD569\uB2C8\uB2E4",
|
|
REVIEW_ALL_CARDS: "\uBAA8\uB4E0 \uB178\uD2B8\uB4E4\uC758 \uD50C\uB798\uC2DC\uCE74\uB4DC\uB4E4\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4",
|
|
CRAM_ALL_CARDS: "Select a deck to cram",
|
|
REVIEW_CARDS_IN_NOTE: "\uC774 \uB178\uD2B8\uC758 \uD50C\uB798\uC2DC\uCE74\uB4DC\uB4E4\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4",
|
|
CRAM_CARDS_IN_NOTE: "\uC774 \uB178\uD2B8\uC758 \uD50C\uB798\uC2DC\uCE74\uB4DC\uB4E4\uC744 \uBCBC\uB77D\uCE58\uAE30\uD569\uB2C8\uB2E4.",
|
|
VIEW_STATS: "\uD1B5\uACC4 \uD655\uC778",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "--\uB9AC\uBDF0: ${dueNotesCount} \uB178\uD2B8, ${dueFlashcardsCount} \uCE74\uB4DC \uB0A8\uC558\uC2B5\uB2C8\uB2E4.",
|
|
SYNC_TIME_TAKEN: "\uB3D9\uAE30\uD654\uC5D0 ${t}\uBC00\uB9AC\uCD08 \uAC78\uB838\uC2B5\uB2C8\uB2E4",
|
|
NOTE_IN_IGNORED_FOLDER: "\uB178\uD2B8\uAC00 \uBB34\uC2DC\uB41C \uD3F4\uB354 \uC544\uB798\uC5D0 \uC800\uC7A5\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. (\uC124\uC815\uC744 \uD655\uC778\uD574\uC8FC\uC138\uC694)",
|
|
PLEASE_TAG_NOTE: "\uB9AC\uBDF0\uB97C \uD558\uAE30\uC704\uD574 \uB178\uD2B8\uC5D0 \uC801\uC808\uD788 \uD0DC\uADF8\uD574\uC8FC\uC138\uC694. (\uC124\uC815\uC744 \uD655\uC778\uD574\uC8FC\uC138\uC694)",
|
|
RESPONSE_RECEIVED: "\uC694\uCCAD\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
NO_DECK_EXISTS: "${deckName}\uC774\uB77C\uB294 \uC774\uB984\uC758 \uB371\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
ALL_CAUGHT_UP: "\uBAA8\uB450 \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4. :D",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} \uC77C \uD6C4",
|
|
MONTHS_STR_IVL: "${interval} \uAC1C\uC6D4 \uD6C4",
|
|
YEARS_STR_IVL: "${interval} \uB144 \uD6C4",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}y",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '\uB354 \uB9CE\uC740 \uC815\uBCF4\uB97C \uC6D0\uD558\uC2DC\uBA74, <a href="${wikiUrl}">wiki</a>\uB97C \uD655\uC778\uD574\uC8FC\uC138\uC694.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\uBB34\uC2DC\uD560 \uD3F4\uB354\uB4E4",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\uD50C\uB798\uC2DC\uCE74\uB4DC",
|
|
FLASHCARD_EASY_LABEL: "Easy Button Text",
|
|
FLASHCARD_GOOD_LABEL: "Good Button Text",
|
|
FLASHCARD_HARD_LABEL: "Hard Button Text",
|
|
FLASHCARD_EASY_DESC: 'Customize the label for the "Easy" Button',
|
|
FLASHCARD_GOOD_DESC: 'Customize the label for the "Good" Button',
|
|
FLASHCARD_HARD_DESC: 'Customize the label for the "Hard" Button',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\uD50C\uB798\uC2DC\uCE74\uB4DC \uD0DC\uADF8",
|
|
FLASHCARD_TAGS_DESC: "\uD0DC\uADF8\uB97C \uACF5\uBC31 \uB610\uB294 \uBE48 \uC904\uB85C \uAD6C\uBD84\uD574\uC11C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608) '#flashcards #deck2 #deck3'",
|
|
CONVERT_FOLDERS_TO_DECKS: "\uD3F4\uB354\uB97C \uB371\uACFC \uC11C\uBE0C\uB371\uC73C\uB85C \uC0AC\uC6A9\uD560\uAE4C\uC694?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "\uC774 \uAE30\uB2A5\uC740 \uC704\uC758 \uD50C\uB798\uC2DC\uCE74\uB4DC \uD0DC\uADF8 \uC635\uC158\uC744 \uB300\uCCB4\uD569\uB2C8\uB2E4.",
|
|
INLINE_SCHEDULING_COMMENTS: "\uD50C\uB798\uC2DC\uCE74\uB4DC\uC758 \uB9C8\uC9C0\uB9C9 \uC904\uACFC \uB3D9\uC77C\uD55C \uC904\uC5D0 \uC2A4\uCF00\uC904\uB9C1 \uCF54\uBA58\uD2B8\uB97C \uC800\uC7A5\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "\uC774 \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uBA74 HTML \uC8FC\uC11D\uC774 \uBAA9\uB85D\uC758 \uD3EC\uB9E4\uD305\uC744 \uBB34\uB108\uD2B8\uB9AC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Sibling \uCE74\uB4DC\uB97C \uB2E4\uC74C\uB0A0\uAE4C\uC9C0 \uBB3B\uC5B4\uB450\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Sibling \uCE74\uB4DC\uB294 \uB3D9\uC77C\uD55C \uCE74\uB4DC \uD14D\uC2A4\uD2B8\uC5D0\uC11C \uC0DD\uC131\uB41C \uCE74\uB4DC\uC785\uB2C8\uB2E4. i.e. cloze deletions",
|
|
SHOW_CARD_CONTEXT: "\uCE74\uB4DC\uC758 \uBB38\uB9E5(context)\uC744 \uD45C\uC2DC\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
SHOW_CARD_CONTEXT_DESC: "\uCE74\uB4DC\uC5D0\uC11C 'Title > Heading 1 > Subheading > ... > Subheading' \uC758 \uD45C\uC2DC\uB97C \uD560\uC9C0 \uC124\uC815\uD569\uB2C8\uB2E4.",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\uD50C\uB798\uC2DC\uCE74\uB4DC \uB192\uC774 \uBE44\uC728",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\uBAA8\uBC14\uC77C \uBC84\uC804 \uD639\uC740 \uB9E4\uC6B0 \uD070 \uC774\uBBF8\uC9C0\uAC00 \uC788\uB294 \uACBD\uC6B0 100%\uB85C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
RESET_DEFAULT: "\uAE30\uBCF8\uAC12\uC73C\uB85C \uCD08\uAE30\uD654",
|
|
CARD_MODAL_WIDTH_PERCENT: "\uD50C\uB798\uC2DC\uCE74\uB4DC \uB108\uBE44 \uBE44\uC728",
|
|
RANDOMIZE_CARD_ORDER: "\uB9AC\uBDF0\uC911\uC778 \uCE74\uB4DC\uC758 \uC21C\uC11C\uB97C \uB79C\uB364\uC73C\uB85C \uB450\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "\uBE48 \uCE78 \uCC44\uC6B0\uAE30 \uCE74\uB4DC\uB97C \uBE44\uD65C\uC131\uD654\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "==highlights== \uB97C \uBE48 \uCE78 \uCC44\uC6B0\uAE30\uB85C \uC804\uD658\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "**bolded text** \uB97C \uBE48 \uCE78 \uCC44\uC6B0\uAE30\uB85C \uC804\uD658\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "{{curly brackets}} \uB97C \uBE48 \uCE78 \uCC44\uC6B0\uAE30\uB85C \uC804\uD658\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
CLOZE_PATTERNS: "\uBE48 \uCE78 \uCC44\uC6B0\uAE30 \uD328\uD134",
|
|
CLOZE_PATTERNS_DESC: '\uBE48 \uCE78 \uCC44\uC6B0\uAE30 \uD328\uD134\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC904\uBC14\uAFC8\uC73C\uB85C \uAD6C\uBD84\uD569\uB2C8\uB2E4. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\uC778\uB77C\uC778 \uD50C\uB798\uC2DC\uCE74\uB4DC \uAD6C\uBD84\uC790",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\uC8FC\uC758: \uC774 \uC635\uC158\uC744 \uC218\uC815\uD55C \uD6C4\uC5D0\uB294 \uC774\uBBF8 \uC791\uC131\uB41C \uD50C\uB798\uC2DC\uCE74\uB4DC\uB97C \uC218\uB3D9\uC73C\uB85C \uC218\uC815\uD574\uC57C \uD568\uC744 \uC8FC\uC758\uD558\uC2ED\uC2DC\uC624.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\uC778\uB77C\uC778 \uBC18\uC804 \uD50C\uB798\uC2DC\uCE74\uB4DC \uAD6C\uBD84\uC790",
|
|
MULTILINE_CARDS_SEPARATOR: "\uC5EC\uB7EC \uC904 \uD50C\uB798\uC2DC\uCE74\uB4DC \uAD6C\uBD84\uC790",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\uC5EC\uB7EC \uC904 \uBC18\uC804 \uD50C\uB798\uC2DC\uCE74\uB4DC \uAD6C\uBD84\uC790",
|
|
MULTILINE_CARDS_END_MARKER: "\uD074\uB85C\uC988\uC640 \uB2E4\uC911 \uD589 \uD50C\uB798\uC2DC\uCE74\uB4DC\uC758 \uB05D\uC744 \uB098\uD0C0\uB0B4\uB294 \uBB38\uC790",
|
|
NOTES: "\uB178\uD2B8",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Enable note review pane on startup",
|
|
TAGS_TO_REVIEW: "\uB9AC\uBDF0\uC5D0 \uC0AC\uC6A9\uD560 \uD0DC\uADF8",
|
|
TAGS_TO_REVIEW_DESC: "\uD0DC\uADF8\uB97C \uACF5\uBC31 \uB610\uB294 \uBE48 \uC904\uB85C \uAD6C\uBD84\uD574\uC11C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608) '#review #tag2 #tag3'",
|
|
OPEN_RANDOM_NOTE: "\uB9AC\uBDF0\uB97C \uC704\uD574 \uB79C\uB364 \uB178\uD2B8\uB97C \uC5FD\uB2C8\uB2E4.",
|
|
OPEN_RANDOM_NOTE_DESC: "\uC774 \uC635\uC158\uC774 \uAEBC\uC838\uC788\uC73C\uBA74, \uB178\uD2B8\uB294 \uC911\uC694\uB3C4(\uD398\uC774\uC9C0 \uB7AD\uD06C)\uC5D0 \uB530\uB77C \uC815\uB82C\uB429\uB2C8\uB2E4.",
|
|
AUTO_NEXT_NOTE: "\uB9AC\uBDF0 \uD6C4\uC5D0 \uB2E4\uC74C \uB178\uD2B8\uB97C \uC790\uB3D9\uC73C\uB85C \uC5FD\uB2C8\uB2E4.",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\uD30C\uC77C \uBA54\uB274\uC5D0\uC11C \uAC80\uD1A0 \uC635\uC158\uC744 \uD65C\uC131\uD654\uD558\uC138\uC694 (\uC608: \uAC80\uD1A0: \uC26C\uC6C0, \uC88B\uC74C, \uC5B4\uB824\uC6C0)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\uD30C\uC77C \uBA54\uB274\uC5D0\uC11C \uAC80\uD1A0 \uC635\uC158\uC744 \uBE44\uD65C\uC131\uD654\uD558\uBA74 \uD50C\uB7EC\uADF8\uC778 \uBA85\uB839\uC744 \uC0AC\uC6A9\uD574 \uB178\uD2B8\uB97C \uAC80\uD1A0\uD560 \uC218 \uC788\uC73C\uBA70, \uC815\uC758\uB41C \uACBD\uC6B0\uC5D0\uB294 \uAD00\uB828\uB41C \uB2E8\uCD95\uD0A4\uB3C4 \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\uC624\uB978\uCABD \uD328\uB110\uC5D0 \uD45C\uC2DC\uD560 \uCD5C\uB300 \uC77C\uC218",
|
|
MIN_ONE_DAY: "\uC801\uC5B4\uB3C4 1\uC774\uC0C1\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
VALID_NUMBER_WARNING: "\uC720\uD6A8\uD55C \uC22B\uC790\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\uB371 \uD2B8\uB9AC\uB294 \uCC98\uC74C\uC5D0 \uD655\uC7A5\uB41C \uAC83\uC73C\uB85C \uD45C\uC2DC\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "\uAC19\uC740 \uCE74\uB4DC\uC5D0 \uC911\uCCA9\uB41C \uB371\uC744 \uC811\uC73C\uB824\uBA74 \uC774 \uC635\uC158\uC744 \uB044\uC2ED\uC2DC\uC624. \uAC19\uC740 \uD30C\uC77C\uC5D0 \uC5EC\uB7EC \uB371\uC5D0 \uC18D\uD55C \uCE74\uB4DC\uAC00 \uC788\uB294 \uACBD\uC6B0 \uC720\uC6A9\uD569\uB2C8\uB2E4.",
|
|
ALGORITHM: "\uC54C\uACE0\uB9AC\uC998",
|
|
CHECK_ALGORITHM_WIKI: '\uB354 \uB9CE\uC740 \uC815\uBCF4\uB97C \uC6D0\uD558\uC2DC\uBA74, <a href="${algoUrl}">algorithm details</a>\uC744 \uD655\uC778\uD574\uC8FC\uC138\uC694.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\uAE30\uBCF8 ease",
|
|
BASE_EASE_DESC: "\uCD5C\uC19F\uAC12 = 130, \uC801\uC815\uCE58\uB294 \uB300\uB7B5 250\uC785\uB2C8\uB2E4.",
|
|
BASE_EASE_MIN_WARNING: "\uAE30\uBCF8 ease\uB294 \uC801\uC5B4\uB3C4 130 \uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
LAPSE_INTERVAL_CHANGE: "\uD50C\uB798\uC2DC\uCE74\uB4DC/\uB178\uD2B8\uB97C \uC5B4\uB824\uC6C0(Hard)\uC73C\uB85C \uB9AC\uBDF0\uD588\uC744 \uB54C\uC758 \uAC04\uACA9 \uBCC0\uACBD",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "\uC0C8\uB85C\uC6B4 \uAC04\uACA9 = \uC774\uC804 \uAC04\uACA9 * \uAC04\uACA9\uBCC0\uACBD \uAC12 / 100.",
|
|
EASY_BONUS: "\uC26C\uC6C0(Easy) \uBCF4\uB108\uC2A4",
|
|
EASY_BONUS_DESC: "\uC26C\uC6C0(Easy) \uBCF4\uB108\uC2A4\uB294 \uD50C\uB798\uC2DC\uCE74\uB4DC/\uB178\uD2B8\uC5D0\uC11C \uC88B\uC74C(Good)\uACFC \uC26C\uC6C0(Easy) \uC0AC\uC774\uC758 \uAC04\uACA9 \uCC28\uC774\uB97C \uC124\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. (\uCD5C\uC18C = 100%)",
|
|
EASY_BONUS_MIN_WARNING: "\uC26C\uC6C0(Easy) \uBCF4\uB108\uC2A4\uB294 \uC801\uC5B4\uB3C4 100\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maximum interval in days",
|
|
MAX_INTERVAL_DESC: "\uAC04\uACA9\uC758 \uC0C1\uD55C\uC120\uC744 \uB458 \uC218 \uC788\uC2B5\uB2C8\uB2E4. (\uAE30\uBCF8\uAC12 = 100\uB144)",
|
|
MAX_INTERVAL_MIN_WARNING: "\uCD5C\uB300 \uAC04\uACA9\uC740 \uC801\uC5B4\uB3C4 1\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
MAX_LINK_CONTRIB: "\uCD5C\uB300 \uC5F0\uACB0 \uAE30\uC5EC\uB3C4",
|
|
MAX_LINK_CONTRIB_DESC: "\uB9C1\uD06C\uB41C \uB178\uD2B8\uC758 \uCD08\uAE30 ease\uC5D0 \uB300\uD55C \uAC00\uC911\uCE58\uAC00 \uC801\uC6A9\uB41C ease\uC758 \uCD5C\uB300 \uAE30\uC5EC\uB3C4\uC785\uB2C8\uB2E4.",
|
|
LOGGING: "\uB85C\uAE45",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\uB514\uBC84\uAE45 \uC815\uBCF4\uB97C \uAC1C\uBC1C\uC790 \uCF58\uC194\uC5D0 \uD45C\uC2DC\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\uB9AC\uBDF0\uD560 \uB178\uD2B8 \uB300\uAE30\uC5F4",
|
|
CLOSE: "\uB2EB\uAE30",
|
|
NEW: "New",
|
|
YESTERDAY: "\uC5B4\uC81C",
|
|
TODAY: "\uC624\uB298",
|
|
TOMORROW: "\uB0B4\uC77C",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\uD1B5\uACC4",
|
|
MONTH: "\uC6D4",
|
|
QUARTER: "\uBD84\uAE30",
|
|
YEAR: "\uB144",
|
|
LIFETIME: "\uD3C9\uC0DD",
|
|
FORECAST: "\uC608\uCE21",
|
|
FORECAST_DESC: "\uC774\uD6C4\uC5D0 \uD559\uC2B5\uD560 \uCE74\uB4DC\uC758 \uC218",
|
|
SCHEDULED: "Scheduled",
|
|
DAYS: "\uC77C",
|
|
NUMBER_OF_CARDS: "\uCE74\uB4DC\uC758 \uC218",
|
|
REVIEWS_PER_DAY: "\uD3C9\uADE0: ${avg} \uB9AC\uBDF0/\uC77C",
|
|
INTERVALS: "\uAC04\uACA9",
|
|
INTERVALS_DESC: "\uB9AC\uBDF0\uB97C \uB2E4\uC2DC \uD560 \uB54C \uAE4C\uC9C0\uC758 \uAE30\uAC04",
|
|
COUNT: "Count",
|
|
INTERVALS_SUMMARY: "\uD3C9\uADE0 \uAC04\uACA9: ${avg}, \uAC00\uC7A5 \uAE34 \uAC04\uACA9: ${longest}",
|
|
EASES: "Eases",
|
|
EASES_SUMMARY: "Average ease: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\uCE74\uB4DC \uD0C0\uC785",
|
|
CARD_TYPES_DESC: "\uC5EC\uAE30\uC5D0\uB294 \uBB3B\uC5B4\uB454 \uCE74\uB4DC\uB3C4 \uD3EC\uD568\uB429\uB2C8\uB2E4.",
|
|
CARD_TYPE_NEW: "New",
|
|
CARD_TYPE_YOUNG: "Young",
|
|
CARD_TYPE_MATURE: "Mature",
|
|
CARD_TYPES_SUMMARY: "\uC804\uCCB4 \uCE74\uB4DC \uC218: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/mr.ts
|
|
var mr_default = {};
|
|
|
|
// src/lang/locale/nl.ts
|
|
var nl_default = {};
|
|
|
|
// src/lang/locale/no.ts
|
|
var no_default = {};
|
|
|
|
// src/lang/locale/pl.ts
|
|
var pl_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Talie",
|
|
DUE_CARDS: "Fiszki z terminem",
|
|
NEW_CARDS: "Nowe fiszki",
|
|
TOTAL_CARDS: "Wszystkie karty",
|
|
BACK: "Wstecz",
|
|
SKIP: "Pomi\u0144",
|
|
EDIT_CARD: "Edytuj kart\u0119",
|
|
RESET_CARD_PROGRESS: "Zresetuj post\u0119p karty",
|
|
HARD: "Trudne",
|
|
GOOD: "\u015Arednio Trudne",
|
|
EASY: "\u0141atwe",
|
|
SHOW_ANSWER: "Poka\u017C odpowied\u017A",
|
|
CARD_PROGRESS_RESET: "Post\u0119p karty zosta\u0142 zresetowany.",
|
|
SAVE: "Zapisz",
|
|
CANCEL: "Anuluj",
|
|
NO_INPUT: "Nie wprowadzono warto\u015Bci.",
|
|
CURRENT_EASE_HELP_TEXT: "Aktualna \u0142atwo\u015B\u0107: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Aktualny interwa\u0142: ",
|
|
CARD_GENERATED_FROM: "Wygenerowano z: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Otw\xF3rz notatk\u0119 do przegl\u0105du",
|
|
REVIEW_CARDS: "Przegl\u0105daj fiszki",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Przegl\u0105daj: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Przegl\u0105daj notatk\u0119 jako ${difficulty}",
|
|
CRAM_ALL_CARDS: "Wybierz tali\u0119 do intensywnego uczenia",
|
|
REVIEW_ALL_CARDS: "Przegl\u0105daj fiszki ze wszystkich notatek",
|
|
REVIEW_CARDS_IN_NOTE: "Przegl\u0105daj fiszki w tej notatce",
|
|
CRAM_CARDS_IN_NOTE: "Intensywne uczenie fiszek w tej notatce",
|
|
VIEW_STATS: "Wy\u015Bwietl statystyki",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Przegl\u0105daj: ${dueNotesCount} notatek, ${dueFlashcardsCount} fiszek z terminem",
|
|
SYNC_TIME_TAKEN: "Synchronizacja zaj\u0119\u0142a ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "Notatka jest zapisana w folderze zignorowanym (sprawd\u017A ustawienia).",
|
|
PLEASE_TAG_NOTE: "Prosz\u0119 odpowiednio otagowa\u0107 notatk\u0119 do przegl\u0105du (w ustawieniach).",
|
|
RESPONSE_RECEIVED: "Otrzymano odpowied\u017A.",
|
|
NO_DECK_EXISTS: "Nie istnieje talia o nazwie ${deckName}",
|
|
ALL_CAUGHT_UP: "Jeste\u015B teraz na bie\u017C\u0105co :D.",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} dni",
|
|
MONTHS_STR_IVL: "${interval} miesi\u0119cy",
|
|
YEARS_STR_IVL: "${interval} lata",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}r",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Aby uzyska\u0107 wi\u0119cej informacji, sprawd\u017A <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Foldery do zignorowania",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Fiszki",
|
|
FLASHCARD_EASY_LABEL: "Tekst przycisku \u0141atwe",
|
|
FLASHCARD_GOOD_LABEL: "Tekst przycisku \u015Arednio trudne",
|
|
FLASHCARD_HARD_LABEL: "Tekst przycisku Trudne",
|
|
FLASHCARD_EASY_DESC: 'Dostosuj etykiet\u0119 dla przycisku "\u0141atwe"',
|
|
FLASHCARD_GOOD_DESC: 'Dostosuj etykiet\u0119 dla przycisku "\u015Arednio trudne"',
|
|
FLASHCARD_HARD_DESC: 'Dostosuj etykiet\u0119 dla przycisku "Trudne"',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Tagi fiszek",
|
|
FLASHCARD_TAGS_DESC: "Wprowad\u017A tagi oddzielone spacj\u0105 lub nowymi liniami, np. #fiszki #talia2 #talia3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Czy konwertowa\u0107 foldery na talie i podtalie?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Jest to alternatywa dla opcji tag\xF3w fiszek powy\u017Cej.",
|
|
INLINE_SCHEDULING_COMMENTS: "Czy zachowa\u0107 komentarz harmonogramowania w tej samej linii co ostatnia linia fiszki?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "W\u0142\u0105czenie tej opcji sprawi, \u017Ce komentarze HTML nie b\u0119d\u0105 przerywa\u0107 formatowania listy.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Czy ukrywa\u0107 karty rodze\u0144stwa do nast\u0119pnego dnia?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Rodze\u0144stwo to karty wygenerowane z tego samego tekstu karty, np. usuni\u0119cia zamaskowane",
|
|
SHOW_CARD_CONTEXT: "Czy pokazywa\u0107 kontekst na kartach?",
|
|
SHOW_CARD_CONTEXT_DESC: "np. Tytu\u0142 > Nag\u0142\xF3wek 1 > Podnag\u0142\xF3wek > ... > Podnag\u0142\xF3wek",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Procentowa wysoko\u015B\u0107 fiszki",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Powinno by\u0107 ustawione na 100% na urz\u0105dzeniach mobilnych lub gdy masz bardzo du\u017Ce obrazy",
|
|
RESET_DEFAULT: "Zresetuj do domy\u015Blnych",
|
|
CARD_MODAL_WIDTH_PERCENT: "Procentowa szeroko\u015B\u0107 fiszki",
|
|
RANDOMIZE_CARD_ORDER: "Czy losowa\u0107 kolejno\u015B\u0107 kart podczas przegl\u0105du?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Kolejno\u015B\u0107 kart w talii wy\u015Bwietlana podczas przegl\u0105dania",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Kolejno w ramach talii (Najpierw wszystkie nowe karty)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Kolejno w ramach talii (Najpierw wszystkie karty z terminem)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Losowo w ramach talii (Najpierw wszystkie nowe karty)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Losowo w ramach talii (Najpierw wszystkie karty z terminem)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Losowa karta z losowej talii",
|
|
REVIEW_DECK_ORDER: "Kolejno\u015B\u0107 talii wy\u015Bwietlana podczas przegl\u0105dania",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Kolejno (gdy wszystkie karty w poprzedniej talii przegl\u0105dni\u0119te)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Losowo (gdy wszystkie karty w poprzedniej talii przegl\u0105dni\u0119te)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Losowa karta z losowej talii",
|
|
DISABLE_CLOZE_CARDS: "Wy\u0142\u0105czy\u0107 karty zamaskowane?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Konwertowa\u0107 ==pod\u015Bwietlenia== na karty zamaskowane?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Konwertowa\u0107 pogrubiony tekst na karty zamaskowane?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Konwertowa\u0107 {{klamry}} na karty zamaskowane?",
|
|
CLOZE_PATTERNS: "Wzory kart zamaskowanych",
|
|
CLOZE_PATTERNS_DESC: 'Wprowad\u017A wzory kart zamaskowanych oddzielone nowymi liniami. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Separator dla kart zamaskowanych w linii",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Pami\u0119taj, \u017Ce po zmianie tego musisz r\u0119cznie edytowa\u0107 wszystkie karty zamaskowane, kt\xF3re ju\u017C masz.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Separator dla kart zamaskowanych odwr\xF3conych w linii",
|
|
MULTILINE_CARDS_SEPARATOR: "Separator dla kart zamaskowanych wieloliniowych",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Separator dla kart zamaskowanych odwr\xF3conych wieloliniowych",
|
|
MULTILINE_CARDS_END_MARKER: "Caracteres que denotam o fim de clozes e flashcards multilineares",
|
|
NOTES: "Notatki",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "W\u0142\u0105czy\u0107 panel przegl\u0105du notatek przy starcie",
|
|
TAGS_TO_REVIEW: "Tagi do przegl\u0105du",
|
|
TAGS_TO_REVIEW_DESC: "Wprowad\u017A tagi oddzielone spacj\u0105 lub nowymi liniami, np. #przegl\u0105d #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "Otw\xF3rz losow\u0105 notatk\u0119 do przegl\u0105du",
|
|
OPEN_RANDOM_NOTE_DESC: "Po wy\u0142\u0105czeniu tej opcji notatki s\u0105 uporz\u0105dkowane wed\u0142ug istotno\u015Bci (PageRank).",
|
|
AUTO_NEXT_NOTE: "Automatycznie otwiera\u0107 nast\u0119pn\u0105 notatk\u0119 po przegl\u0105dzie",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Wy\u0142\u0105czy\u0107 opcje przegl\u0105du w menu pliku, tj. Przegl\u0105daj: \u0141atwe Dobrze Trudne",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Je\u015Bli wy\u0142\u0105czysz opcje przegl\u0105du w menu Plik, mo\u017Cesz przegl\u0105da\u0107 swoje notatki za pomoc\u0105 polece\u0144 wtyczki i, je\u015Bli je zdefiniowa\u0142e\u015B, przypisanych skr\xF3t\xF3w klawiszowych.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Maksymalna liczba dni do wy\u015Bwietlenia w panelu prawym",
|
|
MIN_ONE_DAY: "Liczba dni musi wynosi\u0107 co najmniej 1.",
|
|
VALID_NUMBER_WARNING: "Podaj prawid\u0142ow\u0105 liczb\u0119.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Podtalie powinny by\u0107 pocz\u0105tkowo wy\u015Bwietlane rozszerzone",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Wy\u0142\u0105cz to, aby zwin\u0105\u0107 zagnie\u017Cd\u017Cone talie w tej samej karcie. Przydatne, je\u015Bli karty nale\u017C\u0105 do wielu talii w tym samym pliku.",
|
|
ALGORITHM: "Algorytm",
|
|
CHECK_ALGORITHM_WIKI: 'Aby uzyska\u0107 wi\u0119cej informacji, sprawd\u017A <a href="${algoUrl}">implementacj\u0119 algorytmu</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Podstawowa \u0142atwo\u015B\u0107",
|
|
BASE_EASE_DESC: "minimum = 130, preferowana warto\u015B\u0107 to oko\u0142o 250.",
|
|
BASE_EASE_MIN_WARNING: "Podstawowa \u0142atwo\u015B\u0107 musi wynosi\u0107 co najmniej 130.",
|
|
LAPSE_INTERVAL_CHANGE: "Zmiana interwa\u0142u podczas przegl\u0105dania fiszki/notatki jako trudne",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "nowyInterwa\u0142 = staryInterwa\u0142 * zmianaInterwa\u0142u / 100.",
|
|
EASY_BONUS: "Bonus za \u0142atwe",
|
|
EASY_BONUS_DESC: "Bonus za \u0142atwe pozwala ustawi\u0107 r\xF3\u017Cnic\u0119 w interwa\u0142ach mi\u0119dzy odpowiedziami \u015Arednio trudne i \u0141atwe na fiszce/notatce (minimum = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "Bonus za \u0142atwe musi wynosi\u0107 co najmniej 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maksymalny interwa\u0142 w dniach",
|
|
MAX_INTERVAL_DESC: "Pozwala na ustawienie g\xF3rnego limitu interwa\u0142u (domy\u015Blnie = 100 lat).",
|
|
MAX_INTERVAL_MIN_WARNING: "Maksymalny interwa\u0142 musi wynosi\u0107 co najmniej 1 dzie\u0144.",
|
|
MAX_LINK_CONTRIB: "Maksymalny wk\u0142ad \u0142\u0105cza",
|
|
MAX_LINK_CONTRIB_DESC: "Maksymalny wk\u0142ad wa\u017Conej \u0142atwo\u015Bci po\u0142\u0105czonych notatek do pocz\u0105tkowej \u0142atwo\u015Bci.",
|
|
LOGGING: "Logowanie",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Wy\u015Bwietl informacje debugowania w konsoli deweloperskiej",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Kolejka przegl\u0105du notatek",
|
|
CLOSE: "Zamknij",
|
|
NEW: "Nowe",
|
|
YESTERDAY: "Wczoraj",
|
|
TODAY: "Dzisiaj",
|
|
TOMORROW: "Jutro",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Statystyki",
|
|
MONTH: "Miesi\u0105c",
|
|
QUARTER: "Kwarta\u0142",
|
|
YEAR: "Rok",
|
|
LIFETIME: "Ca\u0142e \u017Cycie",
|
|
FORECAST: "Prognoza",
|
|
FORECAST_DESC: "Liczba kart z terminem w przysz\u0142o\u015Bci",
|
|
SCHEDULED: "Zaplanowane",
|
|
DAYS: "Dni",
|
|
NUMBER_OF_CARDS: "Liczba kart",
|
|
REVIEWS_PER_DAY: "\u015Arednio: ${avg} przegl\u0105d\xF3w/dzie\u0144",
|
|
INTERVALS: "Interwa\u0142y",
|
|
INTERVALS_DESC: "Op\xF3\u017Anienia przed ponownym pokazaniem przegl\u0105d\xF3w",
|
|
COUNT: "Liczba",
|
|
INTERVALS_SUMMARY: "\u015Aredni interwa\u0142: ${avg}, Najd\u0142u\u017Cszy interwa\u0142: ${longest}",
|
|
EASES: "\u0141atwo\u015Bci",
|
|
EASES_SUMMARY: "\u015Arednia \u0142atwo\u015B\u0107: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Typy kart",
|
|
CARD_TYPES_DESC: "Obejmuje tak\u017Ce ukryte karty, je\u015Bli takie s\u0105",
|
|
CARD_TYPE_NEW: "Nowe",
|
|
CARD_TYPE_YOUNG: "M\u0142ode",
|
|
CARD_TYPE_MATURE: "Stare",
|
|
CARD_TYPES_SUMMARY: "\u0141\u0105czna liczba kart: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/pt.ts
|
|
var pt_default = {};
|
|
|
|
// src/lang/locale/pt-br.ts
|
|
var pt_br_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Baralhos",
|
|
DUE_CARDS: "Cartas para Colocar em Dia",
|
|
NEW_CARDS: "Novas Cartas",
|
|
TOTAL_CARDS: "Total de Cartas",
|
|
BACK: "Voltar",
|
|
SKIP: "Pular",
|
|
EDIT_CARD: "Editar Cart\xE3o",
|
|
RESET_CARD_PROGRESS: "Reiniciar o Progresso da Carta",
|
|
HARD: "Dif\xEDcil",
|
|
GOOD: "OK",
|
|
EASY: "F\xE1cil",
|
|
SHOW_ANSWER: "Mostrar Resposta",
|
|
CARD_PROGRESS_RESET: "O Progresso da Carta foi reiniciado",
|
|
SAVE: "Salvar",
|
|
CANCEL: "Cancelar",
|
|
NO_INPUT: "Nenhuma entrada fornecida.",
|
|
CURRENT_EASE_HELP_TEXT: "Facilidade atual: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Intervalo atual: ",
|
|
CARD_GENERATED_FROM: "Gerada a partir de: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "Abrir uma nota para revisar",
|
|
REVIEW_CARDS: "Revisar flashcards",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "Revis\xE3o: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Revisar nota como ${difficulty}",
|
|
REVIEW_ALL_CARDS: "Revisar flashcards de todas as notas",
|
|
CRAM_ALL_CARDS: "Selecione um baralho para revisar",
|
|
REVIEW_CARDS_IN_NOTE: "Revisar flashcards nessa nota",
|
|
CRAM_CARDS_IN_NOTE: "Revisar todas as flashcards nessa nota",
|
|
VIEW_STATS: "Ver estat\xEDsticas",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "Revis\xE3o: ${dueNotesCount} nota(s), ${dueFlashcardsCount} Carta(s) para colocar em dia",
|
|
SYNC_TIME_TAKEN: "Sincroniza\xE7\xE3o levou ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "Nota \xE9 salva na pasta ignorada (cheque as configura\xE7\xF5es).",
|
|
PLEASE_TAG_NOTE: "Por favor etiquete a nota apropriadamente para revisar (nas configura\xE7\xF5es).",
|
|
RESPONSE_RECEIVED: "Resposta recebida.",
|
|
NO_DECK_EXISTS: "Nenhum baralho existe para ${deckName}",
|
|
ALL_CAUGHT_UP: "Voc\xEA colocou tudo em dia agora :D.",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} dia(s)",
|
|
MONTHS_STR_IVL: "${interval} m\xEAs(es)",
|
|
YEARS_STR_IVL: "${interval} ano(s)",
|
|
DAYS_STR_IVL_MOBILE: "${interval}d",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}m",
|
|
YEARS_STR_IVL_MOBILE: "${interval}a",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: 'Para mais informa\xE7\xF5es, cheque a <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "Pastas para ignorar",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Flashcards",
|
|
FLASHCARD_EASY_LABEL: "Texto do Bot\xE3o de F\xE1cil",
|
|
FLASHCARD_GOOD_LABEL: "Texto do Bot\xE3o de OK",
|
|
FLASHCARD_HARD_LABEL: "Texto do Bot\xE3o de Dif\xEDcil",
|
|
FLASHCARD_EASY_DESC: 'Customize o r\xF3tulo para o bot\xE3o de "F\xE1cil"',
|
|
FLASHCARD_GOOD_DESC: 'Customize o r\xF3tulo para o bot\xE3o de "OK"',
|
|
FLASHCARD_HARD_DESC: 'Customize o r\xF3tulo para o bot\xE3o de "Dif\xEDcil"',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Etiquetas dos Flashcards",
|
|
FLASHCARD_TAGS_DESC: "Insira etiquetas separadas por espa\xE7os ou quebras de linha ex: #flashcards #baralho2 #baralho3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Converter pastas para baralhos e sub-baralhos?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Isso \xE9 uma alternativa para a op\xE7\xE3o de etiqueta dos Flashcards em cima.",
|
|
INLINE_SCHEDULING_COMMENTS: "Salvar coment\xE1rios de agendamento na mesma linha que a \xFAltima linha do flashcard?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Ligar isso vai fazer com que os coment\xE1rios em HTML n\xE3o quebrem a formata\xE7\xE3o de listas.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Enterrar cartas irm\xE3s at\xE9 o pr\xF3ximo dia?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Cartas irm\xE3s s\xE3o geradas pelo texto da mesma carta ex: omiss\xE3o de palavras",
|
|
SHOW_CARD_CONTEXT: "Mostrar contexto nas cartas?",
|
|
SHOW_CARD_CONTEXT_DESC: "ex: T\xEDtulo > Cabe\xE7alho 1 > Subcabe\xE7alho > ... > Subcabe\xE7alho",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Porcentagem da Altura do Flashcard",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Deveria estar configurado em 100% em dispositivos m\xF3veis ou se voc\xEA tem imagens muito grandes",
|
|
RESET_DEFAULT: "Reiniciar para a pr\xE9-defini\xE7\xE3o",
|
|
CARD_MODAL_WIDTH_PERCENT: "Porcentagem de Largura do Flashcard",
|
|
RANDOMIZE_CARD_ORDER: "Aleatorizar a ordem das cartas durante a revis\xE3o?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "Order cards in a deck are displayed during review",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "Sequentially within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "Sequentially within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Randomly within a deck (All new cards first)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Randomly within a deck (All due cards first)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
REVIEW_DECK_ORDER: "Order decks are displayed during review",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "Sequentially (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Randomly (once all cards in previous deck reviewed)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Random card from random deck",
|
|
DISABLE_CLOZE_CARDS: "Desabilitar cartas que usam omiss\xE3o de palavras?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "Converter ==marca-texto== em omiss\xF5es?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "Converter **texto em negrito** em omiss\xF5es?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "Converter {{chaves}} em omiss\xF5es?",
|
|
CLOZE_PATTERNS: "Padr\xF5es de Omiss\xE3o",
|
|
CLOZE_PATTERNS_DESC: 'Entre os padr\xF5es de omiss\xE3o separados por quebras de linha. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Separador para flashcards inline",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Note que depois de mudar isso voc\xEA vai ter que manualmente mudar quaisquer flashcards que voc\xEA tenha.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Separador para flashcards inline reversos",
|
|
MULTILINE_CARDS_SEPARATOR: "Separador para flashcards de m\xFAltiplas linhas",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "Separador para flashcards de m\xFAltiplas linhas reversos",
|
|
MULTILINE_CARDS_END_MARKER: "Caracteres que denotam o fim de clozes e flashcards multilinha",
|
|
NOTES: "Notas",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Habilitar painel de revis\xE3o de notas na inicializa\xE7\xE3o",
|
|
TAGS_TO_REVIEW: "Etiquetas para revisar",
|
|
TAGS_TO_REVIEW_DESC: "Insira etiquetas separadas por espa\xE7os ou quebra de linhas ex: #revisar #etiqueta2 #etiqueta3.",
|
|
OPEN_RANDOM_NOTE: "Abrir uma nota aleat\xF3ria para revisar",
|
|
OPEN_RANDOM_NOTE_DESC: "Quando voc\xEA desabilitar isso, as notas v\xE3o ser ordenadas por import\xE2ncia (PageRank).",
|
|
AUTO_NEXT_NOTE: "Abrir a pr\xF3xima nota automaticamente depois de uma revis\xE3o",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Ative as op\xE7\xF5es de revis\xE3o no menu Arquivo (ex.: Revis\xE3o: F\xE1cil, OK, Dif\xEDcil)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "Se voc\xEA desativar as op\xE7\xF5es de revis\xE3o no menu Arquivo, poder\xE1 revisar suas anota\xE7\xF5es usando os comandos do plugin e, se os tiver definido, as teclas de atalho associadas.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "N\xFAmero m\xE1ximo de dias para exibir no painel direito",
|
|
MIN_ONE_DAY: "O n\xFAmero de dias deve ser pelo menos 1.",
|
|
VALID_NUMBER_WARNING: "Por favor Insira um n\xFAmero v\xE1lido.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\xC1rvores de baralhos devem inicialmente ser exibidas como expandidas",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Desabilite isso para colapsar baralhos que est\xE3o um dentro do outro na mesma carta. \xDAtil se voc\xEA tem cartas que pertencem a muitos baralhos em um mesmo arquivo.",
|
|
ALGORITHM: "Algor\xEDtmo",
|
|
CHECK_ALGORITHM_WIKI: 'Para mais informa\xE7\xF5es, cheque a <a href="${algoUrl}">implementa\xE7\xE3o do algor\xEDtmo</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Facilidade base",
|
|
BASE_EASE_DESC: "m\xEDnimo = 130, preferivelmente por volta de 250.",
|
|
BASE_EASE_MIN_WARNING: "A facilidade base deve ser pelo menos 130.",
|
|
LAPSE_INTERVAL_CHANGE: "Mudan\xE7a de intervalo quando voc\xEA revisa um(a) flashcard/nota como dif\xEDcil",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "novoIntervalo = velhoIntervalo * mudancaIntervalo / 100.",
|
|
EASY_BONUS: "B\xF4nus de F\xE1cil",
|
|
EASY_BONUS_DESC: "O b\xF4nus de f\xE1cil te permite mudar a difer\xEAncia entre intervalos de responder OK e F\xE1cil em um(a) flashcard/nota (m\xEDnimo = 100%).",
|
|
EASY_BONUS_MIN_WARNING: "O b\xF4nus de f\xE1cil deve ser pelo menos 100.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Intervalo m\xE1ximo em dias",
|
|
MAX_INTERVAL_DESC: "Te permite colocar um limite m\xE1ximo no intervalo (pr\xE9-defini\xE7\xE3o = 100 anos).",
|
|
MAX_INTERVAL_MIN_WARNING: "O intervalo m\xE1ximo deve ser pelo menos 1 dia.",
|
|
MAX_LINK_CONTRIB: "Contribui\xE7\xE3o M\xE1xima de Links",
|
|
MAX_LINK_CONTRIB_DESC: "Contribui\xE7\xE3o m\xE1xima da facilidade ponderada das notas linkadas \xE0 facilidade inicial.",
|
|
LOGGING: "Logging",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Mostrar informa\xE7\xE3o de debugging no console de desenvolvimento",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Fila de Notas para Revisar",
|
|
CLOSE: "Fechar",
|
|
NEW: "Novo",
|
|
YESTERDAY: "Ontem",
|
|
TODAY: "Hoje",
|
|
TOMORROW: "Amanh\xE3",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "Estat\xEDsticas",
|
|
MONTH: "M\xEAs",
|
|
QUARTER: "Trimestre",
|
|
YEAR: "Ano",
|
|
LIFETIME: "Tempo Total",
|
|
FORECAST: "Previs\xE3o",
|
|
FORECAST_DESC: "O n\xFAmero de cartas a serem colocadas em dia no futuro",
|
|
SCHEDULED: "Agendado",
|
|
DAYS: "Dias",
|
|
NUMBER_OF_CARDS: "N\xFAmero de cartas",
|
|
REVIEWS_PER_DAY: "M\xE9dia: ${avg} revis\xF5es/dia",
|
|
INTERVALS: "Intervalos",
|
|
INTERVALS_DESC: "Atrasos at\xE9 que as revis\xF5es sejam exibidas de novo",
|
|
COUNT: "Contagem",
|
|
INTERVALS_SUMMARY: "Intervalo em m\xE9dia: ${avg}, Maior intervalo: ${longest}",
|
|
EASES: "Facilidades",
|
|
EASES_SUMMARY: "Facilidade em m\xE9dia: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Tipos de Cartas",
|
|
CARD_TYPES_DESC: "Isso tamb\xE9m inclui cartas enterradas, caso existam",
|
|
CARD_TYPE_NEW: "Novo",
|
|
CARD_TYPE_YOUNG: "Jovem",
|
|
CARD_TYPE_MATURE: "Amadurecido",
|
|
CARD_TYPES_SUMMARY: "Total de cartas: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/ro.ts
|
|
var ro_default = {};
|
|
|
|
// src/lang/locale/ru.ts
|
|
var ru_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\u041A\u043E\u043B\u043E\u0434\u044B",
|
|
DUE_CARDS: "\u041F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u043C\u044B\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
NEW_CARDS: "\u041D\u043E\u0432\u044B\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
TOTAL_CARDS: "\u0412\u0441\u0435\u0433\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
BACK: "\u041D\u0430\u0437\u0430\u0434",
|
|
SKIP: "\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u044C",
|
|
EDIT_CARD: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443",
|
|
RESET_CARD_PROGRESS: "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
HARD: "\u0421\u043B\u043E\u0436\u043D\u043E",
|
|
GOOD: "\u041D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E",
|
|
EASY: "\u041B\u0435\u0433\u043A\u043E",
|
|
SHOW_ANSWER: "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043E\u0442\u0432\u0435\u0442",
|
|
CARD_PROGRESS_RESET: "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441 \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
SAVE: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C",
|
|
CANCEL: "\u041E\u0442\u043C\u0435\u043D\u0430",
|
|
NO_INPUT: "\u041F\u0443\u0441\u0442\u043E\u0439 \u0432\u0432\u043E\u0434.",
|
|
CURRENT_EASE_HELP_TEXT: "\u0422\u0435\u043A\u0443\u0449\u0438\u0439 \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "\u0422\u0435\u043A\u0443\u0449\u0438\u0439 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B: ",
|
|
CARD_GENERATED_FROM: "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E \u0438\u0437: ${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0437\u0430\u043C\u0435\u0442\u043A\u0443 \u0434\u043B\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
REVIEW_CARDS: "\u0418\u0437\u0443\u0447\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "\u0418\u0437\u0443\u0447\u0435\u043D\u0438\u0435: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "\u0418\u0437\u0443\u0447\u0430\u0442\u044C \u0437\u0430\u043C\u0435\u0442\u043A\u0443 \u043A\u0430\u043A ${difficulty}",
|
|
CRAM_ALL_CARDS: "\u0417\u0443\u0431\u0440\u0438\u0442\u044C \u0432\u0441\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432 \u044D\u0442\u043E\u0439 \u043A\u043E\u043B\u043E\u0434\u0435",
|
|
REVIEW_ALL_CARDS: "\u0418\u0437\u0443\u0447\u0430\u0442\u044C \u0432\u0441\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432\u043E \u0432\u0441\u0435\u0445 \u0437\u0430\u043C\u0435\u0442\u043A\u0430\u0445",
|
|
REVIEW_CARDS_IN_NOTE: "\u0418\u0437\u0443\u0447\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432 \u044D\u0442\u043E\u0439 \u0437\u0430\u043C\u0435\u0442\u043A\u0435",
|
|
CRAM_CARDS_IN_NOTE: "\u0417\u0443\u0431\u0440\u0438\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432 \u044D\u0442\u043E\u0439 \u0437\u0430\u043C\u0435\u0442\u043A\u0435",
|
|
VIEW_STATS: "\u041F\u043E\u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0443",
|
|
OPEN_REVIEW_QUEUE_VIEW: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F \u0437\u0430\u043C\u0435\u0442\u043E\u043A \u043D\u0430 \u0431\u043E\u043A\u043E\u0432\u043E\u0439 \u043F\u0430\u043D\u0435\u043B\u0438",
|
|
STATUS_BAR: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C: ${dueNotesCount} \u0437\u0430\u043C\u0435\u0442\u043E\u043A, ${dueFlashcardsCount} \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
SYNC_TIME_TAKEN: "\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u0437\u0430\u043D\u044F\u043B\u0430 ${t}\u043C\u0441",
|
|
NOTE_IN_IGNORED_FOLDER: "\u0417\u0430\u043C\u0435\u0442\u043A\u0430 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0430 \u0432 \u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0435\u043C\u0443\u044E \u043F\u0430\u043F\u043A\u0443 (\u0441\u043C. \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438).",
|
|
PLEASE_TAG_NOTE: "\u0414\u043B\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E \u043F\u043E\u043C\u0435\u0442\u044C\u0442\u0435 \u0437\u0430\u043C\u0435\u0442\u043A\u0443 \u0442\u0435\u0433\u043E\u043C (\u0441\u043C. \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438).",
|
|
RESPONSE_RECEIVED: "\u041E\u0442\u0432\u0435\u0442 \u043F\u043E\u043B\u0443\u0447\u0435\u043D.",
|
|
NO_DECK_EXISTS: "\u041D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0440\u043E\u0432\u043D\u044F ${deckName}",
|
|
ALL_CAUGHT_UP: "\u041C\u043E\u043B\u043E\u0434\u0435\u0446! \u0422\u044B \u0441\u043F\u0440\u0430\u0432\u0438\u043B\u0441\u044F \u0438 \u0434\u043E\u0448\u0435\u043B \u0434\u043E \u043A\u043E\u043D\u0446\u0430! :D",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} \u0434\u043D\u0435\u0439",
|
|
MONTHS_STR_IVL: "${interval} \u043C\u0435\u0441\u044F\u0446\u0435\u0432",
|
|
YEARS_STR_IVL: "${interval} \u0433\u043E\u0434\u043E\u0432",
|
|
DAYS_STR_IVL_MOBILE: "${interval}\u0434.",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}\u043C.",
|
|
YEARS_STR_IVL_MOBILE: "${interval}\u0433.",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Spaced Repetition",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '\u0414\u043B\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043F\u043E\u0441\u0435\u0442\u0438\u0442\u0435: <a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\u0418\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0435\u043C\u044B\u0435 \u043F\u0430\u043F\u043A\u0438",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
FLASHCARD_EASY_LABEL: '\u0422\u0435\u043A\u0441\u0442 \u043A\u043D\u043E\u043F\u043A\u0438 "\u041B\u0435\u0433\u043A\u043E"',
|
|
FLASHCARD_GOOD_LABEL: '\u0422\u0435\u043A\u0441\u0442 \u043A\u043D\u043E\u043F\u043A\u0438 "\u041D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E"',
|
|
FLASHCARD_HARD_LABEL: '\u0422\u0435\u043A\u0441\u0442 \u043A\u043D\u043E\u043F\u043A\u0438 "\u0421\u043B\u043E\u0436\u043D\u043E"',
|
|
FLASHCARD_EASY_DESC: '\u041D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u044F\u0440\u043B\u044B\u043A \u0434\u043B\u044F \u043A\u043D\u043E\u043F\u043A\u0438 "\u041B\u0435\u0433\u043A\u043E"',
|
|
FLASHCARD_GOOD_DESC: '\u041D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u044F\u0440\u043B\u044B\u043A \u0434\u043B\u044F \u043A\u043D\u043E\u043F\u043A\u0438 "\u041D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E"',
|
|
FLASHCARD_HARD_DESC: '\u041D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u044F\u0440\u043B\u044B\u043A \u0434\u043B\u044F \u043A\u043D\u043E\u043F\u043A\u0438 "\u0421\u043B\u043E\u0436\u043D\u043E"',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\u0422\u0435\u0433\u0438 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
FLASHCARD_TAGS_DESC: "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0442\u0435\u0433\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 Enter-\u043E\u043C \u0438\u043B\u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u043C, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: #flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0438 \u0432 \u0443\u0440\u043E\u0432\u043D\u0438 \u0438 \u043F\u043E\u0434\u0443\u0440\u043E\u0432\u043D\u0438?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "\u042D\u0442\u043E \u0430\u043B\u044C\u0442\u0435\u0440\u043D\u0430\u0442\u0438\u0432\u0430 \u043E\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u043C\u0443 \u0432\u044B\u0448\u0435 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0443 \u0442\u0435\u0433\u043E\u0432 \u0444\u043B\u044D\u0448-\u043A\u0430\u0440\u0442",
|
|
INLINE_SCHEDULING_COMMENTS: "\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043F\u043B\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u043D\u0430 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0439 \u0441\u0442\u0440\u043E\u043A\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "\u0412\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0439 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0441\u0434\u0435\u043B\u0430\u0435\u0442 \u0442\u0430\u043A, \u0447\u0442\u043E HTML \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \u043D\u0435 \u0431\u0443\u0434\u0443\u0442 \u043B\u043E\u043C\u0430\u0442\u044C \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u0441\u043F\u0438\u0441\u043A\u0430.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\u041F\u0440\u044F\u0442\u0430\u0442\u044C \u0440\u043E\u0434\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0434\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0433\u043E \u0434\u043D\u044F?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "\u0420\u043E\u0434\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 - \u0442\u0435, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u043E\u0434\u043D\u043E\u0433\u043E \u0442\u0435\u043A\u0441\u0442\u0430, \u043F\u0440\u0438\u043C\u0435\u0440: \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0441 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u043C\u0438 ([...])",
|
|
SHOW_CARD_CONTEXT: "\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 (\u0443\u0440\u043E\u0432\u0435\u043D\u044C) \u0432 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430\u0445 (\u0432\u043E \u0432\u0440\u0435\u043C\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F)?",
|
|
SHOW_CARD_CONTEXT_DESC: "\u043F\u0440\u0438\u043C\u0435\u0440: Title > Heading 1 > Subheading > ... > Subheading",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\u0412\u044B\u0441\u043E\u0442\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432 \u043F\u0440\u043E\u0446\u0435\u043D\u0442\u0430\u0445",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\u0415\u0441\u043B\u0438 \u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435\u0441\u044C \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u044B\u043C \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u043E\u043C, \u0432\u044B\u0441\u0442\u0430\u0432\u044C\u0442\u0435 100%. \u0418\u043D\u0430\u0447\u0435 \u0443 \u0432\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u043E\u0433\u0440\u043E\u043C\u043D\u044B\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F",
|
|
RESET_DEFAULT: "\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043F\u043E-\u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u0428\u0438\u0440\u0438\u043D\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u0432 \u043F\u0440\u043E\u0446\u0435\u043D\u0442\u0430\u0445",
|
|
RANDOMIZE_CARD_ORDER: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u044B\u0439 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u043A\u0430\u0440\u0442 \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "\u041F\u043E\u0440\u044F\u0434\u043E\u043A \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F \u043A\u0430\u0440\u0442 \u043A\u043E\u043B\u043E\u0434\u044B \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "\u041F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0432\u043D\u0443\u0442\u0440\u0438 \u043A\u043E\u043B\u043E\u0434\u044B (\u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u0441\u0435 \u043D\u043E\u0432\u044B\u0435 \u043A\u0430\u0440\u0442\u044B)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "\u041F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0432\u043D\u0443\u0442\u0440\u0438 \u043A\u043E\u043B\u043E\u0434\u044B (\u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u0441\u0435 \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u043C\u044B\u0435 \u043A\u0430\u0440\u0442\u044B)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u043E \u0432\u043D\u0443\u0442\u0440\u0438 \u043A\u043E\u043B\u043E\u0434\u044B (\u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u0441\u0435 \u043D\u043E\u0432\u044B\u0435 \u043A\u0430\u0440\u0442\u044B)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u043E \u0432\u043D\u0443\u0442\u0440\u0438 \u043A\u043E\u043B\u043E\u0434\u044B (\u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u0441\u0435 \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u043C\u044B\u0435 \u043A\u0430\u0440\u0442\u044B)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u0430\u044F \u043A\u0430\u0440\u0442\u0430 \u0438\u0437 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u043E\u0439 \u043A\u043E\u043B\u043E\u0434\u044B",
|
|
REVIEW_DECK_ORDER: "\u041F\u043E\u0440\u044F\u0434\u043E\u043A \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F \u043A\u043E\u043B\u043E\u0434 \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "\u041F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E (\u043F\u043E\u0441\u043B\u0435 \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u0432\u0441\u0435\u0445 \u043A\u0430\u0440\u0442 \u0438\u0437 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0439 \u043A\u043E\u043B\u043E\u0434\u044B)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u043E (\u043F\u043E\u0441\u043B\u0435 \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u0432\u0441\u0435\u0445 \u043A\u0430\u0440\u0442 \u0438\u0437 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0439 \u043A\u043E\u043B\u043E\u0434\u044B)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "\u0421\u043B\u0443\u0447\u0430\u0439\u043D\u0430\u044F \u043A\u0430\u0440\u0442\u0430 \u0438\u0437 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u043E\u0439 \u043A\u043E\u043B\u043E\u0434\u044B",
|
|
DISABLE_CLOZE_CARDS: "\u0412\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043A\u0430\u0440\u0442\u044B \u0441 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u043C\u0438 (\u043F\u0440\u0438\u043C\u0435\u0440: [...])?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C ==\u0432\u044B\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442== \u0432 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0438 (\u043F\u0440\u0438\u043C\u0435\u0440: [...])?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C **\u0436\u0438\u0440\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442** \u0432 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0438 (\u043F\u0440\u0438\u043C\u0435\u0440: [...])?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C {{\u0444\u0438\u0433\u0443\u0440\u043D\u044B\u0435 \u0441\u043A\u043E\u0431\u043A\u0438}} \u0432 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0438 (\u043F\u0440\u0438\u043C\u0435\u0440: [...])?",
|
|
CLOZE_PATTERNS: "\u0428\u0430\u0431\u043B\u043E\u043D\u044B \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u043E\u0432",
|
|
CLOZE_PATTERNS_DESC: '\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0448\u0430\u0431\u043B\u043E\u043D\u044B \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u043E\u0432, \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430\u043C\u0438 \u0441\u0442\u0440\u043E\u043A. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u0434\u043B\u044F \u0432\u043D\u0443\u0442\u0440\u0438\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0445 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\u0412\u043D\u0438\u043C\u0430\u043D\u0438\u0435! \u041F\u043E\u0441\u043B\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u044D\u0442\u043E\u0433\u043E \u0432\u0430\u043C \u043F\u0440\u0438\u0434\u0451\u0442\u0441\u044F \u0432\u0440\u0443\u0447\u043D\u0443\u044E \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u0434\u043B\u044F \u043E\u0431\u0440\u0430\u0442\u043D\u044B\u0445 \u0432\u043D\u0443\u0442\u0440\u0438\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0445 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
MULTILINE_CARDS_SEPARATOR: "\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u0434\u043B\u044F \u043C\u043D\u043E\u0433\u043E\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0445 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u0434\u043B\u044F \u043E\u0431\u0440\u0430\u0442\u043D\u044B\u0445 \u043C\u043D\u043E\u0433\u043E\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0445 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
MULTILINE_CARDS_END_MARKER: "\u0421\u0438\u043C\u0432\u043E\u043B\u044B, \u043E\u0431\u043E\u0437\u043D\u0430\u0447\u0430\u044E\u0449\u0438\u0435 \u043A\u043E\u043D\u0435\u0446 \u043A\u043B\u043E\u0437\u043E\u0432 \u0438 \u043C\u043D\u043E\u0433\u043E\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0445 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
NOTES: "\u0417\u0430\u043C\u0435\u0442\u043A\u0438",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0430\u043D\u0435\u043B\u044C \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B",
|
|
TAGS_TO_REVIEW: "\u0422\u0435\u0433\u0438 \u0434\u043B\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
TAGS_TO_REVIEW_DESC: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u0433\u0438, \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 Enter-\u0430\u043C\u0438 \u0438\u043B\u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u0430\u043C\u0438, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u0443\u044E \u0437\u0430\u043C\u0435\u0442\u043A\u0443 \u0434\u043B\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
OPEN_RANDOM_NOTE_DESC: "\u0415\u0441\u043B\u0438 \u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C, \u0442\u043E \u0437\u0430\u043C\u0435\u0442\u043A\u0438 \u0431\u0443\u0434\u0443\u0442 \u043E\u0442\u0441\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u043F\u043E \u0432\u0430\u0436\u043D\u043E\u0441\u0442\u0438 (PageRank).",
|
|
AUTO_NEXT_NOTE: "\u041F\u043E\u0441\u043B\u0435 \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0437\u0430\u043C\u0435\u0442\u043A\u0443",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u043E\u0431\u0437\u043E\u0440\u0430 \u0432 \u043C\u0435\u043D\u044E \u0424\u0430\u0439\u043B (\u0442.\u0435.: \u0418\u0437\u0443\u0447\u0435\u043D\u0438\u0435: \u041B\u0435\u0433\u043A\u043E, \u041D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E, \u0421\u043B\u043E\u0436\u043D\u043E)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\u0415\u0441\u043B\u0438 \u0432\u044B \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u043E\u0431\u0437\u043E\u0440\u0430 \u0432 \u043C\u0435\u043D\u044E \u0424\u0430\u0439\u043B, \u0432\u044B \u0441\u043C\u043E\u0436\u0435\u0442\u0435 \u043F\u0440\u043E\u0441\u043C\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044C \u0441\u0432\u043E\u0438 \u0437\u0430\u043C\u0435\u0442\u043A\u0438 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043A\u043E\u043C\u0430\u043D\u0434 \u043F\u043B\u0430\u0433\u0438\u043D\u0430 \u0438, \u0435\u0441\u043B\u0438 \u0432\u044B \u0438\u0445 \u0437\u0430\u0434\u0430\u043B\u0438, \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445 \u0433\u043E\u0440\u044F\u0447\u0438\u0445 \u043A\u043B\u0430\u0432\u0438\u0448.",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\u041D\u0430\u0438\u0431\u043E\u043B\u044C\u0448\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0434\u043D\u0435\u0439 \u0434\u043B\u044F \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u043F\u0430\u043D\u0435\u043B\u0438 \u0441\u043F\u0440\u0430\u0432\u0430",
|
|
MIN_ONE_DAY: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0434\u043D\u0435\u0439 \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 1.",
|
|
VALID_NUMBER_WARNING: "\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u044F\u0449\u0435\u0435 \u0447\u0438\u0441\u043B\u043E.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\u0414\u0435\u0440\u0435\u0432\u044C\u044F \u043A\u043E\u043B\u043E\u0434 \u0434\u043E\u043B\u0436\u043D\u044B \u0438\u0437\u043D\u0430\u0447\u0430\u043B\u044C\u043D\u043E \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C\u0441\u044F \u043A\u0430\u043A \u0440\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044B\u0435",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "\u041E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u044D\u0442\u043E\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u043B\u043E\u0434\u044B \u043D\u0430 \u043E\u0434\u043D\u043E\u0439 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435. \u041F\u043E\u043B\u0435\u0437\u043D\u043E, \u0435\u0441\u043B\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C \u043A\u0430\u0440\u0442\u044B, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043F\u0440\u0438\u043D\u0430\u0434\u043B\u0435\u0436\u0430\u0442 \u043C\u043D\u043E\u0433\u0438\u043C \u043A\u043E\u043B\u043E\u0434\u0430\u043C \u0432 \u043E\u0434\u043D\u043E\u043C \u0444\u0430\u0439\u043B\u0435.",
|
|
ALGORITHM: "\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C",
|
|
CHECK_ALGORITHM_WIKI: '\u0417\u0430 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0435\u0439 \u043E\u0431\u0440\u0430\u0449\u0430\u0439\u0442\u0435\u0441\u044C \u043A <a href="${algoUrl}">\u0440\u0435\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F \u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u0430</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\u0411\u0430\u0437\u043E\u0432\u0430\u044F \u041B\u0451\u0433\u043A\u043E\u0441\u0442\u044C",
|
|
BASE_EASE_DESC: "\u043C\u0438\u043D\u0438\u043C\u0443\u043C = 130, \u043F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u043E\u043A\u043E\u043B\u043E 250.",
|
|
BASE_EASE_MIN_WARNING: "\u041B\u0451\u0433\u043A\u043E\u0441\u0442\u044C \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043C\u0438\u043D\u0438\u043C\u0443\u043C 130.",
|
|
LAPSE_INTERVAL_CHANGE: '\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B\u0430 \u043F\u0440\u0438 \u0432\u044B\u0431\u043E\u0440\u0435 "\u0421\u043B\u043E\u0436\u043D\u043E" \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438/\u0437\u0430\u043C\u0435\u0442\u043A\u0438',
|
|
LAPSE_INTERVAL_CHANGE_DESC: "\u043D\u043E\u0432\u044B\u0439\u041F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u043A = \u0441\u0442\u0430\u0440\u044B\u0439\u041F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u043A * \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435\u041F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043A\u0430 / 100.",
|
|
EASY_BONUS: "\u041B\u0435\u0433\u043A\u043E: \u0431\u043E\u043D\u0443\u0441",
|
|
EASY_BONUS_DESC: "\u0411\u043E\u043D\u0443\u0441 \u0437\u0430 \u041B\u0435\u0433\u043A\u043E \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0432\u0430\u043C \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0440\u0430\u0437\u043D\u0438\u0446\u0443 \u0432 \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043A\u0430\u0445 \u043C\u0435\u0436\u0434\u0443 \u043E\u0442\u0432\u0435\u0442\u0430\u043C\u0438 \u0425\u043E\u0440\u043E\u0448\u043E \u0438 \u041B\u0435\u0433\u043A\u043E \u043D\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435/\u0437\u0430\u043C\u0435\u0442\u043A\u0435 (\u043C\u0438\u043D. = 100%).",
|
|
EASY_BONUS_MIN_WARNING: '\u0411\u043E\u043D\u0443\u0441 \u0437\u0430 "\u041B\u0435\u0433\u043A\u043E" \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 100.',
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F \u0432 \u0434\u043D\u044F\u0445",
|
|
MAX_INTERVAL_DESC: "\u041F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0432\u0430\u043C \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0442\u044C \u0432\u0435\u0440\u0445\u043D\u044E\u044E \u0433\u0440\u0430\u043D\u0438\u0446\u0443 \u043D\u0430 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E = 100 \u043B\u0435\u0442).",
|
|
MAX_INTERVAL_MIN_WARNING: "\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u0432\u0430\u043B \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 1.",
|
|
MAX_LINK_CONTRIB: "\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0432\u043A\u043B\u0430\u0434 \u0441\u0432\u044F\u0437\u0438 (\u0441\u0441\u044B\u043B\u043A\u0438)",
|
|
MAX_LINK_CONTRIB_DESC: '\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0432\u043A\u043B\u0430\u0434 \u0441\u0440\u0435\u0434\u043D\u0435\u0433\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F "\u041B\u0451\u0433\u043A\u043E\u0441\u0442\u0438" \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0445 \u0437\u0430\u043C\u0435\u0442\u043E\u043A \u0432 \u043D\u0430\u0447\u0430\u043B\u044C\u043D\u0443\u044E "\u041B\u0451\u0433\u043A\u043E\u0441\u0442\u044C".',
|
|
LOGGING: "\u0416\u0443\u0440\u043D\u0430\u043B\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C \u043E\u0442\u043B\u0430\u0434\u043E\u0447\u043D\u0443\u044E \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u0430",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u0437\u0430\u043C\u0435\u0442\u043E\u043A \u043D\u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u0435",
|
|
CLOSE: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
|
|
NEW: "\u041D\u043E\u0432\u044B\u0435",
|
|
YESTERDAY: "\u0412\u0447\u0435\u0440\u0430\u0448\u043D\u0438\u0435",
|
|
TODAY: "\u0421\u0435\u0433\u043E\u0434\u043D\u044F\u0448\u043D\u0438\u0435",
|
|
TOMORROW: "\u0417\u0430\u0432\u0442\u0440\u0430\u0448\u043D\u0438\u0435",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430",
|
|
MONTH: "\u041C\u0435\u0441\u044F\u0446",
|
|
QUARTER: "\u041A\u0432\u0430\u0440\u0442\u0430\u043B",
|
|
YEAR: "\u0413\u043E\u0434",
|
|
LIFETIME: "\u0412\u0441\u0451 \u0432\u0440\u0435\u043C\u044F",
|
|
FORECAST: "\u041F\u0440\u043E\u0433\u043D\u043E\u0437",
|
|
FORECAST_DESC: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A \u043F\u0440\u0435\u0434\u0441\u0442\u043E\u044F\u0449\u0438\u0445 \u0434\u043B\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F",
|
|
SCHEDULED: "\u0417\u0430\u043F\u043B\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u043E",
|
|
DAYS: "\u0414\u043D\u0438",
|
|
NUMBER_OF_CARDS: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
REVIEWS_PER_DAY: "\u0421\u0440\u0435\u0434\u043D\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E: ${avg} \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u0439 \u0432 \u0434\u0435\u043D\u044C",
|
|
INTERVALS: "\u0418\u043D\u0442\u0435\u0440\u0432\u0430\u043B\u044B",
|
|
INTERVALS_DESC: "\u041F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043A\u0438 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0434\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0433\u043E \u043F\u043E\u043A\u0430\u0437\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F",
|
|
COUNT: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E",
|
|
INTERVALS_SUMMARY: "\u0421\u0440\u0435\u0434\u043D\u0438\u0439 \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u043A: ${avg}, \u0421\u0430\u043C\u044B\u0439 \u0434\u043B\u0438\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u043A: ${longest}",
|
|
EASES: "\u041F\u0440\u043E\u0433\u0440\u0435\u0441\u0441 \u0438\u0437\u0443\u0447\u0435\u043D\u0438\u044F",
|
|
EASES_SUMMARY: "\u0421\u0440\u0435\u0434\u043D\u0435\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441\u0430: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\u0422\u0438\u043F\u044B \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A",
|
|
CARD_TYPES_DESC: "\u0412\u043A\u043B\u044E\u0447\u0430\u044F \u0441\u043F\u0440\u044F\u0442\u0430\u043D\u043D\u044B\u0435 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438, \u0435\u0441\u043B\u0438 \u0442\u0430\u043A\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0442.",
|
|
CARD_TYPE_NEW: "\u041D\u043E\u0432\u044B\u0445",
|
|
CARD_TYPE_YOUNG: "\u041F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u043C\u044B\u0445",
|
|
CARD_TYPE_MATURE: "\u0418\u0437\u0443\u0447\u0435\u043D\u043D\u044B\u0445",
|
|
CARD_TYPES_SUMMARY: "\u0412\u0441\u0435\u0433\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/sw.ts
|
|
var sw_default = {};
|
|
|
|
// src/lang/locale/ta.ts
|
|
var ta_default = {};
|
|
|
|
// src/lang/locale/te.ts
|
|
var te_default = {};
|
|
|
|
// src/lang/locale/th.ts
|
|
var th_default = {};
|
|
|
|
// src/lang/locale/tr.ts
|
|
var tr_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "Desteler",
|
|
DUE_CARDS: "G\xFCncel Kartlar",
|
|
NEW_CARDS: "Yeni Kartlar",
|
|
TOTAL_CARDS: "Toplam Kartlar",
|
|
BACK: "Geri",
|
|
SKIP: "Atla",
|
|
EDIT_CARD: "Kart\u0131 D\xFCzenle",
|
|
RESET_CARD_PROGRESS: "Kart\u0131n ilerlemesini s\u0131f\u0131rla",
|
|
HARD: "Zor",
|
|
GOOD: "Orta",
|
|
EASY: "Kolay",
|
|
SHOW_ANSWER: "Cevab\u0131 G\xF6ster",
|
|
CARD_PROGRESS_RESET: "Kart\u0131n ilerlemesi s\u0131f\u0131rland\u0131.",
|
|
SAVE: "Kaydet",
|
|
CANCEL: "\u0130ptal",
|
|
NO_INPUT: "Girdi sa\u011Flanmad\u0131.",
|
|
CURRENT_EASE_HELP_TEXT: "Mevcut Kolayl\u0131k: ",
|
|
CURRENT_INTERVAL_HELP_TEXT: "Mevcut Aral\u0131k: ",
|
|
CARD_GENERATED_FROM: "${notePath} kayna\u011F\u0131ndan olu\u015Fturuldu.",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "G\xF6zden ge\xE7irmek i\xE7in bir not a\xE7",
|
|
REVIEW_CARDS: "Flash kartlar\u0131 g\xF6zden ge\xE7ir",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "G\xF6zden Ge\xE7ir: ${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "Notu ${difficulty} derecesiyle g\xF6zden ge\xE7ir",
|
|
CRAM_ALL_CARDS: "T\xFCm destelerden yo\u011Fun tekrar yap",
|
|
REVIEW_ALL_CARDS: "T\xFCm notlardaki flash kartlar\u0131 g\xF6zden ge\xE7ir",
|
|
REVIEW_CARDS_IN_NOTE: "Bu nottaki flash kartlar\u0131 g\xF6zden ge\xE7ir",
|
|
CRAM_CARDS_IN_NOTE: "Bu nottaki flash kartlar\u0131 yo\u011Fun tekrar yap",
|
|
VIEW_STATS: "\u0130statistikleri g\xF6r\xFCnt\xFCle",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Kenar \xE7ubu\u011Funda Not G\xF6zden Ge\xE7irme S\u0131ras\u0131n\u0131 a\xE7",
|
|
STATUS_BAR: "G\xF6zden Ge\xE7ir: ${dueNotesCount} not, ${dueFlashcardsCount} kart g\xFCncel",
|
|
SYNC_TIME_TAKEN: "Senkronizasyon ${t}ms s\xFCrd\xFC",
|
|
NOTE_IN_IGNORED_FOLDER: "Not, d\u0131\u015Flanan klas\xF6rde kay\u0131tl\u0131 (ayarlar\u0131 kontrol edin).",
|
|
PLEASE_TAG_NOTE: "L\xFCtfen g\xF6zden ge\xE7irmek i\xE7in notu uygun \u015Fekilde etiketleyin (ayarlar i\xE7inde).",
|
|
RESPONSE_RECEIVED: "Yan\u0131t al\u0131nd\u0131.",
|
|
NO_DECK_EXISTS: "${deckName} ad\u0131nda bir deste yok",
|
|
ALL_CAUGHT_UP: "\u{1F3C6} \u015Eampiyon gibi bitirdin! \u{1F604}",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval} g\xFCn",
|
|
MONTHS_STR_IVL: "${interval} ay",
|
|
YEARS_STR_IVL: "${interval} y\u0131l",
|
|
DAYS_STR_IVL_MOBILE: "${interval}g",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}a",
|
|
YEARS_STR_IVL_MOBILE: "${interval}y",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "Aral\u0131kl\u0131 Tekrar",
|
|
GROUP_TAGS_FOLDERS: "Etiketler ve Klas\xF6rler",
|
|
GROUP_FLASHCARD_REVIEW: "Flash Kartlar\u0131 G\xF6zden Ge\xE7irme",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flash Kart Ay\u0131r\u0131c\u0131lar\u0131",
|
|
GROUP_DATA_STORAGE: "Planlama Verilerinin Saklanmas\u0131",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flash Kartlar ve Notlar",
|
|
GROUP_CONTRIBUTING: "Katk\u0131da Bulunma",
|
|
CHECK_WIKI: 'Daha fazla bilgi i\xE7in <a href="${wikiUrl}">wiki</a> sayfas\u0131na g\xF6z at\u0131n.',
|
|
GITHUB_DISCUSSIONS: 'Soru-cevap, geri bildirim ve genel tart\u0131\u015Fmalar i\xE7in <a href="${discussionsUrl}">tart\u0131\u015Fmalar</a> b\xF6l\xFCm\xFCne g\xF6z at\u0131n.',
|
|
GITHUB_ISSUES: 'Bir \xF6zellik iste\u011Finiz ya da hata bildiriminiz varsa <a href="${issuesUrl}">buradan</a> bildirin.',
|
|
GITHUB_SOURCE_CODE: 'Proje kaynak koduna <a href="${githubProjectUrl}">GitHub</a> \xFCzerinden ula\u015Fabilirsiniz.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Kod katk\u0131lar\u0131</a> hakk\u0131nda bilgi al\u0131n.',
|
|
TRANSLATION_CONTRIBUTION_INFO: 'Eklentiyi kendi dilinize \xE7evirmek hakk\u0131nda bilgi i\xE7in <a href="${translationContributionUrl}">\xE7eviri katk\u0131lar\u0131</a> sayfas\u0131n\u0131 ziyaret edin.',
|
|
FOLDERS_TO_IGNORE: "Yoksay\u0131lan Klas\xF6rler",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "Flash Kartlar",
|
|
FLASHCARD_EASY_LABEL: "Kolay Butonu Metni",
|
|
FLASHCARD_GOOD_LABEL: "Orta Butonu Metni",
|
|
FLASHCARD_HARD_LABEL: "Zor Butonu Metni",
|
|
FLASHCARD_EASY_DESC: '"Kolay" butonunun metnini \xF6zelle\u015Ftirin',
|
|
FLASHCARD_GOOD_DESC: '"Orta" butonunun metnini \xF6zelle\u015Ftirin',
|
|
FLASHCARD_HARD_DESC: '"Zor" butonunun metnini \xF6zelle\u015Ftirin',
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "Flash Kart Etiketleri",
|
|
FLASHCARD_TAGS_DESC: "Etiketleri bo\u015Fluklar veya yeni sat\u0131rlarla ay\u0131rarak girin, \xF6rne\u011Fin: #flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "Klas\xF6rleri destelere ve alt destelere d\xF6n\xFC\u015Ft\xFCr?",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "Bu, yukar\u0131daki Flash Kart etiketleri se\xE7ene\u011Fine bir alternatiftir.",
|
|
INLINE_SCHEDULING_COMMENTS: "Planlama yorumunu flash kart\u0131n son sat\u0131r\u0131yla ayn\u0131 sat\u0131ra kaydet?",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "Bunu a\xE7mak, HTML yorumlar\u0131n\u0131n liste bi\xE7imlendirmesini bozmamas\u0131n\u0131 sa\u011Flar.",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "Karde\u015F kartlar\u0131 bir sonraki g\xFCne kadar gizle?",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "Karde\u015F kartlar, ayn\u0131 kart metninden \xFCretilen kartlard\u0131r (\xF6rne\u011Fin gizlemeler).",
|
|
SHOW_CARD_CONTEXT: "Kartlarda ba\u011Flam\u0131 g\xF6ster?",
|
|
SHOW_CARD_CONTEXT_DESC: "\xD6rne\u011Fin: Ba\u015Fl\u0131k > Ba\u015Fl\u0131k 1 > Alt Ba\u015Fl\u0131k > ... > Alt Ba\u015Fl\u0131k",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "Flash Kart Y\xFCkseklik Y\xFCzdesi",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "Mobilde veya \xE7ok b\xFCy\xFCk resimleriniz varsa %100 olarak ayarlay\u0131n.",
|
|
RESET_DEFAULT: "Varsay\u0131lana s\u0131f\u0131rla",
|
|
CARD_MODAL_WIDTH_PERCENT: "Flash Kart Geni\u015Flik Y\xFCzdesi",
|
|
RANDOMIZE_CARD_ORDER: "\u0130nceleme s\u0131ras\u0131nda kart s\u0131ras\u0131n\u0131 rastgele yap?",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "\u0130nceleme s\u0131ras\u0131nda bir destede kartlar\u0131n g\xF6r\xFCnt\xFClenme s\u0131ras\u0131",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "S\u0131ral\u0131 olarak (\xF6nce t\xFCm yeni kartlar)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "S\u0131ral\u0131 olarak (\xF6nce t\xFCm g\xFCncel kartlar)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "Rastgele olarak (\xF6nce t\xFCm yeni kartlar)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "Rastgele olarak (\xF6nce t\xFCm g\xFCncel kartlar)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "Rastgele desteden rastgele kart",
|
|
REVIEW_DECK_ORDER: "\u0130nceleme s\u0131ras\u0131nda destelerin g\xF6r\xFCnt\xFClenme s\u0131ras\u0131",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "S\u0131ral\u0131 olarak (\xD6nceki destedeki t\xFCm kartlar g\xF6zden ge\xE7irildikten sonra)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "Rastgele olarak (\xD6nceki destedeki t\xFCm kartlar g\xF6zden ge\xE7irildikten sonra)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "Rastgele desteden rastgele kart",
|
|
DISABLE_CLOZE_CARDS: "Gizli kartlar\u0131 devre d\u0131\u015F\u0131 b\u0131rak?",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "==Vurgulanan== metni gizli kartlara d\xF6n\xFC\u015Ft\xFCr?",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "**Kal\u0131n metni** gizli kartlara d\xF6n\xFC\u015Ft\xFCr?",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "{{K\u0131v\u0131rc\u0131k parantezleri}} gizli kartlara d\xF6n\xFC\u015Ft\xFCr?",
|
|
CLOZE_PATTERNS: "Cloze Patterns",
|
|
CLOZE_PATTERNS_DESC: 'Enter cloze patterns separated by newlines. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "Sat\u0131r i\xE7i flash kartlar i\xE7in ay\u0131r\u0131c\u0131",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "Bunu de\u011Fi\u015Ftirdikten sonra mevcut flash kartlar\u0131n\u0131z\u0131 manuel olarak d\xFCzenlemeniz gerekti\u011Fini unutmay\u0131n.",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "Sat\u0131r i\xE7i ters flash kartlar i\xE7in ay\u0131r\u0131c\u0131",
|
|
MULTILINE_CARDS_SEPARATOR: "\xC7ok sat\u0131rl\u0131 flash kartlar i\xE7in ay\u0131r\u0131c\u0131",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\xC7ok sat\u0131rl\u0131 ters flash kartlar i\xE7in ay\u0131r\u0131c\u0131",
|
|
MULTILINE_CARDS_END_MARKER: "Gizli kartlar ve \xE7ok sat\u0131rl\u0131 flash kartlar\u0131n sonunu belirten karakterler",
|
|
NOTES: "Notlar",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "Ba\u015Flang\u0131\xE7ta not inceleme panelini etkinle\u015Ftir",
|
|
TAGS_TO_REVIEW: "G\xF6zden ge\xE7irilecek etiketler",
|
|
TAGS_TO_REVIEW_DESC: "Etiketleri bo\u015Fluklar veya yeni sat\u0131rlarla ay\u0131rarak girin, \xF6rne\u011Fin: #review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "G\xF6zden ge\xE7irmek i\xE7in rastgele bir not a\xE7",
|
|
OPEN_RANDOM_NOTE_DESC: "Bunu kapatt\u0131\u011F\u0131n\u0131zda, notlar \xF6nem s\u0131ras\u0131na g\xF6re s\u0131ralan\u0131r (PageRank).",
|
|
AUTO_NEXT_NOTE: "Bir incelemeden sonra otomatik olarak bir sonraki notu a\xE7",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "Sa\u011F panelde g\xF6sterilecek maksimum g\xFCn say\u0131s\u0131",
|
|
MIN_ONE_DAY: "G\xFCn say\u0131s\u0131 en az 1 olmal\u0131d\u0131r.",
|
|
VALID_NUMBER_WARNING: "L\xFCtfen ge\xE7erli bir say\u0131 girin.",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "Enable the review options in the file menu (e.g. Review: Easy, Good, Hard)",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "If you disable the review options in the file menu, you can review your notes using the plugin commands and, if you defined them, the associated command hotkeys.",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "Deste a\u011Fa\xE7lar\u0131 ba\u015Flang\u0131\xE7ta geni\u015Fletilmi\u015F olarak g\xF6sterilmeli mi",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "Bunu kapat\u0131n, ayn\u0131 dosyada bir\xE7ok desteye ait kartlar\u0131n\u0131z varsa i\xE7 i\xE7e desteleri daraltmak i\xE7in kullan\u0131\u015Fl\u0131d\u0131r.",
|
|
ALGORITHM: "Algoritma",
|
|
CHECK_ALGORITHM_WIKI: 'Daha fazla bilgi i\xE7in <a href="${algoUrl}">algoritma uygulamas\u0131na</a> g\xF6z at\u0131n.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "Temel kolayl\u0131k",
|
|
BASE_EASE_DESC: "minimum = 130, tercihen yakla\u015F\u0131k 250.",
|
|
BASE_EASE_MIN_WARNING: "Temel kolayl\u0131k en az 130 olmal\u0131d\u0131r.",
|
|
LAPSE_INTERVAL_CHANGE: "Bir flash kart\u0131/notu zor olarak inceledi\u011Finizde aral\u0131k de\u011Fi\u015Fikli\u011Fi",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "yeniAral\u0131k = eskiAral\u0131k * aral\u0131kDe\u011Fi\u015Fikli\u011Fi / 100.",
|
|
EASY_BONUS: "Kolayl\u0131k Bonusu",
|
|
EASY_BONUS_DESC: "Kolayl\u0131k bonusu, bir flash kart\u0131/notu \u0130yi ve Kolay yan\u0131tlad\u0131\u011F\u0131n\u0131zda aral\u0131klardaki fark\u0131 ayarlaman\u0131za olanak tan\u0131r (minimum = %100).",
|
|
EASY_BONUS_MIN_WARNING: "Kolayl\u0131k bonusu en az %100 olmal\u0131d\u0131r.",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "Maksimum aral\u0131k (g\xFCn)",
|
|
MAX_INTERVAL_DESC: "Aral\u0131\u011Fa bir \xFCst s\u0131n\u0131r koyman\u0131za olanak tan\u0131r (varsay\u0131lan = 100 y\u0131l).",
|
|
MAX_INTERVAL_MIN_WARNING: "Maksimum aral\u0131k en az 1 g\xFCn olmal\u0131d\u0131r.",
|
|
MAX_LINK_CONTRIB: "Maksimum ba\u011Flant\u0131 katk\u0131s\u0131",
|
|
MAX_LINK_CONTRIB_DESC: "Ba\u011Flant\u0131l\u0131 notlar\u0131n a\u011F\u0131rl\u0131kl\u0131 kolayl\u0131k de\u011Ferinin ba\u015Flang\u0131\xE7 kolayl\u0131\u011F\u0131na maksimum katk\u0131s\u0131.",
|
|
LOGGING: "Kay\u0131t tutma",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "Geli\u015Ftirici konsolunda hata ay\u0131klama bilgilerini g\xF6ster",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Ayr\u0131\u015Ft\u0131r\u0131c\u0131 i\xE7in hata ay\u0131klama bilgilerini geli\u015Ftirici konsolunda g\xF6ster",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "Not \u0130nceleme S\u0131ras\u0131",
|
|
CLOSE: "Kapat",
|
|
NEW: "Yeni",
|
|
YESTERDAY: "D\xFCn",
|
|
TODAY: "Bug\xFCn",
|
|
TOMORROW: "Yar\u0131n",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u0130statistikler",
|
|
MONTH: "Ay",
|
|
QUARTER: "\xC7eyrek",
|
|
YEAR: "Y\u0131l",
|
|
LIFETIME: "\xD6m\xFCr Boyu",
|
|
FORECAST: "Tahmin",
|
|
FORECAST_DESC: "Gelecekte incelemeye al\u0131nacak kartlar\u0131n say\u0131s\u0131",
|
|
SCHEDULED: "Planlanm\u0131\u015F",
|
|
DAYS: "G\xFCnler",
|
|
NUMBER_OF_CARDS: "Kart Say\u0131s\u0131",
|
|
REVIEWS_PER_DAY: "Ortalama: ${avg} inceleme/g\xFCn",
|
|
INTERVALS: "Aral\u0131klar",
|
|
INTERVALS_DESC: "\u0130ncelemelerin tekrar g\xF6sterilme gecikmeleri",
|
|
COUNT: "Say\u0131",
|
|
INTERVALS_SUMMARY: "Ortalama aral\u0131k: ${avg}, En uzun aral\u0131k: ${longest}",
|
|
EASES: "Kolayl\u0131klar",
|
|
EASES_SUMMARY: "Ortalama kolayl\u0131k: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "Kart T\xFCrleri",
|
|
CARD_TYPES_DESC: "Bu, g\xF6m\xFCl\xFC kartlar\u0131 da i\xE7erir (varsa)",
|
|
CARD_TYPE_NEW: "Yeni",
|
|
CARD_TYPE_YOUNG: "Gen\xE7",
|
|
CARD_TYPE_MATURE: "Olgun",
|
|
CARD_TYPES_SUMMARY: "Toplam kart: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/uk.ts
|
|
var uk_default = {};
|
|
|
|
// src/lang/locale/ur.ts
|
|
var ur_default = {};
|
|
|
|
// src/lang/locale/vi.ts
|
|
var vi_default = {};
|
|
|
|
// src/lang/locale/zh-cn.ts
|
|
var zh_cn_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\u5361\u7EC4",
|
|
DUE_CARDS: "\u5230\u671F\u5361\u7247",
|
|
NEW_CARDS: "\u65B0\u5361\u7247",
|
|
TOTAL_CARDS: "\u5168\u90E8\u5361\u7247",
|
|
BACK: "\u8FD4\u56DE",
|
|
SKIP: "\u7565\u8FC7",
|
|
EDIT_CARD: "\u7F16\u8F91\u5361\u7247",
|
|
RESET_CARD_PROGRESS: "\u91CD\u7F6E\u5361\u7247",
|
|
HARD: "\u8F83\u96BE",
|
|
GOOD: "\u8BB0\u5F97",
|
|
EASY: "\u7B80\u5355",
|
|
SHOW_ANSWER: "\u663E\u793A\u7B54\u6848",
|
|
CARD_PROGRESS_RESET: "\u5361\u7247\u5DF2\u88AB\u91CD\u7F6E\u3002",
|
|
SAVE: "\u50A8\u5B58",
|
|
CANCEL: "\u53D6\u6D88",
|
|
NO_INPUT: "\u6CA1\u6709\u63D0\u4F9B\u8F93\u5165\u3002",
|
|
CURRENT_EASE_HELP_TEXT: "\u76EE\u524D\u638C\u63E1\u7A0B\u5EA6\uFF1A",
|
|
CURRENT_INTERVAL_HELP_TEXT: "\u76EE\u524D\u95F4\u9694\uFF1A",
|
|
CARD_GENERATED_FROM: "\u751F\u6210\u81EA\uFF1A${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\u6253\u5F00\u4E00\u4E2A\u7B14\u8BB0\u5F00\u59CB\u590D\u4E60",
|
|
REVIEW_CARDS: "\u590D\u4E60\u5361\u7247",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "\u590D\u4E60\uFF1A${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "\u6807\u8BB0\u4E3A\u201C${difficulty}\u201D",
|
|
REVIEW_ALL_CARDS: "\u590D\u4E60\u6240\u6709\u7B14\u8BB0\u4E2D\u7684\u5361\u7247",
|
|
CRAM_ALL_CARDS: "\u9009\u62E9\u8981\u96C6\u4E2D\u590D\u4E60\u7684\u5361\u7EC4",
|
|
REVIEW_CARDS_IN_NOTE: "\u590D\u4E60\u6B64\u7B14\u8BB0\u4E2D\u7684\u5361\u7247",
|
|
CRAM_CARDS_IN_NOTE: "\u96C6\u4E2D\u590D\u4E60\u6B64\u7B14\u8BB0\u4E2D\u7684\u5361\u7247",
|
|
VIEW_STATS: "\u67E5\u770B\u6570\u636E",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "\u590D\u4E60: ${dueNotesCount} \u7B14\u8BB0, ${dueFlashcardsCount} \u5361\u7247\u5DF2\u5230\u671F",
|
|
SYNC_TIME_TAKEN: "\u540C\u6B65\u65F6\u95F4 ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "\u7B14\u8BB0\u4FDD\u5B58\u5728\u5DF2\u88AB\u5FFD\u7565\u7684\u8DEF\u5F84\u4E2D\uFF08\u68C0\u67E5\u8BBE\u7F6E\u9009\u9879\uFF09\u3002",
|
|
PLEASE_TAG_NOTE: "\u8BF7\u5C06\u9700\u8981\u590D\u4E60\u7684\u7B14\u8BB0\u4E2D\u52A0\u5165\u6B63\u786E\u7684\u6807\u7B7E\uFF08\u68C0\u67E5\u8BBE\u7F6E\u9009\u9879\uFF09\u3002",
|
|
RESPONSE_RECEIVED: "\u53CD\u9988\u5DF2\u6536\u5230",
|
|
NO_DECK_EXISTS: "\u6CA1\u6709 ${deckName} \u5361\u7EC4",
|
|
ALL_CAUGHT_UP: "\u90FD\u590D\u4E60\u5B8C\u5566\uFF0C\u4F60\u771F\u68D2\uFF01",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval}\u5929",
|
|
MONTHS_STR_IVL: "${interval}\u6708",
|
|
YEARS_STR_IVL: "${interval}\u5E74",
|
|
DAYS_STR_IVL_MOBILE: "${interval}\u5929",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}\u6708",
|
|
YEARS_STR_IVL_MOBILE: "${interval}\u5E74",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "\u95F4\u9694\u91CD\u590D\u63D2\u4EF6",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '\u4E86\u89E3\u66F4\u591A, \u8BF7\u70B9\u51FB<a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\u5FFD\u7565\u6B64\u6587\u4EF6\u5939",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\u5361\u7247",
|
|
FLASHCARD_EASY_LABEL: "\u201C\u7B80\u5355\u201D\u6309\u94AE\u6587\u672C",
|
|
FLASHCARD_GOOD_LABEL: "\u201C\u8BB0\u5F97\u201D\u6309\u94AE\u6587\u672C",
|
|
FLASHCARD_HARD_LABEL: "\u201C\u8F83\u96BE\u201D\u6309\u94AE\u6587\u672C",
|
|
FLASHCARD_EASY_DESC: "\u81EA\u5B9A\u4E49\u201C\u7B80\u5355\u201D\u6309\u94AE\u7684\u6807\u7B7E",
|
|
FLASHCARD_GOOD_DESC: "\u81EA\u5B9A\u4E49\u201C\u8BB0\u5F97\u201D\u6309\u94AE\u7684\u6807\u7B7E",
|
|
FLASHCARD_HARD_DESC: "\u81EA\u5B9A\u4E49\u201C\u8F83\u96BE\u201D\u6309\u94AE\u7684\u6807\u7B7E",
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\u5361\u7247\u6807\u7B7E",
|
|
FLASHCARD_TAGS_DESC: "\u8F93\u5165\u6807\u7B7E\uFF0C\u7528\u7A7A\u683C\u6216\u65B0\u5EFA\u884C\u5206\u9694\uFF0C\u4F8B\u5982\uFF1A#flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "\u662F\u5426\u5C06\u6587\u4EF6\u5939\u5185\u5BB9\u8F6C\u6362\u4E3A\u5361\u7247\u7EC4\u548C\u5B50\u5361\u7247\u7EC4\uFF1F",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "\u6B64\u9009\u9879\u4E3A\u5361\u7247\u6807\u7B7E\u9009\u9879\u7684\u66FF\u4EE3\u9009\u9879\u3002",
|
|
INLINE_SCHEDULING_COMMENTS: "\u662F\u5426\u5C06\u8BA1\u5212\u91CD\u590D\u65F6\u95F4\u4FDD\u5B58\u5728\u5361\u7247\u6700\u540E\u4E00\u884C\u7684\u540C\u4E00\u884C\uFF1F",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "HTML\u6CE8\u91CA\u4E0D\u518D\u7834\u574F\u5217\u8868\u683C\u5F0F",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\u5C06\u5173\u8054\u5361\u7247\u9690\u85CF\u81F3\u4E0B\u4E00\u5929\uFF1F",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "\u5173\u8054\u5361\u7247\u662F\u6765\u81EA\u540C\u4E00\u5361\u7247\u7684\u4E0D\u540C\u5F62\u5F0F\uFF0C \u4F8B\u5982\uFF1A\u5B8C\u5F62\u586B\u7A7A\u5361\u7247",
|
|
SHOW_CARD_CONTEXT: "\u5728\u5361\u7247\u4E2D\u663E\u793A\u4E0A\u4E0B\u6587\uFF1F",
|
|
SHOW_CARD_CONTEXT_DESC: "\u4F8B\u5982\uFF1A\u6807\u9898 > \u526F\u6807\u9898 > \u5C0F\u6807\u9898 > ... > \u5C0F\u6807\u9898",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\u5361\u7247\u9AD8\u5EA6\u767E\u5206\u6BD4",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\u8BF7\u5728\u79FB\u52A8\u7AEF\u4F7F\u7528\u5E76\u9700\u8981\u6D4F\u89C8\u8F83\u5927\u56FE\u7247\u65F6\u8BBE\u4E3A100%",
|
|
RESET_DEFAULT: "\u91CD\u7F6E\u4E3A\u9ED8\u8BA4",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u5361\u7247\u5BBD\u5EA6\u767E\u5206\u6BD4",
|
|
RANDOMIZE_CARD_ORDER: "\u590D\u4E60\u65F6\u968F\u673A\u663E\u793A\u5361\u7247\uFF1F",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "\u590D\u4E60\u65F6\u5361\u7247\u7EC4\u5185\u7684\u5361\u7247\u6392\u5E8F",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "\u5361\u7247\u7EC4\u5185\u987A\u5E8F (\u5168\u90E8\u65B0\u5361\u7247\u4F18\u5148)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "\u5361\u7247\u7EC4\u5185\u987A\u5E8F (\u5168\u90E8\u5230\u671F\u5361\u7247\u4F18\u5148)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "\u5361\u7247\u7EC4\u5185\u4E71\u5E8F (\u5168\u90E8\u65B0\u5361\u7247\u4F18\u5148)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "\u5361\u7247\u7EC4\u5185\u4E71\u5E8F (\u5168\u90E8\u5230\u671F\u5361\u7247\u4F18\u5148)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "\u5361\u7247\u7EC4\u53CA\u5361\u7247\u90FD\u4E71\u5E8F",
|
|
REVIEW_DECK_ORDER: "\u590D\u4E60\u65F6\u5361\u7247\u7EC4\u7684\u6392\u5E8F",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "\u987A\u5E8F (\u5728\u524D\u4E00\u5361\u7247\u7EC4\u5185\u5361\u7247\u90FD\u590D\u4E60\u5B8C\u540E)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "\u4E71\u5E8F (\u5728\u524D\u4E00\u5361\u7247\u7EC4\u5185\u5361\u7247\u90FD\u590D\u4E60\u5B8C\u540E)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "\u5361\u7247\u7EC4\u53CA\u5361\u7247\u90FD\u4E71\u5E8F",
|
|
DISABLE_CLOZE_CARDS: "\u4E0D\u8FDB\u884C\u5B8C\u5F62\u586B\u7A7A\uFF1F",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "\u5C06 ==\u9AD8\u4EAE== \u8F6C\u6362\u4E3A\u5B8C\u5F62\u586B\u7A7A\uFF1F",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "\u5C06 **\u7C97\u4F53** \u8F6C\u6362\u4E3A\u5B8C\u5F62\u586B\u7A7A\uFF1F",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "\u5C06 {{\u5927\u62EC\u53F7}} \u8F6C\u6362\u4E3A\u5B8C\u5F62\u586B\u7A7A\uFF1F",
|
|
CLOZE_PATTERNS: "\u5B8C\u5F62\u586B\u7A7A\u6A21\u5F0F",
|
|
CLOZE_PATTERNS_DESC: '\u8F93\u5165\u4EE5\u6362\u884C\u7B26\u5206\u9694\u7684\u5B8C\u5F62\u586B\u7A7A\u6A21\u5F0F. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\u5355\u884C\u5361\u7247\u7684\u5206\u9694\u7B26",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\u6CE8\u610F\uFF1A\u66F4\u6539\u6B64\u9009\u9879\u540E\u4F60\u5C06\u9700\u8981\u81EA\u884C\u66F4\u6539\u5DF2\u5B58\u5728\u5361\u7247\u7684\u5206\u9694\u7B26\u3002",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\u5355\u884C\u7FFB\u8F6C\u5361\u7247\u7684\u5206\u9694\u7B26",
|
|
MULTILINE_CARDS_SEPARATOR: "\u591A\u884C\u5361\u7247\u7684\u5206\u9694\u7B26",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\u591A\u884C\u7FFB\u8F6C\u5361\u7247\u7684\u5206\u9694\u7B26",
|
|
MULTILINE_CARDS_END_MARKER: "\u8868\u793A\u586B\u7A7A\u548C\u591A\u884C\u95EA\u5361\u7ED3\u675F\u7684\u5B57\u7B26",
|
|
NOTES: "\u7B14\u8BB0",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "\u542F\u52A8\u65F6\u5F00\u542F\u7B14\u8BB0\u590D\u4E60\u7A97\u683C",
|
|
TAGS_TO_REVIEW: "\u590D\u4E60\u6807\u7B7E",
|
|
TAGS_TO_REVIEW_DESC: "\u8F93\u5165\u6807\u7B7E\uFF0C\u7528\u7A7A\u683C\u6216\u65B0\u5EFA\u884C\u5206\u9694\uFF0C\u4F8B\u5982\uFF1A#review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "\u590D\u4E60\u968F\u673A\u7B14\u8BB0",
|
|
OPEN_RANDOM_NOTE_DESC: "\u5173\u95ED\u6B64\u9009\u9879\uFF0C\u7B14\u8BB0\u5C06\u4EE5\u91CD\u8981\u5EA6(PageRank)\u6392\u5E8F\u3002",
|
|
AUTO_NEXT_NOTE: "\u590D\u4E60\u540E\u81EA\u52A8\u6253\u5F00\u4E0B\u4E00\u4E2A\u7B14\u8BB0",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\u8BF7\u5728\u6587\u4EF6\u83DC\u5355\u4E2D\u542F\u7528\u590D\u4E60\u9009\u9879\uFF08\u4F8B\u5982\uFF1A\u590D\u4E60\uFF1A\u7B80\u5355\u3001\u826F\u597D\u3001\u56F0\u96BE",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\u5982\u679C\u60A8\u5728\u6587\u4EF6\u83DC\u5355\u4E2D\u7981\u7528\u590D\u4E60\u9009\u9879\uFF0C\u60A8\u53EF\u4EE5\u4F7F\u7528\u63D2\u4EF6\u547D\u4EE4\u6765\u590D\u4E60\u7B14\u8BB0\uFF0C\u5982\u679C\u60A8\u5B9A\u4E49\u4E86\u76F8\u5173\u5FEB\u6377\u952E\uFF0C\u4E5F\u53EF\u4EE5\u4F7F\u7528\u5B83\u4EEC\u3002",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\u53F3\u8FB9\u680F\u4E2D\u663E\u793A\u7684\u6700\u5927\u5929\u6570",
|
|
MIN_ONE_DAY: "\u5929\u6570\u6700\u5C0F\u503C\u4E3A1",
|
|
VALID_NUMBER_WARNING: "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57\u3002",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\u7532\u677F\u6811\u6700\u521D\u5E94\u663E\u793A\u4E3A\u5C55\u5F00",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "\u5173\u95ED\u6B64\u9009\u9879\u53EF\u6298\u53E0\u540C\u4E00\u5F20\u5361\u7247\u4E2D\u7684\u5D4C\u5957\u724C\u7EC4\u3002\u5982\u679C\u60A8\u7684\u5361\u7247\u5C5E\u4E8E\u540C\u4E00\u6587\u4EF6\u4E2D\u7684\u8BB8\u591A\u5957\u724C\uFF0C\u5219\u5F88\u6709\u7528\u3002",
|
|
ALGORITHM: "\u7B97\u6CD5",
|
|
CHECK_ALGORITHM_WIKI: '\u4E86\u89E3\u66F4\u591A, \u8BF7\u70B9\u51FB<a href="${algoUrl}">\u7B97\u6CD5\u5B9E\u73B0</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\u57FA\u7840\u638C\u63E1\u7A0B\u5EA6",
|
|
BASE_EASE_DESC: "\u6700\u5C0F\u503C130\uFF0C\u63A8\u8350\u503C\u7EA6250.",
|
|
BASE_EASE_MIN_WARNING: "\u57FA\u7840\u638C\u63E1\u7A0B\u5EA6\u7684\u6700\u5C0F\u503C\u4E3A130\u3002",
|
|
LAPSE_INTERVAL_CHANGE: "\u5C06\u590D\u4E60\u65F6\u6807\u6CE8\u4E3A\u201C\u8F83\u96BE\u201D\u7684\u5361\u7247\u6216\u7B14\u8BB0\u590D\u4E60\u95F4\u9694\u7F29\u77ED",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "\u65B0\u590D\u4E60\u95F4\u9694 = \u539F\u590D\u4E60\u95F4\u9694 * \u95F4\u9694\u6539\u53D8\u7CFB\u6570 / 100.",
|
|
EASY_BONUS: "\u7B80\u5355\u5956\u52B1",
|
|
EASY_BONUS_DESC: "\u7B80\u5355\u5956\u52B1\u8BBE\u5B9A\u201C\u8BB0\u5F97\u201D\u548C\u201C\u7B80\u5355\u201D\u5361\u7247\u6216\u7B14\u8BB0\u7684\u590D\u4E60\u95F4\u9694\u5DEE\u8DDD\uFF08\u6700\u5C0F\u503C100%\uFF09\u3002",
|
|
EASY_BONUS_MIN_WARNING: "\u7B80\u5355\u5956\u52B1\u81F3\u5C11\u4E3A100\u3002",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "\u6700\u5927\u95F4\u9694\uFF08\u5929\uFF09",
|
|
MAX_INTERVAL_DESC: "\u8BBE\u5B9A\u590D\u4E60\u7684\u6700\u5927\u95F4\u9694\u65F6\u95F4\uFF08\u9ED8\u8BA4\u503C100\u5E74\uFF09\u3002",
|
|
MAX_INTERVAL_MIN_WARNING: "\u6700\u5927\u95F4\u9694\u81F3\u5C11\u4E3A1\u5929",
|
|
MAX_LINK_CONTRIB: "\u6700\u5927\u94FE\u63A5\u6536\u76CA",
|
|
MAX_LINK_CONTRIB_DESC: "\u94FE\u63A5\u7B14\u8BB0\u7684\u52A0\u6743\u638C\u63E1\u7A0B\u5EA6\u5BF9\u539F\u59CB\u638C\u63E1\u7A0B\u5EA6\u7684\u6700\u5927\u8D21\u732E\u3002",
|
|
LOGGING: "\u8BB0\u5F55\u4E2D",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\u5728\u5F00\u53D1\u8005\u63A7\u5236\u53F0\u4E2D\u663E\u793A\u8C03\u8BD5\u4FE1\u606F",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\u7B14\u8BB0\u590D\u4E60\u5E8F\u5217",
|
|
CLOSE: "\u4E34\u8FD1",
|
|
NEW: "\u65B0",
|
|
YESTERDAY: "\u6628\u5929",
|
|
TODAY: "\u4ECA\u5929",
|
|
TOMORROW: "\u660E\u5929",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u6570\u636E",
|
|
MONTH: "\u6708",
|
|
QUARTER: "\u5B63",
|
|
YEAR: "\u5E74",
|
|
LIFETIME: "\u5168\u90E8",
|
|
FORECAST: "\u9884\u671F",
|
|
FORECAST_DESC: "\u5C06\u8981\u5230\u671F\u7684\u5361\u7247\u6570\u91CF",
|
|
SCHEDULED: "\u5DF2\u6392\u671F",
|
|
DAYS: "\u5929",
|
|
NUMBER_OF_CARDS: "\u5361\u7247\u6570\u91CF",
|
|
REVIEWS_PER_DAY: "\u5E73\u5747: \u590D\u4E60${avg} /\u5929",
|
|
INTERVALS: "\u95F4\u9694",
|
|
INTERVALS_DESC: "\u5230\u4E0B\u4E00\u6B21\u590D\u4E60\u7684\u65F6\u95F4\u95F4\u9694",
|
|
COUNT: "\u8BA1\u6570",
|
|
INTERVALS_SUMMARY: "\u5E73\u5747\u95F4\u9694\u65F6\u95F4: ${avg}, \u6700\u957F\u95F4\u9694\u65F6\u95F4: ${longest}",
|
|
EASES: "\u638C\u63E1\u7A0B\u5EA6",
|
|
EASES_SUMMARY: "\u5E73\u5747\u638C\u63E1\u7A0B\u5EA6: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\u5361\u7247\u7C7B\u578B",
|
|
CARD_TYPES_DESC: "\u5982\u6709\uFF0C\u5C06\u663E\u793A\u9690\u85CF\u7684\u5361\u7247",
|
|
CARD_TYPE_NEW: "\u65B0",
|
|
CARD_TYPE_YOUNG: "\u8F83\u65B0",
|
|
CARD_TYPE_MATURE: "\u719F\u6089",
|
|
CARD_TYPES_SUMMARY: "\u603B\u5361\u7247\u6570: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/locale/zh-tw.ts
|
|
var zh_tw_default = {
|
|
// flashcard-modal.tsx
|
|
DECKS: "\u724C\u7D44",
|
|
DUE_CARDS: "\u5230\u671F\u5361\u7247",
|
|
NEW_CARDS: "\u65B0\u5361\u7247",
|
|
TOTAL_CARDS: "\u5168\u90E8\u5361\u7247",
|
|
BACK: "\u8FD4\u56DE",
|
|
SKIP: "\u7565\u904E",
|
|
EDIT_CARD: "\u7DE8\u8F2F\u5361\u7247",
|
|
RESET_CARD_PROGRESS: "\u91CD\u7F6E\u5361\u7247",
|
|
HARD: "\u8F03\u96E3",
|
|
GOOD: "\u8A18\u5F97",
|
|
EASY: "\u7C21\u55AE",
|
|
SHOW_ANSWER: "\u986F\u793A\u7B54\u6848",
|
|
CARD_PROGRESS_RESET: "\u5361\u7247\u5DF2\u88AB\u91CD\u7F6E\u3002",
|
|
SAVE: "\u5132\u5B58",
|
|
CANCEL: "\u53D6\u6D88",
|
|
NO_INPUT: "\u6C92\u6709\u63D0\u4F9B\u8F38\u5165\u3002",
|
|
CURRENT_EASE_HELP_TEXT: "\u76EE\u524D\u638C\u63E1\u7A0B\u5EA6\uFF1A",
|
|
CURRENT_INTERVAL_HELP_TEXT: "\u76EE\u524D\u9593\u9694\u6642\u9593\uFF1A",
|
|
CARD_GENERATED_FROM: "\u751F\u6210\u81EA\uFF1A${notePath}",
|
|
// main.ts
|
|
OPEN_NOTE_FOR_REVIEW: "\u6253\u958B\u4E00\u500B\u7B46\u8A18\u958B\u59CB\u5FA9\u7FD2",
|
|
REVIEW_CARDS: "\u5FA9\u7FD2\u5361\u7247",
|
|
REVIEW_DIFFICULTY_FILE_MENU: "\u5FA9\u7FD2\uFF1A${difficulty}",
|
|
REVIEW_NOTE_DIFFICULTY_CMD: "\u6A19\u8A18\u70BA\u300C${difficulty}\u300D",
|
|
REVIEW_CARDS_IN_NOTE: "\u5FA9\u7FD2\u6B64\u7B46\u8A18\u4E2D\u7684\u5361\u7247",
|
|
CRAM_ALL_CARDS: "\u9078\u64C7\u8981\u4E0D\u8A08\u96E3\u6613\u5EA6\u5FA9\u7FD2\u7684\u724C\u7D44",
|
|
REVIEW_ALL_CARDS: "\u5FA9\u7FD2\u6240\u6709\u7B46\u8A18\u4E2D\u7684\u5361\u7247",
|
|
CRAM_CARDS_IN_NOTE: "\u4E0D\u8A08\u96E3\u6613\u5EA6\u5FA9\u7FD2\u6B64\u7B46\u8A18\u4E2D\u7684\u5361\u7247",
|
|
VIEW_STATS: "\u6AA2\u8996\u6578\u64DA",
|
|
OPEN_REVIEW_QUEUE_VIEW: "Open Notes Review Queue in sidebar",
|
|
STATUS_BAR: "\u5FA9\u7FD2: ${dueNotesCount} \u7B46\u8A18, ${dueFlashcardsCount} \u5361\u7247\u5DF2\u5230\u671F",
|
|
SYNC_TIME_TAKEN: "\u540C\u6B65\u6642\u9593 ${t}ms",
|
|
NOTE_IN_IGNORED_FOLDER: "\u7B46\u8A18\u5132\u5B58\u5728\u5DF2\u88AB\u5FFD\u7565\u7684\u8DEF\u5F91\u4E2D\uFF08\u6AA2\u67E5\u8A2D\u5B9A\u9078\u9805\uFF09\u3002",
|
|
PLEASE_TAG_NOTE: "\u8ACB\u5C07\u9700\u8981\u5FA9\u7FD2\u7684\u7B46\u8A18\u4E2D\u52A0\u5165\u6B63\u78BA\u7684\u6A19\u7C64\uFF08\u6AA2\u67E5\u8A2D\u5B9A\u9078\u9805\uFF09\u3002",
|
|
RESPONSE_RECEIVED: "\u56DE\u994B\u5DF2\u6536\u5230",
|
|
NO_DECK_EXISTS: "\u6C92\u6709 ${deckName} \u724C\u7D44",
|
|
ALL_CAUGHT_UP: "\u90FD\u5FA9\u7FD2\u5B8C\u5566\uFF0C\u4F60\u771F\u68D2\uFF01",
|
|
// scheduling.ts
|
|
DAYS_STR_IVL: "${interval}\u5929",
|
|
MONTHS_STR_IVL: "${interval}\u6708",
|
|
YEARS_STR_IVL: "${interval}\u5E74",
|
|
DAYS_STR_IVL_MOBILE: "${interval}\u5929",
|
|
MONTHS_STR_IVL_MOBILE: "${interval}\u6708",
|
|
YEARS_STR_IVL_MOBILE: "${interval}\u5E74",
|
|
// settings.ts
|
|
SETTINGS_HEADER: "\u9593\u9694\u91CD\u8907\u5916\u639B",
|
|
GROUP_TAGS_FOLDERS: "Tags & Folders",
|
|
GROUP_FLASHCARD_REVIEW: "Flashcard Review",
|
|
GROUP_FLASHCARD_SEPARATORS: "Flashcard Separators",
|
|
GROUP_DATA_STORAGE: "Storage of Scheduling Data",
|
|
GROUP_DATA_STORAGE_DESC: "Choose where to store the scheduling data",
|
|
GROUP_FLASHCARDS_NOTES: "Flashcards & Notes",
|
|
GROUP_CONTRIBUTING: "Contributing",
|
|
CHECK_WIKI: '\u77AD\u89E3\u66F4\u591A, \u8ACB\u9EDE\u9078<a href="${wikiUrl}">wiki</a>.',
|
|
GITHUB_DISCUSSIONS: 'Visit the <a href="${discussionsUrl}">discussions</a> section for Q&A help, feedback, and general discussion.',
|
|
GITHUB_ISSUES: 'Raise an issue <a href="${issuesUrl}">here</a> if you have a feature request or a bug report.',
|
|
GITHUB_SOURCE_CODE: 'The project\'s source code is available on <a href="${githubProjectUrl}">GitHub</a>.',
|
|
CODE_CONTRIBUTION_INFO: '<a href="${codeContributionUrl}">Here\'s</a> how to contribute code to the plugin.',
|
|
TRANSLATION_CONTRIBUTION_INFO: '<a href="${translationContributionUrl}">Here\'s</a> how to translate the plugin to another language.',
|
|
FOLDERS_TO_IGNORE: "\u5FFD\u7565\u6B64\u8CC7\u6599\u593E",
|
|
FOLDERS_TO_IGNORE_DESC: "Enter folder paths or glob patterns on separate lines e.g. Templates/Scripts or **/*.excalidraw.md. This setting is common to both flashcards and notes.",
|
|
OBSIDIAN_INTEGRATION: "Integration into Obsidian",
|
|
FLASHCARDS: "\u5361\u7247",
|
|
FLASHCARD_EASY_LABEL: "\u7C21\u55AE\u6309\u9215\u6587\u5B57",
|
|
FLASHCARD_GOOD_LABEL: "\u8A18\u5F97\u6309\u9215\u6587\u5B57",
|
|
FLASHCARD_HARD_LABEL: "\u8F03\u96E3\u6309\u9215\u6587\u5B57",
|
|
FLASHCARD_EASY_DESC: "\u81EA\u8A02\u300C\u7C21\u55AE\u300D\u6309\u9215\u7684\u6A19\u7C64",
|
|
FLASHCARD_GOOD_DESC: "\u81EA\u8A02\u300C\u8A18\u5F97\u300D\u6309\u9215\u7684\u6A19\u7C64",
|
|
FLASHCARD_HARD_DESC: "\u81EA\u8A02\u300C\u8F03\u96E3\u300D\u6309\u9215\u7684\u6A19\u7C64",
|
|
REVIEW_BUTTON_DELAY: "Button Press Delay (ms)",
|
|
REVIEW_BUTTON_DELAY_DESC: "Add a delay to the review buttons before they can be pressed again.",
|
|
FLASHCARD_TAGS: "\u5361\u7247\u6A19\u7C64",
|
|
FLASHCARD_TAGS_DESC: "\u8F38\u5165\u6A19\u7C64\uFF08\u7528\u7A7A\u767D\u6216\u63DB\u884C\u5B57\u5143\u5206\u9694\uFF09\uFF0C\u4F8B\u5982\uFF1A#flashcards #deck2 #deck3.",
|
|
CONVERT_FOLDERS_TO_DECKS: "\u662F\u5426\u5C07\u8CC7\u6599\u593E\u5167\u5BB9\u8F49\u63DB\u70BA\u724C\u7D44\u548C\u5B50\u724C\u7D44\uFF1F",
|
|
CONVERT_FOLDERS_TO_DECKS_DESC: "\u6B64\u9078\u9805\u70BA\u5361\u7247\u6A19\u7C64\u9078\u9805\u7684\u66FF\u4EE3\u9078\u9805\u3002",
|
|
INLINE_SCHEDULING_COMMENTS: "\u662F\u5426\u5C07\u8A08\u5283\u91CD\u8907\u6642\u9593\u5132\u5B58\u5728\u5361\u7247\u6700\u5F8C\u4E00\u884C\u7684\u540C\u4E00\u884C\uFF1F",
|
|
INLINE_SCHEDULING_COMMENTS_DESC: "\u52FE\u9078\u5F8CHTML\u8A3B\u89E3\u4E0D\u6703\u7834\u58DE\u5217\u8868\u683C\u5F0F\u554F\u984C\u3002",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY: "\u5C07\u53CD\u8F49\u5361\u7247\u96B1\u85CF\u81F3\u4E0B\u4E00\u5929\uFF1F",
|
|
BURY_SIBLINGS_TILL_NEXT_DAY_DESC: "\u53CD\u8F49\u5361\u7247\u7531\u540C\u4E00\u5361\u7247\u6587\u5B57\u7522\u751F\uFF0C\u4F8B\u5982\uFF1A\u586B\u7A7A\u514B\u6F0F\u5B57",
|
|
SHOW_CARD_CONTEXT: "\u5728\u5361\u7247\u4E2D\u986F\u793A\u4E0A\u4E0B\u6587\uFF1F",
|
|
SHOW_CARD_CONTEXT_DESC: "\u4F8B\u5982\uFF1A\u6A19\u984C > \u526F\u6A19\u984C > \u5C0F\u6A19\u984C > ... > \u5C0F\u6A19\u984C",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS: "Show next review time in the review buttons",
|
|
SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC: "Useful to know how far in the future your cards are being pushed.",
|
|
CARD_MODAL_HEIGHT_PERCENT: "\u5361\u7247\u9AD8\u5EA6\u767E\u5206\u6BD4",
|
|
CARD_MODAL_SIZE_PERCENT_DESC: "\u5728\u79FB\u52D5\u7AEF\u6216\u9700\u8981\u8F03\u5927\u5716\u7247\u6642\u61C9\u8A2D\u5B9A\u70BA100%",
|
|
RESET_DEFAULT: "\u91CD\u7F6E\u70BA\u9810\u8A2D\u503C",
|
|
CARD_MODAL_WIDTH_PERCENT: "\u5361\u7247\u5BEC\u5EA6\u767E\u5206\u6BD4",
|
|
RANDOMIZE_CARD_ORDER: "\u5FA9\u7FD2\u6642\u96A8\u6A5F\u986F\u793A\u5361\u7247\uFF1F",
|
|
REVIEW_CARD_ORDER_WITHIN_DECK: "\u5FA9\u7FD2\u6642\u724C\u7D44\u5167\u7684\u5361\u7247\u6392\u5E8F",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL: "\u724C\u7D44\u5167\u9806\u5E8F (\u5168\u90E8\u65B0\u5361\u7247\u512A\u5148)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL: "\u724C\u7D44\u5167\u9806\u5E8F (\u5168\u90E8\u5230\u671F\u5361\u7247\u512A\u5148)",
|
|
REVIEW_CARD_ORDER_NEW_FIRST_RANDOM: "\u724C\u7D44\u5167\u4E82\u5E8F (\u5168\u90E8\u65B0\u5361\u7247\u512A\u5148)",
|
|
REVIEW_CARD_ORDER_DUE_FIRST_RANDOM: "\u724C\u7D44\u5167\u4E82\u5E8F (\u5168\u90E8\u5230\u671F\u5361\u7247\u512A\u5148)",
|
|
REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD: "\u724C\u7D44\u53CA\u5361\u7247\u90FD\u4E82\u5E8F",
|
|
REVIEW_DECK_ORDER: "\u5FA9\u7FD2\u6642\u724C\u7D44\u7684\u6392\u5E8F",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL: "\u9806\u5E8F (\u5728\u524D\u4E00\u724C\u7D44\u5167\u5361\u7247\u90FD\u5FA9\u7FD2\u5B8C\u5F8C)",
|
|
REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM: "\u4E82\u5E8F (\u5728\u524D\u4E00\u724C\u7D44\u5167\u5361\u7247\u90FD\u5FA9\u7FD2\u5B8C\u5F8C)",
|
|
REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD: "\u724C\u7D44\u53CA\u5361\u7247\u90FD\u4E82\u5E8F",
|
|
DISABLE_CLOZE_CARDS: "\u505C\u7528\u586B\u7A7A\u514B\u6F0F\u5B57\u5361\u7247\uFF1F",
|
|
CONVERT_HIGHLIGHTS_TO_CLOZES: "\u5C07 ==\u9AD8\u4EAE== \u8F49\u63DB\u70BA\u586B\u7A7A\u514B\u6F0F\u5B57\uFF1F",
|
|
CONVERT_BOLD_TEXT_TO_CLOZES: "\u5C07 **\u7C97\u9AD4** \u8F49\u63DB\u70BA\u586B\u7A7A\u514B\u6F0F\u5B57\uFF1F",
|
|
CONVERT_CURLY_BRACKETS_TO_CLOZES: "\u5C07 {{\u5927\u62EC\u865F}} \u8F49\u63DB\u70BA\u586B\u7A7A\u514B\u6F0F\u5B57\uFF1F",
|
|
CLOZE_PATTERNS: "\u586B\u7A7A\u514B\u6F0F\u5B57\u6A21\u5F0F",
|
|
CLOZE_PATTERNS_DESC: '\u8F38\u5165\u4EE5\u63DB\u884C\u7B26\u5206\u9694\u7684\u586B\u7A7A\u514B\u6F0F\u5B57\u6A21\u5F0F. Check the <a href="${docsUrl}">wiki</a> for guidance.',
|
|
INLINE_CARDS_SEPARATOR: "\u55AE\u884C\u5361\u7247\u7684\u5206\u9694\u5B57\u5143",
|
|
FIX_SEPARATORS_MANUALLY_WARNING: "\u6CE8\u610F\uFF1A\u66F4\u6539\u6B64\u9078\u9805\u5F8C\u4F60\u5C07\u9700\u8981\u81EA\u884C\u66F4\u6539\u5DF2\u5B58\u5728\u5361\u7247\u7684\u5206\u9694\u5B57\u5143\u3002",
|
|
INLINE_REVERSED_CARDS_SEPARATOR: "\u55AE\u884C\u53CD\u8F49\u5361\u7247\u7684\u5206\u9694\u5B57\u5143",
|
|
MULTILINE_CARDS_SEPARATOR: "\u591A\u884C\u5361\u7247\u7684\u5206\u9694\u5B57\u5143",
|
|
MULTILINE_REVERSED_CARDS_SEPARATOR: "\u591A\u884C\u7FFB\u8F49\u5361\u7247\u7684\u5206\u9694\u5B57\u5143",
|
|
MULTILINE_CARDS_END_MARKER: "\u8868\u793A\u586B\u7A7A\u548C\u591A\u884C\u95EA\u5361\u7ED3\u675F\u7684\u5B57\u7B26",
|
|
NOTES: "\u7B46\u8A18",
|
|
NOTE: "Note",
|
|
REVIEW_PANE_ON_STARTUP: "\u555F\u52D5\u6642\u958B\u555F\u7B46\u8A18\u5FA9\u7FD2\u7A97\u683C",
|
|
TAGS_TO_REVIEW: "\u5FA9\u7FD2\u6A19\u7C64",
|
|
TAGS_TO_REVIEW_DESC: "\u8F38\u5165\u6A19\u7C64\uFF0C\u7528\u7A7A\u683C\u6216\u63DB\u884C\u5B57\u5143\u5206\u9694\uFF0C\u4F8B\u5982\uFF1A#review #tag2 #tag3.",
|
|
OPEN_RANDOM_NOTE: "\u5FA9\u7FD2\u96A8\u6A5F\u7B46\u8A18",
|
|
OPEN_RANDOM_NOTE_DESC: "\u95DC\u9589\u6B64\u9078\u9805\uFF0C\u7B46\u8A18\u5C07\u4EE5\u91CD\u8981\u5EA6(PageRank)\u6392\u5E8F\u3002",
|
|
AUTO_NEXT_NOTE: "\u5FA9\u7FD2\u5F8C\u81EA\u52D5\u6253\u958B\u4E0B\u4E00\u500B\u7B46\u8A18",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS: "\u8ACB\u5728\u6A94\u6848\u9078\u55AE\u4E2D\u555F\u7528\u6AA2\u8996\u9078\u9805\uFF08\u4F8B\u5982\uFF1A\u6AA2\u8996\uFF1A\u7C21\u55AE\u3001\u8A18\u5F97\u3001\u8F03\u96E3\uFF09",
|
|
ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC: "\u5982\u679C\u60A8\u5728\u6A94\u6848\u9078\u55AE\u4E2D\u505C\u7528\u6AA2\u8996\u9078\u9805\uFF0C\u60A8\u53EF\u4EE5\u4F7F\u7528\u63D2\u4EF6\u6307\u4EE4\u6AA2\u8996\u7B46\u8A18\uFF0C\u5982\u679C\u6709\u8A2D\u5B9A\uFF0C\u4E5F\u53EF\u4EE5\u4F7F\u7528\u76F8\u95DC\u7684\u5FEB\u6377\u9375\u3002",
|
|
MAX_N_DAYS_REVIEW_QUEUE: "\u53F3\u908A\u9762\u677F\u986F\u793A\u7684\u6700\u5927\u5929\u6578",
|
|
MIN_ONE_DAY: "\u5929\u6578\u6700\u5C0F\u503C\u70BA1",
|
|
VALID_NUMBER_WARNING: "\u8ACB\u8F38\u5165\u6709\u6548\u7684\u6578\u5B57\u3002",
|
|
UI: "User Interface",
|
|
SHOW_STATUS_BAR: "Show status bar",
|
|
SHOW_STATUS_BAR_DESC: "Turn this off to hide the flashcard's review status in Obsidian's status bar",
|
|
SHOW_RIBBON_ICON: "Show icon in the ribbon bar",
|
|
SHOW_RIBBON_ICON_DESC: "Turn this off to hide the plugin icon from Obsidian's ribbon bar",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE: "\u724C\u7D44\u6A39\u6700\u521D\u61C9\u986F\u793A\u70BA\u5C55\u958B",
|
|
INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC: "\u95DC\u9589\u6B64\u9078\u9805\u53EF\u647A\u758A\u540C\u4E00\u5F35\u5361\u7247\u4E2D\u7684\u5DE2\u72C0\u724C\u7D44\u3002\u5982\u679C\u60A8\u7684\u5361\u7247\u5C6C\u65BC\u540C\u4E00\u6A94\u6848\u4E2D\u7684\u8A31\u591A\u5957\u724C\uFF0C\u5247\u5F88\u6709\u7528\u3002",
|
|
ALGORITHM: "\u6F14\u7B97\u6CD5",
|
|
CHECK_ALGORITHM_WIKI: '\u77AD\u89E3\u66F4\u591A, \u8ACB\u9EDE\u9078<a href="${algoUrl}">\u7B97\u6CD5\u5BE6\u73FE</a>.',
|
|
SM2_OSR_VARIANT: "OSR's variant of SM-2",
|
|
BASE_EASE: "\u57FA\u790E\u638C\u63E1\u7A0B\u5EA6",
|
|
BASE_EASE_DESC: "\u6700\u5C0F\u503C130\uFF0C\u63A8\u85A6\u503C\u7D04250.",
|
|
BASE_EASE_MIN_WARNING: "\u57FA\u790E\u638C\u63E1\u7A0B\u5EA6\u7684\u6700\u5C0F\u503C\u70BA130\u3002",
|
|
LAPSE_INTERVAL_CHANGE: "\u5C07\u5FA9\u7FD2\u6642\u6A19\u8A3B\u70BA\u300C\u8F03\u96E3\u300D\u7684\u5361\u7247\u6216\u7B46\u8A18\u5FA9\u7FD2\u9593\u9694\u7E2E\u77ED",
|
|
LAPSE_INTERVAL_CHANGE_DESC: "\u65B0\u5FA9\u7FD2\u9593\u9694 = \u539F\u5FA9\u7FD2\u9593\u9694 * \u9593\u9694\u6539\u8B8A\u4FC2\u6578 / 100.",
|
|
EASY_BONUS: "\u7C21\u55AE\u734E\u52F5",
|
|
EASY_BONUS_DESC: "\u7C21\u55AE\u734E\u52F5\u8A2D\u5B9A\u300C\u8A18\u5F97\u300D\u548C\u300C\u7C21\u55AE\u300D\u5361\u7247\u6216\u7B46\u8A18\u7684\u5FA9\u7FD2\u9593\u9694\u5DEE\u8DDD\uFF08\u6700\u5C0F\u503C100%\uFF09\u3002",
|
|
EASY_BONUS_MIN_WARNING: "\u7C21\u55AE\u734E\u52F5\u81F3\u5C11\u70BA100\u3002",
|
|
LOAD_BALANCE: "Enable load balancer",
|
|
LOAD_BALANCE_DESC: `Slightly tweaks the interval so that the number of reviews per day is more consistent.
|
|
It's like Anki's fuzz but instead of being random, it picks the day with the least amount of reviews.
|
|
It's turned off for small intervals.`,
|
|
MAX_INTERVAL: "\u6700\u5927\u9593\u9694\uFF08\u5929\uFF09",
|
|
MAX_INTERVAL_DESC: "\u8A2D\u5B9A\u5FA9\u7FD2\u7684\u6700\u5927\u9593\u9694\u6642\u9593\uFF08\u9810\u8A2D\u503C100\u5E74\uFF09\u3002",
|
|
MAX_INTERVAL_MIN_WARNING: "\u6700\u5927\u9593\u9694\u81F3\u5C11\u70BA1\u5929",
|
|
MAX_LINK_CONTRIB: "\u6700\u5927\u93C8\u63A5\u8CA2\u737B",
|
|
MAX_LINK_CONTRIB_DESC: "\u93C8\u63A5\u7B46\u8A18\u7684\u52A0\u6B0A\u638C\u63E1\u7A0B\u5EA6\u5C0D\u539F\u59CB\u638C\u63E1\u7A0B\u5EA6\u7684\u6700\u5927\u8CA2\u737B\u3002",
|
|
LOGGING: "\u8A18\u9304\u4E2D",
|
|
DISPLAY_SCHEDULING_DEBUG_INFO: "\u5728\u958B\u767C\u8005\u63A7\u5236\u53F0\u4E2D\u986F\u793A\u9664\u932F\u8CC7\u8A0A",
|
|
DISPLAY_PARSER_DEBUG_INFO: "Show the parser's debugging information on the developer console",
|
|
SCHEDULING: "Scheduling",
|
|
EXPERIMENTAL: "Experimental",
|
|
HELP: "Help",
|
|
STORE_IN_NOTES: "In the notes",
|
|
// sidebar.ts
|
|
NOTES_REVIEW_QUEUE: "\u7B46\u8A18\u5FA9\u7FD2\u5E8F\u5217",
|
|
CLOSE: "\u81E8\u8FD1",
|
|
NEW: "\u65B0",
|
|
YESTERDAY: "\u6628\u5929",
|
|
TODAY: "\u4ECA\u5929",
|
|
TOMORROW: "\u660E\u5929",
|
|
// stats-modal.tsx
|
|
STATS_TITLE: "\u7D71\u8A08",
|
|
MONTH: "\u6708",
|
|
QUARTER: "\u5B63",
|
|
YEAR: "\u5E74",
|
|
LIFETIME: "\u5168\u90E8",
|
|
FORECAST: "\u9810\u6E2C",
|
|
FORECAST_DESC: "\u5C07\u8981\u5230\u671F\u7684\u5361\u7247\u6578\u91CF",
|
|
SCHEDULED: "\u5DF2\u6392\u7A0B",
|
|
DAYS: "\u5929",
|
|
NUMBER_OF_CARDS: "\u5361\u7247\u6578\u91CF",
|
|
REVIEWS_PER_DAY: "\u5E73\u5747: \u5FA9\u7FD2${avg} /\u5929",
|
|
INTERVALS: "\u9593\u9694",
|
|
INTERVALS_DESC: "\u5230\u4E0B\u4E00\u6B21\u5FA9\u7FD2\u7684\u6642\u9593\u9593\u9694",
|
|
COUNT: "\u8A08\u6578",
|
|
INTERVALS_SUMMARY: "\u5E73\u5747\u9593\u9694\u6642\u9593: ${avg}, \u6700\u9577\u9593\u9694\u6642\u9593: ${longest}",
|
|
EASES: "\u638C\u63E1\u7A0B\u5EA6",
|
|
EASES_SUMMARY: "\u5E73\u5747\u638C\u63E1\u7A0B\u5EA6: ${avgEase}",
|
|
EASE: "Ease",
|
|
CARD_TYPES: "\u5361\u7247\u578B\u5225",
|
|
CARD_TYPES_DESC: "\u5982\u6709\uFF0C\u5C07\u986F\u793A\u96B1\u85CF\u7684\u5361\u7247",
|
|
CARD_TYPE_NEW: "\u65B0",
|
|
CARD_TYPE_YOUNG: "\u8F03\u65B0",
|
|
CARD_TYPE_MATURE: "\u719F\u6089",
|
|
CARD_TYPES_SUMMARY: "\u7E3D\u5361\u7247\u6578: ${totalCardsCount}",
|
|
SEARCH: "Search",
|
|
PREVIOUS: "Previous",
|
|
NEXT: "Next"
|
|
};
|
|
|
|
// src/lang/helpers.ts
|
|
var localeMap = {
|
|
af: af_default,
|
|
ar: ar_default,
|
|
bn: bn_default,
|
|
cs: cz_default,
|
|
da: da_default,
|
|
de: de_default,
|
|
en: en_default,
|
|
"en-gb": en_gb_default,
|
|
es: es_default,
|
|
fr: fr_default,
|
|
hi: hi_default,
|
|
id: id_default,
|
|
it: it_default,
|
|
ja: ja_default,
|
|
ko: ko_default,
|
|
mr: mr_default,
|
|
nl: nl_default,
|
|
nn: no_default,
|
|
pl: pl_default,
|
|
pt: pt_default,
|
|
"pt-br": pt_br_default,
|
|
ro: ro_default,
|
|
ru: ru_default,
|
|
sw: sw_default,
|
|
ta: ta_default,
|
|
te: te_default,
|
|
th: th_default,
|
|
tr: tr_default,
|
|
uk: uk_default,
|
|
ur: ur_default,
|
|
vi: vi_default,
|
|
"zh-cn": zh_cn_default,
|
|
"zh-tw": zh_tw_default
|
|
};
|
|
var locale = localeMap[import_obsidian.moment.locale()];
|
|
function interpolate(str, params) {
|
|
const names2 = Object.keys(params);
|
|
const vals = Object.values(params);
|
|
return new Function(...names2, `return \`${str}\`;`)(...vals);
|
|
}
|
|
function t(str, params) {
|
|
if (!locale) {
|
|
console.error(`SRS error: Locale ${import_obsidian.moment.locale()} not found.`);
|
|
}
|
|
const result = locale && locale[str] || en_default[str];
|
|
if (params) {
|
|
return interpolate(result, params);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// src/algorithms/osr/note-scheduling.ts
|
|
function osrSchedule(response, originalInterval, ease, delayedBeforeReview, settings, dueDateHistogram) {
|
|
const delayedBeforeReviewDays = Math.max(0, Math.floor(delayedBeforeReview / TICKS_PER_DAY));
|
|
let interval = originalInterval;
|
|
if (response === 0 /* Easy */) {
|
|
ease += 20;
|
|
interval = (interval + delayedBeforeReviewDays) * ease / 100;
|
|
interval *= settings.easyBonus;
|
|
} else if (response === 1 /* Good */) {
|
|
interval = (interval + delayedBeforeReviewDays / 2) * ease / 100;
|
|
} else if (response === 2 /* Hard */) {
|
|
ease = Math.max(130, ease - 20);
|
|
interval = Math.max(
|
|
1,
|
|
(interval + delayedBeforeReviewDays / 4) * settings.lapsesIntervalChange
|
|
);
|
|
}
|
|
if (settings.loadBalance && dueDateHistogram !== void 0) {
|
|
interval = Math.round(interval);
|
|
if (interval > 7) {
|
|
let fuzz;
|
|
if (interval <= 21) fuzz = 1;
|
|
else if (interval <= 180) fuzz = Math.min(3, Math.floor(interval * 0.05));
|
|
else fuzz = Math.min(7, Math.floor(interval * 0.025));
|
|
interval = dueDateHistogram.findLeastUsedIntervalOverRange(interval, fuzz);
|
|
}
|
|
}
|
|
interval = Math.min(interval, settings.maximumInterval);
|
|
interval = Math.round(interval * 10) / 10;
|
|
return { interval, ease };
|
|
}
|
|
function textInterval(interval, isMobile) {
|
|
if (interval === void 0) {
|
|
return t("NEW");
|
|
}
|
|
const m2 = Math.round(interval / 3.04375) / 10, y2 = Math.round(interval / 36.525) / 10;
|
|
if (isMobile) {
|
|
if (m2 < 1) return t("DAYS_STR_IVL_MOBILE", { interval });
|
|
else if (y2 < 1) return t("MONTHS_STR_IVL_MOBILE", { interval: m2 });
|
|
else return t("YEARS_STR_IVL_MOBILE", { interval: y2 });
|
|
} else {
|
|
if (m2 < 1) return t("DAYS_STR_IVL", { interval });
|
|
else if (y2 < 1) return t("MONTHS_STR_IVL", { interval: m2 });
|
|
else return t("YEARS_STR_IVL", { interval: y2 });
|
|
}
|
|
}
|
|
|
|
// src/utils/dates.ts
|
|
var import_moment = __toESM(require_moment());
|
|
function formatDateYYYYMMDD(ticks) {
|
|
return ticks.format(PREFERRED_DATE_FORMAT);
|
|
}
|
|
var LiveDateProvider = class {
|
|
get now() {
|
|
return (0, import_moment.default)();
|
|
}
|
|
get today() {
|
|
return (0, import_moment.default)().startOf("day");
|
|
}
|
|
};
|
|
var DateUtil = class {
|
|
static dateStrToMoment(str) {
|
|
return (0, import_moment.default)(str, ALLOWED_DATE_FORMATS);
|
|
}
|
|
};
|
|
var globalDateProvider = new LiveDateProvider();
|
|
|
|
// src/algorithms/base/rep-item-schedule-info.ts
|
|
var RepItemScheduleInfo = class {
|
|
get dueDateAsUnix() {
|
|
return this.dueDate.valueOf();
|
|
}
|
|
isDue() {
|
|
return this.dueDate && this.dueDate.isSameOrBefore(globalDateProvider.today);
|
|
}
|
|
formatDueDate() {
|
|
return formatDateYYYYMMDD(this.dueDate);
|
|
}
|
|
delayedBeforeReviewDaysInt() {
|
|
return Math.max(0, Math.floor(this.delayedBeforeReviewTicks / TICKS_PER_DAY));
|
|
}
|
|
};
|
|
|
|
// src/algorithms/osr/rep-item-schedule-info-osr.ts
|
|
var _RepItemScheduleInfoOsr = class _RepItemScheduleInfoOsr extends RepItemScheduleInfo {
|
|
constructor(dueDate, interval, latestEase, delayedBeforeReviewTicks = null) {
|
|
super();
|
|
this.dueDate = dueDate;
|
|
this.interval = Math.round(interval);
|
|
this.latestEase = latestEase;
|
|
this.delayedBeforeReviewTicks = delayedBeforeReviewTicks;
|
|
if (dueDate && delayedBeforeReviewTicks == null) {
|
|
this.delayedBeforeReviewTicks = globalDateProvider.today.valueOf() - dueDate.valueOf();
|
|
}
|
|
}
|
|
formatCardScheduleForHtmlComment() {
|
|
const dateStr = this.dueDate ? this.formatDueDate() : _RepItemScheduleInfoOsr.dummyDueDateForNewCard;
|
|
return `!${dateStr},${this.interval},${this.latestEase}`;
|
|
}
|
|
static get initialInterval() {
|
|
return 1;
|
|
}
|
|
static getDummyScheduleForNewCard(settings) {
|
|
return _RepItemScheduleInfoOsr.fromDueDateStr(
|
|
_RepItemScheduleInfoOsr.dummyDueDateForNewCard,
|
|
_RepItemScheduleInfoOsr.initialInterval,
|
|
settings.baseEase
|
|
);
|
|
}
|
|
static fromDueDateStr(dueDateStr, interval, ease, delayedBeforeReviewTicks = null) {
|
|
const dueDate = DateUtil.dateStrToMoment(dueDateStr);
|
|
return new _RepItemScheduleInfoOsr(dueDate, interval, ease, delayedBeforeReviewTicks);
|
|
}
|
|
};
|
|
// A question can have multiple cards. The schedule info for all sibling cards are formatted together
|
|
// in a single <!--SR: --> comment, such as:
|
|
// <!--SR:!2023-09-02,4,270!2023-09-02,5,270!2023-09-02,6,270!2023-09-02,7,270-->
|
|
//
|
|
// However, not all sibling cards may have been reviewed. Therefore we need a method of indicating that a particular card
|
|
// has not been reviewed, and should be considered "new"
|
|
// This is done by using this magic value for the date
|
|
_RepItemScheduleInfoOsr.dummyDueDateForNewCard = "2000-01-01";
|
|
var RepItemScheduleInfoOsr = _RepItemScheduleInfoOsr;
|
|
|
|
// src/note-ease-list.ts
|
|
var NoteEaseList = class {
|
|
constructor(settings) {
|
|
this.dict = {};
|
|
this.settings = settings;
|
|
}
|
|
get baseEase() {
|
|
return this.settings.baseEase;
|
|
}
|
|
hasEaseForPath(path3) {
|
|
return Object.prototype.hasOwnProperty.call(this.dict, path3);
|
|
}
|
|
getEaseByPath(path3) {
|
|
let ease = null;
|
|
if (this.hasEaseForPath(path3)) {
|
|
ease = Math.round(this.dict[path3]);
|
|
}
|
|
return ease;
|
|
}
|
|
setEaseForPath(path3, ease) {
|
|
this.dict[path3] = ease;
|
|
}
|
|
};
|
|
|
|
// src/algorithms/osr/srs-algorithm-osr.ts
|
|
var SrsAlgorithmOsr = class _SrsAlgorithmOsr {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
this.noteEaseList = new NoteEaseList(settings);
|
|
}
|
|
static get initialInterval() {
|
|
return 1;
|
|
}
|
|
noteCalcNewSchedule(notePath, osrNoteGraph, response, dueDateNoteHistogram) {
|
|
const noteLinkStat = osrNoteGraph.calcNoteLinkStat(
|
|
notePath,
|
|
this.noteEaseList
|
|
);
|
|
const linkContribution = this.settings.maxLinkFactor * Math.min(1, Math.log(noteLinkStat.totalLinkCount + 0.5) / Math.log(64));
|
|
let ease = (1 - linkContribution) * this.settings.baseEase + (noteLinkStat.totalLinkCount > 0 ? linkContribution * noteLinkStat.linkTotal / noteLinkStat.linkPGTotal : linkContribution * this.settings.baseEase);
|
|
if (this.noteEaseList.hasEaseForPath(notePath)) {
|
|
ease = (ease + this.noteEaseList.getEaseByPath(notePath)) / 2;
|
|
}
|
|
const dueDate = null;
|
|
const interval = _SrsAlgorithmOsr.initialInterval;
|
|
ease = Math.round(ease);
|
|
const temp = new RepItemScheduleInfoOsr(dueDate, interval, ease);
|
|
const result = this.calcSchedule(
|
|
temp,
|
|
response,
|
|
dueDateNoteHistogram
|
|
);
|
|
result.dueDate = (0, import_moment2.default)(globalDateProvider.today.add(result.interval, "d"));
|
|
return result;
|
|
}
|
|
noteOnLoadedNote(path3, note, noteEase) {
|
|
let flashcardsInNoteAvgEase = null;
|
|
if (note) {
|
|
flashcardsInNoteAvgEase = _SrsAlgorithmOsr.calculateFlashcardAvgEase(
|
|
note.questionList,
|
|
this.settings
|
|
);
|
|
}
|
|
let ease = null;
|
|
if (flashcardsInNoteAvgEase && noteEase) {
|
|
ease = (flashcardsInNoteAvgEase + noteEase) / 2;
|
|
} else {
|
|
ease = flashcardsInNoteAvgEase ? flashcardsInNoteAvgEase : noteEase;
|
|
}
|
|
if (ease) {
|
|
this.noteEaseList.setEaseForPath(path3, ease);
|
|
}
|
|
}
|
|
static calculateFlashcardAvgEase(questionList, settings) {
|
|
let totalEase = 0;
|
|
let scheduledCount = 0;
|
|
questionList.forEach((question) => {
|
|
question.cards.filter((card) => card.hasSchedule).forEach((card) => {
|
|
totalEase += card.scheduleInfo.latestEase;
|
|
scheduledCount++;
|
|
});
|
|
});
|
|
let result = 0;
|
|
if (scheduledCount > 0) {
|
|
const flashcardsInNoteAvgEase = totalEase / scheduledCount;
|
|
const flashcardContribution = Math.min(
|
|
1,
|
|
Math.log(scheduledCount + 0.5) / Math.log(64)
|
|
);
|
|
result = flashcardsInNoteAvgEase * flashcardContribution + settings.baseEase * (1 - flashcardContribution);
|
|
}
|
|
return result;
|
|
}
|
|
noteCalcUpdatedSchedule(notePath, noteSchedule, response, dueDateNoteHistogram) {
|
|
const noteScheduleOsr = noteSchedule;
|
|
const temp = this.calcSchedule(
|
|
noteScheduleOsr,
|
|
response,
|
|
dueDateNoteHistogram
|
|
);
|
|
const interval = temp.interval;
|
|
const ease = temp.latestEase;
|
|
const dueDate = (0, import_moment2.default)(globalDateProvider.today.add(interval, "d"));
|
|
this.noteEaseList.setEaseForPath(notePath, ease);
|
|
return new RepItemScheduleInfoOsr(dueDate, interval, ease);
|
|
}
|
|
calcSchedule(schedule, response, dueDateHistogram) {
|
|
const temp = osrSchedule(
|
|
response,
|
|
schedule.interval,
|
|
schedule.latestEase,
|
|
schedule.delayedBeforeReviewTicks,
|
|
this.settings,
|
|
dueDateHistogram
|
|
);
|
|
return new RepItemScheduleInfoOsr(globalDateProvider.today, temp.interval, temp.ease);
|
|
}
|
|
cardGetResetSchedule() {
|
|
const interval = _SrsAlgorithmOsr.initialInterval;
|
|
const ease = this.settings.baseEase;
|
|
const dueDate = globalDateProvider.today.add(interval, "d");
|
|
return new RepItemScheduleInfoOsr(dueDate, interval, ease);
|
|
}
|
|
cardGetNewSchedule(response, notePath, dueDateFlashcardHistogram) {
|
|
let initialEase = this.settings.baseEase;
|
|
if (this.noteEaseList.hasEaseForPath(notePath)) {
|
|
initialEase = Math.round(this.noteEaseList.getEaseByPath(notePath));
|
|
}
|
|
const delayBeforeReview = 0;
|
|
const schedObj = osrSchedule(
|
|
response,
|
|
_SrsAlgorithmOsr.initialInterval,
|
|
initialEase,
|
|
delayBeforeReview,
|
|
this.settings,
|
|
dueDateFlashcardHistogram
|
|
);
|
|
const interval = schedObj.interval;
|
|
const ease = schedObj.ease;
|
|
const dueDate = globalDateProvider.today.add(interval, "d");
|
|
return new RepItemScheduleInfoOsr(dueDate, interval, ease, delayBeforeReview);
|
|
}
|
|
cardCalcUpdatedSchedule(response, cardSchedule, dueDateFlashcardHistogram) {
|
|
const cardScheduleOsr = cardSchedule;
|
|
const schedObj = osrSchedule(
|
|
response,
|
|
cardScheduleOsr.interval,
|
|
cardSchedule.latestEase,
|
|
cardSchedule.delayedBeforeReviewTicks,
|
|
this.settings,
|
|
dueDateFlashcardHistogram
|
|
);
|
|
const interval = schedObj.interval;
|
|
const ease = schedObj.ease;
|
|
const dueDate = globalDateProvider.today.add(interval, "d");
|
|
const delayBeforeReview = 0;
|
|
return new RepItemScheduleInfoOsr(dueDate, interval, ease, delayBeforeReview);
|
|
}
|
|
noteStats() {
|
|
return this.noteEaseList;
|
|
}
|
|
};
|
|
|
|
// src/algorithms/osr/osr-note-graph.ts
|
|
var graph = __toESM(require_lib());
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/index.js
|
|
var import_brace_expansion = __toESM(require_brace_expansion(), 1);
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/assert-valid-pattern.js
|
|
var MAX_PATTERN_LENGTH = 1024 * 64;
|
|
var assertValidPattern = (pattern) => {
|
|
if (typeof pattern !== "string") {
|
|
throw new TypeError("invalid pattern");
|
|
}
|
|
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
throw new TypeError("pattern is too long");
|
|
}
|
|
};
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/brace-expressions.js
|
|
var posixClasses = {
|
|
"[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
|
|
"[:alpha:]": ["\\p{L}\\p{Nl}", true],
|
|
"[:ascii:]": ["\\x00-\\x7f", false],
|
|
"[:blank:]": ["\\p{Zs}\\t", true],
|
|
"[:cntrl:]": ["\\p{Cc}", true],
|
|
"[:digit:]": ["\\p{Nd}", true],
|
|
"[:graph:]": ["\\p{Z}\\p{C}", true, true],
|
|
"[:lower:]": ["\\p{Ll}", true],
|
|
"[:print:]": ["\\p{C}", true],
|
|
"[:punct:]": ["\\p{P}", true],
|
|
"[:space:]": ["\\p{Z}\\t\\r\\n\\v\\f", true],
|
|
"[:upper:]": ["\\p{Lu}", true],
|
|
"[:word:]": ["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}", true],
|
|
"[:xdigit:]": ["A-Fa-f0-9", false]
|
|
};
|
|
var braceEscape = (s2) => s2.replace(/[[\]\\-]/g, "\\$&");
|
|
var regexpEscape = (s2) => s2.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
var rangesToString = (ranges) => ranges.join("");
|
|
var parseClass = (glob, position) => {
|
|
const pos = position;
|
|
if (glob.charAt(pos) !== "[") {
|
|
throw new Error("not in a brace expression");
|
|
}
|
|
const ranges = [];
|
|
const negs = [];
|
|
let i2 = pos + 1;
|
|
let sawStart = false;
|
|
let uflag = false;
|
|
let escaping = false;
|
|
let negate = false;
|
|
let endPos = pos;
|
|
let rangeStart = "";
|
|
WHILE: while (i2 < glob.length) {
|
|
const c2 = glob.charAt(i2);
|
|
if ((c2 === "!" || c2 === "^") && i2 === pos + 1) {
|
|
negate = true;
|
|
i2++;
|
|
continue;
|
|
}
|
|
if (c2 === "]" && sawStart && !escaping) {
|
|
endPos = i2 + 1;
|
|
break;
|
|
}
|
|
sawStart = true;
|
|
if (c2 === "\\") {
|
|
if (!escaping) {
|
|
escaping = true;
|
|
i2++;
|
|
continue;
|
|
}
|
|
}
|
|
if (c2 === "[" && !escaping) {
|
|
for (const [cls, [unip, u2, neg]] of Object.entries(posixClasses)) {
|
|
if (glob.startsWith(cls, i2)) {
|
|
if (rangeStart) {
|
|
return ["$.", false, glob.length - pos, true];
|
|
}
|
|
i2 += cls.length;
|
|
if (neg)
|
|
negs.push(unip);
|
|
else
|
|
ranges.push(unip);
|
|
uflag = uflag || u2;
|
|
continue WHILE;
|
|
}
|
|
}
|
|
}
|
|
escaping = false;
|
|
if (rangeStart) {
|
|
if (c2 > rangeStart) {
|
|
ranges.push(braceEscape(rangeStart) + "-" + braceEscape(c2));
|
|
} else if (c2 === rangeStart) {
|
|
ranges.push(braceEscape(c2));
|
|
}
|
|
rangeStart = "";
|
|
i2++;
|
|
continue;
|
|
}
|
|
if (glob.startsWith("-]", i2 + 1)) {
|
|
ranges.push(braceEscape(c2 + "-"));
|
|
i2 += 2;
|
|
continue;
|
|
}
|
|
if (glob.startsWith("-", i2 + 1)) {
|
|
rangeStart = c2;
|
|
i2 += 2;
|
|
continue;
|
|
}
|
|
ranges.push(braceEscape(c2));
|
|
i2++;
|
|
}
|
|
if (endPos < i2) {
|
|
return ["", false, 0, false];
|
|
}
|
|
if (!ranges.length && !negs.length) {
|
|
return ["$.", false, glob.length - pos, true];
|
|
}
|
|
if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) {
|
|
const r2 = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
|
|
return [regexpEscape(r2), false, endPos - pos, false];
|
|
}
|
|
const sranges = "[" + (negate ? "^" : "") + rangesToString(ranges) + "]";
|
|
const snegs = "[" + (negate ? "" : "^") + rangesToString(negs) + "]";
|
|
const comb = ranges.length && negs.length ? "(" + sranges + "|" + snegs + ")" : ranges.length ? sranges : snegs;
|
|
return [comb, uflag, endPos - pos, true];
|
|
};
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/unescape.js
|
|
var unescape = (s2, { windowsPathsNoEscape = false } = {}) => {
|
|
return windowsPathsNoEscape ? s2.replace(/\[([^\/\\])\]/g, "$1") : s2.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
|
|
};
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/ast.js
|
|
var types = /* @__PURE__ */ new Set(["!", "?", "+", "*", "@"]);
|
|
var isExtglobType = (c2) => types.has(c2);
|
|
var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))";
|
|
var startNoDot = "(?!\\.)";
|
|
var addPatternStart = /* @__PURE__ */ new Set(["[", "."]);
|
|
var justDots = /* @__PURE__ */ new Set(["..", "."]);
|
|
var reSpecials = new Set("().*{}+?[]^$\\!");
|
|
var regExpEscape = (s2) => s2.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
var qmark = "[^/]";
|
|
var star = qmark + "*?";
|
|
var starNoEmpty = qmark + "+?";
|
|
var _root, _hasMagic, _uflag, _parts, _parent, _parentIndex, _negs, _filledNegs, _options, _toString, _emptyExt, _AST_instances, fillNegs_fn, _AST_static, parseAST_fn, partsToRegExp_fn, parseGlob_fn;
|
|
var _AST = class _AST {
|
|
constructor(type, parent, options = {}) {
|
|
__privateAdd(this, _AST_instances);
|
|
__publicField(this, "type");
|
|
__privateAdd(this, _root);
|
|
__privateAdd(this, _hasMagic);
|
|
__privateAdd(this, _uflag, false);
|
|
__privateAdd(this, _parts, []);
|
|
__privateAdd(this, _parent);
|
|
__privateAdd(this, _parentIndex);
|
|
__privateAdd(this, _negs);
|
|
__privateAdd(this, _filledNegs, false);
|
|
__privateAdd(this, _options);
|
|
__privateAdd(this, _toString);
|
|
// set to true if it's an extglob with no children
|
|
// (which really means one child of '')
|
|
__privateAdd(this, _emptyExt, false);
|
|
this.type = type;
|
|
if (type)
|
|
__privateSet(this, _hasMagic, true);
|
|
__privateSet(this, _parent, parent);
|
|
__privateSet(this, _root, __privateGet(this, _parent) ? __privateGet(__privateGet(this, _parent), _root) : this);
|
|
__privateSet(this, _options, __privateGet(this, _root) === this ? options : __privateGet(__privateGet(this, _root), _options));
|
|
__privateSet(this, _negs, __privateGet(this, _root) === this ? [] : __privateGet(__privateGet(this, _root), _negs));
|
|
if (type === "!" && !__privateGet(__privateGet(this, _root), _filledNegs))
|
|
__privateGet(this, _negs).push(this);
|
|
__privateSet(this, _parentIndex, __privateGet(this, _parent) ? __privateGet(__privateGet(this, _parent), _parts).length : 0);
|
|
}
|
|
get hasMagic() {
|
|
if (__privateGet(this, _hasMagic) !== void 0)
|
|
return __privateGet(this, _hasMagic);
|
|
for (const p2 of __privateGet(this, _parts)) {
|
|
if (typeof p2 === "string")
|
|
continue;
|
|
if (p2.type || p2.hasMagic)
|
|
return __privateSet(this, _hasMagic, true);
|
|
}
|
|
return __privateGet(this, _hasMagic);
|
|
}
|
|
// reconstructs the pattern
|
|
toString() {
|
|
if (__privateGet(this, _toString) !== void 0)
|
|
return __privateGet(this, _toString);
|
|
if (!this.type) {
|
|
return __privateSet(this, _toString, __privateGet(this, _parts).map((p2) => String(p2)).join(""));
|
|
} else {
|
|
return __privateSet(this, _toString, this.type + "(" + __privateGet(this, _parts).map((p2) => String(p2)).join("|") + ")");
|
|
}
|
|
}
|
|
push(...parts) {
|
|
for (const p2 of parts) {
|
|
if (p2 === "")
|
|
continue;
|
|
if (typeof p2 !== "string" && !(p2 instanceof _AST && __privateGet(p2, _parent) === this)) {
|
|
throw new Error("invalid part: " + p2);
|
|
}
|
|
__privateGet(this, _parts).push(p2);
|
|
}
|
|
}
|
|
toJSON() {
|
|
var _a;
|
|
const ret = this.type === null ? __privateGet(this, _parts).slice().map((p2) => typeof p2 === "string" ? p2 : p2.toJSON()) : [this.type, ...__privateGet(this, _parts).map((p2) => p2.toJSON())];
|
|
if (this.isStart() && !this.type)
|
|
ret.unshift([]);
|
|
if (this.isEnd() && (this === __privateGet(this, _root) || __privateGet(__privateGet(this, _root), _filledNegs) && ((_a = __privateGet(this, _parent)) == null ? void 0 : _a.type) === "!")) {
|
|
ret.push({});
|
|
}
|
|
return ret;
|
|
}
|
|
isStart() {
|
|
var _a;
|
|
if (__privateGet(this, _root) === this)
|
|
return true;
|
|
if (!((_a = __privateGet(this, _parent)) == null ? void 0 : _a.isStart()))
|
|
return false;
|
|
if (__privateGet(this, _parentIndex) === 0)
|
|
return true;
|
|
const p2 = __privateGet(this, _parent);
|
|
for (let i2 = 0; i2 < __privateGet(this, _parentIndex); i2++) {
|
|
const pp = __privateGet(p2, _parts)[i2];
|
|
if (!(pp instanceof _AST && pp.type === "!")) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
isEnd() {
|
|
var _a, _b, _c;
|
|
if (__privateGet(this, _root) === this)
|
|
return true;
|
|
if (((_a = __privateGet(this, _parent)) == null ? void 0 : _a.type) === "!")
|
|
return true;
|
|
if (!((_b = __privateGet(this, _parent)) == null ? void 0 : _b.isEnd()))
|
|
return false;
|
|
if (!this.type)
|
|
return (_c = __privateGet(this, _parent)) == null ? void 0 : _c.isEnd();
|
|
const pl = __privateGet(this, _parent) ? __privateGet(__privateGet(this, _parent), _parts).length : 0;
|
|
return __privateGet(this, _parentIndex) === pl - 1;
|
|
}
|
|
copyIn(part) {
|
|
if (typeof part === "string")
|
|
this.push(part);
|
|
else
|
|
this.push(part.clone(this));
|
|
}
|
|
clone(parent) {
|
|
const c2 = new _AST(this.type, parent);
|
|
for (const p2 of __privateGet(this, _parts)) {
|
|
c2.copyIn(p2);
|
|
}
|
|
return c2;
|
|
}
|
|
static fromGlob(pattern, options = {}) {
|
|
var _a;
|
|
const ast = new _AST(null, void 0, options);
|
|
__privateMethod(_a = _AST, _AST_static, parseAST_fn).call(_a, pattern, ast, 0, options);
|
|
return ast;
|
|
}
|
|
// returns the regular expression if there's magic, or the unescaped
|
|
// string if not.
|
|
toMMPattern() {
|
|
if (this !== __privateGet(this, _root))
|
|
return __privateGet(this, _root).toMMPattern();
|
|
const glob = this.toString();
|
|
const [re, body, hasMagic, uflag] = this.toRegExpSource();
|
|
const anyMagic = hasMagic || __privateGet(this, _hasMagic) || __privateGet(this, _options).nocase && !__privateGet(this, _options).nocaseMagicOnly && glob.toUpperCase() !== glob.toLowerCase();
|
|
if (!anyMagic) {
|
|
return body;
|
|
}
|
|
const flags = (__privateGet(this, _options).nocase ? "i" : "") + (uflag ? "u" : "");
|
|
return Object.assign(new RegExp(`^${re}$`, flags), {
|
|
_src: re,
|
|
_glob: glob
|
|
});
|
|
}
|
|
get options() {
|
|
return __privateGet(this, _options);
|
|
}
|
|
// returns the string match, the regexp source, whether there's magic
|
|
// in the regexp (so a regular expression is required) and whether or
|
|
// not the uflag is needed for the regular expression (for posix classes)
|
|
// TODO: instead of injecting the start/end at this point, just return
|
|
// the BODY of the regexp, along with the start/end portions suitable
|
|
// for binding the start/end in either a joined full-path makeRe context
|
|
// (where we bind to (^|/), or a standalone matchPart context (where
|
|
// we bind to ^, and not /). Otherwise slashes get duped!
|
|
//
|
|
// In part-matching mode, the start is:
|
|
// - if not isStart: nothing
|
|
// - if traversal possible, but not allowed: ^(?!\.\.?$)
|
|
// - if dots allowed or not possible: ^
|
|
// - if dots possible and not allowed: ^(?!\.)
|
|
// end is:
|
|
// - if not isEnd(): nothing
|
|
// - else: $
|
|
//
|
|
// In full-path matching mode, we put the slash at the START of the
|
|
// pattern, so start is:
|
|
// - if first pattern: same as part-matching mode
|
|
// - if not isStart(): nothing
|
|
// - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
|
|
// - if dots allowed or not possible: /
|
|
// - if dots possible and not allowed: /(?!\.)
|
|
// end is:
|
|
// - if last pattern, same as part-matching mode
|
|
// - else nothing
|
|
//
|
|
// Always put the (?:$|/) on negated tails, though, because that has to be
|
|
// there to bind the end of the negated pattern portion, and it's easier to
|
|
// just stick it in now rather than try to inject it later in the middle of
|
|
// the pattern.
|
|
//
|
|
// We can just always return the same end, and leave it up to the caller
|
|
// to know whether it's going to be used joined or in parts.
|
|
// And, if the start is adjusted slightly, can do the same there:
|
|
// - if not isStart: nothing
|
|
// - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
|
|
// - if dots allowed or not possible: (?:/|^)
|
|
// - if dots possible and not allowed: (?:/|^)(?!\.)
|
|
//
|
|
// But it's better to have a simpler binding without a conditional, for
|
|
// performance, so probably better to return both start options.
|
|
//
|
|
// Then the caller just ignores the end if it's not the first pattern,
|
|
// and the start always gets applied.
|
|
//
|
|
// But that's always going to be $ if it's the ending pattern, or nothing,
|
|
// so the caller can just attach $ at the end of the pattern when building.
|
|
//
|
|
// So the todo is:
|
|
// - better detect what kind of start is needed
|
|
// - return both flavors of starting pattern
|
|
// - attach $ at the end of the pattern when creating the actual RegExp
|
|
//
|
|
// Ah, but wait, no, that all only applies to the root when the first pattern
|
|
// is not an extglob. If the first pattern IS an extglob, then we need all
|
|
// that dot prevention biz to live in the extglob portions, because eg
|
|
// +(*|.x*) can match .xy but not .yx.
|
|
//
|
|
// So, return the two flavors if it's #root and the first child is not an
|
|
// AST, otherwise leave it to the child AST to handle it, and there,
|
|
// use the (?:^|/) style of start binding.
|
|
//
|
|
// Even simplified further:
|
|
// - Since the start for a join is eg /(?!\.) and the start for a part
|
|
// is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
|
|
// or start or whatever) and prepend ^ or / at the Regexp construction.
|
|
toRegExpSource(allowDot) {
|
|
var _a;
|
|
const dot = allowDot != null ? allowDot : !!__privateGet(this, _options).dot;
|
|
if (__privateGet(this, _root) === this)
|
|
__privateMethod(this, _AST_instances, fillNegs_fn).call(this);
|
|
if (!this.type) {
|
|
const noEmpty = this.isStart() && this.isEnd();
|
|
const src = __privateGet(this, _parts).map((p2) => {
|
|
var _a2;
|
|
const [re, _2, hasMagic, uflag] = typeof p2 === "string" ? __privateMethod(_a2 = _AST, _AST_static, parseGlob_fn).call(_a2, p2, __privateGet(this, _hasMagic), noEmpty) : p2.toRegExpSource(allowDot);
|
|
__privateSet(this, _hasMagic, __privateGet(this, _hasMagic) || hasMagic);
|
|
__privateSet(this, _uflag, __privateGet(this, _uflag) || uflag);
|
|
return re;
|
|
}).join("");
|
|
let start2 = "";
|
|
if (this.isStart()) {
|
|
if (typeof __privateGet(this, _parts)[0] === "string") {
|
|
const dotTravAllowed = __privateGet(this, _parts).length === 1 && justDots.has(__privateGet(this, _parts)[0]);
|
|
if (!dotTravAllowed) {
|
|
const aps = addPatternStart;
|
|
const needNoTrav = (
|
|
// dots are allowed, and the pattern starts with [ or .
|
|
dot && aps.has(src.charAt(0)) || // the pattern starts with \., and then [ or .
|
|
src.startsWith("\\.") && aps.has(src.charAt(2)) || // the pattern starts with \.\., and then [ or .
|
|
src.startsWith("\\.\\.") && aps.has(src.charAt(4))
|
|
);
|
|
const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
|
|
start2 = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : "";
|
|
}
|
|
}
|
|
}
|
|
let end = "";
|
|
if (this.isEnd() && __privateGet(__privateGet(this, _root), _filledNegs) && ((_a = __privateGet(this, _parent)) == null ? void 0 : _a.type) === "!") {
|
|
end = "(?:$|\\/)";
|
|
}
|
|
const final2 = start2 + src + end;
|
|
return [
|
|
final2,
|
|
unescape(src),
|
|
__privateSet(this, _hasMagic, !!__privateGet(this, _hasMagic)),
|
|
__privateGet(this, _uflag)
|
|
];
|
|
}
|
|
const repeated = this.type === "*" || this.type === "+";
|
|
const start = this.type === "!" ? "(?:(?!(?:" : "(?:";
|
|
let body = __privateMethod(this, _AST_instances, partsToRegExp_fn).call(this, dot);
|
|
if (this.isStart() && this.isEnd() && !body && this.type !== "!") {
|
|
const s2 = this.toString();
|
|
__privateSet(this, _parts, [s2]);
|
|
this.type = null;
|
|
__privateSet(this, _hasMagic, void 0);
|
|
return [s2, unescape(this.toString()), false, false];
|
|
}
|
|
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ? "" : __privateMethod(this, _AST_instances, partsToRegExp_fn).call(this, true);
|
|
if (bodyDotAllowed === body) {
|
|
bodyDotAllowed = "";
|
|
}
|
|
if (bodyDotAllowed) {
|
|
body = `(?:${body})(?:${bodyDotAllowed})*?`;
|
|
}
|
|
let final = "";
|
|
if (this.type === "!" && __privateGet(this, _emptyExt)) {
|
|
final = (this.isStart() && !dot ? startNoDot : "") + starNoEmpty;
|
|
} else {
|
|
const close = this.type === "!" ? (
|
|
// !() must match something,but !(x) can match ''
|
|
"))" + (this.isStart() && !dot && !allowDot ? startNoDot : "") + star + ")"
|
|
) : this.type === "@" ? ")" : this.type === "?" ? ")?" : this.type === "+" && bodyDotAllowed ? ")" : this.type === "*" && bodyDotAllowed ? `)?` : `)${this.type}`;
|
|
final = start + body + close;
|
|
}
|
|
return [
|
|
final,
|
|
unescape(body),
|
|
__privateSet(this, _hasMagic, !!__privateGet(this, _hasMagic)),
|
|
__privateGet(this, _uflag)
|
|
];
|
|
}
|
|
};
|
|
_root = new WeakMap();
|
|
_hasMagic = new WeakMap();
|
|
_uflag = new WeakMap();
|
|
_parts = new WeakMap();
|
|
_parent = new WeakMap();
|
|
_parentIndex = new WeakMap();
|
|
_negs = new WeakMap();
|
|
_filledNegs = new WeakMap();
|
|
_options = new WeakMap();
|
|
_toString = new WeakMap();
|
|
_emptyExt = new WeakMap();
|
|
_AST_instances = new WeakSet();
|
|
fillNegs_fn = function() {
|
|
if (this !== __privateGet(this, _root))
|
|
throw new Error("should only call on root");
|
|
if (__privateGet(this, _filledNegs))
|
|
return this;
|
|
this.toString();
|
|
__privateSet(this, _filledNegs, true);
|
|
let n2;
|
|
while (n2 = __privateGet(this, _negs).pop()) {
|
|
if (n2.type !== "!")
|
|
continue;
|
|
let p2 = n2;
|
|
let pp = __privateGet(p2, _parent);
|
|
while (pp) {
|
|
for (let i2 = __privateGet(p2, _parentIndex) + 1; !pp.type && i2 < __privateGet(pp, _parts).length; i2++) {
|
|
for (const part of __privateGet(n2, _parts)) {
|
|
if (typeof part === "string") {
|
|
throw new Error("string part in extglob AST??");
|
|
}
|
|
part.copyIn(__privateGet(pp, _parts)[i2]);
|
|
}
|
|
}
|
|
p2 = pp;
|
|
pp = __privateGet(p2, _parent);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
_AST_static = new WeakSet();
|
|
parseAST_fn = function(str, ast, pos, opt) {
|
|
var _a, _b;
|
|
let escaping = false;
|
|
let inBrace = false;
|
|
let braceStart = -1;
|
|
let braceNeg = false;
|
|
if (ast.type === null) {
|
|
let i3 = pos;
|
|
let acc2 = "";
|
|
while (i3 < str.length) {
|
|
const c2 = str.charAt(i3++);
|
|
if (escaping || c2 === "\\") {
|
|
escaping = !escaping;
|
|
acc2 += c2;
|
|
continue;
|
|
}
|
|
if (inBrace) {
|
|
if (i3 === braceStart + 1) {
|
|
if (c2 === "^" || c2 === "!") {
|
|
braceNeg = true;
|
|
}
|
|
} else if (c2 === "]" && !(i3 === braceStart + 2 && braceNeg)) {
|
|
inBrace = false;
|
|
}
|
|
acc2 += c2;
|
|
continue;
|
|
} else if (c2 === "[") {
|
|
inBrace = true;
|
|
braceStart = i3;
|
|
braceNeg = false;
|
|
acc2 += c2;
|
|
continue;
|
|
}
|
|
if (!opt.noext && isExtglobType(c2) && str.charAt(i3) === "(") {
|
|
ast.push(acc2);
|
|
acc2 = "";
|
|
const ext2 = new _AST(c2, ast);
|
|
i3 = __privateMethod(_a = _AST, _AST_static, parseAST_fn).call(_a, str, ext2, i3, opt);
|
|
ast.push(ext2);
|
|
continue;
|
|
}
|
|
acc2 += c2;
|
|
}
|
|
ast.push(acc2);
|
|
return i3;
|
|
}
|
|
let i2 = pos + 1;
|
|
let part = new _AST(null, ast);
|
|
const parts = [];
|
|
let acc = "";
|
|
while (i2 < str.length) {
|
|
const c2 = str.charAt(i2++);
|
|
if (escaping || c2 === "\\") {
|
|
escaping = !escaping;
|
|
acc += c2;
|
|
continue;
|
|
}
|
|
if (inBrace) {
|
|
if (i2 === braceStart + 1) {
|
|
if (c2 === "^" || c2 === "!") {
|
|
braceNeg = true;
|
|
}
|
|
} else if (c2 === "]" && !(i2 === braceStart + 2 && braceNeg)) {
|
|
inBrace = false;
|
|
}
|
|
acc += c2;
|
|
continue;
|
|
} else if (c2 === "[") {
|
|
inBrace = true;
|
|
braceStart = i2;
|
|
braceNeg = false;
|
|
acc += c2;
|
|
continue;
|
|
}
|
|
if (isExtglobType(c2) && str.charAt(i2) === "(") {
|
|
part.push(acc);
|
|
acc = "";
|
|
const ext2 = new _AST(c2, part);
|
|
part.push(ext2);
|
|
i2 = __privateMethod(_b = _AST, _AST_static, parseAST_fn).call(_b, str, ext2, i2, opt);
|
|
continue;
|
|
}
|
|
if (c2 === "|") {
|
|
part.push(acc);
|
|
acc = "";
|
|
parts.push(part);
|
|
part = new _AST(null, ast);
|
|
continue;
|
|
}
|
|
if (c2 === ")") {
|
|
if (acc === "" && __privateGet(ast, _parts).length === 0) {
|
|
__privateSet(ast, _emptyExt, true);
|
|
}
|
|
part.push(acc);
|
|
acc = "";
|
|
ast.push(...parts, part);
|
|
return i2;
|
|
}
|
|
acc += c2;
|
|
}
|
|
ast.type = null;
|
|
__privateSet(ast, _hasMagic, void 0);
|
|
__privateSet(ast, _parts, [str.substring(pos - 1)]);
|
|
return i2;
|
|
};
|
|
partsToRegExp_fn = function(dot) {
|
|
return __privateGet(this, _parts).map((p2) => {
|
|
if (typeof p2 === "string") {
|
|
throw new Error("string type in extglob ast??");
|
|
}
|
|
const [re, _2, _hasMagic2, uflag] = p2.toRegExpSource(dot);
|
|
__privateSet(this, _uflag, __privateGet(this, _uflag) || uflag);
|
|
return re;
|
|
}).filter((p2) => !(this.isStart() && this.isEnd()) || !!p2).join("|");
|
|
};
|
|
parseGlob_fn = function(glob, hasMagic, noEmpty = false) {
|
|
let escaping = false;
|
|
let re = "";
|
|
let uflag = false;
|
|
for (let i2 = 0; i2 < glob.length; i2++) {
|
|
const c2 = glob.charAt(i2);
|
|
if (escaping) {
|
|
escaping = false;
|
|
re += (reSpecials.has(c2) ? "\\" : "") + c2;
|
|
continue;
|
|
}
|
|
if (c2 === "\\") {
|
|
if (i2 === glob.length - 1) {
|
|
re += "\\\\";
|
|
} else {
|
|
escaping = true;
|
|
}
|
|
continue;
|
|
}
|
|
if (c2 === "[") {
|
|
const [src, needUflag, consumed, magic] = parseClass(glob, i2);
|
|
if (consumed) {
|
|
re += src;
|
|
uflag = uflag || needUflag;
|
|
i2 += consumed - 1;
|
|
hasMagic = hasMagic || magic;
|
|
continue;
|
|
}
|
|
}
|
|
if (c2 === "*") {
|
|
if (noEmpty && glob === "*")
|
|
re += starNoEmpty;
|
|
else
|
|
re += star;
|
|
hasMagic = true;
|
|
continue;
|
|
}
|
|
if (c2 === "?") {
|
|
re += qmark;
|
|
hasMagic = true;
|
|
continue;
|
|
}
|
|
re += regExpEscape(c2);
|
|
}
|
|
return [re, unescape(glob), !!hasMagic, uflag];
|
|
};
|
|
__privateAdd(_AST, _AST_static);
|
|
var AST = _AST;
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/escape.js
|
|
var escape = (s2, { windowsPathsNoEscape = false } = {}) => {
|
|
return windowsPathsNoEscape ? s2.replace(/[?*()[\]]/g, "[$&]") : s2.replace(/[?*()[\]\\]/g, "\\$&");
|
|
};
|
|
|
|
// node_modules/.pnpm/minimatch@10.0.1/node_modules/minimatch/dist/esm/index.js
|
|
var minimatch = (p2, pattern, options = {}) => {
|
|
assertValidPattern(pattern);
|
|
if (!options.nocomment && pattern.charAt(0) === "#") {
|
|
return false;
|
|
}
|
|
return new Minimatch(pattern, options).match(p2);
|
|
};
|
|
var starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
|
|
var starDotExtTest = (ext2) => (f2) => !f2.startsWith(".") && f2.endsWith(ext2);
|
|
var starDotExtTestDot = (ext2) => (f2) => f2.endsWith(ext2);
|
|
var starDotExtTestNocase = (ext2) => {
|
|
ext2 = ext2.toLowerCase();
|
|
return (f2) => !f2.startsWith(".") && f2.toLowerCase().endsWith(ext2);
|
|
};
|
|
var starDotExtTestNocaseDot = (ext2) => {
|
|
ext2 = ext2.toLowerCase();
|
|
return (f2) => f2.toLowerCase().endsWith(ext2);
|
|
};
|
|
var starDotStarRE = /^\*+\.\*+$/;
|
|
var starDotStarTest = (f2) => !f2.startsWith(".") && f2.includes(".");
|
|
var starDotStarTestDot = (f2) => f2 !== "." && f2 !== ".." && f2.includes(".");
|
|
var dotStarRE = /^\.\*+$/;
|
|
var dotStarTest = (f2) => f2 !== "." && f2 !== ".." && f2.startsWith(".");
|
|
var starRE = /^\*+$/;
|
|
var starTest = (f2) => f2.length !== 0 && !f2.startsWith(".");
|
|
var starTestDot = (f2) => f2.length !== 0 && f2 !== "." && f2 !== "..";
|
|
var qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
|
|
var qmarksTestNocase = ([$0, ext2 = ""]) => {
|
|
const noext = qmarksTestNoExt([$0]);
|
|
if (!ext2)
|
|
return noext;
|
|
ext2 = ext2.toLowerCase();
|
|
return (f2) => noext(f2) && f2.toLowerCase().endsWith(ext2);
|
|
};
|
|
var qmarksTestNocaseDot = ([$0, ext2 = ""]) => {
|
|
const noext = qmarksTestNoExtDot([$0]);
|
|
if (!ext2)
|
|
return noext;
|
|
ext2 = ext2.toLowerCase();
|
|
return (f2) => noext(f2) && f2.toLowerCase().endsWith(ext2);
|
|
};
|
|
var qmarksTestDot = ([$0, ext2 = ""]) => {
|
|
const noext = qmarksTestNoExtDot([$0]);
|
|
return !ext2 ? noext : (f2) => noext(f2) && f2.endsWith(ext2);
|
|
};
|
|
var qmarksTest = ([$0, ext2 = ""]) => {
|
|
const noext = qmarksTestNoExt([$0]);
|
|
return !ext2 ? noext : (f2) => noext(f2) && f2.endsWith(ext2);
|
|
};
|
|
var qmarksTestNoExt = ([$0]) => {
|
|
const len = $0.length;
|
|
return (f2) => f2.length === len && !f2.startsWith(".");
|
|
};
|
|
var qmarksTestNoExtDot = ([$0]) => {
|
|
const len = $0.length;
|
|
return (f2) => f2.length === len && f2 !== "." && f2 !== "..";
|
|
};
|
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
var path = {
|
|
win32: { sep: "\\" },
|
|
posix: { sep: "/" }
|
|
};
|
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
minimatch.sep = sep;
|
|
var GLOBSTAR = Symbol("globstar **");
|
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
var qmark2 = "[^/]";
|
|
var star2 = qmark2 + "*?";
|
|
var twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?";
|
|
var twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?";
|
|
var filter = (pattern, options = {}) => (p2) => minimatch(p2, pattern, options);
|
|
minimatch.filter = filter;
|
|
var ext = (a2, b2 = {}) => Object.assign({}, a2, b2);
|
|
var defaults = (def) => {
|
|
if (!def || typeof def !== "object" || !Object.keys(def).length) {
|
|
return minimatch;
|
|
}
|
|
const orig = minimatch;
|
|
const m2 = (p2, pattern, options = {}) => orig(p2, pattern, ext(def, options));
|
|
return Object.assign(m2, {
|
|
Minimatch: class Minimatch extends orig.Minimatch {
|
|
constructor(pattern, options = {}) {
|
|
super(pattern, ext(def, options));
|
|
}
|
|
static defaults(options) {
|
|
return orig.defaults(ext(def, options)).Minimatch;
|
|
}
|
|
},
|
|
AST: class AST extends orig.AST {
|
|
/* c8 ignore start */
|
|
constructor(type, parent, options = {}) {
|
|
super(type, parent, ext(def, options));
|
|
}
|
|
/* c8 ignore stop */
|
|
static fromGlob(pattern, options = {}) {
|
|
return orig.AST.fromGlob(pattern, ext(def, options));
|
|
}
|
|
},
|
|
unescape: (s2, options = {}) => orig.unescape(s2, ext(def, options)),
|
|
escape: (s2, options = {}) => orig.escape(s2, ext(def, options)),
|
|
filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
|
|
defaults: (options) => orig.defaults(ext(def, options)),
|
|
makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
|
|
braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
|
|
match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
|
|
sep: orig.sep,
|
|
GLOBSTAR
|
|
});
|
|
};
|
|
minimatch.defaults = defaults;
|
|
var braceExpand = (pattern, options = {}) => {
|
|
assertValidPattern(pattern);
|
|
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
|
return [pattern];
|
|
}
|
|
return (0, import_brace_expansion.default)(pattern);
|
|
};
|
|
minimatch.braceExpand = braceExpand;
|
|
var makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
|
|
minimatch.makeRe = makeRe;
|
|
var match = (list, pattern, options = {}) => {
|
|
const mm = new Minimatch(pattern, options);
|
|
list = list.filter((f2) => mm.match(f2));
|
|
if (mm.options.nonull && !list.length) {
|
|
list.push(pattern);
|
|
}
|
|
return list;
|
|
};
|
|
minimatch.match = match;
|
|
var globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
|
|
var regExpEscape2 = (s2) => s2.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
var Minimatch = class {
|
|
constructor(pattern, options = {}) {
|
|
__publicField(this, "options");
|
|
__publicField(this, "set");
|
|
__publicField(this, "pattern");
|
|
__publicField(this, "windowsPathsNoEscape");
|
|
__publicField(this, "nonegate");
|
|
__publicField(this, "negate");
|
|
__publicField(this, "comment");
|
|
__publicField(this, "empty");
|
|
__publicField(this, "preserveMultipleSlashes");
|
|
__publicField(this, "partial");
|
|
__publicField(this, "globSet");
|
|
__publicField(this, "globParts");
|
|
__publicField(this, "nocase");
|
|
__publicField(this, "isWindows");
|
|
__publicField(this, "platform");
|
|
__publicField(this, "windowsNoMagicRoot");
|
|
__publicField(this, "regexp");
|
|
assertValidPattern(pattern);
|
|
options = options || {};
|
|
this.options = options;
|
|
this.pattern = pattern;
|
|
this.platform = options.platform || defaultPlatform;
|
|
this.isWindows = this.platform === "win32";
|
|
this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
|
|
if (this.windowsPathsNoEscape) {
|
|
this.pattern = this.pattern.replace(/\\/g, "/");
|
|
}
|
|
this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
|
|
this.regexp = null;
|
|
this.negate = false;
|
|
this.nonegate = !!options.nonegate;
|
|
this.comment = false;
|
|
this.empty = false;
|
|
this.partial = !!options.partial;
|
|
this.nocase = !!this.options.nocase;
|
|
this.windowsNoMagicRoot = options.windowsNoMagicRoot !== void 0 ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase);
|
|
this.globSet = [];
|
|
this.globParts = [];
|
|
this.set = [];
|
|
this.make();
|
|
}
|
|
hasMagic() {
|
|
if (this.options.magicalBraces && this.set.length > 1) {
|
|
return true;
|
|
}
|
|
for (const pattern of this.set) {
|
|
for (const part of pattern) {
|
|
if (typeof part !== "string")
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
debug(..._2) {
|
|
}
|
|
make() {
|
|
const pattern = this.pattern;
|
|
const options = this.options;
|
|
if (!options.nocomment && pattern.charAt(0) === "#") {
|
|
this.comment = true;
|
|
return;
|
|
}
|
|
if (!pattern) {
|
|
this.empty = true;
|
|
return;
|
|
}
|
|
this.parseNegate();
|
|
this.globSet = [...new Set(this.braceExpand())];
|
|
if (options.debug) {
|
|
this.debug = (...args) => console.error(...args);
|
|
}
|
|
this.debug(this.pattern, this.globSet);
|
|
const rawGlobParts = this.globSet.map((s2) => this.slashSplit(s2));
|
|
this.globParts = this.preprocess(rawGlobParts);
|
|
this.debug(this.pattern, this.globParts);
|
|
let set2 = this.globParts.map((s2, _2, __) => {
|
|
if (this.isWindows && this.windowsNoMagicRoot) {
|
|
const isUNC = s2[0] === "" && s2[1] === "" && (s2[2] === "?" || !globMagic.test(s2[2])) && !globMagic.test(s2[3]);
|
|
const isDrive = /^[a-z]:/i.test(s2[0]);
|
|
if (isUNC) {
|
|
return [...s2.slice(0, 4), ...s2.slice(4).map((ss) => this.parse(ss))];
|
|
} else if (isDrive) {
|
|
return [s2[0], ...s2.slice(1).map((ss) => this.parse(ss))];
|
|
}
|
|
}
|
|
return s2.map((ss) => this.parse(ss));
|
|
});
|
|
this.debug(this.pattern, set2);
|
|
this.set = set2.filter((s2) => s2.indexOf(false) === -1);
|
|
if (this.isWindows) {
|
|
for (let i2 = 0; i2 < this.set.length; i2++) {
|
|
const p2 = this.set[i2];
|
|
if (p2[0] === "" && p2[1] === "" && this.globParts[i2][2] === "?" && typeof p2[3] === "string" && /^[a-z]:$/i.test(p2[3])) {
|
|
p2[2] = "?";
|
|
}
|
|
}
|
|
}
|
|
this.debug(this.pattern, this.set);
|
|
}
|
|
// various transforms to equivalent pattern sets that are
|
|
// faster to process in a filesystem walk. The goal is to
|
|
// eliminate what we can, and push all ** patterns as far
|
|
// to the right as possible, even if it increases the number
|
|
// of patterns that we have to process.
|
|
preprocess(globParts) {
|
|
if (this.options.noglobstar) {
|
|
for (let i2 = 0; i2 < globParts.length; i2++) {
|
|
for (let j2 = 0; j2 < globParts[i2].length; j2++) {
|
|
if (globParts[i2][j2] === "**") {
|
|
globParts[i2][j2] = "*";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const { optimizationLevel = 1 } = this.options;
|
|
if (optimizationLevel >= 2) {
|
|
globParts = this.firstPhasePreProcess(globParts);
|
|
globParts = this.secondPhasePreProcess(globParts);
|
|
} else if (optimizationLevel >= 1) {
|
|
globParts = this.levelOneOptimize(globParts);
|
|
} else {
|
|
globParts = this.adjascentGlobstarOptimize(globParts);
|
|
}
|
|
return globParts;
|
|
}
|
|
// just get rid of adjascent ** portions
|
|
adjascentGlobstarOptimize(globParts) {
|
|
return globParts.map((parts) => {
|
|
let gs = -1;
|
|
while (-1 !== (gs = parts.indexOf("**", gs + 1))) {
|
|
let i2 = gs;
|
|
while (parts[i2 + 1] === "**") {
|
|
i2++;
|
|
}
|
|
if (i2 !== gs) {
|
|
parts.splice(gs, i2 - gs);
|
|
}
|
|
}
|
|
return parts;
|
|
});
|
|
}
|
|
// get rid of adjascent ** and resolve .. portions
|
|
levelOneOptimize(globParts) {
|
|
return globParts.map((parts) => {
|
|
parts = parts.reduce((set2, part) => {
|
|
const prev = set2[set2.length - 1];
|
|
if (part === "**" && prev === "**") {
|
|
return set2;
|
|
}
|
|
if (part === "..") {
|
|
if (prev && prev !== ".." && prev !== "." && prev !== "**") {
|
|
set2.pop();
|
|
return set2;
|
|
}
|
|
}
|
|
set2.push(part);
|
|
return set2;
|
|
}, []);
|
|
return parts.length === 0 ? [""] : parts;
|
|
});
|
|
}
|
|
levelTwoFileOptimize(parts) {
|
|
if (!Array.isArray(parts)) {
|
|
parts = this.slashSplit(parts);
|
|
}
|
|
let didSomething = false;
|
|
do {
|
|
didSomething = false;
|
|
if (!this.preserveMultipleSlashes) {
|
|
for (let i2 = 1; i2 < parts.length - 1; i2++) {
|
|
const p2 = parts[i2];
|
|
if (i2 === 1 && p2 === "" && parts[0] === "")
|
|
continue;
|
|
if (p2 === "." || p2 === "") {
|
|
didSomething = true;
|
|
parts.splice(i2, 1);
|
|
i2--;
|
|
}
|
|
}
|
|
if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
|
|
didSomething = true;
|
|
parts.pop();
|
|
}
|
|
}
|
|
let dd = 0;
|
|
while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
|
|
const p2 = parts[dd - 1];
|
|
if (p2 && p2 !== "." && p2 !== ".." && p2 !== "**") {
|
|
didSomething = true;
|
|
parts.splice(dd - 1, 2);
|
|
dd -= 2;
|
|
}
|
|
}
|
|
} while (didSomething);
|
|
return parts.length === 0 ? [""] : parts;
|
|
}
|
|
// First phase: single-pattern processing
|
|
// <pre> is 1 or more portions
|
|
// <rest> is 1 or more portions
|
|
// <p> is any portion other than ., .., '', or **
|
|
// <e> is . or ''
|
|
//
|
|
// **/.. is *brutal* for filesystem walking performance, because
|
|
// it effectively resets the recursive walk each time it occurs,
|
|
// and ** cannot be reduced out by a .. pattern part like a regexp
|
|
// or most strings (other than .., ., and '') can be.
|
|
//
|
|
// <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
|
|
// <pre>/<e>/<rest> -> <pre>/<rest>
|
|
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
|
// **/**/<rest> -> **/<rest>
|
|
//
|
|
// **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
|
|
// this WOULD be allowed if ** did follow symlinks, or * didn't
|
|
firstPhasePreProcess(globParts) {
|
|
let didSomething = false;
|
|
do {
|
|
didSomething = false;
|
|
for (let parts of globParts) {
|
|
let gs = -1;
|
|
while (-1 !== (gs = parts.indexOf("**", gs + 1))) {
|
|
let gss = gs;
|
|
while (parts[gss + 1] === "**") {
|
|
gss++;
|
|
}
|
|
if (gss > gs) {
|
|
parts.splice(gs + 1, gss - gs);
|
|
}
|
|
let next = parts[gs + 1];
|
|
const p2 = parts[gs + 2];
|
|
const p22 = parts[gs + 3];
|
|
if (next !== "..")
|
|
continue;
|
|
if (!p2 || p2 === "." || p2 === ".." || !p22 || p22 === "." || p22 === "..") {
|
|
continue;
|
|
}
|
|
didSomething = true;
|
|
parts.splice(gs, 1);
|
|
const other = parts.slice(0);
|
|
other[gs] = "**";
|
|
globParts.push(other);
|
|
gs--;
|
|
}
|
|
if (!this.preserveMultipleSlashes) {
|
|
for (let i2 = 1; i2 < parts.length - 1; i2++) {
|
|
const p2 = parts[i2];
|
|
if (i2 === 1 && p2 === "" && parts[0] === "")
|
|
continue;
|
|
if (p2 === "." || p2 === "") {
|
|
didSomething = true;
|
|
parts.splice(i2, 1);
|
|
i2--;
|
|
}
|
|
}
|
|
if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
|
|
didSomething = true;
|
|
parts.pop();
|
|
}
|
|
}
|
|
let dd = 0;
|
|
while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
|
|
const p2 = parts[dd - 1];
|
|
if (p2 && p2 !== "." && p2 !== ".." && p2 !== "**") {
|
|
didSomething = true;
|
|
const needDot = dd === 1 && parts[dd + 1] === "**";
|
|
const splin = needDot ? ["."] : [];
|
|
parts.splice(dd - 1, 2, ...splin);
|
|
if (parts.length === 0)
|
|
parts.push("");
|
|
dd -= 2;
|
|
}
|
|
}
|
|
}
|
|
} while (didSomething);
|
|
return globParts;
|
|
}
|
|
// second phase: multi-pattern dedupes
|
|
// {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
|
|
// {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
|
|
// {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
|
|
//
|
|
// {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
|
|
// ^-- not valid because ** doens't follow symlinks
|
|
secondPhasePreProcess(globParts) {
|
|
for (let i2 = 0; i2 < globParts.length - 1; i2++) {
|
|
for (let j2 = i2 + 1; j2 < globParts.length; j2++) {
|
|
const matched = this.partsMatch(globParts[i2], globParts[j2], !this.preserveMultipleSlashes);
|
|
if (matched) {
|
|
globParts[i2] = [];
|
|
globParts[j2] = matched;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return globParts.filter((gs) => gs.length);
|
|
}
|
|
partsMatch(a2, b2, emptyGSMatch = false) {
|
|
let ai = 0;
|
|
let bi = 0;
|
|
let result = [];
|
|
let which = "";
|
|
while (ai < a2.length && bi < b2.length) {
|
|
if (a2[ai] === b2[bi]) {
|
|
result.push(which === "b" ? b2[bi] : a2[ai]);
|
|
ai++;
|
|
bi++;
|
|
} else if (emptyGSMatch && a2[ai] === "**" && b2[bi] === a2[ai + 1]) {
|
|
result.push(a2[ai]);
|
|
ai++;
|
|
} else if (emptyGSMatch && b2[bi] === "**" && a2[ai] === b2[bi + 1]) {
|
|
result.push(b2[bi]);
|
|
bi++;
|
|
} else if (a2[ai] === "*" && b2[bi] && (this.options.dot || !b2[bi].startsWith(".")) && b2[bi] !== "**") {
|
|
if (which === "b")
|
|
return false;
|
|
which = "a";
|
|
result.push(a2[ai]);
|
|
ai++;
|
|
bi++;
|
|
} else if (b2[bi] === "*" && a2[ai] && (this.options.dot || !a2[ai].startsWith(".")) && a2[ai] !== "**") {
|
|
if (which === "a")
|
|
return false;
|
|
which = "b";
|
|
result.push(b2[bi]);
|
|
ai++;
|
|
bi++;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return a2.length === b2.length && result;
|
|
}
|
|
parseNegate() {
|
|
if (this.nonegate)
|
|
return;
|
|
const pattern = this.pattern;
|
|
let negate = false;
|
|
let negateOffset = 0;
|
|
for (let i2 = 0; i2 < pattern.length && pattern.charAt(i2) === "!"; i2++) {
|
|
negate = !negate;
|
|
negateOffset++;
|
|
}
|
|
if (negateOffset)
|
|
this.pattern = pattern.slice(negateOffset);
|
|
this.negate = negate;
|
|
}
|
|
// set partial to true to test if, for example,
|
|
// "/a/b" matches the start of "/*/b/*/d"
|
|
// Partial means, if you run out of file before you run
|
|
// out of pattern, then that's fine, as long as all
|
|
// the parts match.
|
|
matchOne(file, pattern, partial = false) {
|
|
const options = this.options;
|
|
if (this.isWindows) {
|
|
const fileDrive = typeof file[0] === "string" && /^[a-z]:$/i.test(file[0]);
|
|
const fileUNC = !fileDrive && file[0] === "" && file[1] === "" && file[2] === "?" && /^[a-z]:$/i.test(file[3]);
|
|
const patternDrive = typeof pattern[0] === "string" && /^[a-z]:$/i.test(pattern[0]);
|
|
const patternUNC = !patternDrive && pattern[0] === "" && pattern[1] === "" && pattern[2] === "?" && typeof pattern[3] === "string" && /^[a-z]:$/i.test(pattern[3]);
|
|
const fdi = fileUNC ? 3 : fileDrive ? 0 : void 0;
|
|
const pdi = patternUNC ? 3 : patternDrive ? 0 : void 0;
|
|
if (typeof fdi === "number" && typeof pdi === "number") {
|
|
const [fd, pd] = [file[fdi], pattern[pdi]];
|
|
if (fd.toLowerCase() === pd.toLowerCase()) {
|
|
pattern[pdi] = fd;
|
|
if (pdi > fdi) {
|
|
pattern = pattern.slice(pdi);
|
|
} else if (fdi > pdi) {
|
|
file = file.slice(fdi);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const { optimizationLevel = 1 } = this.options;
|
|
if (optimizationLevel >= 2) {
|
|
file = this.levelTwoFileOptimize(file);
|
|
}
|
|
this.debug("matchOne", this, { file, pattern });
|
|
this.debug("matchOne", file.length, pattern.length);
|
|
for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
|
this.debug("matchOne loop");
|
|
var p2 = pattern[pi];
|
|
var f2 = file[fi];
|
|
this.debug(pattern, p2, f2);
|
|
if (p2 === false) {
|
|
return false;
|
|
}
|
|
if (p2 === GLOBSTAR) {
|
|
this.debug("GLOBSTAR", [pattern, p2, f2]);
|
|
var fr = fi;
|
|
var pr = pi + 1;
|
|
if (pr === pl) {
|
|
this.debug("** at the end");
|
|
for (; fi < fl; fi++) {
|
|
if (file[fi] === "." || file[fi] === ".." || !options.dot && file[fi].charAt(0) === ".")
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
while (fr < fl) {
|
|
var swallowee = file[fr];
|
|
this.debug("\nglobstar while", file, fr, pattern, pr, swallowee);
|
|
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
|
this.debug("globstar found match!", fr, fl, swallowee);
|
|
return true;
|
|
} else {
|
|
if (swallowee === "." || swallowee === ".." || !options.dot && swallowee.charAt(0) === ".") {
|
|
this.debug("dot detected!", file, fr, pattern, pr);
|
|
break;
|
|
}
|
|
this.debug("globstar swallow a segment, and continue");
|
|
fr++;
|
|
}
|
|
}
|
|
if (partial) {
|
|
this.debug("\n>>> no match, partial?", file, fr, pattern, pr);
|
|
if (fr === fl) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
let hit;
|
|
if (typeof p2 === "string") {
|
|
hit = f2 === p2;
|
|
this.debug("string match", p2, f2, hit);
|
|
} else {
|
|
hit = p2.test(f2);
|
|
this.debug("pattern match", p2, f2, hit);
|
|
}
|
|
if (!hit)
|
|
return false;
|
|
}
|
|
if (fi === fl && pi === pl) {
|
|
return true;
|
|
} else if (fi === fl) {
|
|
return partial;
|
|
} else if (pi === pl) {
|
|
return fi === fl - 1 && file[fi] === "";
|
|
} else {
|
|
throw new Error("wtf?");
|
|
}
|
|
}
|
|
braceExpand() {
|
|
return braceExpand(this.pattern, this.options);
|
|
}
|
|
parse(pattern) {
|
|
assertValidPattern(pattern);
|
|
const options = this.options;
|
|
if (pattern === "**")
|
|
return GLOBSTAR;
|
|
if (pattern === "")
|
|
return "";
|
|
let m2;
|
|
let fastTest = null;
|
|
if (m2 = pattern.match(starRE)) {
|
|
fastTest = options.dot ? starTestDot : starTest;
|
|
} else if (m2 = pattern.match(starDotExtRE)) {
|
|
fastTest = (options.nocase ? options.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options.dot ? starDotExtTestDot : starDotExtTest)(m2[1]);
|
|
} else if (m2 = pattern.match(qmarksRE)) {
|
|
fastTest = (options.nocase ? options.dot ? qmarksTestNocaseDot : qmarksTestNocase : options.dot ? qmarksTestDot : qmarksTest)(m2);
|
|
} else if (m2 = pattern.match(starDotStarRE)) {
|
|
fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
|
|
} else if (m2 = pattern.match(dotStarRE)) {
|
|
fastTest = dotStarTest;
|
|
}
|
|
const re = AST.fromGlob(pattern, this.options).toMMPattern();
|
|
if (fastTest && typeof re === "object") {
|
|
Reflect.defineProperty(re, "test", { value: fastTest });
|
|
}
|
|
return re;
|
|
}
|
|
makeRe() {
|
|
if (this.regexp || this.regexp === false)
|
|
return this.regexp;
|
|
const set2 = this.set;
|
|
if (!set2.length) {
|
|
this.regexp = false;
|
|
return this.regexp;
|
|
}
|
|
const options = this.options;
|
|
const twoStar = options.noglobstar ? star2 : options.dot ? twoStarDot : twoStarNoDot;
|
|
const flags = new Set(options.nocase ? ["i"] : []);
|
|
let re = set2.map((pattern) => {
|
|
const pp = pattern.map((p2) => {
|
|
if (p2 instanceof RegExp) {
|
|
for (const f2 of p2.flags.split(""))
|
|
flags.add(f2);
|
|
}
|
|
return typeof p2 === "string" ? regExpEscape2(p2) : p2 === GLOBSTAR ? GLOBSTAR : p2._src;
|
|
});
|
|
pp.forEach((p2, i2) => {
|
|
const next = pp[i2 + 1];
|
|
const prev = pp[i2 - 1];
|
|
if (p2 !== GLOBSTAR || prev === GLOBSTAR) {
|
|
return;
|
|
}
|
|
if (prev === void 0) {
|
|
if (next !== void 0 && next !== GLOBSTAR) {
|
|
pp[i2 + 1] = "(?:\\/|" + twoStar + "\\/)?" + next;
|
|
} else {
|
|
pp[i2] = twoStar;
|
|
}
|
|
} else if (next === void 0) {
|
|
pp[i2 - 1] = prev + "(?:\\/|" + twoStar + ")?";
|
|
} else if (next !== GLOBSTAR) {
|
|
pp[i2 - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
|
|
pp[i2 + 1] = GLOBSTAR;
|
|
}
|
|
});
|
|
return pp.filter((p2) => p2 !== GLOBSTAR).join("/");
|
|
}).join("|");
|
|
const [open, close] = set2.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
re = "^" + open + re + close + "$";
|
|
if (this.negate)
|
|
re = "^(?!" + re + ").+$";
|
|
try {
|
|
this.regexp = new RegExp(re, [...flags].join(""));
|
|
} catch (ex) {
|
|
this.regexp = false;
|
|
}
|
|
return this.regexp;
|
|
}
|
|
slashSplit(p2) {
|
|
if (this.preserveMultipleSlashes) {
|
|
return p2.split("/");
|
|
} else if (this.isWindows && /^\/\/[^\/]+/.test(p2)) {
|
|
return ["", ...p2.split(/\/+/)];
|
|
} else {
|
|
return p2.split(/\/+/);
|
|
}
|
|
}
|
|
match(f2, partial = this.partial) {
|
|
this.debug("match", f2, this.pattern);
|
|
if (this.comment) {
|
|
return false;
|
|
}
|
|
if (this.empty) {
|
|
return f2 === "";
|
|
}
|
|
if (f2 === "/" && partial) {
|
|
return true;
|
|
}
|
|
const options = this.options;
|
|
if (this.isWindows) {
|
|
f2 = f2.split("\\").join("/");
|
|
}
|
|
const ff = this.slashSplit(f2);
|
|
this.debug(this.pattern, "split", ff);
|
|
const set2 = this.set;
|
|
this.debug(this.pattern, "set", set2);
|
|
let filename = ff[ff.length - 1];
|
|
if (!filename) {
|
|
for (let i2 = ff.length - 2; !filename && i2 >= 0; i2--) {
|
|
filename = ff[i2];
|
|
}
|
|
}
|
|
for (let i2 = 0; i2 < set2.length; i2++) {
|
|
const pattern = set2[i2];
|
|
let file = ff;
|
|
if (options.matchBase && pattern.length === 1) {
|
|
file = [filename];
|
|
}
|
|
const hit = this.matchOne(file, pattern, partial);
|
|
if (hit) {
|
|
if (options.flipNegate) {
|
|
return true;
|
|
}
|
|
return !this.negate;
|
|
}
|
|
}
|
|
if (options.flipNegate) {
|
|
return false;
|
|
}
|
|
return this.negate;
|
|
}
|
|
static defaults(def) {
|
|
return minimatch.defaults(def).Minimatch;
|
|
}
|
|
};
|
|
minimatch.AST = AST;
|
|
minimatch.Minimatch = Minimatch;
|
|
minimatch.escape = escape;
|
|
minimatch.unescape = unescape;
|
|
|
|
// src/utils/fs.ts
|
|
function isSupportedFileType(path3) {
|
|
return path3.split(".").pop().toLowerCase() === "md";
|
|
}
|
|
function pathMatchesPattern(path3, pattern) {
|
|
return path3.startsWith(pattern) || minimatch(path3, pattern);
|
|
}
|
|
|
|
// src/algorithms/osr/osr-note-graph.ts
|
|
var OsrNoteGraph = class {
|
|
constructor(vaultNoteLinkInfoFinder) {
|
|
// Key: targetFilename
|
|
// Value: Map<sourceFilename, linkCount>
|
|
// This is the number of links from sourceFilename to targetFilename
|
|
// For simplicity, we just store the filename without the directory or filename extension
|
|
this.incomingLinks = {};
|
|
this.pageranks = {};
|
|
this.vaultNoteLinkInfoFinder = vaultNoteLinkInfoFinder;
|
|
this.reset();
|
|
}
|
|
reset() {
|
|
this.incomingLinks = {};
|
|
this.pageranks = {};
|
|
graph.reset();
|
|
}
|
|
processLinks(path3) {
|
|
if (this.incomingLinks[path3] === void 0) {
|
|
this.incomingLinks[path3] = [];
|
|
}
|
|
const targetLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(path3) || {};
|
|
for (const targetPath in targetLinks) {
|
|
if (this.incomingLinks[targetPath] === void 0) this.incomingLinks[targetPath] = [];
|
|
if (isSupportedFileType(targetPath)) {
|
|
const linkCount = targetLinks[targetPath];
|
|
this.incomingLinks[targetPath].push({
|
|
sourcePath: path3,
|
|
linkCount
|
|
});
|
|
graph.link(path3, targetPath, linkCount);
|
|
}
|
|
}
|
|
}
|
|
calcNoteLinkStat(notePath, noteEaseList) {
|
|
let linkTotal = 0, linkPGTotal = 0, totalLinkCount = 0;
|
|
for (const statObj of this.incomingLinks[notePath] || []) {
|
|
const ease = noteEaseList.getEaseByPath(statObj.sourcePath);
|
|
if (ease) {
|
|
linkTotal += statObj.linkCount * this.pageranks[statObj.sourcePath] * ease;
|
|
linkPGTotal += this.pageranks[statObj.sourcePath] * statObj.linkCount;
|
|
totalLinkCount += statObj.linkCount;
|
|
}
|
|
}
|
|
const outgoingLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(notePath) || {};
|
|
for (const outgoingLink in outgoingLinks) {
|
|
const ease = noteEaseList.getEaseByPath(outgoingLink);
|
|
const linkCount = outgoingLinks[outgoingLink];
|
|
const pageRank = this.pageranks[outgoingLink];
|
|
if (ease) {
|
|
linkTotal += linkCount * pageRank * ease;
|
|
linkPGTotal += pageRank * linkCount;
|
|
totalLinkCount += linkCount;
|
|
}
|
|
}
|
|
return { linkTotal, linkPGTotal, totalLinkCount };
|
|
}
|
|
generatePageRanks() {
|
|
graph.rank(0.85, 1e-6, (node, rank2) => {
|
|
this.pageranks[node] = rank2 * 1e4;
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/data-store-algorithm/data-store-algorithm.ts
|
|
var DataStoreAlgorithm = class _DataStoreAlgorithm {
|
|
static getInstance() {
|
|
if (!_DataStoreAlgorithm.instance) {
|
|
throw new Error("there is no DataStoreAlgorithm instance.");
|
|
}
|
|
return _DataStoreAlgorithm.instance;
|
|
}
|
|
};
|
|
|
|
// src/data-stores/base/data-store.ts
|
|
var DataStore = class _DataStore {
|
|
static getInstance() {
|
|
if (!_DataStore.instance) {
|
|
throw new Error("there is no DataStore instance.");
|
|
}
|
|
return _DataStore.instance;
|
|
}
|
|
};
|
|
|
|
// src/topic-path.ts
|
|
var TopicPath = class _TopicPath {
|
|
constructor(path3) {
|
|
if (path3 == null) throw "null path";
|
|
if (path3.some((str) => str.includes("/"))) throw "path entries must not contain '/'";
|
|
this.path = path3;
|
|
}
|
|
get hasPath() {
|
|
return this.path.length > 0;
|
|
}
|
|
get isEmptyPath() {
|
|
return !this.hasPath;
|
|
}
|
|
static get emptyPath() {
|
|
return new _TopicPath([]);
|
|
}
|
|
shift() {
|
|
if (this.isEmptyPath) throw "can't shift an empty path";
|
|
return this.path.shift();
|
|
}
|
|
clone() {
|
|
return new _TopicPath([...this.path]);
|
|
}
|
|
formatAsTag() {
|
|
if (this.isEmptyPath) throw "Empty path";
|
|
const result = "#" + this.path.join("/");
|
|
return result;
|
|
}
|
|
static getTopicPathOfFile(noteFile, settings) {
|
|
let deckPath = [];
|
|
let result = _TopicPath.emptyPath;
|
|
if (settings.convertFoldersToDecks) {
|
|
deckPath = noteFile.path.split("/");
|
|
deckPath.pop();
|
|
if (deckPath.length != 0) {
|
|
result = new _TopicPath(deckPath);
|
|
}
|
|
} else {
|
|
const tagList = this.getTopicPathsFromTagList(
|
|
noteFile.getAllTagsFromCache()
|
|
);
|
|
outer: for (const tagToReview of this.getTopicPathsFromTagList(
|
|
settings.flashcardTags
|
|
)) {
|
|
for (const tag of tagList) {
|
|
if (tagToReview.isSameOrAncestorOf(tag)) {
|
|
result = tag;
|
|
break outer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
isSameOrAncestorOf(topicPath) {
|
|
if (this.isEmptyPath) return topicPath.isEmptyPath;
|
|
if (this.path.length > topicPath.path.length) return false;
|
|
for (let i2 = 0; i2 < this.path.length; i2++) {
|
|
if (this.path[i2] != topicPath.path[i2]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
static getTopicPathFromCardText(cardText) {
|
|
var _a;
|
|
const path3 = (_a = cardText.trimStart().match(OBSIDIAN_TAG_AT_STARTOFLINE_REGEX)) == null ? void 0 : _a.slice(-1)[0];
|
|
return (path3 == null ? void 0 : path3.length) > 0 ? _TopicPath.getTopicPathFromTag(path3) : null;
|
|
}
|
|
static getTopicPathsFromTagList(tagList) {
|
|
const result = [];
|
|
for (const tag of tagList) {
|
|
if (this.isValidTag(tag)) result.push(_TopicPath.getTopicPathFromTag(tag));
|
|
}
|
|
return result;
|
|
}
|
|
static isValidTag(tag) {
|
|
if (tag == null || tag.length == 0) return false;
|
|
if (tag[0] != "#") return false;
|
|
if (tag.length == 1) return false;
|
|
return true;
|
|
}
|
|
static getTopicPathFromTag(tag) {
|
|
if (tag == null || tag.length == 0) throw "Null/empty tag";
|
|
if (tag[0] != "#") throw "Tag must start with #";
|
|
if (tag.length == 1) throw "Invalid tag";
|
|
const path3 = tag.replace("#", "").split("/").filter((str) => str);
|
|
return new _TopicPath(path3);
|
|
}
|
|
static getFolderPathFromFilename(noteFile, settings) {
|
|
let result = _TopicPath.emptyPath;
|
|
if (settings.convertFoldersToDecks) {
|
|
const deckPath = noteFile.path.split("/");
|
|
deckPath.pop();
|
|
if (deckPath.length != 0) {
|
|
result = new _TopicPath(deckPath);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
var TopicPathList = class _TopicPathList {
|
|
constructor(list, lineNum = null) {
|
|
if (list == null) throw "TopicPathList null";
|
|
this.list = list;
|
|
this.lineNum = lineNum;
|
|
}
|
|
get length() {
|
|
return this.list.length;
|
|
}
|
|
isAnyElementSameOrAncestorOf(topicPath) {
|
|
return this.list.some((item) => item.isSameOrAncestorOf(topicPath));
|
|
}
|
|
formatPsv() {
|
|
return this.format("|");
|
|
}
|
|
format(sep2) {
|
|
return this.list.map((topicPath) => topicPath.formatAsTag()).join(sep2);
|
|
}
|
|
static empty() {
|
|
return new _TopicPathList([]);
|
|
}
|
|
static fromPsv(str, lineNum) {
|
|
const result = _TopicPathList.convertTagListToTopicPathList(str.split("|"));
|
|
result.lineNum = lineNum;
|
|
return result;
|
|
}
|
|
//
|
|
// tagList is a list of tags such as:
|
|
// ["#flashcards/computing", "#boring-stuff", "#news-worthy"]
|
|
// validTopicPathList is a list of valid tags, such as those from settings.flashcardTags,E.g.
|
|
// ["#flashcards"]
|
|
//
|
|
// This returns a filtered version of tagList, containing only topic paths that are considered valid.
|
|
// Validity is defined as "isAnyElementSameOrAncestorOf", and "#flashcards" is considered the ancestor of
|
|
// "#flashcards/computing".
|
|
//
|
|
// Therefore this would return:
|
|
// "#flashcards/computing" (but not "#boring-stuff" or "#news-worthy")
|
|
//
|
|
static filterValidTopicPathsFromTagList(list, validTopicPathList, lineNum = null) {
|
|
const result = [];
|
|
for (const tag of list.list) {
|
|
if (validTopicPathList.isAnyElementSameOrAncestorOf(tag)) result.push(tag);
|
|
}
|
|
return new _TopicPathList(result, lineNum);
|
|
}
|
|
static convertTagListToTopicPathList(tagList) {
|
|
const result = [];
|
|
for (const tag of tagList) {
|
|
if (TopicPath.isValidTag(tag)) result.push(TopicPath.getTopicPathFromTag(tag));
|
|
}
|
|
return new _TopicPathList(result);
|
|
}
|
|
};
|
|
var TopicPathWithWs = class {
|
|
constructor(topicPath, preWhitespace, postWhitespace) {
|
|
if (!topicPath || topicPath.isEmptyPath) throw "topicPath null";
|
|
this.topicPath = topicPath;
|
|
this.preWhitespace = preWhitespace;
|
|
this.postWhitespace = postWhitespace;
|
|
}
|
|
formatWithWs() {
|
|
return `${this.preWhitespace}${this.topicPath.formatAsTag()}${this.postWhitespace}`;
|
|
}
|
|
};
|
|
|
|
// src/flashcard-review-sequencer.ts
|
|
var DeckStats = class {
|
|
constructor(dueCount, newCount, totalCount) {
|
|
this.dueCount = dueCount;
|
|
this.newCount = newCount;
|
|
this.totalCount = totalCount;
|
|
}
|
|
};
|
|
var FlashcardReviewSequencer = class {
|
|
constructor(reviewMode, cardSequencer, settings, srsAlgorithm, questionPostponementList, dueDateFlashcardHistogram) {
|
|
this.reviewMode = reviewMode;
|
|
this.cardSequencer = cardSequencer;
|
|
this.settings = settings;
|
|
this.srsAlgorithm = srsAlgorithm;
|
|
this.questionPostponementList = questionPostponementList;
|
|
this.dueDateFlashcardHistogram = dueDateFlashcardHistogram;
|
|
}
|
|
get hasCurrentCard() {
|
|
return this.cardSequencer.currentCard != null;
|
|
}
|
|
get currentCard() {
|
|
return this.cardSequencer.currentCard;
|
|
}
|
|
get currentQuestion() {
|
|
var _a;
|
|
return (_a = this.currentCard) == null ? void 0 : _a.question;
|
|
}
|
|
get currentDeck() {
|
|
return this.cardSequencer.currentDeck;
|
|
}
|
|
get currentNote() {
|
|
return this.currentQuestion.note;
|
|
}
|
|
// originalDeckTree isn't modified by the review process
|
|
// Only remainingDeckTree
|
|
setDeckTree(originalDeckTree, remainingDeckTree) {
|
|
this.cardSequencer.setBaseDeck(remainingDeckTree);
|
|
this._originalDeckTree = originalDeckTree;
|
|
this.remainingDeckTree = remainingDeckTree;
|
|
this.setCurrentDeck(TopicPath.emptyPath);
|
|
}
|
|
setCurrentDeck(topicPath) {
|
|
this.cardSequencer.setIteratorTopicPath(topicPath);
|
|
this.cardSequencer.nextCard();
|
|
}
|
|
get originalDeckTree() {
|
|
return this._originalDeckTree;
|
|
}
|
|
getDeckStats(topicPath) {
|
|
const totalCount = this._originalDeckTree.getDeck(topicPath).getDistinctCardCount(2 /* All */, true);
|
|
const remainingDeck = this.remainingDeckTree.getDeck(topicPath);
|
|
const newCount = remainingDeck.getDistinctCardCount(0 /* NewCard */, true);
|
|
const dueCount = remainingDeck.getDistinctCardCount(1 /* DueCard */, true);
|
|
return new DeckStats(dueCount, newCount, totalCount);
|
|
}
|
|
skipCurrentCard() {
|
|
this.cardSequencer.deleteCurrentQuestionFromAllDecks();
|
|
}
|
|
deleteCurrentCard() {
|
|
this.cardSequencer.deleteCurrentCardFromAllDecks();
|
|
}
|
|
async processReview(response) {
|
|
switch (this.reviewMode) {
|
|
case 1 /* Review */:
|
|
await this.processReviewReviewMode(response);
|
|
break;
|
|
case 0 /* Cram */:
|
|
await this.processReviewCramMode(response);
|
|
break;
|
|
}
|
|
}
|
|
async processReviewReviewMode(response) {
|
|
if (response != 3 /* Reset */ || this.currentCard.hasSchedule) {
|
|
const oldSchedule = this.currentCard.scheduleInfo;
|
|
this.currentCard.scheduleInfo = this.determineCardSchedule(response, this.currentCard);
|
|
await DataStore.getInstance().questionWriteSchedule(this.currentQuestion);
|
|
if (oldSchedule) {
|
|
const today = globalDateProvider.today.valueOf();
|
|
const nDays = Math.ceil(
|
|
(oldSchedule.dueDateAsUnix - today) / TICKS_PER_DAY
|
|
);
|
|
this.dueDateFlashcardHistogram.decrement(nDays);
|
|
}
|
|
this.dueDateFlashcardHistogram.increment(this.currentCard.scheduleInfo.interval);
|
|
}
|
|
if (response == 3 /* Reset */) {
|
|
this.cardSequencer.moveCurrentCardToEndOfList();
|
|
this.cardSequencer.nextCard();
|
|
} else {
|
|
if (this.settings.burySiblingCards) {
|
|
await this.burySiblingCards();
|
|
this.cardSequencer.deleteCurrentQuestionFromAllDecks();
|
|
} else {
|
|
this.deleteCurrentCard();
|
|
}
|
|
}
|
|
}
|
|
async burySiblingCards() {
|
|
const remaining = this.currentDeck.getQuestionCardCount(this.currentQuestion);
|
|
if (remaining > 1) {
|
|
this.questionPostponementList.add(this.currentQuestion);
|
|
await this.questionPostponementList.write();
|
|
}
|
|
}
|
|
async processReviewCramMode(response) {
|
|
if (response == 0 /* Easy */) this.deleteCurrentCard();
|
|
else {
|
|
this.cardSequencer.moveCurrentCardToEndOfList();
|
|
this.cardSequencer.nextCard();
|
|
}
|
|
}
|
|
determineCardSchedule(response, card) {
|
|
let result;
|
|
if (response == 3 /* Reset */) {
|
|
result = this.srsAlgorithm.cardGetResetSchedule();
|
|
} else {
|
|
if (card.hasSchedule) {
|
|
result = this.srsAlgorithm.cardCalcUpdatedSchedule(
|
|
response,
|
|
card.scheduleInfo,
|
|
this.dueDateFlashcardHistogram
|
|
);
|
|
} else {
|
|
const currentNote = card.question.note;
|
|
result = this.srsAlgorithm.cardGetNewSchedule(
|
|
response,
|
|
currentNote.filePath,
|
|
this.dueDateFlashcardHistogram
|
|
);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
async updateCurrentQuestionText(text) {
|
|
const q2 = this.currentQuestion.questionText;
|
|
q2.actualQuestion = text;
|
|
await DataStore.getInstance().questionWrite(this.currentQuestion);
|
|
}
|
|
};
|
|
|
|
// src/deck.ts
|
|
var Deck2 = class _Deck {
|
|
constructor(deckName, parent) {
|
|
this.deckName = deckName;
|
|
this.newFlashcards = [];
|
|
this.dueFlashcards = [];
|
|
this.subdecks = [];
|
|
this.parent = parent;
|
|
}
|
|
getCardCount(cardListType, includeSubdeckCounts) {
|
|
let result = 0;
|
|
if (cardListType == 0 /* NewCard */ || cardListType == 2 /* All */)
|
|
result += this.newFlashcards.length;
|
|
if (cardListType == 1 /* DueCard */ || cardListType == 2 /* All */)
|
|
result += this.dueFlashcards.length;
|
|
if (includeSubdeckCounts) {
|
|
for (const deck of this.subdecks) {
|
|
result += deck.getCardCount(cardListType, includeSubdeckCounts);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
getDistinctCardCount(cardListType, includeSubdeckCounts) {
|
|
const cardList = this.getFlattenedCardArray(cardListType, includeSubdeckCounts);
|
|
const distinctCardSet = new Set(cardList);
|
|
return distinctCardSet.size;
|
|
}
|
|
getFlattenedCardArray(cardListType, includeSubdeckCounts) {
|
|
let result = [];
|
|
switch (cardListType) {
|
|
case 0 /* NewCard */:
|
|
result = this.newFlashcards;
|
|
break;
|
|
case 1 /* DueCard */:
|
|
result = this.dueFlashcards;
|
|
break;
|
|
case 2 /* All */:
|
|
result = this.newFlashcards.concat(this.dueFlashcards);
|
|
}
|
|
if (includeSubdeckCounts) {
|
|
for (const subdeck of this.subdecks) {
|
|
result = result.concat(
|
|
subdeck.getFlattenedCardArray(cardListType, includeSubdeckCounts)
|
|
);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// Returns a count of the number of this question's cards are present in this deck.
|
|
// (The returned value would be <= question.cards.length)
|
|
getQuestionCardCount(question) {
|
|
let result = 0;
|
|
result += this.getQuestionCardCountForCardListType(question, this.newFlashcards);
|
|
result += this.getQuestionCardCountForCardListType(question, this.dueFlashcards);
|
|
return result;
|
|
}
|
|
getQuestionCardCountForCardListType(question, cards) {
|
|
let result = 0;
|
|
for (let i2 = 0; i2 < cards.length; i2++) {
|
|
if (Object.is(question, cards[i2].question)) result++;
|
|
}
|
|
return result;
|
|
}
|
|
static get emptyDeck() {
|
|
return new _Deck("Root", null);
|
|
}
|
|
get isRootDeck() {
|
|
return this.parent == null;
|
|
}
|
|
getDeckByTopicTag(tag) {
|
|
return this.getDeck(TopicPath.getTopicPathFromTag(tag));
|
|
}
|
|
getDeck(topicPath) {
|
|
return this._getOrCreateDeck(topicPath, false);
|
|
}
|
|
getOrCreateDeck(topicPath) {
|
|
return this._getOrCreateDeck(topicPath, true);
|
|
}
|
|
_getOrCreateDeck(topicPath, createAllowed) {
|
|
if (!topicPath.hasPath) {
|
|
return this;
|
|
}
|
|
const t3 = topicPath.clone();
|
|
const deckName = t3.shift();
|
|
for (const subdeck of this.subdecks) {
|
|
if (deckName === subdeck.deckName) {
|
|
return subdeck._getOrCreateDeck(t3, createAllowed);
|
|
}
|
|
}
|
|
let result = null;
|
|
if (createAllowed) {
|
|
const subdeck = new _Deck(
|
|
deckName,
|
|
this
|
|
/* parent */
|
|
);
|
|
this.subdecks.push(subdeck);
|
|
result = subdeck._getOrCreateDeck(t3, createAllowed);
|
|
}
|
|
return result;
|
|
}
|
|
getTopicPath() {
|
|
const list = [];
|
|
let deck = this;
|
|
while (!deck.isRootDeck) {
|
|
list.push(deck.deckName);
|
|
deck = deck.parent;
|
|
}
|
|
return new TopicPath(list.reverse());
|
|
}
|
|
getRootDeck() {
|
|
let deck = this;
|
|
while (!deck.isRootDeck) {
|
|
deck = deck.parent;
|
|
}
|
|
return deck;
|
|
}
|
|
getCard(index, cardListType) {
|
|
const cardList = this.getCardListForCardType(cardListType);
|
|
return cardList[index];
|
|
}
|
|
getCardListForCardType(cardListType) {
|
|
return cardListType == 1 /* DueCard */ ? this.dueFlashcards : this.newFlashcards;
|
|
}
|
|
appendCard(topicPathList, cardObj) {
|
|
if (topicPathList.list.length == 0) {
|
|
this.appendCardToRootDeck(cardObj);
|
|
} else {
|
|
for (const topicPath of topicPathList.list) {
|
|
this.appendCardSingleTopic(topicPath, cardObj);
|
|
}
|
|
}
|
|
}
|
|
appendCardToRootDeck(cardObj) {
|
|
this.appendCardSingleTopic(TopicPath.emptyPath, cardObj);
|
|
}
|
|
appendCardSingleTopic(topicPath, cardObj) {
|
|
const deck = this.getOrCreateDeck(topicPath);
|
|
const cardList = deck.getCardListForCardType(cardObj.cardListType);
|
|
cardList.push(cardObj);
|
|
}
|
|
// The question lists all the topics in which this card is included.
|
|
// The topics are relative to the base deck, and this method must be called on that deck
|
|
deleteQuestionFromAllDecks(question, exceptionIfMissing) {
|
|
for (const card of question.cards) {
|
|
this.deleteCardFromAllDecks(card, exceptionIfMissing);
|
|
}
|
|
}
|
|
deleteQuestion(question, exceptionIfMissing) {
|
|
for (const card of question.cards) {
|
|
this.deleteCardFromThisDeck(card, exceptionIfMissing);
|
|
}
|
|
}
|
|
// The card's question lists all the topics in which this card is included.
|
|
// The topics are relative to the base deck, and this method must be called on that deck
|
|
deleteCardFromAllDecks(card, exceptionIfMissing) {
|
|
for (const topicPath of card.question.topicPathList.list) {
|
|
const deck = this.getDeck(topicPath);
|
|
deck.deleteCardFromThisDeck(card, exceptionIfMissing);
|
|
}
|
|
}
|
|
deleteCardFromThisDeck(card, exceptionIfMissing) {
|
|
const newIdx = this.newFlashcards.indexOf(card);
|
|
if (newIdx != -1) this.newFlashcards.splice(newIdx, 1);
|
|
const dueIdx = this.dueFlashcards.indexOf(card);
|
|
if (dueIdx != -1) this.dueFlashcards.splice(dueIdx, 1);
|
|
if (newIdx == -1 && dueIdx == -1 && exceptionIfMissing) {
|
|
throw `deleteCardFromThisDeck: Card: ${card.front} not found in deck: ${this.deckName}`;
|
|
}
|
|
}
|
|
deleteCardAtIndex(index, cardListType) {
|
|
const cardList = this.getCardListForCardType(cardListType);
|
|
cardList.splice(index, 1);
|
|
}
|
|
toDeckArray() {
|
|
const result = [];
|
|
result.push(this);
|
|
for (const subdeck of this.subdecks) {
|
|
result.push(...subdeck.toDeckArray());
|
|
}
|
|
return result;
|
|
}
|
|
sortSubdecksList() {
|
|
this.subdecks.sort((a2, b2) => {
|
|
if (a2.deckName < b2.deckName) {
|
|
return -1;
|
|
} else if (a2.deckName > b2.deckName) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
for (const deck of this.subdecks) {
|
|
deck.sortSubdecksList();
|
|
}
|
|
}
|
|
debugLogToConsole(desc = null, indent = 0) {
|
|
let str = desc != null ? `${desc}: ` : "";
|
|
console.log(str += this.toString(indent));
|
|
}
|
|
toString(indent = 0) {
|
|
let result = "";
|
|
let indentStr = " ".repeat(indent * 4);
|
|
result += `${indentStr}${this.deckName}\r
|
|
`;
|
|
indentStr += " ";
|
|
for (let i2 = 0; i2 < this.newFlashcards.length; i2++) {
|
|
const card = this.newFlashcards[i2];
|
|
result += `${indentStr}New: ${i2}: ${card.front}::${card.back}\r
|
|
`;
|
|
}
|
|
for (let i2 = 0; i2 < this.dueFlashcards.length; i2++) {
|
|
const card = this.dueFlashcards[i2];
|
|
const s2 = card.isDue ? "Due" : "Not due";
|
|
result += `${indentStr}${s2}: ${i2}: ${card.front}::${card.back}\r
|
|
`;
|
|
}
|
|
for (const subdeck of this.subdecks) {
|
|
result += subdeck.toString(indent + 1);
|
|
}
|
|
return result;
|
|
}
|
|
clone() {
|
|
return this.copyWithCardFilter(() => true);
|
|
}
|
|
copyWithCardFilter(predicate, parent = null) {
|
|
const result = new _Deck(this.deckName, parent);
|
|
result.newFlashcards = [...this.newFlashcards.filter((card) => predicate(card))];
|
|
result.dueFlashcards = [...this.dueFlashcards.filter((card) => predicate(card))];
|
|
for (const s2 of this.subdecks) {
|
|
const newParent = result;
|
|
const newDeck = s2.copyWithCardFilter(predicate, newParent);
|
|
result.subdecks.push(newDeck);
|
|
}
|
|
return result;
|
|
}
|
|
static otherListType(cardListType) {
|
|
let result;
|
|
if (cardListType == 0 /* NewCard */) result = 1 /* DueCard */;
|
|
else if (cardListType == 1 /* DueCard */) result = 0 /* NewCard */;
|
|
else throw "Invalid cardListType";
|
|
return result;
|
|
}
|
|
};
|
|
var DeckTreeFilter = class {
|
|
static filterForReviewableCards(reviewableDeckTree) {
|
|
return reviewableDeckTree.copyWithCardFilter((card) => !card.question.hasEditLaterTag);
|
|
}
|
|
static filterForRemainingCards(questionPostponementList, deckTree, reviewMode) {
|
|
return deckTree.copyWithCardFilter(
|
|
(card) => (reviewMode == 0 /* Cram */ || card.isNew || card.isDue) && !questionPostponementList.includes(card.question)
|
|
);
|
|
}
|
|
};
|
|
|
|
// src/utils/types.ts
|
|
function getTypedObjectEntries(obj) {
|
|
return Object.entries(obj);
|
|
}
|
|
var getKeysPreserveType = Object.keys;
|
|
function mapRecord(record, transform) {
|
|
return Object.fromEntries(
|
|
Object.entries(record).map(([key, value]) => transform(key, value))
|
|
);
|
|
}
|
|
|
|
// src/utils/numbers.ts
|
|
var ValueCountDict = class {
|
|
constructor() {
|
|
this.dict = {};
|
|
}
|
|
// Record<value, count>
|
|
clearCountIfMissing(value) {
|
|
if (!this.hasValue(value)) this.dict[value] = 0;
|
|
}
|
|
hasValue(value) {
|
|
return Object.prototype.hasOwnProperty.call(this.dict, value);
|
|
}
|
|
incrementCount(value) {
|
|
this.clearCountIfMissing(value);
|
|
this.dict[value]++;
|
|
}
|
|
getMaxValue() {
|
|
return Math.max(...getKeysPreserveType(this.dict)) || 0;
|
|
}
|
|
getTotalOfValueMultiplyCount() {
|
|
const v2 = getTypedObjectEntries(this.dict).map(([value, count]) => value * count).reduce((a2, b2) => a2 + b2, 0) || 0;
|
|
return v2;
|
|
}
|
|
};
|
|
var RandomNumberProvider = class {
|
|
getInteger(lowerBound, upperBound) {
|
|
const range = upperBound - lowerBound + 1;
|
|
return Math.floor(Math.random() * range) + lowerBound;
|
|
}
|
|
};
|
|
var StaticRandomNumberProvider = class {
|
|
getInteger(lowerBound, upperBound) {
|
|
if (lowerBound != this.expectedLowerBound || upperBound != this.expectedUpperBound)
|
|
throw `lowerBound: A${lowerBound}/E${this.expectedLowerBound}, upperBound: A${upperBound}/E${this.expectedUpperBound}`;
|
|
return this.next;
|
|
}
|
|
};
|
|
var WeightedRandomNumber = class _WeightedRandomNumber {
|
|
constructor(provider) {
|
|
this.provider = provider;
|
|
}
|
|
static create() {
|
|
return new _WeightedRandomNumber(globalRandomNumberProvider);
|
|
}
|
|
// weights is a dictionary:
|
|
// first number - a key that can be returned
|
|
// second number - the "bucket size" - this is a weight that influences the probability of the
|
|
// first number being returned
|
|
//
|
|
// returns:
|
|
// first number - one of the keys from the weights parameter
|
|
// second number - an "index" value; 0 <= index < bucketSize
|
|
getRandomValues(weights) {
|
|
const total = _WeightedRandomNumber.calcTotalOfCount(weights);
|
|
if (Object.values(weights).some((i2) => !Number.isInteger(i2) || i2 < 0))
|
|
throw "All weights must be positive integers";
|
|
const v2 = this.provider.getInteger(0, total - 1);
|
|
let x2 = 0;
|
|
for (const kvp in weights) {
|
|
const [value, count] = [Number(kvp), weights[kvp]];
|
|
if (v2 < x2 + count) {
|
|
const index = v2 - x2;
|
|
return [value, index];
|
|
}
|
|
x2 += count;
|
|
}
|
|
throw "";
|
|
}
|
|
static calcTotalOfCount(weights) {
|
|
const total = getTypedObjectEntries(weights).map(([_2, count]) => count).reduce((a2, b2) => a2 + b2, 0) || 0;
|
|
return total;
|
|
}
|
|
};
|
|
var globalRandomNumberProvider = new RandomNumberProvider();
|
|
var staticRandomNumberProvider = new StaticRandomNumberProvider();
|
|
|
|
// src/deck-tree-iterator.ts
|
|
var CardOrder = /* @__PURE__ */ ((CardOrder2) => {
|
|
CardOrder2[CardOrder2["NewFirstSequential"] = 0] = "NewFirstSequential";
|
|
CardOrder2[CardOrder2["NewFirstRandom"] = 1] = "NewFirstRandom";
|
|
CardOrder2[CardOrder2["DueFirstSequential"] = 2] = "DueFirstSequential";
|
|
CardOrder2[CardOrder2["DueFirstRandom"] = 3] = "DueFirstRandom";
|
|
CardOrder2[CardOrder2["EveryCardRandomDeckAndCard"] = 4] = "EveryCardRandomDeckAndCard";
|
|
return CardOrder2;
|
|
})(CardOrder || {});
|
|
var DeckOrder = /* @__PURE__ */ ((DeckOrder2) => {
|
|
DeckOrder2[DeckOrder2["PrevDeckComplete_Sequential"] = 0] = "PrevDeckComplete_Sequential";
|
|
DeckOrder2[DeckOrder2["PrevDeckComplete_Random"] = 1] = "PrevDeckComplete_Random";
|
|
return DeckOrder2;
|
|
})(DeckOrder || {});
|
|
var SingleDeckIterator = class _SingleDeckIterator {
|
|
get hasCurrentCard() {
|
|
return this.cardIdx != null;
|
|
}
|
|
get currentCard() {
|
|
let result = null;
|
|
if (this.cardIdx != null) result = this.deck.getCard(this.cardIdx, this.cardListType);
|
|
return result;
|
|
}
|
|
constructor(iteratorOrder) {
|
|
this.iteratorOrder = iteratorOrder;
|
|
this.preferredCardListType = _SingleDeckIterator.getCardListTypeForIterator(
|
|
this.iteratorOrder
|
|
);
|
|
this.weightedRandomNumber = WeightedRandomNumber.create();
|
|
}
|
|
setDeck(deck) {
|
|
this.deck = deck;
|
|
this.setCardListType(null);
|
|
}
|
|
//
|
|
// 0 <= cardIndex < newFlashcards.length + dueFlashcards.length
|
|
//
|
|
setNewOrDueCardIdx(cardIndex) {
|
|
let cardListType = 0 /* NewCard */;
|
|
let index = cardIndex;
|
|
if (cardIndex >= this.deck.newFlashcards.length) {
|
|
cardListType = 1 /* DueCard */;
|
|
index = cardIndex - this.deck.newFlashcards.length;
|
|
}
|
|
this.setCardListType(cardListType, index);
|
|
}
|
|
setCardListType(cardListType, cardIdx = null) {
|
|
this.cardListType = cardListType;
|
|
this.cardIdx = cardIdx;
|
|
}
|
|
nextCard() {
|
|
if (this.iteratorOrder.cardOrder == 4 /* EveryCardRandomDeckAndCard */) {
|
|
this.nextRandomCard();
|
|
} else {
|
|
if (this.cardListType == null) {
|
|
this.setCardListType(this.preferredCardListType);
|
|
}
|
|
if (!this.nextCardWithinCurrentList()) {
|
|
if (this.cardListType == this.preferredCardListType) {
|
|
this.setCardListType(Deck2.otherListType(this.cardListType));
|
|
if (!this.nextCardWithinCurrentList()) {
|
|
this.setCardListType(null);
|
|
}
|
|
} else {
|
|
this.cardIdx = null;
|
|
}
|
|
}
|
|
}
|
|
return this.cardIdx != null;
|
|
}
|
|
nextRandomCard() {
|
|
const newCount = this.deck.newFlashcards.length;
|
|
const dueCount = this.deck.dueFlashcards.length;
|
|
if (newCount + dueCount > 0) {
|
|
const weights = {};
|
|
if (newCount > 0) weights[0 /* NewCard */] = newCount;
|
|
if (dueCount > 0) weights[1 /* DueCard */] = dueCount;
|
|
const [cardListType, index] = this.weightedRandomNumber.getRandomValues(weights);
|
|
this.setCardListType(cardListType, index);
|
|
} else {
|
|
this.setCardListType(null);
|
|
}
|
|
}
|
|
nextCardWithinCurrentList() {
|
|
const cardList = this.deck.getCardListForCardType(this.cardListType);
|
|
const result = cardList.length > 0;
|
|
if (result) {
|
|
switch (this.iteratorOrder.cardOrder) {
|
|
case 2 /* DueFirstSequential */:
|
|
case 0 /* NewFirstSequential */:
|
|
this.cardIdx = 0;
|
|
break;
|
|
case 3 /* DueFirstRandom */:
|
|
case 1 /* NewFirstRandom */:
|
|
this.cardIdx = globalRandomNumberProvider.getInteger(0, cardList.length - 1);
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
moveCurrentCardToEndOfList() {
|
|
this.ensureCurrentCard();
|
|
const cardList = this.deck.getCardListForCardType(this.cardListType);
|
|
if (cardList.length <= 1) return;
|
|
const card = this.currentCard;
|
|
this.deck.deleteCardAtIndex(this.cardIdx, this.cardListType);
|
|
this.deck.appendCardToRootDeck(card);
|
|
this.setNoCurrentCard();
|
|
}
|
|
setNoCurrentCard() {
|
|
this.cardIdx = null;
|
|
}
|
|
ensureCurrentCard() {
|
|
if (this.cardIdx == null || this.cardListType == null) throw "no current card";
|
|
}
|
|
static getCardListTypeForIterator(iteratorOrder) {
|
|
let result = null;
|
|
switch (iteratorOrder.cardOrder) {
|
|
case 3 /* DueFirstRandom */:
|
|
case 2 /* DueFirstSequential */:
|
|
result = 1 /* DueCard */;
|
|
break;
|
|
case 1 /* NewFirstRandom */:
|
|
case 0 /* NewFirstSequential */:
|
|
result = 0 /* NewCard */;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
var DeckTreeIterator = class _DeckTreeIterator {
|
|
get hasCurrentCard() {
|
|
return this.deckIdx != null && this.singleDeckIterator.hasCurrentCard;
|
|
}
|
|
get currentTopicPath() {
|
|
var _a;
|
|
return (_a = this.currentDeck) == null ? void 0 : _a.getTopicPath();
|
|
}
|
|
get currentDeck() {
|
|
if (this.deckIdx == null) return null;
|
|
return this.deckArray[this.deckIdx];
|
|
}
|
|
get currentCard() {
|
|
let result = null;
|
|
if (this.deckIdx != null && this.singleDeckIterator.hasCurrentCard)
|
|
result = this.singleDeckIterator.currentCard;
|
|
return result;
|
|
}
|
|
get currentQuestion() {
|
|
var _a;
|
|
return (_a = this.currentCard) == null ? void 0 : _a.question;
|
|
}
|
|
constructor(iteratorOrder, baseDeckTree) {
|
|
this.singleDeckIterator = new SingleDeckIterator(iteratorOrder);
|
|
this.iteratorOrder = iteratorOrder;
|
|
this.weightedRandomNumber = WeightedRandomNumber.create();
|
|
this.setBaseDeck(baseDeckTree);
|
|
}
|
|
setBaseDeck(baseDeck) {
|
|
this.baseDeckTree = baseDeck;
|
|
this.singleDeckIterator.setNoCurrentCard();
|
|
}
|
|
setIteratorTopicPath(topicPath) {
|
|
const iteratorDeck = this.baseDeckTree.getDeck(topicPath);
|
|
this.deckArray = _DeckTreeIterator.filterForDecksWithCards(iteratorDeck.toDeckArray());
|
|
this.setDeckIdx(null);
|
|
}
|
|
static filterForDecksWithCards(sourceArray) {
|
|
const result = [];
|
|
for (let idx = 0; idx < sourceArray.length; idx++) {
|
|
const deck = sourceArray[idx];
|
|
const hasAnyCards = deck.getCardCount(2 /* All */, false) > 0;
|
|
if (hasAnyCards) {
|
|
result.push(deck);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
setDeckIdx(deckIdx) {
|
|
this.deckIdx = deckIdx;
|
|
if (deckIdx != null) this.singleDeckIterator.setDeck(this.deckArray[deckIdx]);
|
|
}
|
|
nextCard() {
|
|
let result = false;
|
|
if (this.hasCurrentCard) {
|
|
this.baseDeckTree.deleteCardFromAllDecks(this.currentCard, true);
|
|
}
|
|
if (this.iteratorOrder.cardOrder == 4 /* EveryCardRandomDeckAndCard */) {
|
|
result = this.nextCardEveryCardRandomDeck();
|
|
} else {
|
|
if (this.deckIdx == null) {
|
|
this.chooseNextDeck(true);
|
|
}
|
|
while (this.deckIdx < this.deckArray.length) {
|
|
if (this.singleDeckIterator.nextCard()) {
|
|
result = true;
|
|
break;
|
|
}
|
|
this.chooseNextDeck(false);
|
|
}
|
|
}
|
|
if (!result) this.deckIdx = null;
|
|
return result;
|
|
}
|
|
chooseNextDeck(firstTime) {
|
|
switch (this.iteratorOrder.deckOrder) {
|
|
case 0 /* PrevDeckComplete_Sequential */:
|
|
this.deckIdx = firstTime ? 0 : this.deckIdx + 1;
|
|
break;
|
|
case 1 /* PrevDeckComplete_Random */: {
|
|
const weights = {};
|
|
let hasDeck = false;
|
|
for (let i2 = 0; i2 < this.deckArray.length; i2++) {
|
|
if (this.deckArray[i2].getCardCount(2 /* All */, false)) {
|
|
weights[i2] = 1;
|
|
hasDeck = true;
|
|
}
|
|
}
|
|
if (hasDeck) {
|
|
const [deckIdx, _2] = this.weightedRandomNumber.getRandomValues(weights);
|
|
this.deckIdx = deckIdx;
|
|
} else {
|
|
this.deckIdx = this.deckArray.length;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (this.deckIdx < this.deckArray.length) {
|
|
this.singleDeckIterator.setDeck(this.deckArray[this.deckIdx]);
|
|
}
|
|
}
|
|
nextCardEveryCardRandomDeck() {
|
|
const weights = {};
|
|
for (let i2 = 0; i2 < this.deckArray.length; i2++) {
|
|
const cardCount = this.deckArray[i2].getCardCount(2 /* All */, false);
|
|
if (cardCount) {
|
|
weights[i2] = cardCount;
|
|
}
|
|
}
|
|
if (Object.keys(weights).length == 0) return false;
|
|
const [deckIdx, cardIdx] = this.weightedRandomNumber.getRandomValues(weights);
|
|
this.setDeckIdx(deckIdx);
|
|
this.singleDeckIterator.setNewOrDueCardIdx(cardIdx);
|
|
return true;
|
|
}
|
|
deleteCurrentQuestionFromAllDecks() {
|
|
this.singleDeckIterator.ensureCurrentCard();
|
|
this.baseDeckTree.deleteQuestionFromAllDecks(this.currentQuestion, false);
|
|
this.singleDeckIterator.setNoCurrentCard();
|
|
return this.nextCard();
|
|
}
|
|
deleteCurrentCardFromAllDecks() {
|
|
this.singleDeckIterator.ensureCurrentCard();
|
|
this.baseDeckTree.deleteCardFromAllDecks(this.currentCard, true);
|
|
this.singleDeckIterator.setNoCurrentCard();
|
|
return this.nextCard();
|
|
}
|
|
moveCurrentCardToEndOfList() {
|
|
this.singleDeckIterator.moveCurrentCardToEndOfList();
|
|
}
|
|
removeCurrentDeckIfEmpty() {
|
|
if (this.currentDeck.getCardCount(2 /* All */, false) == 0) {
|
|
this.deckArray.splice(this.deckIdx, 1);
|
|
if (this.deckIdx < this.deckArray.length) this.setDeckIdx(this.deckIdx);
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/stats.ts
|
|
var Stats = class {
|
|
constructor() {
|
|
this.eases = new ValueCountDict();
|
|
this.intervals = new ValueCountDict();
|
|
this.delayedDays = new ValueCountDict();
|
|
this.newCount = 0;
|
|
this.youngCount = 0;
|
|
this.matureCount = 0;
|
|
}
|
|
get totalCount() {
|
|
return this.youngCount + this.matureCount;
|
|
}
|
|
incrementNew() {
|
|
this.newCount++;
|
|
}
|
|
update(delayedDays, interval, ease) {
|
|
this.intervals.incrementCount(interval);
|
|
this.eases.incrementCount(ease);
|
|
this.delayedDays.incrementCount(delayedDays);
|
|
if (interval >= 32) {
|
|
this.matureCount++;
|
|
} else {
|
|
this.youngCount++;
|
|
}
|
|
}
|
|
getMaxInterval() {
|
|
return this.intervals.getMaxValue();
|
|
}
|
|
getAverageInterval() {
|
|
return this.intervals.getTotalOfValueMultiplyCount() / this.totalCount;
|
|
}
|
|
getAverageEases() {
|
|
return this.eases.getTotalOfValueMultiplyCount() / this.totalCount;
|
|
}
|
|
};
|
|
|
|
// src/deck-tree-stats-calculator.ts
|
|
var DeckTreeStatsCalculator = class {
|
|
calculate(deckTree) {
|
|
const iteratorOrder = {
|
|
deckOrder: 0 /* PrevDeckComplete_Sequential */,
|
|
cardOrder: 2 /* DueFirstSequential */
|
|
};
|
|
const iterator = new DeckTreeIterator(iteratorOrder, deckTree.clone());
|
|
const result = new Stats();
|
|
iterator.setIteratorTopicPath(TopicPath.emptyPath);
|
|
while (iterator.nextCard()) {
|
|
const card = iterator.currentCard;
|
|
if (card.hasSchedule) {
|
|
const schedule = card.scheduleInfo;
|
|
result.update(
|
|
schedule.delayedBeforeReviewDaysInt(),
|
|
schedule.interval,
|
|
schedule.latestEase
|
|
);
|
|
} else {
|
|
result.incrementNew();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/due-date-histogram.ts
|
|
var _DueDateHistogram = class _DueDateHistogram {
|
|
constructor(rec = null) {
|
|
// Key - # of days in future
|
|
// Value - Count of notes due
|
|
this.dueDatesMap = /* @__PURE__ */ new Map();
|
|
this.dueDatesMap = /* @__PURE__ */ new Map();
|
|
if (rec != null) {
|
|
Object.entries(rec).forEach(([key, value]) => {
|
|
this.dueDatesMap.set(Number(key), value);
|
|
});
|
|
}
|
|
}
|
|
get dueNotesCount() {
|
|
let result = 0;
|
|
if (this.dueDatesMap.has(_DueDateHistogram.dueNowNDays))
|
|
result = this.dueDatesMap.get(_DueDateHistogram.dueNowNDays);
|
|
return result;
|
|
}
|
|
hasEntryForDays(days) {
|
|
return this.dueDatesMap.has(days);
|
|
}
|
|
set(days, value) {
|
|
this.dueDatesMap.set(days, value);
|
|
}
|
|
get(days) {
|
|
return this.dueDatesMap.get(days);
|
|
}
|
|
increment(days) {
|
|
let value = 0;
|
|
if (this.dueDatesMap.has(days)) {
|
|
value = this.dueDatesMap.get(days);
|
|
}
|
|
this.dueDatesMap.set(days, value + 1);
|
|
}
|
|
decrement(days) {
|
|
let value = 0;
|
|
if (this.dueDatesMap.has(days)) value = this.dueDatesMap.get(days);
|
|
if (value > 0) {
|
|
this.dueDatesMap.set(days, value - 1);
|
|
}
|
|
}
|
|
findLeastUsedIntervalOverRange(originalInterval, fuzz) {
|
|
if (!this.hasEntryForDays(originalInterval)) {
|
|
return originalInterval;
|
|
}
|
|
let interval = originalInterval;
|
|
outer: for (let i2 = 1; i2 <= fuzz; i2++) {
|
|
for (const ivl of [originalInterval - i2, originalInterval + i2]) {
|
|
if (!this.hasEntryForDays(ivl)) {
|
|
interval = ivl;
|
|
break outer;
|
|
}
|
|
if (this.dueDatesMap.get(ivl) < this.dueDatesMap.get(interval)) interval = ivl;
|
|
}
|
|
}
|
|
return interval;
|
|
}
|
|
};
|
|
// The key for dueDatesNotes is the number of days after today
|
|
// therefore the key to lookup how many cards are due today is 0
|
|
_DueDateHistogram.dueNowNDays = 0;
|
|
var DueDateHistogram = _DueDateHistogram;
|
|
var NoteDueDateHistogram = class extends DueDateHistogram {
|
|
calculateFromReviewDecksAndSort(reviewDecks, osrNoteGraph) {
|
|
this.dueDatesMap = /* @__PURE__ */ new Map();
|
|
const today = globalDateProvider.today.valueOf();
|
|
reviewDecks.forEach((reviewDeck) => {
|
|
reviewDeck.scheduledNotes.forEach((scheduledNote) => {
|
|
const nDays = Math.ceil((scheduledNote.dueUnix - today) / TICKS_PER_DAY);
|
|
this.increment(nDays);
|
|
});
|
|
reviewDeck.sortNotesByDateAndImportance(osrNoteGraph.pageranks);
|
|
});
|
|
}
|
|
};
|
|
var CardDueDateHistogram = class extends DueDateHistogram {
|
|
calculateFromDeckTree(deckTree) {
|
|
this.dueDatesMap = /* @__PURE__ */ new Map();
|
|
const iteratorOrder = {
|
|
deckOrder: 0 /* PrevDeckComplete_Sequential */,
|
|
cardOrder: 2 /* DueFirstSequential */
|
|
};
|
|
const today = globalDateProvider.today.valueOf();
|
|
const iterator = new DeckTreeIterator(iteratorOrder, deckTree.clone());
|
|
iterator.setIteratorTopicPath(TopicPath.emptyPath);
|
|
while (iterator.nextCard()) {
|
|
const card = iterator.currentCard;
|
|
if (card.hasSchedule) {
|
|
const scheduledCard = card.scheduleInfo;
|
|
const nDays = Math.ceil(
|
|
(scheduledCard.dueDateAsUnix - today) / TICKS_PER_DAY
|
|
);
|
|
this.increment(nDays);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/file.ts
|
|
var import_obsidian2 = require("obsidian");
|
|
|
|
// src/utils/strings.ts
|
|
function literalStringReplace(text, searchStr, replacementStr) {
|
|
let result = text;
|
|
const startIdx = text.indexOf(searchStr);
|
|
if (startIdx >= 0) {
|
|
const startStr = text.substring(0, startIdx);
|
|
const endIdx = startIdx + searchStr.length;
|
|
const endStr = text.substring(endIdx);
|
|
result = startStr + replacementStr + endStr;
|
|
}
|
|
return result;
|
|
}
|
|
function cyrb53(str, seed = 0) {
|
|
let h12 = 3735928559 ^ seed, h22 = 1103547991 ^ seed;
|
|
for (let i2 = 0, ch; i2 < str.length; i2++) {
|
|
ch = str.charCodeAt(i2);
|
|
h12 = Math.imul(h12 ^ ch, 2654435761);
|
|
h22 = Math.imul(h22 ^ ch, 1597334677);
|
|
}
|
|
h12 = Math.imul(h12 ^ h12 >>> 16, 2246822507) ^ Math.imul(h22 ^ h22 >>> 13, 3266489909);
|
|
h22 = Math.imul(h22 ^ h22 >>> 16, 2246822507) ^ Math.imul(h12 ^ h12 >>> 13, 3266489909);
|
|
return (4294967296 * (2097151 & h22) + (h12 >>> 0)).toString(16);
|
|
}
|
|
function convertToStringOrEmpty(v2) {
|
|
let result = "";
|
|
if (v2 != null && v2 != void 0) {
|
|
result = v2 + "";
|
|
}
|
|
return result;
|
|
}
|
|
function splitTextIntoLineArray(text) {
|
|
return text.replaceAll(/\r\n|\r/g, "\n").split("\n");
|
|
}
|
|
function stringTrimStart(str) {
|
|
if (!str) {
|
|
return ["", ""];
|
|
}
|
|
const trimmed = str.trimStart();
|
|
const wsCount = str.length - trimmed.length;
|
|
const ws = str.substring(0, wsCount);
|
|
return [ws, trimmed];
|
|
}
|
|
function splitNoteIntoFrontmatterAndContent(str) {
|
|
const lines = splitTextIntoLineArray(str);
|
|
let lineIndex = 0;
|
|
let hasFrontmatter = false;
|
|
do {
|
|
if (lineIndex === 0 && lines[lineIndex] === "---") {
|
|
hasFrontmatter = true;
|
|
} else if (hasFrontmatter && lines[lineIndex] === "---") {
|
|
hasFrontmatter = false;
|
|
lineIndex++;
|
|
}
|
|
if (hasFrontmatter) {
|
|
lineIndex++;
|
|
}
|
|
} while (hasFrontmatter && lineIndex < lines.length);
|
|
if (hasFrontmatter) {
|
|
lineIndex = 0;
|
|
}
|
|
const frontmatter = lines.slice(0, lineIndex).join("\n");
|
|
const emptyLines = lineIndex > 0 ? Array(lineIndex).join(".").split(".") : [];
|
|
const content = emptyLines.concat(lines.slice(lineIndex)).join("\n");
|
|
return [frontmatter, content];
|
|
}
|
|
function findLineIndexOfSearchStringIgnoringWs(lines, searchString) {
|
|
let result = -1;
|
|
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
if (lines[i2].trim() == searchString) {
|
|
result = i2;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function parseObsidianFrontmatterTag(tagStr) {
|
|
const result = [];
|
|
if (tagStr) {
|
|
const tagStrList = tagStr.split(",");
|
|
for (const tag of tagStrList) {
|
|
if (tag !== "") {
|
|
result.push(tag.startsWith("#") ? tag : "#" + tag);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
var MultiLineTextFinder = class _MultiLineTextFinder {
|
|
static findAndReplace(sourceText, searchText, replacementText) {
|
|
let result = null;
|
|
if (sourceText.includes(searchText)) {
|
|
result = literalStringReplace(sourceText, searchText, replacementText);
|
|
} else {
|
|
const sourceTextArray = splitTextIntoLineArray(sourceText);
|
|
const searchTextArray = splitTextIntoLineArray(searchText);
|
|
const lineNo = _MultiLineTextFinder.find(
|
|
sourceTextArray,
|
|
searchTextArray
|
|
);
|
|
if (lineNo !== null) {
|
|
const replacementTextArray = splitTextIntoLineArray(replacementText);
|
|
const linesToRemove = searchTextArray.length;
|
|
sourceTextArray.splice(lineNo, linesToRemove, ...replacementTextArray);
|
|
result = sourceTextArray.join("\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
static find(sourceText, searchText) {
|
|
let result = null;
|
|
let searchIdx = 0;
|
|
const maxSearchIdx = searchText.length - 1;
|
|
for (let sourceIdx = 0; sourceIdx < sourceText.length; sourceIdx++) {
|
|
const sourceLine = sourceText[sourceIdx].trim();
|
|
const searchLine = searchText[searchIdx].trim();
|
|
if (searchLine == sourceLine) {
|
|
if (searchIdx == maxSearchIdx) {
|
|
result = sourceIdx - searchIdx;
|
|
break;
|
|
}
|
|
searchIdx++;
|
|
} else {
|
|
searchIdx = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/file.ts
|
|
var frontmatterTagPseudoLineNum = -1;
|
|
var SrTFile = class {
|
|
constructor(vault, metadataCache, file) {
|
|
this.vault = vault;
|
|
this.metadataCache = metadataCache;
|
|
this.file = file;
|
|
}
|
|
get path() {
|
|
return this.file.path;
|
|
}
|
|
get basename() {
|
|
return this.file.basename;
|
|
}
|
|
get tfile() {
|
|
return this.file;
|
|
}
|
|
async getFrontmatter() {
|
|
const fileCachedData = this.metadataCache.getFileCache(this.file) || {};
|
|
const frontmatter = fileCachedData.frontmatter || {};
|
|
const result = /* @__PURE__ */ new Map();
|
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
const v2 = Array.isArray(value) && value.length > 0 ? value[0] : value;
|
|
const vStr = v2 + "";
|
|
result.set(key, vStr);
|
|
}
|
|
return result;
|
|
}
|
|
getAllTagsFromCache() {
|
|
const fileCachedData = this.metadataCache.getFileCache(this.file) || {};
|
|
const result = (0, import_obsidian2.getAllTags)(fileCachedData) || [];
|
|
return result;
|
|
}
|
|
getAllTagsFromText() {
|
|
var _a;
|
|
const result = [];
|
|
const fileCachedData = this.metadataCache.getFileCache(this.file) || {};
|
|
if (((_a = fileCachedData.tags) == null ? void 0 : _a.length) > 0) {
|
|
result.push(...fileCachedData.tags);
|
|
}
|
|
result.push(...this.getFrontmatterTags(fileCachedData.frontmatter));
|
|
return result;
|
|
}
|
|
getFrontmatterTags(frontmatter) {
|
|
const result = [];
|
|
const frontmatterTags = frontmatter != null ? frontmatter["tags"] + "" : null;
|
|
if (frontmatterTags) {
|
|
const tagStrList = parseObsidianFrontmatterTag(frontmatterTags);
|
|
for (const str of tagStrList) {
|
|
const tag = {
|
|
tag: str,
|
|
position: {
|
|
start: {
|
|
line: frontmatterTagPseudoLineNum,
|
|
col: null,
|
|
offset: null
|
|
},
|
|
end: {
|
|
line: frontmatterTagPseudoLineNum,
|
|
col: null,
|
|
offset: null
|
|
}
|
|
}
|
|
};
|
|
result.push(tag);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
getQuestionContext(cardLine) {
|
|
const fileCachedData = this.metadataCache.getFileCache(this.file) || {};
|
|
const headings = fileCachedData.headings || [];
|
|
const stack = [];
|
|
for (const heading of headings) {
|
|
if (heading.position.start.line > cardLine) {
|
|
break;
|
|
}
|
|
while (stack.length > 0 && stack[stack.length - 1].level >= heading.level) {
|
|
stack.pop();
|
|
}
|
|
stack.push(heading);
|
|
}
|
|
const result = [];
|
|
for (const headingObj of stack) {
|
|
headingObj.heading = headingObj.heading.replace(/\[\^\d+\]/gm, "").trim();
|
|
result.push(headingObj.heading);
|
|
}
|
|
return result;
|
|
}
|
|
getTextDirection() {
|
|
let result = 0 /* Unspecified */;
|
|
const fileCache = this.metadataCache.getFileCache(this.file);
|
|
const frontMatter = fileCache == null ? void 0 : fileCache.frontmatter;
|
|
if (frontMatter && (frontMatter == null ? void 0 : frontMatter.direction)) {
|
|
const str = (frontMatter.direction + "").toLowerCase();
|
|
result = str == "rtl" ? 2 /* Rtl */ : 1 /* Ltr */;
|
|
}
|
|
return result;
|
|
}
|
|
async read() {
|
|
return await this.vault.read(this.file);
|
|
}
|
|
async write(content) {
|
|
await this.vault.modify(this.file, content);
|
|
}
|
|
};
|
|
|
|
// src/note.ts
|
|
var Note = class {
|
|
get hasChanged() {
|
|
return this.questionList.some((question) => question.hasChanged);
|
|
}
|
|
get filePath() {
|
|
return this.file.path;
|
|
}
|
|
constructor(file, questionList) {
|
|
this.file = file;
|
|
this.questionList = questionList;
|
|
questionList.forEach((question) => question.note = this);
|
|
}
|
|
appendCardsToDeck(deck) {
|
|
for (const question of this.questionList) {
|
|
for (const card of question.cards) {
|
|
deck.appendCard(question.topicPathList, card);
|
|
}
|
|
}
|
|
}
|
|
debugLogToConsole(desc = "") {
|
|
var _a;
|
|
let str = `Note: ${desc}: ${this.questionList.length} questions\r
|
|
`;
|
|
for (let i2 = 0; i2 < this.questionList.length; i2++) {
|
|
const q2 = this.questionList[i2];
|
|
str += `[${i2}]: ${q2.questionType}: ${q2.lineNo}: ${(_a = q2.topicPathList) == null ? void 0 : _a.format("|")}: ${q2.questionText.original}\r
|
|
`;
|
|
}
|
|
console.debug(str);
|
|
}
|
|
async writeNoteFile(settings) {
|
|
let fileText = await this.file.read();
|
|
for (const question of this.questionList) {
|
|
if (question.hasChanged) {
|
|
fileText = question.updateQuestionWithinNoteText(fileText, settings);
|
|
}
|
|
}
|
|
await this.file.write(fileText);
|
|
this.questionList.forEach((question) => question.hasChanged = false);
|
|
}
|
|
};
|
|
|
|
// src/card.ts
|
|
var Card = class extends RepetitionItem {
|
|
constructor(init) {
|
|
super();
|
|
Object.assign(this, init);
|
|
}
|
|
get cardListType() {
|
|
return this.isNew ? 0 /* NewCard */ : 1 /* DueCard */;
|
|
}
|
|
formatSchedule() {
|
|
let result = "";
|
|
if (this.hasSchedule) result = this.scheduleInfo.formatCardScheduleForHtmlComment();
|
|
else result = "New";
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/parser.ts
|
|
var import_clozecraft = __toESM(require_dist());
|
|
|
|
// src/question.ts
|
|
var QuestionText = class _QuestionText {
|
|
constructor(original, topicPathWithWs, actualQuestion, textDirection, blockId) {
|
|
this.original = original;
|
|
this.topicPathWithWs = topicPathWithWs;
|
|
this.actualQuestion = actualQuestion;
|
|
this.textDirection = textDirection;
|
|
this.obsidianBlockId = blockId;
|
|
this.textHash = cyrb53(this.formatTopicAndQuestion());
|
|
}
|
|
endsWithCodeBlock() {
|
|
return this.actualQuestion.endsWith("```");
|
|
}
|
|
static create(original, textDirection, settings) {
|
|
const [topicPathWithWs, actualQuestion, blockId] = this.splitText(original, settings);
|
|
return new _QuestionText(original, topicPathWithWs, actualQuestion, textDirection, blockId);
|
|
}
|
|
static splitText(original, settings) {
|
|
const originalWithoutSR = DataStore.getInstance().questionRemoveScheduleInfo(original);
|
|
let actualQuestion = originalWithoutSR.trimEnd();
|
|
let topicPathWithWs = null;
|
|
let blockId = null;
|
|
const topicPath = TopicPath.getTopicPathFromCardText(originalWithoutSR);
|
|
if (topicPath == null ? void 0 : topicPath.hasPath) {
|
|
const [preTopicPathWs, cardText2] = stringTrimStart(originalWithoutSR);
|
|
const cardText3 = cardText2.replaceAll(OBSIDIAN_TAG_AT_STARTOFLINE_REGEX, "");
|
|
let postTopicPathWs = null;
|
|
[postTopicPathWs, actualQuestion] = stringTrimStart(cardText3);
|
|
if (!settings.convertFoldersToDecks) {
|
|
topicPathWithWs = new TopicPathWithWs(topicPath, preTopicPathWs, postTopicPathWs);
|
|
}
|
|
}
|
|
[actualQuestion, blockId] = this.extractObsidianBlockId(actualQuestion);
|
|
return [topicPathWithWs, actualQuestion, blockId];
|
|
}
|
|
static extractObsidianBlockId(text) {
|
|
let question = text;
|
|
let blockId = null;
|
|
const match2 = text.match(OBSIDIAN_BLOCK_ID_ENDOFLINE_REGEX);
|
|
if (match2) {
|
|
blockId = match2[0].trim();
|
|
const newLength = question.length - blockId.length;
|
|
question = question.substring(0, newLength).trimEnd();
|
|
}
|
|
return [question, blockId];
|
|
}
|
|
formatTopicAndQuestion() {
|
|
let result = "";
|
|
if (this.topicPathWithWs) {
|
|
result += this.topicPathWithWs.formatWithWs();
|
|
}
|
|
result += this.actualQuestion;
|
|
return result;
|
|
}
|
|
};
|
|
var Question = class _Question {
|
|
get questionType() {
|
|
return this.parsedQuestionInfo.cardType;
|
|
}
|
|
get lineNo() {
|
|
return this.parsedQuestionInfo.firstLineNum;
|
|
}
|
|
constructor(init) {
|
|
Object.assign(this, init);
|
|
}
|
|
getHtmlCommentSeparator(settings) {
|
|
const sep2 = this.isCardCommentsOnSameLine(settings) ? " " : "\n";
|
|
return sep2;
|
|
}
|
|
isCardCommentsOnSameLine(settings) {
|
|
let result = settings.cardCommentOnSameLine;
|
|
if (this.questionText.endsWithCodeBlock()) {
|
|
result = false;
|
|
}
|
|
return result;
|
|
}
|
|
setCardList(cards) {
|
|
this.cards = cards;
|
|
this.cards.forEach((card) => card.question = this);
|
|
}
|
|
formatForNote(settings) {
|
|
let result = this.questionText.formatTopicAndQuestion();
|
|
const blockId = this.questionText.obsidianBlockId;
|
|
const hasSchedule = this.cards.some((card) => card.hasSchedule);
|
|
if (hasSchedule) {
|
|
result = result.trimEnd();
|
|
const scheduleHtml = DataStoreAlgorithm.getInstance().questionFormatScheduleAsHtmlComment(this);
|
|
if (blockId) {
|
|
if (this.isCardCommentsOnSameLine(settings))
|
|
result += ` ${scheduleHtml} ${blockId}`;
|
|
else result += ` ${blockId}
|
|
${scheduleHtml}`;
|
|
} else {
|
|
result += this.getHtmlCommentSeparator(settings) + scheduleHtml;
|
|
}
|
|
} else {
|
|
if (blockId) result += ` ${blockId}`;
|
|
}
|
|
return result;
|
|
}
|
|
updateQuestionWithinNoteText(noteText, settings) {
|
|
const originalText = this.questionText.original;
|
|
const replacementText = this.formatForNote(settings);
|
|
let newText = MultiLineTextFinder.findAndReplace(noteText, originalText, replacementText);
|
|
if (newText) {
|
|
this.questionText = QuestionText.create(
|
|
replacementText,
|
|
this.questionText.textDirection,
|
|
settings
|
|
);
|
|
} else {
|
|
console.error(
|
|
`updateQuestionText: Text not found: ${originalText.substring(
|
|
0,
|
|
100
|
|
)} in note: ${noteText.substring(0, 100)}`
|
|
);
|
|
newText = noteText;
|
|
}
|
|
return newText;
|
|
}
|
|
async writeQuestion(settings) {
|
|
const fileText = await this.note.file.read();
|
|
const newText = this.updateQuestionWithinNoteText(fileText, settings);
|
|
await this.note.file.write(newText);
|
|
this.hasChanged = false;
|
|
}
|
|
formatTopicPathList() {
|
|
return this.topicPathList.format("|");
|
|
}
|
|
static Create(settings, parsedQuestionInfo, noteTopicPathList, textDirection, context) {
|
|
const hasEditLaterTag = parsedQuestionInfo.text.includes(settings.editLaterTag);
|
|
const questionText = QuestionText.create(
|
|
parsedQuestionInfo.text,
|
|
textDirection,
|
|
settings
|
|
);
|
|
let topicPathList = noteTopicPathList;
|
|
if (questionText.topicPathWithWs) {
|
|
topicPathList = new TopicPathList([questionText.topicPathWithWs.topicPath]);
|
|
}
|
|
const result = new _Question({
|
|
parsedQuestionInfo,
|
|
topicPathList,
|
|
questionText,
|
|
hasEditLaterTag,
|
|
questionContext: context,
|
|
cards: null,
|
|
hasChanged: false
|
|
});
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/parser.ts
|
|
var debugParser = false;
|
|
function setDebugParser(value) {
|
|
debugParser = value;
|
|
}
|
|
var ParsedQuestionInfo = class {
|
|
constructor(cardType, text, firstLineNum, lastLineNum) {
|
|
this.cardType = cardType;
|
|
this.text = text;
|
|
this.firstLineNum = firstLineNum;
|
|
this.lastLineNum = lastLineNum;
|
|
}
|
|
isQuestionLineNum(lineNum) {
|
|
return lineNum >= this.firstLineNum && lineNum <= this.lastLineNum;
|
|
}
|
|
};
|
|
function markerInsideCodeBlock(text, marker, markerIndex) {
|
|
let goingBack = markerIndex - 1, goingForward = markerIndex + marker.length;
|
|
let backTicksBefore = 0, backTicksAfter = 0;
|
|
while (goingBack >= 0) {
|
|
if (text[goingBack] === "`") backTicksBefore++;
|
|
goingBack--;
|
|
}
|
|
while (goingForward < text.length) {
|
|
if (text[goingForward] === "`") backTicksAfter++;
|
|
goingForward++;
|
|
}
|
|
return backTicksBefore % 2 === 1 && backTicksAfter % 2 === 1;
|
|
}
|
|
function hasInlineMarker(text, marker) {
|
|
if (marker.length == 0) return false;
|
|
const markerIdx = text.indexOf(marker);
|
|
if (markerIdx === -1) return false;
|
|
return !markerInsideCodeBlock(text, marker, markerIdx);
|
|
}
|
|
function parse(text, options) {
|
|
if (debugParser) {
|
|
console.log("Text to parse:\n<<<" + text + ">>>");
|
|
}
|
|
const inlineSeparators = [
|
|
{ separator: options.singleLineCardSeparator, type: 0 /* SingleLineBasic */ },
|
|
{ separator: options.singleLineReversedCardSeparator, type: 1 /* SingleLineReversed */ }
|
|
];
|
|
inlineSeparators.sort((a2, b2) => b2.separator.length - a2.separator.length);
|
|
const cards = [];
|
|
let cardText = "";
|
|
let cardType = null;
|
|
let firstLineNo = 0, lastLineNo = 0;
|
|
const clozecrafter = new import_clozecraft.ClozeCrafter(options.clozePatterns);
|
|
const lines = text.replaceAll("\r\n", "\n").split("\n");
|
|
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
const currentLine = lines[i2], currentTrimmed = lines[i2].trim();
|
|
if (currentLine.startsWith("<!--") && !currentLine.startsWith("<!--SR:")) {
|
|
while (i2 + 1 < lines.length && !currentLine.includes("-->")) i2++;
|
|
i2++;
|
|
continue;
|
|
}
|
|
const isEmptyLine = currentTrimmed.length == 0;
|
|
const hasMultilineCardEndMarker = options.multilineCardEndMarker && currentTrimmed == options.multilineCardEndMarker;
|
|
if (
|
|
// We've probably reached the end of a card
|
|
isEmptyLine && !options.multilineCardEndMarker || // Empty line & we're not picking up any card
|
|
isEmptyLine && cardType == null || // We've reached the end of a multi line card &
|
|
// we're using custom end markers
|
|
hasMultilineCardEndMarker
|
|
) {
|
|
if (cardType) {
|
|
lastLineNo = i2 - 1;
|
|
cards.push(
|
|
new ParsedQuestionInfo(cardType, cardText.trimEnd(), firstLineNo, lastLineNo)
|
|
);
|
|
cardType = null;
|
|
}
|
|
cardText = "";
|
|
firstLineNo = i2 + 1;
|
|
continue;
|
|
}
|
|
if (cardText.length > 0) {
|
|
cardText += "\n";
|
|
}
|
|
cardText += currentLine.trimEnd();
|
|
for (const { separator, type } of inlineSeparators) {
|
|
if (hasInlineMarker(currentLine, separator)) {
|
|
cardType = type;
|
|
break;
|
|
}
|
|
}
|
|
if (cardType == 0 /* SingleLineBasic */ || cardType == 1 /* SingleLineReversed */) {
|
|
cardText = currentLine;
|
|
firstLineNo = i2;
|
|
if (i2 + 1 < lines.length && lines[i2 + 1].startsWith("<!--SR:")) {
|
|
cardText += "\n" + lines[i2 + 1];
|
|
i2++;
|
|
}
|
|
lastLineNo = i2;
|
|
cards.push(new ParsedQuestionInfo(cardType, cardText, firstLineNo, lastLineNo));
|
|
cardType = null;
|
|
cardText = "";
|
|
} else if (currentTrimmed === options.multilineCardSeparator) {
|
|
if (cardText.length > 1) {
|
|
cardType = 2 /* MultiLineBasic */;
|
|
}
|
|
} else if (currentTrimmed === options.multilineReversedCardSeparator) {
|
|
if (cardText.length > 1) {
|
|
cardType = 3 /* MultiLineReversed */;
|
|
}
|
|
} else if (currentLine.startsWith("```") || currentLine.startsWith("~~~")) {
|
|
const codeBlockClose = currentLine.match(/`+|~+/)[0];
|
|
while (i2 + 1 < lines.length && !lines[i2 + 1].startsWith(codeBlockClose)) {
|
|
i2++;
|
|
cardText += "\n" + lines[i2];
|
|
}
|
|
cardText += "\n" + codeBlockClose;
|
|
i2++;
|
|
} else if (cardType === null && clozecrafter.isClozeNote(currentLine)) {
|
|
cardType = 4 /* Cloze */;
|
|
}
|
|
}
|
|
if (cardType && cardText) {
|
|
lastLineNo = lines.length - 1;
|
|
cards.push(new ParsedQuestionInfo(cardType, cardText.trimEnd(), firstLineNo, lastLineNo));
|
|
}
|
|
if (debugParser) {
|
|
console.log("Parsed cards:\n", cards);
|
|
}
|
|
return cards;
|
|
}
|
|
|
|
// src/question-type.ts
|
|
var import_clozecraft2 = __toESM(require_dist());
|
|
var CardFrontBack = class {
|
|
// The caller is responsible for any required trimming of leading/trailing spaces
|
|
constructor(front, back) {
|
|
this.front = front;
|
|
this.back = back;
|
|
}
|
|
};
|
|
var CardFrontBackUtil = class {
|
|
static expand(questionType, questionText, settings) {
|
|
const handler = QuestionTypeFactory.create(questionType);
|
|
return handler.expand(questionText, settings);
|
|
}
|
|
};
|
|
var QuestionTypeSingleLineBasic = class {
|
|
expand(questionText, settings) {
|
|
const idx = questionText.indexOf(settings.singleLineCardSeparator);
|
|
const item = new CardFrontBack(
|
|
questionText.substring(0, idx),
|
|
questionText.substring(idx + settings.singleLineCardSeparator.length)
|
|
);
|
|
const result = [item];
|
|
return result;
|
|
}
|
|
};
|
|
var QuestionTypeSingleLineReversed = class {
|
|
expand(questionText, settings) {
|
|
const idx = questionText.indexOf(settings.singleLineReversedCardSeparator);
|
|
const side1 = questionText.substring(0, idx), side2 = questionText.substring(
|
|
idx + settings.singleLineReversedCardSeparator.length
|
|
);
|
|
const result = [
|
|
new CardFrontBack(side1, side2),
|
|
new CardFrontBack(side2, side1)
|
|
];
|
|
return result;
|
|
}
|
|
};
|
|
var QuestionTypeMultiLineBasic = class {
|
|
expand(questionText, settings) {
|
|
const questionLines = questionText.split("\n");
|
|
const lineIdx = findLineIndexOfSearchStringIgnoringWs(
|
|
questionLines,
|
|
settings.multilineCardSeparator
|
|
);
|
|
const side1 = questionLines.slice(0, lineIdx).join("\n");
|
|
const side2 = questionLines.slice(lineIdx + 1).join("\n");
|
|
const result = [new CardFrontBack(side1, side2)];
|
|
return result;
|
|
}
|
|
};
|
|
var QuestionTypeMultiLineReversed = class {
|
|
expand(questionText, settings) {
|
|
const questionLines = questionText.split("\n");
|
|
const lineIdx = findLineIndexOfSearchStringIgnoringWs(
|
|
questionLines,
|
|
settings.multilineReversedCardSeparator
|
|
);
|
|
const side1 = questionLines.slice(0, lineIdx).join("\n");
|
|
const side2 = questionLines.slice(lineIdx + 1).join("\n");
|
|
const result = [
|
|
new CardFrontBack(side1, side2),
|
|
new CardFrontBack(side2, side1)
|
|
];
|
|
return result;
|
|
}
|
|
};
|
|
var QuestionTypeCloze = class {
|
|
expand(questionText, settings) {
|
|
const clozecrafter = new import_clozecraft2.ClozeCrafter(settings.clozePatterns);
|
|
const clozeNote = clozecrafter.createClozeNote(questionText);
|
|
const clozeFormatter = new QuestionTypeClozeFormatter();
|
|
let front, back;
|
|
const result = [];
|
|
for (let i2 = 0; i2 < clozeNote.numCards; i2++) {
|
|
front = clozeNote.getCardFront(i2, clozeFormatter);
|
|
back = clozeNote.getCardBack(i2, clozeFormatter);
|
|
result.push(new CardFrontBack(front, back));
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
var QuestionTypeClozeFormatter = class {
|
|
asking(answer, hint) {
|
|
return `<span style='color:#2196f3'>${!hint ? "[...]" : `[${hint}]`}</span>`;
|
|
}
|
|
showingAnswer(answer, _hint) {
|
|
return `<span style='color:#2196f3'>${answer}</span>`;
|
|
}
|
|
hiding(answer, hint) {
|
|
return `<span style='color:var(--code-comment)'>${!hint ? "[...]" : `[${hint}]`}</span>`;
|
|
}
|
|
};
|
|
var QuestionTypeFactory = class {
|
|
static create(questionType) {
|
|
let handler;
|
|
switch (questionType) {
|
|
case 0 /* SingleLineBasic */:
|
|
handler = new QuestionTypeSingleLineBasic();
|
|
break;
|
|
case 1 /* SingleLineReversed */:
|
|
handler = new QuestionTypeSingleLineReversed();
|
|
break;
|
|
case 2 /* MultiLineBasic */:
|
|
handler = new QuestionTypeMultiLineBasic();
|
|
break;
|
|
case 3 /* MultiLineReversed */:
|
|
handler = new QuestionTypeMultiLineReversed();
|
|
break;
|
|
case 4 /* Cloze */:
|
|
handler = new QuestionTypeCloze();
|
|
break;
|
|
}
|
|
return handler;
|
|
}
|
|
};
|
|
|
|
// src/settings.ts
|
|
var import_obsidian3 = require("obsidian");
|
|
var DEFAULT_SETTINGS = {
|
|
// flashcards
|
|
flashcardTags: ["#flashcards"],
|
|
convertFoldersToDecks: false,
|
|
burySiblingCards: false,
|
|
randomizeCardOrder: null,
|
|
flashcardCardOrder: "DueFirstRandom",
|
|
flashcardDeckOrder: "PrevDeckComplete_Sequential",
|
|
convertHighlightsToClozes: true,
|
|
convertBoldTextToClozes: false,
|
|
convertCurlyBracketsToClozes: false,
|
|
clozePatterns: ["==[123;;]answer[;;hint]=="],
|
|
singleLineCardSeparator: "::",
|
|
singleLineReversedCardSeparator: ":::",
|
|
multilineCardSeparator: "?",
|
|
multilineReversedCardSeparator: "??",
|
|
multilineCardEndMarker: "",
|
|
editLaterTag: "#edit-later",
|
|
// notes
|
|
enableNoteReviewPaneOnStartup: true,
|
|
tagsToReview: ["#review"],
|
|
noteFoldersToIgnore: ["**/*.excalidraw.md"],
|
|
openRandomNote: false,
|
|
autoNextNote: false,
|
|
disableFileMenuReviewOptions: false,
|
|
maxNDaysNotesReviewQueue: 365,
|
|
// UI settings
|
|
showRibbonIcon: true,
|
|
showStatusBar: true,
|
|
initiallyExpandAllSubdecksInTree: false,
|
|
showContextInCards: true,
|
|
showIntervalInReviewButtons: true,
|
|
flashcardHeightPercentage: import_obsidian3.Platform.isMobile ? 100 : 80,
|
|
flashcardWidthPercentage: import_obsidian3.Platform.isMobile ? 100 : 40,
|
|
flashcardEasyText: t("EASY"),
|
|
flashcardGoodText: t("GOOD"),
|
|
flashcardHardText: t("HARD"),
|
|
reviewButtonDelay: 0,
|
|
// algorithm
|
|
algorithm: "SM-2-OSR" /* SM_2_OSR */,
|
|
baseEase: 250,
|
|
lapsesIntervalChange: 0.5,
|
|
easyBonus: 1.3,
|
|
loadBalance: true,
|
|
maximumInterval: 36525,
|
|
maxLinkFactor: 1,
|
|
// storage
|
|
dataStore: "NOTES" /* NOTES */,
|
|
cardCommentOnSameLine: false,
|
|
// logging
|
|
showSchedulingDebugMessages: false,
|
|
showParserDebugMessages: false
|
|
};
|
|
function upgradeSettings(settings) {
|
|
if (settings.randomizeCardOrder != null && settings.flashcardCardOrder == null && settings.flashcardDeckOrder == null) {
|
|
settings.flashcardCardOrder = settings.randomizeCardOrder ? "DueFirstRandom" : "DueFirstSequential";
|
|
settings.flashcardDeckOrder = "PrevDeckComplete_Sequential";
|
|
settings.randomizeCardOrder = null;
|
|
}
|
|
if (settings.clozePatterns == null) {
|
|
settings.clozePatterns = [];
|
|
if (settings.convertHighlightsToClozes)
|
|
settings.clozePatterns.push("==[123;;]answer[;;hint]==");
|
|
if (settings.convertBoldTextToClozes)
|
|
settings.clozePatterns.push("**[123;;]answer[;;hint]**");
|
|
if (settings.convertCurlyBracketsToClozes)
|
|
settings.clozePatterns.push("{{[123;;]answer[;;hint]}}");
|
|
}
|
|
}
|
|
var SettingsUtil = class _SettingsUtil {
|
|
static isFlashcardTag(settings, tag) {
|
|
return _SettingsUtil.isTagInList(settings.flashcardTags, tag);
|
|
}
|
|
static isPathInNoteIgnoreFolder(settings, path3) {
|
|
return settings.noteFoldersToIgnore.some((folder) => pathMatchesPattern(path3, folder));
|
|
}
|
|
static isAnyTagANoteReviewTag(settings, tags) {
|
|
for (const tag of tags) {
|
|
if (settings.tagsToReview.some(
|
|
(tagToReview) => tag === tagToReview || tag.startsWith(tagToReview + "/")
|
|
)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
// Given a list of tags, return the subset that is in settings.tagsToReview
|
|
static filterForNoteReviewTag(settings, tags) {
|
|
const result = [];
|
|
for (const tagToReview of settings.tagsToReview) {
|
|
if (tags.some((tag) => tag === tagToReview || tag.startsWith(tagToReview + "/"))) {
|
|
result.push(tagToReview);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
static isTagInList(tagList, tag) {
|
|
for (const tagFromList of tagList) {
|
|
if (tag === tagFromList || tag.startsWith(tagFromList + "/")) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// src/note-question-parser.ts
|
|
var NoteQuestionParser = class {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
}
|
|
async createQuestionList(noteFile, defaultTextDirection, folderTopicPath, onlyKeepQuestionsWithTopicPath) {
|
|
this.noteFile = noteFile;
|
|
const tagCacheList = noteFile.getAllTagsFromCache();
|
|
const hasTopicPaths = tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath;
|
|
if (hasTopicPaths) {
|
|
const noteText = await noteFile.read();
|
|
const tagCompleteList = noteFile.getAllTagsFromText();
|
|
[this.frontmatterText, this.contentText] = splitNoteIntoFrontmatterAndContent(noteText);
|
|
let textDirection = noteFile.getTextDirection();
|
|
if (textDirection == 0 /* Unspecified */) textDirection = defaultTextDirection;
|
|
this.questionList = this.doCreateQuestionList(
|
|
noteText,
|
|
textDirection,
|
|
folderTopicPath,
|
|
this.tagCacheList
|
|
);
|
|
[this.frontmatterTopicPathList, this.contentTopicPathInfo] = this.analyseTagCacheList(tagCompleteList);
|
|
for (const question of this.questionList) {
|
|
question.topicPathList = this.determineQuestionTopicPathList(question);
|
|
}
|
|
if (onlyKeepQuestionsWithTopicPath) {
|
|
this.questionList = this.questionList.filter((q2) => q2.topicPathList);
|
|
}
|
|
} else {
|
|
this.questionList = [];
|
|
}
|
|
return this.questionList;
|
|
}
|
|
doCreateQuestionList(noteText, textDirection, folderTopicPath, tagCacheList) {
|
|
this.noteText = noteText;
|
|
this.noteLines = splitTextIntoLineArray(noteText);
|
|
this.folderTopicPath = folderTopicPath;
|
|
this.tagCacheList = tagCacheList;
|
|
const result = [];
|
|
const parsedQuestionInfoList = this.parseQuestions();
|
|
for (const parsedQuestionInfo of parsedQuestionInfoList) {
|
|
const question = this.createQuestionObject(parsedQuestionInfo, textDirection);
|
|
const cardFrontBackList = CardFrontBackUtil.expand(
|
|
question.questionType,
|
|
question.questionText.actualQuestion,
|
|
this.settings
|
|
);
|
|
let cardScheduleInfoList = DataStore.getInstance().questionCreateSchedule(
|
|
question.questionText.original,
|
|
null
|
|
);
|
|
const correctLength = cardFrontBackList.length;
|
|
if (cardScheduleInfoList.length > correctLength) {
|
|
question.hasChanged = true;
|
|
cardScheduleInfoList = cardScheduleInfoList.slice(0, correctLength);
|
|
}
|
|
const cardList = this.createCardList(cardFrontBackList, cardScheduleInfoList);
|
|
question.setCardList(cardList);
|
|
result.push(question);
|
|
}
|
|
return result;
|
|
}
|
|
parseQuestions() {
|
|
const settings = this.settings;
|
|
const parserOptions = {
|
|
singleLineCardSeparator: settings.singleLineCardSeparator,
|
|
singleLineReversedCardSeparator: settings.singleLineReversedCardSeparator,
|
|
multilineCardSeparator: settings.multilineCardSeparator,
|
|
multilineReversedCardSeparator: settings.multilineReversedCardSeparator,
|
|
multilineCardEndMarker: settings.multilineCardEndMarker,
|
|
clozePatterns: settings.clozePatterns
|
|
};
|
|
return parse(this.contentText, parserOptions);
|
|
}
|
|
createQuestionObject(parsedQuestionInfo, textDirection) {
|
|
const questionContext = this.noteFile.getQuestionContext(
|
|
parsedQuestionInfo.firstLineNum
|
|
);
|
|
const result = Question.Create(
|
|
this.settings,
|
|
parsedQuestionInfo,
|
|
null,
|
|
// We haven't worked out the TopicPathList yet
|
|
textDirection,
|
|
questionContext
|
|
);
|
|
return result;
|
|
}
|
|
createCardList(cardFrontBackList, cardScheduleInfoList) {
|
|
const siblings = [];
|
|
for (let i2 = 0; i2 < cardFrontBackList.length; i2++) {
|
|
const { front, back } = cardFrontBackList[i2];
|
|
const hasScheduleInfo = i2 < cardScheduleInfoList.length;
|
|
const schedule = cardScheduleInfoList[i2];
|
|
const cardObj = new Card({
|
|
front,
|
|
back,
|
|
cardIdx: i2
|
|
});
|
|
cardObj.scheduleInfo = hasScheduleInfo ? schedule : null;
|
|
siblings.push(cardObj);
|
|
}
|
|
return siblings;
|
|
}
|
|
//
|
|
// Given the complete list of tags within a note:
|
|
// 1. Only keep tags that are specified in the user settings as flashcardTags
|
|
// 2. Filter out tags that are question specific
|
|
// (these will be parsed separately by class QuestionText)
|
|
// 3. Combine all tags present logically grouped together into a single entry
|
|
// - All tags present on the same line grouped together
|
|
// - All tags within frontmatter grouped together (note that multiple tags
|
|
// within frontmatter appear on separate lines)
|
|
//
|
|
analyseTagCacheList(tagCacheList) {
|
|
this.flashcardTagList = tagCacheList.filter(
|
|
(item) => SettingsUtil.isFlashcardTag(this.settings, item.tag)
|
|
);
|
|
if (this.flashcardTagList.length > 0) {
|
|
this.flashcardTagList.sort((a2, b2) => a2.position.start.line - b2.position.start.line);
|
|
}
|
|
let frontmatterLineCount = 0;
|
|
if (this.frontmatterText) {
|
|
frontmatterLineCount = splitTextIntoLineArray(this.frontmatterText).length;
|
|
}
|
|
const frontmatterTopicPathList = this.determineFrontmatterTopicPathList(
|
|
this.flashcardTagList,
|
|
frontmatterLineCount
|
|
);
|
|
const contentTopicPathList = this.determineContentTopicPathList(
|
|
this.flashcardTagList,
|
|
frontmatterLineCount
|
|
);
|
|
return [frontmatterTopicPathList, contentTopicPathList];
|
|
}
|
|
determineFrontmatterTopicPathList(flashcardTagList, frontmatterLineCount) {
|
|
let result = null;
|
|
const noteLevelTagList = flashcardTagList.filter(
|
|
(item) => item.position.start.line == frontmatterTagPseudoLineNum && this.isNoteLevelFlashcardTag(item)
|
|
);
|
|
if (noteLevelTagList.length > 0) {
|
|
if (this.frontmatterText) {
|
|
const frontmatterTagCacheList = noteLevelTagList.filter(
|
|
(item) => item.position.start.line < frontmatterLineCount
|
|
);
|
|
if (frontmatterTagCacheList.length > 0)
|
|
result = this.createTopicPathList(
|
|
frontmatterTagCacheList,
|
|
frontmatterTagPseudoLineNum
|
|
);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
determineContentTopicPathList(flashcardTagList, frontmatterLineCount) {
|
|
const result = [];
|
|
const contentStartLineNum = frontmatterLineCount;
|
|
const contentTagCacheList = flashcardTagList.filter(
|
|
(item) => item.position.start.line >= contentStartLineNum && this.isNoteLevelFlashcardTag(item)
|
|
);
|
|
let list = [];
|
|
for (const tag of contentTagCacheList) {
|
|
if (list.length != 0) {
|
|
const startLineNum = list[0].position.start.line;
|
|
if (startLineNum != tag.position.start.line) {
|
|
result.push(this.createTopicPathList(list, startLineNum));
|
|
list = [];
|
|
}
|
|
}
|
|
list.push(tag);
|
|
}
|
|
if (list.length > 0) {
|
|
const startLineNum = list[0].position.start.line;
|
|
result.push(this.createTopicPathList(list, startLineNum));
|
|
}
|
|
return result;
|
|
}
|
|
isNoteLevelFlashcardTag(tagItem) {
|
|
const tagLineNum = tagItem.position.start.line;
|
|
const isQuestionSpecific = this.questionList.some(
|
|
(q2) => q2.parsedQuestionInfo.isQuestionLineNum(tagLineNum)
|
|
);
|
|
return !isQuestionSpecific;
|
|
}
|
|
createTopicPathList(tagCacheList, lineNum) {
|
|
const list = [];
|
|
for (const tagCache of tagCacheList) {
|
|
list.push(TopicPath.getTopicPathFromTag(tagCache.tag));
|
|
}
|
|
return new TopicPathList(list, lineNum);
|
|
}
|
|
createTopicPathListFromSingleTag(tagCache) {
|
|
const list = [TopicPath.getTopicPathFromTag(tagCache.tag)];
|
|
return new TopicPathList(list, tagCache.position.start.line);
|
|
}
|
|
// A question can be associated with multiple topics (hence returning TopicPathList and not just TopicPath).
|
|
//
|
|
// If the question has an associated question specific TopicPath, then that is returned.
|
|
//
|
|
// Else the first TopicPathList prior to the question (in the order present in the file) is returned.
|
|
// That could be either the tags within the note's frontmatter, or tags on lines within the note's content.
|
|
determineQuestionTopicPathList(question) {
|
|
let result;
|
|
if (this.settings.convertFoldersToDecks) {
|
|
result = new TopicPathList([this.folderTopicPath]);
|
|
} else {
|
|
const questionText = question.questionText;
|
|
if (questionText.topicPathWithWs)
|
|
result = new TopicPathList(
|
|
[questionText.topicPathWithWs.topicPath],
|
|
question.parsedQuestionInfo.firstLineNum
|
|
);
|
|
else {
|
|
result = this.frontmatterTopicPathList;
|
|
for (let i2 = this.contentTopicPathInfo.length - 1; i2 >= 0; i2--) {
|
|
const topicPathList = this.contentTopicPathInfo[i2];
|
|
if (topicPathList.lineNum < question.parsedQuestionInfo.firstLineNum) {
|
|
result = topicPathList;
|
|
break;
|
|
}
|
|
}
|
|
if (!result && this.flashcardTagList.length > 0) {
|
|
result = this.createTopicPathListFromSingleTag(this.flashcardTagList[0]);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/note-file-loader.ts
|
|
var NoteFileLoader = class {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
}
|
|
async load(noteFile, defaultTextDirection, folderTopicPath) {
|
|
this.noteFile = noteFile;
|
|
const questionParser = new NoteQuestionParser(this.settings);
|
|
const onlyKeepQuestionsWithTopicPath = true;
|
|
const questionList = await questionParser.createQuestionList(
|
|
noteFile,
|
|
defaultTextDirection,
|
|
folderTopicPath,
|
|
onlyKeepQuestionsWithTopicPath
|
|
);
|
|
const result = new Note(noteFile, questionList);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/core.ts
|
|
var OsrCore = class {
|
|
constructor() {
|
|
this._reviewableDeckTree = new Deck2("root", null);
|
|
}
|
|
get noteReviewQueue() {
|
|
return this._noteReviewQueue;
|
|
}
|
|
get remainingDeckTree() {
|
|
return this._remainingDeckTree;
|
|
}
|
|
get reviewableDeckTree() {
|
|
return this._reviewableDeckTree;
|
|
}
|
|
get questionPostponementList() {
|
|
return this._questionPostponementList;
|
|
}
|
|
get dueDateFlashcardHistogram() {
|
|
return this._dueDateFlashcardHistogram;
|
|
}
|
|
get dueDateNoteHistogram() {
|
|
return this._dueDateNoteHistogram;
|
|
}
|
|
get cardStats() {
|
|
return this._cardStats;
|
|
}
|
|
init(questionPostponementList, osrNoteLinkInfoFinder, settings, dataChangedHandler, noteReviewQueue) {
|
|
this.settings = settings;
|
|
this.osrNoteLinkInfoFinder = osrNoteLinkInfoFinder;
|
|
this.dataChangedHandler = dataChangedHandler;
|
|
this._noteReviewQueue = noteReviewQueue;
|
|
this._questionPostponementList = questionPostponementList;
|
|
this._dueDateFlashcardHistogram = new CardDueDateHistogram();
|
|
this._dueDateNoteHistogram = new NoteDueDateHistogram();
|
|
}
|
|
loadInit() {
|
|
this.osrNoteGraph = new OsrNoteGraph(this.osrNoteLinkInfoFinder);
|
|
this._noteReviewQueue.init();
|
|
this.fullDeckTree = new Deck2("root", null);
|
|
}
|
|
async processFile(noteFile) {
|
|
const schedule = await DataStoreAlgorithm.getInstance().noteGetSchedule(noteFile);
|
|
let note = null;
|
|
this.osrNoteGraph.processLinks(noteFile.path);
|
|
const topicPath = this.findTopicPath(noteFile);
|
|
if (topicPath.hasPath) {
|
|
note = await this.loadNote(noteFile, topicPath);
|
|
note.appendCardsToDeck(this.fullDeckTree);
|
|
}
|
|
SrsAlgorithm.getInstance().noteOnLoadedNote(noteFile.path, note, schedule == null ? void 0 : schedule.latestEase);
|
|
const tags = noteFile.getAllTagsFromCache();
|
|
const matchedNoteTags = SettingsUtil.filterForNoteReviewTag(this.settings, tags);
|
|
if (matchedNoteTags.length == 0) {
|
|
return;
|
|
}
|
|
const noteSchedule = await DataStoreAlgorithm.getInstance().noteGetSchedule(noteFile);
|
|
this._noteReviewQueue.addNoteToQueue(noteFile, noteSchedule, matchedNoteTags);
|
|
}
|
|
finaliseLoad() {
|
|
this.osrNoteGraph.generatePageRanks();
|
|
this._reviewableDeckTree = DeckTreeFilter.filterForReviewableCards(this.fullDeckTree);
|
|
this._reviewableDeckTree.sortSubdecksList();
|
|
this._remainingDeckTree = DeckTreeFilter.filterForRemainingCards(
|
|
this._questionPostponementList,
|
|
this._reviewableDeckTree,
|
|
1 /* Review */
|
|
);
|
|
const calc = new DeckTreeStatsCalculator();
|
|
this._cardStats = calc.calculate(this._reviewableDeckTree);
|
|
this.calculateDerivedInfo();
|
|
this._dueDateFlashcardHistogram.calculateFromDeckTree(this._reviewableDeckTree);
|
|
if (this.dataChangedHandler) this.dataChangedHandler();
|
|
}
|
|
async saveNoteReviewResponse(noteFile, response, settings) {
|
|
const originalNoteSchedule = await DataStoreAlgorithm.getInstance().noteGetSchedule(noteFile);
|
|
let noteSchedule;
|
|
if (originalNoteSchedule == null) {
|
|
noteSchedule = SrsAlgorithm.getInstance().noteCalcNewSchedule(
|
|
noteFile.path,
|
|
this.osrNoteGraph,
|
|
response,
|
|
this._dueDateNoteHistogram
|
|
);
|
|
} else {
|
|
noteSchedule = SrsAlgorithm.getInstance().noteCalcUpdatedSchedule(
|
|
noteFile.path,
|
|
originalNoteSchedule,
|
|
response,
|
|
this._dueDateNoteHistogram
|
|
);
|
|
}
|
|
await DataStoreAlgorithm.getInstance().noteSetSchedule(noteFile, noteSchedule);
|
|
this._noteReviewQueue.updateScheduleInfo(noteFile, noteSchedule);
|
|
this.calculateDerivedInfo();
|
|
await this.buryAllCardsInNote(settings, noteFile);
|
|
if (this.dataChangedHandler) this.dataChangedHandler();
|
|
}
|
|
calculateDerivedInfo() {
|
|
const todayUnix = globalDateProvider.today.valueOf();
|
|
this.noteReviewQueue.calcDueNotesCount(todayUnix);
|
|
this._dueDateNoteHistogram.calculateFromReviewDecksAndSort(
|
|
this.noteReviewQueue.reviewDecks,
|
|
this.osrNoteGraph
|
|
);
|
|
}
|
|
async buryAllCardsInNote(settings, noteFile) {
|
|
if (settings.burySiblingCards) {
|
|
const topicPath = this.findTopicPath(noteFile);
|
|
const noteX = await this.loadNote(noteFile, topicPath);
|
|
if (noteX.questionList.length > 0) {
|
|
for (const question of noteX.questionList) {
|
|
this._questionPostponementList.add(question);
|
|
}
|
|
await this._questionPostponementList.write();
|
|
}
|
|
}
|
|
}
|
|
async loadNote(noteFile, topicPath) {
|
|
const loader = new NoteFileLoader(this.settings);
|
|
const note = await loader.load(noteFile, this.defaultTextDirection, topicPath);
|
|
if (note.hasChanged) {
|
|
await note.writeNoteFile(this.settings);
|
|
}
|
|
return note;
|
|
}
|
|
findTopicPath(note) {
|
|
return TopicPath.getTopicPathOfFile(note, this.settings);
|
|
}
|
|
};
|
|
var OsrAppCore = class extends OsrCore {
|
|
constructor(app) {
|
|
super();
|
|
this._syncLock = false;
|
|
this.app = app;
|
|
}
|
|
get syncLock() {
|
|
return this._syncLock;
|
|
}
|
|
async loadVault() {
|
|
if (this._syncLock) {
|
|
return;
|
|
}
|
|
this._syncLock = true;
|
|
try {
|
|
this.loadInit();
|
|
const notes = this.app.vault.getMarkdownFiles();
|
|
for (const noteFile of notes) {
|
|
if (SettingsUtil.isPathInNoteIgnoreFolder(this.settings, noteFile.path)) {
|
|
continue;
|
|
}
|
|
const file = this.createSrTFile(noteFile);
|
|
await this.processFile(file);
|
|
}
|
|
this.finaliseLoad();
|
|
} finally {
|
|
this._syncLock = false;
|
|
}
|
|
}
|
|
createSrTFile(note) {
|
|
return new SrTFile(this.app.vault, this.app.metadataCache, note);
|
|
}
|
|
};
|
|
|
|
// src/data-store-algorithm/data-store-in-note-algorithm-osr.ts
|
|
var import_moment3 = __toESM(require_moment());
|
|
var DataStoreInNoteAlgorithmOsr = class {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
}
|
|
async noteGetSchedule(note) {
|
|
let result = null;
|
|
const frontmatter = await note.getFrontmatter();
|
|
if (frontmatter && frontmatter.has("sr-due") && frontmatter.has("sr-interval") && frontmatter.has("sr-ease")) {
|
|
const dueDate = (0, import_moment3.default)(frontmatter.get("sr-due"), ALLOWED_DATE_FORMATS);
|
|
const interval = parseFloat(frontmatter.get("sr-interval"));
|
|
const ease = parseFloat(frontmatter.get("sr-ease"));
|
|
result = new RepItemScheduleInfoOsr(dueDate, interval, ease);
|
|
}
|
|
return result;
|
|
}
|
|
async noteSetSchedule(note, repItemScheduleInfo) {
|
|
let fileText = await note.read();
|
|
const schedInfo = repItemScheduleInfo;
|
|
const dueString = formatDateYYYYMMDD(schedInfo.dueDate);
|
|
const interval = schedInfo.interval;
|
|
const ease = schedInfo.latestEase;
|
|
if (SCHEDULING_INFO_REGEX.test(fileText)) {
|
|
const schedulingInfo = SCHEDULING_INFO_REGEX.exec(fileText);
|
|
fileText = fileText.replace(
|
|
SCHEDULING_INFO_REGEX,
|
|
`---
|
|
${schedulingInfo[1]}sr-due: ${dueString}
|
|
sr-interval: ${interval}
|
|
sr-ease: ${ease}
|
|
${schedulingInfo[5]}---`
|
|
);
|
|
} else if (YAML_FRONT_MATTER_REGEX.test(fileText)) {
|
|
const existingYaml = YAML_FRONT_MATTER_REGEX.exec(fileText);
|
|
fileText = fileText.replace(
|
|
YAML_FRONT_MATTER_REGEX,
|
|
`---
|
|
${existingYaml[1]}sr-due: ${dueString}
|
|
sr-interval: ${interval}
|
|
sr-ease: ${ease}
|
|
---`
|
|
);
|
|
} else {
|
|
fileText = `---
|
|
sr-due: ${dueString}
|
|
sr-interval: ${interval}
|
|
sr-ease: ${ease}
|
|
---
|
|
|
|
${fileText}`;
|
|
}
|
|
await note.write(fileText);
|
|
}
|
|
questionFormatScheduleAsHtmlComment(question) {
|
|
let result = SR_HTML_COMMENT_BEGIN;
|
|
for (let i2 = 0; i2 < question.cards.length; i2++) {
|
|
const card = question.cards[i2];
|
|
result += this.formatCardSchedule(card);
|
|
}
|
|
result += SR_HTML_COMMENT_END;
|
|
return result;
|
|
}
|
|
formatCardSchedule(card) {
|
|
let result;
|
|
if (card.hasSchedule) {
|
|
const schedule = card.scheduleInfo;
|
|
const dateStr = schedule.dueDate ? formatDateYYYYMMDD(schedule.dueDate) : RepItemScheduleInfoOsr.dummyDueDateForNewCard;
|
|
result = `!${dateStr},${schedule.interval},${schedule.latestEase}`;
|
|
} else {
|
|
result = `!${RepItemScheduleInfoOsr.dummyDueDateForNewCard},${RepItemScheduleInfoOsr.initialInterval},${this.settings.baseEase}`;
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// src/data-stores/notes/notes.ts
|
|
var StoreInNotes = class {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
}
|
|
questionCreateSchedule(originalQuestionText, _2) {
|
|
let scheduling = [
|
|
...originalQuestionText.matchAll(MULTI_SCHEDULING_EXTRACTOR)
|
|
];
|
|
if (scheduling.length === 0)
|
|
scheduling = [...originalQuestionText.matchAll(LEGACY_SCHEDULING_EXTRACTOR)];
|
|
const result = [];
|
|
for (let i2 = 0; i2 < scheduling.length; i2++) {
|
|
const match2 = scheduling[i2];
|
|
const dueDateStr = match2[1];
|
|
const interval = parseInt(match2[2]);
|
|
const ease = parseInt(match2[3]);
|
|
const dueDate = DateUtil.dateStrToMoment(dueDateStr);
|
|
let info;
|
|
if (dueDate == null || formatDateYYYYMMDD(dueDate) == RepItemScheduleInfoOsr.dummyDueDateForNewCard) {
|
|
info = null;
|
|
} else {
|
|
const delayBeforeReviewTicks = dueDate.valueOf() - globalDateProvider.today.valueOf();
|
|
info = new RepItemScheduleInfoOsr(dueDate, interval, ease, delayBeforeReviewTicks);
|
|
}
|
|
result.push(info);
|
|
}
|
|
return result;
|
|
}
|
|
questionRemoveScheduleInfo(questionText) {
|
|
return questionText.replace(/<!--SR:.+-->/gm, "");
|
|
}
|
|
async questionWriteSchedule(question) {
|
|
await this.questionWrite(question);
|
|
}
|
|
async questionWrite(question) {
|
|
const fileText = await question.note.file.read();
|
|
const newText = question.updateQuestionWithinNoteText(fileText, this.settings);
|
|
await question.note.file.write(newText);
|
|
question.hasChanged = false;
|
|
}
|
|
};
|
|
|
|
// src/gui/flashcard-modal.tsx
|
|
var import_obsidian7 = require("obsidian");
|
|
|
|
// src/gui/deck-list-view.tsx
|
|
var import_vhtml = __toESM(require_vhtml());
|
|
var DeckListView = class {
|
|
constructor(plugin, settings, reviewSequencer, contentEl, startReviewOfDeck) {
|
|
this.plugin = plugin;
|
|
this.settings = settings;
|
|
this.reviewSequencer = reviewSequencer;
|
|
this.modalContentEl = contentEl;
|
|
this.startReviewOfDeck = startReviewOfDeck;
|
|
this.init();
|
|
}
|
|
/**
|
|
* Initializes all static elements in the DeckListView
|
|
*/
|
|
init() {
|
|
this.view = this.modalContentEl.createDiv();
|
|
this.view.addClasses(["sr-deck-list", "sr-is-hidden"]);
|
|
this.header = this.view.createDiv();
|
|
this.header.addClass("sr-header");
|
|
this.title = this.header.createDiv();
|
|
this.title.addClass("sr-title");
|
|
this.title.setText(t("DECKS"));
|
|
this.stats = this.header.createDiv();
|
|
this.stats.addClass("sr-header-stats-container");
|
|
this._createHeaderStats();
|
|
this.content = this.view.createDiv();
|
|
this.content.addClass("sr-content");
|
|
}
|
|
/**
|
|
* Shows the DeckListView & rerenders dynamic elements
|
|
*/
|
|
show() {
|
|
this.mode = 0 /* DecksList */;
|
|
this._createHeaderStats();
|
|
this.content.empty();
|
|
for (const deck of this.reviewSequencer.originalDeckTree.subdecks) {
|
|
this._createTree(deck, this.content);
|
|
}
|
|
if (this.view.hasClass("sr-is-hidden")) {
|
|
this.view.removeClass("sr-is-hidden");
|
|
}
|
|
}
|
|
/**
|
|
* Hides the DeckListView
|
|
*/
|
|
hide() {
|
|
if (!this.view.hasClass("sr-is-hidden")) {
|
|
this.view.addClass("sr-is-hidden");
|
|
}
|
|
}
|
|
/**
|
|
* Closes the DeckListView
|
|
*/
|
|
close() {
|
|
this.hide();
|
|
}
|
|
// -> Header
|
|
_createHeaderStats() {
|
|
const statistics = this.reviewSequencer.getDeckStats(TopicPath.emptyPath);
|
|
this.stats.empty();
|
|
this._createHeaderStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green");
|
|
this._createHeaderStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue");
|
|
this._createHeaderStatsContainer(t("TOTAL_CARDS"), statistics.totalCount, "sr-bg-red");
|
|
}
|
|
_createHeaderStatsContainer(statsLable, statsNumber, statsClass) {
|
|
const statsContainer = this.stats.createDiv();
|
|
statsContainer.ariaLabel = statsLable;
|
|
statsContainer.addClasses([
|
|
"tag-pane-tag-count",
|
|
"tree-item-flair",
|
|
"sr-header-stats-count",
|
|
statsClass
|
|
]);
|
|
const lable = statsContainer.createDiv();
|
|
lable.setText(statsLable + ":");
|
|
const number = statsContainer.createDiv();
|
|
number.setText(statsNumber.toString());
|
|
}
|
|
// -> Tree content
|
|
_createTree(deck, container) {
|
|
const deckTree = container.createDiv("tree-item sr-tree-item-container");
|
|
const deckTreeSelf = deckTree.createDiv(
|
|
"tree-item-self tag-pane-tag is-clickable sr-tree-item-row"
|
|
);
|
|
const shouldBeInitiallyExpanded = this.settings.initiallyExpandAllSubdecksInTree;
|
|
let collapsed = !shouldBeInitiallyExpanded;
|
|
let collapseIconEl = null;
|
|
if (deck.subdecks.length > 0) {
|
|
collapseIconEl = deckTreeSelf.createDiv("tree-item-icon collapse-icon");
|
|
collapseIconEl.innerHTML = COLLAPSE_ICON;
|
|
collapseIconEl.childNodes[0].style.transform = collapsed ? "rotate(-90deg)" : "";
|
|
}
|
|
const deckTreeInner = deckTreeSelf.createDiv("tree-item-inner");
|
|
const deckTreeInnerText = deckTreeInner.createDiv("tag-pane-tag-text");
|
|
deckTreeInnerText.innerHTML += /* @__PURE__ */ (0, import_vhtml.default)("span", { class: "tag-pane-tag-self" }, deck.deckName);
|
|
const deckTreeOuter = deckTreeSelf.createDiv();
|
|
deckTreeOuter.addClasses(["tree-item-flair-outer", "sr-tree-stats-container"]);
|
|
const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath());
|
|
this._createStats(deckStats, deckTreeOuter);
|
|
const deckTreeChildren = deckTree.createDiv("tree-item-children");
|
|
deckTreeChildren.style.display = collapsed ? "none" : "block";
|
|
if (deck.subdecks.length > 0) {
|
|
collapseIconEl.addEventListener("click", (e2) => {
|
|
if (collapsed) {
|
|
collapseIconEl.childNodes[0].style.transform = "";
|
|
deckTreeChildren.style.display = "block";
|
|
} else {
|
|
collapseIconEl.childNodes[0].style.transform = "rotate(-90deg)";
|
|
deckTreeChildren.style.display = "none";
|
|
}
|
|
e2.stopPropagation();
|
|
collapsed = !collapsed;
|
|
});
|
|
}
|
|
deckTreeSelf.addEventListener("click", () => {
|
|
this.startReviewOfDeck(deck);
|
|
});
|
|
for (const subdeck of deck.subdecks) {
|
|
this._createTree(subdeck, deckTreeChildren);
|
|
}
|
|
}
|
|
_createStats(statistics, statsWrapper) {
|
|
statsWrapper.empty();
|
|
this._createStatsContainer(
|
|
t("DUE_CARDS"),
|
|
statistics.dueCount,
|
|
"sr-bg-green",
|
|
statsWrapper
|
|
);
|
|
this._createStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue", statsWrapper);
|
|
this._createStatsContainer(
|
|
t("TOTAL_CARDS"),
|
|
statistics.totalCount,
|
|
"sr-bg-red",
|
|
statsWrapper
|
|
);
|
|
}
|
|
_createStatsContainer(statsLable, statsNumber, statsClass, statsWrapper) {
|
|
const statsContainer = statsWrapper.createDiv();
|
|
statsContainer.ariaLabel = statsLable;
|
|
statsContainer.addClasses([
|
|
"tag-pane-tag-count",
|
|
"tree-item-flair",
|
|
"sr-tree-stats-count",
|
|
statsClass
|
|
]);
|
|
statsContainer.setText(statsNumber.toString());
|
|
}
|
|
};
|
|
|
|
// src/gui/edit-modal.tsx
|
|
var import_obsidian4 = require("obsidian");
|
|
var FlashcardEditModal = class _FlashcardEditModal extends import_obsidian4.Modal {
|
|
constructor(app, existingText, textDirection) {
|
|
super(app);
|
|
this.didSaveChanges = false;
|
|
// -> Functions & helpers
|
|
this.saveClickCallback = (_2) => this.save();
|
|
this.cancelClickCallback = (_2) => this.cancel();
|
|
this.saveOnEnterCallback = (evt) => {
|
|
if ((evt.ctrlKey || evt.metaKey) && evt.key === "Enter") {
|
|
evt.preventDefault();
|
|
this.save();
|
|
}
|
|
};
|
|
this.modalText = existingText;
|
|
this.changedText = existingText;
|
|
this.textDirection = textDirection;
|
|
this.waitForClose = new Promise((resolve2, reject) => {
|
|
this.resolvePromise = resolve2;
|
|
this.rejectPromise = reject;
|
|
});
|
|
this.modalEl.addClasses(["sr-modal", "sr-edit-modal"]);
|
|
this.init();
|
|
this.open();
|
|
}
|
|
static Prompt(app, placeholder, textDirection) {
|
|
const newPromptModal = new _FlashcardEditModal(app, placeholder, textDirection);
|
|
return newPromptModal.waitForClose;
|
|
}
|
|
/**
|
|
* Initializes all components of the EditModal
|
|
*/
|
|
init() {
|
|
var _a;
|
|
this.contentEl.empty();
|
|
this.contentEl.addClass("sr-edit-view");
|
|
this.title = this.contentEl.createDiv();
|
|
this.title.setText(t("EDIT_CARD"));
|
|
this.title.addClass("sr-title");
|
|
this.textArea = this.contentEl.createEl("textarea");
|
|
this.textArea.addClass("sr-input");
|
|
this.textArea.setText((_a = this.modalText) != null ? _a : "");
|
|
this.textArea.addEventListener("keydown", this.saveOnEnterCallback);
|
|
if (this.textDirection == 2 /* Rtl */) {
|
|
this.textArea.setAttribute("dir", "rtl");
|
|
}
|
|
this._createResponse(this.contentEl);
|
|
}
|
|
/**
|
|
* Opens the EditModal
|
|
*/
|
|
onOpen() {
|
|
super.onOpen();
|
|
this.textArea.focus();
|
|
}
|
|
/**
|
|
* Closes the EditModal
|
|
*/
|
|
onClose() {
|
|
super.onClose();
|
|
this.resolveInput();
|
|
this.removeInputListener();
|
|
}
|
|
save() {
|
|
this.didSaveChanges = true;
|
|
this.changedText = this.textArea.value;
|
|
this.close();
|
|
}
|
|
cancel() {
|
|
this.close();
|
|
}
|
|
resolveInput() {
|
|
if (!this.didSaveChanges) this.rejectPromise(t("NO_INPUT"));
|
|
else this.resolvePromise(this.changedText);
|
|
}
|
|
removeInputListener() {
|
|
this.textArea.removeEventListener("keydown", this.saveOnEnterCallback);
|
|
}
|
|
// -> Response section
|
|
_createResponseButton(container, text, colorClass, callback2) {
|
|
const button = container.createEl("button");
|
|
button.addClasses(["sr-response-button", colorClass]);
|
|
button.setText(text);
|
|
button.addEventListener("click", callback2);
|
|
}
|
|
_createResponse(mainContentContainer) {
|
|
const response = mainContentContainer.createDiv();
|
|
response.addClass("sr-response");
|
|
this._createResponseButton(response, t("CANCEL"), "sr-bg-red", this.cancelClickCallback);
|
|
this._createResponseButton(response, "", "sr-spacer", () => {
|
|
});
|
|
this._createResponseButton(response, t("SAVE"), "sr-bg-green", this.saveClickCallback);
|
|
}
|
|
};
|
|
|
|
// src/gui/flashcard-review-view.tsx
|
|
var import_moment4 = __toESM(require_moment());
|
|
var import_obsidian6 = require("obsidian");
|
|
|
|
// src/utils/renderers.ts
|
|
var import_obsidian5 = require("obsidian");
|
|
var RenderMarkdownWrapper = class {
|
|
constructor(app, plugin, notePath) {
|
|
this.app = app;
|
|
this.notePath = notePath;
|
|
this.plugin = plugin;
|
|
}
|
|
// slightly modified version of the renderMarkdown function in
|
|
// https://github.com/mgmeyers/obsidian-kanban/blob/main/src/KanbanView.tsx
|
|
async renderMarkdownWrapper(markdownString, containerEl, textDirection, recursiveDepth = 0) {
|
|
if (recursiveDepth > 4) return;
|
|
let el;
|
|
if (textDirection == 2 /* Rtl */) {
|
|
el = containerEl.createDiv();
|
|
el.setAttribute("dir", "rtl");
|
|
} else el = containerEl;
|
|
import_obsidian5.MarkdownRenderer.render(this.app, markdownString, el, this.notePath, this.plugin);
|
|
el.findAll(".internal-embed").forEach((el2) => {
|
|
const link2 = this.parseLink(el2.getAttribute("src"));
|
|
if (!link2.target) {
|
|
el2.innerText = link2.text;
|
|
} else if (link2.target instanceof import_obsidian5.TFile) {
|
|
if (link2.target.extension !== "md") {
|
|
this.embedMediaFile(el2, link2.target);
|
|
} else {
|
|
}
|
|
}
|
|
});
|
|
}
|
|
parseLink(src) {
|
|
const linkComponentsRegex = /^(?<file>[^#^]+)?(?:#(?!\^)(?<heading>.+)|#\^(?<blockId>.+)|#)?$/;
|
|
const matched = typeof src === "string" && src.match(linkComponentsRegex);
|
|
const file = matched.groups.file || this.notePath;
|
|
const target = this.plugin.app.metadataCache.getFirstLinkpathDest(file, this.notePath);
|
|
return {
|
|
text: matched[0],
|
|
file: matched.groups.file,
|
|
heading: matched.groups.heading,
|
|
blockId: matched.groups.blockId,
|
|
target
|
|
};
|
|
}
|
|
embedMediaFile(el, target) {
|
|
el.innerText = "";
|
|
if (IMAGE_FORMATS.includes(target.extension)) {
|
|
el.createEl(
|
|
"img",
|
|
{
|
|
attr: {
|
|
src: this.plugin.app.vault.getResourcePath(target)
|
|
}
|
|
},
|
|
(img) => {
|
|
if (el.hasAttribute("width"))
|
|
img.setAttribute("width", el.getAttribute("width"));
|
|
else img.setAttribute("width", "100%");
|
|
if (el.hasAttribute("alt")) img.setAttribute("alt", el.getAttribute("alt"));
|
|
el.addEventListener(
|
|
"click",
|
|
(ev) => ev.target.style.minWidth = ev.target.style.minWidth === "100%" ? null : "100%"
|
|
);
|
|
}
|
|
);
|
|
el.addClasses(["image-embed", "is-loaded"]);
|
|
} else if (AUDIO_FORMATS.includes(target.extension) || VIDEO_FORMATS.includes(target.extension)) {
|
|
el.createEl(
|
|
AUDIO_FORMATS.includes(target.extension) ? "audio" : "video",
|
|
{
|
|
attr: {
|
|
controls: "",
|
|
src: this.plugin.app.vault.getResourcePath(target)
|
|
}
|
|
},
|
|
(audio) => {
|
|
if (el.hasAttribute("alt")) audio.setAttribute("alt", el.getAttribute("alt"));
|
|
}
|
|
);
|
|
el.addClasses(["media-embed", "is-loaded"]);
|
|
} else {
|
|
el.innerText = target.path;
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/gui/flashcard-review-view.tsx
|
|
var FlashcardReviewView = class {
|
|
constructor(app, plugin, settings, reviewSequencer, reviewMode, contentEl, modalEl, backClickHandler, editClickHandler) {
|
|
this._keydownHandler = (e2) => {
|
|
if (document.activeElement.nodeName === "TEXTAREA" || this.mode === 3 /* Closed */) {
|
|
return;
|
|
}
|
|
const consumeKeyEvent = () => {
|
|
e2.preventDefault();
|
|
e2.stopPropagation();
|
|
};
|
|
switch (e2.code) {
|
|
case "KeyS":
|
|
this._skipCurrentCard();
|
|
consumeKeyEvent();
|
|
break;
|
|
case "Space":
|
|
if (this.mode === 1 /* Front */) {
|
|
this._showAnswer();
|
|
consumeKeyEvent();
|
|
} else if (this.mode === 2 /* Back */) {
|
|
this._processReview(1 /* Good */);
|
|
consumeKeyEvent();
|
|
}
|
|
break;
|
|
case "Enter":
|
|
case "NumpadEnter":
|
|
if (this.mode !== 1 /* Front */) {
|
|
break;
|
|
}
|
|
this._showAnswer();
|
|
consumeKeyEvent();
|
|
break;
|
|
case "Numpad1":
|
|
case "Digit1":
|
|
if (this.mode !== 2 /* Back */) {
|
|
break;
|
|
}
|
|
this._processReview(2 /* Hard */);
|
|
consumeKeyEvent();
|
|
break;
|
|
case "Numpad2":
|
|
case "Digit2":
|
|
if (this.mode !== 2 /* Back */) {
|
|
break;
|
|
}
|
|
this._processReview(1 /* Good */);
|
|
consumeKeyEvent();
|
|
break;
|
|
case "Numpad3":
|
|
case "Digit3":
|
|
if (this.mode !== 2 /* Back */) {
|
|
break;
|
|
}
|
|
this._processReview(0 /* Easy */);
|
|
consumeKeyEvent();
|
|
break;
|
|
case "Numpad0":
|
|
case "Digit0":
|
|
if (this.mode !== 2 /* Back */) {
|
|
break;
|
|
}
|
|
this._processReview(3 /* Reset */);
|
|
consumeKeyEvent();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
this.app = app;
|
|
this.plugin = plugin;
|
|
this.settings = settings;
|
|
this.reviewSequencer = reviewSequencer;
|
|
this.reviewMode = reviewMode;
|
|
this.backClickHandler = backClickHandler;
|
|
this.editClickHandler = editClickHandler;
|
|
this.modalContentEl = contentEl;
|
|
this.modalEl = modalEl;
|
|
this.chosenDeck = null;
|
|
this.init();
|
|
}
|
|
/**
|
|
* Initializes all static elements in the FlashcardView
|
|
*/
|
|
init() {
|
|
this._createBackButton();
|
|
this.view = this.modalContentEl.createDiv();
|
|
this.view.addClasses(["sr-flashcard", "sr-is-hidden"]);
|
|
this.header = this.view.createDiv();
|
|
this.header.addClass("sr-header");
|
|
this.titleWrapper = this.header.createDiv();
|
|
this.titleWrapper.addClass("sr-title-wrapper");
|
|
this.title = this.titleWrapper.createDiv();
|
|
this.title.addClass("sr-title");
|
|
this.subTitle = this.titleWrapper.createDiv();
|
|
this.subTitle.addClasses(["sr-sub-title", "sr-is-hidden"]);
|
|
this.controls = this.header.createDiv();
|
|
this.controls.addClass("sr-controls");
|
|
this._createCardControls();
|
|
if (this.settings.showContextInCards) {
|
|
this.context = this.view.createDiv();
|
|
this.context.addClass("sr-context");
|
|
}
|
|
this.content = this.view.createDiv();
|
|
this.content.addClass("sr-content");
|
|
this.response = this.view.createDiv();
|
|
this.response.addClass("sr-response");
|
|
this._createResponseButtons();
|
|
}
|
|
/**
|
|
* Shows the FlashcardView if it is hidden
|
|
*/
|
|
async show(chosenDeck) {
|
|
if (!this.view.hasClass("sr-is-hidden")) {
|
|
return;
|
|
}
|
|
this.chosenDeck = chosenDeck;
|
|
await this._drawContent();
|
|
this.view.removeClass("sr-is-hidden");
|
|
this.backButton.removeClass("sr-is-hidden");
|
|
document.addEventListener("keydown", this._keydownHandler);
|
|
}
|
|
/**
|
|
* Refreshes all dynamic elements
|
|
*/
|
|
async refresh() {
|
|
await this._drawContent();
|
|
}
|
|
/**
|
|
* Hides the FlashcardView if it is visible
|
|
*/
|
|
hide() {
|
|
if (this.view.hasClass("sr-is-hidden")) {
|
|
return;
|
|
}
|
|
document.removeEventListener("keydown", this._keydownHandler);
|
|
this.view.addClass("sr-is-hidden");
|
|
this.backButton.addClass("sr-is-hidden");
|
|
}
|
|
/**
|
|
* Closes the FlashcardView
|
|
*/
|
|
close() {
|
|
this.hide();
|
|
document.removeEventListener("keydown", this._keydownHandler);
|
|
}
|
|
// #region -> Functions & helpers
|
|
async _drawContent() {
|
|
this.mode = 1 /* Front */;
|
|
const currentDeck = this.reviewSequencer.currentDeck;
|
|
this._setTitle(this.chosenDeck);
|
|
this._setSubTitle(this.chosenDeck, currentDeck);
|
|
this.resetButton.disabled = true;
|
|
if (this.settings.showContextInCards) {
|
|
this.context.setText(
|
|
this._formatQuestionContextText(this._currentQuestion.questionContext)
|
|
);
|
|
}
|
|
this.content.empty();
|
|
const wrapper = new RenderMarkdownWrapper(
|
|
this.app,
|
|
this.plugin,
|
|
this._currentNote.filePath
|
|
);
|
|
await wrapper.renderMarkdownWrapper(
|
|
this._currentCard.front.trimStart(),
|
|
this.content,
|
|
this._currentQuestion.questionText.textDirection
|
|
);
|
|
this.content.scrollTop = 0;
|
|
this._resetResponseButtons();
|
|
}
|
|
_displayCurrentCardInfoNotice() {
|
|
var _a;
|
|
const schedule = this._currentCard.scheduleInfo;
|
|
const currentEaseStr = t("CURRENT_EASE_HELP_TEXT") + ((_a = schedule == null ? void 0 : schedule.latestEase) != null ? _a : t("NEW"));
|
|
const currentIntervalStr = t("CURRENT_INTERVAL_HELP_TEXT") + textInterval(schedule == null ? void 0 : schedule.interval, false);
|
|
const generatedFromStr = t("CARD_GENERATED_FROM", {
|
|
notePath: this._currentQuestion.note.filePath
|
|
});
|
|
new import_obsidian6.Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr);
|
|
}
|
|
get _currentCard() {
|
|
return this.reviewSequencer.currentCard;
|
|
}
|
|
get _currentQuestion() {
|
|
return this.reviewSequencer.currentQuestion;
|
|
}
|
|
get _currentNote() {
|
|
return this.reviewSequencer.currentNote;
|
|
}
|
|
_showAnswer() {
|
|
const timeNow = (0, import_moment4.now)();
|
|
if (this.lastPressed && timeNow - this.lastPressed < this.plugin.data.settings.reviewButtonDelay) {
|
|
return;
|
|
}
|
|
this.lastPressed = timeNow;
|
|
this.mode = 2 /* Back */;
|
|
this.resetButton.disabled = false;
|
|
if (this._currentQuestion.questionType !== 4 /* Cloze */) {
|
|
const hr = document.createElement("hr");
|
|
hr.addClass("sr-card-divide");
|
|
this.content.appendChild(hr);
|
|
} else {
|
|
this.content.empty();
|
|
}
|
|
const wrapper = new RenderMarkdownWrapper(
|
|
this.app,
|
|
this.plugin,
|
|
this._currentNote.filePath
|
|
);
|
|
wrapper.renderMarkdownWrapper(
|
|
this._currentCard.back,
|
|
this.content,
|
|
this._currentQuestion.questionText.textDirection
|
|
);
|
|
this.answerButton.addClass("sr-is-hidden");
|
|
this.hardButton.removeClass("sr-is-hidden");
|
|
this.easyButton.removeClass("sr-is-hidden");
|
|
if (this.reviewMode === 0 /* Cram */) {
|
|
this.response.addClass("is-cram");
|
|
this.hardButton.setText(`${this.settings.flashcardHardText}`);
|
|
this.easyButton.setText(`${this.settings.flashcardEasyText}`);
|
|
} else {
|
|
this.goodButton.removeClass("sr-is-hidden");
|
|
this._setupEaseButton(
|
|
this.hardButton,
|
|
this.settings.flashcardHardText,
|
|
2 /* Hard */
|
|
);
|
|
this._setupEaseButton(
|
|
this.goodButton,
|
|
this.settings.flashcardGoodText,
|
|
1 /* Good */
|
|
);
|
|
this._setupEaseButton(
|
|
this.easyButton,
|
|
this.settings.flashcardEasyText,
|
|
0 /* Easy */
|
|
);
|
|
}
|
|
}
|
|
async _processReview(response) {
|
|
const timeNow = (0, import_moment4.now)();
|
|
if (this.lastPressed && timeNow - this.lastPressed < this.plugin.data.settings.reviewButtonDelay) {
|
|
return;
|
|
}
|
|
this.lastPressed = timeNow;
|
|
await this.reviewSequencer.processReview(response);
|
|
await this._handleSkipCard();
|
|
}
|
|
async _skipCurrentCard() {
|
|
this.reviewSequencer.skipCurrentCard();
|
|
await this._handleSkipCard();
|
|
}
|
|
async _handleSkipCard() {
|
|
if (this._currentCard != null) await this.refresh();
|
|
else this.backClickHandler();
|
|
}
|
|
_formatQuestionContextText(questionContext) {
|
|
const separator = " > ";
|
|
let result = this._currentNote.file.basename;
|
|
questionContext.forEach((context) => {
|
|
if (context.startsWith("[[") && context.endsWith("]]")) {
|
|
context = context.replace("[[", "").replace("]]", "");
|
|
if (context.contains("|")) {
|
|
context = context.split("|")[1];
|
|
}
|
|
}
|
|
result += separator + context;
|
|
});
|
|
return result;
|
|
}
|
|
// -> Header
|
|
_createBackButton() {
|
|
this.backButton = this.modalEl.createDiv();
|
|
this.backButton.addClasses(["sr-back-button", "sr-is-hidden"]);
|
|
(0, import_obsidian6.setIcon)(this.backButton, "arrow-left");
|
|
this.backButton.setAttribute("aria-label", t("BACK"));
|
|
this.backButton.addEventListener("click", () => {
|
|
this.backClickHandler();
|
|
});
|
|
}
|
|
_setTitle(deck) {
|
|
let text = deck.deckName;
|
|
const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath());
|
|
const cardsInQueue = deckStats.dueCount + deckStats.newCount;
|
|
text += `: ${cardsInQueue}`;
|
|
this.title.setText(text);
|
|
}
|
|
_setSubTitle(chosenDeck, currentDeck) {
|
|
if (chosenDeck.subdecks.length === 0) {
|
|
if (!this.subTitle.hasClass("sr-is-hidden")) {
|
|
this.subTitle.addClass("sr-is-hidden");
|
|
}
|
|
return;
|
|
}
|
|
if (this.subTitle.hasClass("sr-is-hidden")) {
|
|
this.subTitle.removeClass("sr-is-hidden");
|
|
}
|
|
let text = `${currentDeck.deckName}`;
|
|
const isRandomMode = this.settings.flashcardCardOrder === "EveryCardRandomDeckAndCard";
|
|
if (!isRandomMode) {
|
|
const subDecksWithCardsInQueue = chosenDeck.subdecks.filter((subDeck) => {
|
|
const deckStats = this.reviewSequencer.getDeckStats(subDeck.getTopicPath());
|
|
return deckStats.dueCount + deckStats.newCount > 0;
|
|
});
|
|
text = `${t("DECKS")}: ${subDecksWithCardsInQueue.length} | ${text}`;
|
|
text += `: ${currentDeck.getCardCount(2 /* All */, false)}`;
|
|
}
|
|
this.subTitle.setText(text);
|
|
}
|
|
// -> Controls
|
|
_createCardControls() {
|
|
this._createEditButton();
|
|
this._createResetButton();
|
|
this._createCardInfoButton();
|
|
this._createSkipButton();
|
|
}
|
|
_createEditButton() {
|
|
this.editButton = this.controls.createEl("button");
|
|
this.editButton.addClasses(["sr-button", "sr-edit-button"]);
|
|
(0, import_obsidian6.setIcon)(this.editButton, "edit");
|
|
this.editButton.setAttribute("aria-label", t("EDIT_CARD"));
|
|
this.editButton.addEventListener("click", async () => {
|
|
this.editClickHandler();
|
|
});
|
|
}
|
|
_createResetButton() {
|
|
this.resetButton = this.controls.createEl("button");
|
|
this.resetButton.addClasses(["sr-button", "sr-reset-button"]);
|
|
(0, import_obsidian6.setIcon)(this.resetButton, "refresh-cw");
|
|
this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS"));
|
|
this.resetButton.addEventListener("click", () => {
|
|
this._processReview(3 /* Reset */);
|
|
});
|
|
}
|
|
_createCardInfoButton() {
|
|
this.infoButton = this.controls.createEl("button");
|
|
this.infoButton.addClasses(["sr-button", "sr-info-button"]);
|
|
(0, import_obsidian6.setIcon)(this.infoButton, "info");
|
|
this.infoButton.setAttribute("aria-label", "View Card Info");
|
|
this.infoButton.addEventListener("click", async () => {
|
|
this._displayCurrentCardInfoNotice();
|
|
});
|
|
}
|
|
_createSkipButton() {
|
|
this.skipButton = this.controls.createEl("button");
|
|
this.skipButton.addClasses(["sr-button", "sr-skip-button"]);
|
|
(0, import_obsidian6.setIcon)(this.skipButton, "chevrons-right");
|
|
this.skipButton.setAttribute("aria-label", t("SKIP"));
|
|
this.skipButton.addEventListener("click", () => {
|
|
this._skipCurrentCard();
|
|
});
|
|
}
|
|
// -> Response
|
|
_createResponseButtons() {
|
|
this._createShowAnswerButton();
|
|
this._createHardButton();
|
|
this._createGoodButton();
|
|
this._createEasyButton();
|
|
}
|
|
_resetResponseButtons() {
|
|
this.answerButton.removeClass("sr-is-hidden");
|
|
this.hardButton.addClass("sr-is-hidden");
|
|
this.goodButton.addClass("sr-is-hidden");
|
|
this.easyButton.addClass("sr-is-hidden");
|
|
}
|
|
_createShowAnswerButton() {
|
|
this.answerButton = this.response.createEl("button");
|
|
this.answerButton.addClasses(["sr-response-button", "sr-show-answer-button", "sr-bg-blue"]);
|
|
this.answerButton.setText(t("SHOW_ANSWER"));
|
|
this.answerButton.addEventListener("click", () => {
|
|
this._showAnswer();
|
|
});
|
|
}
|
|
_createHardButton() {
|
|
this.hardButton = this.response.createEl("button");
|
|
this.hardButton.addClasses([
|
|
"sr-response-button",
|
|
"sr-hard-button",
|
|
"sr-bg-red",
|
|
"sr-is-hidden"
|
|
]);
|
|
this.hardButton.setText(this.settings.flashcardHardText);
|
|
this.hardButton.addEventListener("click", () => {
|
|
this._processReview(2 /* Hard */);
|
|
});
|
|
}
|
|
_createGoodButton() {
|
|
this.goodButton = this.response.createEl("button");
|
|
this.goodButton.addClasses([
|
|
"sr-response-button",
|
|
"sr-good-button",
|
|
"sr-bg-blue",
|
|
"sr-is-hidden"
|
|
]);
|
|
this.goodButton.setText(this.settings.flashcardGoodText);
|
|
this.goodButton.addEventListener("click", () => {
|
|
this._processReview(1 /* Good */);
|
|
});
|
|
}
|
|
_createEasyButton() {
|
|
this.easyButton = this.response.createEl("button");
|
|
this.easyButton.addClasses([
|
|
"sr-response-button",
|
|
"sr-hard-button",
|
|
"sr-bg-green",
|
|
"sr-is-hidden"
|
|
]);
|
|
this.easyButton.setText(this.settings.flashcardEasyText);
|
|
this.easyButton.addEventListener("click", () => {
|
|
this._processReview(0 /* Easy */);
|
|
});
|
|
}
|
|
_setupEaseButton(button, buttonName, reviewResponse) {
|
|
const schedule = this.reviewSequencer.determineCardSchedule(
|
|
reviewResponse,
|
|
this._currentCard
|
|
);
|
|
const interval = schedule.interval;
|
|
if (this.settings.showIntervalInReviewButtons) {
|
|
if (import_obsidian6.Platform.isMobile) {
|
|
button.setText(textInterval(interval, true));
|
|
} else {
|
|
button.setText(`${buttonName} - ${textInterval(interval, false)}`);
|
|
}
|
|
} else {
|
|
button.setText(buttonName);
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/gui/flashcard-modal.tsx
|
|
var FlashcardModal = class extends import_obsidian7.Modal {
|
|
constructor(app, plugin, settings, reviewSequencer, reviewMode) {
|
|
super(app);
|
|
this.plugin = plugin;
|
|
this.settings = settings;
|
|
this.reviewSequencer = reviewSequencer;
|
|
this.reviewMode = reviewMode;
|
|
this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%";
|
|
this.modalEl.style.maxHeight = this.settings.flashcardHeightPercentage + "%";
|
|
this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%";
|
|
this.modalEl.style.maxWidth = this.settings.flashcardWidthPercentage + "%";
|
|
this.modalEl.setAttribute("id", "sr-modal");
|
|
this.contentEl.addClass("sr-modal-content");
|
|
this.deckView = new DeckListView(
|
|
this.plugin,
|
|
this.settings,
|
|
this.reviewSequencer,
|
|
this.contentEl,
|
|
this._startReviewOfDeck.bind(this)
|
|
);
|
|
this.flashcardView = new FlashcardReviewView(
|
|
this.app,
|
|
this.plugin,
|
|
this.settings,
|
|
this.reviewSequencer,
|
|
this.reviewMode,
|
|
this.contentEl,
|
|
this.modalEl,
|
|
this._showDecksList.bind(this),
|
|
this._doEditQuestionText.bind(this)
|
|
);
|
|
}
|
|
onOpen() {
|
|
this._showDecksList();
|
|
}
|
|
onClose() {
|
|
this.mode = 3 /* Closed */;
|
|
this.deckView.close();
|
|
this.flashcardView.close();
|
|
}
|
|
_showDecksList() {
|
|
this._hideFlashcard();
|
|
this.deckView.show();
|
|
}
|
|
_hideDecksList() {
|
|
this.deckView.hide();
|
|
}
|
|
_showFlashcard(deck) {
|
|
this._hideDecksList();
|
|
this.flashcardView.show(deck);
|
|
}
|
|
_hideFlashcard() {
|
|
this.flashcardView.hide();
|
|
}
|
|
_startReviewOfDeck(deck) {
|
|
this.reviewSequencer.setCurrentDeck(deck.getTopicPath());
|
|
if (this.reviewSequencer.hasCurrentCard) {
|
|
this._showFlashcard(deck);
|
|
} else {
|
|
this._showDecksList();
|
|
}
|
|
}
|
|
async _doEditQuestionText() {
|
|
const currentQ = this.reviewSequencer.currentQuestion;
|
|
const textPrompt = currentQ.questionText.actualQuestion;
|
|
const editModal = FlashcardEditModal.Prompt(
|
|
this.app,
|
|
textPrompt,
|
|
currentQ.questionText.textDirection
|
|
);
|
|
editModal.then(async (modifiedCardText) => {
|
|
this.reviewSequencer.updateCurrentQuestionText(modifiedCardText);
|
|
}).catch((reason) => console.log(reason));
|
|
}
|
|
};
|
|
|
|
// src/gui/review-queue-list-view.tsx
|
|
var import_obsidian8 = require("obsidian");
|
|
var REVIEW_QUEUE_VIEW_TYPE = "review-queue-list-view";
|
|
var ReviewQueueListView = class extends import_obsidian8.ItemView {
|
|
get noteReviewQueue() {
|
|
return this.nextNoteReviewHandler.noteReviewQueue;
|
|
}
|
|
constructor(leaf, nextNoteReviewHandler, settings) {
|
|
super(leaf);
|
|
this.nextNoteReviewHandler = nextNoteReviewHandler;
|
|
this.settings = settings;
|
|
if (this.settings.enableNoteReviewPaneOnStartup) {
|
|
this.registerEvent(this.app.workspace.on("file-open", () => this.redraw()));
|
|
this.registerEvent(this.app.vault.on("rename", () => this.redraw()));
|
|
}
|
|
}
|
|
getViewType() {
|
|
return REVIEW_QUEUE_VIEW_TYPE;
|
|
}
|
|
getDisplayText() {
|
|
return t("NOTES_REVIEW_QUEUE");
|
|
}
|
|
getIcon() {
|
|
return "SpacedRepIcon";
|
|
}
|
|
onHeaderMenu(menu) {
|
|
menu.addItem((item) => {
|
|
item.setTitle(t("CLOSE")).setIcon("cross").onClick(() => {
|
|
this.app.workspace.detachLeavesOfType(REVIEW_QUEUE_VIEW_TYPE);
|
|
});
|
|
});
|
|
}
|
|
redraw() {
|
|
if (!this.noteReviewQueue.reviewDecks) return;
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
const rootEl = createDiv("tree-item nav-folder mod-root");
|
|
const childrenEl = rootEl.createDiv("tree-item-children nav-folder-children");
|
|
for (const [deckKey, deck] of this.noteReviewQueue.reviewDecks) {
|
|
const deckCollapsed = !deck.activeFolders.has(deck.deckName);
|
|
const deckFolderEl = this.createRightPaneFolder(
|
|
childrenEl,
|
|
deckKey,
|
|
deckCollapsed,
|
|
false,
|
|
deck
|
|
).getElementsByClassName("tree-item-children nav-folder-children")[0];
|
|
if (deck.newNotes.length > 0) {
|
|
const newNotesFolderEl = this.createRightPaneFolder(
|
|
deckFolderEl,
|
|
t("NEW"),
|
|
!deck.activeFolders.has(t("NEW")),
|
|
deckCollapsed,
|
|
deck
|
|
);
|
|
for (const newFile of deck.newNotes) {
|
|
const fileIsOpen = activeFile && newFile.path === activeFile.path;
|
|
if (fileIsOpen) {
|
|
deck.activeFolders.add(deck.deckName);
|
|
deck.activeFolders.add(t("NEW"));
|
|
this.changeFolderFolding(newNotesFolderEl);
|
|
this.changeFolderFolding(deckFolderEl);
|
|
}
|
|
this.createRightPaneFile(
|
|
newNotesFolderEl,
|
|
newFile.tfile,
|
|
fileIsOpen,
|
|
!deck.activeFolders.has(t("NEW")),
|
|
deck
|
|
);
|
|
}
|
|
}
|
|
if (deck.scheduledNotes.length > 0) {
|
|
const now2 = Date.now();
|
|
let currUnix = -1;
|
|
let schedFolderEl = null, folderTitle = "";
|
|
const maxDaysToRender = this.settings.maxNDaysNotesReviewQueue;
|
|
for (const sNote of deck.scheduledNotes) {
|
|
if (sNote.dueUnix != currUnix) {
|
|
const nDays = Math.ceil((sNote.dueUnix - now2) / TICKS_PER_DAY);
|
|
if (nDays > maxDaysToRender) {
|
|
break;
|
|
}
|
|
if (nDays === -1) {
|
|
folderTitle = t("YESTERDAY");
|
|
} else if (nDays === 0) {
|
|
folderTitle = t("TODAY");
|
|
} else if (nDays === 1) {
|
|
folderTitle = t("TOMORROW");
|
|
} else {
|
|
folderTitle = new Date(sNote.dueUnix).toDateString();
|
|
}
|
|
schedFolderEl = this.createRightPaneFolder(
|
|
deckFolderEl,
|
|
folderTitle,
|
|
!deck.activeFolders.has(folderTitle),
|
|
deckCollapsed,
|
|
deck
|
|
);
|
|
currUnix = sNote.dueUnix;
|
|
}
|
|
const fileIsOpen = activeFile && sNote.note.path === activeFile.path;
|
|
if (fileIsOpen) {
|
|
deck.activeFolders.add(deck.deckName);
|
|
deck.activeFolders.add(folderTitle);
|
|
this.changeFolderFolding(schedFolderEl);
|
|
this.changeFolderFolding(deckFolderEl);
|
|
}
|
|
this.createRightPaneFile(
|
|
schedFolderEl,
|
|
sNote.note.tfile,
|
|
fileIsOpen,
|
|
!deck.activeFolders.has(folderTitle),
|
|
deck
|
|
);
|
|
}
|
|
}
|
|
}
|
|
const contentEl = this.containerEl.children[1];
|
|
contentEl.empty();
|
|
contentEl.appendChild(rootEl);
|
|
}
|
|
createRightPaneFolder(parentEl, folderTitle, collapsed, hidden, deck) {
|
|
const folderEl = parentEl.createDiv("tree-item nav-folder");
|
|
const folderTitleEl = folderEl.createDiv("tree-item-self nav-folder-title");
|
|
const childrenEl = folderEl.createDiv(
|
|
"tree-item-children nav-folder-children"
|
|
);
|
|
const collapseIconEl = folderTitleEl.createDiv(
|
|
"tree-item-icon collapse-icon nav-folder-collapse-indicator"
|
|
);
|
|
collapseIconEl.innerHTML = COLLAPSE_ICON;
|
|
this.changeFolderFolding(folderEl, collapsed);
|
|
folderTitleEl.createDiv("tree-item-inner nav-folder-title-content").setText(folderTitle);
|
|
if (hidden) {
|
|
folderEl.style.display = "none";
|
|
}
|
|
folderTitleEl.onClickEvent(() => {
|
|
this.changeFolderFolding(folderEl, !folderEl.hasClass("is-collapsed"));
|
|
childrenEl.style.display = !folderEl.hasClass("is-collapsed") ? "block" : "none";
|
|
if (!folderEl.hasClass("is-collapsed")) {
|
|
deck.activeFolders.delete(folderTitle);
|
|
} else {
|
|
deck.activeFolders.add(folderTitle);
|
|
}
|
|
});
|
|
return folderEl;
|
|
}
|
|
createRightPaneFile(folderEl, file, fileElActive, hidden, deck) {
|
|
const childrenEl = folderEl.getElementsByClassName(
|
|
"tree-item-children nav-folder-children"
|
|
)[0];
|
|
const navFileEl = childrenEl.createDiv("nav-file");
|
|
if (hidden) {
|
|
childrenEl.style.display = "none";
|
|
}
|
|
const navFileTitle = navFileEl.createDiv("tree-item-self nav-file-title");
|
|
if (fileElActive) {
|
|
navFileTitle.addClass("is-active");
|
|
}
|
|
navFileTitle.createDiv("tree-item-inner nav-file-title-content").setText(file.basename);
|
|
navFileTitle.addEventListener(
|
|
"click",
|
|
async (event) => {
|
|
event.preventDefault();
|
|
await this.nextNoteReviewHandler.openNote(deck.deckName, file);
|
|
return false;
|
|
},
|
|
false
|
|
);
|
|
navFileTitle.addEventListener(
|
|
"contextmenu",
|
|
(event) => {
|
|
event.preventDefault();
|
|
const fileMenu = new import_obsidian8.Menu();
|
|
this.app.workspace.trigger("file-menu", fileMenu, file, "my-context-menu", null);
|
|
fileMenu.showAtPosition({
|
|
x: event.pageX,
|
|
y: event.pageY
|
|
});
|
|
return false;
|
|
},
|
|
false
|
|
);
|
|
}
|
|
changeFolderFolding(folderEl, collapsed = false) {
|
|
if (collapsed) {
|
|
folderEl.addClass("is-collapsed");
|
|
const collapseIconEl = folderEl.find("div.nav-folder-collapse-indicator");
|
|
collapseIconEl.addClass("is-collapsed");
|
|
} else {
|
|
folderEl.removeClass("is-collapsed");
|
|
const collapseIconEl = folderEl.find("div.nav-folder-collapse-indicator");
|
|
collapseIconEl.removeClass("is-collapsed");
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/gui/settings.tsx
|
|
var import_obsidian10 = require("obsidian");
|
|
|
|
// node_modules/.pnpm/@kurkle+color@0.3.2/node_modules/@kurkle/color/dist/color.esm.js
|
|
function round(v2) {
|
|
return v2 + 0.5 | 0;
|
|
}
|
|
var lim = (v2, l2, h6) => Math.max(Math.min(v2, h6), l2);
|
|
function p2b(v2) {
|
|
return lim(round(v2 * 2.55), 0, 255);
|
|
}
|
|
function n2b(v2) {
|
|
return lim(round(v2 * 255), 0, 255);
|
|
}
|
|
function b2n(v2) {
|
|
return lim(round(v2 / 2.55) / 100, 0, 1);
|
|
}
|
|
function n2p(v2) {
|
|
return lim(round(v2 * 100), 0, 100);
|
|
}
|
|
var map$1 = { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 };
|
|
var hex = [..."0123456789ABCDEF"];
|
|
var h1 = (b2) => hex[b2 & 15];
|
|
var h2 = (b2) => hex[(b2 & 240) >> 4] + hex[b2 & 15];
|
|
var eq = (b2) => (b2 & 240) >> 4 === (b2 & 15);
|
|
var isShort = (v2) => eq(v2.r) && eq(v2.g) && eq(v2.b) && eq(v2.a);
|
|
function hexParse(str) {
|
|
var len = str.length;
|
|
var ret;
|
|
if (str[0] === "#") {
|
|
if (len === 4 || len === 5) {
|
|
ret = {
|
|
r: 255 & map$1[str[1]] * 17,
|
|
g: 255 & map$1[str[2]] * 17,
|
|
b: 255 & map$1[str[3]] * 17,
|
|
a: len === 5 ? map$1[str[4]] * 17 : 255
|
|
};
|
|
} else if (len === 7 || len === 9) {
|
|
ret = {
|
|
r: map$1[str[1]] << 4 | map$1[str[2]],
|
|
g: map$1[str[3]] << 4 | map$1[str[4]],
|
|
b: map$1[str[5]] << 4 | map$1[str[6]],
|
|
a: len === 9 ? map$1[str[7]] << 4 | map$1[str[8]] : 255
|
|
};
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
var alpha = (a2, f2) => a2 < 255 ? f2(a2) : "";
|
|
function hexString(v2) {
|
|
var f2 = isShort(v2) ? h1 : h2;
|
|
return v2 ? "#" + f2(v2.r) + f2(v2.g) + f2(v2.b) + alpha(v2.a, f2) : void 0;
|
|
}
|
|
var HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
|
|
function hsl2rgbn(h6, s2, l2) {
|
|
const a2 = s2 * Math.min(l2, 1 - l2);
|
|
const f2 = (n2, k = (n2 + h6 / 30) % 12) => l2 - a2 * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
return [f2(0), f2(8), f2(4)];
|
|
}
|
|
function hsv2rgbn(h6, s2, v2) {
|
|
const f2 = (n2, k = (n2 + h6 / 60) % 6) => v2 - v2 * s2 * Math.max(Math.min(k, 4 - k, 1), 0);
|
|
return [f2(5), f2(3), f2(1)];
|
|
}
|
|
function hwb2rgbn(h6, w2, b2) {
|
|
const rgb = hsl2rgbn(h6, 1, 0.5);
|
|
let i2;
|
|
if (w2 + b2 > 1) {
|
|
i2 = 1 / (w2 + b2);
|
|
w2 *= i2;
|
|
b2 *= i2;
|
|
}
|
|
for (i2 = 0; i2 < 3; i2++) {
|
|
rgb[i2] *= 1 - w2 - b2;
|
|
rgb[i2] += w2;
|
|
}
|
|
return rgb;
|
|
}
|
|
function hueValue(r2, g2, b2, d2, max) {
|
|
if (r2 === max) {
|
|
return (g2 - b2) / d2 + (g2 < b2 ? 6 : 0);
|
|
}
|
|
if (g2 === max) {
|
|
return (b2 - r2) / d2 + 2;
|
|
}
|
|
return (r2 - g2) / d2 + 4;
|
|
}
|
|
function rgb2hsl(v2) {
|
|
const range = 255;
|
|
const r2 = v2.r / range;
|
|
const g2 = v2.g / range;
|
|
const b2 = v2.b / range;
|
|
const max = Math.max(r2, g2, b2);
|
|
const min = Math.min(r2, g2, b2);
|
|
const l2 = (max + min) / 2;
|
|
let h6, s2, d2;
|
|
if (max !== min) {
|
|
d2 = max - min;
|
|
s2 = l2 > 0.5 ? d2 / (2 - max - min) : d2 / (max + min);
|
|
h6 = hueValue(r2, g2, b2, d2, max);
|
|
h6 = h6 * 60 + 0.5;
|
|
}
|
|
return [h6 | 0, s2 || 0, l2];
|
|
}
|
|
function calln(f2, a2, b2, c2) {
|
|
return (Array.isArray(a2) ? f2(a2[0], a2[1], a2[2]) : f2(a2, b2, c2)).map(n2b);
|
|
}
|
|
function hsl2rgb(h6, s2, l2) {
|
|
return calln(hsl2rgbn, h6, s2, l2);
|
|
}
|
|
function hwb2rgb(h6, w2, b2) {
|
|
return calln(hwb2rgbn, h6, w2, b2);
|
|
}
|
|
function hsv2rgb(h6, s2, v2) {
|
|
return calln(hsv2rgbn, h6, s2, v2);
|
|
}
|
|
function hue(h6) {
|
|
return (h6 % 360 + 360) % 360;
|
|
}
|
|
function hueParse(str) {
|
|
const m2 = HUE_RE.exec(str);
|
|
let a2 = 255;
|
|
let v2;
|
|
if (!m2) {
|
|
return;
|
|
}
|
|
if (m2[5] !== v2) {
|
|
a2 = m2[6] ? p2b(+m2[5]) : n2b(+m2[5]);
|
|
}
|
|
const h6 = hue(+m2[2]);
|
|
const p1 = +m2[3] / 100;
|
|
const p2 = +m2[4] / 100;
|
|
if (m2[1] === "hwb") {
|
|
v2 = hwb2rgb(h6, p1, p2);
|
|
} else if (m2[1] === "hsv") {
|
|
v2 = hsv2rgb(h6, p1, p2);
|
|
} else {
|
|
v2 = hsl2rgb(h6, p1, p2);
|
|
}
|
|
return {
|
|
r: v2[0],
|
|
g: v2[1],
|
|
b: v2[2],
|
|
a: a2
|
|
};
|
|
}
|
|
function rotate(v2, deg) {
|
|
var h6 = rgb2hsl(v2);
|
|
h6[0] = hue(h6[0] + deg);
|
|
h6 = hsl2rgb(h6);
|
|
v2.r = h6[0];
|
|
v2.g = h6[1];
|
|
v2.b = h6[2];
|
|
}
|
|
function hslString(v2) {
|
|
if (!v2) {
|
|
return;
|
|
}
|
|
const a2 = rgb2hsl(v2);
|
|
const h6 = a2[0];
|
|
const s2 = n2p(a2[1]);
|
|
const l2 = n2p(a2[2]);
|
|
return v2.a < 255 ? `hsla(${h6}, ${s2}%, ${l2}%, ${b2n(v2.a)})` : `hsl(${h6}, ${s2}%, ${l2}%)`;
|
|
}
|
|
var map = {
|
|
x: "dark",
|
|
Z: "light",
|
|
Y: "re",
|
|
X: "blu",
|
|
W: "gr",
|
|
V: "medium",
|
|
U: "slate",
|
|
A: "ee",
|
|
T: "ol",
|
|
S: "or",
|
|
B: "ra",
|
|
C: "lateg",
|
|
D: "ights",
|
|
R: "in",
|
|
Q: "turquois",
|
|
E: "hi",
|
|
P: "ro",
|
|
O: "al",
|
|
N: "le",
|
|
M: "de",
|
|
L: "yello",
|
|
F: "en",
|
|
K: "ch",
|
|
G: "arks",
|
|
H: "ea",
|
|
I: "ightg",
|
|
J: "wh"
|
|
};
|
|
var names$1 = {
|
|
OiceXe: "f0f8ff",
|
|
antiquewEte: "faebd7",
|
|
aqua: "ffff",
|
|
aquamarRe: "7fffd4",
|
|
azuY: "f0ffff",
|
|
beige: "f5f5dc",
|
|
bisque: "ffe4c4",
|
|
black: "0",
|
|
blanKedOmond: "ffebcd",
|
|
Xe: "ff",
|
|
XeviTet: "8a2be2",
|
|
bPwn: "a52a2a",
|
|
burlywood: "deb887",
|
|
caMtXe: "5f9ea0",
|
|
KartYuse: "7fff00",
|
|
KocTate: "d2691e",
|
|
cSO: "ff7f50",
|
|
cSnflowerXe: "6495ed",
|
|
cSnsilk: "fff8dc",
|
|
crimson: "dc143c",
|
|
cyan: "ffff",
|
|
xXe: "8b",
|
|
xcyan: "8b8b",
|
|
xgTMnPd: "b8860b",
|
|
xWay: "a9a9a9",
|
|
xgYF: "6400",
|
|
xgYy: "a9a9a9",
|
|
xkhaki: "bdb76b",
|
|
xmagFta: "8b008b",
|
|
xTivegYF: "556b2f",
|
|
xSange: "ff8c00",
|
|
xScEd: "9932cc",
|
|
xYd: "8b0000",
|
|
xsOmon: "e9967a",
|
|
xsHgYF: "8fbc8f",
|
|
xUXe: "483d8b",
|
|
xUWay: "2f4f4f",
|
|
xUgYy: "2f4f4f",
|
|
xQe: "ced1",
|
|
xviTet: "9400d3",
|
|
dAppRk: "ff1493",
|
|
dApskyXe: "bfff",
|
|
dimWay: "696969",
|
|
dimgYy: "696969",
|
|
dodgerXe: "1e90ff",
|
|
fiYbrick: "b22222",
|
|
flSOwEte: "fffaf0",
|
|
foYstWAn: "228b22",
|
|
fuKsia: "ff00ff",
|
|
gaRsbSo: "dcdcdc",
|
|
ghostwEte: "f8f8ff",
|
|
gTd: "ffd700",
|
|
gTMnPd: "daa520",
|
|
Way: "808080",
|
|
gYF: "8000",
|
|
gYFLw: "adff2f",
|
|
gYy: "808080",
|
|
honeyMw: "f0fff0",
|
|
hotpRk: "ff69b4",
|
|
RdianYd: "cd5c5c",
|
|
Rdigo: "4b0082",
|
|
ivSy: "fffff0",
|
|
khaki: "f0e68c",
|
|
lavFMr: "e6e6fa",
|
|
lavFMrXsh: "fff0f5",
|
|
lawngYF: "7cfc00",
|
|
NmoncEffon: "fffacd",
|
|
ZXe: "add8e6",
|
|
ZcSO: "f08080",
|
|
Zcyan: "e0ffff",
|
|
ZgTMnPdLw: "fafad2",
|
|
ZWay: "d3d3d3",
|
|
ZgYF: "90ee90",
|
|
ZgYy: "d3d3d3",
|
|
ZpRk: "ffb6c1",
|
|
ZsOmon: "ffa07a",
|
|
ZsHgYF: "20b2aa",
|
|
ZskyXe: "87cefa",
|
|
ZUWay: "778899",
|
|
ZUgYy: "778899",
|
|
ZstAlXe: "b0c4de",
|
|
ZLw: "ffffe0",
|
|
lime: "ff00",
|
|
limegYF: "32cd32",
|
|
lRF: "faf0e6",
|
|
magFta: "ff00ff",
|
|
maPon: "800000",
|
|
VaquamarRe: "66cdaa",
|
|
VXe: "cd",
|
|
VScEd: "ba55d3",
|
|
VpurpN: "9370db",
|
|
VsHgYF: "3cb371",
|
|
VUXe: "7b68ee",
|
|
VsprRggYF: "fa9a",
|
|
VQe: "48d1cc",
|
|
VviTetYd: "c71585",
|
|
midnightXe: "191970",
|
|
mRtcYam: "f5fffa",
|
|
mistyPse: "ffe4e1",
|
|
moccasR: "ffe4b5",
|
|
navajowEte: "ffdead",
|
|
navy: "80",
|
|
Tdlace: "fdf5e6",
|
|
Tive: "808000",
|
|
TivedBb: "6b8e23",
|
|
Sange: "ffa500",
|
|
SangeYd: "ff4500",
|
|
ScEd: "da70d6",
|
|
pOegTMnPd: "eee8aa",
|
|
pOegYF: "98fb98",
|
|
pOeQe: "afeeee",
|
|
pOeviTetYd: "db7093",
|
|
papayawEp: "ffefd5",
|
|
pHKpuff: "ffdab9",
|
|
peru: "cd853f",
|
|
pRk: "ffc0cb",
|
|
plum: "dda0dd",
|
|
powMrXe: "b0e0e6",
|
|
purpN: "800080",
|
|
YbeccapurpN: "663399",
|
|
Yd: "ff0000",
|
|
Psybrown: "bc8f8f",
|
|
PyOXe: "4169e1",
|
|
saddNbPwn: "8b4513",
|
|
sOmon: "fa8072",
|
|
sandybPwn: "f4a460",
|
|
sHgYF: "2e8b57",
|
|
sHshell: "fff5ee",
|
|
siFna: "a0522d",
|
|
silver: "c0c0c0",
|
|
skyXe: "87ceeb",
|
|
UXe: "6a5acd",
|
|
UWay: "708090",
|
|
UgYy: "708090",
|
|
snow: "fffafa",
|
|
sprRggYF: "ff7f",
|
|
stAlXe: "4682b4",
|
|
tan: "d2b48c",
|
|
teO: "8080",
|
|
tEstN: "d8bfd8",
|
|
tomato: "ff6347",
|
|
Qe: "40e0d0",
|
|
viTet: "ee82ee",
|
|
JHt: "f5deb3",
|
|
wEte: "ffffff",
|
|
wEtesmoke: "f5f5f5",
|
|
Lw: "ffff00",
|
|
LwgYF: "9acd32"
|
|
};
|
|
function unpack() {
|
|
const unpacked = {};
|
|
const keys = Object.keys(names$1);
|
|
const tkeys = Object.keys(map);
|
|
let i2, j2, k, ok, nk;
|
|
for (i2 = 0; i2 < keys.length; i2++) {
|
|
ok = nk = keys[i2];
|
|
for (j2 = 0; j2 < tkeys.length; j2++) {
|
|
k = tkeys[j2];
|
|
nk = nk.replace(k, map[k]);
|
|
}
|
|
k = parseInt(names$1[ok], 16);
|
|
unpacked[nk] = [k >> 16 & 255, k >> 8 & 255, k & 255];
|
|
}
|
|
return unpacked;
|
|
}
|
|
var names;
|
|
function nameParse(str) {
|
|
if (!names) {
|
|
names = unpack();
|
|
names.transparent = [0, 0, 0, 0];
|
|
}
|
|
const a2 = names[str.toLowerCase()];
|
|
return a2 && {
|
|
r: a2[0],
|
|
g: a2[1],
|
|
b: a2[2],
|
|
a: a2.length === 4 ? a2[3] : 255
|
|
};
|
|
}
|
|
var RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
|
|
function rgbParse(str) {
|
|
const m2 = RGB_RE.exec(str);
|
|
let a2 = 255;
|
|
let r2, g2, b2;
|
|
if (!m2) {
|
|
return;
|
|
}
|
|
if (m2[7] !== r2) {
|
|
const v2 = +m2[7];
|
|
a2 = m2[8] ? p2b(v2) : lim(v2 * 255, 0, 255);
|
|
}
|
|
r2 = +m2[1];
|
|
g2 = +m2[3];
|
|
b2 = +m2[5];
|
|
r2 = 255 & (m2[2] ? p2b(r2) : lim(r2, 0, 255));
|
|
g2 = 255 & (m2[4] ? p2b(g2) : lim(g2, 0, 255));
|
|
b2 = 255 & (m2[6] ? p2b(b2) : lim(b2, 0, 255));
|
|
return {
|
|
r: r2,
|
|
g: g2,
|
|
b: b2,
|
|
a: a2
|
|
};
|
|
}
|
|
function rgbString(v2) {
|
|
return v2 && (v2.a < 255 ? `rgba(${v2.r}, ${v2.g}, ${v2.b}, ${b2n(v2.a)})` : `rgb(${v2.r}, ${v2.g}, ${v2.b})`);
|
|
}
|
|
var to = (v2) => v2 <= 31308e-7 ? v2 * 12.92 : Math.pow(v2, 1 / 2.4) * 1.055 - 0.055;
|
|
var from = (v2) => v2 <= 0.04045 ? v2 / 12.92 : Math.pow((v2 + 0.055) / 1.055, 2.4);
|
|
function interpolate2(rgb1, rgb2, t3) {
|
|
const r2 = from(b2n(rgb1.r));
|
|
const g2 = from(b2n(rgb1.g));
|
|
const b2 = from(b2n(rgb1.b));
|
|
return {
|
|
r: n2b(to(r2 + t3 * (from(b2n(rgb2.r)) - r2))),
|
|
g: n2b(to(g2 + t3 * (from(b2n(rgb2.g)) - g2))),
|
|
b: n2b(to(b2 + t3 * (from(b2n(rgb2.b)) - b2))),
|
|
a: rgb1.a + t3 * (rgb2.a - rgb1.a)
|
|
};
|
|
}
|
|
function modHSL(v2, i2, ratio) {
|
|
if (v2) {
|
|
let tmp = rgb2hsl(v2);
|
|
tmp[i2] = Math.max(0, Math.min(tmp[i2] + tmp[i2] * ratio, i2 === 0 ? 360 : 1));
|
|
tmp = hsl2rgb(tmp);
|
|
v2.r = tmp[0];
|
|
v2.g = tmp[1];
|
|
v2.b = tmp[2];
|
|
}
|
|
}
|
|
function clone(v2, proto) {
|
|
return v2 ? Object.assign(proto || {}, v2) : v2;
|
|
}
|
|
function fromObject(input) {
|
|
var v2 = { r: 0, g: 0, b: 0, a: 255 };
|
|
if (Array.isArray(input)) {
|
|
if (input.length >= 3) {
|
|
v2 = { r: input[0], g: input[1], b: input[2], a: 255 };
|
|
if (input.length > 3) {
|
|
v2.a = n2b(input[3]);
|
|
}
|
|
}
|
|
} else {
|
|
v2 = clone(input, { r: 0, g: 0, b: 0, a: 1 });
|
|
v2.a = n2b(v2.a);
|
|
}
|
|
return v2;
|
|
}
|
|
function functionParse(str) {
|
|
if (str.charAt(0) === "r") {
|
|
return rgbParse(str);
|
|
}
|
|
return hueParse(str);
|
|
}
|
|
var Color = class _Color {
|
|
constructor(input) {
|
|
if (input instanceof _Color) {
|
|
return input;
|
|
}
|
|
const type = typeof input;
|
|
let v2;
|
|
if (type === "object") {
|
|
v2 = fromObject(input);
|
|
} else if (type === "string") {
|
|
v2 = hexParse(input) || nameParse(input) || functionParse(input);
|
|
}
|
|
this._rgb = v2;
|
|
this._valid = !!v2;
|
|
}
|
|
get valid() {
|
|
return this._valid;
|
|
}
|
|
get rgb() {
|
|
var v2 = clone(this._rgb);
|
|
if (v2) {
|
|
v2.a = b2n(v2.a);
|
|
}
|
|
return v2;
|
|
}
|
|
set rgb(obj) {
|
|
this._rgb = fromObject(obj);
|
|
}
|
|
rgbString() {
|
|
return this._valid ? rgbString(this._rgb) : void 0;
|
|
}
|
|
hexString() {
|
|
return this._valid ? hexString(this._rgb) : void 0;
|
|
}
|
|
hslString() {
|
|
return this._valid ? hslString(this._rgb) : void 0;
|
|
}
|
|
mix(color2, weight) {
|
|
if (color2) {
|
|
const c1 = this.rgb;
|
|
const c2 = color2.rgb;
|
|
let w2;
|
|
const p2 = weight === w2 ? 0.5 : weight;
|
|
const w3 = 2 * p2 - 1;
|
|
const a2 = c1.a - c2.a;
|
|
const w1 = ((w3 * a2 === -1 ? w3 : (w3 + a2) / (1 + w3 * a2)) + 1) / 2;
|
|
w2 = 1 - w1;
|
|
c1.r = 255 & w1 * c1.r + w2 * c2.r + 0.5;
|
|
c1.g = 255 & w1 * c1.g + w2 * c2.g + 0.5;
|
|
c1.b = 255 & w1 * c1.b + w2 * c2.b + 0.5;
|
|
c1.a = p2 * c1.a + (1 - p2) * c2.a;
|
|
this.rgb = c1;
|
|
}
|
|
return this;
|
|
}
|
|
interpolate(color2, t3) {
|
|
if (color2) {
|
|
this._rgb = interpolate2(this._rgb, color2._rgb, t3);
|
|
}
|
|
return this;
|
|
}
|
|
clone() {
|
|
return new _Color(this.rgb);
|
|
}
|
|
alpha(a2) {
|
|
this._rgb.a = n2b(a2);
|
|
return this;
|
|
}
|
|
clearer(ratio) {
|
|
const rgb = this._rgb;
|
|
rgb.a *= 1 - ratio;
|
|
return this;
|
|
}
|
|
greyscale() {
|
|
const rgb = this._rgb;
|
|
const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
|
|
rgb.r = rgb.g = rgb.b = val;
|
|
return this;
|
|
}
|
|
opaquer(ratio) {
|
|
const rgb = this._rgb;
|
|
rgb.a *= 1 + ratio;
|
|
return this;
|
|
}
|
|
negate() {
|
|
const v2 = this._rgb;
|
|
v2.r = 255 - v2.r;
|
|
v2.g = 255 - v2.g;
|
|
v2.b = 255 - v2.b;
|
|
return this;
|
|
}
|
|
lighten(ratio) {
|
|
modHSL(this._rgb, 2, ratio);
|
|
return this;
|
|
}
|
|
darken(ratio) {
|
|
modHSL(this._rgb, 2, -ratio);
|
|
return this;
|
|
}
|
|
saturate(ratio) {
|
|
modHSL(this._rgb, 1, ratio);
|
|
return this;
|
|
}
|
|
desaturate(ratio) {
|
|
modHSL(this._rgb, 1, -ratio);
|
|
return this;
|
|
}
|
|
rotate(deg) {
|
|
rotate(this._rgb, deg);
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// node_modules/.pnpm/chart.js@4.4.4/node_modules/chart.js/dist/chunks/helpers.segment.js
|
|
function noop() {
|
|
}
|
|
var uid = /* @__PURE__ */ (() => {
|
|
let id = 0;
|
|
return () => id++;
|
|
})();
|
|
function isNullOrUndef(value) {
|
|
return value === null || typeof value === "undefined";
|
|
}
|
|
function isArray(value) {
|
|
if (Array.isArray && Array.isArray(value)) {
|
|
return true;
|
|
}
|
|
const type = Object.prototype.toString.call(value);
|
|
if (type.slice(0, 7) === "[object" && type.slice(-6) === "Array]") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function isObject(value) {
|
|
return value !== null && Object.prototype.toString.call(value) === "[object Object]";
|
|
}
|
|
function isNumberFinite(value) {
|
|
return (typeof value === "number" || value instanceof Number) && isFinite(+value);
|
|
}
|
|
function finiteOrDefault(value, defaultValue) {
|
|
return isNumberFinite(value) ? value : defaultValue;
|
|
}
|
|
function valueOrDefault(value, defaultValue) {
|
|
return typeof value === "undefined" ? defaultValue : value;
|
|
}
|
|
var toPercentage = (value, dimension) => typeof value === "string" && value.endsWith("%") ? parseFloat(value) / 100 : +value / dimension;
|
|
var toDimension = (value, dimension) => typeof value === "string" && value.endsWith("%") ? parseFloat(value) / 100 * dimension : +value;
|
|
function callback(fn2, args, thisArg) {
|
|
if (fn2 && typeof fn2.call === "function") {
|
|
return fn2.apply(thisArg, args);
|
|
}
|
|
}
|
|
function each(loopable, fn2, thisArg, reverse) {
|
|
let i2, len, keys;
|
|
if (isArray(loopable)) {
|
|
len = loopable.length;
|
|
if (reverse) {
|
|
for (i2 = len - 1; i2 >= 0; i2--) {
|
|
fn2.call(thisArg, loopable[i2], i2);
|
|
}
|
|
} else {
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
fn2.call(thisArg, loopable[i2], i2);
|
|
}
|
|
}
|
|
} else if (isObject(loopable)) {
|
|
keys = Object.keys(loopable);
|
|
len = keys.length;
|
|
for (i2 = 0; i2 < len; i2++) {
|
|
fn2.call(thisArg, loopable[keys[i2]], keys[i2]);
|
|
}
|
|
}
|
|
}
|
|
function _elementsEqual(a0, a1) {
|
|
let i2, ilen, v0, v1;
|
|
if (!a0 || !a1 || a0.length !== a1.length) {
|
|
return false;
|
|
}
|
|
for (i2 = 0, ilen = a0.length; i2 < ilen; ++i2) {
|
|
v0 = a0[i2];
|
|
v1 = a1[i2];
|
|
if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function clone2(source) {
|
|
if (isArray(source)) {
|
|
return source.map(clone2);
|
|
}
|
|
if (isObject(source)) {
|
|
const target = /* @__PURE__ */ Object.create(null);
|
|
const keys = Object.keys(source);
|
|
const klen = keys.length;
|
|
let k = 0;
|
|
for (; k < klen; ++k) {
|
|
target[keys[k]] = clone2(source[keys[k]]);
|
|
}
|
|
return target;
|
|
}
|
|
return source;
|
|
}
|
|
function isValidKey(key) {
|
|
return [
|
|
"__proto__",
|
|
"prototype",
|
|
"constructor"
|
|
].indexOf(key) === -1;
|
|
}
|
|
function _merger(key, target, source, options) {
|
|
if (!isValidKey(key)) {
|
|
return;
|
|
}
|
|
const tval = target[key];
|
|
const sval = source[key];
|
|
if (isObject(tval) && isObject(sval)) {
|
|
merge(tval, sval, options);
|
|
} else {
|
|
target[key] = clone2(sval);
|
|
}
|
|
}
|
|
function merge(target, source, options) {
|
|
const sources = isArray(source) ? source : [
|
|
source
|
|
];
|
|
const ilen = sources.length;
|
|
if (!isObject(target)) {
|
|
return target;
|
|
}
|
|
options = options || {};
|
|
const merger = options.merger || _merger;
|
|
let current;
|
|
for (let i2 = 0; i2 < ilen; ++i2) {
|
|
current = sources[i2];
|
|
if (!isObject(current)) {
|
|
continue;
|
|
}
|
|
const keys = Object.keys(current);
|
|
for (let k = 0, klen = keys.length; k < klen; ++k) {
|
|
merger(keys[k], target, current, options);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function mergeIf(target, source) {
|
|
return merge(target, source, {
|
|
merger: _mergerIf
|
|
});
|
|
}
|
|
function _mergerIf(key, target, source) {
|
|
if (!isValidKey(key)) {
|
|
return;
|
|
}
|
|
const tval = target[key];
|
|
const sval = source[key];
|
|
if (isObject(tval) && isObject(sval)) {
|
|
mergeIf(tval, sval);
|
|
} else if (!Object.prototype.hasOwnProperty.call(target, key)) {
|
|
target[key] = clone2(sval);
|
|
}
|
|
}
|
|
var keyResolvers = {
|
|
// Chart.helpers.core resolveObjectKey should resolve empty key to root object
|
|
"": (v2) => v2,
|
|
// default resolvers
|
|
x: (o2) => o2.x,
|
|
y: (o2) => o2.y
|
|
};
|
|
function _splitKey(key) {
|
|
const parts = key.split(".");
|
|
const keys = [];
|
|
let tmp = "";
|
|
for (const part of parts) {
|
|
tmp += part;
|
|
if (tmp.endsWith("\\")) {
|
|
tmp = tmp.slice(0, -1) + ".";
|
|
} else {
|
|
keys.push(tmp);
|
|
tmp = "";
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
function _getKeyResolver(key) {
|
|
const keys = _splitKey(key);
|
|
return (obj) => {
|
|
for (const k of keys) {
|
|
if (k === "") {
|
|
break;
|
|
}
|
|
obj = obj && obj[k];
|
|
}
|
|
return obj;
|
|
};
|
|
}
|
|
function resolveObjectKey(obj, key) {
|
|
const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
|
|
return resolver(obj);
|
|
}
|
|
function _capitalize(str) {
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
}
|
|
var defined = (value) => typeof value !== "undefined";
|
|
var isFunction = (value) => typeof value === "function";
|
|
var setsEqual = (a2, b2) => {
|
|
if (a2.size !== b2.size) {
|
|
return false;
|
|
}
|
|
for (const item of a2) {
|
|
if (!b2.has(item)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
function _isClickEvent(e2) {
|
|
return e2.type === "mouseup" || e2.type === "click" || e2.type === "contextmenu";
|
|
}
|
|
var PI = Math.PI;
|
|
var TAU = 2 * PI;
|
|
var PITAU = TAU + PI;
|
|
var INFINITY = Number.POSITIVE_INFINITY;
|
|
var RAD_PER_DEG = PI / 180;
|
|
var HALF_PI = PI / 2;
|
|
var QUARTER_PI = PI / 4;
|
|
var TWO_THIRDS_PI = PI * 2 / 3;
|
|
var log10 = Math.log10;
|
|
var sign = Math.sign;
|
|
function almostEquals(x2, y2, epsilon) {
|
|
return Math.abs(x2 - y2) < epsilon;
|
|
}
|
|
function niceNum(range) {
|
|
const roundedRange = Math.round(range);
|
|
range = almostEquals(range, roundedRange, range / 1e3) ? roundedRange : range;
|
|
const niceRange = Math.pow(10, Math.floor(log10(range)));
|
|
const fraction = range / niceRange;
|
|
const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
|
|
return niceFraction * niceRange;
|
|
}
|
|
function _factorize(value) {
|
|
const result = [];
|
|
const sqrt = Math.sqrt(value);
|
|
let i2;
|
|
for (i2 = 1; i2 < sqrt; i2++) {
|
|
if (value % i2 === 0) {
|
|
result.push(i2);
|
|
result.push(value / i2);
|
|
}
|
|
}
|
|
if (sqrt === (sqrt | 0)) {
|
|
result.push(sqrt);
|
|
}
|
|
result.sort((a2, b2) => a2 - b2).pop();
|
|
return result;
|
|
}
|
|
function isNumber(n2) {
|
|
return !isNaN(parseFloat(n2)) && isFinite(n2);
|
|
}
|
|
function almostWhole(x2, epsilon) {
|
|
const rounded = Math.round(x2);
|
|
return rounded - epsilon <= x2 && rounded + epsilon >= x2;
|
|
}
|
|
function _setMinAndMaxByKey(array, target, property) {
|
|
let i2, ilen, value;
|
|
for (i2 = 0, ilen = array.length; i2 < ilen; i2++) {
|
|
value = array[i2][property];
|
|
if (!isNaN(value)) {
|
|
target.min = Math.min(target.min, value);
|
|
target.max = Math.max(target.max, value);
|
|
}
|
|
}
|
|
}
|
|
function toRadians(degrees) {
|
|
return degrees * (PI / 180);
|
|
}
|
|
function toDegrees(radians) {
|
|
return radians * (180 / PI);
|
|
}
|
|
function _decimalPlaces(x2) {
|
|
if (!isNumberFinite(x2)) {
|
|
return;
|
|
}
|
|
let e2 = 1;
|
|
let p2 = 0;
|
|
while (Math.round(x2 * e2) / e2 !== x2) {
|
|
e2 *= 10;
|
|
p2++;
|
|
}
|
|
return p2;
|
|
}
|
|
function getAngleFromPoint(centrePoint, anglePoint) {
|
|
const distanceFromXCenter = anglePoint.x - centrePoint.x;
|
|
const distanceFromYCenter = anglePoint.y - centrePoint.y;
|
|
const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
|
|
let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
|
|
if (angle < -0.5 * PI) {
|
|
angle += TAU;
|
|
}
|
|
return {
|
|
angle,
|
|
distance: radialDistanceFromCenter
|
|
};
|
|
}
|
|
function distanceBetweenPoints(pt1, pt2) {
|
|
return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
|
|
}
|
|
function _normalizeAngle(a2) {
|
|
return (a2 % TAU + TAU) % TAU;
|
|
}
|
|
function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
|
|
const a2 = _normalizeAngle(angle);
|
|
const s2 = _normalizeAngle(start);
|
|
const e2 = _normalizeAngle(end);
|
|
const angleToStart = _normalizeAngle(s2 - a2);
|
|
const angleToEnd = _normalizeAngle(e2 - a2);
|
|
const startToAngle = _normalizeAngle(a2 - s2);
|
|
const endToAngle = _normalizeAngle(a2 - e2);
|
|
return a2 === s2 || a2 === e2 || sameAngleIsFullCircle && s2 === e2 || angleToStart > angleToEnd && startToAngle < endToAngle;
|
|
}
|
|
function _limitValue(value, min, max) {
|
|
return Math.max(min, Math.min(max, value));
|
|
}
|
|
function _int16Range(value) {
|
|
return _limitValue(value, -32768, 32767);
|
|
}
|
|
function _isBetween(value, start, end, epsilon = 1e-6) {
|
|
return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
|
|
}
|
|
function _lookup(table, value, cmp) {
|
|
cmp = cmp || ((index) => table[index] < value);
|
|
let hi = table.length - 1;
|
|
let lo = 0;
|
|
let mid;
|
|
while (hi - lo > 1) {
|
|
mid = lo + hi >> 1;
|
|
if (cmp(mid)) {
|
|
lo = mid;
|
|
} else {
|
|
hi = mid;
|
|
}
|
|
}
|
|
return {
|
|
lo,
|
|
hi
|
|
};
|
|
}
|
|
var _lookupByKey = (table, key, value, last) => _lookup(table, value, last ? (index) => {
|
|
const ti = table[index][key];
|
|
return ti < value || ti === value && table[index + 1][key] === value;
|
|
} : (index) => table[index][key] < value);
|
|
var _rlookupByKey = (table, key, value) => _lookup(table, value, (index) => table[index][key] >= value);
|
|
function _filterBetween(values, min, max) {
|
|
let start = 0;
|
|
let end = values.length;
|
|
while (start < end && values[start] < min) {
|
|
start++;
|
|
}
|
|
while (end > start && values[end - 1] > max) {
|
|
end--;
|
|
}
|
|
return start > 0 || end < values.length ? values.slice(start, end) : values;
|
|
}
|
|
var arrayEvents = [
|
|
"push",
|
|
"pop",
|
|
"shift",
|
|
"splice",
|
|
"unshift"
|
|
];
|
|
function listenArrayEvents(array, listener) {
|
|
if (array._chartjs) {
|
|
array._chartjs.listeners.push(listener);
|
|
return;
|
|
}
|
|
Object.defineProperty(array, "_chartjs", {
|
|
configurable: true,
|
|
enumerable: false,
|
|
value: {
|
|
listeners: [
|
|
listener
|
|
]
|
|
}
|
|
});
|
|
arrayEvents.forEach((key) => {
|
|
const method = "_onData" + _capitalize(key);
|
|
const base = array[key];
|
|
Object.defineProperty(array, key, {
|
|
configurable: true,
|
|
enumerable: false,
|
|
value(...args) {
|
|
const res = base.apply(this, args);
|
|
array._chartjs.listeners.forEach((object) => {
|
|
if (typeof object[method] === "function") {
|
|
object[method](...args);
|
|
}
|
|
});
|
|
return res;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function unlistenArrayEvents(array, listener) {
|
|
const stub = array._chartjs;
|
|
if (!stub) {
|
|
return;
|
|
}
|
|
const listeners = stub.listeners;
|
|
const index = listeners.indexOf(listener);
|
|
if (index !== -1) {
|
|
listeners.splice(index, 1);
|
|
}
|
|
if (listeners.length > 0) {
|
|
return;
|
|
}
|
|
arrayEvents.forEach((key) => {
|
|
delete array[key];
|
|
});
|
|
delete array._chartjs;
|
|
}
|
|
function _arrayUnique(items) {
|
|
const set2 = new Set(items);
|
|
if (set2.size === items.length) {
|
|
return items;
|
|
}
|
|
return Array.from(set2);
|
|
}
|
|
var requestAnimFrame = function() {
|
|
if (typeof window === "undefined") {
|
|
return function(callback2) {
|
|
return callback2();
|
|
};
|
|
}
|
|
return window.requestAnimationFrame;
|
|
}();
|
|
function throttled(fn2, thisArg) {
|
|
let argsToUse = [];
|
|
let ticking = false;
|
|
return function(...args) {
|
|
argsToUse = args;
|
|
if (!ticking) {
|
|
ticking = true;
|
|
requestAnimFrame.call(window, () => {
|
|
ticking = false;
|
|
fn2.apply(thisArg, argsToUse);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
function debounce(fn2, delay) {
|
|
let timeout;
|
|
return function(...args) {
|
|
if (delay) {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(fn2, delay, args);
|
|
} else {
|
|
fn2.apply(this, args);
|
|
}
|
|
return delay;
|
|
};
|
|
}
|
|
var _toLeftRightCenter = (align) => align === "start" ? "left" : align === "end" ? "right" : "center";
|
|
var _alignStartEnd = (align, start, end) => align === "start" ? start : align === "end" ? end : (start + end) / 2;
|
|
var _textX = (align, left, right, rtl) => {
|
|
const check = rtl ? "left" : "right";
|
|
return align === check ? right : align === "center" ? (left + right) / 2 : left;
|
|
};
|
|
var atEdge = (t3) => t3 === 0 || t3 === 1;
|
|
var elasticIn = (t3, s2, p2) => -(Math.pow(2, 10 * (t3 -= 1)) * Math.sin((t3 - s2) * TAU / p2));
|
|
var elasticOut = (t3, s2, p2) => Math.pow(2, -10 * t3) * Math.sin((t3 - s2) * TAU / p2) + 1;
|
|
var effects = {
|
|
linear: (t3) => t3,
|
|
easeInQuad: (t3) => t3 * t3,
|
|
easeOutQuad: (t3) => -t3 * (t3 - 2),
|
|
easeInOutQuad: (t3) => (t3 /= 0.5) < 1 ? 0.5 * t3 * t3 : -0.5 * (--t3 * (t3 - 2) - 1),
|
|
easeInCubic: (t3) => t3 * t3 * t3,
|
|
easeOutCubic: (t3) => (t3 -= 1) * t3 * t3 + 1,
|
|
easeInOutCubic: (t3) => (t3 /= 0.5) < 1 ? 0.5 * t3 * t3 * t3 : 0.5 * ((t3 -= 2) * t3 * t3 + 2),
|
|
easeInQuart: (t3) => t3 * t3 * t3 * t3,
|
|
easeOutQuart: (t3) => -((t3 -= 1) * t3 * t3 * t3 - 1),
|
|
easeInOutQuart: (t3) => (t3 /= 0.5) < 1 ? 0.5 * t3 * t3 * t3 * t3 : -0.5 * ((t3 -= 2) * t3 * t3 * t3 - 2),
|
|
easeInQuint: (t3) => t3 * t3 * t3 * t3 * t3,
|
|
easeOutQuint: (t3) => (t3 -= 1) * t3 * t3 * t3 * t3 + 1,
|
|
easeInOutQuint: (t3) => (t3 /= 0.5) < 1 ? 0.5 * t3 * t3 * t3 * t3 * t3 : 0.5 * ((t3 -= 2) * t3 * t3 * t3 * t3 + 2),
|
|
easeInSine: (t3) => -Math.cos(t3 * HALF_PI) + 1,
|
|
easeOutSine: (t3) => Math.sin(t3 * HALF_PI),
|
|
easeInOutSine: (t3) => -0.5 * (Math.cos(PI * t3) - 1),
|
|
easeInExpo: (t3) => t3 === 0 ? 0 : Math.pow(2, 10 * (t3 - 1)),
|
|
easeOutExpo: (t3) => t3 === 1 ? 1 : -Math.pow(2, -10 * t3) + 1,
|
|
easeInOutExpo: (t3) => atEdge(t3) ? t3 : t3 < 0.5 ? 0.5 * Math.pow(2, 10 * (t3 * 2 - 1)) : 0.5 * (-Math.pow(2, -10 * (t3 * 2 - 1)) + 2),
|
|
easeInCirc: (t3) => t3 >= 1 ? t3 : -(Math.sqrt(1 - t3 * t3) - 1),
|
|
easeOutCirc: (t3) => Math.sqrt(1 - (t3 -= 1) * t3),
|
|
easeInOutCirc: (t3) => (t3 /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t3 * t3) - 1) : 0.5 * (Math.sqrt(1 - (t3 -= 2) * t3) + 1),
|
|
easeInElastic: (t3) => atEdge(t3) ? t3 : elasticIn(t3, 0.075, 0.3),
|
|
easeOutElastic: (t3) => atEdge(t3) ? t3 : elasticOut(t3, 0.075, 0.3),
|
|
easeInOutElastic(t3) {
|
|
const s2 = 0.1125;
|
|
const p2 = 0.45;
|
|
return atEdge(t3) ? t3 : t3 < 0.5 ? 0.5 * elasticIn(t3 * 2, s2, p2) : 0.5 + 0.5 * elasticOut(t3 * 2 - 1, s2, p2);
|
|
},
|
|
easeInBack(t3) {
|
|
const s2 = 1.70158;
|
|
return t3 * t3 * ((s2 + 1) * t3 - s2);
|
|
},
|
|
easeOutBack(t3) {
|
|
const s2 = 1.70158;
|
|
return (t3 -= 1) * t3 * ((s2 + 1) * t3 + s2) + 1;
|
|
},
|
|
easeInOutBack(t3) {
|
|
let s2 = 1.70158;
|
|
if ((t3 /= 0.5) < 1) {
|
|
return 0.5 * (t3 * t3 * (((s2 *= 1.525) + 1) * t3 - s2));
|
|
}
|
|
return 0.5 * ((t3 -= 2) * t3 * (((s2 *= 1.525) + 1) * t3 + s2) + 2);
|
|
},
|
|
easeInBounce: (t3) => 1 - effects.easeOutBounce(1 - t3),
|
|
easeOutBounce(t3) {
|
|
const m2 = 7.5625;
|
|
const d2 = 2.75;
|
|
if (t3 < 1 / d2) {
|
|
return m2 * t3 * t3;
|
|
}
|
|
if (t3 < 2 / d2) {
|
|
return m2 * (t3 -= 1.5 / d2) * t3 + 0.75;
|
|
}
|
|
if (t3 < 2.5 / d2) {
|
|
return m2 * (t3 -= 2.25 / d2) * t3 + 0.9375;
|
|
}
|
|
return m2 * (t3 -= 2.625 / d2) * t3 + 0.984375;
|
|
},
|
|
easeInOutBounce: (t3) => t3 < 0.5 ? effects.easeInBounce(t3 * 2) * 0.5 : effects.easeOutBounce(t3 * 2 - 1) * 0.5 + 0.5
|
|
};
|
|
function isPatternOrGradient(value) {
|
|
if (value && typeof value === "object") {
|
|
const type = value.toString();
|
|
return type === "[object CanvasPattern]" || type === "[object CanvasGradient]";
|
|
}
|
|
return false;
|
|
}
|
|
function color(value) {
|
|
return isPatternOrGradient(value) ? value : new Color(value);
|
|
}
|
|
function getHoverColor(value) {
|
|
return isPatternOrGradient(value) ? value : new Color(value).saturate(0.5).darken(0.1).hexString();
|
|
}
|
|
var numbers = [
|
|
"x",
|
|
"y",
|
|
"borderWidth",
|
|
"radius",
|
|
"tension"
|
|
];
|
|
var colors = [
|
|
"color",
|
|
"borderColor",
|
|
"backgroundColor"
|
|
];
|
|
function applyAnimationsDefaults(defaults3) {
|
|
defaults3.set("animation", {
|
|
delay: void 0,
|
|
duration: 1e3,
|
|
easing: "easeOutQuart",
|
|
fn: void 0,
|
|
from: void 0,
|
|
loop: void 0,
|
|
to: void 0,
|
|
type: void 0
|
|
});
|
|
defaults3.describe("animation", {
|
|
_fallback: false,
|
|
_indexable: false,
|
|
_scriptable: (name) => name !== "onProgress" && name !== "onComplete" && name !== "fn"
|
|
});
|
|
defaults3.set("animations", {
|
|
colors: {
|
|
type: "color",
|
|
properties: colors
|
|
},
|
|
numbers: {
|
|
type: "number",
|
|
properties: numbers
|
|
}
|
|
});
|
|
defaults3.describe("animations", {
|
|
_fallback: "animation"
|
|
});
|
|
defaults3.set("transitions", {
|
|
active: {
|
|
animation: {
|
|
duration: 400
|
|
}
|
|
},
|
|
resize: {
|
|
animation: {
|
|
duration: 0
|
|
}
|
|
},
|
|
show: {
|
|
animations: {
|
|
colors: {
|
|
from: "transparent"
|
|
},
|
|
visible: {
|
|
type: "boolean",
|
|
duration: 0
|
|
}
|
|
}
|
|
},
|
|
hide: {
|
|
animations: {
|
|
colors: {
|
|
to: "transparent"
|
|
},
|
|
visible: {
|
|
type: "boolean",
|
|
easing: "linear",
|
|
fn: (v2) => v2 | 0
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function applyLayoutsDefaults(defaults3) {
|
|
defaults3.set("layout", {
|
|
autoPadding: true,
|
|
padding: {
|
|
top: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
left: 0
|
|
}
|
|
});
|
|
}
|
|
var intlCache = /* @__PURE__ */ new Map();
|
|
function getNumberFormat(locale2, options) {
|
|
options = options || {};
|
|
const cacheKey = locale2 + JSON.stringify(options);
|
|
let formatter = intlCache.get(cacheKey);
|
|
if (!formatter) {
|
|
formatter = new Intl.NumberFormat(locale2, options);
|
|
intlCache.set(cacheKey, formatter);
|
|
}
|
|
return formatter;
|
|
}
|
|
function formatNumber(num, locale2, options) {
|
|
return getNumberFormat(locale2, options).format(num);
|
|
}
|
|
var formatters = {
|
|
values(value) {
|
|
return isArray(value) ? value : "" + value;
|
|
},
|
|
numeric(tickValue, index, ticks) {
|
|
if (tickValue === 0) {
|
|
return "0";
|
|
}
|
|
const locale2 = this.chart.options.locale;
|
|
let notation;
|
|
let delta = tickValue;
|
|
if (ticks.length > 1) {
|
|
const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
|
|
if (maxTick < 1e-4 || maxTick > 1e15) {
|
|
notation = "scientific";
|
|
}
|
|
delta = calculateDelta(tickValue, ticks);
|
|
}
|
|
const logDelta = log10(Math.abs(delta));
|
|
const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
|
|
const options = {
|
|
notation,
|
|
minimumFractionDigits: numDecimal,
|
|
maximumFractionDigits: numDecimal
|
|
};
|
|
Object.assign(options, this.options.ticks.format);
|
|
return formatNumber(tickValue, locale2, options);
|
|
},
|
|
logarithmic(tickValue, index, ticks) {
|
|
if (tickValue === 0) {
|
|
return "0";
|
|
}
|
|
const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));
|
|
if ([
|
|
1,
|
|
2,
|
|
3,
|
|
5,
|
|
10,
|
|
15
|
|
].includes(remain) || index > 0.8 * ticks.length) {
|
|
return formatters.numeric.call(this, tickValue, index, ticks);
|
|
}
|
|
return "";
|
|
}
|
|
};
|
|
function calculateDelta(tickValue, ticks) {
|
|
let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
|
|
if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
|
|
delta = tickValue - Math.floor(tickValue);
|
|
}
|
|
return delta;
|
|
}
|
|
var Ticks = {
|
|
formatters
|
|
};
|
|
function applyScaleDefaults(defaults3) {
|
|
defaults3.set("scale", {
|
|
display: true,
|
|
offset: false,
|
|
reverse: false,
|
|
beginAtZero: false,
|
|
bounds: "ticks",
|
|
clip: true,
|
|
grace: 0,
|
|
grid: {
|
|
display: true,
|
|
lineWidth: 1,
|
|
drawOnChartArea: true,
|
|
drawTicks: true,
|
|
tickLength: 8,
|
|
tickWidth: (_ctx, options) => options.lineWidth,
|
|
tickColor: (_ctx, options) => options.color,
|
|
offset: false
|
|
},
|
|
border: {
|
|
display: true,
|
|
dash: [],
|
|
dashOffset: 0,
|
|
width: 1
|
|
},
|
|
title: {
|
|
display: false,
|
|
text: "",
|
|
padding: {
|
|
top: 4,
|
|
bottom: 4
|
|
}
|
|
},
|
|
ticks: {
|
|
minRotation: 0,
|
|
maxRotation: 50,
|
|
mirror: false,
|
|
textStrokeWidth: 0,
|
|
textStrokeColor: "",
|
|
padding: 3,
|
|
display: true,
|
|
autoSkip: true,
|
|
autoSkipPadding: 3,
|
|
labelOffset: 0,
|
|
callback: Ticks.formatters.values,
|
|
minor: {},
|
|
major: {},
|
|
align: "center",
|
|
crossAlign: "near",
|
|
showLabelBackdrop: false,
|
|
backdropColor: "rgba(255, 255, 255, 0.75)",
|
|
backdropPadding: 2
|
|
}
|
|
});
|
|
defaults3.route("scale.ticks", "color", "", "color");
|
|
defaults3.route("scale.grid", "color", "", "borderColor");
|
|
defaults3.route("scale.border", "color", "", "borderColor");
|
|
defaults3.route("scale.title", "color", "", "color");
|
|
defaults3.describe("scale", {
|
|
_fallback: false,
|
|
_scriptable: (name) => !name.startsWith("before") && !name.startsWith("after") && name !== "callback" && name !== "parser",
|
|
_indexable: (name) => name !== "borderDash" && name !== "tickBorderDash" && name !== "dash"
|
|
});
|
|
defaults3.describe("scales", {
|
|
_fallback: "scale"
|
|
});
|
|
defaults3.describe("scale.ticks", {
|
|
_scriptable: (name) => name !== "backdropPadding" && name !== "callback",
|
|
_indexable: (name) => name !== "backdropPadding"
|
|
});
|
|
}
|
|
var overrides = /* @__PURE__ */ Object.create(null);
|
|
var descriptors = /* @__PURE__ */ Object.create(null);
|
|
function getScope$1(node, key) {
|
|
if (!key) {
|
|
return node;
|
|
}
|
|
const keys = key.split(".");
|
|
for (let i2 = 0, n2 = keys.length; i2 < n2; ++i2) {
|
|
const k = keys[i2];
|
|
node = node[k] || (node[k] = /* @__PURE__ */ Object.create(null));
|
|
}
|
|
return node;
|
|
}
|
|
function set(root, scope, values) {
|
|
if (typeof scope === "string") {
|
|
return merge(getScope$1(root, scope), values);
|
|
}
|
|
return merge(getScope$1(root, ""), scope);
|
|
}
|
|
var Defaults = class {
|
|
constructor(_descriptors2, _appliers) {
|
|
this.animation = void 0;
|
|
this.backgroundColor = "rgba(0,0,0,0.1)";
|
|
this.borderColor = "rgba(0,0,0,0.1)";
|
|
this.color = "#666";
|
|
this.datasets = {};
|
|
this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio();
|
|
this.elements = {};
|
|
this.events = [
|
|
"mousemove",
|
|
"mouseout",
|
|
"click",
|
|
"touchstart",
|
|
"touchmove"
|
|
];
|
|
this.font = {
|
|
family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
|
size: 12,
|
|
style: "normal",
|
|
lineHeight: 1.2,
|
|
weight: null
|
|
};
|
|
this.hover = {};
|
|
this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor);
|
|
this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor);
|
|
this.hoverColor = (ctx, options) => getHoverColor(options.color);
|
|
this.indexAxis = "x";
|
|
this.interaction = {
|
|
mode: "nearest",
|
|
intersect: true,
|
|
includeInvisible: false
|
|
};
|
|
this.maintainAspectRatio = true;
|
|
this.onHover = null;
|
|
this.onClick = null;
|
|
this.parsing = true;
|
|
this.plugins = {};
|
|
this.responsive = true;
|
|
this.scale = void 0;
|
|
this.scales = {};
|
|
this.showLine = true;
|
|
this.drawActiveElementsOnTop = true;
|
|
this.describe(_descriptors2);
|
|
this.apply(_appliers);
|
|
}
|
|
set(scope, values) {
|
|
return set(this, scope, values);
|
|
}
|
|
get(scope) {
|
|
return getScope$1(this, scope);
|
|
}
|
|
describe(scope, values) {
|
|
return set(descriptors, scope, values);
|
|
}
|
|
override(scope, values) {
|
|
return set(overrides, scope, values);
|
|
}
|
|
route(scope, name, targetScope, targetName) {
|
|
const scopeObject = getScope$1(this, scope);
|
|
const targetScopeObject = getScope$1(this, targetScope);
|
|
const privateName = "_" + name;
|
|
Object.defineProperties(scopeObject, {
|
|
[privateName]: {
|
|
value: scopeObject[name],
|
|
writable: true
|
|
},
|
|
[name]: {
|
|
enumerable: true,
|
|
get() {
|
|
const local = this[privateName];
|
|
const target = targetScopeObject[targetName];
|
|
if (isObject(local)) {
|
|
return Object.assign({}, target, local);
|
|
}
|
|
return valueOrDefault(local, target);
|
|
},
|
|
set(value) {
|
|
this[privateName] = value;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
apply(appliers) {
|
|
appliers.forEach((apply) => apply(this));
|
|
}
|
|
};
|
|
var defaults2 = /* @__PURE__ */ new Defaults({
|
|
_scriptable: (name) => !name.startsWith("on"),
|
|
_indexable: (name) => name !== "events",
|
|
hover: {
|
|
_fallback: "interaction"
|
|
},
|
|
interaction: {
|
|
_scriptable: false,
|
|
_indexable: false
|
|
}
|
|
}, [
|
|
applyAnimationsDefaults,
|
|
applyLayoutsDefaults,
|
|
applyScaleDefaults
|
|
]);
|
|
function toFontString(font) {
|
|
if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
|
|
return null;
|
|
}
|
|
return (font.style ? font.style + " " : "") + (font.weight ? font.weight + " " : "") + font.size + "px " + font.family;
|
|
}
|
|
function _measureText(ctx, data, gc, longest, string) {
|
|
let textWidth = data[string];
|
|
if (!textWidth) {
|
|
textWidth = data[string] = ctx.measureText(string).width;
|
|
gc.push(string);
|
|
}
|
|
if (textWidth > longest) {
|
|
longest = textWidth;
|
|
}
|
|
return longest;
|
|
}
|
|
function _longestText(ctx, font, arrayOfThings, cache) {
|
|
cache = cache || {};
|
|
let data = cache.data = cache.data || {};
|
|
let gc = cache.garbageCollect = cache.garbageCollect || [];
|
|
if (cache.font !== font) {
|
|
data = cache.data = {};
|
|
gc = cache.garbageCollect = [];
|
|
cache.font = font;
|
|
}
|
|
ctx.save();
|
|
ctx.font = font;
|
|
let longest = 0;
|
|
const ilen = arrayOfThings.length;
|
|
let i2, j2, jlen, thing, nestedThing;
|
|
for (i2 = 0; i2 < ilen; i2++) {
|
|
thing = arrayOfThings[i2];
|
|
if (thing !== void 0 && thing !== null && !isArray(thing)) {
|
|
longest = _measureText(ctx, data, gc, longest, thing);
|
|
} else if (isArray(thing)) {
|
|
for (j2 = 0, jlen = thing.length; j2 < jlen; j2++) {
|
|
nestedThing = thing[j2];
|
|
if (nestedThing !== void 0 && nestedThing !== null && !isArray(nestedThing)) {
|
|
longest = _measureText(ctx, data, gc, longest, nestedThing);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ctx.restore();
|
|
const gcLen = gc.length / 2;
|
|
if (gcLen > arrayOfThings.length) {
|
|
for (i2 = 0; i2 < gcLen; i2++) {
|
|
delete data[gc[i2]];
|
|
}
|
|
gc.splice(0, gcLen);
|
|
}
|
|
return longest;
|
|
}
|
|
function _alignPixel(chart, pixel, width) {
|
|
const devicePixelRatio = chart.currentDevicePixelRatio;
|
|
const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
|
|
return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
|
|
}
|
|
function clearCanvas(canvas, ctx) {
|
|
if (!ctx && !canvas) {
|
|
return;
|
|
}
|
|
ctx = ctx || canvas.getContext("2d");
|
|
ctx.save();
|
|
ctx.resetTransform();
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
ctx.restore();
|
|
}
|
|
function drawPoint(ctx, options, x2, y2) {
|
|
drawPointLegend(ctx, options, x2, y2, null);
|
|
}
|
|
function drawPointLegend(ctx, options, x2, y2, w2) {
|
|
let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;
|
|
const style = options.pointStyle;
|
|
const rotation = options.rotation;
|
|
const radius = options.radius;
|
|
let rad = (rotation || 0) * RAD_PER_DEG;
|
|
if (style && typeof style === "object") {
|
|
type = style.toString();
|
|
if (type === "[object HTMLImageElement]" || type === "[object HTMLCanvasElement]") {
|
|
ctx.save();
|
|
ctx.translate(x2, y2);
|
|
ctx.rotate(rad);
|
|
ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
|
|
ctx.restore();
|
|
return;
|
|
}
|
|
}
|
|
if (isNaN(radius) || radius <= 0) {
|
|
return;
|
|
}
|
|
ctx.beginPath();
|
|
switch (style) {
|
|
// Default includes circle
|
|
default:
|
|
if (w2) {
|
|
ctx.ellipse(x2, y2, w2 / 2, radius, 0, 0, TAU);
|
|
} else {
|
|
ctx.arc(x2, y2, radius, 0, TAU);
|
|
}
|
|
ctx.closePath();
|
|
break;
|
|
case "triangle":
|
|
width = w2 ? w2 / 2 : radius;
|
|
ctx.moveTo(x2 + Math.sin(rad) * width, y2 - Math.cos(rad) * radius);
|
|
rad += TWO_THIRDS_PI;
|
|
ctx.lineTo(x2 + Math.sin(rad) * width, y2 - Math.cos(rad) * radius);
|
|
rad += TWO_THIRDS_PI;
|
|
ctx.lineTo(x2 + Math.sin(rad) * width, y2 - Math.cos(rad) * radius);
|
|
ctx.closePath();
|
|
break;
|
|
case "rectRounded":
|
|
cornerRadius = radius * 0.516;
|
|
size = radius - cornerRadius;
|
|
xOffset = Math.cos(rad + QUARTER_PI) * size;
|
|
xOffsetW = Math.cos(rad + QUARTER_PI) * (w2 ? w2 / 2 - cornerRadius : size);
|
|
yOffset = Math.sin(rad + QUARTER_PI) * size;
|
|
yOffsetW = Math.sin(rad + QUARTER_PI) * (w2 ? w2 / 2 - cornerRadius : size);
|
|
ctx.arc(x2 - xOffsetW, y2 - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
|
|
ctx.arc(x2 + yOffsetW, y2 - xOffset, cornerRadius, rad - HALF_PI, rad);
|
|
ctx.arc(x2 + xOffsetW, y2 + yOffset, cornerRadius, rad, rad + HALF_PI);
|
|
ctx.arc(x2 - yOffsetW, y2 + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
|
|
ctx.closePath();
|
|
break;
|
|
case "rect":
|
|
if (!rotation) {
|
|
size = Math.SQRT1_2 * radius;
|
|
width = w2 ? w2 / 2 : size;
|
|
ctx.rect(x2 - width, y2 - size, 2 * width, 2 * size);
|
|
break;
|
|
}
|
|
rad += QUARTER_PI;
|
|
/* falls through */
|
|
case "rectRot":
|
|
xOffsetW = Math.cos(rad) * (w2 ? w2 / 2 : radius);
|
|
xOffset = Math.cos(rad) * radius;
|
|
yOffset = Math.sin(rad) * radius;
|
|
yOffsetW = Math.sin(rad) * (w2 ? w2 / 2 : radius);
|
|
ctx.moveTo(x2 - xOffsetW, y2 - yOffset);
|
|
ctx.lineTo(x2 + yOffsetW, y2 - xOffset);
|
|
ctx.lineTo(x2 + xOffsetW, y2 + yOffset);
|
|
ctx.lineTo(x2 - yOffsetW, y2 + xOffset);
|
|
ctx.closePath();
|
|
break;
|
|
case "crossRot":
|
|
rad += QUARTER_PI;
|
|
/* falls through */
|
|
case "cross":
|
|
xOffsetW = Math.cos(rad) * (w2 ? w2 / 2 : radius);
|
|
xOffset = Math.cos(rad) * radius;
|
|
yOffset = Math.sin(rad) * radius;
|
|
yOffsetW = Math.sin(rad) * (w2 ? w2 / 2 : radius);
|
|
ctx.moveTo(x2 - xOffsetW, y2 - yOffset);
|
|
ctx.lineTo(x2 + xOffsetW, y2 + yOffset);
|
|
ctx.moveTo(x2 + yOffsetW, y2 - xOffset);
|
|
ctx.lineTo(x2 - yOffsetW, y2 + xOffset);
|
|
break;
|
|
case "star":
|
|
xOffsetW = Math.cos(rad) * (w2 ? w2 / 2 : radius);
|
|
xOffset = Math.cos(rad) * radius;
|
|
yOffset = Math.sin(rad) * radius;
|
|
yOffsetW = Math.sin(rad) * (w2 ? w2 / 2 : radius);
|
|
ctx.moveTo(x2 - xOffsetW, y2 - yOffset);
|
|
ctx.lineTo(x2 + xOffsetW, y2 + yOffset);
|
|
ctx.moveTo(x2 + yOffsetW, y2 - xOffset);
|
|
ctx.lineTo(x2 - yOffsetW, y2 + xOffset);
|
|
rad += QUARTER_PI;
|
|
xOffsetW = Math.cos(rad) * (w2 ? w2 / 2 : radius);
|
|
xOffset = Math.cos(rad) * radius;
|
|
yOffset = Math.sin(rad) * radius;
|
|
yOffsetW = Math.sin(rad) * (w2 ? w2 / 2 : radius);
|
|
ctx.moveTo(x2 - xOffsetW, y2 - yOffset);
|
|
ctx.lineTo(x2 + xOffsetW, y2 + yOffset);
|
|
ctx.moveTo(x2 + yOffsetW, y2 - xOffset);
|
|
ctx.lineTo(x2 - yOffsetW, y2 + xOffset);
|
|
break;
|
|
case "line":
|
|
xOffset = w2 ? w2 / 2 : Math.cos(rad) * radius;
|
|
yOffset = Math.sin(rad) * radius;
|
|
ctx.moveTo(x2 - xOffset, y2 - yOffset);
|
|
ctx.lineTo(x2 + xOffset, y2 + yOffset);
|
|
break;
|
|
case "dash":
|
|
ctx.moveTo(x2, y2);
|
|
ctx.lineTo(x2 + Math.cos(rad) * (w2 ? w2 / 2 : radius), y2 + Math.sin(rad) * radius);
|
|
break;
|
|
case false:
|
|
ctx.closePath();
|
|
break;
|
|
}
|
|
ctx.fill();
|
|
if (options.borderWidth > 0) {
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
function _isPointInArea(point, area, margin) {
|
|
margin = margin || 0.5;
|
|
return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;
|
|
}
|
|
function clipArea(ctx, area) {
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
|
|
ctx.clip();
|
|
}
|
|
function unclipArea(ctx) {
|
|
ctx.restore();
|
|
}
|
|
function setRenderOpts(ctx, opts) {
|
|
if (opts.translation) {
|
|
ctx.translate(opts.translation[0], opts.translation[1]);
|
|
}
|
|
if (!isNullOrUndef(opts.rotation)) {
|
|
ctx.rotate(opts.rotation);
|
|
}
|
|
if (opts.color) {
|
|
ctx.fillStyle = opts.color;
|
|
}
|
|
if (opts.textAlign) {
|
|
ctx.textAlign = opts.textAlign;
|
|
}
|
|
if (opts.textBaseline) {
|
|
ctx.textBaseline = opts.textBaseline;
|
|
}
|
|
}
|
|
function decorateText(ctx, x2, y2, line, opts) {
|
|
if (opts.strikethrough || opts.underline) {
|
|
const metrics = ctx.measureText(line);
|
|
const left = x2 - metrics.actualBoundingBoxLeft;
|
|
const right = x2 + metrics.actualBoundingBoxRight;
|
|
const top = y2 - metrics.actualBoundingBoxAscent;
|
|
const bottom = y2 + metrics.actualBoundingBoxDescent;
|
|
const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
|
|
ctx.strokeStyle = ctx.fillStyle;
|
|
ctx.beginPath();
|
|
ctx.lineWidth = opts.decorationWidth || 2;
|
|
ctx.moveTo(left, yDecoration);
|
|
ctx.lineTo(right, yDecoration);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
function drawBackdrop(ctx, opts) {
|
|
const oldColor = ctx.fillStyle;
|
|
ctx.fillStyle = opts.color;
|
|
ctx.fillRect(opts.left, opts.top, opts.width, opts.height);
|
|
ctx.fillStyle = oldColor;
|
|
}
|
|
function renderText(ctx, text, x2, y2, font, opts = {}) {
|
|
const lines = isArray(text) ? text : [
|
|
text
|
|
];
|
|
const stroke = opts.strokeWidth > 0 && opts.strokeColor !== "";
|
|
let i2, line;
|
|
ctx.save();
|
|
ctx.font = font.string;
|
|
setRenderOpts(ctx, opts);
|
|
for (i2 = 0; i2 < lines.length; ++i2) {
|
|
line = lines[i2];
|
|
if (opts.backdrop) {
|
|
drawBackdrop(ctx, opts.backdrop);
|
|
}
|
|
if (stroke) {
|
|
if (opts.strokeColor) {
|
|
ctx.strokeStyle = opts.strokeColor;
|
|
}
|
|
if (!isNullOrUndef(opts.strokeWidth)) {
|
|
ctx.lineWidth = opts.strokeWidth;
|
|
}
|
|
ctx.strokeText(line, x2, y2, opts.maxWidth);
|
|
}
|
|
ctx.fillText(line, x2, y2, opts.maxWidth);
|
|
decorateText(ctx, x2, y2, line, opts);
|
|
y2 += Number(font.lineHeight);
|
|
}
|
|
ctx.restore();
|
|
}
|
|
function addRoundedRectPath(ctx, rect) {
|
|
const { x: x2, y: y2, w: w2, h: h6, radius } = rect;
|
|
ctx.arc(x2 + radius.topLeft, y2 + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);
|
|
ctx.lineTo(x2, y2 + h6 - radius.bottomLeft);
|
|
ctx.arc(x2 + radius.bottomLeft, y2 + h6 - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
|
|
ctx.lineTo(x2 + w2 - radius.bottomRight, y2 + h6);
|
|
ctx.arc(x2 + w2 - radius.bottomRight, y2 + h6 - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
|
|
ctx.lineTo(x2 + w2, y2 + radius.topRight);
|
|
ctx.arc(x2 + w2 - radius.topRight, y2 + radius.topRight, radius.topRight, 0, -HALF_PI, true);
|
|
ctx.lineTo(x2 + radius.topLeft, y2);
|
|
}
|
|
var LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/;
|
|
var FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;
|
|
function toLineHeight(value, size) {
|
|
const matches = ("" + value).match(LINE_HEIGHT);
|
|
if (!matches || matches[1] === "normal") {
|
|
return size * 1.2;
|
|
}
|
|
value = +matches[2];
|
|
switch (matches[3]) {
|
|
case "px":
|
|
return value;
|
|
case "%":
|
|
value /= 100;
|
|
break;
|
|
}
|
|
return size * value;
|
|
}
|
|
var numberOrZero = (v2) => +v2 || 0;
|
|
function _readValueToProps(value, props) {
|
|
const ret = {};
|
|
const objProps = isObject(props);
|
|
const keys = objProps ? Object.keys(props) : props;
|
|
const read = isObject(value) ? objProps ? (prop) => valueOrDefault(value[prop], value[props[prop]]) : (prop) => value[prop] : () => value;
|
|
for (const prop of keys) {
|
|
ret[prop] = numberOrZero(read(prop));
|
|
}
|
|
return ret;
|
|
}
|
|
function toTRBL(value) {
|
|
return _readValueToProps(value, {
|
|
top: "y",
|
|
right: "x",
|
|
bottom: "y",
|
|
left: "x"
|
|
});
|
|
}
|
|
function toTRBLCorners(value) {
|
|
return _readValueToProps(value, [
|
|
"topLeft",
|
|
"topRight",
|
|
"bottomLeft",
|
|
"bottomRight"
|
|
]);
|
|
}
|
|
function toPadding(value) {
|
|
const obj = toTRBL(value);
|
|
obj.width = obj.left + obj.right;
|
|
obj.height = obj.top + obj.bottom;
|
|
return obj;
|
|
}
|
|
function toFont(options, fallback) {
|
|
options = options || {};
|
|
fallback = fallback || defaults2.font;
|
|
let size = valueOrDefault(options.size, fallback.size);
|
|
if (typeof size === "string") {
|
|
size = parseInt(size, 10);
|
|
}
|
|
let style = valueOrDefault(options.style, fallback.style);
|
|
if (style && !("" + style).match(FONT_STYLE)) {
|
|
console.warn('Invalid font style specified: "' + style + '"');
|
|
style = void 0;
|
|
}
|
|
const font = {
|
|
family: valueOrDefault(options.family, fallback.family),
|
|
lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
|
|
size,
|
|
style,
|
|
weight: valueOrDefault(options.weight, fallback.weight),
|
|
string: ""
|
|
};
|
|
font.string = toFontString(font);
|
|
return font;
|
|
}
|
|
function resolve(inputs, context, index, info) {
|
|
let cacheable = true;
|
|
let i2, ilen, value;
|
|
for (i2 = 0, ilen = inputs.length; i2 < ilen; ++i2) {
|
|
value = inputs[i2];
|
|
if (value === void 0) {
|
|
continue;
|
|
}
|
|
if (context !== void 0 && typeof value === "function") {
|
|
value = value(context);
|
|
cacheable = false;
|
|
}
|
|
if (index !== void 0 && isArray(value)) {
|
|
value = value[index % value.length];
|
|
cacheable = false;
|
|
}
|
|
if (value !== void 0) {
|
|
if (info && !cacheable) {
|
|
info.cacheable = false;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
function _addGrace(minmax, grace, beginAtZero) {
|
|
const { min, max } = minmax;
|
|
const change = toDimension(grace, (max - min) / 2);
|
|
const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add;
|
|
return {
|
|
min: keepZero(min, -Math.abs(change)),
|
|
max: keepZero(max, change)
|
|
};
|
|
}
|
|
function createContext(parentContext, context) {
|
|
return Object.assign(Object.create(parentContext), context);
|
|
}
|
|
function _createResolver(scopes, prefixes = [
|
|
""
|
|
], rootScopes, fallback, getTarget = () => scopes[0]) {
|
|
const finalRootScopes = rootScopes || scopes;
|
|
if (typeof fallback === "undefined") {
|
|
fallback = _resolve("_fallback", scopes);
|
|
}
|
|
const cache = {
|
|
[Symbol.toStringTag]: "Object",
|
|
_cacheable: true,
|
|
_scopes: scopes,
|
|
_rootScopes: finalRootScopes,
|
|
_fallback: fallback,
|
|
_getTarget: getTarget,
|
|
override: (scope) => _createResolver([
|
|
scope,
|
|
...scopes
|
|
], prefixes, finalRootScopes, fallback)
|
|
};
|
|
return new Proxy(cache, {
|
|
/**
|
|
* A trap for the delete operator.
|
|
*/
|
|
deleteProperty(target, prop) {
|
|
delete target[prop];
|
|
delete target._keys;
|
|
delete scopes[0][prop];
|
|
return true;
|
|
},
|
|
/**
|
|
* A trap for getting property values.
|
|
*/
|
|
get(target, prop) {
|
|
return _cached(target, prop, () => _resolveWithPrefixes(prop, prefixes, scopes, target));
|
|
},
|
|
/**
|
|
* A trap for Object.getOwnPropertyDescriptor.
|
|
* Also used by Object.hasOwnProperty.
|
|
*/
|
|
getOwnPropertyDescriptor(target, prop) {
|
|
return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
|
|
},
|
|
/**
|
|
* A trap for Object.getPrototypeOf.
|
|
*/
|
|
getPrototypeOf() {
|
|
return Reflect.getPrototypeOf(scopes[0]);
|
|
},
|
|
/**
|
|
* A trap for the in operator.
|
|
*/
|
|
has(target, prop) {
|
|
return getKeysFromAllScopes(target).includes(prop);
|
|
},
|
|
/**
|
|
* A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
|
|
*/
|
|
ownKeys(target) {
|
|
return getKeysFromAllScopes(target);
|
|
},
|
|
/**
|
|
* A trap for setting property values.
|
|
*/
|
|
set(target, prop, value) {
|
|
const storage = target._storage || (target._storage = getTarget());
|
|
target[prop] = storage[prop] = value;
|
|
delete target._keys;
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
function _attachContext(proxy, context, subProxy, descriptorDefaults) {
|
|
const cache = {
|
|
_cacheable: false,
|
|
_proxy: proxy,
|
|
_context: context,
|
|
_subProxy: subProxy,
|
|
_stack: /* @__PURE__ */ new Set(),
|
|
_descriptors: _descriptors(proxy, descriptorDefaults),
|
|
setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults),
|
|
override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
|
|
};
|
|
return new Proxy(cache, {
|
|
/**
|
|
* A trap for the delete operator.
|
|
*/
|
|
deleteProperty(target, prop) {
|
|
delete target[prop];
|
|
delete proxy[prop];
|
|
return true;
|
|
},
|
|
/**
|
|
* A trap for getting property values.
|
|
*/
|
|
get(target, prop, receiver) {
|
|
return _cached(target, prop, () => _resolveWithContext(target, prop, receiver));
|
|
},
|
|
/**
|
|
* A trap for Object.getOwnPropertyDescriptor.
|
|
* Also used by Object.hasOwnProperty.
|
|
*/
|
|
getOwnPropertyDescriptor(target, prop) {
|
|
return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {
|
|
enumerable: true,
|
|
configurable: true
|
|
} : void 0 : Reflect.getOwnPropertyDescriptor(proxy, prop);
|
|
},
|
|
/**
|
|
* A trap for Object.getPrototypeOf.
|
|
*/
|
|
getPrototypeOf() {
|
|
return Reflect.getPrototypeOf(proxy);
|
|
},
|
|
/**
|
|
* A trap for the in operator.
|
|
*/
|
|
has(target, prop) {
|
|
return Reflect.has(proxy, prop);
|
|
},
|
|
/**
|
|
* A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
|
|
*/
|
|
ownKeys() {
|
|
return Reflect.ownKeys(proxy);
|
|
},
|
|
/**
|
|
* A trap for setting property values.
|
|
*/
|
|
set(target, prop, value) {
|
|
proxy[prop] = value;
|
|
delete target[prop];
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
function _descriptors(proxy, defaults3 = {
|
|
scriptable: true,
|
|
indexable: true
|
|
}) {
|
|
const { _scriptable = defaults3.scriptable, _indexable = defaults3.indexable, _allKeys = defaults3.allKeys } = proxy;
|
|
return {
|
|
allKeys: _allKeys,
|
|
scriptable: _scriptable,
|
|
indexable: _indexable,
|
|
isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable,
|
|
isIndexable: isFunction(_indexable) ? _indexable : () => _indexable
|
|
};
|
|
}
|
|
var readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name;
|
|
var needsSubResolver = (prop, value) => isObject(value) && prop !== "adapters" && (Object.getPrototypeOf(value) === null || value.constructor === Object);
|
|
function _cached(target, prop, resolve2) {
|
|
if (Object.prototype.hasOwnProperty.call(target, prop) || prop === "constructor") {
|
|
return target[prop];
|
|
}
|
|
const value = resolve2();
|
|
target[prop] = value;
|
|
return value;
|
|
}
|
|
function _resolveWithContext(target, prop, receiver) {
|
|
const { _proxy, _context, _subProxy, _descriptors: descriptors2 } = target;
|
|
let value = _proxy[prop];
|
|
if (isFunction(value) && descriptors2.isScriptable(prop)) {
|
|
value = _resolveScriptable(prop, value, target, receiver);
|
|
}
|
|
if (isArray(value) && value.length) {
|
|
value = _resolveArray(prop, value, target, descriptors2.isIndexable);
|
|
}
|
|
if (needsSubResolver(prop, value)) {
|
|
value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors2);
|
|
}
|
|
return value;
|
|
}
|
|
function _resolveScriptable(prop, getValue, target, receiver) {
|
|
const { _proxy, _context, _subProxy, _stack } = target;
|
|
if (_stack.has(prop)) {
|
|
throw new Error("Recursion detected: " + Array.from(_stack).join("->") + "->" + prop);
|
|
}
|
|
_stack.add(prop);
|
|
let value = getValue(_context, _subProxy || receiver);
|
|
_stack.delete(prop);
|
|
if (needsSubResolver(prop, value)) {
|
|
value = createSubResolver(_proxy._scopes, _proxy, prop, value);
|
|
}
|
|
return value;
|
|
}
|
|
function _resolveArray(prop, value, target, isIndexable) {
|
|
const { _proxy, _context, _subProxy, _descriptors: descriptors2 } = target;
|
|
if (typeof _context.index !== "undefined" && isIndexable(prop)) {
|
|
return value[_context.index % value.length];
|
|
} else if (isObject(value[0])) {
|
|
const arr = value;
|
|
const scopes = _proxy._scopes.filter((s2) => s2 !== arr);
|
|
value = [];
|
|
for (const item of arr) {
|
|
const resolver = createSubResolver(scopes, _proxy, prop, item);
|
|
value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors2));
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function resolveFallback(fallback, prop, value) {
|
|
return isFunction(fallback) ? fallback(prop, value) : fallback;
|
|
}
|
|
var getScope = (key, parent) => key === true ? parent : typeof key === "string" ? resolveObjectKey(parent, key) : void 0;
|
|
function addScopes(set2, parentScopes, key, parentFallback, value) {
|
|
for (const parent of parentScopes) {
|
|
const scope = getScope(key, parent);
|
|
if (scope) {
|
|
set2.add(scope);
|
|
const fallback = resolveFallback(scope._fallback, key, value);
|
|
if (typeof fallback !== "undefined" && fallback !== key && fallback !== parentFallback) {
|
|
return fallback;
|
|
}
|
|
} else if (scope === false && typeof parentFallback !== "undefined" && key !== parentFallback) {
|
|
return null;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function createSubResolver(parentScopes, resolver, prop, value) {
|
|
const rootScopes = resolver._rootScopes;
|
|
const fallback = resolveFallback(resolver._fallback, prop, value);
|
|
const allScopes = [
|
|
...parentScopes,
|
|
...rootScopes
|
|
];
|
|
const set2 = /* @__PURE__ */ new Set();
|
|
set2.add(value);
|
|
let key = addScopesFromKey(set2, allScopes, prop, fallback || prop, value);
|
|
if (key === null) {
|
|
return false;
|
|
}
|
|
if (typeof fallback !== "undefined" && fallback !== prop) {
|
|
key = addScopesFromKey(set2, allScopes, fallback, key, value);
|
|
if (key === null) {
|
|
return false;
|
|
}
|
|
}
|
|
return _createResolver(Array.from(set2), [
|
|
""
|
|
], rootScopes, fallback, () => subGetTarget(resolver, prop, value));
|
|
}
|
|
function addScopesFromKey(set2, allScopes, key, fallback, item) {
|
|
while (key) {
|
|
key = addScopes(set2, allScopes, key, fallback, item);
|
|
}
|
|
return key;
|
|
}
|
|
function subGetTarget(resolver, prop, value) {
|
|
const parent = resolver._getTarget();
|
|
if (!(prop in parent)) {
|
|
parent[prop] = {};
|
|
}
|
|
const target = parent[prop];
|
|
if (isArray(target) && isObject(value)) {
|
|
return value;
|
|
}
|
|
return target || {};
|
|
}
|
|
function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
|
|
let value;
|
|
for (const prefix of prefixes) {
|
|
value = _resolve(readKey(prefix, prop), scopes);
|
|
if (typeof value !== "undefined") {
|
|
return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;
|
|
}
|
|
}
|
|
}
|
|
function _resolve(key, scopes) {
|
|
for (const scope of scopes) {
|
|
if (!scope) {
|
|
continue;
|
|
}
|
|
const value = scope[key];
|
|
if (typeof value !== "undefined") {
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
function getKeysFromAllScopes(target) {
|
|
let keys = target._keys;
|
|
if (!keys) {
|
|
keys = target._keys = resolveKeysFromAllScopes(target._scopes);
|
|
}
|
|
return keys;
|
|
}
|
|
function resolveKeysFromAllScopes(scopes) {
|
|
const set2 = /* @__PURE__ */ new Set();
|
|
for (const scope of scopes) {
|
|
for (const key of Object.keys(scope).filter((k) => !k.startsWith("_"))) {
|
|
set2.add(key);
|
|
}
|
|
}
|
|
return Array.from(set2);
|
|
}
|
|
var EPSILON = Number.EPSILON || 1e-14;
|
|
function _isDomSupported() {
|
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
}
|
|
function _getParentNode(domNode) {
|
|
let parent = domNode.parentNode;
|
|
if (parent && parent.toString() === "[object ShadowRoot]") {
|
|
parent = parent.host;
|
|
}
|
|
return parent;
|
|
}
|
|
function parseMaxStyle(styleValue, node, parentProperty) {
|
|
let valueInPixels;
|
|
if (typeof styleValue === "string") {
|
|
valueInPixels = parseInt(styleValue, 10);
|
|
if (styleValue.indexOf("%") !== -1) {
|
|
valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
|
|
}
|
|
} else {
|
|
valueInPixels = styleValue;
|
|
}
|
|
return valueInPixels;
|
|
}
|
|
var getComputedStyle2 = (element) => element.ownerDocument.defaultView.getComputedStyle(element, null);
|
|
function getStyle(el, property) {
|
|
return getComputedStyle2(el).getPropertyValue(property);
|
|
}
|
|
var positions = [
|
|
"top",
|
|
"right",
|
|
"bottom",
|
|
"left"
|
|
];
|
|
function getPositionedStyle(styles, style, suffix) {
|
|
const result = {};
|
|
suffix = suffix ? "-" + suffix : "";
|
|
for (let i2 = 0; i2 < 4; i2++) {
|
|
const pos = positions[i2];
|
|
result[pos] = parseFloat(styles[style + "-" + pos + suffix]) || 0;
|
|
}
|
|
result.width = result.left + result.right;
|
|
result.height = result.top + result.bottom;
|
|
return result;
|
|
}
|
|
var useOffsetPos = (x2, y2, target) => (x2 > 0 || y2 > 0) && (!target || !target.shadowRoot);
|
|
function getCanvasPosition(e2, canvas) {
|
|
const touches = e2.touches;
|
|
const source = touches && touches.length ? touches[0] : e2;
|
|
const { offsetX, offsetY } = source;
|
|
let box = false;
|
|
let x2, y2;
|
|
if (useOffsetPos(offsetX, offsetY, e2.target)) {
|
|
x2 = offsetX;
|
|
y2 = offsetY;
|
|
} else {
|
|
const rect = canvas.getBoundingClientRect();
|
|
x2 = source.clientX - rect.left;
|
|
y2 = source.clientY - rect.top;
|
|
box = true;
|
|
}
|
|
return {
|
|
x: x2,
|
|
y: y2,
|
|
box
|
|
};
|
|
}
|
|
function getRelativePosition(event, chart) {
|
|
if ("native" in event) {
|
|
return event;
|
|
}
|
|
const { canvas, currentDevicePixelRatio } = chart;
|
|
const style = getComputedStyle2(canvas);
|
|
const borderBox = style.boxSizing === "border-box";
|
|
const paddings = getPositionedStyle(style, "padding");
|
|
const borders = getPositionedStyle(style, "border", "width");
|
|
const { x: x2, y: y2, box } = getCanvasPosition(event, canvas);
|
|
const xOffset = paddings.left + (box && borders.left);
|
|
const yOffset = paddings.top + (box && borders.top);
|
|
let { width, height } = chart;
|
|
if (borderBox) {
|
|
width -= paddings.width + borders.width;
|
|
height -= paddings.height + borders.height;
|
|
}
|
|
return {
|
|
x: Math.round((x2 - xOffset) / width * canvas.width / currentDevicePixelRatio),
|
|
y: Math.round((y2 - yOffset) / height * canvas.height / currentDevicePixelRatio)
|
|
};
|
|
}
|
|
function getContainerSize(canvas, width, height) {
|
|
let maxWidth, maxHeight;
|
|
if (width === void 0 || height === void 0) {
|
|
const container = canvas && _getParentNode(canvas);
|
|
if (!container) {
|
|
width = canvas.clientWidth;
|
|
height = canvas.clientHeight;
|
|
} else {
|
|
const rect = container.getBoundingClientRect();
|
|
const containerStyle = getComputedStyle2(container);
|
|
const containerBorder = getPositionedStyle(containerStyle, "border", "width");
|
|
const containerPadding = getPositionedStyle(containerStyle, "padding");
|
|
width = rect.width - containerPadding.width - containerBorder.width;
|
|
height = rect.height - containerPadding.height - containerBorder.height;
|
|
maxWidth = parseMaxStyle(containerStyle.maxWidth, container, "clientWidth");
|
|
maxHeight = parseMaxStyle(containerStyle.maxHeight, container, "clientHeight");
|
|
}
|
|
}
|
|
return {
|
|
width,
|
|
height,
|
|
maxWidth: maxWidth || INFINITY,
|
|
maxHeight: maxHeight || INFINITY
|
|
};
|
|
}
|
|
var round1 = (v2) => Math.round(v2 * 10) / 10;
|
|
function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
|
|
const style = getComputedStyle2(canvas);
|
|
const margins = getPositionedStyle(style, "margin");
|
|
const maxWidth = parseMaxStyle(style.maxWidth, canvas, "clientWidth") || INFINITY;
|
|
const maxHeight = parseMaxStyle(style.maxHeight, canvas, "clientHeight") || INFINITY;
|
|
const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
|
|
let { width, height } = containerSize;
|
|
if (style.boxSizing === "content-box") {
|
|
const borders = getPositionedStyle(style, "border", "width");
|
|
const paddings = getPositionedStyle(style, "padding");
|
|
width -= paddings.width + borders.width;
|
|
height -= paddings.height + borders.height;
|
|
}
|
|
width = Math.max(0, width - margins.width);
|
|
height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);
|
|
width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
|
|
height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
|
|
if (width && !height) {
|
|
height = round1(width / 2);
|
|
}
|
|
const maintainHeight = bbWidth !== void 0 || bbHeight !== void 0;
|
|
if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {
|
|
height = containerSize.height;
|
|
width = round1(Math.floor(height * aspectRatio));
|
|
}
|
|
return {
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
function retinaScale(chart, forceRatio, forceStyle) {
|
|
const pixelRatio = forceRatio || 1;
|
|
const deviceHeight = Math.floor(chart.height * pixelRatio);
|
|
const deviceWidth = Math.floor(chart.width * pixelRatio);
|
|
chart.height = Math.floor(chart.height);
|
|
chart.width = Math.floor(chart.width);
|
|
const canvas = chart.canvas;
|
|
if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {
|
|
canvas.style.height = `${chart.height}px`;
|
|
canvas.style.width = `${chart.width}px`;
|
|
}
|
|
if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {
|
|
chart.currentDevicePixelRatio = pixelRatio;
|
|
canvas.height = deviceHeight;
|
|
canvas.width = deviceWidth;
|
|
chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
var supportsEventListenerOptions = function() {
|
|
let passiveSupported = false;
|
|
try {
|
|
const options = {
|
|
get passive() {
|
|
passiveSupported = true;
|
|
return false;
|
|
}
|
|
};
|
|
if (_isDomSupported()) {
|
|
window.addEventListener("test", null, options);
|
|
window.removeEventListener("test", null, options);
|
|
}
|
|
} catch (e2) {
|
|
}
|
|
return passiveSupported;
|
|
}();
|
|
function readUsedSize(element, property) {
|
|
const value = getStyle(element, property);
|
|
const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
|
|
return matches ? +matches[1] : void 0;
|
|
}
|
|
var getRightToLeftAdapter = function(rectX, width) {
|
|
return {
|
|
x(x2) {
|
|
return rectX + rectX + width - x2;
|
|
},
|
|
setWidth(w2) {
|
|
width = w2;
|
|
},
|
|
textAlign(align) {
|
|
if (align === "center") {
|
|
return align;
|
|
}
|
|
return align === "right" ? "left" : "right";
|
|
},
|
|
xPlus(x2, value) {
|
|
return x2 - value;
|
|
},
|
|
leftForLtr(x2, itemWidth) {
|
|
return x2 - itemWidth;
|
|
}
|
|
};
|
|
};
|
|
var getLeftToRightAdapter = function() {
|
|
return {
|
|
x(x2) {
|
|
return x2;
|
|
},
|
|
setWidth(w2) {
|
|
},
|
|
textAlign(align) {
|
|
return align;
|
|
},
|
|
xPlus(x2, value) {
|
|
return x2 + value;
|
|
},
|
|
leftForLtr(x2, _itemWidth) {
|
|
return x2;
|
|
}
|
|
};
|
|
};
|
|
function getRtlAdapter(rtl, rectX, width) {
|
|
return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
|
|
}
|
|
function overrideTextDirection(ctx, direction) {
|
|
let style, original;
|
|
if (direction === "ltr" || direction === "rtl") {
|
|
style = ctx.canvas.style;
|
|
original = [
|
|
style.getPropertyValue("direction"),
|
|
style.getPropertyPriority("direction")
|
|
];
|
|
style.setProperty("direction", direction, "important");
|
|
ctx.prevTextDirection = original;
|
|
}
|
|
}
|
|
function restoreTextDirection(ctx, original) {
|
|
if (original !== void 0) {
|
|
delete ctx.prevTextDirection;
|
|
ctx.canvas.style.setProperty("direction", original[0], original[1]);
|
|
}
|
|
}
|
|
|
|
// node_modules/.pnpm/chart.js@4.4.4/node_modules/chart.js/dist/chart.js
|
|
var Animator = class {
|
|
constructor() {
|
|
this._request = null;
|
|
this._charts = /* @__PURE__ */ new Map();
|
|
this._running = false;
|
|
this._lastDate = void 0;
|
|
}
|
|
_notify(chart, anims, date, type) {
|
|
const callbacks = anims.listeners[type];
|
|
const numSteps = anims.duration;
|
|
callbacks.forEach((fn2) => fn2({
|
|
chart,
|
|
initial: anims.initial,
|
|
numSteps,
|
|
currentStep: Math.min(date - anims.start, numSteps)
|
|
}));
|
|
}
|
|
_refresh() {
|
|
if (this._request) {
|
|
return;
|
|
}
|
|
this._running = true;
|
|
this._request = requestAnimFrame.call(window, () => {
|
|
this._update();
|
|
this._request = null;
|
|
if (this._running) {
|
|
this._refresh();
|
|
}
|
|
});
|
|
}
|
|
_update(date = Date.now()) {
|
|
let remaining = 0;
|
|
this._charts.forEach((anims, chart) => {
|
|
if (!anims.running || !anims.items.length) {
|
|
return;
|
|
}
|
|
const items = anims.items;
|
|
let i2 = items.length - 1;
|
|
let draw = false;
|
|
let item;
|
|
for (; i2 >= 0; --i2) {
|
|
item = items[i2];
|
|
if (item._active) {
|
|
if (item._total > anims.duration) {
|
|
anims.duration = item._total;
|
|
}
|
|
item.tick(date);
|
|
draw = true;
|
|
} else {
|
|
items[i2] = items[items.length - 1];
|
|
items.pop();
|
|
}
|
|
}
|
|
if (draw) {
|
|
chart.draw();
|
|
this._notify(chart, anims, date, "progress");
|
|
}
|
|
if (!items.length) {
|
|
anims.running = false;
|
|
this._notify(chart, anims, date, "complete");
|
|
anims.initial = false;
|
|
}
|
|
remaining += items.length;
|
|
});
|
|
this._lastDate = date;
|
|
if (remaining === 0) {
|
|
this._running = false;
|
|
}
|
|
}
|
|
_getAnims(chart) {
|
|
const charts = this._charts;
|
|
let anims = charts.get(chart);
|
|
if (!anims) {
|
|
anims = {
|
|
running: false,
|
|
initial: true,
|
|
items: [],
|
|
listeners: {
|
|
complete: [],
|
|
progress: []
|
|
}
|
|
};
|
|
charts.set(chart, anims);
|
|
}
|
|
return anims;
|
|
}
|
|
listen(chart, event, cb) {
|
|
this._getAnims(chart).listeners[event].push(cb);
|
|
}
|
|
add(chart, items) {
|
|
if (!items || !items.length) {
|
|
return;
|
|
}
|
|
this._getAnims(chart).items.push(...items);
|
|
}
|
|
has(chart) {
|
|
return this._getAnims(chart).items.length > 0;
|
|
}
|
|
start(chart) {
|
|
const anims = this._charts.get(chart);
|
|
if (!anims) {
|
|
return;
|
|
}
|
|
anims.running = true;
|
|
anims.start = Date.now();
|
|
anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);
|
|
this._refresh();
|
|
}
|
|
running(chart) {
|
|
if (!this._running) {
|
|
return false;
|
|
}
|
|
const anims = this._charts.get(chart);
|
|
if (!anims || !anims.running || !anims.items.length) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
stop(chart) {
|
|
const anims = this._charts.get(chart);
|
|
if (!anims || !anims.items.length) {
|
|
return;
|
|
}
|
|
const items = anims.items;
|
|
let i2 = items.length - 1;
|
|
for (; i2 >= 0; --i2) {
|
|
items[i2].cancel();
|
|
}
|
|
anims.items = [];
|
|
this._notify(chart, anims, Date.now(), "complete");
|
|
}
|
|
remove(chart) {
|
|
return this._charts.delete(chart);
|
|
}
|
|
};
|
|
var animator = /* @__PURE__ */ new Animator();
|
|
var transparent = "transparent";
|
|
var interpolators = {
|
|
boolean(from2, to2, factor) {
|
|
return factor > 0.5 ? to2 : from2;
|
|
},
|
|
color(from2, to2, factor) {
|
|
const c0 = color(from2 || transparent);
|
|
const c1 = c0.valid && color(to2 || transparent);
|
|
return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to2;
|
|
},
|
|
number(from2, to2, factor) {
|
|
return from2 + (to2 - from2) * factor;
|
|
}
|
|
};
|
|
var Animation = class {
|
|
constructor(cfg, target, prop, to2) {
|
|
const currentValue = target[prop];
|
|
to2 = resolve([
|
|
cfg.to,
|
|
to2,
|
|
currentValue,
|
|
cfg.from
|
|
]);
|
|
const from2 = resolve([
|
|
cfg.from,
|
|
currentValue,
|
|
to2
|
|
]);
|
|
this._active = true;
|
|
this._fn = cfg.fn || interpolators[cfg.type || typeof from2];
|
|
this._easing = effects[cfg.easing] || effects.linear;
|
|
this._start = Math.floor(Date.now() + (cfg.delay || 0));
|
|
this._duration = this._total = Math.floor(cfg.duration);
|
|
this._loop = !!cfg.loop;
|
|
this._target = target;
|
|
this._prop = prop;
|
|
this._from = from2;
|
|
this._to = to2;
|
|
this._promises = void 0;
|
|
}
|
|
active() {
|
|
return this._active;
|
|
}
|
|
update(cfg, to2, date) {
|
|
if (this._active) {
|
|
this._notify(false);
|
|
const currentValue = this._target[this._prop];
|
|
const elapsed = date - this._start;
|
|
const remain = this._duration - elapsed;
|
|
this._start = date;
|
|
this._duration = Math.floor(Math.max(remain, cfg.duration));
|
|
this._total += elapsed;
|
|
this._loop = !!cfg.loop;
|
|
this._to = resolve([
|
|
cfg.to,
|
|
to2,
|
|
currentValue,
|
|
cfg.from
|
|
]);
|
|
this._from = resolve([
|
|
cfg.from,
|
|
currentValue,
|
|
to2
|
|
]);
|
|
}
|
|
}
|
|
cancel() {
|
|
if (this._active) {
|
|
this.tick(Date.now());
|
|
this._active = false;
|
|
this._notify(false);
|
|
}
|
|
}
|
|
tick(date) {
|
|
const elapsed = date - this._start;
|
|
const duration = this._duration;
|
|
const prop = this._prop;
|
|
const from2 = this._from;
|
|
const loop = this._loop;
|
|
const to2 = this._to;
|
|
let factor;
|
|
this._active = from2 !== to2 && (loop || elapsed < duration);
|
|
if (!this._active) {
|
|
this._target[prop] = to2;
|
|
this._notify(true);
|
|
return;
|
|
}
|
|
if (elapsed < 0) {
|
|
this._target[prop] = from2;
|
|
return;
|
|
}
|
|
factor = elapsed / duration % 2;
|
|
factor = loop && factor > 1 ? 2 - factor : factor;
|
|
factor = this._easing(Math.min(1, Math.max(0, factor)));
|
|
this._target[prop] = this._fn(from2, to2, factor);
|
|
}
|
|
wait() {
|
|
const promises = this._promises || (this._promises = []);
|
|
return new Promise((res, rej) => {
|
|
promises.push({
|
|
res,
|
|
rej
|
|
});
|
|
});
|
|
}
|
|
_notify(resolved) {
|
|
const method = resolved ? "res" : "rej";
|
|
const promises = this._promises || [];
|
|
for (let i2 = 0; i2 < promises.length; i2++) {
|
|
promises[i2][method]();
|
|
}
|
|
}
|
|
};
|
|
var Animations = class {
|
|
constructor(chart, config) {
|
|
this._chart = chart;
|
|
this._properties = /* @__PURE__ */ new Map();
|
|
this.configure(config);
|
|
}
|
|
configure(config) {
|
|
if (!isObject(config)) {
|
|
return;
|
|
}
|
|
const animationOptions = Object.keys(defaults2.animation);
|
|
const animatedProps = this._properties;
|
|
Object.getOwnPropertyNames(config).forEach((key) => {
|
|
const cfg = config[key];
|
|
if (!isObject(cfg)) {
|
|
return;
|
|
}
|
|
const resolved = {};
|
|
for (const option of animationOptions) {
|
|
resolved[option] = cfg[option];
|
|
}
|
|
(isArray(cfg.properties) && cfg.properties || [
|
|
key
|
|
]).forEach((prop) => {
|
|
if (prop === key || !animatedProps.has(prop)) {
|
|
animatedProps.set(prop, resolved);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
_animateOptions(target, values) {
|
|
const newOptions = values.options;
|
|
const options = resolveTargetOptions(target, newOptions);
|
|
if (!options) {
|
|
return [];
|
|
}
|
|
const animations = this._createAnimations(options, newOptions);
|
|
if (newOptions.$shared) {
|
|
awaitAll(target.options.$animations, newOptions).then(() => {
|
|
target.options = newOptions;
|
|
}, () => {
|
|
});
|
|
}
|
|
return animations;
|
|
}
|
|
_createAnimations(target, values) {
|
|
const animatedProps = this._properties;
|
|
const animations = [];
|
|
const running = target.$animations || (target.$animations = {});
|
|
const props = Object.keys(values);
|
|
const date = Date.now();
|
|
let i2;
|
|
for (i2 = props.length - 1; i2 >= 0; --i2) {
|
|
const prop = props[i2];
|
|
if (prop.charAt(0) === "$") {
|
|
continue;
|
|
}
|
|
if (prop === "options") {
|
|
animations.push(...this._animateOptions(target, values));
|
|
continue;
|
|
}
|
|
const value = values[prop];
|
|
let animation = running[prop];
|
|
const cfg = animatedProps.get(prop);
|
|
if (animation) {
|
|
if (cfg && animation.active()) {
|
|
animation.update(cfg, value, date);
|
|
continue;
|
|
} else {
|
|
animation.cancel();
|
|
}
|
|
}
|
|
if (!cfg || !cfg.duration) {
|
|
target[prop] = value;
|
|
continue;
|
|
}
|
|
running[prop] = animation = new Animation(cfg, target, prop, value);
|
|
animations.push(animation);
|
|
}
|
|
return animations;
|
|
}
|
|
update(target, values) {
|
|
if (this._properties.size === 0) {
|
|
Object.assign(target, values);
|
|
return;
|
|
}
|
|
const animations = this._createAnimations(target, values);
|
|
if (animations.length) {
|
|
animator.add(this._chart, animations);
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
function awaitAll(animations, properties) {
|
|
const running = [];
|
|
const keys = Object.keys(properties);
|
|
for (let i2 = 0; i2 < keys.length; i2++) {
|
|
const anim = animations[keys[i2]];
|
|
if (anim && anim.active()) {
|
|
running.push(anim.wait());
|
|
}
|
|
}
|
|
return Promise.all(running);
|
|
}
|
|
function resolveTargetOptions(target, newOptions) {
|
|
if (!newOptions) {
|
|
return;
|
|
}
|
|
let options = target.options;
|
|
if (!options) {
|
|
target.options = newOptions;
|
|
return;
|
|
}
|
|
if (options.$shared) {
|
|
target.options = options = Object.assign({}, options, {
|
|
$shared: false,
|
|
$animations: {}
|
|
});
|
|
}
|
|
return options;
|
|
}
|
|
function scaleClip(scale, allowedOverflow) {
|
|
const opts = scale && scale.options || {};
|
|
const reverse = opts.reverse;
|
|
const min = opts.min === void 0 ? allowedOverflow : 0;
|
|
const max = opts.max === void 0 ? allowedOverflow : 0;
|
|
return {
|
|
start: reverse ? max : min,
|
|
end: reverse ? min : max
|
|
};
|
|
}
|
|
function defaultClip(xScale, yScale, allowedOverflow) {
|
|
if (allowedOverflow === false) {
|
|
return false;
|
|
}
|
|
const x2 = scaleClip(xScale, allowedOverflow);
|
|
const y2 = scaleClip(yScale, allowedOverflow);
|
|
return {
|
|
top: y2.end,
|
|
right: x2.end,
|
|
bottom: y2.start,
|
|
left: x2.start
|
|
};
|
|
}
|
|
function toClip(value) {
|
|
let t3, r2, b2, l2;
|
|
if (isObject(value)) {
|
|
t3 = value.top;
|
|
r2 = value.right;
|
|
b2 = value.bottom;
|
|
l2 = value.left;
|
|
} else {
|
|
t3 = r2 = b2 = l2 = value;
|
|
}
|
|
return {
|
|
top: t3,
|
|
right: r2,
|
|
bottom: b2,
|
|
left: l2,
|
|
disabled: value === false
|
|
};
|
|
}
|
|
function getSortedDatasetIndices(chart, filterVisible) {
|
|
const keys = [];
|
|
const metasets = chart._getSortedDatasetMetas(filterVisible);
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = metasets.length; i2 < ilen; ++i2) {
|
|
keys.push(metasets[i2].index);
|
|
}
|
|
return keys;
|
|
}
|
|
function applyStack(stack, value, dsIndex, options = {}) {
|
|
const keys = stack.keys;
|
|
const singleMode = options.mode === "single";
|
|
let i2, ilen, datasetIndex, otherValue;
|
|
if (value === null) {
|
|
return;
|
|
}
|
|
for (i2 = 0, ilen = keys.length; i2 < ilen; ++i2) {
|
|
datasetIndex = +keys[i2];
|
|
if (datasetIndex === dsIndex) {
|
|
if (options.all) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
otherValue = stack.values[datasetIndex];
|
|
if (isNumberFinite(otherValue) && (singleMode || value === 0 || sign(value) === sign(otherValue))) {
|
|
value += otherValue;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function convertObjectDataToArray(data, meta) {
|
|
const { iScale, vScale } = meta;
|
|
const iAxisKey = iScale.axis === "x" ? "x" : "y";
|
|
const vAxisKey = vScale.axis === "x" ? "x" : "y";
|
|
const keys = Object.keys(data);
|
|
const adata = new Array(keys.length);
|
|
let i2, ilen, key;
|
|
for (i2 = 0, ilen = keys.length; i2 < ilen; ++i2) {
|
|
key = keys[i2];
|
|
adata[i2] = {
|
|
[iAxisKey]: key,
|
|
[vAxisKey]: data[key]
|
|
};
|
|
}
|
|
return adata;
|
|
}
|
|
function isStacked(scale, meta) {
|
|
const stacked = scale && scale.options.stacked;
|
|
return stacked || stacked === void 0 && meta.stack !== void 0;
|
|
}
|
|
function getStackKey(indexScale, valueScale, meta) {
|
|
return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
|
|
}
|
|
function getUserBounds(scale) {
|
|
const { min, max, minDefined, maxDefined } = scale.getUserBounds();
|
|
return {
|
|
min: minDefined ? min : Number.NEGATIVE_INFINITY,
|
|
max: maxDefined ? max : Number.POSITIVE_INFINITY
|
|
};
|
|
}
|
|
function getOrCreateStack(stacks, stackKey, indexValue) {
|
|
const subStack = stacks[stackKey] || (stacks[stackKey] = {});
|
|
return subStack[indexValue] || (subStack[indexValue] = {});
|
|
}
|
|
function getLastIndexInStack(stack, vScale, positive, type) {
|
|
for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) {
|
|
const value = stack[meta.index];
|
|
if (positive && value > 0 || !positive && value < 0) {
|
|
return meta.index;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function updateStacks(controller, parsed) {
|
|
const { chart, _cachedMeta: meta } = controller;
|
|
const stacks = chart._stacks || (chart._stacks = {});
|
|
const { iScale, vScale, index: datasetIndex } = meta;
|
|
const iAxis = iScale.axis;
|
|
const vAxis = vScale.axis;
|
|
const key = getStackKey(iScale, vScale, meta);
|
|
const ilen = parsed.length;
|
|
let stack;
|
|
for (let i2 = 0; i2 < ilen; ++i2) {
|
|
const item = parsed[i2];
|
|
const { [iAxis]: index, [vAxis]: value } = item;
|
|
const itemStacks = item._stacks || (item._stacks = {});
|
|
stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
|
|
stack[datasetIndex] = value;
|
|
stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
|
|
stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
|
|
const visualValues = stack._visualValues || (stack._visualValues = {});
|
|
visualValues[datasetIndex] = value;
|
|
}
|
|
}
|
|
function getFirstScaleId(chart, axis) {
|
|
const scales = chart.scales;
|
|
return Object.keys(scales).filter((key) => scales[key].axis === axis).shift();
|
|
}
|
|
function createDatasetContext(parent, index) {
|
|
return createContext(parent, {
|
|
active: false,
|
|
dataset: void 0,
|
|
datasetIndex: index,
|
|
index,
|
|
mode: "default",
|
|
type: "dataset"
|
|
});
|
|
}
|
|
function createDataContext(parent, index, element) {
|
|
return createContext(parent, {
|
|
active: false,
|
|
dataIndex: index,
|
|
parsed: void 0,
|
|
raw: void 0,
|
|
element,
|
|
index,
|
|
mode: "default",
|
|
type: "data"
|
|
});
|
|
}
|
|
function clearStacks(meta, items) {
|
|
const datasetIndex = meta.controller.index;
|
|
const axis = meta.vScale && meta.vScale.axis;
|
|
if (!axis) {
|
|
return;
|
|
}
|
|
items = items || meta._parsed;
|
|
for (const parsed of items) {
|
|
const stacks = parsed._stacks;
|
|
if (!stacks || stacks[axis] === void 0 || stacks[axis][datasetIndex] === void 0) {
|
|
return;
|
|
}
|
|
delete stacks[axis][datasetIndex];
|
|
if (stacks[axis]._visualValues !== void 0 && stacks[axis]._visualValues[datasetIndex] !== void 0) {
|
|
delete stacks[axis]._visualValues[datasetIndex];
|
|
}
|
|
}
|
|
}
|
|
var isDirectUpdateMode = (mode) => mode === "reset" || mode === "none";
|
|
var cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached);
|
|
var createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked && {
|
|
keys: getSortedDatasetIndices(chart, true),
|
|
values: null
|
|
};
|
|
var DatasetController = class {
|
|
constructor(chart, datasetIndex) {
|
|
this.chart = chart;
|
|
this._ctx = chart.ctx;
|
|
this.index = datasetIndex;
|
|
this._cachedDataOpts = {};
|
|
this._cachedMeta = this.getMeta();
|
|
this._type = this._cachedMeta.type;
|
|
this.options = void 0;
|
|
this._parsing = false;
|
|
this._data = void 0;
|
|
this._objectData = void 0;
|
|
this._sharedOptions = void 0;
|
|
this._drawStart = void 0;
|
|
this._drawCount = void 0;
|
|
this.enableOptionSharing = false;
|
|
this.supportsDecimation = false;
|
|
this.$context = void 0;
|
|
this._syncList = [];
|
|
this.datasetElementType = new.target.datasetElementType;
|
|
this.dataElementType = new.target.dataElementType;
|
|
this.initialize();
|
|
}
|
|
initialize() {
|
|
const meta = this._cachedMeta;
|
|
this.configure();
|
|
this.linkScales();
|
|
meta._stacked = isStacked(meta.vScale, meta);
|
|
this.addElements();
|
|
if (this.options.fill && !this.chart.isPluginEnabled("filler")) {
|
|
console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options");
|
|
}
|
|
}
|
|
updateIndex(datasetIndex) {
|
|
if (this.index !== datasetIndex) {
|
|
clearStacks(this._cachedMeta);
|
|
}
|
|
this.index = datasetIndex;
|
|
}
|
|
linkScales() {
|
|
const chart = this.chart;
|
|
const meta = this._cachedMeta;
|
|
const dataset = this.getDataset();
|
|
const chooseId = (axis, x2, y2, r2) => axis === "x" ? x2 : axis === "r" ? r2 : y2;
|
|
const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, "x"));
|
|
const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, "y"));
|
|
const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, "r"));
|
|
const indexAxis = meta.indexAxis;
|
|
const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
|
|
const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
|
|
meta.xScale = this.getScaleForId(xid);
|
|
meta.yScale = this.getScaleForId(yid);
|
|
meta.rScale = this.getScaleForId(rid);
|
|
meta.iScale = this.getScaleForId(iid);
|
|
meta.vScale = this.getScaleForId(vid);
|
|
}
|
|
getDataset() {
|
|
return this.chart.data.datasets[this.index];
|
|
}
|
|
getMeta() {
|
|
return this.chart.getDatasetMeta(this.index);
|
|
}
|
|
getScaleForId(scaleID) {
|
|
return this.chart.scales[scaleID];
|
|
}
|
|
_getOtherScale(scale) {
|
|
const meta = this._cachedMeta;
|
|
return scale === meta.iScale ? meta.vScale : meta.iScale;
|
|
}
|
|
reset() {
|
|
this._update("reset");
|
|
}
|
|
_destroy() {
|
|
const meta = this._cachedMeta;
|
|
if (this._data) {
|
|
unlistenArrayEvents(this._data, this);
|
|
}
|
|
if (meta._stacked) {
|
|
clearStacks(meta);
|
|
}
|
|
}
|
|
_dataCheck() {
|
|
const dataset = this.getDataset();
|
|
const data = dataset.data || (dataset.data = []);
|
|
const _data = this._data;
|
|
if (isObject(data)) {
|
|
const meta = this._cachedMeta;
|
|
this._data = convertObjectDataToArray(data, meta);
|
|
} else if (_data !== data) {
|
|
if (_data) {
|
|
unlistenArrayEvents(_data, this);
|
|
const meta = this._cachedMeta;
|
|
clearStacks(meta);
|
|
meta._parsed = [];
|
|
}
|
|
if (data && Object.isExtensible(data)) {
|
|
listenArrayEvents(data, this);
|
|
}
|
|
this._syncList = [];
|
|
this._data = data;
|
|
}
|
|
}
|
|
addElements() {
|
|
const meta = this._cachedMeta;
|
|
this._dataCheck();
|
|
if (this.datasetElementType) {
|
|
meta.dataset = new this.datasetElementType();
|
|
}
|
|
}
|
|
buildOrUpdateElements(resetNewElements) {
|
|
const meta = this._cachedMeta;
|
|
const dataset = this.getDataset();
|
|
let stackChanged = false;
|
|
this._dataCheck();
|
|
const oldStacked = meta._stacked;
|
|
meta._stacked = isStacked(meta.vScale, meta);
|
|
if (meta.stack !== dataset.stack) {
|
|
stackChanged = true;
|
|
clearStacks(meta);
|
|
meta.stack = dataset.stack;
|
|
}
|
|
this._resyncElements(resetNewElements);
|
|
if (stackChanged || oldStacked !== meta._stacked) {
|
|
updateStacks(this, meta._parsed);
|
|
}
|
|
}
|
|
configure() {
|
|
const config = this.chart.config;
|
|
const scopeKeys = config.datasetScopeKeys(this._type);
|
|
const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
|
|
this.options = config.createResolver(scopes, this.getContext());
|
|
this._parsing = this.options.parsing;
|
|
this._cachedDataOpts = {};
|
|
}
|
|
parse(start, count) {
|
|
const { _cachedMeta: meta, _data: data } = this;
|
|
const { iScale, _stacked } = meta;
|
|
const iAxis = iScale.axis;
|
|
let sorted = start === 0 && count === data.length ? true : meta._sorted;
|
|
let prev = start > 0 && meta._parsed[start - 1];
|
|
let i2, cur, parsed;
|
|
if (this._parsing === false) {
|
|
meta._parsed = data;
|
|
meta._sorted = true;
|
|
parsed = data;
|
|
} else {
|
|
if (isArray(data[start])) {
|
|
parsed = this.parseArrayData(meta, data, start, count);
|
|
} else if (isObject(data[start])) {
|
|
parsed = this.parseObjectData(meta, data, start, count);
|
|
} else {
|
|
parsed = this.parsePrimitiveData(meta, data, start, count);
|
|
}
|
|
const isNotInOrderComparedToPrev = () => cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];
|
|
for (i2 = 0; i2 < count; ++i2) {
|
|
meta._parsed[i2 + start] = cur = parsed[i2];
|
|
if (sorted) {
|
|
if (isNotInOrderComparedToPrev()) {
|
|
sorted = false;
|
|
}
|
|
prev = cur;
|
|
}
|
|
}
|
|
meta._sorted = sorted;
|
|
}
|
|
if (_stacked) {
|
|
updateStacks(this, parsed);
|
|
}
|
|
}
|
|
parsePrimitiveData(meta, data, start, count) {
|
|
const { iScale, vScale } = meta;
|
|
const iAxis = iScale.axis;
|
|
const vAxis = vScale.axis;
|
|
const labels = iScale.getLabels();
|
|
const singleScale = iScale === vScale;
|
|
const parsed = new Array(count);
|
|
let i2, ilen, index;
|
|
for (i2 = 0, ilen = count; i2 < ilen; ++i2) {
|
|
index = i2 + start;
|
|
parsed[i2] = {
|
|
[iAxis]: singleScale || iScale.parse(labels[index], index),
|
|
[vAxis]: vScale.parse(data[index], index)
|
|
};
|
|
}
|
|
return parsed;
|
|
}
|
|
parseArrayData(meta, data, start, count) {
|
|
const { xScale, yScale } = meta;
|
|
const parsed = new Array(count);
|
|
let i2, ilen, index, item;
|
|
for (i2 = 0, ilen = count; i2 < ilen; ++i2) {
|
|
index = i2 + start;
|
|
item = data[index];
|
|
parsed[i2] = {
|
|
x: xScale.parse(item[0], index),
|
|
y: yScale.parse(item[1], index)
|
|
};
|
|
}
|
|
return parsed;
|
|
}
|
|
parseObjectData(meta, data, start, count) {
|
|
const { xScale, yScale } = meta;
|
|
const { xAxisKey = "x", yAxisKey = "y" } = this._parsing;
|
|
const parsed = new Array(count);
|
|
let i2, ilen, index, item;
|
|
for (i2 = 0, ilen = count; i2 < ilen; ++i2) {
|
|
index = i2 + start;
|
|
item = data[index];
|
|
parsed[i2] = {
|
|
x: xScale.parse(resolveObjectKey(item, xAxisKey), index),
|
|
y: yScale.parse(resolveObjectKey(item, yAxisKey), index)
|
|
};
|
|
}
|
|
return parsed;
|
|
}
|
|
getParsed(index) {
|
|
return this._cachedMeta._parsed[index];
|
|
}
|
|
getDataElement(index) {
|
|
return this._cachedMeta.data[index];
|
|
}
|
|
applyStack(scale, parsed, mode) {
|
|
const chart = this.chart;
|
|
const meta = this._cachedMeta;
|
|
const value = parsed[scale.axis];
|
|
const stack = {
|
|
keys: getSortedDatasetIndices(chart, true),
|
|
values: parsed._stacks[scale.axis]._visualValues
|
|
};
|
|
return applyStack(stack, value, meta.index, {
|
|
mode
|
|
});
|
|
}
|
|
updateRangeFromParsed(range, scale, parsed, stack) {
|
|
const parsedValue = parsed[scale.axis];
|
|
let value = parsedValue === null ? NaN : parsedValue;
|
|
const values = stack && parsed._stacks[scale.axis];
|
|
if (stack && values) {
|
|
stack.values = values;
|
|
value = applyStack(stack, parsedValue, this._cachedMeta.index);
|
|
}
|
|
range.min = Math.min(range.min, value);
|
|
range.max = Math.max(range.max, value);
|
|
}
|
|
getMinMax(scale, canStack) {
|
|
const meta = this._cachedMeta;
|
|
const _parsed = meta._parsed;
|
|
const sorted = meta._sorted && scale === meta.iScale;
|
|
const ilen = _parsed.length;
|
|
const otherScale = this._getOtherScale(scale);
|
|
const stack = createStack(canStack, meta, this.chart);
|
|
const range = {
|
|
min: Number.POSITIVE_INFINITY,
|
|
max: Number.NEGATIVE_INFINITY
|
|
};
|
|
const { min: otherMin, max: otherMax } = getUserBounds(otherScale);
|
|
let i2, parsed;
|
|
function _skip() {
|
|
parsed = _parsed[i2];
|
|
const otherValue = parsed[otherScale.axis];
|
|
return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
|
|
}
|
|
for (i2 = 0; i2 < ilen; ++i2) {
|
|
if (_skip()) {
|
|
continue;
|
|
}
|
|
this.updateRangeFromParsed(range, scale, parsed, stack);
|
|
if (sorted) {
|
|
break;
|
|
}
|
|
}
|
|
if (sorted) {
|
|
for (i2 = ilen - 1; i2 >= 0; --i2) {
|
|
if (_skip()) {
|
|
continue;
|
|
}
|
|
this.updateRangeFromParsed(range, scale, parsed, stack);
|
|
break;
|
|
}
|
|
}
|
|
return range;
|
|
}
|
|
getAllParsedValues(scale) {
|
|
const parsed = this._cachedMeta._parsed;
|
|
const values = [];
|
|
let i2, ilen, value;
|
|
for (i2 = 0, ilen = parsed.length; i2 < ilen; ++i2) {
|
|
value = parsed[i2][scale.axis];
|
|
if (isNumberFinite(value)) {
|
|
values.push(value);
|
|
}
|
|
}
|
|
return values;
|
|
}
|
|
getMaxOverflow() {
|
|
return false;
|
|
}
|
|
getLabelAndValue(index) {
|
|
const meta = this._cachedMeta;
|
|
const iScale = meta.iScale;
|
|
const vScale = meta.vScale;
|
|
const parsed = this.getParsed(index);
|
|
return {
|
|
label: iScale ? "" + iScale.getLabelForValue(parsed[iScale.axis]) : "",
|
|
value: vScale ? "" + vScale.getLabelForValue(parsed[vScale.axis]) : ""
|
|
};
|
|
}
|
|
_update(mode) {
|
|
const meta = this._cachedMeta;
|
|
this.update(mode || "default");
|
|
meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
|
|
}
|
|
update(mode) {
|
|
}
|
|
draw() {
|
|
const ctx = this._ctx;
|
|
const chart = this.chart;
|
|
const meta = this._cachedMeta;
|
|
const elements = meta.data || [];
|
|
const area = chart.chartArea;
|
|
const active = [];
|
|
const start = this._drawStart || 0;
|
|
const count = this._drawCount || elements.length - start;
|
|
const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
|
|
let i2;
|
|
if (meta.dataset) {
|
|
meta.dataset.draw(ctx, area, start, count);
|
|
}
|
|
for (i2 = start; i2 < start + count; ++i2) {
|
|
const element = elements[i2];
|
|
if (element.hidden) {
|
|
continue;
|
|
}
|
|
if (element.active && drawActiveElementsOnTop) {
|
|
active.push(element);
|
|
} else {
|
|
element.draw(ctx, area);
|
|
}
|
|
}
|
|
for (i2 = 0; i2 < active.length; ++i2) {
|
|
active[i2].draw(ctx, area);
|
|
}
|
|
}
|
|
getStyle(index, active) {
|
|
const mode = active ? "active" : "default";
|
|
return index === void 0 && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);
|
|
}
|
|
getContext(index, active, mode) {
|
|
const dataset = this.getDataset();
|
|
let context;
|
|
if (index >= 0 && index < this._cachedMeta.data.length) {
|
|
const element = this._cachedMeta.data[index];
|
|
context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));
|
|
context.parsed = this.getParsed(index);
|
|
context.raw = dataset.data[index];
|
|
context.index = context.dataIndex = index;
|
|
} else {
|
|
context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));
|
|
context.dataset = dataset;
|
|
context.index = context.datasetIndex = this.index;
|
|
}
|
|
context.active = !!active;
|
|
context.mode = mode;
|
|
return context;
|
|
}
|
|
resolveDatasetElementOptions(mode) {
|
|
return this._resolveElementOptions(this.datasetElementType.id, mode);
|
|
}
|
|
resolveDataElementOptions(index, mode) {
|
|
return this._resolveElementOptions(this.dataElementType.id, mode, index);
|
|
}
|
|
_resolveElementOptions(elementType, mode = "default", index) {
|
|
const active = mode === "active";
|
|
const cache = this._cachedDataOpts;
|
|
const cacheKey = elementType + "-" + mode;
|
|
const cached = cache[cacheKey];
|
|
const sharing = this.enableOptionSharing && defined(index);
|
|
if (cached) {
|
|
return cloneIfNotShared(cached, sharing);
|
|
}
|
|
const config = this.chart.config;
|
|
const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
|
|
const prefixes = active ? [
|
|
`${elementType}Hover`,
|
|
"hover",
|
|
elementType,
|
|
""
|
|
] : [
|
|
elementType,
|
|
""
|
|
];
|
|
const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
|
|
const names2 = Object.keys(defaults2.elements[elementType]);
|
|
const context = () => this.getContext(index, active, mode);
|
|
const values = config.resolveNamedOptions(scopes, names2, context, prefixes);
|
|
if (values.$shared) {
|
|
values.$shared = sharing;
|
|
cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
|
|
}
|
|
return values;
|
|
}
|
|
_resolveAnimations(index, transition, active) {
|
|
const chart = this.chart;
|
|
const cache = this._cachedDataOpts;
|
|
const cacheKey = `animation-${transition}`;
|
|
const cached = cache[cacheKey];
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
let options;
|
|
if (chart.options.animation !== false) {
|
|
const config = this.chart.config;
|
|
const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
|
|
const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
|
|
options = config.createResolver(scopes, this.getContext(index, active, transition));
|
|
}
|
|
const animations = new Animations(chart, options && options.animations);
|
|
if (options && options._cacheable) {
|
|
cache[cacheKey] = Object.freeze(animations);
|
|
}
|
|
return animations;
|
|
}
|
|
getSharedOptions(options) {
|
|
if (!options.$shared) {
|
|
return;
|
|
}
|
|
return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
|
|
}
|
|
includeOptions(mode, sharedOptions) {
|
|
return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
|
|
}
|
|
_getSharedOptions(start, mode) {
|
|
const firstOpts = this.resolveDataElementOptions(start, mode);
|
|
const previouslySharedOptions = this._sharedOptions;
|
|
const sharedOptions = this.getSharedOptions(firstOpts);
|
|
const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;
|
|
this.updateSharedOptions(sharedOptions, mode, firstOpts);
|
|
return {
|
|
sharedOptions,
|
|
includeOptions
|
|
};
|
|
}
|
|
updateElement(element, index, properties, mode) {
|
|
if (isDirectUpdateMode(mode)) {
|
|
Object.assign(element, properties);
|
|
} else {
|
|
this._resolveAnimations(index, mode).update(element, properties);
|
|
}
|
|
}
|
|
updateSharedOptions(sharedOptions, mode, newOptions) {
|
|
if (sharedOptions && !isDirectUpdateMode(mode)) {
|
|
this._resolveAnimations(void 0, mode).update(sharedOptions, newOptions);
|
|
}
|
|
}
|
|
_setStyle(element, index, mode, active) {
|
|
element.active = active;
|
|
const options = this.getStyle(index, active);
|
|
this._resolveAnimations(index, mode, active).update(element, {
|
|
options: !active && this.getSharedOptions(options) || options
|
|
});
|
|
}
|
|
removeHoverStyle(element, datasetIndex, index) {
|
|
this._setStyle(element, index, "active", false);
|
|
}
|
|
setHoverStyle(element, datasetIndex, index) {
|
|
this._setStyle(element, index, "active", true);
|
|
}
|
|
_removeDatasetHoverStyle() {
|
|
const element = this._cachedMeta.dataset;
|
|
if (element) {
|
|
this._setStyle(element, void 0, "active", false);
|
|
}
|
|
}
|
|
_setDatasetHoverStyle() {
|
|
const element = this._cachedMeta.dataset;
|
|
if (element) {
|
|
this._setStyle(element, void 0, "active", true);
|
|
}
|
|
}
|
|
_resyncElements(resetNewElements) {
|
|
const data = this._data;
|
|
const elements = this._cachedMeta.data;
|
|
for (const [method, arg1, arg2] of this._syncList) {
|
|
this[method](arg1, arg2);
|
|
}
|
|
this._syncList = [];
|
|
const numMeta = elements.length;
|
|
const numData = data.length;
|
|
const count = Math.min(numData, numMeta);
|
|
if (count) {
|
|
this.parse(0, count);
|
|
}
|
|
if (numData > numMeta) {
|
|
this._insertElements(numMeta, numData - numMeta, resetNewElements);
|
|
} else if (numData < numMeta) {
|
|
this._removeElements(numData, numMeta - numData);
|
|
}
|
|
}
|
|
_insertElements(start, count, resetNewElements = true) {
|
|
const meta = this._cachedMeta;
|
|
const data = meta.data;
|
|
const end = start + count;
|
|
let i2;
|
|
const move = (arr) => {
|
|
arr.length += count;
|
|
for (i2 = arr.length - 1; i2 >= end; i2--) {
|
|
arr[i2] = arr[i2 - count];
|
|
}
|
|
};
|
|
move(data);
|
|
for (i2 = start; i2 < end; ++i2) {
|
|
data[i2] = new this.dataElementType();
|
|
}
|
|
if (this._parsing) {
|
|
move(meta._parsed);
|
|
}
|
|
this.parse(start, count);
|
|
if (resetNewElements) {
|
|
this.updateElements(data, start, count, "reset");
|
|
}
|
|
}
|
|
updateElements(element, start, count, mode) {
|
|
}
|
|
_removeElements(start, count) {
|
|
const meta = this._cachedMeta;
|
|
if (this._parsing) {
|
|
const removed = meta._parsed.splice(start, count);
|
|
if (meta._stacked) {
|
|
clearStacks(meta, removed);
|
|
}
|
|
}
|
|
meta.data.splice(start, count);
|
|
}
|
|
_sync(args) {
|
|
if (this._parsing) {
|
|
this._syncList.push(args);
|
|
} else {
|
|
const [method, arg1, arg2] = args;
|
|
this[method](arg1, arg2);
|
|
}
|
|
this.chart._dataChanges.push([
|
|
this.index,
|
|
...args
|
|
]);
|
|
}
|
|
_onDataPush() {
|
|
const count = arguments.length;
|
|
this._sync([
|
|
"_insertElements",
|
|
this.getDataset().data.length - count,
|
|
count
|
|
]);
|
|
}
|
|
_onDataPop() {
|
|
this._sync([
|
|
"_removeElements",
|
|
this._cachedMeta.data.length - 1,
|
|
1
|
|
]);
|
|
}
|
|
_onDataShift() {
|
|
this._sync([
|
|
"_removeElements",
|
|
0,
|
|
1
|
|
]);
|
|
}
|
|
_onDataSplice(start, count) {
|
|
if (count) {
|
|
this._sync([
|
|
"_removeElements",
|
|
start,
|
|
count
|
|
]);
|
|
}
|
|
const newCount = arguments.length - 2;
|
|
if (newCount) {
|
|
this._sync([
|
|
"_insertElements",
|
|
start,
|
|
newCount
|
|
]);
|
|
}
|
|
}
|
|
_onDataUnshift() {
|
|
this._sync([
|
|
"_insertElements",
|
|
0,
|
|
arguments.length
|
|
]);
|
|
}
|
|
};
|
|
__publicField(DatasetController, "defaults", {});
|
|
__publicField(DatasetController, "datasetElementType", null);
|
|
__publicField(DatasetController, "dataElementType", null);
|
|
function getAllScaleValues(scale, type) {
|
|
if (!scale._cache.$bar) {
|
|
const visibleMetas = scale.getMatchingVisibleMetas(type);
|
|
let values = [];
|
|
for (let i2 = 0, ilen = visibleMetas.length; i2 < ilen; i2++) {
|
|
values = values.concat(visibleMetas[i2].controller.getAllParsedValues(scale));
|
|
}
|
|
scale._cache.$bar = _arrayUnique(values.sort((a2, b2) => a2 - b2));
|
|
}
|
|
return scale._cache.$bar;
|
|
}
|
|
function computeMinSampleSize(meta) {
|
|
const scale = meta.iScale;
|
|
const values = getAllScaleValues(scale, meta.type);
|
|
let min = scale._length;
|
|
let i2, ilen, curr, prev;
|
|
const updateMinAndPrev = () => {
|
|
if (curr === 32767 || curr === -32768) {
|
|
return;
|
|
}
|
|
if (defined(prev)) {
|
|
min = Math.min(min, Math.abs(curr - prev) || min);
|
|
}
|
|
prev = curr;
|
|
};
|
|
for (i2 = 0, ilen = values.length; i2 < ilen; ++i2) {
|
|
curr = scale.getPixelForValue(values[i2]);
|
|
updateMinAndPrev();
|
|
}
|
|
prev = void 0;
|
|
for (i2 = 0, ilen = scale.ticks.length; i2 < ilen; ++i2) {
|
|
curr = scale.getPixelForTick(i2);
|
|
updateMinAndPrev();
|
|
}
|
|
return min;
|
|
}
|
|
function computeFitCategoryTraits(index, ruler, options, stackCount) {
|
|
const thickness = options.barThickness;
|
|
let size, ratio;
|
|
if (isNullOrUndef(thickness)) {
|
|
size = ruler.min * options.categoryPercentage;
|
|
ratio = options.barPercentage;
|
|
} else {
|
|
size = thickness * stackCount;
|
|
ratio = 1;
|
|
}
|
|
return {
|
|
chunk: size / stackCount,
|
|
ratio,
|
|
start: ruler.pixels[index] - size / 2
|
|
};
|
|
}
|
|
function computeFlexCategoryTraits(index, ruler, options, stackCount) {
|
|
const pixels = ruler.pixels;
|
|
const curr = pixels[index];
|
|
let prev = index > 0 ? pixels[index - 1] : null;
|
|
let next = index < pixels.length - 1 ? pixels[index + 1] : null;
|
|
const percent = options.categoryPercentage;
|
|
if (prev === null) {
|
|
prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
|
|
}
|
|
if (next === null) {
|
|
next = curr + curr - prev;
|
|
}
|
|
const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
|
|
const size = Math.abs(next - prev) / 2 * percent;
|
|
return {
|
|
chunk: size / stackCount,
|
|
ratio: options.barPercentage,
|
|
start
|
|
};
|
|
}
|
|
function parseFloatBar(entry, item, vScale, i2) {
|
|
const startValue = vScale.parse(entry[0], i2);
|
|
const endValue = vScale.parse(entry[1], i2);
|
|
const min = Math.min(startValue, endValue);
|
|
const max = Math.max(startValue, endValue);
|
|
let barStart = min;
|
|
let barEnd = max;
|
|
if (Math.abs(min) > Math.abs(max)) {
|
|
barStart = max;
|
|
barEnd = min;
|
|
}
|
|
item[vScale.axis] = barEnd;
|
|
item._custom = {
|
|
barStart,
|
|
barEnd,
|
|
start: startValue,
|
|
end: endValue,
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
function parseValue(entry, item, vScale, i2) {
|
|
if (isArray(entry)) {
|
|
parseFloatBar(entry, item, vScale, i2);
|
|
} else {
|
|
item[vScale.axis] = vScale.parse(entry, i2);
|
|
}
|
|
return item;
|
|
}
|
|
function parseArrayOrPrimitive(meta, data, start, count) {
|
|
const iScale = meta.iScale;
|
|
const vScale = meta.vScale;
|
|
const labels = iScale.getLabels();
|
|
const singleScale = iScale === vScale;
|
|
const parsed = [];
|
|
let i2, ilen, item, entry;
|
|
for (i2 = start, ilen = start + count; i2 < ilen; ++i2) {
|
|
entry = data[i2];
|
|
item = {};
|
|
item[iScale.axis] = singleScale || iScale.parse(labels[i2], i2);
|
|
parsed.push(parseValue(entry, item, vScale, i2));
|
|
}
|
|
return parsed;
|
|
}
|
|
function isFloatBar(custom) {
|
|
return custom && custom.barStart !== void 0 && custom.barEnd !== void 0;
|
|
}
|
|
function barSign(size, vScale, actualBase) {
|
|
if (size !== 0) {
|
|
return sign(size);
|
|
}
|
|
return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
|
|
}
|
|
function borderProps(properties) {
|
|
let reverse, start, end, top, bottom;
|
|
if (properties.horizontal) {
|
|
reverse = properties.base > properties.x;
|
|
start = "left";
|
|
end = "right";
|
|
} else {
|
|
reverse = properties.base < properties.y;
|
|
start = "bottom";
|
|
end = "top";
|
|
}
|
|
if (reverse) {
|
|
top = "end";
|
|
bottom = "start";
|
|
} else {
|
|
top = "start";
|
|
bottom = "end";
|
|
}
|
|
return {
|
|
start,
|
|
end,
|
|
reverse,
|
|
top,
|
|
bottom
|
|
};
|
|
}
|
|
function setBorderSkipped(properties, options, stack, index) {
|
|
let edge = options.borderSkipped;
|
|
const res = {};
|
|
if (!edge) {
|
|
properties.borderSkipped = res;
|
|
return;
|
|
}
|
|
if (edge === true) {
|
|
properties.borderSkipped = {
|
|
top: true,
|
|
right: true,
|
|
bottom: true,
|
|
left: true
|
|
};
|
|
return;
|
|
}
|
|
const { start, end, reverse, top, bottom } = borderProps(properties);
|
|
if (edge === "middle" && stack) {
|
|
properties.enableBorderRadius = true;
|
|
if ((stack._top || 0) === index) {
|
|
edge = top;
|
|
} else if ((stack._bottom || 0) === index) {
|
|
edge = bottom;
|
|
} else {
|
|
res[parseEdge(bottom, start, end, reverse)] = true;
|
|
edge = top;
|
|
}
|
|
}
|
|
res[parseEdge(edge, start, end, reverse)] = true;
|
|
properties.borderSkipped = res;
|
|
}
|
|
function parseEdge(edge, a2, b2, reverse) {
|
|
if (reverse) {
|
|
edge = swap(edge, a2, b2);
|
|
edge = startEnd(edge, b2, a2);
|
|
} else {
|
|
edge = startEnd(edge, a2, b2);
|
|
}
|
|
return edge;
|
|
}
|
|
function swap(orig, v1, v2) {
|
|
return orig === v1 ? v2 : orig === v2 ? v1 : orig;
|
|
}
|
|
function startEnd(v2, start, end) {
|
|
return v2 === "start" ? start : v2 === "end" ? end : v2;
|
|
}
|
|
function setInflateAmount(properties, { inflateAmount }, ratio) {
|
|
properties.inflateAmount = inflateAmount === "auto" ? ratio === 1 ? 0.33 : 0 : inflateAmount;
|
|
}
|
|
var BarController = class extends DatasetController {
|
|
parsePrimitiveData(meta, data, start, count) {
|
|
return parseArrayOrPrimitive(meta, data, start, count);
|
|
}
|
|
parseArrayData(meta, data, start, count) {
|
|
return parseArrayOrPrimitive(meta, data, start, count);
|
|
}
|
|
parseObjectData(meta, data, start, count) {
|
|
const { iScale, vScale } = meta;
|
|
const { xAxisKey = "x", yAxisKey = "y" } = this._parsing;
|
|
const iAxisKey = iScale.axis === "x" ? xAxisKey : yAxisKey;
|
|
const vAxisKey = vScale.axis === "x" ? xAxisKey : yAxisKey;
|
|
const parsed = [];
|
|
let i2, ilen, item, obj;
|
|
for (i2 = start, ilen = start + count; i2 < ilen; ++i2) {
|
|
obj = data[i2];
|
|
item = {};
|
|
item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i2);
|
|
parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i2));
|
|
}
|
|
return parsed;
|
|
}
|
|
updateRangeFromParsed(range, scale, parsed, stack) {
|
|
super.updateRangeFromParsed(range, scale, parsed, stack);
|
|
const custom = parsed._custom;
|
|
if (custom && scale === this._cachedMeta.vScale) {
|
|
range.min = Math.min(range.min, custom.min);
|
|
range.max = Math.max(range.max, custom.max);
|
|
}
|
|
}
|
|
getMaxOverflow() {
|
|
return 0;
|
|
}
|
|
getLabelAndValue(index) {
|
|
const meta = this._cachedMeta;
|
|
const { iScale, vScale } = meta;
|
|
const parsed = this.getParsed(index);
|
|
const custom = parsed._custom;
|
|
const value = isFloatBar(custom) ? "[" + custom.start + ", " + custom.end + "]" : "" + vScale.getLabelForValue(parsed[vScale.axis]);
|
|
return {
|
|
label: "" + iScale.getLabelForValue(parsed[iScale.axis]),
|
|
value
|
|
};
|
|
}
|
|
initialize() {
|
|
this.enableOptionSharing = true;
|
|
super.initialize();
|
|
const meta = this._cachedMeta;
|
|
meta.stack = this.getDataset().stack;
|
|
}
|
|
update(mode) {
|
|
const meta = this._cachedMeta;
|
|
this.updateElements(meta.data, 0, meta.data.length, mode);
|
|
}
|
|
updateElements(bars, start, count, mode) {
|
|
const reset2 = mode === "reset";
|
|
const { index, _cachedMeta: { vScale } } = this;
|
|
const base = vScale.getBasePixel();
|
|
const horizontal = vScale.isHorizontal();
|
|
const ruler = this._getRuler();
|
|
const { sharedOptions, includeOptions } = this._getSharedOptions(start, mode);
|
|
for (let i2 = start; i2 < start + count; i2++) {
|
|
const parsed = this.getParsed(i2);
|
|
const vpixels = reset2 || isNullOrUndef(parsed[vScale.axis]) ? {
|
|
base,
|
|
head: base
|
|
} : this._calculateBarValuePixels(i2);
|
|
const ipixels = this._calculateBarIndexPixels(i2, ruler);
|
|
const stack = (parsed._stacks || {})[vScale.axis];
|
|
const properties = {
|
|
horizontal,
|
|
base: vpixels.base,
|
|
enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,
|
|
x: horizontal ? vpixels.head : ipixels.center,
|
|
y: horizontal ? ipixels.center : vpixels.head,
|
|
height: horizontal ? ipixels.size : Math.abs(vpixels.size),
|
|
width: horizontal ? Math.abs(vpixels.size) : ipixels.size
|
|
};
|
|
if (includeOptions) {
|
|
properties.options = sharedOptions || this.resolveDataElementOptions(i2, bars[i2].active ? "active" : mode);
|
|
}
|
|
const options = properties.options || bars[i2].options;
|
|
setBorderSkipped(properties, options, stack, index);
|
|
setInflateAmount(properties, options, ruler.ratio);
|
|
this.updateElement(bars[i2], i2, properties, mode);
|
|
}
|
|
}
|
|
_getStacks(last, dataIndex) {
|
|
const { iScale } = this._cachedMeta;
|
|
const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta) => meta.controller.options.grouped);
|
|
const stacked = iScale.options.stacked;
|
|
const stacks = [];
|
|
const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);
|
|
const iScaleValue = currentParsed && currentParsed[iScale.axis];
|
|
const skipNull = (meta) => {
|
|
const parsed = meta._parsed.find((item) => item[iScale.axis] === iScaleValue);
|
|
const val = parsed && parsed[meta.vScale.axis];
|
|
if (isNullOrUndef(val) || isNaN(val)) {
|
|
return true;
|
|
}
|
|
};
|
|
for (const meta of metasets) {
|
|
if (dataIndex !== void 0 && skipNull(meta)) {
|
|
continue;
|
|
}
|
|
if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === void 0 && meta.stack === void 0) {
|
|
stacks.push(meta.stack);
|
|
}
|
|
if (meta.index === last) {
|
|
break;
|
|
}
|
|
}
|
|
if (!stacks.length) {
|
|
stacks.push(void 0);
|
|
}
|
|
return stacks;
|
|
}
|
|
_getStackCount(index) {
|
|
return this._getStacks(void 0, index).length;
|
|
}
|
|
_getStackIndex(datasetIndex, name, dataIndex) {
|
|
const stacks = this._getStacks(datasetIndex, dataIndex);
|
|
const index = name !== void 0 ? stacks.indexOf(name) : -1;
|
|
return index === -1 ? stacks.length - 1 : index;
|
|
}
|
|
_getRuler() {
|
|
const opts = this.options;
|
|
const meta = this._cachedMeta;
|
|
const iScale = meta.iScale;
|
|
const pixels = [];
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = meta.data.length; i2 < ilen; ++i2) {
|
|
pixels.push(iScale.getPixelForValue(this.getParsed(i2)[iScale.axis], i2));
|
|
}
|
|
const barThickness = opts.barThickness;
|
|
const min = barThickness || computeMinSampleSize(meta);
|
|
return {
|
|
min,
|
|
pixels,
|
|
start: iScale._startPixel,
|
|
end: iScale._endPixel,
|
|
stackCount: this._getStackCount(),
|
|
scale: iScale,
|
|
grouped: opts.grouped,
|
|
ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
|
|
};
|
|
}
|
|
_calculateBarValuePixels(index) {
|
|
const { _cachedMeta: { vScale, _stacked, index: datasetIndex }, options: { base: baseValue, minBarLength } } = this;
|
|
const actualBase = baseValue || 0;
|
|
const parsed = this.getParsed(index);
|
|
const custom = parsed._custom;
|
|
const floating = isFloatBar(custom);
|
|
let value = parsed[vScale.axis];
|
|
let start = 0;
|
|
let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
|
|
let head, size;
|
|
if (length !== value) {
|
|
start = length - value;
|
|
length = value;
|
|
}
|
|
if (floating) {
|
|
value = custom.barStart;
|
|
length = custom.barEnd - custom.barStart;
|
|
if (value !== 0 && sign(value) !== sign(custom.barEnd)) {
|
|
start = 0;
|
|
}
|
|
start += value;
|
|
}
|
|
const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;
|
|
let base = vScale.getPixelForValue(startValue);
|
|
if (this.chart.getDataVisibility(index)) {
|
|
head = vScale.getPixelForValue(start + length);
|
|
} else {
|
|
head = base;
|
|
}
|
|
size = head - base;
|
|
if (Math.abs(size) < minBarLength) {
|
|
size = barSign(size, vScale, actualBase) * minBarLength;
|
|
if (value === actualBase) {
|
|
base -= size / 2;
|
|
}
|
|
const startPixel = vScale.getPixelForDecimal(0);
|
|
const endPixel = vScale.getPixelForDecimal(1);
|
|
const min = Math.min(startPixel, endPixel);
|
|
const max = Math.max(startPixel, endPixel);
|
|
base = Math.max(Math.min(base, max), min);
|
|
head = base + size;
|
|
if (_stacked && !floating) {
|
|
parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);
|
|
}
|
|
}
|
|
if (base === vScale.getPixelForValue(actualBase)) {
|
|
const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2;
|
|
base += halfGrid;
|
|
size -= halfGrid;
|
|
}
|
|
return {
|
|
size,
|
|
base,
|
|
head,
|
|
center: head + size / 2
|
|
};
|
|
}
|
|
_calculateBarIndexPixels(index, ruler) {
|
|
const scale = ruler.scale;
|
|
const options = this.options;
|
|
const skipNull = options.skipNull;
|
|
const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity);
|
|
let center, size;
|
|
if (ruler.grouped) {
|
|
const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
|
|
const range = options.barThickness === "flex" ? computeFlexCategoryTraits(index, ruler, options, stackCount) : computeFitCategoryTraits(index, ruler, options, stackCount);
|
|
const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : void 0);
|
|
center = range.start + range.chunk * stackIndex + range.chunk / 2;
|
|
size = Math.min(maxBarThickness, range.chunk * range.ratio);
|
|
} else {
|
|
center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
|
|
size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
|
|
}
|
|
return {
|
|
base: center - size / 2,
|
|
head: center + size / 2,
|
|
center,
|
|
size
|
|
};
|
|
}
|
|
draw() {
|
|
const meta = this._cachedMeta;
|
|
const vScale = meta.vScale;
|
|
const rects = meta.data;
|
|
const ilen = rects.length;
|
|
let i2 = 0;
|
|
for (; i2 < ilen; ++i2) {
|
|
if (this.getParsed(i2)[vScale.axis] !== null && !rects[i2].hidden) {
|
|
rects[i2].draw(this._ctx);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
__publicField(BarController, "id", "bar");
|
|
__publicField(BarController, "defaults", {
|
|
datasetElementType: false,
|
|
dataElementType: "bar",
|
|
categoryPercentage: 0.8,
|
|
barPercentage: 0.9,
|
|
grouped: true,
|
|
animations: {
|
|
numbers: {
|
|
type: "number",
|
|
properties: [
|
|
"x",
|
|
"y",
|
|
"base",
|
|
"width",
|
|
"height"
|
|
]
|
|
}
|
|
}
|
|
});
|
|
__publicField(BarController, "overrides", {
|
|
scales: {
|
|
_index_: {
|
|
type: "category",
|
|
offset: true,
|
|
grid: {
|
|
offset: true
|
|
}
|
|
},
|
|
_value_: {
|
|
type: "linear",
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
});
|
|
function getRatioAndOffset(rotation, circumference, cutout) {
|
|
let ratioX = 1;
|
|
let ratioY = 1;
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
if (circumference < TAU) {
|
|
const startAngle = rotation;
|
|
const endAngle = startAngle + circumference;
|
|
const startX = Math.cos(startAngle);
|
|
const startY = Math.sin(startAngle);
|
|
const endX = Math.cos(endAngle);
|
|
const endY = Math.sin(endAngle);
|
|
const calcMax = (angle, a2, b2) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a2, a2 * cutout, b2, b2 * cutout);
|
|
const calcMin = (angle, a2, b2) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a2, a2 * cutout, b2, b2 * cutout);
|
|
const maxX = calcMax(0, startX, endX);
|
|
const maxY = calcMax(HALF_PI, startY, endY);
|
|
const minX = calcMin(PI, startX, endX);
|
|
const minY = calcMin(PI + HALF_PI, startY, endY);
|
|
ratioX = (maxX - minX) / 2;
|
|
ratioY = (maxY - minY) / 2;
|
|
offsetX = -(maxX + minX) / 2;
|
|
offsetY = -(maxY + minY) / 2;
|
|
}
|
|
return {
|
|
ratioX,
|
|
ratioY,
|
|
offsetX,
|
|
offsetY
|
|
};
|
|
}
|
|
var DoughnutController = class extends DatasetController {
|
|
constructor(chart, datasetIndex) {
|
|
super(chart, datasetIndex);
|
|
this.enableOptionSharing = true;
|
|
this.innerRadius = void 0;
|
|
this.outerRadius = void 0;
|
|
this.offsetX = void 0;
|
|
this.offsetY = void 0;
|
|
}
|
|
linkScales() {
|
|
}
|
|
parse(start, count) {
|
|
const data = this.getDataset().data;
|
|
const meta = this._cachedMeta;
|
|
if (this._parsing === false) {
|
|
meta._parsed = data;
|
|
} else {
|
|
let getter = (i3) => +data[i3];
|
|
if (isObject(data[start])) {
|
|
const { key = "value" } = this._parsing;
|
|
getter = (i3) => +resolveObjectKey(data[i3], key);
|
|
}
|
|
let i2, ilen;
|
|
for (i2 = start, ilen = start + count; i2 < ilen; ++i2) {
|
|
meta._parsed[i2] = getter(i2);
|
|
}
|
|
}
|
|
}
|
|
_getRotation() {
|
|
return toRadians(this.options.rotation - 90);
|
|
}
|
|
_getCircumference() {
|
|
return toRadians(this.options.circumference);
|
|
}
|
|
_getRotationExtents() {
|
|
let min = TAU;
|
|
let max = -TAU;
|
|
for (let i2 = 0; i2 < this.chart.data.datasets.length; ++i2) {
|
|
if (this.chart.isDatasetVisible(i2) && this.chart.getDatasetMeta(i2).type === this._type) {
|
|
const controller = this.chart.getDatasetMeta(i2).controller;
|
|
const rotation = controller._getRotation();
|
|
const circumference = controller._getCircumference();
|
|
min = Math.min(min, rotation);
|
|
max = Math.max(max, rotation + circumference);
|
|
}
|
|
}
|
|
return {
|
|
rotation: min,
|
|
circumference: max - min
|
|
};
|
|
}
|
|
update(mode) {
|
|
const chart = this.chart;
|
|
const { chartArea } = chart;
|
|
const meta = this._cachedMeta;
|
|
const arcs = meta.data;
|
|
const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
|
|
const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
|
|
const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1);
|
|
const chartWeight = this._getRingWeight(this.index);
|
|
const { circumference, rotation } = this._getRotationExtents();
|
|
const { ratioX, ratioY, offsetX, offsetY } = getRatioAndOffset(rotation, circumference, cutout);
|
|
const maxWidth = (chartArea.width - spacing) / ratioX;
|
|
const maxHeight = (chartArea.height - spacing) / ratioY;
|
|
const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
|
|
const outerRadius = toDimension(this.options.radius, maxRadius);
|
|
const innerRadius = Math.max(outerRadius * cutout, 0);
|
|
const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
|
|
this.offsetX = offsetX * outerRadius;
|
|
this.offsetY = offsetY * outerRadius;
|
|
meta.total = this.calculateTotal();
|
|
this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
|
|
this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
|
|
this.updateElements(arcs, 0, arcs.length, mode);
|
|
}
|
|
_circumference(i2, reset2) {
|
|
const opts = this.options;
|
|
const meta = this._cachedMeta;
|
|
const circumference = this._getCircumference();
|
|
if (reset2 && opts.animation.animateRotate || !this.chart.getDataVisibility(i2) || meta._parsed[i2] === null || meta.data[i2].hidden) {
|
|
return 0;
|
|
}
|
|
return this.calculateCircumference(meta._parsed[i2] * circumference / TAU);
|
|
}
|
|
updateElements(arcs, start, count, mode) {
|
|
const reset2 = mode === "reset";
|
|
const chart = this.chart;
|
|
const chartArea = chart.chartArea;
|
|
const opts = chart.options;
|
|
const animationOpts = opts.animation;
|
|
const centerX = (chartArea.left + chartArea.right) / 2;
|
|
const centerY = (chartArea.top + chartArea.bottom) / 2;
|
|
const animateScale = reset2 && animationOpts.animateScale;
|
|
const innerRadius = animateScale ? 0 : this.innerRadius;
|
|
const outerRadius = animateScale ? 0 : this.outerRadius;
|
|
const { sharedOptions, includeOptions } = this._getSharedOptions(start, mode);
|
|
let startAngle = this._getRotation();
|
|
let i2;
|
|
for (i2 = 0; i2 < start; ++i2) {
|
|
startAngle += this._circumference(i2, reset2);
|
|
}
|
|
for (i2 = start; i2 < start + count; ++i2) {
|
|
const circumference = this._circumference(i2, reset2);
|
|
const arc = arcs[i2];
|
|
const properties = {
|
|
x: centerX + this.offsetX,
|
|
y: centerY + this.offsetY,
|
|
startAngle,
|
|
endAngle: startAngle + circumference,
|
|
circumference,
|
|
outerRadius,
|
|
innerRadius
|
|
};
|
|
if (includeOptions) {
|
|
properties.options = sharedOptions || this.resolveDataElementOptions(i2, arc.active ? "active" : mode);
|
|
}
|
|
startAngle += circumference;
|
|
this.updateElement(arc, i2, properties, mode);
|
|
}
|
|
}
|
|
calculateTotal() {
|
|
const meta = this._cachedMeta;
|
|
const metaData = meta.data;
|
|
let total = 0;
|
|
let i2;
|
|
for (i2 = 0; i2 < metaData.length; i2++) {
|
|
const value = meta._parsed[i2];
|
|
if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i2) && !metaData[i2].hidden) {
|
|
total += Math.abs(value);
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
calculateCircumference(value) {
|
|
const total = this._cachedMeta.total;
|
|
if (total > 0 && !isNaN(value)) {
|
|
return TAU * (Math.abs(value) / total);
|
|
}
|
|
return 0;
|
|
}
|
|
getLabelAndValue(index) {
|
|
const meta = this._cachedMeta;
|
|
const chart = this.chart;
|
|
const labels = chart.data.labels || [];
|
|
const value = formatNumber(meta._parsed[index], chart.options.locale);
|
|
return {
|
|
label: labels[index] || "",
|
|
value
|
|
};
|
|
}
|
|
getMaxBorderWidth(arcs) {
|
|
let max = 0;
|
|
const chart = this.chart;
|
|
let i2, ilen, meta, controller, options;
|
|
if (!arcs) {
|
|
for (i2 = 0, ilen = chart.data.datasets.length; i2 < ilen; ++i2) {
|
|
if (chart.isDatasetVisible(i2)) {
|
|
meta = chart.getDatasetMeta(i2);
|
|
arcs = meta.data;
|
|
controller = meta.controller;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!arcs) {
|
|
return 0;
|
|
}
|
|
for (i2 = 0, ilen = arcs.length; i2 < ilen; ++i2) {
|
|
options = controller.resolveDataElementOptions(i2);
|
|
if (options.borderAlign !== "inner") {
|
|
max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
getMaxOffset(arcs) {
|
|
let max = 0;
|
|
for (let i2 = 0, ilen = arcs.length; i2 < ilen; ++i2) {
|
|
const options = this.resolveDataElementOptions(i2);
|
|
max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
|
|
}
|
|
return max;
|
|
}
|
|
_getRingWeightOffset(datasetIndex) {
|
|
let ringWeightOffset = 0;
|
|
for (let i2 = 0; i2 < datasetIndex; ++i2) {
|
|
if (this.chart.isDatasetVisible(i2)) {
|
|
ringWeightOffset += this._getRingWeight(i2);
|
|
}
|
|
}
|
|
return ringWeightOffset;
|
|
}
|
|
_getRingWeight(datasetIndex) {
|
|
return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);
|
|
}
|
|
_getVisibleDatasetWeightTotal() {
|
|
return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
|
|
}
|
|
};
|
|
__publicField(DoughnutController, "id", "doughnut");
|
|
__publicField(DoughnutController, "defaults", {
|
|
datasetElementType: false,
|
|
dataElementType: "arc",
|
|
animation: {
|
|
animateRotate: true,
|
|
animateScale: false
|
|
},
|
|
animations: {
|
|
numbers: {
|
|
type: "number",
|
|
properties: [
|
|
"circumference",
|
|
"endAngle",
|
|
"innerRadius",
|
|
"outerRadius",
|
|
"startAngle",
|
|
"x",
|
|
"y",
|
|
"offset",
|
|
"borderWidth",
|
|
"spacing"
|
|
]
|
|
}
|
|
},
|
|
cutout: "50%",
|
|
rotation: 0,
|
|
circumference: 360,
|
|
radius: "100%",
|
|
spacing: 0,
|
|
indexAxis: "r"
|
|
});
|
|
__publicField(DoughnutController, "descriptors", {
|
|
_scriptable: (name) => name !== "spacing",
|
|
_indexable: (name) => name !== "spacing" && !name.startsWith("borderDash") && !name.startsWith("hoverBorderDash")
|
|
});
|
|
__publicField(DoughnutController, "overrides", {
|
|
aspectRatio: 1,
|
|
plugins: {
|
|
legend: {
|
|
labels: {
|
|
generateLabels(chart) {
|
|
const data = chart.data;
|
|
if (data.labels.length && data.datasets.length) {
|
|
const { labels: { pointStyle, color: color2 } } = chart.legend.options;
|
|
return data.labels.map((label, i2) => {
|
|
const meta = chart.getDatasetMeta(0);
|
|
const style = meta.controller.getStyle(i2);
|
|
return {
|
|
text: label,
|
|
fillStyle: style.backgroundColor,
|
|
strokeStyle: style.borderColor,
|
|
fontColor: color2,
|
|
lineWidth: style.borderWidth,
|
|
pointStyle,
|
|
hidden: !chart.getDataVisibility(i2),
|
|
index: i2
|
|
};
|
|
});
|
|
}
|
|
return [];
|
|
}
|
|
},
|
|
onClick(e2, legendItem, legend) {
|
|
legend.chart.toggleDataVisibility(legendItem.index);
|
|
legend.chart.update();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
var PieController = class extends DoughnutController {
|
|
};
|
|
__publicField(PieController, "id", "pie");
|
|
__publicField(PieController, "defaults", {
|
|
cutout: 0,
|
|
rotation: 0,
|
|
circumference: 360,
|
|
radius: "100%"
|
|
});
|
|
function abstract() {
|
|
throw new Error("This method is not implemented: Check that a complete date adapter is provided.");
|
|
}
|
|
var DateAdapterBase = class _DateAdapterBase {
|
|
constructor(options) {
|
|
__publicField(this, "options");
|
|
this.options = options || {};
|
|
}
|
|
/**
|
|
* Override default date adapter methods.
|
|
* Accepts type parameter to define options type.
|
|
* @example
|
|
* Chart._adapters._date.override<{myAdapterOption: string}>({
|
|
* init() {
|
|
* console.log(this.options.myAdapterOption);
|
|
* }
|
|
* })
|
|
*/
|
|
static override(members) {
|
|
Object.assign(_DateAdapterBase.prototype, members);
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
init() {
|
|
}
|
|
formats() {
|
|
return abstract();
|
|
}
|
|
parse() {
|
|
return abstract();
|
|
}
|
|
format() {
|
|
return abstract();
|
|
}
|
|
add() {
|
|
return abstract();
|
|
}
|
|
diff() {
|
|
return abstract();
|
|
}
|
|
startOf() {
|
|
return abstract();
|
|
}
|
|
endOf() {
|
|
return abstract();
|
|
}
|
|
};
|
|
var adapters = {
|
|
_date: DateAdapterBase
|
|
};
|
|
function binarySearch(metaset, axis, value, intersect) {
|
|
const { controller, data, _sorted } = metaset;
|
|
const iScale = controller._cachedMeta.iScale;
|
|
if (iScale && axis === iScale.axis && axis !== "r" && _sorted && data.length) {
|
|
const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;
|
|
if (!intersect) {
|
|
return lookupMethod(data, axis, value);
|
|
} else if (controller._sharedOptions) {
|
|
const el = data[0];
|
|
const range = typeof el.getRange === "function" && el.getRange(axis);
|
|
if (range) {
|
|
const start = lookupMethod(data, axis, value - range);
|
|
const end = lookupMethod(data, axis, value + range);
|
|
return {
|
|
lo: start.lo,
|
|
hi: end.hi
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
lo: 0,
|
|
hi: data.length - 1
|
|
};
|
|
}
|
|
function evaluateInteractionItems(chart, axis, position, handler, intersect) {
|
|
const metasets = chart.getSortedVisibleDatasetMetas();
|
|
const value = position[axis];
|
|
for (let i2 = 0, ilen = metasets.length; i2 < ilen; ++i2) {
|
|
const { index, data } = metasets[i2];
|
|
const { lo, hi } = binarySearch(metasets[i2], axis, value, intersect);
|
|
for (let j2 = lo; j2 <= hi; ++j2) {
|
|
const element = data[j2];
|
|
if (!element.skip) {
|
|
handler(element, index, j2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function getDistanceMetricForAxis(axis) {
|
|
const useX = axis.indexOf("x") !== -1;
|
|
const useY = axis.indexOf("y") !== -1;
|
|
return function(pt1, pt2) {
|
|
const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
|
|
const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
|
|
return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
|
|
};
|
|
}
|
|
function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {
|
|
const items = [];
|
|
if (!includeInvisible && !chart.isPointInArea(position)) {
|
|
return items;
|
|
}
|
|
const evaluationFunc = function(element, datasetIndex, index) {
|
|
if (!includeInvisible && !_isPointInArea(element, chart.chartArea, 0)) {
|
|
return;
|
|
}
|
|
if (element.inRange(position.x, position.y, useFinalPosition)) {
|
|
items.push({
|
|
element,
|
|
datasetIndex,
|
|
index
|
|
});
|
|
}
|
|
};
|
|
evaluateInteractionItems(chart, axis, position, evaluationFunc, true);
|
|
return items;
|
|
}
|
|
function getNearestRadialItems(chart, position, axis, useFinalPosition) {
|
|
let items = [];
|
|
function evaluationFunc(element, datasetIndex, index) {
|
|
const { startAngle, endAngle } = element.getProps([
|
|
"startAngle",
|
|
"endAngle"
|
|
], useFinalPosition);
|
|
const { angle } = getAngleFromPoint(element, {
|
|
x: position.x,
|
|
y: position.y
|
|
});
|
|
if (_angleBetween(angle, startAngle, endAngle)) {
|
|
items.push({
|
|
element,
|
|
datasetIndex,
|
|
index
|
|
});
|
|
}
|
|
}
|
|
evaluateInteractionItems(chart, axis, position, evaluationFunc);
|
|
return items;
|
|
}
|
|
function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
|
|
let items = [];
|
|
const distanceMetric = getDistanceMetricForAxis(axis);
|
|
let minDistance = Number.POSITIVE_INFINITY;
|
|
function evaluationFunc(element, datasetIndex, index) {
|
|
const inRange2 = element.inRange(position.x, position.y, useFinalPosition);
|
|
if (intersect && !inRange2) {
|
|
return;
|
|
}
|
|
const center = element.getCenterPoint(useFinalPosition);
|
|
const pointInArea = !!includeInvisible || chart.isPointInArea(center);
|
|
if (!pointInArea && !inRange2) {
|
|
return;
|
|
}
|
|
const distance = distanceMetric(position, center);
|
|
if (distance < minDistance) {
|
|
items = [
|
|
{
|
|
element,
|
|
datasetIndex,
|
|
index
|
|
}
|
|
];
|
|
minDistance = distance;
|
|
} else if (distance === minDistance) {
|
|
items.push({
|
|
element,
|
|
datasetIndex,
|
|
index
|
|
});
|
|
}
|
|
}
|
|
evaluateInteractionItems(chart, axis, position, evaluationFunc);
|
|
return items;
|
|
}
|
|
function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {
|
|
if (!includeInvisible && !chart.isPointInArea(position)) {
|
|
return [];
|
|
}
|
|
return axis === "r" && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);
|
|
}
|
|
function getAxisItems(chart, position, axis, intersect, useFinalPosition) {
|
|
const items = [];
|
|
const rangeMethod = axis === "x" ? "inXRange" : "inYRange";
|
|
let intersectsItem = false;
|
|
evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index) => {
|
|
if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {
|
|
items.push({
|
|
element,
|
|
datasetIndex,
|
|
index
|
|
});
|
|
intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);
|
|
}
|
|
});
|
|
if (intersect && !intersectsItem) {
|
|
return [];
|
|
}
|
|
return items;
|
|
}
|
|
var Interaction = {
|
|
evaluateInteractionItems,
|
|
modes: {
|
|
index(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
const axis = options.axis || "x";
|
|
const includeInvisible = options.includeInvisible || false;
|
|
const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
|
|
const elements = [];
|
|
if (!items.length) {
|
|
return [];
|
|
}
|
|
chart.getSortedVisibleDatasetMetas().forEach((meta) => {
|
|
const index = items[0].index;
|
|
const element = meta.data[index];
|
|
if (element && !element.skip) {
|
|
elements.push({
|
|
element,
|
|
datasetIndex: meta.index,
|
|
index
|
|
});
|
|
}
|
|
});
|
|
return elements;
|
|
},
|
|
dataset(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
const axis = options.axis || "xy";
|
|
const includeInvisible = options.includeInvisible || false;
|
|
let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);
|
|
if (items.length > 0) {
|
|
const datasetIndex = items[0].datasetIndex;
|
|
const data = chart.getDatasetMeta(datasetIndex).data;
|
|
items = [];
|
|
for (let i2 = 0; i2 < data.length; ++i2) {
|
|
items.push({
|
|
element: data[i2],
|
|
datasetIndex,
|
|
index: i2
|
|
});
|
|
}
|
|
}
|
|
return items;
|
|
},
|
|
point(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
const axis = options.axis || "xy";
|
|
const includeInvisible = options.includeInvisible || false;
|
|
return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);
|
|
},
|
|
nearest(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
const axis = options.axis || "xy";
|
|
const includeInvisible = options.includeInvisible || false;
|
|
return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);
|
|
},
|
|
x(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
return getAxisItems(chart, position, "x", options.intersect, useFinalPosition);
|
|
},
|
|
y(chart, e2, options, useFinalPosition) {
|
|
const position = getRelativePosition(e2, chart);
|
|
return getAxisItems(chart, position, "y", options.intersect, useFinalPosition);
|
|
}
|
|
}
|
|
};
|
|
var STATIC_POSITIONS = [
|
|
"left",
|
|
"top",
|
|
"right",
|
|
"bottom"
|
|
];
|
|
function filterByPosition(array, position) {
|
|
return array.filter((v2) => v2.pos === position);
|
|
}
|
|
function filterDynamicPositionByAxis(array, axis) {
|
|
return array.filter((v2) => STATIC_POSITIONS.indexOf(v2.pos) === -1 && v2.box.axis === axis);
|
|
}
|
|
function sortByWeight(array, reverse) {
|
|
return array.sort((a2, b2) => {
|
|
const v0 = reverse ? b2 : a2;
|
|
const v1 = reverse ? a2 : b2;
|
|
return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;
|
|
});
|
|
}
|
|
function wrapBoxes(boxes) {
|
|
const layoutBoxes = [];
|
|
let i2, ilen, box, pos, stack, stackWeight;
|
|
for (i2 = 0, ilen = (boxes || []).length; i2 < ilen; ++i2) {
|
|
box = boxes[i2];
|
|
({ position: pos, options: { stack, stackWeight = 1 } } = box);
|
|
layoutBoxes.push({
|
|
index: i2,
|
|
box,
|
|
pos,
|
|
horizontal: box.isHorizontal(),
|
|
weight: box.weight,
|
|
stack: stack && pos + stack,
|
|
stackWeight
|
|
});
|
|
}
|
|
return layoutBoxes;
|
|
}
|
|
function buildStacks(layouts2) {
|
|
const stacks = {};
|
|
for (const wrap of layouts2) {
|
|
const { stack, pos, stackWeight } = wrap;
|
|
if (!stack || !STATIC_POSITIONS.includes(pos)) {
|
|
continue;
|
|
}
|
|
const _stack = stacks[stack] || (stacks[stack] = {
|
|
count: 0,
|
|
placed: 0,
|
|
weight: 0,
|
|
size: 0
|
|
});
|
|
_stack.count++;
|
|
_stack.weight += stackWeight;
|
|
}
|
|
return stacks;
|
|
}
|
|
function setLayoutDims(layouts2, params) {
|
|
const stacks = buildStacks(layouts2);
|
|
const { vBoxMaxWidth, hBoxMaxHeight } = params;
|
|
let i2, ilen, layout;
|
|
for (i2 = 0, ilen = layouts2.length; i2 < ilen; ++i2) {
|
|
layout = layouts2[i2];
|
|
const { fullSize } = layout.box;
|
|
const stack = stacks[layout.stack];
|
|
const factor = stack && layout.stackWeight / stack.weight;
|
|
if (layout.horizontal) {
|
|
layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
|
|
layout.height = hBoxMaxHeight;
|
|
} else {
|
|
layout.width = vBoxMaxWidth;
|
|
layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
|
|
}
|
|
}
|
|
return stacks;
|
|
}
|
|
function buildLayoutBoxes(boxes) {
|
|
const layoutBoxes = wrapBoxes(boxes);
|
|
const fullSize = sortByWeight(layoutBoxes.filter((wrap) => wrap.box.fullSize), true);
|
|
const left = sortByWeight(filterByPosition(layoutBoxes, "left"), true);
|
|
const right = sortByWeight(filterByPosition(layoutBoxes, "right"));
|
|
const top = sortByWeight(filterByPosition(layoutBoxes, "top"), true);
|
|
const bottom = sortByWeight(filterByPosition(layoutBoxes, "bottom"));
|
|
const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, "x");
|
|
const centerVertical = filterDynamicPositionByAxis(layoutBoxes, "y");
|
|
return {
|
|
fullSize,
|
|
leftAndTop: left.concat(top),
|
|
rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
|
|
chartArea: filterByPosition(layoutBoxes, "chartArea"),
|
|
vertical: left.concat(right).concat(centerVertical),
|
|
horizontal: top.concat(bottom).concat(centerHorizontal)
|
|
};
|
|
}
|
|
function getCombinedMax(maxPadding, chartArea, a2, b2) {
|
|
return Math.max(maxPadding[a2], chartArea[a2]) + Math.max(maxPadding[b2], chartArea[b2]);
|
|
}
|
|
function updateMaxPadding(maxPadding, boxPadding) {
|
|
maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
|
|
maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
|
|
maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
|
|
maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
|
|
}
|
|
function updateDims(chartArea, params, layout, stacks) {
|
|
const { pos, box } = layout;
|
|
const maxPadding = chartArea.maxPadding;
|
|
if (!isObject(pos)) {
|
|
if (layout.size) {
|
|
chartArea[pos] -= layout.size;
|
|
}
|
|
const stack = stacks[layout.stack] || {
|
|
size: 0,
|
|
count: 1
|
|
};
|
|
stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
|
|
layout.size = stack.size / stack.count;
|
|
chartArea[pos] += layout.size;
|
|
}
|
|
if (box.getPadding) {
|
|
updateMaxPadding(maxPadding, box.getPadding());
|
|
}
|
|
const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, "left", "right"));
|
|
const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, "top", "bottom"));
|
|
const widthChanged = newWidth !== chartArea.w;
|
|
const heightChanged = newHeight !== chartArea.h;
|
|
chartArea.w = newWidth;
|
|
chartArea.h = newHeight;
|
|
return layout.horizontal ? {
|
|
same: widthChanged,
|
|
other: heightChanged
|
|
} : {
|
|
same: heightChanged,
|
|
other: widthChanged
|
|
};
|
|
}
|
|
function handleMaxPadding(chartArea) {
|
|
const maxPadding = chartArea.maxPadding;
|
|
function updatePos(pos) {
|
|
const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
|
|
chartArea[pos] += change;
|
|
return change;
|
|
}
|
|
chartArea.y += updatePos("top");
|
|
chartArea.x += updatePos("left");
|
|
updatePos("right");
|
|
updatePos("bottom");
|
|
}
|
|
function getMargins(horizontal, chartArea) {
|
|
const maxPadding = chartArea.maxPadding;
|
|
function marginForPositions(positions2) {
|
|
const margin = {
|
|
left: 0,
|
|
top: 0,
|
|
right: 0,
|
|
bottom: 0
|
|
};
|
|
positions2.forEach((pos) => {
|
|
margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
|
|
});
|
|
return margin;
|
|
}
|
|
return horizontal ? marginForPositions([
|
|
"left",
|
|
"right"
|
|
]) : marginForPositions([
|
|
"top",
|
|
"bottom"
|
|
]);
|
|
}
|
|
function fitBoxes(boxes, chartArea, params, stacks) {
|
|
const refitBoxes = [];
|
|
let i2, ilen, layout, box, refit, changed;
|
|
for (i2 = 0, ilen = boxes.length, refit = 0; i2 < ilen; ++i2) {
|
|
layout = boxes[i2];
|
|
box = layout.box;
|
|
box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));
|
|
const { same, other } = updateDims(chartArea, params, layout, stacks);
|
|
refit |= same && refitBoxes.length;
|
|
changed = changed || other;
|
|
if (!box.fullSize) {
|
|
refitBoxes.push(layout);
|
|
}
|
|
}
|
|
return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
|
|
}
|
|
function setBoxDims(box, left, top, width, height) {
|
|
box.top = top;
|
|
box.left = left;
|
|
box.right = left + width;
|
|
box.bottom = top + height;
|
|
box.width = width;
|
|
box.height = height;
|
|
}
|
|
function placeBoxes(boxes, chartArea, params, stacks) {
|
|
const userPadding = params.padding;
|
|
let { x: x2, y: y2 } = chartArea;
|
|
for (const layout of boxes) {
|
|
const box = layout.box;
|
|
const stack = stacks[layout.stack] || {
|
|
count: 1,
|
|
placed: 0,
|
|
weight: 1
|
|
};
|
|
const weight = layout.stackWeight / stack.weight || 1;
|
|
if (layout.horizontal) {
|
|
const width = chartArea.w * weight;
|
|
const height = stack.size || box.height;
|
|
if (defined(stack.start)) {
|
|
y2 = stack.start;
|
|
}
|
|
if (box.fullSize) {
|
|
setBoxDims(box, userPadding.left, y2, params.outerWidth - userPadding.right - userPadding.left, height);
|
|
} else {
|
|
setBoxDims(box, chartArea.left + stack.placed, y2, width, height);
|
|
}
|
|
stack.start = y2;
|
|
stack.placed += width;
|
|
y2 = box.bottom;
|
|
} else {
|
|
const height = chartArea.h * weight;
|
|
const width = stack.size || box.width;
|
|
if (defined(stack.start)) {
|
|
x2 = stack.start;
|
|
}
|
|
if (box.fullSize) {
|
|
setBoxDims(box, x2, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
|
|
} else {
|
|
setBoxDims(box, x2, chartArea.top + stack.placed, width, height);
|
|
}
|
|
stack.start = x2;
|
|
stack.placed += height;
|
|
x2 = box.right;
|
|
}
|
|
}
|
|
chartArea.x = x2;
|
|
chartArea.y = y2;
|
|
}
|
|
var layouts = {
|
|
addBox(chart, item) {
|
|
if (!chart.boxes) {
|
|
chart.boxes = [];
|
|
}
|
|
item.fullSize = item.fullSize || false;
|
|
item.position = item.position || "top";
|
|
item.weight = item.weight || 0;
|
|
item._layers = item._layers || function() {
|
|
return [
|
|
{
|
|
z: 0,
|
|
draw(chartArea) {
|
|
item.draw(chartArea);
|
|
}
|
|
}
|
|
];
|
|
};
|
|
chart.boxes.push(item);
|
|
},
|
|
removeBox(chart, layoutItem) {
|
|
const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
|
|
if (index !== -1) {
|
|
chart.boxes.splice(index, 1);
|
|
}
|
|
},
|
|
configure(chart, item, options) {
|
|
item.fullSize = options.fullSize;
|
|
item.position = options.position;
|
|
item.weight = options.weight;
|
|
},
|
|
update(chart, width, height, minPadding) {
|
|
if (!chart) {
|
|
return;
|
|
}
|
|
const padding = toPadding(chart.options.layout.padding);
|
|
const availableWidth = Math.max(width - padding.width, 0);
|
|
const availableHeight = Math.max(height - padding.height, 0);
|
|
const boxes = buildLayoutBoxes(chart.boxes);
|
|
const verticalBoxes = boxes.vertical;
|
|
const horizontalBoxes = boxes.horizontal;
|
|
each(chart.boxes, (box) => {
|
|
if (typeof box.beforeLayout === "function") {
|
|
box.beforeLayout();
|
|
}
|
|
});
|
|
const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) => wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
|
|
const params = Object.freeze({
|
|
outerWidth: width,
|
|
outerHeight: height,
|
|
padding,
|
|
availableWidth,
|
|
availableHeight,
|
|
vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
|
|
hBoxMaxHeight: availableHeight / 2
|
|
});
|
|
const maxPadding = Object.assign({}, padding);
|
|
updateMaxPadding(maxPadding, toPadding(minPadding));
|
|
const chartArea = Object.assign({
|
|
maxPadding,
|
|
w: availableWidth,
|
|
h: availableHeight,
|
|
x: padding.left,
|
|
y: padding.top
|
|
}, padding);
|
|
const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
|
|
fitBoxes(boxes.fullSize, chartArea, params, stacks);
|
|
fitBoxes(verticalBoxes, chartArea, params, stacks);
|
|
if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
|
|
fitBoxes(verticalBoxes, chartArea, params, stacks);
|
|
}
|
|
handleMaxPadding(chartArea);
|
|
placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
|
|
chartArea.x += chartArea.w;
|
|
chartArea.y += chartArea.h;
|
|
placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
|
|
chart.chartArea = {
|
|
left: chartArea.left,
|
|
top: chartArea.top,
|
|
right: chartArea.left + chartArea.w,
|
|
bottom: chartArea.top + chartArea.h,
|
|
height: chartArea.h,
|
|
width: chartArea.w
|
|
};
|
|
each(boxes.chartArea, (layout) => {
|
|
const box = layout.box;
|
|
Object.assign(box, chart.chartArea);
|
|
box.update(chartArea.w, chartArea.h, {
|
|
left: 0,
|
|
top: 0,
|
|
right: 0,
|
|
bottom: 0
|
|
});
|
|
});
|
|
}
|
|
};
|
|
var BasePlatform = class {
|
|
acquireContext(canvas, aspectRatio) {
|
|
}
|
|
releaseContext(context) {
|
|
return false;
|
|
}
|
|
addEventListener(chart, type, listener) {
|
|
}
|
|
removeEventListener(chart, type, listener) {
|
|
}
|
|
getDevicePixelRatio() {
|
|
return 1;
|
|
}
|
|
getMaximumSize(element, width, height, aspectRatio) {
|
|
width = Math.max(0, width || element.width);
|
|
height = height || element.height;
|
|
return {
|
|
width,
|
|
height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
|
|
};
|
|
}
|
|
isAttached(canvas) {
|
|
return true;
|
|
}
|
|
updateConfig(config) {
|
|
}
|
|
};
|
|
var BasicPlatform = class extends BasePlatform {
|
|
acquireContext(item) {
|
|
return item && item.getContext && item.getContext("2d") || null;
|
|
}
|
|
updateConfig(config) {
|
|
config.options.animation = false;
|
|
}
|
|
};
|
|
var EXPANDO_KEY = "$chartjs";
|
|
var EVENT_TYPES = {
|
|
touchstart: "mousedown",
|
|
touchmove: "mousemove",
|
|
touchend: "mouseup",
|
|
pointerenter: "mouseenter",
|
|
pointerdown: "mousedown",
|
|
pointermove: "mousemove",
|
|
pointerup: "mouseup",
|
|
pointerleave: "mouseout",
|
|
pointerout: "mouseout"
|
|
};
|
|
var isNullOrEmpty = (value) => value === null || value === "";
|
|
function initCanvas(canvas, aspectRatio) {
|
|
const style = canvas.style;
|
|
const renderHeight = canvas.getAttribute("height");
|
|
const renderWidth = canvas.getAttribute("width");
|
|
canvas[EXPANDO_KEY] = {
|
|
initial: {
|
|
height: renderHeight,
|
|
width: renderWidth,
|
|
style: {
|
|
display: style.display,
|
|
height: style.height,
|
|
width: style.width
|
|
}
|
|
}
|
|
};
|
|
style.display = style.display || "block";
|
|
style.boxSizing = style.boxSizing || "border-box";
|
|
if (isNullOrEmpty(renderWidth)) {
|
|
const displayWidth = readUsedSize(canvas, "width");
|
|
if (displayWidth !== void 0) {
|
|
canvas.width = displayWidth;
|
|
}
|
|
}
|
|
if (isNullOrEmpty(renderHeight)) {
|
|
if (canvas.style.height === "") {
|
|
canvas.height = canvas.width / (aspectRatio || 2);
|
|
} else {
|
|
const displayHeight = readUsedSize(canvas, "height");
|
|
if (displayHeight !== void 0) {
|
|
canvas.height = displayHeight;
|
|
}
|
|
}
|
|
}
|
|
return canvas;
|
|
}
|
|
var eventListenerOptions = supportsEventListenerOptions ? {
|
|
passive: true
|
|
} : false;
|
|
function addListener(node, type, listener) {
|
|
if (node) {
|
|
node.addEventListener(type, listener, eventListenerOptions);
|
|
}
|
|
}
|
|
function removeListener(chart, type, listener) {
|
|
if (chart && chart.canvas) {
|
|
chart.canvas.removeEventListener(type, listener, eventListenerOptions);
|
|
}
|
|
}
|
|
function fromNativeEvent(event, chart) {
|
|
const type = EVENT_TYPES[event.type] || event.type;
|
|
const { x: x2, y: y2 } = getRelativePosition(event, chart);
|
|
return {
|
|
type,
|
|
chart,
|
|
native: event,
|
|
x: x2 !== void 0 ? x2 : null,
|
|
y: y2 !== void 0 ? y2 : null
|
|
};
|
|
}
|
|
function nodeListContains(nodeList, canvas) {
|
|
for (const node of nodeList) {
|
|
if (node === canvas || node.contains(canvas)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
function createAttachObserver(chart, type, listener) {
|
|
const canvas = chart.canvas;
|
|
const observer = new MutationObserver((entries) => {
|
|
let trigger = false;
|
|
for (const entry of entries) {
|
|
trigger = trigger || nodeListContains(entry.addedNodes, canvas);
|
|
trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
|
|
}
|
|
if (trigger) {
|
|
listener();
|
|
}
|
|
});
|
|
observer.observe(document, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
return observer;
|
|
}
|
|
function createDetachObserver(chart, type, listener) {
|
|
const canvas = chart.canvas;
|
|
const observer = new MutationObserver((entries) => {
|
|
let trigger = false;
|
|
for (const entry of entries) {
|
|
trigger = trigger || nodeListContains(entry.removedNodes, canvas);
|
|
trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
|
|
}
|
|
if (trigger) {
|
|
listener();
|
|
}
|
|
});
|
|
observer.observe(document, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
return observer;
|
|
}
|
|
var drpListeningCharts = /* @__PURE__ */ new Map();
|
|
var oldDevicePixelRatio = 0;
|
|
function onWindowResize() {
|
|
const dpr = window.devicePixelRatio;
|
|
if (dpr === oldDevicePixelRatio) {
|
|
return;
|
|
}
|
|
oldDevicePixelRatio = dpr;
|
|
drpListeningCharts.forEach((resize, chart) => {
|
|
if (chart.currentDevicePixelRatio !== dpr) {
|
|
resize();
|
|
}
|
|
});
|
|
}
|
|
function listenDevicePixelRatioChanges(chart, resize) {
|
|
if (!drpListeningCharts.size) {
|
|
window.addEventListener("resize", onWindowResize);
|
|
}
|
|
drpListeningCharts.set(chart, resize);
|
|
}
|
|
function unlistenDevicePixelRatioChanges(chart) {
|
|
drpListeningCharts.delete(chart);
|
|
if (!drpListeningCharts.size) {
|
|
window.removeEventListener("resize", onWindowResize);
|
|
}
|
|
}
|
|
function createResizeObserver(chart, type, listener) {
|
|
const canvas = chart.canvas;
|
|
const container = canvas && _getParentNode(canvas);
|
|
if (!container) {
|
|
return;
|
|
}
|
|
const resize = throttled((width, height) => {
|
|
const w2 = container.clientWidth;
|
|
listener(width, height);
|
|
if (w2 < container.clientWidth) {
|
|
listener();
|
|
}
|
|
}, window);
|
|
const observer = new ResizeObserver((entries) => {
|
|
const entry = entries[0];
|
|
const width = entry.contentRect.width;
|
|
const height = entry.contentRect.height;
|
|
if (width === 0 && height === 0) {
|
|
return;
|
|
}
|
|
resize(width, height);
|
|
});
|
|
observer.observe(container);
|
|
listenDevicePixelRatioChanges(chart, resize);
|
|
return observer;
|
|
}
|
|
function releaseObserver(chart, type, observer) {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
}
|
|
if (type === "resize") {
|
|
unlistenDevicePixelRatioChanges(chart);
|
|
}
|
|
}
|
|
function createProxyAndListen(chart, type, listener) {
|
|
const canvas = chart.canvas;
|
|
const proxy = throttled((event) => {
|
|
if (chart.ctx !== null) {
|
|
listener(fromNativeEvent(event, chart));
|
|
}
|
|
}, chart);
|
|
addListener(canvas, type, proxy);
|
|
return proxy;
|
|
}
|
|
var DomPlatform = class extends BasePlatform {
|
|
acquireContext(canvas, aspectRatio) {
|
|
const context = canvas && canvas.getContext && canvas.getContext("2d");
|
|
if (context && context.canvas === canvas) {
|
|
initCanvas(canvas, aspectRatio);
|
|
return context;
|
|
}
|
|
return null;
|
|
}
|
|
releaseContext(context) {
|
|
const canvas = context.canvas;
|
|
if (!canvas[EXPANDO_KEY]) {
|
|
return false;
|
|
}
|
|
const initial = canvas[EXPANDO_KEY].initial;
|
|
[
|
|
"height",
|
|
"width"
|
|
].forEach((prop) => {
|
|
const value = initial[prop];
|
|
if (isNullOrUndef(value)) {
|
|
canvas.removeAttribute(prop);
|
|
} else {
|
|
canvas.setAttribute(prop, value);
|
|
}
|
|
});
|
|
const style = initial.style || {};
|
|
Object.keys(style).forEach((key) => {
|
|
canvas.style[key] = style[key];
|
|
});
|
|
canvas.width = canvas.width;
|
|
delete canvas[EXPANDO_KEY];
|
|
return true;
|
|
}
|
|
addEventListener(chart, type, listener) {
|
|
this.removeEventListener(chart, type);
|
|
const proxies = chart.$proxies || (chart.$proxies = {});
|
|
const handlers = {
|
|
attach: createAttachObserver,
|
|
detach: createDetachObserver,
|
|
resize: createResizeObserver
|
|
};
|
|
const handler = handlers[type] || createProxyAndListen;
|
|
proxies[type] = handler(chart, type, listener);
|
|
}
|
|
removeEventListener(chart, type) {
|
|
const proxies = chart.$proxies || (chart.$proxies = {});
|
|
const proxy = proxies[type];
|
|
if (!proxy) {
|
|
return;
|
|
}
|
|
const handlers = {
|
|
attach: releaseObserver,
|
|
detach: releaseObserver,
|
|
resize: releaseObserver
|
|
};
|
|
const handler = handlers[type] || removeListener;
|
|
handler(chart, type, proxy);
|
|
proxies[type] = void 0;
|
|
}
|
|
getDevicePixelRatio() {
|
|
return window.devicePixelRatio;
|
|
}
|
|
getMaximumSize(canvas, width, height, aspectRatio) {
|
|
return getMaximumSize(canvas, width, height, aspectRatio);
|
|
}
|
|
isAttached(canvas) {
|
|
const container = canvas && _getParentNode(canvas);
|
|
return !!(container && container.isConnected);
|
|
}
|
|
};
|
|
function _detectPlatform(canvas) {
|
|
if (!_isDomSupported() || typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
|
|
return BasicPlatform;
|
|
}
|
|
return DomPlatform;
|
|
}
|
|
var Element = class {
|
|
constructor() {
|
|
__publicField(this, "x");
|
|
__publicField(this, "y");
|
|
__publicField(this, "active", false);
|
|
__publicField(this, "options");
|
|
__publicField(this, "$animations");
|
|
}
|
|
tooltipPosition(useFinalPosition) {
|
|
const { x: x2, y: y2 } = this.getProps([
|
|
"x",
|
|
"y"
|
|
], useFinalPosition);
|
|
return {
|
|
x: x2,
|
|
y: y2
|
|
};
|
|
}
|
|
hasValue() {
|
|
return isNumber(this.x) && isNumber(this.y);
|
|
}
|
|
getProps(props, final) {
|
|
const anims = this.$animations;
|
|
if (!final || !anims) {
|
|
return this;
|
|
}
|
|
const ret = {};
|
|
props.forEach((prop) => {
|
|
ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
|
|
});
|
|
return ret;
|
|
}
|
|
};
|
|
__publicField(Element, "defaults", {});
|
|
__publicField(Element, "defaultRoutes");
|
|
function autoSkip(scale, ticks) {
|
|
const tickOpts = scale.options.ticks;
|
|
const determinedMaxTicks = determineMaxTicks(scale);
|
|
const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);
|
|
const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
|
|
const numMajorIndices = majorIndices.length;
|
|
const first = majorIndices[0];
|
|
const last = majorIndices[numMajorIndices - 1];
|
|
const newTicks = [];
|
|
if (numMajorIndices > ticksLimit) {
|
|
skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
|
|
return newTicks;
|
|
}
|
|
const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
|
|
if (numMajorIndices > 0) {
|
|
let i2, ilen;
|
|
const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
|
|
skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
|
|
for (i2 = 0, ilen = numMajorIndices - 1; i2 < ilen; i2++) {
|
|
skip(ticks, newTicks, spacing, majorIndices[i2], majorIndices[i2 + 1]);
|
|
}
|
|
skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
|
|
return newTicks;
|
|
}
|
|
skip(ticks, newTicks, spacing);
|
|
return newTicks;
|
|
}
|
|
function determineMaxTicks(scale) {
|
|
const offset = scale.options.offset;
|
|
const tickLength = scale._tickSize();
|
|
const maxScale = scale._length / tickLength + (offset ? 0 : 1);
|
|
const maxChart = scale._maxLength / tickLength;
|
|
return Math.floor(Math.min(maxScale, maxChart));
|
|
}
|
|
function calculateSpacing(majorIndices, ticks, ticksLimit) {
|
|
const evenMajorSpacing = getEvenSpacing(majorIndices);
|
|
const spacing = ticks.length / ticksLimit;
|
|
if (!evenMajorSpacing) {
|
|
return Math.max(spacing, 1);
|
|
}
|
|
const factors = _factorize(evenMajorSpacing);
|
|
for (let i2 = 0, ilen = factors.length - 1; i2 < ilen; i2++) {
|
|
const factor = factors[i2];
|
|
if (factor > spacing) {
|
|
return factor;
|
|
}
|
|
}
|
|
return Math.max(spacing, 1);
|
|
}
|
|
function getMajorIndices(ticks) {
|
|
const result = [];
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = ticks.length; i2 < ilen; i2++) {
|
|
if (ticks[i2].major) {
|
|
result.push(i2);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function skipMajors(ticks, newTicks, majorIndices, spacing) {
|
|
let count = 0;
|
|
let next = majorIndices[0];
|
|
let i2;
|
|
spacing = Math.ceil(spacing);
|
|
for (i2 = 0; i2 < ticks.length; i2++) {
|
|
if (i2 === next) {
|
|
newTicks.push(ticks[i2]);
|
|
count++;
|
|
next = majorIndices[count * spacing];
|
|
}
|
|
}
|
|
}
|
|
function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
|
|
const start = valueOrDefault(majorStart, 0);
|
|
const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
|
|
let count = 0;
|
|
let length, i2, next;
|
|
spacing = Math.ceil(spacing);
|
|
if (majorEnd) {
|
|
length = majorEnd - majorStart;
|
|
spacing = length / Math.floor(length / spacing);
|
|
}
|
|
next = start;
|
|
while (next < 0) {
|
|
count++;
|
|
next = Math.round(start + count * spacing);
|
|
}
|
|
for (i2 = Math.max(start, 0); i2 < end; i2++) {
|
|
if (i2 === next) {
|
|
newTicks.push(ticks[i2]);
|
|
count++;
|
|
next = Math.round(start + count * spacing);
|
|
}
|
|
}
|
|
}
|
|
function getEvenSpacing(arr) {
|
|
const len = arr.length;
|
|
let i2, diff;
|
|
if (len < 2) {
|
|
return false;
|
|
}
|
|
for (diff = arr[0], i2 = 1; i2 < len; ++i2) {
|
|
if (arr[i2] - arr[i2 - 1] !== diff) {
|
|
return false;
|
|
}
|
|
}
|
|
return diff;
|
|
}
|
|
var reverseAlign = (align) => align === "left" ? "right" : align === "right" ? "left" : align;
|
|
var offsetFromEdge = (scale, edge, offset) => edge === "top" || edge === "left" ? scale[edge] + offset : scale[edge] - offset;
|
|
var getTicksLimit = (ticksLength, maxTicksLimit) => Math.min(maxTicksLimit || ticksLength, ticksLength);
|
|
function sample(arr, numItems) {
|
|
const result = [];
|
|
const increment = arr.length / numItems;
|
|
const len = arr.length;
|
|
let i2 = 0;
|
|
for (; i2 < len; i2 += increment) {
|
|
result.push(arr[Math.floor(i2)]);
|
|
}
|
|
return result;
|
|
}
|
|
function getPixelForGridLine(scale, index, offsetGridLines) {
|
|
const length = scale.ticks.length;
|
|
const validIndex2 = Math.min(index, length - 1);
|
|
const start = scale._startPixel;
|
|
const end = scale._endPixel;
|
|
const epsilon = 1e-6;
|
|
let lineValue = scale.getPixelForTick(validIndex2);
|
|
let offset;
|
|
if (offsetGridLines) {
|
|
if (length === 1) {
|
|
offset = Math.max(lineValue - start, end - lineValue);
|
|
} else if (index === 0) {
|
|
offset = (scale.getPixelForTick(1) - lineValue) / 2;
|
|
} else {
|
|
offset = (lineValue - scale.getPixelForTick(validIndex2 - 1)) / 2;
|
|
}
|
|
lineValue += validIndex2 < index ? offset : -offset;
|
|
if (lineValue < start - epsilon || lineValue > end + epsilon) {
|
|
return;
|
|
}
|
|
}
|
|
return lineValue;
|
|
}
|
|
function garbageCollect(caches, length) {
|
|
each(caches, (cache) => {
|
|
const gc = cache.gc;
|
|
const gcLen = gc.length / 2;
|
|
let i2;
|
|
if (gcLen > length) {
|
|
for (i2 = 0; i2 < gcLen; ++i2) {
|
|
delete cache.data[gc[i2]];
|
|
}
|
|
gc.splice(0, gcLen);
|
|
}
|
|
});
|
|
}
|
|
function getTickMarkLength(options) {
|
|
return options.drawTicks ? options.tickLength : 0;
|
|
}
|
|
function getTitleHeight(options, fallback) {
|
|
if (!options.display) {
|
|
return 0;
|
|
}
|
|
const font = toFont(options.font, fallback);
|
|
const padding = toPadding(options.padding);
|
|
const lines = isArray(options.text) ? options.text.length : 1;
|
|
return lines * font.lineHeight + padding.height;
|
|
}
|
|
function createScaleContext(parent, scale) {
|
|
return createContext(parent, {
|
|
scale,
|
|
type: "scale"
|
|
});
|
|
}
|
|
function createTickContext(parent, index, tick) {
|
|
return createContext(parent, {
|
|
tick,
|
|
index,
|
|
type: "tick"
|
|
});
|
|
}
|
|
function titleAlign(align, position, reverse) {
|
|
let ret = _toLeftRightCenter(align);
|
|
if (reverse && position !== "right" || !reverse && position === "right") {
|
|
ret = reverseAlign(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
function titleArgs(scale, offset, position, align) {
|
|
const { top, left, bottom, right, chart } = scale;
|
|
const { chartArea, scales } = chart;
|
|
let rotation = 0;
|
|
let maxWidth, titleX, titleY;
|
|
const height = bottom - top;
|
|
const width = right - left;
|
|
if (scale.isHorizontal()) {
|
|
titleX = _alignStartEnd(align, left, right);
|
|
if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
|
|
} else if (position === "center") {
|
|
titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
|
|
} else {
|
|
titleY = offsetFromEdge(scale, position, offset);
|
|
}
|
|
maxWidth = right - left;
|
|
} else {
|
|
if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
|
|
} else if (position === "center") {
|
|
titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
|
|
} else {
|
|
titleX = offsetFromEdge(scale, position, offset);
|
|
}
|
|
titleY = _alignStartEnd(align, bottom, top);
|
|
rotation = position === "left" ? -HALF_PI : HALF_PI;
|
|
}
|
|
return {
|
|
titleX,
|
|
titleY,
|
|
maxWidth,
|
|
rotation
|
|
};
|
|
}
|
|
var Scale = class _Scale extends Element {
|
|
constructor(cfg) {
|
|
super();
|
|
this.id = cfg.id;
|
|
this.type = cfg.type;
|
|
this.options = void 0;
|
|
this.ctx = cfg.ctx;
|
|
this.chart = cfg.chart;
|
|
this.top = void 0;
|
|
this.bottom = void 0;
|
|
this.left = void 0;
|
|
this.right = void 0;
|
|
this.width = void 0;
|
|
this.height = void 0;
|
|
this._margins = {
|
|
left: 0,
|
|
right: 0,
|
|
top: 0,
|
|
bottom: 0
|
|
};
|
|
this.maxWidth = void 0;
|
|
this.maxHeight = void 0;
|
|
this.paddingTop = void 0;
|
|
this.paddingBottom = void 0;
|
|
this.paddingLeft = void 0;
|
|
this.paddingRight = void 0;
|
|
this.axis = void 0;
|
|
this.labelRotation = void 0;
|
|
this.min = void 0;
|
|
this.max = void 0;
|
|
this._range = void 0;
|
|
this.ticks = [];
|
|
this._gridLineItems = null;
|
|
this._labelItems = null;
|
|
this._labelSizes = null;
|
|
this._length = 0;
|
|
this._maxLength = 0;
|
|
this._longestTextCache = {};
|
|
this._startPixel = void 0;
|
|
this._endPixel = void 0;
|
|
this._reversePixels = false;
|
|
this._userMax = void 0;
|
|
this._userMin = void 0;
|
|
this._suggestedMax = void 0;
|
|
this._suggestedMin = void 0;
|
|
this._ticksLength = 0;
|
|
this._borderValue = 0;
|
|
this._cache = {};
|
|
this._dataLimitsCached = false;
|
|
this.$context = void 0;
|
|
}
|
|
init(options) {
|
|
this.options = options.setContext(this.getContext());
|
|
this.axis = options.axis;
|
|
this._userMin = this.parse(options.min);
|
|
this._userMax = this.parse(options.max);
|
|
this._suggestedMin = this.parse(options.suggestedMin);
|
|
this._suggestedMax = this.parse(options.suggestedMax);
|
|
}
|
|
parse(raw, index) {
|
|
return raw;
|
|
}
|
|
getUserBounds() {
|
|
let { _userMin, _userMax, _suggestedMin, _suggestedMax } = this;
|
|
_userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);
|
|
_userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);
|
|
_suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);
|
|
_suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);
|
|
return {
|
|
min: finiteOrDefault(_userMin, _suggestedMin),
|
|
max: finiteOrDefault(_userMax, _suggestedMax),
|
|
minDefined: isNumberFinite(_userMin),
|
|
maxDefined: isNumberFinite(_userMax)
|
|
};
|
|
}
|
|
getMinMax(canStack) {
|
|
let { min, max, minDefined, maxDefined } = this.getUserBounds();
|
|
let range;
|
|
if (minDefined && maxDefined) {
|
|
return {
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
const metas = this.getMatchingVisibleMetas();
|
|
for (let i2 = 0, ilen = metas.length; i2 < ilen; ++i2) {
|
|
range = metas[i2].controller.getMinMax(this, canStack);
|
|
if (!minDefined) {
|
|
min = Math.min(min, range.min);
|
|
}
|
|
if (!maxDefined) {
|
|
max = Math.max(max, range.max);
|
|
}
|
|
}
|
|
min = maxDefined && min > max ? max : min;
|
|
max = minDefined && min > max ? min : max;
|
|
return {
|
|
min: finiteOrDefault(min, finiteOrDefault(max, min)),
|
|
max: finiteOrDefault(max, finiteOrDefault(min, max))
|
|
};
|
|
}
|
|
getPadding() {
|
|
return {
|
|
left: this.paddingLeft || 0,
|
|
top: this.paddingTop || 0,
|
|
right: this.paddingRight || 0,
|
|
bottom: this.paddingBottom || 0
|
|
};
|
|
}
|
|
getTicks() {
|
|
return this.ticks;
|
|
}
|
|
getLabels() {
|
|
const data = this.chart.data;
|
|
return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
|
|
}
|
|
getLabelItems(chartArea = this.chart.chartArea) {
|
|
const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
|
|
return items;
|
|
}
|
|
beforeLayout() {
|
|
this._cache = {};
|
|
this._dataLimitsCached = false;
|
|
}
|
|
beforeUpdate() {
|
|
callback(this.options.beforeUpdate, [
|
|
this
|
|
]);
|
|
}
|
|
update(maxWidth, maxHeight, margins) {
|
|
const { beginAtZero, grace, ticks: tickOpts } = this.options;
|
|
const sampleSize = tickOpts.sampleSize;
|
|
this.beforeUpdate();
|
|
this.maxWidth = maxWidth;
|
|
this.maxHeight = maxHeight;
|
|
this._margins = margins = Object.assign({
|
|
left: 0,
|
|
right: 0,
|
|
top: 0,
|
|
bottom: 0
|
|
}, margins);
|
|
this.ticks = null;
|
|
this._labelSizes = null;
|
|
this._gridLineItems = null;
|
|
this._labelItems = null;
|
|
this.beforeSetDimensions();
|
|
this.setDimensions();
|
|
this.afterSetDimensions();
|
|
this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;
|
|
if (!this._dataLimitsCached) {
|
|
this.beforeDataLimits();
|
|
this.determineDataLimits();
|
|
this.afterDataLimits();
|
|
this._range = _addGrace(this, grace, beginAtZero);
|
|
this._dataLimitsCached = true;
|
|
}
|
|
this.beforeBuildTicks();
|
|
this.ticks = this.buildTicks() || [];
|
|
this.afterBuildTicks();
|
|
const samplingEnabled = sampleSize < this.ticks.length;
|
|
this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
|
|
this.configure();
|
|
this.beforeCalculateLabelRotation();
|
|
this.calculateLabelRotation();
|
|
this.afterCalculateLabelRotation();
|
|
if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === "auto")) {
|
|
this.ticks = autoSkip(this, this.ticks);
|
|
this._labelSizes = null;
|
|
this.afterAutoSkip();
|
|
}
|
|
if (samplingEnabled) {
|
|
this._convertTicksToLabels(this.ticks);
|
|
}
|
|
this.beforeFit();
|
|
this.fit();
|
|
this.afterFit();
|
|
this.afterUpdate();
|
|
}
|
|
configure() {
|
|
let reversePixels = this.options.reverse;
|
|
let startPixel, endPixel;
|
|
if (this.isHorizontal()) {
|
|
startPixel = this.left;
|
|
endPixel = this.right;
|
|
} else {
|
|
startPixel = this.top;
|
|
endPixel = this.bottom;
|
|
reversePixels = !reversePixels;
|
|
}
|
|
this._startPixel = startPixel;
|
|
this._endPixel = endPixel;
|
|
this._reversePixels = reversePixels;
|
|
this._length = endPixel - startPixel;
|
|
this._alignToPixels = this.options.alignToPixels;
|
|
}
|
|
afterUpdate() {
|
|
callback(this.options.afterUpdate, [
|
|
this
|
|
]);
|
|
}
|
|
beforeSetDimensions() {
|
|
callback(this.options.beforeSetDimensions, [
|
|
this
|
|
]);
|
|
}
|
|
setDimensions() {
|
|
if (this.isHorizontal()) {
|
|
this.width = this.maxWidth;
|
|
this.left = 0;
|
|
this.right = this.width;
|
|
} else {
|
|
this.height = this.maxHeight;
|
|
this.top = 0;
|
|
this.bottom = this.height;
|
|
}
|
|
this.paddingLeft = 0;
|
|
this.paddingTop = 0;
|
|
this.paddingRight = 0;
|
|
this.paddingBottom = 0;
|
|
}
|
|
afterSetDimensions() {
|
|
callback(this.options.afterSetDimensions, [
|
|
this
|
|
]);
|
|
}
|
|
_callHooks(name) {
|
|
this.chart.notifyPlugins(name, this.getContext());
|
|
callback(this.options[name], [
|
|
this
|
|
]);
|
|
}
|
|
beforeDataLimits() {
|
|
this._callHooks("beforeDataLimits");
|
|
}
|
|
determineDataLimits() {
|
|
}
|
|
afterDataLimits() {
|
|
this._callHooks("afterDataLimits");
|
|
}
|
|
beforeBuildTicks() {
|
|
this._callHooks("beforeBuildTicks");
|
|
}
|
|
buildTicks() {
|
|
return [];
|
|
}
|
|
afterBuildTicks() {
|
|
this._callHooks("afterBuildTicks");
|
|
}
|
|
beforeTickToLabelConversion() {
|
|
callback(this.options.beforeTickToLabelConversion, [
|
|
this
|
|
]);
|
|
}
|
|
generateTickLabels(ticks) {
|
|
const tickOpts = this.options.ticks;
|
|
let i2, ilen, tick;
|
|
for (i2 = 0, ilen = ticks.length; i2 < ilen; i2++) {
|
|
tick = ticks[i2];
|
|
tick.label = callback(tickOpts.callback, [
|
|
tick.value,
|
|
i2,
|
|
ticks
|
|
], this);
|
|
}
|
|
}
|
|
afterTickToLabelConversion() {
|
|
callback(this.options.afterTickToLabelConversion, [
|
|
this
|
|
]);
|
|
}
|
|
beforeCalculateLabelRotation() {
|
|
callback(this.options.beforeCalculateLabelRotation, [
|
|
this
|
|
]);
|
|
}
|
|
calculateLabelRotation() {
|
|
const options = this.options;
|
|
const tickOpts = options.ticks;
|
|
const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);
|
|
const minRotation = tickOpts.minRotation || 0;
|
|
const maxRotation = tickOpts.maxRotation;
|
|
let labelRotation = minRotation;
|
|
let tickWidth, maxHeight, maxLabelDiagonal;
|
|
if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
|
|
this.labelRotation = minRotation;
|
|
return;
|
|
}
|
|
const labelSizes = this._getLabelSizes();
|
|
const maxLabelWidth = labelSizes.widest.width;
|
|
const maxLabelHeight = labelSizes.highest.height;
|
|
const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth);
|
|
tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
|
|
if (maxLabelWidth + 6 > tickWidth) {
|
|
tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
|
|
maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
|
|
maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
|
|
labelRotation = toDegrees(Math.min(Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1))));
|
|
labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
|
|
}
|
|
this.labelRotation = labelRotation;
|
|
}
|
|
afterCalculateLabelRotation() {
|
|
callback(this.options.afterCalculateLabelRotation, [
|
|
this
|
|
]);
|
|
}
|
|
afterAutoSkip() {
|
|
}
|
|
beforeFit() {
|
|
callback(this.options.beforeFit, [
|
|
this
|
|
]);
|
|
}
|
|
fit() {
|
|
const minSize = {
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
const { chart, options: { ticks: tickOpts, title: titleOpts, grid: gridOpts } } = this;
|
|
const display = this._isVisible();
|
|
const isHorizontal = this.isHorizontal();
|
|
if (display) {
|
|
const titleHeight = getTitleHeight(titleOpts, chart.options.font);
|
|
if (isHorizontal) {
|
|
minSize.width = this.maxWidth;
|
|
minSize.height = getTickMarkLength(gridOpts) + titleHeight;
|
|
} else {
|
|
minSize.height = this.maxHeight;
|
|
minSize.width = getTickMarkLength(gridOpts) + titleHeight;
|
|
}
|
|
if (tickOpts.display && this.ticks.length) {
|
|
const { first, last, widest, highest } = this._getLabelSizes();
|
|
const tickPadding = tickOpts.padding * 2;
|
|
const angleRadians = toRadians(this.labelRotation);
|
|
const cos = Math.cos(angleRadians);
|
|
const sin = Math.sin(angleRadians);
|
|
if (isHorizontal) {
|
|
const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
|
|
minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
|
|
} else {
|
|
const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
|
|
minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
|
|
}
|
|
this._calculatePadding(first, last, sin, cos);
|
|
}
|
|
}
|
|
this._handleMargins();
|
|
if (isHorizontal) {
|
|
this.width = this._length = chart.width - this._margins.left - this._margins.right;
|
|
this.height = minSize.height;
|
|
} else {
|
|
this.width = minSize.width;
|
|
this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
|
|
}
|
|
}
|
|
_calculatePadding(first, last, sin, cos) {
|
|
const { ticks: { align, padding }, position } = this.options;
|
|
const isRotated = this.labelRotation !== 0;
|
|
const labelsBelowTicks = position !== "top" && this.axis === "x";
|
|
if (this.isHorizontal()) {
|
|
const offsetLeft = this.getPixelForTick(0) - this.left;
|
|
const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
|
|
let paddingLeft = 0;
|
|
let paddingRight = 0;
|
|
if (isRotated) {
|
|
if (labelsBelowTicks) {
|
|
paddingLeft = cos * first.width;
|
|
paddingRight = sin * last.height;
|
|
} else {
|
|
paddingLeft = sin * first.height;
|
|
paddingRight = cos * last.width;
|
|
}
|
|
} else if (align === "start") {
|
|
paddingRight = last.width;
|
|
} else if (align === "end") {
|
|
paddingLeft = first.width;
|
|
} else if (align !== "inner") {
|
|
paddingLeft = first.width / 2;
|
|
paddingRight = last.width / 2;
|
|
}
|
|
this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
|
|
this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
|
|
} else {
|
|
let paddingTop = last.height / 2;
|
|
let paddingBottom = first.height / 2;
|
|
if (align === "start") {
|
|
paddingTop = 0;
|
|
paddingBottom = first.height;
|
|
} else if (align === "end") {
|
|
paddingTop = last.height;
|
|
paddingBottom = 0;
|
|
}
|
|
this.paddingTop = paddingTop + padding;
|
|
this.paddingBottom = paddingBottom + padding;
|
|
}
|
|
}
|
|
_handleMargins() {
|
|
if (this._margins) {
|
|
this._margins.left = Math.max(this.paddingLeft, this._margins.left);
|
|
this._margins.top = Math.max(this.paddingTop, this._margins.top);
|
|
this._margins.right = Math.max(this.paddingRight, this._margins.right);
|
|
this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
|
|
}
|
|
}
|
|
afterFit() {
|
|
callback(this.options.afterFit, [
|
|
this
|
|
]);
|
|
}
|
|
isHorizontal() {
|
|
const { axis, position } = this.options;
|
|
return position === "top" || position === "bottom" || axis === "x";
|
|
}
|
|
isFullSize() {
|
|
return this.options.fullSize;
|
|
}
|
|
_convertTicksToLabels(ticks) {
|
|
this.beforeTickToLabelConversion();
|
|
this.generateTickLabels(ticks);
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = ticks.length; i2 < ilen; i2++) {
|
|
if (isNullOrUndef(ticks[i2].label)) {
|
|
ticks.splice(i2, 1);
|
|
ilen--;
|
|
i2--;
|
|
}
|
|
}
|
|
this.afterTickToLabelConversion();
|
|
}
|
|
_getLabelSizes() {
|
|
let labelSizes = this._labelSizes;
|
|
if (!labelSizes) {
|
|
const sampleSize = this.options.ticks.sampleSize;
|
|
let ticks = this.ticks;
|
|
if (sampleSize < ticks.length) {
|
|
ticks = sample(ticks, sampleSize);
|
|
}
|
|
this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);
|
|
}
|
|
return labelSizes;
|
|
}
|
|
_computeLabelSizes(ticks, length, maxTicksLimit) {
|
|
const { ctx, _longestTextCache: caches } = this;
|
|
const widths = [];
|
|
const heights = [];
|
|
const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));
|
|
let widestLabelSize = 0;
|
|
let highestLabelSize = 0;
|
|
let i2, j2, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
|
|
for (i2 = 0; i2 < length; i2 += increment) {
|
|
label = ticks[i2].label;
|
|
tickFont = this._resolveTickFontOptions(i2);
|
|
ctx.font = fontString = tickFont.string;
|
|
cache = caches[fontString] = caches[fontString] || {
|
|
data: {},
|
|
gc: []
|
|
};
|
|
lineHeight = tickFont.lineHeight;
|
|
width = height = 0;
|
|
if (!isNullOrUndef(label) && !isArray(label)) {
|
|
width = _measureText(ctx, cache.data, cache.gc, width, label);
|
|
height = lineHeight;
|
|
} else if (isArray(label)) {
|
|
for (j2 = 0, jlen = label.length; j2 < jlen; ++j2) {
|
|
nestedLabel = label[j2];
|
|
if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
|
|
width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);
|
|
height += lineHeight;
|
|
}
|
|
}
|
|
}
|
|
widths.push(width);
|
|
heights.push(height);
|
|
widestLabelSize = Math.max(width, widestLabelSize);
|
|
highestLabelSize = Math.max(height, highestLabelSize);
|
|
}
|
|
garbageCollect(caches, length);
|
|
const widest = widths.indexOf(widestLabelSize);
|
|
const highest = heights.indexOf(highestLabelSize);
|
|
const valueAt = (idx) => ({
|
|
width: widths[idx] || 0,
|
|
height: heights[idx] || 0
|
|
});
|
|
return {
|
|
first: valueAt(0),
|
|
last: valueAt(length - 1),
|
|
widest: valueAt(widest),
|
|
highest: valueAt(highest),
|
|
widths,
|
|
heights
|
|
};
|
|
}
|
|
getLabelForValue(value) {
|
|
return value;
|
|
}
|
|
getPixelForValue(value, index) {
|
|
return NaN;
|
|
}
|
|
getValueForPixel(pixel) {
|
|
}
|
|
getPixelForTick(index) {
|
|
const ticks = this.ticks;
|
|
if (index < 0 || index > ticks.length - 1) {
|
|
return null;
|
|
}
|
|
return this.getPixelForValue(ticks[index].value);
|
|
}
|
|
getPixelForDecimal(decimal) {
|
|
if (this._reversePixels) {
|
|
decimal = 1 - decimal;
|
|
}
|
|
const pixel = this._startPixel + decimal * this._length;
|
|
return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel);
|
|
}
|
|
getDecimalForPixel(pixel) {
|
|
const decimal = (pixel - this._startPixel) / this._length;
|
|
return this._reversePixels ? 1 - decimal : decimal;
|
|
}
|
|
getBasePixel() {
|
|
return this.getPixelForValue(this.getBaseValue());
|
|
}
|
|
getBaseValue() {
|
|
const { min, max } = this;
|
|
return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;
|
|
}
|
|
getContext(index) {
|
|
const ticks = this.ticks || [];
|
|
if (index >= 0 && index < ticks.length) {
|
|
const tick = ticks[index];
|
|
return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));
|
|
}
|
|
return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));
|
|
}
|
|
_tickSize() {
|
|
const optionTicks = this.options.ticks;
|
|
const rot = toRadians(this.labelRotation);
|
|
const cos = Math.abs(Math.cos(rot));
|
|
const sin = Math.abs(Math.sin(rot));
|
|
const labelSizes = this._getLabelSizes();
|
|
const padding = optionTicks.autoSkipPadding || 0;
|
|
const w2 = labelSizes ? labelSizes.widest.width + padding : 0;
|
|
const h6 = labelSizes ? labelSizes.highest.height + padding : 0;
|
|
return this.isHorizontal() ? h6 * cos > w2 * sin ? w2 / cos : h6 / sin : h6 * sin < w2 * cos ? h6 / cos : w2 / sin;
|
|
}
|
|
_isVisible() {
|
|
const display = this.options.display;
|
|
if (display !== "auto") {
|
|
return !!display;
|
|
}
|
|
return this.getMatchingVisibleMetas().length > 0;
|
|
}
|
|
_computeGridLineItems(chartArea) {
|
|
const axis = this.axis;
|
|
const chart = this.chart;
|
|
const options = this.options;
|
|
const { grid, position, border } = options;
|
|
const offset = grid.offset;
|
|
const isHorizontal = this.isHorizontal();
|
|
const ticks = this.ticks;
|
|
const ticksLength = ticks.length + (offset ? 1 : 0);
|
|
const tl = getTickMarkLength(grid);
|
|
const items = [];
|
|
const borderOpts = border.setContext(this.getContext());
|
|
const axisWidth = borderOpts.display ? borderOpts.width : 0;
|
|
const axisHalfWidth = axisWidth / 2;
|
|
const alignBorderValue = function(pixel) {
|
|
return _alignPixel(chart, pixel, axisWidth);
|
|
};
|
|
let borderValue, i2, lineValue, alignedLineValue;
|
|
let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
|
|
if (position === "top") {
|
|
borderValue = alignBorderValue(this.bottom);
|
|
ty1 = this.bottom - tl;
|
|
ty2 = borderValue - axisHalfWidth;
|
|
y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
|
|
y2 = chartArea.bottom;
|
|
} else if (position === "bottom") {
|
|
borderValue = alignBorderValue(this.top);
|
|
y1 = chartArea.top;
|
|
y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
|
|
ty1 = borderValue + axisHalfWidth;
|
|
ty2 = this.top + tl;
|
|
} else if (position === "left") {
|
|
borderValue = alignBorderValue(this.right);
|
|
tx1 = this.right - tl;
|
|
tx2 = borderValue - axisHalfWidth;
|
|
x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
|
|
x2 = chartArea.right;
|
|
} else if (position === "right") {
|
|
borderValue = alignBorderValue(this.left);
|
|
x1 = chartArea.left;
|
|
x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
|
|
tx1 = borderValue + axisHalfWidth;
|
|
tx2 = this.left + tl;
|
|
} else if (axis === "x") {
|
|
if (position === "center") {
|
|
borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
|
|
} else if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
|
|
}
|
|
y1 = chartArea.top;
|
|
y2 = chartArea.bottom;
|
|
ty1 = borderValue + axisHalfWidth;
|
|
ty2 = ty1 + tl;
|
|
} else if (axis === "y") {
|
|
if (position === "center") {
|
|
borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
|
|
} else if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
|
|
}
|
|
tx1 = borderValue - axisHalfWidth;
|
|
tx2 = tx1 - tl;
|
|
x1 = chartArea.left;
|
|
x2 = chartArea.right;
|
|
}
|
|
const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength);
|
|
const step = Math.max(1, Math.ceil(ticksLength / limit));
|
|
for (i2 = 0; i2 < ticksLength; i2 += step) {
|
|
const context = this.getContext(i2);
|
|
const optsAtIndex = grid.setContext(context);
|
|
const optsAtIndexBorder = border.setContext(context);
|
|
const lineWidth = optsAtIndex.lineWidth;
|
|
const lineColor = optsAtIndex.color;
|
|
const borderDash = optsAtIndexBorder.dash || [];
|
|
const borderDashOffset = optsAtIndexBorder.dashOffset;
|
|
const tickWidth = optsAtIndex.tickWidth;
|
|
const tickColor = optsAtIndex.tickColor;
|
|
const tickBorderDash = optsAtIndex.tickBorderDash || [];
|
|
const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
|
|
lineValue = getPixelForGridLine(this, i2, offset);
|
|
if (lineValue === void 0) {
|
|
continue;
|
|
}
|
|
alignedLineValue = _alignPixel(chart, lineValue, lineWidth);
|
|
if (isHorizontal) {
|
|
tx1 = tx2 = x1 = x2 = alignedLineValue;
|
|
} else {
|
|
ty1 = ty2 = y1 = y2 = alignedLineValue;
|
|
}
|
|
items.push({
|
|
tx1,
|
|
ty1,
|
|
tx2,
|
|
ty2,
|
|
x1,
|
|
y1,
|
|
x2,
|
|
y2,
|
|
width: lineWidth,
|
|
color: lineColor,
|
|
borderDash,
|
|
borderDashOffset,
|
|
tickWidth,
|
|
tickColor,
|
|
tickBorderDash,
|
|
tickBorderDashOffset
|
|
});
|
|
}
|
|
this._ticksLength = ticksLength;
|
|
this._borderValue = borderValue;
|
|
return items;
|
|
}
|
|
_computeLabelItems(chartArea) {
|
|
const axis = this.axis;
|
|
const options = this.options;
|
|
const { position, ticks: optionTicks } = options;
|
|
const isHorizontal = this.isHorizontal();
|
|
const ticks = this.ticks;
|
|
const { align, crossAlign, padding, mirror } = optionTicks;
|
|
const tl = getTickMarkLength(options.grid);
|
|
const tickAndPadding = tl + padding;
|
|
const hTickAndPadding = mirror ? -padding : tickAndPadding;
|
|
const rotation = -toRadians(this.labelRotation);
|
|
const items = [];
|
|
let i2, ilen, tick, label, x2, y2, textAlign, pixel, font, lineHeight, lineCount, textOffset;
|
|
let textBaseline = "middle";
|
|
if (position === "top") {
|
|
y2 = this.bottom - hTickAndPadding;
|
|
textAlign = this._getXAxisLabelAlignment();
|
|
} else if (position === "bottom") {
|
|
y2 = this.top + hTickAndPadding;
|
|
textAlign = this._getXAxisLabelAlignment();
|
|
} else if (position === "left") {
|
|
const ret = this._getYAxisLabelAlignment(tl);
|
|
textAlign = ret.textAlign;
|
|
x2 = ret.x;
|
|
} else if (position === "right") {
|
|
const ret = this._getYAxisLabelAlignment(tl);
|
|
textAlign = ret.textAlign;
|
|
x2 = ret.x;
|
|
} else if (axis === "x") {
|
|
if (position === "center") {
|
|
y2 = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;
|
|
} else if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
y2 = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
|
|
}
|
|
textAlign = this._getXAxisLabelAlignment();
|
|
} else if (axis === "y") {
|
|
if (position === "center") {
|
|
x2 = (chartArea.left + chartArea.right) / 2 - tickAndPadding;
|
|
} else if (isObject(position)) {
|
|
const positionAxisID = Object.keys(position)[0];
|
|
const value = position[positionAxisID];
|
|
x2 = this.chart.scales[positionAxisID].getPixelForValue(value);
|
|
}
|
|
textAlign = this._getYAxisLabelAlignment(tl).textAlign;
|
|
}
|
|
if (axis === "y") {
|
|
if (align === "start") {
|
|
textBaseline = "top";
|
|
} else if (align === "end") {
|
|
textBaseline = "bottom";
|
|
}
|
|
}
|
|
const labelSizes = this._getLabelSizes();
|
|
for (i2 = 0, ilen = ticks.length; i2 < ilen; ++i2) {
|
|
tick = ticks[i2];
|
|
label = tick.label;
|
|
const optsAtIndex = optionTicks.setContext(this.getContext(i2));
|
|
pixel = this.getPixelForTick(i2) + optionTicks.labelOffset;
|
|
font = this._resolveTickFontOptions(i2);
|
|
lineHeight = font.lineHeight;
|
|
lineCount = isArray(label) ? label.length : 1;
|
|
const halfCount = lineCount / 2;
|
|
const color2 = optsAtIndex.color;
|
|
const strokeColor = optsAtIndex.textStrokeColor;
|
|
const strokeWidth = optsAtIndex.textStrokeWidth;
|
|
let tickTextAlign = textAlign;
|
|
if (isHorizontal) {
|
|
x2 = pixel;
|
|
if (textAlign === "inner") {
|
|
if (i2 === ilen - 1) {
|
|
tickTextAlign = !this.options.reverse ? "right" : "left";
|
|
} else if (i2 === 0) {
|
|
tickTextAlign = !this.options.reverse ? "left" : "right";
|
|
} else {
|
|
tickTextAlign = "center";
|
|
}
|
|
}
|
|
if (position === "top") {
|
|
if (crossAlign === "near" || rotation !== 0) {
|
|
textOffset = -lineCount * lineHeight + lineHeight / 2;
|
|
} else if (crossAlign === "center") {
|
|
textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
|
|
} else {
|
|
textOffset = -labelSizes.highest.height + lineHeight / 2;
|
|
}
|
|
} else {
|
|
if (crossAlign === "near" || rotation !== 0) {
|
|
textOffset = lineHeight / 2;
|
|
} else if (crossAlign === "center") {
|
|
textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
|
|
} else {
|
|
textOffset = labelSizes.highest.height - lineCount * lineHeight;
|
|
}
|
|
}
|
|
if (mirror) {
|
|
textOffset *= -1;
|
|
}
|
|
if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {
|
|
x2 += lineHeight / 2 * Math.sin(rotation);
|
|
}
|
|
} else {
|
|
y2 = pixel;
|
|
textOffset = (1 - lineCount) * lineHeight / 2;
|
|
}
|
|
let backdrop;
|
|
if (optsAtIndex.showLabelBackdrop) {
|
|
const labelPadding = toPadding(optsAtIndex.backdropPadding);
|
|
const height = labelSizes.heights[i2];
|
|
const width = labelSizes.widths[i2];
|
|
let top = textOffset - labelPadding.top;
|
|
let left = 0 - labelPadding.left;
|
|
switch (textBaseline) {
|
|
case "middle":
|
|
top -= height / 2;
|
|
break;
|
|
case "bottom":
|
|
top -= height;
|
|
break;
|
|
}
|
|
switch (textAlign) {
|
|
case "center":
|
|
left -= width / 2;
|
|
break;
|
|
case "right":
|
|
left -= width;
|
|
break;
|
|
case "inner":
|
|
if (i2 === ilen - 1) {
|
|
left -= width;
|
|
} else if (i2 > 0) {
|
|
left -= width / 2;
|
|
}
|
|
break;
|
|
}
|
|
backdrop = {
|
|
left,
|
|
top,
|
|
width: width + labelPadding.width,
|
|
height: height + labelPadding.height,
|
|
color: optsAtIndex.backdropColor
|
|
};
|
|
}
|
|
items.push({
|
|
label,
|
|
font,
|
|
textOffset,
|
|
options: {
|
|
rotation,
|
|
color: color2,
|
|
strokeColor,
|
|
strokeWidth,
|
|
textAlign: tickTextAlign,
|
|
textBaseline,
|
|
translation: [
|
|
x2,
|
|
y2
|
|
],
|
|
backdrop
|
|
}
|
|
});
|
|
}
|
|
return items;
|
|
}
|
|
_getXAxisLabelAlignment() {
|
|
const { position, ticks } = this.options;
|
|
const rotation = -toRadians(this.labelRotation);
|
|
if (rotation) {
|
|
return position === "top" ? "left" : "right";
|
|
}
|
|
let align = "center";
|
|
if (ticks.align === "start") {
|
|
align = "left";
|
|
} else if (ticks.align === "end") {
|
|
align = "right";
|
|
} else if (ticks.align === "inner") {
|
|
align = "inner";
|
|
}
|
|
return align;
|
|
}
|
|
_getYAxisLabelAlignment(tl) {
|
|
const { position, ticks: { crossAlign, mirror, padding } } = this.options;
|
|
const labelSizes = this._getLabelSizes();
|
|
const tickAndPadding = tl + padding;
|
|
const widest = labelSizes.widest.width;
|
|
let textAlign;
|
|
let x2;
|
|
if (position === "left") {
|
|
if (mirror) {
|
|
x2 = this.right + padding;
|
|
if (crossAlign === "near") {
|
|
textAlign = "left";
|
|
} else if (crossAlign === "center") {
|
|
textAlign = "center";
|
|
x2 += widest / 2;
|
|
} else {
|
|
textAlign = "right";
|
|
x2 += widest;
|
|
}
|
|
} else {
|
|
x2 = this.right - tickAndPadding;
|
|
if (crossAlign === "near") {
|
|
textAlign = "right";
|
|
} else if (crossAlign === "center") {
|
|
textAlign = "center";
|
|
x2 -= widest / 2;
|
|
} else {
|
|
textAlign = "left";
|
|
x2 = this.left;
|
|
}
|
|
}
|
|
} else if (position === "right") {
|
|
if (mirror) {
|
|
x2 = this.left + padding;
|
|
if (crossAlign === "near") {
|
|
textAlign = "right";
|
|
} else if (crossAlign === "center") {
|
|
textAlign = "center";
|
|
x2 -= widest / 2;
|
|
} else {
|
|
textAlign = "left";
|
|
x2 -= widest;
|
|
}
|
|
} else {
|
|
x2 = this.left + tickAndPadding;
|
|
if (crossAlign === "near") {
|
|
textAlign = "left";
|
|
} else if (crossAlign === "center") {
|
|
textAlign = "center";
|
|
x2 += widest / 2;
|
|
} else {
|
|
textAlign = "right";
|
|
x2 = this.right;
|
|
}
|
|
}
|
|
} else {
|
|
textAlign = "right";
|
|
}
|
|
return {
|
|
textAlign,
|
|
x: x2
|
|
};
|
|
}
|
|
_computeLabelArea() {
|
|
if (this.options.ticks.mirror) {
|
|
return;
|
|
}
|
|
const chart = this.chart;
|
|
const position = this.options.position;
|
|
if (position === "left" || position === "right") {
|
|
return {
|
|
top: 0,
|
|
left: this.left,
|
|
bottom: chart.height,
|
|
right: this.right
|
|
};
|
|
}
|
|
if (position === "top" || position === "bottom") {
|
|
return {
|
|
top: this.top,
|
|
left: 0,
|
|
bottom: this.bottom,
|
|
right: chart.width
|
|
};
|
|
}
|
|
}
|
|
drawBackground() {
|
|
const { ctx, options: { backgroundColor }, left, top, width, height } = this;
|
|
if (backgroundColor) {
|
|
ctx.save();
|
|
ctx.fillStyle = backgroundColor;
|
|
ctx.fillRect(left, top, width, height);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
getLineWidthForValue(value) {
|
|
const grid = this.options.grid;
|
|
if (!this._isVisible() || !grid.display) {
|
|
return 0;
|
|
}
|
|
const ticks = this.ticks;
|
|
const index = ticks.findIndex((t3) => t3.value === value);
|
|
if (index >= 0) {
|
|
const opts = grid.setContext(this.getContext(index));
|
|
return opts.lineWidth;
|
|
}
|
|
return 0;
|
|
}
|
|
drawGrid(chartArea) {
|
|
const grid = this.options.grid;
|
|
const ctx = this.ctx;
|
|
const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
|
|
let i2, ilen;
|
|
const drawLine = (p1, p2, style) => {
|
|
if (!style.width || !style.color) {
|
|
return;
|
|
}
|
|
ctx.save();
|
|
ctx.lineWidth = style.width;
|
|
ctx.strokeStyle = style.color;
|
|
ctx.setLineDash(style.borderDash || []);
|
|
ctx.lineDashOffset = style.borderDashOffset;
|
|
ctx.beginPath();
|
|
ctx.moveTo(p1.x, p1.y);
|
|
ctx.lineTo(p2.x, p2.y);
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
};
|
|
if (grid.display) {
|
|
for (i2 = 0, ilen = items.length; i2 < ilen; ++i2) {
|
|
const item = items[i2];
|
|
if (grid.drawOnChartArea) {
|
|
drawLine({
|
|
x: item.x1,
|
|
y: item.y1
|
|
}, {
|
|
x: item.x2,
|
|
y: item.y2
|
|
}, item);
|
|
}
|
|
if (grid.drawTicks) {
|
|
drawLine({
|
|
x: item.tx1,
|
|
y: item.ty1
|
|
}, {
|
|
x: item.tx2,
|
|
y: item.ty2
|
|
}, {
|
|
color: item.tickColor,
|
|
width: item.tickWidth,
|
|
borderDash: item.tickBorderDash,
|
|
borderDashOffset: item.tickBorderDashOffset
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
drawBorder() {
|
|
const { chart, ctx, options: { border, grid } } = this;
|
|
const borderOpts = border.setContext(this.getContext());
|
|
const axisWidth = border.display ? borderOpts.width : 0;
|
|
if (!axisWidth) {
|
|
return;
|
|
}
|
|
const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
|
|
const borderValue = this._borderValue;
|
|
let x1, x2, y1, y2;
|
|
if (this.isHorizontal()) {
|
|
x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2;
|
|
x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2;
|
|
y1 = y2 = borderValue;
|
|
} else {
|
|
y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2;
|
|
y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
|
|
x1 = x2 = borderValue;
|
|
}
|
|
ctx.save();
|
|
ctx.lineWidth = borderOpts.width;
|
|
ctx.strokeStyle = borderOpts.color;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x1, y1);
|
|
ctx.lineTo(x2, y2);
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
}
|
|
drawLabels(chartArea) {
|
|
const optionTicks = this.options.ticks;
|
|
if (!optionTicks.display) {
|
|
return;
|
|
}
|
|
const ctx = this.ctx;
|
|
const area = this._computeLabelArea();
|
|
if (area) {
|
|
clipArea(ctx, area);
|
|
}
|
|
const items = this.getLabelItems(chartArea);
|
|
for (const item of items) {
|
|
const renderTextOptions = item.options;
|
|
const tickFont = item.font;
|
|
const label = item.label;
|
|
const y2 = item.textOffset;
|
|
renderText(ctx, label, 0, y2, tickFont, renderTextOptions);
|
|
}
|
|
if (area) {
|
|
unclipArea(ctx);
|
|
}
|
|
}
|
|
drawTitle() {
|
|
const { ctx, options: { position, title, reverse } } = this;
|
|
if (!title.display) {
|
|
return;
|
|
}
|
|
const font = toFont(title.font);
|
|
const padding = toPadding(title.padding);
|
|
const align = title.align;
|
|
let offset = font.lineHeight / 2;
|
|
if (position === "bottom" || position === "center" || isObject(position)) {
|
|
offset += padding.bottom;
|
|
if (isArray(title.text)) {
|
|
offset += font.lineHeight * (title.text.length - 1);
|
|
}
|
|
} else {
|
|
offset += padding.top;
|
|
}
|
|
const { titleX, titleY, maxWidth, rotation } = titleArgs(this, offset, position, align);
|
|
renderText(ctx, title.text, 0, 0, font, {
|
|
color: title.color,
|
|
maxWidth,
|
|
rotation,
|
|
textAlign: titleAlign(align, position, reverse),
|
|
textBaseline: "middle",
|
|
translation: [
|
|
titleX,
|
|
titleY
|
|
]
|
|
});
|
|
}
|
|
draw(chartArea) {
|
|
if (!this._isVisible()) {
|
|
return;
|
|
}
|
|
this.drawBackground();
|
|
this.drawGrid(chartArea);
|
|
this.drawBorder();
|
|
this.drawTitle();
|
|
this.drawLabels(chartArea);
|
|
}
|
|
_layers() {
|
|
const opts = this.options;
|
|
const tz = opts.ticks && opts.ticks.z || 0;
|
|
const gz = valueOrDefault(opts.grid && opts.grid.z, -1);
|
|
const bz = valueOrDefault(opts.border && opts.border.z, 0);
|
|
if (!this._isVisible() || this.draw !== _Scale.prototype.draw) {
|
|
return [
|
|
{
|
|
z: tz,
|
|
draw: (chartArea) => {
|
|
this.draw(chartArea);
|
|
}
|
|
}
|
|
];
|
|
}
|
|
return [
|
|
{
|
|
z: gz,
|
|
draw: (chartArea) => {
|
|
this.drawBackground();
|
|
this.drawGrid(chartArea);
|
|
this.drawTitle();
|
|
}
|
|
},
|
|
{
|
|
z: bz,
|
|
draw: () => {
|
|
this.drawBorder();
|
|
}
|
|
},
|
|
{
|
|
z: tz,
|
|
draw: (chartArea) => {
|
|
this.drawLabels(chartArea);
|
|
}
|
|
}
|
|
];
|
|
}
|
|
getMatchingVisibleMetas(type) {
|
|
const metas = this.chart.getSortedVisibleDatasetMetas();
|
|
const axisID = this.axis + "AxisID";
|
|
const result = [];
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = metas.length; i2 < ilen; ++i2) {
|
|
const meta = metas[i2];
|
|
if (meta[axisID] === this.id && (!type || meta.type === type)) {
|
|
result.push(meta);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
_resolveTickFontOptions(index) {
|
|
const opts = this.options.ticks.setContext(this.getContext(index));
|
|
return toFont(opts.font);
|
|
}
|
|
_maxDigits() {
|
|
const fontSize = this._resolveTickFontOptions(0).lineHeight;
|
|
return (this.isHorizontal() ? this.width : this.height) / fontSize;
|
|
}
|
|
};
|
|
var TypedRegistry = class {
|
|
constructor(type, scope, override) {
|
|
this.type = type;
|
|
this.scope = scope;
|
|
this.override = override;
|
|
this.items = /* @__PURE__ */ Object.create(null);
|
|
}
|
|
isForType(type) {
|
|
return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
|
|
}
|
|
register(item) {
|
|
const proto = Object.getPrototypeOf(item);
|
|
let parentScope;
|
|
if (isIChartComponent(proto)) {
|
|
parentScope = this.register(proto);
|
|
}
|
|
const items = this.items;
|
|
const id = item.id;
|
|
const scope = this.scope + "." + id;
|
|
if (!id) {
|
|
throw new Error("class does not have id: " + item);
|
|
}
|
|
if (id in items) {
|
|
return scope;
|
|
}
|
|
items[id] = item;
|
|
registerDefaults(item, scope, parentScope);
|
|
if (this.override) {
|
|
defaults2.override(item.id, item.overrides);
|
|
}
|
|
return scope;
|
|
}
|
|
get(id) {
|
|
return this.items[id];
|
|
}
|
|
unregister(item) {
|
|
const items = this.items;
|
|
const id = item.id;
|
|
const scope = this.scope;
|
|
if (id in items) {
|
|
delete items[id];
|
|
}
|
|
if (scope && id in defaults2[scope]) {
|
|
delete defaults2[scope][id];
|
|
if (this.override) {
|
|
delete overrides[id];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function registerDefaults(item, scope, parentScope) {
|
|
const itemDefaults = merge(/* @__PURE__ */ Object.create(null), [
|
|
parentScope ? defaults2.get(parentScope) : {},
|
|
defaults2.get(scope),
|
|
item.defaults
|
|
]);
|
|
defaults2.set(scope, itemDefaults);
|
|
if (item.defaultRoutes) {
|
|
routeDefaults(scope, item.defaultRoutes);
|
|
}
|
|
if (item.descriptors) {
|
|
defaults2.describe(scope, item.descriptors);
|
|
}
|
|
}
|
|
function routeDefaults(scope, routes) {
|
|
Object.keys(routes).forEach((property) => {
|
|
const propertyParts = property.split(".");
|
|
const sourceName = propertyParts.pop();
|
|
const sourceScope = [
|
|
scope
|
|
].concat(propertyParts).join(".");
|
|
const parts = routes[property].split(".");
|
|
const targetName = parts.pop();
|
|
const targetScope = parts.join(".");
|
|
defaults2.route(sourceScope, sourceName, targetScope, targetName);
|
|
});
|
|
}
|
|
function isIChartComponent(proto) {
|
|
return "id" in proto && "defaults" in proto;
|
|
}
|
|
var Registry = class {
|
|
constructor() {
|
|
this.controllers = new TypedRegistry(DatasetController, "datasets", true);
|
|
this.elements = new TypedRegistry(Element, "elements");
|
|
this.plugins = new TypedRegistry(Object, "plugins");
|
|
this.scales = new TypedRegistry(Scale, "scales");
|
|
this._typedRegistries = [
|
|
this.controllers,
|
|
this.scales,
|
|
this.elements
|
|
];
|
|
}
|
|
add(...args) {
|
|
this._each("register", args);
|
|
}
|
|
remove(...args) {
|
|
this._each("unregister", args);
|
|
}
|
|
addControllers(...args) {
|
|
this._each("register", args, this.controllers);
|
|
}
|
|
addElements(...args) {
|
|
this._each("register", args, this.elements);
|
|
}
|
|
addPlugins(...args) {
|
|
this._each("register", args, this.plugins);
|
|
}
|
|
addScales(...args) {
|
|
this._each("register", args, this.scales);
|
|
}
|
|
getController(id) {
|
|
return this._get(id, this.controllers, "controller");
|
|
}
|
|
getElement(id) {
|
|
return this._get(id, this.elements, "element");
|
|
}
|
|
getPlugin(id) {
|
|
return this._get(id, this.plugins, "plugin");
|
|
}
|
|
getScale(id) {
|
|
return this._get(id, this.scales, "scale");
|
|
}
|
|
removeControllers(...args) {
|
|
this._each("unregister", args, this.controllers);
|
|
}
|
|
removeElements(...args) {
|
|
this._each("unregister", args, this.elements);
|
|
}
|
|
removePlugins(...args) {
|
|
this._each("unregister", args, this.plugins);
|
|
}
|
|
removeScales(...args) {
|
|
this._each("unregister", args, this.scales);
|
|
}
|
|
_each(method, args, typedRegistry) {
|
|
[
|
|
...args
|
|
].forEach((arg) => {
|
|
const reg = typedRegistry || this._getRegistryForType(arg);
|
|
if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {
|
|
this._exec(method, reg, arg);
|
|
} else {
|
|
each(arg, (item) => {
|
|
const itemReg = typedRegistry || this._getRegistryForType(item);
|
|
this._exec(method, itemReg, item);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
_exec(method, registry2, component) {
|
|
const camelMethod = _capitalize(method);
|
|
callback(component["before" + camelMethod], [], component);
|
|
registry2[method](component);
|
|
callback(component["after" + camelMethod], [], component);
|
|
}
|
|
_getRegistryForType(type) {
|
|
for (let i2 = 0; i2 < this._typedRegistries.length; i2++) {
|
|
const reg = this._typedRegistries[i2];
|
|
if (reg.isForType(type)) {
|
|
return reg;
|
|
}
|
|
}
|
|
return this.plugins;
|
|
}
|
|
_get(id, typedRegistry, type) {
|
|
const item = typedRegistry.get(id);
|
|
if (item === void 0) {
|
|
throw new Error('"' + id + '" is not a registered ' + type + ".");
|
|
}
|
|
return item;
|
|
}
|
|
};
|
|
var registry = /* @__PURE__ */ new Registry();
|
|
var PluginService = class {
|
|
constructor() {
|
|
this._init = [];
|
|
}
|
|
notify(chart, hook, args, filter2) {
|
|
if (hook === "beforeInit") {
|
|
this._init = this._createDescriptors(chart, true);
|
|
this._notify(this._init, chart, "install");
|
|
}
|
|
const descriptors2 = filter2 ? this._descriptors(chart).filter(filter2) : this._descriptors(chart);
|
|
const result = this._notify(descriptors2, chart, hook, args);
|
|
if (hook === "afterDestroy") {
|
|
this._notify(descriptors2, chart, "stop");
|
|
this._notify(this._init, chart, "uninstall");
|
|
}
|
|
return result;
|
|
}
|
|
_notify(descriptors2, chart, hook, args) {
|
|
args = args || {};
|
|
for (const descriptor of descriptors2) {
|
|
const plugin = descriptor.plugin;
|
|
const method = plugin[hook];
|
|
const params = [
|
|
chart,
|
|
args,
|
|
descriptor.options
|
|
];
|
|
if (callback(method, params, plugin) === false && args.cancelable) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
invalidate() {
|
|
if (!isNullOrUndef(this._cache)) {
|
|
this._oldCache = this._cache;
|
|
this._cache = void 0;
|
|
}
|
|
}
|
|
_descriptors(chart) {
|
|
if (this._cache) {
|
|
return this._cache;
|
|
}
|
|
const descriptors2 = this._cache = this._createDescriptors(chart);
|
|
this._notifyStateChanges(chart);
|
|
return descriptors2;
|
|
}
|
|
_createDescriptors(chart, all) {
|
|
const config = chart && chart.config;
|
|
const options = valueOrDefault(config.options && config.options.plugins, {});
|
|
const plugins = allPlugins(config);
|
|
return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
|
|
}
|
|
_notifyStateChanges(chart) {
|
|
const previousDescriptors = this._oldCache || [];
|
|
const descriptors2 = this._cache;
|
|
const diff = (a2, b2) => a2.filter((x2) => !b2.some((y2) => x2.plugin.id === y2.plugin.id));
|
|
this._notify(diff(previousDescriptors, descriptors2), chart, "stop");
|
|
this._notify(diff(descriptors2, previousDescriptors), chart, "start");
|
|
}
|
|
};
|
|
function allPlugins(config) {
|
|
const localIds = {};
|
|
const plugins = [];
|
|
const keys = Object.keys(registry.plugins.items);
|
|
for (let i2 = 0; i2 < keys.length; i2++) {
|
|
plugins.push(registry.getPlugin(keys[i2]));
|
|
}
|
|
const local = config.plugins || [];
|
|
for (let i2 = 0; i2 < local.length; i2++) {
|
|
const plugin = local[i2];
|
|
if (plugins.indexOf(plugin) === -1) {
|
|
plugins.push(plugin);
|
|
localIds[plugin.id] = true;
|
|
}
|
|
}
|
|
return {
|
|
plugins,
|
|
localIds
|
|
};
|
|
}
|
|
function getOpts(options, all) {
|
|
if (!all && options === false) {
|
|
return null;
|
|
}
|
|
if (options === true) {
|
|
return {};
|
|
}
|
|
return options;
|
|
}
|
|
function createDescriptors(chart, { plugins, localIds }, options, all) {
|
|
const result = [];
|
|
const context = chart.getContext();
|
|
for (const plugin of plugins) {
|
|
const id = plugin.id;
|
|
const opts = getOpts(options[id], all);
|
|
if (opts === null) {
|
|
continue;
|
|
}
|
|
result.push({
|
|
plugin,
|
|
options: pluginOpts(chart.config, {
|
|
plugin,
|
|
local: localIds[id]
|
|
}, opts, context)
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
function pluginOpts(config, { plugin, local }, opts, context) {
|
|
const keys = config.pluginScopeKeys(plugin);
|
|
const scopes = config.getOptionScopes(opts, keys);
|
|
if (local && plugin.defaults) {
|
|
scopes.push(plugin.defaults);
|
|
}
|
|
return config.createResolver(scopes, context, [
|
|
""
|
|
], {
|
|
scriptable: false,
|
|
indexable: false,
|
|
allKeys: true
|
|
});
|
|
}
|
|
function getIndexAxis(type, options) {
|
|
const datasetDefaults = defaults2.datasets[type] || {};
|
|
const datasetOptions = (options.datasets || {})[type] || {};
|
|
return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || "x";
|
|
}
|
|
function getAxisFromDefaultScaleID(id, indexAxis) {
|
|
let axis = id;
|
|
if (id === "_index_") {
|
|
axis = indexAxis;
|
|
} else if (id === "_value_") {
|
|
axis = indexAxis === "x" ? "y" : "x";
|
|
}
|
|
return axis;
|
|
}
|
|
function getDefaultScaleIDFromAxis(axis, indexAxis) {
|
|
return axis === indexAxis ? "_index_" : "_value_";
|
|
}
|
|
function idMatchesAxis(id) {
|
|
if (id === "x" || id === "y" || id === "r") {
|
|
return id;
|
|
}
|
|
}
|
|
function axisFromPosition(position) {
|
|
if (position === "top" || position === "bottom") {
|
|
return "x";
|
|
}
|
|
if (position === "left" || position === "right") {
|
|
return "y";
|
|
}
|
|
}
|
|
function determineAxis(id, ...scaleOptions) {
|
|
if (idMatchesAxis(id)) {
|
|
return id;
|
|
}
|
|
for (const opts of scaleOptions) {
|
|
const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());
|
|
if (axis) {
|
|
return axis;
|
|
}
|
|
}
|
|
throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
|
|
}
|
|
function getAxisFromDataset(id, axis, dataset) {
|
|
if (dataset[axis + "AxisID"] === id) {
|
|
return {
|
|
axis
|
|
};
|
|
}
|
|
}
|
|
function retrieveAxisFromDatasets(id, config) {
|
|
if (config.data && config.data.datasets) {
|
|
const boundDs = config.data.datasets.filter((d2) => d2.xAxisID === id || d2.yAxisID === id);
|
|
if (boundDs.length) {
|
|
return getAxisFromDataset(id, "x", boundDs[0]) || getAxisFromDataset(id, "y", boundDs[0]);
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
function mergeScaleConfig(config, options) {
|
|
const chartDefaults = overrides[config.type] || {
|
|
scales: {}
|
|
};
|
|
const configScales = options.scales || {};
|
|
const chartIndexAxis = getIndexAxis(config.type, options);
|
|
const scales = /* @__PURE__ */ Object.create(null);
|
|
Object.keys(configScales).forEach((id) => {
|
|
const scaleConf = configScales[id];
|
|
if (!isObject(scaleConf)) {
|
|
return console.error(`Invalid scale configuration for scale: ${id}`);
|
|
}
|
|
if (scaleConf._proxy) {
|
|
return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
|
|
}
|
|
const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), defaults2.scales[scaleConf.type]);
|
|
const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
|
|
const defaultScaleOptions = chartDefaults.scales || {};
|
|
scales[id] = mergeIf(/* @__PURE__ */ Object.create(null), [
|
|
{
|
|
axis
|
|
},
|
|
scaleConf,
|
|
defaultScaleOptions[axis],
|
|
defaultScaleOptions[defaultId]
|
|
]);
|
|
});
|
|
config.data.datasets.forEach((dataset) => {
|
|
const type = dataset.type || config.type;
|
|
const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
|
|
const datasetDefaults = overrides[type] || {};
|
|
const defaultScaleOptions = datasetDefaults.scales || {};
|
|
Object.keys(defaultScaleOptions).forEach((defaultID) => {
|
|
const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
|
|
const id = dataset[axis + "AxisID"] || axis;
|
|
scales[id] = scales[id] || /* @__PURE__ */ Object.create(null);
|
|
mergeIf(scales[id], [
|
|
{
|
|
axis
|
|
},
|
|
configScales[id],
|
|
defaultScaleOptions[defaultID]
|
|
]);
|
|
});
|
|
});
|
|
Object.keys(scales).forEach((key) => {
|
|
const scale = scales[key];
|
|
mergeIf(scale, [
|
|
defaults2.scales[scale.type],
|
|
defaults2.scale
|
|
]);
|
|
});
|
|
return scales;
|
|
}
|
|
function initOptions(config) {
|
|
const options = config.options || (config.options = {});
|
|
options.plugins = valueOrDefault(options.plugins, {});
|
|
options.scales = mergeScaleConfig(config, options);
|
|
}
|
|
function initData(data) {
|
|
data = data || {};
|
|
data.datasets = data.datasets || [];
|
|
data.labels = data.labels || [];
|
|
return data;
|
|
}
|
|
function initConfig(config) {
|
|
config = config || {};
|
|
config.data = initData(config.data);
|
|
initOptions(config);
|
|
return config;
|
|
}
|
|
var keyCache = /* @__PURE__ */ new Map();
|
|
var keysCached = /* @__PURE__ */ new Set();
|
|
function cachedKeys(cacheKey, generate) {
|
|
let keys = keyCache.get(cacheKey);
|
|
if (!keys) {
|
|
keys = generate();
|
|
keyCache.set(cacheKey, keys);
|
|
keysCached.add(keys);
|
|
}
|
|
return keys;
|
|
}
|
|
var addIfFound = (set2, obj, key) => {
|
|
const opts = resolveObjectKey(obj, key);
|
|
if (opts !== void 0) {
|
|
set2.add(opts);
|
|
}
|
|
};
|
|
var Config = class {
|
|
constructor(config) {
|
|
this._config = initConfig(config);
|
|
this._scopeCache = /* @__PURE__ */ new Map();
|
|
this._resolverCache = /* @__PURE__ */ new Map();
|
|
}
|
|
get platform() {
|
|
return this._config.platform;
|
|
}
|
|
get type() {
|
|
return this._config.type;
|
|
}
|
|
set type(type) {
|
|
this._config.type = type;
|
|
}
|
|
get data() {
|
|
return this._config.data;
|
|
}
|
|
set data(data) {
|
|
this._config.data = initData(data);
|
|
}
|
|
get options() {
|
|
return this._config.options;
|
|
}
|
|
set options(options) {
|
|
this._config.options = options;
|
|
}
|
|
get plugins() {
|
|
return this._config.plugins;
|
|
}
|
|
update() {
|
|
const config = this._config;
|
|
this.clearCache();
|
|
initOptions(config);
|
|
}
|
|
clearCache() {
|
|
this._scopeCache.clear();
|
|
this._resolverCache.clear();
|
|
}
|
|
datasetScopeKeys(datasetType) {
|
|
return cachedKeys(datasetType, () => [
|
|
[
|
|
`datasets.${datasetType}`,
|
|
""
|
|
]
|
|
]);
|
|
}
|
|
datasetAnimationScopeKeys(datasetType, transition) {
|
|
return cachedKeys(`${datasetType}.transition.${transition}`, () => [
|
|
[
|
|
`datasets.${datasetType}.transitions.${transition}`,
|
|
`transitions.${transition}`
|
|
],
|
|
[
|
|
`datasets.${datasetType}`,
|
|
""
|
|
]
|
|
]);
|
|
}
|
|
datasetElementScopeKeys(datasetType, elementType) {
|
|
return cachedKeys(`${datasetType}-${elementType}`, () => [
|
|
[
|
|
`datasets.${datasetType}.elements.${elementType}`,
|
|
`datasets.${datasetType}`,
|
|
`elements.${elementType}`,
|
|
""
|
|
]
|
|
]);
|
|
}
|
|
pluginScopeKeys(plugin) {
|
|
const id = plugin.id;
|
|
const type = this.type;
|
|
return cachedKeys(`${type}-plugin-${id}`, () => [
|
|
[
|
|
`plugins.${id}`,
|
|
...plugin.additionalOptionScopes || []
|
|
]
|
|
]);
|
|
}
|
|
_cachedScopes(mainScope, resetCache) {
|
|
const _scopeCache = this._scopeCache;
|
|
let cache = _scopeCache.get(mainScope);
|
|
if (!cache || resetCache) {
|
|
cache = /* @__PURE__ */ new Map();
|
|
_scopeCache.set(mainScope, cache);
|
|
}
|
|
return cache;
|
|
}
|
|
getOptionScopes(mainScope, keyLists, resetCache) {
|
|
const { options, type } = this;
|
|
const cache = this._cachedScopes(mainScope, resetCache);
|
|
const cached = cache.get(keyLists);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
const scopes = /* @__PURE__ */ new Set();
|
|
keyLists.forEach((keys) => {
|
|
if (mainScope) {
|
|
scopes.add(mainScope);
|
|
keys.forEach((key) => addIfFound(scopes, mainScope, key));
|
|
}
|
|
keys.forEach((key) => addIfFound(scopes, options, key));
|
|
keys.forEach((key) => addIfFound(scopes, overrides[type] || {}, key));
|
|
keys.forEach((key) => addIfFound(scopes, defaults2, key));
|
|
keys.forEach((key) => addIfFound(scopes, descriptors, key));
|
|
});
|
|
const array = Array.from(scopes);
|
|
if (array.length === 0) {
|
|
array.push(/* @__PURE__ */ Object.create(null));
|
|
}
|
|
if (keysCached.has(keyLists)) {
|
|
cache.set(keyLists, array);
|
|
}
|
|
return array;
|
|
}
|
|
chartOptionScopes() {
|
|
const { options, type } = this;
|
|
return [
|
|
options,
|
|
overrides[type] || {},
|
|
defaults2.datasets[type] || {},
|
|
{
|
|
type
|
|
},
|
|
defaults2,
|
|
descriptors
|
|
];
|
|
}
|
|
resolveNamedOptions(scopes, names2, context, prefixes = [
|
|
""
|
|
]) {
|
|
const result = {
|
|
$shared: true
|
|
};
|
|
const { resolver, subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);
|
|
let options = resolver;
|
|
if (needContext(resolver, names2)) {
|
|
result.$shared = false;
|
|
context = isFunction(context) ? context() : context;
|
|
const subResolver = this.createResolver(scopes, context, subPrefixes);
|
|
options = _attachContext(resolver, context, subResolver);
|
|
}
|
|
for (const prop of names2) {
|
|
result[prop] = options[prop];
|
|
}
|
|
return result;
|
|
}
|
|
createResolver(scopes, context, prefixes = [
|
|
""
|
|
], descriptorDefaults) {
|
|
const { resolver } = getResolver(this._resolverCache, scopes, prefixes);
|
|
return isObject(context) ? _attachContext(resolver, context, void 0, descriptorDefaults) : resolver;
|
|
}
|
|
};
|
|
function getResolver(resolverCache, scopes, prefixes) {
|
|
let cache = resolverCache.get(scopes);
|
|
if (!cache) {
|
|
cache = /* @__PURE__ */ new Map();
|
|
resolverCache.set(scopes, cache);
|
|
}
|
|
const cacheKey = prefixes.join();
|
|
let cached = cache.get(cacheKey);
|
|
if (!cached) {
|
|
const resolver = _createResolver(scopes, prefixes);
|
|
cached = {
|
|
resolver,
|
|
subPrefixes: prefixes.filter((p2) => !p2.toLowerCase().includes("hover"))
|
|
};
|
|
cache.set(cacheKey, cached);
|
|
}
|
|
return cached;
|
|
}
|
|
var hasFunction = (value) => isObject(value) && Object.getOwnPropertyNames(value).some((key) => isFunction(value[key]));
|
|
function needContext(proxy, names2) {
|
|
const { isScriptable, isIndexable } = _descriptors(proxy);
|
|
for (const prop of names2) {
|
|
const scriptable = isScriptable(prop);
|
|
const indexable = isIndexable(prop);
|
|
const value = (indexable || scriptable) && proxy[prop];
|
|
if (scriptable && (isFunction(value) || hasFunction(value)) || indexable && isArray(value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
var version = "4.4.4";
|
|
var KNOWN_POSITIONS = [
|
|
"top",
|
|
"bottom",
|
|
"left",
|
|
"right",
|
|
"chartArea"
|
|
];
|
|
function positionIsHorizontal(position, axis) {
|
|
return position === "top" || position === "bottom" || KNOWN_POSITIONS.indexOf(position) === -1 && axis === "x";
|
|
}
|
|
function compare2Level(l1, l2) {
|
|
return function(a2, b2) {
|
|
return a2[l1] === b2[l1] ? a2[l2] - b2[l2] : a2[l1] - b2[l1];
|
|
};
|
|
}
|
|
function onAnimationsComplete(context) {
|
|
const chart = context.chart;
|
|
const animationOptions = chart.options.animation;
|
|
chart.notifyPlugins("afterRender");
|
|
callback(animationOptions && animationOptions.onComplete, [
|
|
context
|
|
], chart);
|
|
}
|
|
function onAnimationProgress(context) {
|
|
const chart = context.chart;
|
|
const animationOptions = chart.options.animation;
|
|
callback(animationOptions && animationOptions.onProgress, [
|
|
context
|
|
], chart);
|
|
}
|
|
function getCanvas(item) {
|
|
if (_isDomSupported() && typeof item === "string") {
|
|
item = document.getElementById(item);
|
|
} else if (item && item.length) {
|
|
item = item[0];
|
|
}
|
|
if (item && item.canvas) {
|
|
item = item.canvas;
|
|
}
|
|
return item;
|
|
}
|
|
var instances = {};
|
|
var getChart = (key) => {
|
|
const canvas = getCanvas(key);
|
|
return Object.values(instances).filter((c2) => c2.canvas === canvas).pop();
|
|
};
|
|
function moveNumericKeys(obj, start, move) {
|
|
const keys = Object.keys(obj);
|
|
for (const key of keys) {
|
|
const intKey = +key;
|
|
if (intKey >= start) {
|
|
const value = obj[key];
|
|
delete obj[key];
|
|
if (move > 0 || intKey > start) {
|
|
obj[intKey + move] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function determineLastEvent(e2, lastEvent, inChartArea, isClick) {
|
|
if (!inChartArea || e2.type === "mouseout") {
|
|
return null;
|
|
}
|
|
if (isClick) {
|
|
return lastEvent;
|
|
}
|
|
return e2;
|
|
}
|
|
function getSizeForArea(scale, chartArea, field) {
|
|
return scale.options.clip ? scale[field] : chartArea[field];
|
|
}
|
|
function getDatasetArea(meta, chartArea) {
|
|
const { xScale, yScale } = meta;
|
|
if (xScale && yScale) {
|
|
return {
|
|
left: getSizeForArea(xScale, chartArea, "left"),
|
|
right: getSizeForArea(xScale, chartArea, "right"),
|
|
top: getSizeForArea(yScale, chartArea, "top"),
|
|
bottom: getSizeForArea(yScale, chartArea, "bottom")
|
|
};
|
|
}
|
|
return chartArea;
|
|
}
|
|
var Chart = class {
|
|
static register(...items) {
|
|
registry.add(...items);
|
|
invalidatePlugins();
|
|
}
|
|
static unregister(...items) {
|
|
registry.remove(...items);
|
|
invalidatePlugins();
|
|
}
|
|
constructor(item, userConfig) {
|
|
const config = this.config = new Config(userConfig);
|
|
const initialCanvas = getCanvas(item);
|
|
const existingChart = getChart(initialCanvas);
|
|
if (existingChart) {
|
|
throw new Error("Canvas is already in use. Chart with ID '" + existingChart.id + "' must be destroyed before the canvas with ID '" + existingChart.canvas.id + "' can be reused.");
|
|
}
|
|
const options = config.createResolver(config.chartOptionScopes(), this.getContext());
|
|
this.platform = new (config.platform || _detectPlatform(initialCanvas))();
|
|
this.platform.updateConfig(config);
|
|
const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
|
|
const canvas = context && context.canvas;
|
|
const height = canvas && canvas.height;
|
|
const width = canvas && canvas.width;
|
|
this.id = uid();
|
|
this.ctx = context;
|
|
this.canvas = canvas;
|
|
this.width = width;
|
|
this.height = height;
|
|
this._options = options;
|
|
this._aspectRatio = this.aspectRatio;
|
|
this._layers = [];
|
|
this._metasets = [];
|
|
this._stacks = void 0;
|
|
this.boxes = [];
|
|
this.currentDevicePixelRatio = void 0;
|
|
this.chartArea = void 0;
|
|
this._active = [];
|
|
this._lastEvent = void 0;
|
|
this._listeners = {};
|
|
this._responsiveListeners = void 0;
|
|
this._sortedMetasets = [];
|
|
this.scales = {};
|
|
this._plugins = new PluginService();
|
|
this.$proxies = {};
|
|
this._hiddenIndices = {};
|
|
this.attached = false;
|
|
this._animationsDisabled = void 0;
|
|
this.$context = void 0;
|
|
this._doResize = debounce((mode) => this.update(mode), options.resizeDelay || 0);
|
|
this._dataChanges = [];
|
|
instances[this.id] = this;
|
|
if (!context || !canvas) {
|
|
console.error("Failed to create chart: can't acquire context from the given item");
|
|
return;
|
|
}
|
|
animator.listen(this, "complete", onAnimationsComplete);
|
|
animator.listen(this, "progress", onAnimationProgress);
|
|
this._initialize();
|
|
if (this.attached) {
|
|
this.update();
|
|
}
|
|
}
|
|
get aspectRatio() {
|
|
const { options: { aspectRatio, maintainAspectRatio }, width, height, _aspectRatio } = this;
|
|
if (!isNullOrUndef(aspectRatio)) {
|
|
return aspectRatio;
|
|
}
|
|
if (maintainAspectRatio && _aspectRatio) {
|
|
return _aspectRatio;
|
|
}
|
|
return height ? width / height : null;
|
|
}
|
|
get data() {
|
|
return this.config.data;
|
|
}
|
|
set data(data) {
|
|
this.config.data = data;
|
|
}
|
|
get options() {
|
|
return this._options;
|
|
}
|
|
set options(options) {
|
|
this.config.options = options;
|
|
}
|
|
get registry() {
|
|
return registry;
|
|
}
|
|
_initialize() {
|
|
this.notifyPlugins("beforeInit");
|
|
if (this.options.responsive) {
|
|
this.resize();
|
|
} else {
|
|
retinaScale(this, this.options.devicePixelRatio);
|
|
}
|
|
this.bindEvents();
|
|
this.notifyPlugins("afterInit");
|
|
return this;
|
|
}
|
|
clear() {
|
|
clearCanvas(this.canvas, this.ctx);
|
|
return this;
|
|
}
|
|
stop() {
|
|
animator.stop(this);
|
|
return this;
|
|
}
|
|
resize(width, height) {
|
|
if (!animator.running(this)) {
|
|
this._resize(width, height);
|
|
} else {
|
|
this._resizeBeforeDraw = {
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
}
|
|
_resize(width, height) {
|
|
const options = this.options;
|
|
const canvas = this.canvas;
|
|
const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
|
|
const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
|
|
const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
|
|
const mode = this.width ? "resize" : "attach";
|
|
this.width = newSize.width;
|
|
this.height = newSize.height;
|
|
this._aspectRatio = this.aspectRatio;
|
|
if (!retinaScale(this, newRatio, true)) {
|
|
return;
|
|
}
|
|
this.notifyPlugins("resize", {
|
|
size: newSize
|
|
});
|
|
callback(options.onResize, [
|
|
this,
|
|
newSize
|
|
], this);
|
|
if (this.attached) {
|
|
if (this._doResize(mode)) {
|
|
this.render();
|
|
}
|
|
}
|
|
}
|
|
ensureScalesHaveIDs() {
|
|
const options = this.options;
|
|
const scalesOptions = options.scales || {};
|
|
each(scalesOptions, (axisOptions, axisID) => {
|
|
axisOptions.id = axisID;
|
|
});
|
|
}
|
|
buildOrUpdateScales() {
|
|
const options = this.options;
|
|
const scaleOpts = options.scales;
|
|
const scales = this.scales;
|
|
const updated = Object.keys(scales).reduce((obj, id) => {
|
|
obj[id] = false;
|
|
return obj;
|
|
}, {});
|
|
let items = [];
|
|
if (scaleOpts) {
|
|
items = items.concat(Object.keys(scaleOpts).map((id) => {
|
|
const scaleOptions = scaleOpts[id];
|
|
const axis = determineAxis(id, scaleOptions);
|
|
const isRadial = axis === "r";
|
|
const isHorizontal = axis === "x";
|
|
return {
|
|
options: scaleOptions,
|
|
dposition: isRadial ? "chartArea" : isHorizontal ? "bottom" : "left",
|
|
dtype: isRadial ? "radialLinear" : isHorizontal ? "category" : "linear"
|
|
};
|
|
}));
|
|
}
|
|
each(items, (item) => {
|
|
const scaleOptions = item.options;
|
|
const id = scaleOptions.id;
|
|
const axis = determineAxis(id, scaleOptions);
|
|
const scaleType = valueOrDefault(scaleOptions.type, item.dtype);
|
|
if (scaleOptions.position === void 0 || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
|
|
scaleOptions.position = item.dposition;
|
|
}
|
|
updated[id] = true;
|
|
let scale = null;
|
|
if (id in scales && scales[id].type === scaleType) {
|
|
scale = scales[id];
|
|
} else {
|
|
const scaleClass = registry.getScale(scaleType);
|
|
scale = new scaleClass({
|
|
id,
|
|
type: scaleType,
|
|
ctx: this.ctx,
|
|
chart: this
|
|
});
|
|
scales[scale.id] = scale;
|
|
}
|
|
scale.init(scaleOptions, options);
|
|
});
|
|
each(updated, (hasUpdated, id) => {
|
|
if (!hasUpdated) {
|
|
delete scales[id];
|
|
}
|
|
});
|
|
each(scales, (scale) => {
|
|
layouts.configure(this, scale, scale.options);
|
|
layouts.addBox(this, scale);
|
|
});
|
|
}
|
|
_updateMetasets() {
|
|
const metasets = this._metasets;
|
|
const numData = this.data.datasets.length;
|
|
const numMeta = metasets.length;
|
|
metasets.sort((a2, b2) => a2.index - b2.index);
|
|
if (numMeta > numData) {
|
|
for (let i2 = numData; i2 < numMeta; ++i2) {
|
|
this._destroyDatasetMeta(i2);
|
|
}
|
|
metasets.splice(numData, numMeta - numData);
|
|
}
|
|
this._sortedMetasets = metasets.slice(0).sort(compare2Level("order", "index"));
|
|
}
|
|
_removeUnreferencedMetasets() {
|
|
const { _metasets: metasets, data: { datasets } } = this;
|
|
if (metasets.length > datasets.length) {
|
|
delete this._stacks;
|
|
}
|
|
metasets.forEach((meta, index) => {
|
|
if (datasets.filter((x2) => x2 === meta._dataset).length === 0) {
|
|
this._destroyDatasetMeta(index);
|
|
}
|
|
});
|
|
}
|
|
buildOrUpdateControllers() {
|
|
const newControllers = [];
|
|
const datasets = this.data.datasets;
|
|
let i2, ilen;
|
|
this._removeUnreferencedMetasets();
|
|
for (i2 = 0, ilen = datasets.length; i2 < ilen; i2++) {
|
|
const dataset = datasets[i2];
|
|
let meta = this.getDatasetMeta(i2);
|
|
const type = dataset.type || this.config.type;
|
|
if (meta.type && meta.type !== type) {
|
|
this._destroyDatasetMeta(i2);
|
|
meta = this.getDatasetMeta(i2);
|
|
}
|
|
meta.type = type;
|
|
meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
|
|
meta.order = dataset.order || 0;
|
|
meta.index = i2;
|
|
meta.label = "" + dataset.label;
|
|
meta.visible = this.isDatasetVisible(i2);
|
|
if (meta.controller) {
|
|
meta.controller.updateIndex(i2);
|
|
meta.controller.linkScales();
|
|
} else {
|
|
const ControllerClass = registry.getController(type);
|
|
const { datasetElementType, dataElementType } = defaults2.datasets[type];
|
|
Object.assign(ControllerClass, {
|
|
dataElementType: registry.getElement(dataElementType),
|
|
datasetElementType: datasetElementType && registry.getElement(datasetElementType)
|
|
});
|
|
meta.controller = new ControllerClass(this, i2);
|
|
newControllers.push(meta.controller);
|
|
}
|
|
}
|
|
this._updateMetasets();
|
|
return newControllers;
|
|
}
|
|
_resetElements() {
|
|
each(this.data.datasets, (dataset, datasetIndex) => {
|
|
this.getDatasetMeta(datasetIndex).controller.reset();
|
|
}, this);
|
|
}
|
|
reset() {
|
|
this._resetElements();
|
|
this.notifyPlugins("reset");
|
|
}
|
|
update(mode) {
|
|
const config = this.config;
|
|
config.update();
|
|
const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
|
|
const animsDisabled = this._animationsDisabled = !options.animation;
|
|
this._updateScales();
|
|
this._checkEventBindings();
|
|
this._updateHiddenIndices();
|
|
this._plugins.invalidate();
|
|
if (this.notifyPlugins("beforeUpdate", {
|
|
mode,
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
const newControllers = this.buildOrUpdateControllers();
|
|
this.notifyPlugins("beforeElementsUpdate");
|
|
let minPadding = 0;
|
|
for (let i2 = 0, ilen = this.data.datasets.length; i2 < ilen; i2++) {
|
|
const { controller } = this.getDatasetMeta(i2);
|
|
const reset2 = !animsDisabled && newControllers.indexOf(controller) === -1;
|
|
controller.buildOrUpdateElements(reset2);
|
|
minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
|
|
}
|
|
minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
|
|
this._updateLayout(minPadding);
|
|
if (!animsDisabled) {
|
|
each(newControllers, (controller) => {
|
|
controller.reset();
|
|
});
|
|
}
|
|
this._updateDatasets(mode);
|
|
this.notifyPlugins("afterUpdate", {
|
|
mode
|
|
});
|
|
this._layers.sort(compare2Level("z", "_idx"));
|
|
const { _active, _lastEvent } = this;
|
|
if (_lastEvent) {
|
|
this._eventHandler(_lastEvent, true);
|
|
} else if (_active.length) {
|
|
this._updateHoverStyles(_active, _active, true);
|
|
}
|
|
this.render();
|
|
}
|
|
_updateScales() {
|
|
each(this.scales, (scale) => {
|
|
layouts.removeBox(this, scale);
|
|
});
|
|
this.ensureScalesHaveIDs();
|
|
this.buildOrUpdateScales();
|
|
}
|
|
_checkEventBindings() {
|
|
const options = this.options;
|
|
const existingEvents = new Set(Object.keys(this._listeners));
|
|
const newEvents = new Set(options.events);
|
|
if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
|
|
this.unbindEvents();
|
|
this.bindEvents();
|
|
}
|
|
}
|
|
_updateHiddenIndices() {
|
|
const { _hiddenIndices } = this;
|
|
const changes = this._getUniformDataChanges() || [];
|
|
for (const { method, start, count } of changes) {
|
|
const move = method === "_removeElements" ? -count : count;
|
|
moveNumericKeys(_hiddenIndices, start, move);
|
|
}
|
|
}
|
|
_getUniformDataChanges() {
|
|
const _dataChanges = this._dataChanges;
|
|
if (!_dataChanges || !_dataChanges.length) {
|
|
return;
|
|
}
|
|
this._dataChanges = [];
|
|
const datasetCount = this.data.datasets.length;
|
|
const makeSet = (idx) => new Set(_dataChanges.filter((c2) => c2[0] === idx).map((c2, i2) => i2 + "," + c2.splice(1).join(",")));
|
|
const changeSet = makeSet(0);
|
|
for (let i2 = 1; i2 < datasetCount; i2++) {
|
|
if (!setsEqual(changeSet, makeSet(i2))) {
|
|
return;
|
|
}
|
|
}
|
|
return Array.from(changeSet).map((c2) => c2.split(",")).map((a2) => ({
|
|
method: a2[1],
|
|
start: +a2[2],
|
|
count: +a2[3]
|
|
}));
|
|
}
|
|
_updateLayout(minPadding) {
|
|
if (this.notifyPlugins("beforeLayout", {
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
layouts.update(this, this.width, this.height, minPadding);
|
|
const area = this.chartArea;
|
|
const noArea = area.width <= 0 || area.height <= 0;
|
|
this._layers = [];
|
|
each(this.boxes, (box) => {
|
|
if (noArea && box.position === "chartArea") {
|
|
return;
|
|
}
|
|
if (box.configure) {
|
|
box.configure();
|
|
}
|
|
this._layers.push(...box._layers());
|
|
}, this);
|
|
this._layers.forEach((item, index) => {
|
|
item._idx = index;
|
|
});
|
|
this.notifyPlugins("afterLayout");
|
|
}
|
|
_updateDatasets(mode) {
|
|
if (this.notifyPlugins("beforeDatasetsUpdate", {
|
|
mode,
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
for (let i2 = 0, ilen = this.data.datasets.length; i2 < ilen; ++i2) {
|
|
this.getDatasetMeta(i2).controller.configure();
|
|
}
|
|
for (let i2 = 0, ilen = this.data.datasets.length; i2 < ilen; ++i2) {
|
|
this._updateDataset(i2, isFunction(mode) ? mode({
|
|
datasetIndex: i2
|
|
}) : mode);
|
|
}
|
|
this.notifyPlugins("afterDatasetsUpdate", {
|
|
mode
|
|
});
|
|
}
|
|
_updateDataset(index, mode) {
|
|
const meta = this.getDatasetMeta(index);
|
|
const args = {
|
|
meta,
|
|
index,
|
|
mode,
|
|
cancelable: true
|
|
};
|
|
if (this.notifyPlugins("beforeDatasetUpdate", args) === false) {
|
|
return;
|
|
}
|
|
meta.controller._update(mode);
|
|
args.cancelable = false;
|
|
this.notifyPlugins("afterDatasetUpdate", args);
|
|
}
|
|
render() {
|
|
if (this.notifyPlugins("beforeRender", {
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
if (animator.has(this)) {
|
|
if (this.attached && !animator.running(this)) {
|
|
animator.start(this);
|
|
}
|
|
} else {
|
|
this.draw();
|
|
onAnimationsComplete({
|
|
chart: this
|
|
});
|
|
}
|
|
}
|
|
draw() {
|
|
let i2;
|
|
if (this._resizeBeforeDraw) {
|
|
const { width, height } = this._resizeBeforeDraw;
|
|
this._resizeBeforeDraw = null;
|
|
this._resize(width, height);
|
|
}
|
|
this.clear();
|
|
if (this.width <= 0 || this.height <= 0) {
|
|
return;
|
|
}
|
|
if (this.notifyPlugins("beforeDraw", {
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
const layers = this._layers;
|
|
for (i2 = 0; i2 < layers.length && layers[i2].z <= 0; ++i2) {
|
|
layers[i2].draw(this.chartArea);
|
|
}
|
|
this._drawDatasets();
|
|
for (; i2 < layers.length; ++i2) {
|
|
layers[i2].draw(this.chartArea);
|
|
}
|
|
this.notifyPlugins("afterDraw");
|
|
}
|
|
_getSortedDatasetMetas(filterVisible) {
|
|
const metasets = this._sortedMetasets;
|
|
const result = [];
|
|
let i2, ilen;
|
|
for (i2 = 0, ilen = metasets.length; i2 < ilen; ++i2) {
|
|
const meta = metasets[i2];
|
|
if (!filterVisible || meta.visible) {
|
|
result.push(meta);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
getSortedVisibleDatasetMetas() {
|
|
return this._getSortedDatasetMetas(true);
|
|
}
|
|
_drawDatasets() {
|
|
if (this.notifyPlugins("beforeDatasetsDraw", {
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
const metasets = this.getSortedVisibleDatasetMetas();
|
|
for (let i2 = metasets.length - 1; i2 >= 0; --i2) {
|
|
this._drawDataset(metasets[i2]);
|
|
}
|
|
this.notifyPlugins("afterDatasetsDraw");
|
|
}
|
|
_drawDataset(meta) {
|
|
const ctx = this.ctx;
|
|
const clip = meta._clip;
|
|
const useClip = !clip.disabled;
|
|
const area = getDatasetArea(meta, this.chartArea);
|
|
const args = {
|
|
meta,
|
|
index: meta.index,
|
|
cancelable: true
|
|
};
|
|
if (this.notifyPlugins("beforeDatasetDraw", args) === false) {
|
|
return;
|
|
}
|
|
if (useClip) {
|
|
clipArea(ctx, {
|
|
left: clip.left === false ? 0 : area.left - clip.left,
|
|
right: clip.right === false ? this.width : area.right + clip.right,
|
|
top: clip.top === false ? 0 : area.top - clip.top,
|
|
bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom
|
|
});
|
|
}
|
|
meta.controller.draw();
|
|
if (useClip) {
|
|
unclipArea(ctx);
|
|
}
|
|
args.cancelable = false;
|
|
this.notifyPlugins("afterDatasetDraw", args);
|
|
}
|
|
isPointInArea(point) {
|
|
return _isPointInArea(point, this.chartArea, this._minPadding);
|
|
}
|
|
getElementsAtEventForMode(e2, mode, options, useFinalPosition) {
|
|
const method = Interaction.modes[mode];
|
|
if (typeof method === "function") {
|
|
return method(this, e2, options, useFinalPosition);
|
|
}
|
|
return [];
|
|
}
|
|
getDatasetMeta(datasetIndex) {
|
|
const dataset = this.data.datasets[datasetIndex];
|
|
const metasets = this._metasets;
|
|
let meta = metasets.filter((x2) => x2 && x2._dataset === dataset).pop();
|
|
if (!meta) {
|
|
meta = {
|
|
type: null,
|
|
data: [],
|
|
dataset: null,
|
|
controller: null,
|
|
hidden: null,
|
|
xAxisID: null,
|
|
yAxisID: null,
|
|
order: dataset && dataset.order || 0,
|
|
index: datasetIndex,
|
|
_dataset: dataset,
|
|
_parsed: [],
|
|
_sorted: false
|
|
};
|
|
metasets.push(meta);
|
|
}
|
|
return meta;
|
|
}
|
|
getContext() {
|
|
return this.$context || (this.$context = createContext(null, {
|
|
chart: this,
|
|
type: "chart"
|
|
}));
|
|
}
|
|
getVisibleDatasetCount() {
|
|
return this.getSortedVisibleDatasetMetas().length;
|
|
}
|
|
isDatasetVisible(datasetIndex) {
|
|
const dataset = this.data.datasets[datasetIndex];
|
|
if (!dataset) {
|
|
return false;
|
|
}
|
|
const meta = this.getDatasetMeta(datasetIndex);
|
|
return typeof meta.hidden === "boolean" ? !meta.hidden : !dataset.hidden;
|
|
}
|
|
setDatasetVisibility(datasetIndex, visible) {
|
|
const meta = this.getDatasetMeta(datasetIndex);
|
|
meta.hidden = !visible;
|
|
}
|
|
toggleDataVisibility(index) {
|
|
this._hiddenIndices[index] = !this._hiddenIndices[index];
|
|
}
|
|
getDataVisibility(index) {
|
|
return !this._hiddenIndices[index];
|
|
}
|
|
_updateVisibility(datasetIndex, dataIndex, visible) {
|
|
const mode = visible ? "show" : "hide";
|
|
const meta = this.getDatasetMeta(datasetIndex);
|
|
const anims = meta.controller._resolveAnimations(void 0, mode);
|
|
if (defined(dataIndex)) {
|
|
meta.data[dataIndex].hidden = !visible;
|
|
this.update();
|
|
} else {
|
|
this.setDatasetVisibility(datasetIndex, visible);
|
|
anims.update(meta, {
|
|
visible
|
|
});
|
|
this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : void 0);
|
|
}
|
|
}
|
|
hide(datasetIndex, dataIndex) {
|
|
this._updateVisibility(datasetIndex, dataIndex, false);
|
|
}
|
|
show(datasetIndex, dataIndex) {
|
|
this._updateVisibility(datasetIndex, dataIndex, true);
|
|
}
|
|
_destroyDatasetMeta(datasetIndex) {
|
|
const meta = this._metasets[datasetIndex];
|
|
if (meta && meta.controller) {
|
|
meta.controller._destroy();
|
|
}
|
|
delete this._metasets[datasetIndex];
|
|
}
|
|
_stop() {
|
|
let i2, ilen;
|
|
this.stop();
|
|
animator.remove(this);
|
|
for (i2 = 0, ilen = this.data.datasets.length; i2 < ilen; ++i2) {
|
|
this._destroyDatasetMeta(i2);
|
|
}
|
|
}
|
|
destroy() {
|
|
this.notifyPlugins("beforeDestroy");
|
|
const { canvas, ctx } = this;
|
|
this._stop();
|
|
this.config.clearCache();
|
|
if (canvas) {
|
|
this.unbindEvents();
|
|
clearCanvas(canvas, ctx);
|
|
this.platform.releaseContext(ctx);
|
|
this.canvas = null;
|
|
this.ctx = null;
|
|
}
|
|
delete instances[this.id];
|
|
this.notifyPlugins("afterDestroy");
|
|
}
|
|
toBase64Image(...args) {
|
|
return this.canvas.toDataURL(...args);
|
|
}
|
|
bindEvents() {
|
|
this.bindUserEvents();
|
|
if (this.options.responsive) {
|
|
this.bindResponsiveEvents();
|
|
} else {
|
|
this.attached = true;
|
|
}
|
|
}
|
|
bindUserEvents() {
|
|
const listeners = this._listeners;
|
|
const platform = this.platform;
|
|
const _add = (type, listener2) => {
|
|
platform.addEventListener(this, type, listener2);
|
|
listeners[type] = listener2;
|
|
};
|
|
const listener = (e2, x2, y2) => {
|
|
e2.offsetX = x2;
|
|
e2.offsetY = y2;
|
|
this._eventHandler(e2);
|
|
};
|
|
each(this.options.events, (type) => _add(type, listener));
|
|
}
|
|
bindResponsiveEvents() {
|
|
if (!this._responsiveListeners) {
|
|
this._responsiveListeners = {};
|
|
}
|
|
const listeners = this._responsiveListeners;
|
|
const platform = this.platform;
|
|
const _add = (type, listener2) => {
|
|
platform.addEventListener(this, type, listener2);
|
|
listeners[type] = listener2;
|
|
};
|
|
const _remove = (type, listener2) => {
|
|
if (listeners[type]) {
|
|
platform.removeEventListener(this, type, listener2);
|
|
delete listeners[type];
|
|
}
|
|
};
|
|
const listener = (width, height) => {
|
|
if (this.canvas) {
|
|
this.resize(width, height);
|
|
}
|
|
};
|
|
let detached;
|
|
const attached = () => {
|
|
_remove("attach", attached);
|
|
this.attached = true;
|
|
this.resize();
|
|
_add("resize", listener);
|
|
_add("detach", detached);
|
|
};
|
|
detached = () => {
|
|
this.attached = false;
|
|
_remove("resize", listener);
|
|
this._stop();
|
|
this._resize(0, 0);
|
|
_add("attach", attached);
|
|
};
|
|
if (platform.isAttached(this.canvas)) {
|
|
attached();
|
|
} else {
|
|
detached();
|
|
}
|
|
}
|
|
unbindEvents() {
|
|
each(this._listeners, (listener, type) => {
|
|
this.platform.removeEventListener(this, type, listener);
|
|
});
|
|
this._listeners = {};
|
|
each(this._responsiveListeners, (listener, type) => {
|
|
this.platform.removeEventListener(this, type, listener);
|
|
});
|
|
this._responsiveListeners = void 0;
|
|
}
|
|
updateHoverStyle(items, mode, enabled) {
|
|
const prefix = enabled ? "set" : "remove";
|
|
let meta, item, i2, ilen;
|
|
if (mode === "dataset") {
|
|
meta = this.getDatasetMeta(items[0].datasetIndex);
|
|
meta.controller["_" + prefix + "DatasetHoverStyle"]();
|
|
}
|
|
for (i2 = 0, ilen = items.length; i2 < ilen; ++i2) {
|
|
item = items[i2];
|
|
const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
|
|
if (controller) {
|
|
controller[prefix + "HoverStyle"](item.element, item.datasetIndex, item.index);
|
|
}
|
|
}
|
|
}
|
|
getActiveElements() {
|
|
return this._active || [];
|
|
}
|
|
setActiveElements(activeElements) {
|
|
const lastActive = this._active || [];
|
|
const active = activeElements.map(({ datasetIndex, index }) => {
|
|
const meta = this.getDatasetMeta(datasetIndex);
|
|
if (!meta) {
|
|
throw new Error("No dataset found at index " + datasetIndex);
|
|
}
|
|
return {
|
|
datasetIndex,
|
|
element: meta.data[index],
|
|
index
|
|
};
|
|
});
|
|
const changed = !_elementsEqual(active, lastActive);
|
|
if (changed) {
|
|
this._active = active;
|
|
this._lastEvent = null;
|
|
this._updateHoverStyles(active, lastActive);
|
|
}
|
|
}
|
|
notifyPlugins(hook, args, filter2) {
|
|
return this._plugins.notify(this, hook, args, filter2);
|
|
}
|
|
isPluginEnabled(pluginId) {
|
|
return this._plugins._cache.filter((p2) => p2.plugin.id === pluginId).length === 1;
|
|
}
|
|
_updateHoverStyles(active, lastActive, replay) {
|
|
const hoverOptions = this.options.hover;
|
|
const diff = (a2, b2) => a2.filter((x2) => !b2.some((y2) => x2.datasetIndex === y2.datasetIndex && x2.index === y2.index));
|
|
const deactivated = diff(lastActive, active);
|
|
const activated = replay ? active : diff(active, lastActive);
|
|
if (deactivated.length) {
|
|
this.updateHoverStyle(deactivated, hoverOptions.mode, false);
|
|
}
|
|
if (activated.length && hoverOptions.mode) {
|
|
this.updateHoverStyle(activated, hoverOptions.mode, true);
|
|
}
|
|
}
|
|
_eventHandler(e2, replay) {
|
|
const args = {
|
|
event: e2,
|
|
replay,
|
|
cancelable: true,
|
|
inChartArea: this.isPointInArea(e2)
|
|
};
|
|
const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e2.native.type);
|
|
if (this.notifyPlugins("beforeEvent", args, eventFilter) === false) {
|
|
return;
|
|
}
|
|
const changed = this._handleEvent(e2, replay, args.inChartArea);
|
|
args.cancelable = false;
|
|
this.notifyPlugins("afterEvent", args, eventFilter);
|
|
if (changed || args.changed) {
|
|
this.render();
|
|
}
|
|
return this;
|
|
}
|
|
_handleEvent(e2, replay, inChartArea) {
|
|
const { _active: lastActive = [], options } = this;
|
|
const useFinalPosition = replay;
|
|
const active = this._getActiveElements(e2, lastActive, inChartArea, useFinalPosition);
|
|
const isClick = _isClickEvent(e2);
|
|
const lastEvent = determineLastEvent(e2, this._lastEvent, inChartArea, isClick);
|
|
if (inChartArea) {
|
|
this._lastEvent = null;
|
|
callback(options.onHover, [
|
|
e2,
|
|
active,
|
|
this
|
|
], this);
|
|
if (isClick) {
|
|
callback(options.onClick, [
|
|
e2,
|
|
active,
|
|
this
|
|
], this);
|
|
}
|
|
}
|
|
const changed = !_elementsEqual(active, lastActive);
|
|
if (changed || replay) {
|
|
this._active = active;
|
|
this._updateHoverStyles(active, lastActive, replay);
|
|
}
|
|
this._lastEvent = lastEvent;
|
|
return changed;
|
|
}
|
|
_getActiveElements(e2, lastActive, inChartArea, useFinalPosition) {
|
|
if (e2.type === "mouseout") {
|
|
return [];
|
|
}
|
|
if (!inChartArea) {
|
|
return lastActive;
|
|
}
|
|
const hoverOptions = this.options.hover;
|
|
return this.getElementsAtEventForMode(e2, hoverOptions.mode, hoverOptions, useFinalPosition);
|
|
}
|
|
};
|
|
__publicField(Chart, "defaults", defaults2);
|
|
__publicField(Chart, "instances", instances);
|
|
__publicField(Chart, "overrides", overrides);
|
|
__publicField(Chart, "registry", registry);
|
|
__publicField(Chart, "version", version);
|
|
__publicField(Chart, "getChart", getChart);
|
|
function invalidatePlugins() {
|
|
return each(Chart.instances, (chart) => chart._plugins.invalidate());
|
|
}
|
|
function clipArc(ctx, element, endAngle) {
|
|
const { startAngle, pixelMargin, x: x2, y: y2, outerRadius, innerRadius } = element;
|
|
let angleMargin = pixelMargin / outerRadius;
|
|
ctx.beginPath();
|
|
ctx.arc(x2, y2, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
|
|
if (innerRadius > pixelMargin) {
|
|
angleMargin = pixelMargin / innerRadius;
|
|
ctx.arc(x2, y2, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
|
|
} else {
|
|
ctx.arc(x2, y2, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);
|
|
}
|
|
ctx.closePath();
|
|
ctx.clip();
|
|
}
|
|
function toRadiusCorners(value) {
|
|
return _readValueToProps(value, [
|
|
"outerStart",
|
|
"outerEnd",
|
|
"innerStart",
|
|
"innerEnd"
|
|
]);
|
|
}
|
|
function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
|
|
const o2 = toRadiusCorners(arc.options.borderRadius);
|
|
const halfThickness = (outerRadius - innerRadius) / 2;
|
|
const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
|
|
const computeOuterLimit = (val) => {
|
|
const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
|
|
return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit));
|
|
};
|
|
return {
|
|
outerStart: computeOuterLimit(o2.outerStart),
|
|
outerEnd: computeOuterLimit(o2.outerEnd),
|
|
innerStart: _limitValue(o2.innerStart, 0, innerLimit),
|
|
innerEnd: _limitValue(o2.innerEnd, 0, innerLimit)
|
|
};
|
|
}
|
|
function rThetaToXY(r2, theta, x2, y2) {
|
|
return {
|
|
x: x2 + r2 * Math.cos(theta),
|
|
y: y2 + r2 * Math.sin(theta)
|
|
};
|
|
}
|
|
function pathArc(ctx, element, offset, spacing, end, circular) {
|
|
const { x: x2, y: y2, startAngle: start, pixelMargin, innerRadius: innerR } = element;
|
|
const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
|
|
const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
|
|
let spacingOffset = 0;
|
|
const alpha2 = end - start;
|
|
if (spacing) {
|
|
const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
|
|
const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
|
|
const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
|
|
const adjustedAngle = avNogSpacingRadius !== 0 ? alpha2 * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha2;
|
|
spacingOffset = (alpha2 - adjustedAngle) / 2;
|
|
}
|
|
const beta = Math.max(1e-3, alpha2 * outerRadius - offset / PI) / outerRadius;
|
|
const angleOffset = (alpha2 - beta) / 2;
|
|
const startAngle = start + angleOffset + spacingOffset;
|
|
const endAngle = end - angleOffset - spacingOffset;
|
|
const { outerStart, outerEnd, innerStart, innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
|
|
const outerStartAdjustedRadius = outerRadius - outerStart;
|
|
const outerEndAdjustedRadius = outerRadius - outerEnd;
|
|
const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
|
|
const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
|
|
const innerStartAdjustedRadius = innerRadius + innerStart;
|
|
const innerEndAdjustedRadius = innerRadius + innerEnd;
|
|
const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
|
|
const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
|
|
ctx.beginPath();
|
|
if (circular) {
|
|
const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;
|
|
ctx.arc(x2, y2, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);
|
|
ctx.arc(x2, y2, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);
|
|
if (outerEnd > 0) {
|
|
const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x2, y2);
|
|
ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);
|
|
}
|
|
const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x2, y2);
|
|
ctx.lineTo(p4.x, p4.y);
|
|
if (innerEnd > 0) {
|
|
const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x2, y2);
|
|
ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);
|
|
}
|
|
const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;
|
|
ctx.arc(x2, y2, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);
|
|
ctx.arc(x2, y2, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);
|
|
if (innerStart > 0) {
|
|
const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x2, y2);
|
|
ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);
|
|
}
|
|
const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x2, y2);
|
|
ctx.lineTo(p8.x, p8.y);
|
|
if (outerStart > 0) {
|
|
const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x2, y2);
|
|
ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);
|
|
}
|
|
} else {
|
|
ctx.moveTo(x2, y2);
|
|
const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x2;
|
|
const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y2;
|
|
ctx.lineTo(outerStartX, outerStartY);
|
|
const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x2;
|
|
const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y2;
|
|
ctx.lineTo(outerEndX, outerEndY);
|
|
}
|
|
ctx.closePath();
|
|
}
|
|
function drawArc(ctx, element, offset, spacing, circular) {
|
|
const { fullCircles, startAngle, circumference } = element;
|
|
let endAngle = element.endAngle;
|
|
if (fullCircles) {
|
|
pathArc(ctx, element, offset, spacing, endAngle, circular);
|
|
for (let i2 = 0; i2 < fullCircles; ++i2) {
|
|
ctx.fill();
|
|
}
|
|
if (!isNaN(circumference)) {
|
|
endAngle = startAngle + (circumference % TAU || TAU);
|
|
}
|
|
}
|
|
pathArc(ctx, element, offset, spacing, endAngle, circular);
|
|
ctx.fill();
|
|
return endAngle;
|
|
}
|
|
function drawBorder(ctx, element, offset, spacing, circular) {
|
|
const { fullCircles, startAngle, circumference, options } = element;
|
|
const { borderWidth, borderJoinStyle, borderDash, borderDashOffset } = options;
|
|
const inner = options.borderAlign === "inner";
|
|
if (!borderWidth) {
|
|
return;
|
|
}
|
|
ctx.setLineDash(borderDash || []);
|
|
ctx.lineDashOffset = borderDashOffset;
|
|
if (inner) {
|
|
ctx.lineWidth = borderWidth * 2;
|
|
ctx.lineJoin = borderJoinStyle || "round";
|
|
} else {
|
|
ctx.lineWidth = borderWidth;
|
|
ctx.lineJoin = borderJoinStyle || "bevel";
|
|
}
|
|
let endAngle = element.endAngle;
|
|
if (fullCircles) {
|
|
pathArc(ctx, element, offset, spacing, endAngle, circular);
|
|
for (let i2 = 0; i2 < fullCircles; ++i2) {
|
|
ctx.stroke();
|
|
}
|
|
if (!isNaN(circumference)) {
|
|
endAngle = startAngle + (circumference % TAU || TAU);
|
|
}
|
|
}
|
|
if (inner) {
|
|
clipArc(ctx, element, endAngle);
|
|
}
|
|
if (!fullCircles) {
|
|
pathArc(ctx, element, offset, spacing, endAngle, circular);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
var ArcElement = class extends Element {
|
|
constructor(cfg) {
|
|
super();
|
|
__publicField(this, "circumference");
|
|
__publicField(this, "endAngle");
|
|
__publicField(this, "fullCircles");
|
|
__publicField(this, "innerRadius");
|
|
__publicField(this, "outerRadius");
|
|
__publicField(this, "pixelMargin");
|
|
__publicField(this, "startAngle");
|
|
this.options = void 0;
|
|
this.circumference = void 0;
|
|
this.startAngle = void 0;
|
|
this.endAngle = void 0;
|
|
this.innerRadius = void 0;
|
|
this.outerRadius = void 0;
|
|
this.pixelMargin = 0;
|
|
this.fullCircles = 0;
|
|
if (cfg) {
|
|
Object.assign(this, cfg);
|
|
}
|
|
}
|
|
inRange(chartX, chartY, useFinalPosition) {
|
|
const point = this.getProps([
|
|
"x",
|
|
"y"
|
|
], useFinalPosition);
|
|
const { angle, distance } = getAngleFromPoint(point, {
|
|
x: chartX,
|
|
y: chartY
|
|
});
|
|
const { startAngle, endAngle, innerRadius, outerRadius, circumference } = this.getProps([
|
|
"startAngle",
|
|
"endAngle",
|
|
"innerRadius",
|
|
"outerRadius",
|
|
"circumference"
|
|
], useFinalPosition);
|
|
const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;
|
|
const _circumference = valueOrDefault(circumference, endAngle - startAngle);
|
|
const nonZeroBetween = _angleBetween(angle, startAngle, endAngle) && startAngle !== endAngle;
|
|
const betweenAngles = _circumference >= TAU || nonZeroBetween;
|
|
const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);
|
|
return betweenAngles && withinRadius;
|
|
}
|
|
getCenterPoint(useFinalPosition) {
|
|
const { x: x2, y: y2, startAngle, endAngle, innerRadius, outerRadius } = this.getProps([
|
|
"x",
|
|
"y",
|
|
"startAngle",
|
|
"endAngle",
|
|
"innerRadius",
|
|
"outerRadius"
|
|
], useFinalPosition);
|
|
const { offset, spacing } = this.options;
|
|
const halfAngle = (startAngle + endAngle) / 2;
|
|
const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
|
|
return {
|
|
x: x2 + Math.cos(halfAngle) * halfRadius,
|
|
y: y2 + Math.sin(halfAngle) * halfRadius
|
|
};
|
|
}
|
|
tooltipPosition(useFinalPosition) {
|
|
return this.getCenterPoint(useFinalPosition);
|
|
}
|
|
draw(ctx) {
|
|
const { options, circumference } = this;
|
|
const offset = (options.offset || 0) / 4;
|
|
const spacing = (options.spacing || 0) / 2;
|
|
const circular = options.circular;
|
|
this.pixelMargin = options.borderAlign === "inner" ? 0.33 : 0;
|
|
this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0;
|
|
if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
|
|
return;
|
|
}
|
|
ctx.save();
|
|
const halfAngle = (this.startAngle + this.endAngle) / 2;
|
|
ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
|
|
const fix = 1 - Math.sin(Math.min(PI, circumference || 0));
|
|
const radiusOffset = offset * fix;
|
|
ctx.fillStyle = options.backgroundColor;
|
|
ctx.strokeStyle = options.borderColor;
|
|
drawArc(ctx, this, radiusOffset, spacing, circular);
|
|
drawBorder(ctx, this, radiusOffset, spacing, circular);
|
|
ctx.restore();
|
|
}
|
|
};
|
|
__publicField(ArcElement, "id", "arc");
|
|
__publicField(ArcElement, "defaults", {
|
|
borderAlign: "center",
|
|
borderColor: "#fff",
|
|
borderDash: [],
|
|
borderDashOffset: 0,
|
|
borderJoinStyle: void 0,
|
|
borderRadius: 0,
|
|
borderWidth: 2,
|
|
offset: 0,
|
|
spacing: 0,
|
|
angle: void 0,
|
|
circular: true
|
|
});
|
|
__publicField(ArcElement, "defaultRoutes", {
|
|
backgroundColor: "backgroundColor"
|
|
});
|
|
__publicField(ArcElement, "descriptors", {
|
|
_scriptable: true,
|
|
_indexable: (name) => name !== "borderDash"
|
|
});
|
|
function getBarBounds(bar, useFinalPosition) {
|
|
const { x: x2, y: y2, base, width, height } = bar.getProps([
|
|
"x",
|
|
"y",
|
|
"base",
|
|
"width",
|
|
"height"
|
|
], useFinalPosition);
|
|
let left, right, top, bottom, half;
|
|
if (bar.horizontal) {
|
|
half = height / 2;
|
|
left = Math.min(x2, base);
|
|
right = Math.max(x2, base);
|
|
top = y2 - half;
|
|
bottom = y2 + half;
|
|
} else {
|
|
half = width / 2;
|
|
left = x2 - half;
|
|
right = x2 + half;
|
|
top = Math.min(y2, base);
|
|
bottom = Math.max(y2, base);
|
|
}
|
|
return {
|
|
left,
|
|
top,
|
|
right,
|
|
bottom
|
|
};
|
|
}
|
|
function skipOrLimit(skip2, value, min, max) {
|
|
return skip2 ? 0 : _limitValue(value, min, max);
|
|
}
|
|
function parseBorderWidth(bar, maxW, maxH) {
|
|
const value = bar.options.borderWidth;
|
|
const skip2 = bar.borderSkipped;
|
|
const o2 = toTRBL(value);
|
|
return {
|
|
t: skipOrLimit(skip2.top, o2.top, 0, maxH),
|
|
r: skipOrLimit(skip2.right, o2.right, 0, maxW),
|
|
b: skipOrLimit(skip2.bottom, o2.bottom, 0, maxH),
|
|
l: skipOrLimit(skip2.left, o2.left, 0, maxW)
|
|
};
|
|
}
|
|
function parseBorderRadius(bar, maxW, maxH) {
|
|
const { enableBorderRadius } = bar.getProps([
|
|
"enableBorderRadius"
|
|
]);
|
|
const value = bar.options.borderRadius;
|
|
const o2 = toTRBLCorners(value);
|
|
const maxR = Math.min(maxW, maxH);
|
|
const skip2 = bar.borderSkipped;
|
|
const enableBorder = enableBorderRadius || isObject(value);
|
|
return {
|
|
topLeft: skipOrLimit(!enableBorder || skip2.top || skip2.left, o2.topLeft, 0, maxR),
|
|
topRight: skipOrLimit(!enableBorder || skip2.top || skip2.right, o2.topRight, 0, maxR),
|
|
bottomLeft: skipOrLimit(!enableBorder || skip2.bottom || skip2.left, o2.bottomLeft, 0, maxR),
|
|
bottomRight: skipOrLimit(!enableBorder || skip2.bottom || skip2.right, o2.bottomRight, 0, maxR)
|
|
};
|
|
}
|
|
function boundingRects(bar) {
|
|
const bounds = getBarBounds(bar);
|
|
const width = bounds.right - bounds.left;
|
|
const height = bounds.bottom - bounds.top;
|
|
const border = parseBorderWidth(bar, width / 2, height / 2);
|
|
const radius = parseBorderRadius(bar, width / 2, height / 2);
|
|
return {
|
|
outer: {
|
|
x: bounds.left,
|
|
y: bounds.top,
|
|
w: width,
|
|
h: height,
|
|
radius
|
|
},
|
|
inner: {
|
|
x: bounds.left + border.l,
|
|
y: bounds.top + border.t,
|
|
w: width - border.l - border.r,
|
|
h: height - border.t - border.b,
|
|
radius: {
|
|
topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
|
|
topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
|
|
bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
|
|
bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function inRange(bar, x2, y2, useFinalPosition) {
|
|
const skipX = x2 === null;
|
|
const skipY = y2 === null;
|
|
const skipBoth = skipX && skipY;
|
|
const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
|
|
return bounds && (skipX || _isBetween(x2, bounds.left, bounds.right)) && (skipY || _isBetween(y2, bounds.top, bounds.bottom));
|
|
}
|
|
function hasRadius(radius) {
|
|
return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
|
|
}
|
|
function addNormalRectPath(ctx, rect) {
|
|
ctx.rect(rect.x, rect.y, rect.w, rect.h);
|
|
}
|
|
function inflateRect(rect, amount, refRect = {}) {
|
|
const x2 = rect.x !== refRect.x ? -amount : 0;
|
|
const y2 = rect.y !== refRect.y ? -amount : 0;
|
|
const w2 = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x2;
|
|
const h6 = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y2;
|
|
return {
|
|
x: rect.x + x2,
|
|
y: rect.y + y2,
|
|
w: rect.w + w2,
|
|
h: rect.h + h6,
|
|
radius: rect.radius
|
|
};
|
|
}
|
|
var BarElement = class extends Element {
|
|
constructor(cfg) {
|
|
super();
|
|
this.options = void 0;
|
|
this.horizontal = void 0;
|
|
this.base = void 0;
|
|
this.width = void 0;
|
|
this.height = void 0;
|
|
this.inflateAmount = void 0;
|
|
if (cfg) {
|
|
Object.assign(this, cfg);
|
|
}
|
|
}
|
|
draw(ctx) {
|
|
const { inflateAmount, options: { borderColor, backgroundColor } } = this;
|
|
const { inner, outer } = boundingRects(this);
|
|
const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;
|
|
ctx.save();
|
|
if (outer.w !== inner.w || outer.h !== inner.h) {
|
|
ctx.beginPath();
|
|
addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
|
|
ctx.clip();
|
|
addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
|
|
ctx.fillStyle = borderColor;
|
|
ctx.fill("evenodd");
|
|
}
|
|
ctx.beginPath();
|
|
addRectPath(ctx, inflateRect(inner, inflateAmount));
|
|
ctx.fillStyle = backgroundColor;
|
|
ctx.fill();
|
|
ctx.restore();
|
|
}
|
|
inRange(mouseX, mouseY, useFinalPosition) {
|
|
return inRange(this, mouseX, mouseY, useFinalPosition);
|
|
}
|
|
inXRange(mouseX, useFinalPosition) {
|
|
return inRange(this, mouseX, null, useFinalPosition);
|
|
}
|
|
inYRange(mouseY, useFinalPosition) {
|
|
return inRange(this, null, mouseY, useFinalPosition);
|
|
}
|
|
getCenterPoint(useFinalPosition) {
|
|
const { x: x2, y: y2, base, horizontal } = this.getProps([
|
|
"x",
|
|
"y",
|
|
"base",
|
|
"horizontal"
|
|
], useFinalPosition);
|
|
return {
|
|
x: horizontal ? (x2 + base) / 2 : x2,
|
|
y: horizontal ? y2 : (y2 + base) / 2
|
|
};
|
|
}
|
|
getRange(axis) {
|
|
return axis === "x" ? this.width / 2 : this.height / 2;
|
|
}
|
|
};
|
|
__publicField(BarElement, "id", "bar");
|
|
__publicField(BarElement, "defaults", {
|
|
borderSkipped: "start",
|
|
borderWidth: 0,
|
|
borderRadius: 0,
|
|
inflateAmount: "auto",
|
|
pointStyle: void 0
|
|
});
|
|
__publicField(BarElement, "defaultRoutes", {
|
|
backgroundColor: "backgroundColor",
|
|
borderColor: "borderColor"
|
|
});
|
|
var getBoxSize = (labelOpts, fontSize) => {
|
|
let { boxHeight = fontSize, boxWidth = fontSize } = labelOpts;
|
|
if (labelOpts.usePointStyle) {
|
|
boxHeight = Math.min(boxHeight, fontSize);
|
|
boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);
|
|
}
|
|
return {
|
|
boxWidth,
|
|
boxHeight,
|
|
itemHeight: Math.max(fontSize, boxHeight)
|
|
};
|
|
};
|
|
var itemsEqual = (a2, b2) => a2 !== null && b2 !== null && a2.datasetIndex === b2.datasetIndex && a2.index === b2.index;
|
|
var Legend = class extends Element {
|
|
constructor(config) {
|
|
super();
|
|
this._added = false;
|
|
this.legendHitBoxes = [];
|
|
this._hoveredItem = null;
|
|
this.doughnutMode = false;
|
|
this.chart = config.chart;
|
|
this.options = config.options;
|
|
this.ctx = config.ctx;
|
|
this.legendItems = void 0;
|
|
this.columnSizes = void 0;
|
|
this.lineWidths = void 0;
|
|
this.maxHeight = void 0;
|
|
this.maxWidth = void 0;
|
|
this.top = void 0;
|
|
this.bottom = void 0;
|
|
this.left = void 0;
|
|
this.right = void 0;
|
|
this.height = void 0;
|
|
this.width = void 0;
|
|
this._margins = void 0;
|
|
this.position = void 0;
|
|
this.weight = void 0;
|
|
this.fullSize = void 0;
|
|
}
|
|
update(maxWidth, maxHeight, margins) {
|
|
this.maxWidth = maxWidth;
|
|
this.maxHeight = maxHeight;
|
|
this._margins = margins;
|
|
this.setDimensions();
|
|
this.buildLabels();
|
|
this.fit();
|
|
}
|
|
setDimensions() {
|
|
if (this.isHorizontal()) {
|
|
this.width = this.maxWidth;
|
|
this.left = this._margins.left;
|
|
this.right = this.width;
|
|
} else {
|
|
this.height = this.maxHeight;
|
|
this.top = this._margins.top;
|
|
this.bottom = this.height;
|
|
}
|
|
}
|
|
buildLabels() {
|
|
const labelOpts = this.options.labels || {};
|
|
let legendItems = callback(labelOpts.generateLabels, [
|
|
this.chart
|
|
], this) || [];
|
|
if (labelOpts.filter) {
|
|
legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data));
|
|
}
|
|
if (labelOpts.sort) {
|
|
legendItems = legendItems.sort((a2, b2) => labelOpts.sort(a2, b2, this.chart.data));
|
|
}
|
|
if (this.options.reverse) {
|
|
legendItems.reverse();
|
|
}
|
|
this.legendItems = legendItems;
|
|
}
|
|
fit() {
|
|
const { options, ctx } = this;
|
|
if (!options.display) {
|
|
this.width = this.height = 0;
|
|
return;
|
|
}
|
|
const labelOpts = options.labels;
|
|
const labelFont = toFont(labelOpts.font);
|
|
const fontSize = labelFont.size;
|
|
const titleHeight = this._computeTitleHeight();
|
|
const { boxWidth, itemHeight } = getBoxSize(labelOpts, fontSize);
|
|
let width, height;
|
|
ctx.font = labelFont.string;
|
|
if (this.isHorizontal()) {
|
|
width = this.maxWidth;
|
|
height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
|
|
} else {
|
|
height = this.maxHeight;
|
|
width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;
|
|
}
|
|
this.width = Math.min(width, options.maxWidth || this.maxWidth);
|
|
this.height = Math.min(height, options.maxHeight || this.maxHeight);
|
|
}
|
|
_fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
|
|
const { ctx, maxWidth, options: { labels: { padding } } } = this;
|
|
const hitboxes = this.legendHitBoxes = [];
|
|
const lineWidths = this.lineWidths = [
|
|
0
|
|
];
|
|
const lineHeight = itemHeight + padding;
|
|
let totalHeight = titleHeight;
|
|
ctx.textAlign = "left";
|
|
ctx.textBaseline = "middle";
|
|
let row = -1;
|
|
let top = -lineHeight;
|
|
this.legendItems.forEach((legendItem, i2) => {
|
|
const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;
|
|
if (i2 === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
|
|
totalHeight += lineHeight;
|
|
lineWidths[lineWidths.length - (i2 > 0 ? 0 : 1)] = 0;
|
|
top += lineHeight;
|
|
row++;
|
|
}
|
|
hitboxes[i2] = {
|
|
left: 0,
|
|
top,
|
|
row,
|
|
width: itemWidth,
|
|
height: itemHeight
|
|
};
|
|
lineWidths[lineWidths.length - 1] += itemWidth + padding;
|
|
});
|
|
return totalHeight;
|
|
}
|
|
_fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {
|
|
const { ctx, maxHeight, options: { labels: { padding } } } = this;
|
|
const hitboxes = this.legendHitBoxes = [];
|
|
const columnSizes = this.columnSizes = [];
|
|
const heightLimit = maxHeight - titleHeight;
|
|
let totalWidth = padding;
|
|
let currentColWidth = 0;
|
|
let currentColHeight = 0;
|
|
let left = 0;
|
|
let col = 0;
|
|
this.legendItems.forEach((legendItem, i2) => {
|
|
const { itemWidth, itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);
|
|
if (i2 > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
|
|
totalWidth += currentColWidth + padding;
|
|
columnSizes.push({
|
|
width: currentColWidth,
|
|
height: currentColHeight
|
|
});
|
|
left += currentColWidth + padding;
|
|
col++;
|
|
currentColWidth = currentColHeight = 0;
|
|
}
|
|
hitboxes[i2] = {
|
|
left,
|
|
top: currentColHeight,
|
|
col,
|
|
width: itemWidth,
|
|
height: itemHeight
|
|
};
|
|
currentColWidth = Math.max(currentColWidth, itemWidth);
|
|
currentColHeight += itemHeight + padding;
|
|
});
|
|
totalWidth += currentColWidth;
|
|
columnSizes.push({
|
|
width: currentColWidth,
|
|
height: currentColHeight
|
|
});
|
|
return totalWidth;
|
|
}
|
|
adjustHitBoxes() {
|
|
if (!this.options.display) {
|
|
return;
|
|
}
|
|
const titleHeight = this._computeTitleHeight();
|
|
const { legendHitBoxes: hitboxes, options: { align, labels: { padding }, rtl } } = this;
|
|
const rtlHelper = getRtlAdapter(rtl, this.left, this.width);
|
|
if (this.isHorizontal()) {
|
|
let row = 0;
|
|
let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
|
|
for (const hitbox of hitboxes) {
|
|
if (row !== hitbox.row) {
|
|
row = hitbox.row;
|
|
left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
|
|
}
|
|
hitbox.top += this.top + titleHeight + padding;
|
|
hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
|
|
left += hitbox.width + padding;
|
|
}
|
|
} else {
|
|
let col = 0;
|
|
let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
|
|
for (const hitbox of hitboxes) {
|
|
if (hitbox.col !== col) {
|
|
col = hitbox.col;
|
|
top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
|
|
}
|
|
hitbox.top = top;
|
|
hitbox.left += this.left + padding;
|
|
hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
|
|
top += hitbox.height + padding;
|
|
}
|
|
}
|
|
}
|
|
isHorizontal() {
|
|
return this.options.position === "top" || this.options.position === "bottom";
|
|
}
|
|
draw() {
|
|
if (this.options.display) {
|
|
const ctx = this.ctx;
|
|
clipArea(ctx, this);
|
|
this._draw();
|
|
unclipArea(ctx);
|
|
}
|
|
}
|
|
_draw() {
|
|
const { options: opts, columnSizes, lineWidths, ctx } = this;
|
|
const { align, labels: labelOpts } = opts;
|
|
const defaultColor = defaults2.color;
|
|
const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
|
|
const labelFont = toFont(labelOpts.font);
|
|
const { padding } = labelOpts;
|
|
const fontSize = labelFont.size;
|
|
const halfFontSize = fontSize / 2;
|
|
let cursor;
|
|
this.drawTitle();
|
|
ctx.textAlign = rtlHelper.textAlign("left");
|
|
ctx.textBaseline = "middle";
|
|
ctx.lineWidth = 0.5;
|
|
ctx.font = labelFont.string;
|
|
const { boxWidth, boxHeight, itemHeight } = getBoxSize(labelOpts, fontSize);
|
|
const drawLegendBox = function(x2, y2, legendItem) {
|
|
if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
|
|
return;
|
|
}
|
|
ctx.save();
|
|
const lineWidth = valueOrDefault(legendItem.lineWidth, 1);
|
|
ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
|
|
ctx.lineCap = valueOrDefault(legendItem.lineCap, "butt");
|
|
ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);
|
|
ctx.lineJoin = valueOrDefault(legendItem.lineJoin, "miter");
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
|
|
ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));
|
|
if (labelOpts.usePointStyle) {
|
|
const drawOptions = {
|
|
radius: boxHeight * Math.SQRT2 / 2,
|
|
pointStyle: legendItem.pointStyle,
|
|
rotation: legendItem.rotation,
|
|
borderWidth: lineWidth
|
|
};
|
|
const centerX = rtlHelper.xPlus(x2, boxWidth / 2);
|
|
const centerY = y2 + halfFontSize;
|
|
drawPointLegend(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);
|
|
} else {
|
|
const yBoxTop = y2 + Math.max((fontSize - boxHeight) / 2, 0);
|
|
const xBoxLeft = rtlHelper.leftForLtr(x2, boxWidth);
|
|
const borderRadius = toTRBLCorners(legendItem.borderRadius);
|
|
ctx.beginPath();
|
|
if (Object.values(borderRadius).some((v2) => v2 !== 0)) {
|
|
addRoundedRectPath(ctx, {
|
|
x: xBoxLeft,
|
|
y: yBoxTop,
|
|
w: boxWidth,
|
|
h: boxHeight,
|
|
radius: borderRadius
|
|
});
|
|
} else {
|
|
ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
|
|
}
|
|
ctx.fill();
|
|
if (lineWidth !== 0) {
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
ctx.restore();
|
|
};
|
|
const fillText = function(x2, y2, legendItem) {
|
|
renderText(ctx, legendItem.text, x2, y2 + itemHeight / 2, labelFont, {
|
|
strikethrough: legendItem.hidden,
|
|
textAlign: rtlHelper.textAlign(legendItem.textAlign)
|
|
});
|
|
};
|
|
const isHorizontal = this.isHorizontal();
|
|
const titleHeight = this._computeTitleHeight();
|
|
if (isHorizontal) {
|
|
cursor = {
|
|
x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]),
|
|
y: this.top + padding + titleHeight,
|
|
line: 0
|
|
};
|
|
} else {
|
|
cursor = {
|
|
x: this.left + padding,
|
|
y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
|
|
line: 0
|
|
};
|
|
}
|
|
overrideTextDirection(this.ctx, opts.textDirection);
|
|
const lineHeight = itemHeight + padding;
|
|
this.legendItems.forEach((legendItem, i2) => {
|
|
ctx.strokeStyle = legendItem.fontColor;
|
|
ctx.fillStyle = legendItem.fontColor;
|
|
const textWidth = ctx.measureText(legendItem.text).width;
|
|
const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
|
|
const width = boxWidth + halfFontSize + textWidth;
|
|
let x2 = cursor.x;
|
|
let y2 = cursor.y;
|
|
rtlHelper.setWidth(this.width);
|
|
if (isHorizontal) {
|
|
if (i2 > 0 && x2 + width + padding > this.right) {
|
|
y2 = cursor.y += lineHeight;
|
|
cursor.line++;
|
|
x2 = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]);
|
|
}
|
|
} else if (i2 > 0 && y2 + lineHeight > this.bottom) {
|
|
x2 = cursor.x = x2 + columnSizes[cursor.line].width + padding;
|
|
cursor.line++;
|
|
y2 = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
|
|
}
|
|
const realX = rtlHelper.x(x2);
|
|
drawLegendBox(realX, y2, legendItem);
|
|
x2 = _textX(textAlign, x2 + boxWidth + halfFontSize, isHorizontal ? x2 + width : this.right, opts.rtl);
|
|
fillText(rtlHelper.x(x2), y2, legendItem);
|
|
if (isHorizontal) {
|
|
cursor.x += width + padding;
|
|
} else if (typeof legendItem.text !== "string") {
|
|
const fontLineHeight = labelFont.lineHeight;
|
|
cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;
|
|
} else {
|
|
cursor.y += lineHeight;
|
|
}
|
|
});
|
|
restoreTextDirection(this.ctx, opts.textDirection);
|
|
}
|
|
drawTitle() {
|
|
const opts = this.options;
|
|
const titleOpts = opts.title;
|
|
const titleFont = toFont(titleOpts.font);
|
|
const titlePadding = toPadding(titleOpts.padding);
|
|
if (!titleOpts.display) {
|
|
return;
|
|
}
|
|
const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
|
|
const ctx = this.ctx;
|
|
const position = titleOpts.position;
|
|
const halfFontSize = titleFont.size / 2;
|
|
const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
|
|
let y2;
|
|
let left = this.left;
|
|
let maxWidth = this.width;
|
|
if (this.isHorizontal()) {
|
|
maxWidth = Math.max(...this.lineWidths);
|
|
y2 = this.top + topPaddingPlusHalfFontSize;
|
|
left = _alignStartEnd(opts.align, left, this.right - maxWidth);
|
|
} else {
|
|
const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
|
|
y2 = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
|
|
}
|
|
const x2 = _alignStartEnd(position, left, left + maxWidth);
|
|
ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));
|
|
ctx.textBaseline = "middle";
|
|
ctx.strokeStyle = titleOpts.color;
|
|
ctx.fillStyle = titleOpts.color;
|
|
ctx.font = titleFont.string;
|
|
renderText(ctx, titleOpts.text, x2, y2, titleFont);
|
|
}
|
|
_computeTitleHeight() {
|
|
const titleOpts = this.options.title;
|
|
const titleFont = toFont(titleOpts.font);
|
|
const titlePadding = toPadding(titleOpts.padding);
|
|
return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
|
|
}
|
|
_getLegendItemAt(x2, y2) {
|
|
let i2, hitBox, lh;
|
|
if (_isBetween(x2, this.left, this.right) && _isBetween(y2, this.top, this.bottom)) {
|
|
lh = this.legendHitBoxes;
|
|
for (i2 = 0; i2 < lh.length; ++i2) {
|
|
hitBox = lh[i2];
|
|
if (_isBetween(x2, hitBox.left, hitBox.left + hitBox.width) && _isBetween(y2, hitBox.top, hitBox.top + hitBox.height)) {
|
|
return this.legendItems[i2];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
handleEvent(e2) {
|
|
const opts = this.options;
|
|
if (!isListened(e2.type, opts)) {
|
|
return;
|
|
}
|
|
const hoveredItem = this._getLegendItemAt(e2.x, e2.y);
|
|
if (e2.type === "mousemove" || e2.type === "mouseout") {
|
|
const previous = this._hoveredItem;
|
|
const sameItem = itemsEqual(previous, hoveredItem);
|
|
if (previous && !sameItem) {
|
|
callback(opts.onLeave, [
|
|
e2,
|
|
previous,
|
|
this
|
|
], this);
|
|
}
|
|
this._hoveredItem = hoveredItem;
|
|
if (hoveredItem && !sameItem) {
|
|
callback(opts.onHover, [
|
|
e2,
|
|
hoveredItem,
|
|
this
|
|
], this);
|
|
}
|
|
} else if (hoveredItem) {
|
|
callback(opts.onClick, [
|
|
e2,
|
|
hoveredItem,
|
|
this
|
|
], this);
|
|
}
|
|
}
|
|
};
|
|
function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {
|
|
const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);
|
|
const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);
|
|
return {
|
|
itemWidth,
|
|
itemHeight
|
|
};
|
|
}
|
|
function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {
|
|
let legendItemText = legendItem.text;
|
|
if (legendItemText && typeof legendItemText !== "string") {
|
|
legendItemText = legendItemText.reduce((a2, b2) => a2.length > b2.length ? a2 : b2);
|
|
}
|
|
return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;
|
|
}
|
|
function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {
|
|
let itemHeight = _itemHeight;
|
|
if (typeof legendItem.text !== "string") {
|
|
itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);
|
|
}
|
|
return itemHeight;
|
|
}
|
|
function calculateLegendItemHeight(legendItem, fontLineHeight) {
|
|
const labelHeight = legendItem.text ? legendItem.text.length : 0;
|
|
return fontLineHeight * labelHeight;
|
|
}
|
|
function isListened(type, opts) {
|
|
if ((type === "mousemove" || type === "mouseout") && (opts.onHover || opts.onLeave)) {
|
|
return true;
|
|
}
|
|
if (opts.onClick && (type === "click" || type === "mouseup")) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
var plugin_legend = {
|
|
id: "legend",
|
|
_element: Legend,
|
|
start(chart, _args, options) {
|
|
const legend = chart.legend = new Legend({
|
|
ctx: chart.ctx,
|
|
options,
|
|
chart
|
|
});
|
|
layouts.configure(chart, legend, options);
|
|
layouts.addBox(chart, legend);
|
|
},
|
|
stop(chart) {
|
|
layouts.removeBox(chart, chart.legend);
|
|
delete chart.legend;
|
|
},
|
|
beforeUpdate(chart, _args, options) {
|
|
const legend = chart.legend;
|
|
layouts.configure(chart, legend, options);
|
|
legend.options = options;
|
|
},
|
|
afterUpdate(chart) {
|
|
const legend = chart.legend;
|
|
legend.buildLabels();
|
|
legend.adjustHitBoxes();
|
|
},
|
|
afterEvent(chart, args) {
|
|
if (!args.replay) {
|
|
chart.legend.handleEvent(args.event);
|
|
}
|
|
},
|
|
defaults: {
|
|
display: true,
|
|
position: "top",
|
|
align: "center",
|
|
fullSize: true,
|
|
reverse: false,
|
|
weight: 1e3,
|
|
onClick(e2, legendItem, legend) {
|
|
const index = legendItem.datasetIndex;
|
|
const ci = legend.chart;
|
|
if (ci.isDatasetVisible(index)) {
|
|
ci.hide(index);
|
|
legendItem.hidden = true;
|
|
} else {
|
|
ci.show(index);
|
|
legendItem.hidden = false;
|
|
}
|
|
},
|
|
onHover: null,
|
|
onLeave: null,
|
|
labels: {
|
|
color: (ctx) => ctx.chart.options.color,
|
|
boxWidth: 40,
|
|
padding: 10,
|
|
generateLabels(chart) {
|
|
const datasets = chart.data.datasets;
|
|
const { labels: { usePointStyle, pointStyle, textAlign, color: color2, useBorderRadius, borderRadius } } = chart.legend.options;
|
|
return chart._getSortedDatasetMetas().map((meta) => {
|
|
const style = meta.controller.getStyle(usePointStyle ? 0 : void 0);
|
|
const borderWidth = toPadding(style.borderWidth);
|
|
return {
|
|
text: datasets[meta.index].label,
|
|
fillStyle: style.backgroundColor,
|
|
fontColor: color2,
|
|
hidden: !meta.visible,
|
|
lineCap: style.borderCapStyle,
|
|
lineDash: style.borderDash,
|
|
lineDashOffset: style.borderDashOffset,
|
|
lineJoin: style.borderJoinStyle,
|
|
lineWidth: (borderWidth.width + borderWidth.height) / 4,
|
|
strokeStyle: style.borderColor,
|
|
pointStyle: pointStyle || style.pointStyle,
|
|
rotation: style.rotation,
|
|
textAlign: textAlign || style.textAlign,
|
|
borderRadius: useBorderRadius && (borderRadius || style.borderRadius),
|
|
datasetIndex: meta.index
|
|
};
|
|
}, this);
|
|
}
|
|
},
|
|
title: {
|
|
color: (ctx) => ctx.chart.options.color,
|
|
display: false,
|
|
position: "center",
|
|
text: ""
|
|
}
|
|
},
|
|
descriptors: {
|
|
_scriptable: (name) => !name.startsWith("on"),
|
|
labels: {
|
|
_scriptable: (name) => ![
|
|
"generateLabels",
|
|
"filter",
|
|
"sort"
|
|
].includes(name)
|
|
}
|
|
}
|
|
};
|
|
var Title = class extends Element {
|
|
constructor(config) {
|
|
super();
|
|
this.chart = config.chart;
|
|
this.options = config.options;
|
|
this.ctx = config.ctx;
|
|
this._padding = void 0;
|
|
this.top = void 0;
|
|
this.bottom = void 0;
|
|
this.left = void 0;
|
|
this.right = void 0;
|
|
this.width = void 0;
|
|
this.height = void 0;
|
|
this.position = void 0;
|
|
this.weight = void 0;
|
|
this.fullSize = void 0;
|
|
}
|
|
update(maxWidth, maxHeight) {
|
|
const opts = this.options;
|
|
this.left = 0;
|
|
this.top = 0;
|
|
if (!opts.display) {
|
|
this.width = this.height = this.right = this.bottom = 0;
|
|
return;
|
|
}
|
|
this.width = this.right = maxWidth;
|
|
this.height = this.bottom = maxHeight;
|
|
const lineCount = isArray(opts.text) ? opts.text.length : 1;
|
|
this._padding = toPadding(opts.padding);
|
|
const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height;
|
|
if (this.isHorizontal()) {
|
|
this.height = textSize;
|
|
} else {
|
|
this.width = textSize;
|
|
}
|
|
}
|
|
isHorizontal() {
|
|
const pos = this.options.position;
|
|
return pos === "top" || pos === "bottom";
|
|
}
|
|
_drawArgs(offset) {
|
|
const { top, left, bottom, right, options } = this;
|
|
const align = options.align;
|
|
let rotation = 0;
|
|
let maxWidth, titleX, titleY;
|
|
if (this.isHorizontal()) {
|
|
titleX = _alignStartEnd(align, left, right);
|
|
titleY = top + offset;
|
|
maxWidth = right - left;
|
|
} else {
|
|
if (options.position === "left") {
|
|
titleX = left + offset;
|
|
titleY = _alignStartEnd(align, bottom, top);
|
|
rotation = PI * -0.5;
|
|
} else {
|
|
titleX = right - offset;
|
|
titleY = _alignStartEnd(align, top, bottom);
|
|
rotation = PI * 0.5;
|
|
}
|
|
maxWidth = bottom - top;
|
|
}
|
|
return {
|
|
titleX,
|
|
titleY,
|
|
maxWidth,
|
|
rotation
|
|
};
|
|
}
|
|
draw() {
|
|
const ctx = this.ctx;
|
|
const opts = this.options;
|
|
if (!opts.display) {
|
|
return;
|
|
}
|
|
const fontOpts = toFont(opts.font);
|
|
const lineHeight = fontOpts.lineHeight;
|
|
const offset = lineHeight / 2 + this._padding.top;
|
|
const { titleX, titleY, maxWidth, rotation } = this._drawArgs(offset);
|
|
renderText(ctx, opts.text, 0, 0, fontOpts, {
|
|
color: opts.color,
|
|
maxWidth,
|
|
rotation,
|
|
textAlign: _toLeftRightCenter(opts.align),
|
|
textBaseline: "middle",
|
|
translation: [
|
|
titleX,
|
|
titleY
|
|
]
|
|
});
|
|
}
|
|
};
|
|
function createTitle(chart, titleOpts) {
|
|
const title = new Title({
|
|
ctx: chart.ctx,
|
|
options: titleOpts,
|
|
chart
|
|
});
|
|
layouts.configure(chart, title, titleOpts);
|
|
layouts.addBox(chart, title);
|
|
chart.titleBlock = title;
|
|
}
|
|
var plugin_title = {
|
|
id: "title",
|
|
_element: Title,
|
|
start(chart, _args, options) {
|
|
createTitle(chart, options);
|
|
},
|
|
stop(chart) {
|
|
const titleBlock = chart.titleBlock;
|
|
layouts.removeBox(chart, titleBlock);
|
|
delete chart.titleBlock;
|
|
},
|
|
beforeUpdate(chart, _args, options) {
|
|
const title = chart.titleBlock;
|
|
layouts.configure(chart, title, options);
|
|
title.options = options;
|
|
},
|
|
defaults: {
|
|
align: "center",
|
|
display: false,
|
|
font: {
|
|
weight: "bold"
|
|
},
|
|
fullSize: true,
|
|
padding: 10,
|
|
position: "top",
|
|
text: "",
|
|
weight: 2e3
|
|
},
|
|
defaultRoutes: {
|
|
color: "color"
|
|
},
|
|
descriptors: {
|
|
_scriptable: true,
|
|
_indexable: false
|
|
}
|
|
};
|
|
var map2 = /* @__PURE__ */ new WeakMap();
|
|
var plugin_subtitle = {
|
|
id: "subtitle",
|
|
start(chart, _args, options) {
|
|
const title = new Title({
|
|
ctx: chart.ctx,
|
|
options,
|
|
chart
|
|
});
|
|
layouts.configure(chart, title, options);
|
|
layouts.addBox(chart, title);
|
|
map2.set(chart, title);
|
|
},
|
|
stop(chart) {
|
|
layouts.removeBox(chart, map2.get(chart));
|
|
map2.delete(chart);
|
|
},
|
|
beforeUpdate(chart, _args, options) {
|
|
const title = map2.get(chart);
|
|
layouts.configure(chart, title, options);
|
|
title.options = options;
|
|
},
|
|
defaults: {
|
|
align: "center",
|
|
display: false,
|
|
font: {
|
|
weight: "normal"
|
|
},
|
|
fullSize: true,
|
|
padding: 0,
|
|
position: "top",
|
|
text: "",
|
|
weight: 1500
|
|
},
|
|
defaultRoutes: {
|
|
color: "color"
|
|
},
|
|
descriptors: {
|
|
_scriptable: true,
|
|
_indexable: false
|
|
}
|
|
};
|
|
var positioners = {
|
|
average(items) {
|
|
if (!items.length) {
|
|
return false;
|
|
}
|
|
let i2, len;
|
|
let xSet = /* @__PURE__ */ new Set();
|
|
let y2 = 0;
|
|
let count = 0;
|
|
for (i2 = 0, len = items.length; i2 < len; ++i2) {
|
|
const el = items[i2].element;
|
|
if (el && el.hasValue()) {
|
|
const pos = el.tooltipPosition();
|
|
xSet.add(pos.x);
|
|
y2 += pos.y;
|
|
++count;
|
|
}
|
|
}
|
|
if (count === 0 || xSet.size === 0) {
|
|
return false;
|
|
}
|
|
const xAverage = [
|
|
...xSet
|
|
].reduce((a2, b2) => a2 + b2) / xSet.size;
|
|
return {
|
|
x: xAverage,
|
|
y: y2 / count
|
|
};
|
|
},
|
|
nearest(items, eventPosition) {
|
|
if (!items.length) {
|
|
return false;
|
|
}
|
|
let x2 = eventPosition.x;
|
|
let y2 = eventPosition.y;
|
|
let minDistance = Number.POSITIVE_INFINITY;
|
|
let i2, len, nearestElement;
|
|
for (i2 = 0, len = items.length; i2 < len; ++i2) {
|
|
const el = items[i2].element;
|
|
if (el && el.hasValue()) {
|
|
const center = el.getCenterPoint();
|
|
const d2 = distanceBetweenPoints(eventPosition, center);
|
|
if (d2 < minDistance) {
|
|
minDistance = d2;
|
|
nearestElement = el;
|
|
}
|
|
}
|
|
}
|
|
if (nearestElement) {
|
|
const tp = nearestElement.tooltipPosition();
|
|
x2 = tp.x;
|
|
y2 = tp.y;
|
|
}
|
|
return {
|
|
x: x2,
|
|
y: y2
|
|
};
|
|
}
|
|
};
|
|
function pushOrConcat(base, toPush) {
|
|
if (toPush) {
|
|
if (isArray(toPush)) {
|
|
Array.prototype.push.apply(base, toPush);
|
|
} else {
|
|
base.push(toPush);
|
|
}
|
|
}
|
|
return base;
|
|
}
|
|
function splitNewlines(str) {
|
|
if ((typeof str === "string" || str instanceof String) && str.indexOf("\n") > -1) {
|
|
return str.split("\n");
|
|
}
|
|
return str;
|
|
}
|
|
function createTooltipItem(chart, item) {
|
|
const { element, datasetIndex, index } = item;
|
|
const controller = chart.getDatasetMeta(datasetIndex).controller;
|
|
const { label, value } = controller.getLabelAndValue(index);
|
|
return {
|
|
chart,
|
|
label,
|
|
parsed: controller.getParsed(index),
|
|
raw: chart.data.datasets[datasetIndex].data[index],
|
|
formattedValue: value,
|
|
dataset: controller.getDataset(),
|
|
dataIndex: index,
|
|
datasetIndex,
|
|
element
|
|
};
|
|
}
|
|
function getTooltipSize(tooltip, options) {
|
|
const ctx = tooltip.chart.ctx;
|
|
const { body, footer, title } = tooltip;
|
|
const { boxWidth, boxHeight } = options;
|
|
const bodyFont = toFont(options.bodyFont);
|
|
const titleFont = toFont(options.titleFont);
|
|
const footerFont = toFont(options.footerFont);
|
|
const titleLineCount = title.length;
|
|
const footerLineCount = footer.length;
|
|
const bodyLineItemCount = body.length;
|
|
const padding = toPadding(options.padding);
|
|
let height = padding.height;
|
|
let width = 0;
|
|
let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
|
|
combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
|
|
if (titleLineCount) {
|
|
height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;
|
|
}
|
|
if (combinedBodyLength) {
|
|
const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
|
|
height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;
|
|
}
|
|
if (footerLineCount) {
|
|
height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;
|
|
}
|
|
let widthPadding = 0;
|
|
const maxLineWidth = function(line) {
|
|
width = Math.max(width, ctx.measureText(line).width + widthPadding);
|
|
};
|
|
ctx.save();
|
|
ctx.font = titleFont.string;
|
|
each(tooltip.title, maxLineWidth);
|
|
ctx.font = bodyFont.string;
|
|
each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
|
|
widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;
|
|
each(body, (bodyItem) => {
|
|
each(bodyItem.before, maxLineWidth);
|
|
each(bodyItem.lines, maxLineWidth);
|
|
each(bodyItem.after, maxLineWidth);
|
|
});
|
|
widthPadding = 0;
|
|
ctx.font = footerFont.string;
|
|
each(tooltip.footer, maxLineWidth);
|
|
ctx.restore();
|
|
width += padding.width;
|
|
return {
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
function determineYAlign(chart, size) {
|
|
const { y: y2, height } = size;
|
|
if (y2 < height / 2) {
|
|
return "top";
|
|
} else if (y2 > chart.height - height / 2) {
|
|
return "bottom";
|
|
}
|
|
return "center";
|
|
}
|
|
function doesNotFitWithAlign(xAlign, chart, options, size) {
|
|
const { x: x2, width } = size;
|
|
const caret = options.caretSize + options.caretPadding;
|
|
if (xAlign === "left" && x2 + width + caret > chart.width) {
|
|
return true;
|
|
}
|
|
if (xAlign === "right" && x2 - width - caret < 0) {
|
|
return true;
|
|
}
|
|
}
|
|
function determineXAlign(chart, options, size, yAlign) {
|
|
const { x: x2, width } = size;
|
|
const { width: chartWidth, chartArea: { left, right } } = chart;
|
|
let xAlign = "center";
|
|
if (yAlign === "center") {
|
|
xAlign = x2 <= (left + right) / 2 ? "left" : "right";
|
|
} else if (x2 <= width / 2) {
|
|
xAlign = "left";
|
|
} else if (x2 >= chartWidth - width / 2) {
|
|
xAlign = "right";
|
|
}
|
|
if (doesNotFitWithAlign(xAlign, chart, options, size)) {
|
|
xAlign = "center";
|
|
}
|
|
return xAlign;
|
|
}
|
|
function determineAlignment(chart, options, size) {
|
|
const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
|
|
return {
|
|
xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
|
|
yAlign
|
|
};
|
|
}
|
|
function alignX(size, xAlign) {
|
|
let { x: x2, width } = size;
|
|
if (xAlign === "right") {
|
|
x2 -= width;
|
|
} else if (xAlign === "center") {
|
|
x2 -= width / 2;
|
|
}
|
|
return x2;
|
|
}
|
|
function alignY(size, yAlign, paddingAndSize) {
|
|
let { y: y2, height } = size;
|
|
if (yAlign === "top") {
|
|
y2 += paddingAndSize;
|
|
} else if (yAlign === "bottom") {
|
|
y2 -= height + paddingAndSize;
|
|
} else {
|
|
y2 -= height / 2;
|
|
}
|
|
return y2;
|
|
}
|
|
function getBackgroundPoint(options, size, alignment, chart) {
|
|
const { caretSize, caretPadding, cornerRadius } = options;
|
|
const { xAlign, yAlign } = alignment;
|
|
const paddingAndSize = caretSize + caretPadding;
|
|
const { topLeft, topRight, bottomLeft, bottomRight } = toTRBLCorners(cornerRadius);
|
|
let x2 = alignX(size, xAlign);
|
|
const y2 = alignY(size, yAlign, paddingAndSize);
|
|
if (yAlign === "center") {
|
|
if (xAlign === "left") {
|
|
x2 += paddingAndSize;
|
|
} else if (xAlign === "right") {
|
|
x2 -= paddingAndSize;
|
|
}
|
|
} else if (xAlign === "left") {
|
|
x2 -= Math.max(topLeft, bottomLeft) + caretSize;
|
|
} else if (xAlign === "right") {
|
|
x2 += Math.max(topRight, bottomRight) + caretSize;
|
|
}
|
|
return {
|
|
x: _limitValue(x2, 0, chart.width - size.width),
|
|
y: _limitValue(y2, 0, chart.height - size.height)
|
|
};
|
|
}
|
|
function getAlignedX(tooltip, align, options) {
|
|
const padding = toPadding(options.padding);
|
|
return align === "center" ? tooltip.x + tooltip.width / 2 : align === "right" ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;
|
|
}
|
|
function getBeforeAfterBodyLines(callback2) {
|
|
return pushOrConcat([], splitNewlines(callback2));
|
|
}
|
|
function createTooltipContext(parent, tooltip, tooltipItems) {
|
|
return createContext(parent, {
|
|
tooltip,
|
|
tooltipItems,
|
|
type: "tooltip"
|
|
});
|
|
}
|
|
function overrideCallbacks(callbacks, context) {
|
|
const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
|
|
return override ? callbacks.override(override) : callbacks;
|
|
}
|
|
var defaultCallbacks = {
|
|
beforeTitle: noop,
|
|
title(tooltipItems) {
|
|
if (tooltipItems.length > 0) {
|
|
const item = tooltipItems[0];
|
|
const labels = item.chart.data.labels;
|
|
const labelCount = labels ? labels.length : 0;
|
|
if (this && this.options && this.options.mode === "dataset") {
|
|
return item.dataset.label || "";
|
|
} else if (item.label) {
|
|
return item.label;
|
|
} else if (labelCount > 0 && item.dataIndex < labelCount) {
|
|
return labels[item.dataIndex];
|
|
}
|
|
}
|
|
return "";
|
|
},
|
|
afterTitle: noop,
|
|
beforeBody: noop,
|
|
beforeLabel: noop,
|
|
label(tooltipItem) {
|
|
if (this && this.options && this.options.mode === "dataset") {
|
|
return tooltipItem.label + ": " + tooltipItem.formattedValue || tooltipItem.formattedValue;
|
|
}
|
|
let label = tooltipItem.dataset.label || "";
|
|
if (label) {
|
|
label += ": ";
|
|
}
|
|
const value = tooltipItem.formattedValue;
|
|
if (!isNullOrUndef(value)) {
|
|
label += value;
|
|
}
|
|
return label;
|
|
},
|
|
labelColor(tooltipItem) {
|
|
const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
|
|
const options = meta.controller.getStyle(tooltipItem.dataIndex);
|
|
return {
|
|
borderColor: options.borderColor,
|
|
backgroundColor: options.backgroundColor,
|
|
borderWidth: options.borderWidth,
|
|
borderDash: options.borderDash,
|
|
borderDashOffset: options.borderDashOffset,
|
|
borderRadius: 0
|
|
};
|
|
},
|
|
labelTextColor() {
|
|
return this.options.bodyColor;
|
|
},
|
|
labelPointStyle(tooltipItem) {
|
|
const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
|
|
const options = meta.controller.getStyle(tooltipItem.dataIndex);
|
|
return {
|
|
pointStyle: options.pointStyle,
|
|
rotation: options.rotation
|
|
};
|
|
},
|
|
afterLabel: noop,
|
|
afterBody: noop,
|
|
beforeFooter: noop,
|
|
footer: noop,
|
|
afterFooter: noop
|
|
};
|
|
function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
|
|
const result = callbacks[name].call(ctx, arg);
|
|
if (typeof result === "undefined") {
|
|
return defaultCallbacks[name].call(ctx, arg);
|
|
}
|
|
return result;
|
|
}
|
|
var Tooltip = class extends Element {
|
|
constructor(config) {
|
|
super();
|
|
this.opacity = 0;
|
|
this._active = [];
|
|
this._eventPosition = void 0;
|
|
this._size = void 0;
|
|
this._cachedAnimations = void 0;
|
|
this._tooltipItems = [];
|
|
this.$animations = void 0;
|
|
this.$context = void 0;
|
|
this.chart = config.chart;
|
|
this.options = config.options;
|
|
this.dataPoints = void 0;
|
|
this.title = void 0;
|
|
this.beforeBody = void 0;
|
|
this.body = void 0;
|
|
this.afterBody = void 0;
|
|
this.footer = void 0;
|
|
this.xAlign = void 0;
|
|
this.yAlign = void 0;
|
|
this.x = void 0;
|
|
this.y = void 0;
|
|
this.height = void 0;
|
|
this.width = void 0;
|
|
this.caretX = void 0;
|
|
this.caretY = void 0;
|
|
this.labelColors = void 0;
|
|
this.labelPointStyles = void 0;
|
|
this.labelTextColors = void 0;
|
|
}
|
|
initialize(options) {
|
|
this.options = options;
|
|
this._cachedAnimations = void 0;
|
|
this.$context = void 0;
|
|
}
|
|
_resolveAnimations() {
|
|
const cached = this._cachedAnimations;
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
const chart = this.chart;
|
|
const options = this.options.setContext(this.getContext());
|
|
const opts = options.enabled && chart.options.animation && options.animations;
|
|
const animations = new Animations(this.chart, opts);
|
|
if (opts._cacheable) {
|
|
this._cachedAnimations = Object.freeze(animations);
|
|
}
|
|
return animations;
|
|
}
|
|
getContext() {
|
|
return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
|
|
}
|
|
getTitle(context, options) {
|
|
const { callbacks } = options;
|
|
const beforeTitle = invokeCallbackWithFallback(callbacks, "beforeTitle", this, context);
|
|
const title = invokeCallbackWithFallback(callbacks, "title", this, context);
|
|
const afterTitle = invokeCallbackWithFallback(callbacks, "afterTitle", this, context);
|
|
let lines = [];
|
|
lines = pushOrConcat(lines, splitNewlines(beforeTitle));
|
|
lines = pushOrConcat(lines, splitNewlines(title));
|
|
lines = pushOrConcat(lines, splitNewlines(afterTitle));
|
|
return lines;
|
|
}
|
|
getBeforeBody(tooltipItems, options) {
|
|
return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, "beforeBody", this, tooltipItems));
|
|
}
|
|
getBody(tooltipItems, options) {
|
|
const { callbacks } = options;
|
|
const bodyItems = [];
|
|
each(tooltipItems, (context) => {
|
|
const bodyItem = {
|
|
before: [],
|
|
lines: [],
|
|
after: []
|
|
};
|
|
const scoped = overrideCallbacks(callbacks, context);
|
|
pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, "beforeLabel", this, context)));
|
|
pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, "label", this, context));
|
|
pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, "afterLabel", this, context)));
|
|
bodyItems.push(bodyItem);
|
|
});
|
|
return bodyItems;
|
|
}
|
|
getAfterBody(tooltipItems, options) {
|
|
return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, "afterBody", this, tooltipItems));
|
|
}
|
|
getFooter(tooltipItems, options) {
|
|
const { callbacks } = options;
|
|
const beforeFooter = invokeCallbackWithFallback(callbacks, "beforeFooter", this, tooltipItems);
|
|
const footer = invokeCallbackWithFallback(callbacks, "footer", this, tooltipItems);
|
|
const afterFooter = invokeCallbackWithFallback(callbacks, "afterFooter", this, tooltipItems);
|
|
let lines = [];
|
|
lines = pushOrConcat(lines, splitNewlines(beforeFooter));
|
|
lines = pushOrConcat(lines, splitNewlines(footer));
|
|
lines = pushOrConcat(lines, splitNewlines(afterFooter));
|
|
return lines;
|
|
}
|
|
_createItems(options) {
|
|
const active = this._active;
|
|
const data = this.chart.data;
|
|
const labelColors = [];
|
|
const labelPointStyles = [];
|
|
const labelTextColors = [];
|
|
let tooltipItems = [];
|
|
let i2, len;
|
|
for (i2 = 0, len = active.length; i2 < len; ++i2) {
|
|
tooltipItems.push(createTooltipItem(this.chart, active[i2]));
|
|
}
|
|
if (options.filter) {
|
|
tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));
|
|
}
|
|
if (options.itemSort) {
|
|
tooltipItems = tooltipItems.sort((a2, b2) => options.itemSort(a2, b2, data));
|
|
}
|
|
each(tooltipItems, (context) => {
|
|
const scoped = overrideCallbacks(options.callbacks, context);
|
|
labelColors.push(invokeCallbackWithFallback(scoped, "labelColor", this, context));
|
|
labelPointStyles.push(invokeCallbackWithFallback(scoped, "labelPointStyle", this, context));
|
|
labelTextColors.push(invokeCallbackWithFallback(scoped, "labelTextColor", this, context));
|
|
});
|
|
this.labelColors = labelColors;
|
|
this.labelPointStyles = labelPointStyles;
|
|
this.labelTextColors = labelTextColors;
|
|
this.dataPoints = tooltipItems;
|
|
return tooltipItems;
|
|
}
|
|
update(changed, replay) {
|
|
const options = this.options.setContext(this.getContext());
|
|
const active = this._active;
|
|
let properties;
|
|
let tooltipItems = [];
|
|
if (!active.length) {
|
|
if (this.opacity !== 0) {
|
|
properties = {
|
|
opacity: 0
|
|
};
|
|
}
|
|
} else {
|
|
const position = positioners[options.position].call(this, active, this._eventPosition);
|
|
tooltipItems = this._createItems(options);
|
|
this.title = this.getTitle(tooltipItems, options);
|
|
this.beforeBody = this.getBeforeBody(tooltipItems, options);
|
|
this.body = this.getBody(tooltipItems, options);
|
|
this.afterBody = this.getAfterBody(tooltipItems, options);
|
|
this.footer = this.getFooter(tooltipItems, options);
|
|
const size = this._size = getTooltipSize(this, options);
|
|
const positionAndSize = Object.assign({}, position, size);
|
|
const alignment = determineAlignment(this.chart, options, positionAndSize);
|
|
const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
|
|
this.xAlign = alignment.xAlign;
|
|
this.yAlign = alignment.yAlign;
|
|
properties = {
|
|
opacity: 1,
|
|
x: backgroundPoint.x,
|
|
y: backgroundPoint.y,
|
|
width: size.width,
|
|
height: size.height,
|
|
caretX: position.x,
|
|
caretY: position.y
|
|
};
|
|
}
|
|
this._tooltipItems = tooltipItems;
|
|
this.$context = void 0;
|
|
if (properties) {
|
|
this._resolveAnimations().update(this, properties);
|
|
}
|
|
if (changed && options.external) {
|
|
options.external.call(this, {
|
|
chart: this.chart,
|
|
tooltip: this,
|
|
replay
|
|
});
|
|
}
|
|
}
|
|
drawCaret(tooltipPoint, ctx, size, options) {
|
|
const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
|
|
ctx.lineTo(caretPosition.x1, caretPosition.y1);
|
|
ctx.lineTo(caretPosition.x2, caretPosition.y2);
|
|
ctx.lineTo(caretPosition.x3, caretPosition.y3);
|
|
}
|
|
getCaretPosition(tooltipPoint, size, options) {
|
|
const { xAlign, yAlign } = this;
|
|
const { caretSize, cornerRadius } = options;
|
|
const { topLeft, topRight, bottomLeft, bottomRight } = toTRBLCorners(cornerRadius);
|
|
const { x: ptX, y: ptY } = tooltipPoint;
|
|
const { width, height } = size;
|
|
let x1, x2, x3, y1, y2, y3;
|
|
if (yAlign === "center") {
|
|
y2 = ptY + height / 2;
|
|
if (xAlign === "left") {
|
|
x1 = ptX;
|
|
x2 = x1 - caretSize;
|
|
y1 = y2 + caretSize;
|
|
y3 = y2 - caretSize;
|
|
} else {
|
|
x1 = ptX + width;
|
|
x2 = x1 + caretSize;
|
|
y1 = y2 - caretSize;
|
|
y3 = y2 + caretSize;
|
|
}
|
|
x3 = x1;
|
|
} else {
|
|
if (xAlign === "left") {
|
|
x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;
|
|
} else if (xAlign === "right") {
|
|
x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
|
|
} else {
|
|
x2 = this.caretX;
|
|
}
|
|
if (yAlign === "top") {
|
|
y1 = ptY;
|
|
y2 = y1 - caretSize;
|
|
x1 = x2 - caretSize;
|
|
x3 = x2 + caretSize;
|
|
} else {
|
|
y1 = ptY + height;
|
|
y2 = y1 + caretSize;
|
|
x1 = x2 + caretSize;
|
|
x3 = x2 - caretSize;
|
|
}
|
|
y3 = y1;
|
|
}
|
|
return {
|
|
x1,
|
|
x2,
|
|
x3,
|
|
y1,
|
|
y2,
|
|
y3
|
|
};
|
|
}
|
|
drawTitle(pt2, ctx, options) {
|
|
const title = this.title;
|
|
const length = title.length;
|
|
let titleFont, titleSpacing, i2;
|
|
if (length) {
|
|
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
|
pt2.x = getAlignedX(this, options.titleAlign, options);
|
|
ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
|
|
ctx.textBaseline = "middle";
|
|
titleFont = toFont(options.titleFont);
|
|
titleSpacing = options.titleSpacing;
|
|
ctx.fillStyle = options.titleColor;
|
|
ctx.font = titleFont.string;
|
|
for (i2 = 0; i2 < length; ++i2) {
|
|
ctx.fillText(title[i2], rtlHelper.x(pt2.x), pt2.y + titleFont.lineHeight / 2);
|
|
pt2.y += titleFont.lineHeight + titleSpacing;
|
|
if (i2 + 1 === length) {
|
|
pt2.y += options.titleMarginBottom - titleSpacing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_drawColorBox(ctx, pt2, i2, rtlHelper, options) {
|
|
const labelColor = this.labelColors[i2];
|
|
const labelPointStyle = this.labelPointStyles[i2];
|
|
const { boxHeight, boxWidth } = options;
|
|
const bodyFont = toFont(options.bodyFont);
|
|
const colorX = getAlignedX(this, "left", options);
|
|
const rtlColorX = rtlHelper.x(colorX);
|
|
const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
|
|
const colorY = pt2.y + yOffSet;
|
|
if (options.usePointStyle) {
|
|
const drawOptions = {
|
|
radius: Math.min(boxWidth, boxHeight) / 2,
|
|
pointStyle: labelPointStyle.pointStyle,
|
|
rotation: labelPointStyle.rotation,
|
|
borderWidth: 1
|
|
};
|
|
const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
|
|
const centerY = colorY + boxHeight / 2;
|
|
ctx.strokeStyle = options.multiKeyBackground;
|
|
ctx.fillStyle = options.multiKeyBackground;
|
|
drawPoint(ctx, drawOptions, centerX, centerY);
|
|
ctx.strokeStyle = labelColor.borderColor;
|
|
ctx.fillStyle = labelColor.backgroundColor;
|
|
drawPoint(ctx, drawOptions, centerX, centerY);
|
|
} else {
|
|
ctx.lineWidth = isObject(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;
|
|
ctx.strokeStyle = labelColor.borderColor;
|
|
ctx.setLineDash(labelColor.borderDash || []);
|
|
ctx.lineDashOffset = labelColor.borderDashOffset || 0;
|
|
const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);
|
|
const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);
|
|
const borderRadius = toTRBLCorners(labelColor.borderRadius);
|
|
if (Object.values(borderRadius).some((v2) => v2 !== 0)) {
|
|
ctx.beginPath();
|
|
ctx.fillStyle = options.multiKeyBackground;
|
|
addRoundedRectPath(ctx, {
|
|
x: outerX,
|
|
y: colorY,
|
|
w: boxWidth,
|
|
h: boxHeight,
|
|
radius: borderRadius
|
|
});
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
ctx.fillStyle = labelColor.backgroundColor;
|
|
ctx.beginPath();
|
|
addRoundedRectPath(ctx, {
|
|
x: innerX,
|
|
y: colorY + 1,
|
|
w: boxWidth - 2,
|
|
h: boxHeight - 2,
|
|
radius: borderRadius
|
|
});
|
|
ctx.fill();
|
|
} else {
|
|
ctx.fillStyle = options.multiKeyBackground;
|
|
ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
|
|
ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
|
|
ctx.fillStyle = labelColor.backgroundColor;
|
|
ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
|
|
}
|
|
}
|
|
ctx.fillStyle = this.labelTextColors[i2];
|
|
}
|
|
drawBody(pt2, ctx, options) {
|
|
const { body } = this;
|
|
const { bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding } = options;
|
|
const bodyFont = toFont(options.bodyFont);
|
|
let bodyLineHeight = bodyFont.lineHeight;
|
|
let xLinePadding = 0;
|
|
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
|
const fillLineOfText = function(line) {
|
|
ctx.fillText(line, rtlHelper.x(pt2.x + xLinePadding), pt2.y + bodyLineHeight / 2);
|
|
pt2.y += bodyLineHeight + bodySpacing;
|
|
};
|
|
const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
|
|
let bodyItem, textColor, lines, i2, j2, ilen, jlen;
|
|
ctx.textAlign = bodyAlign;
|
|
ctx.textBaseline = "middle";
|
|
ctx.font = bodyFont.string;
|
|
pt2.x = getAlignedX(this, bodyAlignForCalculation, options);
|
|
ctx.fillStyle = options.bodyColor;
|
|
each(this.beforeBody, fillLineOfText);
|
|
xLinePadding = displayColors && bodyAlignForCalculation !== "right" ? bodyAlign === "center" ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;
|
|
for (i2 = 0, ilen = body.length; i2 < ilen; ++i2) {
|
|
bodyItem = body[i2];
|
|
textColor = this.labelTextColors[i2];
|
|
ctx.fillStyle = textColor;
|
|
each(bodyItem.before, fillLineOfText);
|
|
lines = bodyItem.lines;
|
|
if (displayColors && lines.length) {
|
|
this._drawColorBox(ctx, pt2, i2, rtlHelper, options);
|
|
bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
|
|
}
|
|
for (j2 = 0, jlen = lines.length; j2 < jlen; ++j2) {
|
|
fillLineOfText(lines[j2]);
|
|
bodyLineHeight = bodyFont.lineHeight;
|
|
}
|
|
each(bodyItem.after, fillLineOfText);
|
|
}
|
|
xLinePadding = 0;
|
|
bodyLineHeight = bodyFont.lineHeight;
|
|
each(this.afterBody, fillLineOfText);
|
|
pt2.y -= bodySpacing;
|
|
}
|
|
drawFooter(pt2, ctx, options) {
|
|
const footer = this.footer;
|
|
const length = footer.length;
|
|
let footerFont, i2;
|
|
if (length) {
|
|
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
|
pt2.x = getAlignedX(this, options.footerAlign, options);
|
|
pt2.y += options.footerMarginTop;
|
|
ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
|
|
ctx.textBaseline = "middle";
|
|
footerFont = toFont(options.footerFont);
|
|
ctx.fillStyle = options.footerColor;
|
|
ctx.font = footerFont.string;
|
|
for (i2 = 0; i2 < length; ++i2) {
|
|
ctx.fillText(footer[i2], rtlHelper.x(pt2.x), pt2.y + footerFont.lineHeight / 2);
|
|
pt2.y += footerFont.lineHeight + options.footerSpacing;
|
|
}
|
|
}
|
|
}
|
|
drawBackground(pt2, ctx, tooltipSize, options) {
|
|
const { xAlign, yAlign } = this;
|
|
const { x: x2, y: y2 } = pt2;
|
|
const { width, height } = tooltipSize;
|
|
const { topLeft, topRight, bottomLeft, bottomRight } = toTRBLCorners(options.cornerRadius);
|
|
ctx.fillStyle = options.backgroundColor;
|
|
ctx.strokeStyle = options.borderColor;
|
|
ctx.lineWidth = options.borderWidth;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x2 + topLeft, y2);
|
|
if (yAlign === "top") {
|
|
this.drawCaret(pt2, ctx, tooltipSize, options);
|
|
}
|
|
ctx.lineTo(x2 + width - topRight, y2);
|
|
ctx.quadraticCurveTo(x2 + width, y2, x2 + width, y2 + topRight);
|
|
if (yAlign === "center" && xAlign === "right") {
|
|
this.drawCaret(pt2, ctx, tooltipSize, options);
|
|
}
|
|
ctx.lineTo(x2 + width, y2 + height - bottomRight);
|
|
ctx.quadraticCurveTo(x2 + width, y2 + height, x2 + width - bottomRight, y2 + height);
|
|
if (yAlign === "bottom") {
|
|
this.drawCaret(pt2, ctx, tooltipSize, options);
|
|
}
|
|
ctx.lineTo(x2 + bottomLeft, y2 + height);
|
|
ctx.quadraticCurveTo(x2, y2 + height, x2, y2 + height - bottomLeft);
|
|
if (yAlign === "center" && xAlign === "left") {
|
|
this.drawCaret(pt2, ctx, tooltipSize, options);
|
|
}
|
|
ctx.lineTo(x2, y2 + topLeft);
|
|
ctx.quadraticCurveTo(x2, y2, x2 + topLeft, y2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
if (options.borderWidth > 0) {
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
_updateAnimationTarget(options) {
|
|
const chart = this.chart;
|
|
const anims = this.$animations;
|
|
const animX = anims && anims.x;
|
|
const animY = anims && anims.y;
|
|
if (animX || animY) {
|
|
const position = positioners[options.position].call(this, this._active, this._eventPosition);
|
|
if (!position) {
|
|
return;
|
|
}
|
|
const size = this._size = getTooltipSize(this, options);
|
|
const positionAndSize = Object.assign({}, position, this._size);
|
|
const alignment = determineAlignment(chart, options, positionAndSize);
|
|
const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
|
|
if (animX._to !== point.x || animY._to !== point.y) {
|
|
this.xAlign = alignment.xAlign;
|
|
this.yAlign = alignment.yAlign;
|
|
this.width = size.width;
|
|
this.height = size.height;
|
|
this.caretX = position.x;
|
|
this.caretY = position.y;
|
|
this._resolveAnimations().update(this, point);
|
|
}
|
|
}
|
|
}
|
|
_willRender() {
|
|
return !!this.opacity;
|
|
}
|
|
draw(ctx) {
|
|
const options = this.options.setContext(this.getContext());
|
|
let opacity = this.opacity;
|
|
if (!opacity) {
|
|
return;
|
|
}
|
|
this._updateAnimationTarget(options);
|
|
const tooltipSize = {
|
|
width: this.width,
|
|
height: this.height
|
|
};
|
|
const pt2 = {
|
|
x: this.x,
|
|
y: this.y
|
|
};
|
|
opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
|
|
const padding = toPadding(options.padding);
|
|
const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
|
|
if (options.enabled && hasTooltipContent) {
|
|
ctx.save();
|
|
ctx.globalAlpha = opacity;
|
|
this.drawBackground(pt2, ctx, tooltipSize, options);
|
|
overrideTextDirection(ctx, options.textDirection);
|
|
pt2.y += padding.top;
|
|
this.drawTitle(pt2, ctx, options);
|
|
this.drawBody(pt2, ctx, options);
|
|
this.drawFooter(pt2, ctx, options);
|
|
restoreTextDirection(ctx, options.textDirection);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
getActiveElements() {
|
|
return this._active || [];
|
|
}
|
|
setActiveElements(activeElements, eventPosition) {
|
|
const lastActive = this._active;
|
|
const active = activeElements.map(({ datasetIndex, index }) => {
|
|
const meta = this.chart.getDatasetMeta(datasetIndex);
|
|
if (!meta) {
|
|
throw new Error("Cannot find a dataset at index " + datasetIndex);
|
|
}
|
|
return {
|
|
datasetIndex,
|
|
element: meta.data[index],
|
|
index
|
|
};
|
|
});
|
|
const changed = !_elementsEqual(lastActive, active);
|
|
const positionChanged = this._positionChanged(active, eventPosition);
|
|
if (changed || positionChanged) {
|
|
this._active = active;
|
|
this._eventPosition = eventPosition;
|
|
this._ignoreReplayEvents = true;
|
|
this.update(true);
|
|
}
|
|
}
|
|
handleEvent(e2, replay, inChartArea = true) {
|
|
if (replay && this._ignoreReplayEvents) {
|
|
return false;
|
|
}
|
|
this._ignoreReplayEvents = false;
|
|
const options = this.options;
|
|
const lastActive = this._active || [];
|
|
const active = this._getActiveElements(e2, lastActive, replay, inChartArea);
|
|
const positionChanged = this._positionChanged(active, e2);
|
|
const changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
|
|
if (changed) {
|
|
this._active = active;
|
|
if (options.enabled || options.external) {
|
|
this._eventPosition = {
|
|
x: e2.x,
|
|
y: e2.y
|
|
};
|
|
this.update(true, replay);
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
_getActiveElements(e2, lastActive, replay, inChartArea) {
|
|
const options = this.options;
|
|
if (e2.type === "mouseout") {
|
|
return [];
|
|
}
|
|
if (!inChartArea) {
|
|
return lastActive.filter((i2) => this.chart.data.datasets[i2.datasetIndex] && this.chart.getDatasetMeta(i2.datasetIndex).controller.getParsed(i2.index) !== void 0);
|
|
}
|
|
const active = this.chart.getElementsAtEventForMode(e2, options.mode, options, replay);
|
|
if (options.reverse) {
|
|
active.reverse();
|
|
}
|
|
return active;
|
|
}
|
|
_positionChanged(active, e2) {
|
|
const { caretX, caretY, options } = this;
|
|
const position = positioners[options.position].call(this, active, e2);
|
|
return position !== false && (caretX !== position.x || caretY !== position.y);
|
|
}
|
|
};
|
|
__publicField(Tooltip, "positioners", positioners);
|
|
var plugin_tooltip = {
|
|
id: "tooltip",
|
|
_element: Tooltip,
|
|
positioners,
|
|
afterInit(chart, _args, options) {
|
|
if (options) {
|
|
chart.tooltip = new Tooltip({
|
|
chart,
|
|
options
|
|
});
|
|
}
|
|
},
|
|
beforeUpdate(chart, _args, options) {
|
|
if (chart.tooltip) {
|
|
chart.tooltip.initialize(options);
|
|
}
|
|
},
|
|
reset(chart, _args, options) {
|
|
if (chart.tooltip) {
|
|
chart.tooltip.initialize(options);
|
|
}
|
|
},
|
|
afterDraw(chart) {
|
|
const tooltip = chart.tooltip;
|
|
if (tooltip && tooltip._willRender()) {
|
|
const args = {
|
|
tooltip
|
|
};
|
|
if (chart.notifyPlugins("beforeTooltipDraw", {
|
|
...args,
|
|
cancelable: true
|
|
}) === false) {
|
|
return;
|
|
}
|
|
tooltip.draw(chart.ctx);
|
|
chart.notifyPlugins("afterTooltipDraw", args);
|
|
}
|
|
},
|
|
afterEvent(chart, args) {
|
|
if (chart.tooltip) {
|
|
const useFinalPosition = args.replay;
|
|
if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
|
|
args.changed = true;
|
|
}
|
|
}
|
|
},
|
|
defaults: {
|
|
enabled: true,
|
|
external: null,
|
|
position: "average",
|
|
backgroundColor: "rgba(0,0,0,0.8)",
|
|
titleColor: "#fff",
|
|
titleFont: {
|
|
weight: "bold"
|
|
},
|
|
titleSpacing: 2,
|
|
titleMarginBottom: 6,
|
|
titleAlign: "left",
|
|
bodyColor: "#fff",
|
|
bodySpacing: 2,
|
|
bodyFont: {},
|
|
bodyAlign: "left",
|
|
footerColor: "#fff",
|
|
footerSpacing: 2,
|
|
footerMarginTop: 6,
|
|
footerFont: {
|
|
weight: "bold"
|
|
},
|
|
footerAlign: "left",
|
|
padding: 6,
|
|
caretPadding: 2,
|
|
caretSize: 5,
|
|
cornerRadius: 6,
|
|
boxHeight: (ctx, opts) => opts.bodyFont.size,
|
|
boxWidth: (ctx, opts) => opts.bodyFont.size,
|
|
multiKeyBackground: "#fff",
|
|
displayColors: true,
|
|
boxPadding: 0,
|
|
borderColor: "rgba(0,0,0,0)",
|
|
borderWidth: 0,
|
|
animation: {
|
|
duration: 400,
|
|
easing: "easeOutQuart"
|
|
},
|
|
animations: {
|
|
numbers: {
|
|
type: "number",
|
|
properties: [
|
|
"x",
|
|
"y",
|
|
"width",
|
|
"height",
|
|
"caretX",
|
|
"caretY"
|
|
]
|
|
},
|
|
opacity: {
|
|
easing: "linear",
|
|
duration: 200
|
|
}
|
|
},
|
|
callbacks: defaultCallbacks
|
|
},
|
|
defaultRoutes: {
|
|
bodyFont: "font",
|
|
footerFont: "font",
|
|
titleFont: "font"
|
|
},
|
|
descriptors: {
|
|
_scriptable: (name) => name !== "filter" && name !== "itemSort" && name !== "external",
|
|
_indexable: false,
|
|
callbacks: {
|
|
_scriptable: false,
|
|
_indexable: false
|
|
},
|
|
animation: {
|
|
_fallback: false
|
|
},
|
|
animations: {
|
|
_fallback: "animation"
|
|
}
|
|
},
|
|
additionalOptionScopes: [
|
|
"interaction"
|
|
]
|
|
};
|
|
var addIfString = (labels, raw, index, addedLabels) => {
|
|
if (typeof raw === "string") {
|
|
index = labels.push(raw) - 1;
|
|
addedLabels.unshift({
|
|
index,
|
|
label: raw
|
|
});
|
|
} else if (isNaN(raw)) {
|
|
index = null;
|
|
}
|
|
return index;
|
|
};
|
|
function findOrAddLabel(labels, raw, index, addedLabels) {
|
|
const first = labels.indexOf(raw);
|
|
if (first === -1) {
|
|
return addIfString(labels, raw, index, addedLabels);
|
|
}
|
|
const last = labels.lastIndexOf(raw);
|
|
return first !== last ? index : first;
|
|
}
|
|
var validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max);
|
|
function _getLabelForValue(value) {
|
|
const labels = this.getLabels();
|
|
if (value >= 0 && value < labels.length) {
|
|
return labels[value];
|
|
}
|
|
return value;
|
|
}
|
|
var CategoryScale = class extends Scale {
|
|
constructor(cfg) {
|
|
super(cfg);
|
|
this._startValue = void 0;
|
|
this._valueRange = 0;
|
|
this._addedLabels = [];
|
|
}
|
|
init(scaleOptions) {
|
|
const added = this._addedLabels;
|
|
if (added.length) {
|
|
const labels = this.getLabels();
|
|
for (const { index, label } of added) {
|
|
if (labels[index] === label) {
|
|
labels.splice(index, 1);
|
|
}
|
|
}
|
|
this._addedLabels = [];
|
|
}
|
|
super.init(scaleOptions);
|
|
}
|
|
parse(raw, index) {
|
|
if (isNullOrUndef(raw)) {
|
|
return null;
|
|
}
|
|
const labels = this.getLabels();
|
|
index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels);
|
|
return validIndex(index, labels.length - 1);
|
|
}
|
|
determineDataLimits() {
|
|
const { minDefined, maxDefined } = this.getUserBounds();
|
|
let { min, max } = this.getMinMax(true);
|
|
if (this.options.bounds === "ticks") {
|
|
if (!minDefined) {
|
|
min = 0;
|
|
}
|
|
if (!maxDefined) {
|
|
max = this.getLabels().length - 1;
|
|
}
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
buildTicks() {
|
|
const min = this.min;
|
|
const max = this.max;
|
|
const offset = this.options.offset;
|
|
const ticks = [];
|
|
let labels = this.getLabels();
|
|
labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);
|
|
this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
|
|
this._startValue = this.min - (offset ? 0.5 : 0);
|
|
for (let value = min; value <= max; value++) {
|
|
ticks.push({
|
|
value
|
|
});
|
|
}
|
|
return ticks;
|
|
}
|
|
getLabelForValue(value) {
|
|
return _getLabelForValue.call(this, value);
|
|
}
|
|
configure() {
|
|
super.configure();
|
|
if (!this.isHorizontal()) {
|
|
this._reversePixels = !this._reversePixels;
|
|
}
|
|
}
|
|
getPixelForValue(value) {
|
|
if (typeof value !== "number") {
|
|
value = this.parse(value);
|
|
}
|
|
return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
|
|
}
|
|
getPixelForTick(index) {
|
|
const ticks = this.ticks;
|
|
if (index < 0 || index > ticks.length - 1) {
|
|
return null;
|
|
}
|
|
return this.getPixelForValue(ticks[index].value);
|
|
}
|
|
getValueForPixel(pixel) {
|
|
return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
|
|
}
|
|
getBasePixel() {
|
|
return this.bottom;
|
|
}
|
|
};
|
|
__publicField(CategoryScale, "id", "category");
|
|
__publicField(CategoryScale, "defaults", {
|
|
ticks: {
|
|
callback: _getLabelForValue
|
|
}
|
|
});
|
|
function generateTicks$1(generationOptions, dataRange) {
|
|
const ticks = [];
|
|
const MIN_SPACING = 1e-14;
|
|
const { bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds } = generationOptions;
|
|
const unit = step || 1;
|
|
const maxSpaces = maxTicks - 1;
|
|
const { min: rmin, max: rmax } = dataRange;
|
|
const minDefined = !isNullOrUndef(min);
|
|
const maxDefined = !isNullOrUndef(max);
|
|
const countDefined = !isNullOrUndef(count);
|
|
const minSpacing = (rmax - rmin) / (maxDigits + 1);
|
|
let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit;
|
|
let factor, niceMin, niceMax, numSpaces;
|
|
if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
|
|
return [
|
|
{
|
|
value: rmin
|
|
},
|
|
{
|
|
value: rmax
|
|
}
|
|
];
|
|
}
|
|
numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
|
|
if (numSpaces > maxSpaces) {
|
|
spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit;
|
|
}
|
|
if (!isNullOrUndef(precision)) {
|
|
factor = Math.pow(10, precision);
|
|
spacing = Math.ceil(spacing * factor) / factor;
|
|
}
|
|
if (bounds === "ticks") {
|
|
niceMin = Math.floor(rmin / spacing) * spacing;
|
|
niceMax = Math.ceil(rmax / spacing) * spacing;
|
|
} else {
|
|
niceMin = rmin;
|
|
niceMax = rmax;
|
|
}
|
|
if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1e3)) {
|
|
numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
|
|
spacing = (max - min) / numSpaces;
|
|
niceMin = min;
|
|
niceMax = max;
|
|
} else if (countDefined) {
|
|
niceMin = minDefined ? min : niceMin;
|
|
niceMax = maxDefined ? max : niceMax;
|
|
numSpaces = count - 1;
|
|
spacing = (niceMax - niceMin) / numSpaces;
|
|
} else {
|
|
numSpaces = (niceMax - niceMin) / spacing;
|
|
if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1e3)) {
|
|
numSpaces = Math.round(numSpaces);
|
|
} else {
|
|
numSpaces = Math.ceil(numSpaces);
|
|
}
|
|
}
|
|
const decimalPlaces = Math.max(_decimalPlaces(spacing), _decimalPlaces(niceMin));
|
|
factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision);
|
|
niceMin = Math.round(niceMin * factor) / factor;
|
|
niceMax = Math.round(niceMax * factor) / factor;
|
|
let j2 = 0;
|
|
if (minDefined) {
|
|
if (includeBounds && niceMin !== min) {
|
|
ticks.push({
|
|
value: min
|
|
});
|
|
if (niceMin < min) {
|
|
j2++;
|
|
}
|
|
if (almostEquals(Math.round((niceMin + j2 * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
|
|
j2++;
|
|
}
|
|
} else if (niceMin < min) {
|
|
j2++;
|
|
}
|
|
}
|
|
for (; j2 < numSpaces; ++j2) {
|
|
const tickValue = Math.round((niceMin + j2 * spacing) * factor) / factor;
|
|
if (maxDefined && tickValue > max) {
|
|
break;
|
|
}
|
|
ticks.push({
|
|
value: tickValue
|
|
});
|
|
}
|
|
if (maxDefined && includeBounds && niceMax !== max) {
|
|
if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
|
|
ticks[ticks.length - 1].value = max;
|
|
} else {
|
|
ticks.push({
|
|
value: max
|
|
});
|
|
}
|
|
} else if (!maxDefined || niceMax === max) {
|
|
ticks.push({
|
|
value: niceMax
|
|
});
|
|
}
|
|
return ticks;
|
|
}
|
|
function relativeLabelSize(value, minSpacing, { horizontal, minRotation }) {
|
|
const rad = toRadians(minRotation);
|
|
const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 1e-3;
|
|
const length = 0.75 * minSpacing * ("" + value).length;
|
|
return Math.min(minSpacing / ratio, length);
|
|
}
|
|
var LinearScaleBase = class extends Scale {
|
|
constructor(cfg) {
|
|
super(cfg);
|
|
this.start = void 0;
|
|
this.end = void 0;
|
|
this._startValue = void 0;
|
|
this._endValue = void 0;
|
|
this._valueRange = 0;
|
|
}
|
|
parse(raw, index) {
|
|
if (isNullOrUndef(raw)) {
|
|
return null;
|
|
}
|
|
if ((typeof raw === "number" || raw instanceof Number) && !isFinite(+raw)) {
|
|
return null;
|
|
}
|
|
return +raw;
|
|
}
|
|
handleTickRangeOptions() {
|
|
const { beginAtZero } = this.options;
|
|
const { minDefined, maxDefined } = this.getUserBounds();
|
|
let { min, max } = this;
|
|
const setMin = (v2) => min = minDefined ? min : v2;
|
|
const setMax = (v2) => max = maxDefined ? max : v2;
|
|
if (beginAtZero) {
|
|
const minSign = sign(min);
|
|
const maxSign = sign(max);
|
|
if (minSign < 0 && maxSign < 0) {
|
|
setMax(0);
|
|
} else if (minSign > 0 && maxSign > 0) {
|
|
setMin(0);
|
|
}
|
|
}
|
|
if (min === max) {
|
|
let offset = max === 0 ? 1 : Math.abs(max * 0.05);
|
|
setMax(max + offset);
|
|
if (!beginAtZero) {
|
|
setMin(min - offset);
|
|
}
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
getTickLimit() {
|
|
const tickOpts = this.options.ticks;
|
|
let { maxTicksLimit, stepSize } = tickOpts;
|
|
let maxTicks;
|
|
if (stepSize) {
|
|
maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
|
|
if (maxTicks > 1e3) {
|
|
console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
|
|
maxTicks = 1e3;
|
|
}
|
|
} else {
|
|
maxTicks = this.computeTickLimit();
|
|
maxTicksLimit = maxTicksLimit || 11;
|
|
}
|
|
if (maxTicksLimit) {
|
|
maxTicks = Math.min(maxTicksLimit, maxTicks);
|
|
}
|
|
return maxTicks;
|
|
}
|
|
computeTickLimit() {
|
|
return Number.POSITIVE_INFINITY;
|
|
}
|
|
buildTicks() {
|
|
const opts = this.options;
|
|
const tickOpts = opts.ticks;
|
|
let maxTicks = this.getTickLimit();
|
|
maxTicks = Math.max(2, maxTicks);
|
|
const numericGeneratorOptions = {
|
|
maxTicks,
|
|
bounds: opts.bounds,
|
|
min: opts.min,
|
|
max: opts.max,
|
|
precision: tickOpts.precision,
|
|
step: tickOpts.stepSize,
|
|
count: tickOpts.count,
|
|
maxDigits: this._maxDigits(),
|
|
horizontal: this.isHorizontal(),
|
|
minRotation: tickOpts.minRotation || 0,
|
|
includeBounds: tickOpts.includeBounds !== false
|
|
};
|
|
const dataRange = this._range || this;
|
|
const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
|
|
if (opts.bounds === "ticks") {
|
|
_setMinAndMaxByKey(ticks, this, "value");
|
|
}
|
|
if (opts.reverse) {
|
|
ticks.reverse();
|
|
this.start = this.max;
|
|
this.end = this.min;
|
|
} else {
|
|
this.start = this.min;
|
|
this.end = this.max;
|
|
}
|
|
return ticks;
|
|
}
|
|
configure() {
|
|
const ticks = this.ticks;
|
|
let start = this.min;
|
|
let end = this.max;
|
|
super.configure();
|
|
if (this.options.offset && ticks.length) {
|
|
const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
|
|
start -= offset;
|
|
end += offset;
|
|
}
|
|
this._startValue = start;
|
|
this._endValue = end;
|
|
this._valueRange = end - start;
|
|
}
|
|
getLabelForValue(value) {
|
|
return formatNumber(value, this.chart.options.locale, this.options.ticks.format);
|
|
}
|
|
};
|
|
var LinearScale = class extends LinearScaleBase {
|
|
determineDataLimits() {
|
|
const { min, max } = this.getMinMax(true);
|
|
this.min = isNumberFinite(min) ? min : 0;
|
|
this.max = isNumberFinite(max) ? max : 1;
|
|
this.handleTickRangeOptions();
|
|
}
|
|
computeTickLimit() {
|
|
const horizontal = this.isHorizontal();
|
|
const length = horizontal ? this.width : this.height;
|
|
const minRotation = toRadians(this.options.ticks.minRotation);
|
|
const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 1e-3;
|
|
const tickFont = this._resolveTickFontOptions(0);
|
|
return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
|
|
}
|
|
getPixelForValue(value) {
|
|
return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
|
|
}
|
|
getValueForPixel(pixel) {
|
|
return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
|
|
}
|
|
};
|
|
__publicField(LinearScale, "id", "linear");
|
|
__publicField(LinearScale, "defaults", {
|
|
ticks: {
|
|
callback: Ticks.formatters.numeric
|
|
}
|
|
});
|
|
var log10Floor = (v2) => Math.floor(log10(v2));
|
|
var changeExponent = (v2, m2) => Math.pow(10, log10Floor(v2) + m2);
|
|
function isMajor(tickVal) {
|
|
const remain = tickVal / Math.pow(10, log10Floor(tickVal));
|
|
return remain === 1;
|
|
}
|
|
function steps(min, max, rangeExp) {
|
|
const rangeStep = Math.pow(10, rangeExp);
|
|
const start = Math.floor(min / rangeStep);
|
|
const end = Math.ceil(max / rangeStep);
|
|
return end - start;
|
|
}
|
|
function startExp(min, max) {
|
|
const range = max - min;
|
|
let rangeExp = log10Floor(range);
|
|
while (steps(min, max, rangeExp) > 10) {
|
|
rangeExp++;
|
|
}
|
|
while (steps(min, max, rangeExp) < 10) {
|
|
rangeExp--;
|
|
}
|
|
return Math.min(rangeExp, log10Floor(min));
|
|
}
|
|
function generateTicks(generationOptions, { min, max }) {
|
|
min = finiteOrDefault(generationOptions.min, min);
|
|
const ticks = [];
|
|
const minExp = log10Floor(min);
|
|
let exp = startExp(min, max);
|
|
let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
|
|
const stepSize = Math.pow(10, exp);
|
|
const base = minExp > exp ? Math.pow(10, minExp) : 0;
|
|
const start = Math.round((min - base) * precision) / precision;
|
|
const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;
|
|
let significand = Math.floor((start - offset) / Math.pow(10, exp));
|
|
let value = finiteOrDefault(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision);
|
|
while (value < max) {
|
|
ticks.push({
|
|
value,
|
|
major: isMajor(value),
|
|
significand
|
|
});
|
|
if (significand >= 10) {
|
|
significand = significand < 15 ? 15 : 20;
|
|
} else {
|
|
significand++;
|
|
}
|
|
if (significand >= 20) {
|
|
exp++;
|
|
significand = 2;
|
|
precision = exp >= 0 ? 1 : precision;
|
|
}
|
|
value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;
|
|
}
|
|
const lastTick = finiteOrDefault(generationOptions.max, value);
|
|
ticks.push({
|
|
value: lastTick,
|
|
major: isMajor(lastTick),
|
|
significand
|
|
});
|
|
return ticks;
|
|
}
|
|
var LogarithmicScale = class extends Scale {
|
|
constructor(cfg) {
|
|
super(cfg);
|
|
this.start = void 0;
|
|
this.end = void 0;
|
|
this._startValue = void 0;
|
|
this._valueRange = 0;
|
|
}
|
|
parse(raw, index) {
|
|
const value = LinearScaleBase.prototype.parse.apply(this, [
|
|
raw,
|
|
index
|
|
]);
|
|
if (value === 0) {
|
|
this._zero = true;
|
|
return void 0;
|
|
}
|
|
return isNumberFinite(value) && value > 0 ? value : null;
|
|
}
|
|
determineDataLimits() {
|
|
const { min, max } = this.getMinMax(true);
|
|
this.min = isNumberFinite(min) ? Math.max(0, min) : null;
|
|
this.max = isNumberFinite(max) ? Math.max(0, max) : null;
|
|
if (this.options.beginAtZero) {
|
|
this._zero = true;
|
|
}
|
|
if (this._zero && this.min !== this._suggestedMin && !isNumberFinite(this._userMin)) {
|
|
this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);
|
|
}
|
|
this.handleTickRangeOptions();
|
|
}
|
|
handleTickRangeOptions() {
|
|
const { minDefined, maxDefined } = this.getUserBounds();
|
|
let min = this.min;
|
|
let max = this.max;
|
|
const setMin = (v2) => min = minDefined ? min : v2;
|
|
const setMax = (v2) => max = maxDefined ? max : v2;
|
|
if (min === max) {
|
|
if (min <= 0) {
|
|
setMin(1);
|
|
setMax(10);
|
|
} else {
|
|
setMin(changeExponent(min, -1));
|
|
setMax(changeExponent(max, 1));
|
|
}
|
|
}
|
|
if (min <= 0) {
|
|
setMin(changeExponent(max, -1));
|
|
}
|
|
if (max <= 0) {
|
|
setMax(changeExponent(min, 1));
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
buildTicks() {
|
|
const opts = this.options;
|
|
const generationOptions = {
|
|
min: this._userMin,
|
|
max: this._userMax
|
|
};
|
|
const ticks = generateTicks(generationOptions, this);
|
|
if (opts.bounds === "ticks") {
|
|
_setMinAndMaxByKey(ticks, this, "value");
|
|
}
|
|
if (opts.reverse) {
|
|
ticks.reverse();
|
|
this.start = this.max;
|
|
this.end = this.min;
|
|
} else {
|
|
this.start = this.min;
|
|
this.end = this.max;
|
|
}
|
|
return ticks;
|
|
}
|
|
getLabelForValue(value) {
|
|
return value === void 0 ? "0" : formatNumber(value, this.chart.options.locale, this.options.ticks.format);
|
|
}
|
|
configure() {
|
|
const start = this.min;
|
|
super.configure();
|
|
this._startValue = log10(start);
|
|
this._valueRange = log10(this.max) - log10(start);
|
|
}
|
|
getPixelForValue(value) {
|
|
if (value === void 0 || value === 0) {
|
|
value = this.min;
|
|
}
|
|
if (value === null || isNaN(value)) {
|
|
return NaN;
|
|
}
|
|
return this.getPixelForDecimal(value === this.min ? 0 : (log10(value) - this._startValue) / this._valueRange);
|
|
}
|
|
getValueForPixel(pixel) {
|
|
const decimal = this.getDecimalForPixel(pixel);
|
|
return Math.pow(10, this._startValue + decimal * this._valueRange);
|
|
}
|
|
};
|
|
__publicField(LogarithmicScale, "id", "logarithmic");
|
|
__publicField(LogarithmicScale, "defaults", {
|
|
ticks: {
|
|
callback: Ticks.formatters.logarithmic,
|
|
major: {
|
|
enabled: true
|
|
}
|
|
}
|
|
});
|
|
function getTickBackdropHeight(opts) {
|
|
const tickOpts = opts.ticks;
|
|
if (tickOpts.display && opts.display) {
|
|
const padding = toPadding(tickOpts.backdropPadding);
|
|
return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults2.font.size) + padding.height;
|
|
}
|
|
return 0;
|
|
}
|
|
function measureLabelSize(ctx, font, label) {
|
|
label = isArray(label) ? label : [
|
|
label
|
|
];
|
|
return {
|
|
w: _longestText(ctx, font.string, label),
|
|
h: label.length * font.lineHeight
|
|
};
|
|
}
|
|
function determineLimits(angle, pos, size, min, max) {
|
|
if (angle === min || angle === max) {
|
|
return {
|
|
start: pos - size / 2,
|
|
end: pos + size / 2
|
|
};
|
|
} else if (angle < min || angle > max) {
|
|
return {
|
|
start: pos - size,
|
|
end: pos
|
|
};
|
|
}
|
|
return {
|
|
start: pos,
|
|
end: pos + size
|
|
};
|
|
}
|
|
function fitWithPointLabels(scale) {
|
|
const orig = {
|
|
l: scale.left + scale._padding.left,
|
|
r: scale.right - scale._padding.right,
|
|
t: scale.top + scale._padding.top,
|
|
b: scale.bottom - scale._padding.bottom
|
|
};
|
|
const limits = Object.assign({}, orig);
|
|
const labelSizes = [];
|
|
const padding = [];
|
|
const valueCount = scale._pointLabels.length;
|
|
const pointLabelOpts = scale.options.pointLabels;
|
|
const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0;
|
|
for (let i2 = 0; i2 < valueCount; i2++) {
|
|
const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i2));
|
|
padding[i2] = opts.padding;
|
|
const pointPosition = scale.getPointPosition(i2, scale.drawingArea + padding[i2], additionalAngle);
|
|
const plFont = toFont(opts.font);
|
|
const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i2]);
|
|
labelSizes[i2] = textSize;
|
|
const angleRadians = _normalizeAngle(scale.getIndexAngle(i2) + additionalAngle);
|
|
const angle = Math.round(toDegrees(angleRadians));
|
|
const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
|
|
const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
|
|
updateLimits(limits, orig, angleRadians, hLimits, vLimits);
|
|
}
|
|
scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);
|
|
scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
|
|
}
|
|
function updateLimits(limits, orig, angle, hLimits, vLimits) {
|
|
const sin = Math.abs(Math.sin(angle));
|
|
const cos = Math.abs(Math.cos(angle));
|
|
let x2 = 0;
|
|
let y2 = 0;
|
|
if (hLimits.start < orig.l) {
|
|
x2 = (orig.l - hLimits.start) / sin;
|
|
limits.l = Math.min(limits.l, orig.l - x2);
|
|
} else if (hLimits.end > orig.r) {
|
|
x2 = (hLimits.end - orig.r) / sin;
|
|
limits.r = Math.max(limits.r, orig.r + x2);
|
|
}
|
|
if (vLimits.start < orig.t) {
|
|
y2 = (orig.t - vLimits.start) / cos;
|
|
limits.t = Math.min(limits.t, orig.t - y2);
|
|
} else if (vLimits.end > orig.b) {
|
|
y2 = (vLimits.end - orig.b) / cos;
|
|
limits.b = Math.max(limits.b, orig.b + y2);
|
|
}
|
|
}
|
|
function createPointLabelItem(scale, index, itemOpts) {
|
|
const outerDistance = scale.drawingArea;
|
|
const { extra, additionalAngle, padding, size } = itemOpts;
|
|
const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);
|
|
const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI)));
|
|
const y2 = yForAngle(pointLabelPosition.y, size.h, angle);
|
|
const textAlign = getTextAlignForAngle(angle);
|
|
const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
|
|
return {
|
|
visible: true,
|
|
x: pointLabelPosition.x,
|
|
y: y2,
|
|
textAlign,
|
|
left,
|
|
top: y2,
|
|
right: left + size.w,
|
|
bottom: y2 + size.h
|
|
};
|
|
}
|
|
function isNotOverlapped(item, area) {
|
|
if (!area) {
|
|
return true;
|
|
}
|
|
const { left, top, right, bottom } = item;
|
|
const apexesInArea = _isPointInArea({
|
|
x: left,
|
|
y: top
|
|
}, area) || _isPointInArea({
|
|
x: left,
|
|
y: bottom
|
|
}, area) || _isPointInArea({
|
|
x: right,
|
|
y: top
|
|
}, area) || _isPointInArea({
|
|
x: right,
|
|
y: bottom
|
|
}, area);
|
|
return !apexesInArea;
|
|
}
|
|
function buildPointLabelItems(scale, labelSizes, padding) {
|
|
const items = [];
|
|
const valueCount = scale._pointLabels.length;
|
|
const opts = scale.options;
|
|
const { centerPointLabels, display } = opts.pointLabels;
|
|
const itemOpts = {
|
|
extra: getTickBackdropHeight(opts) / 2,
|
|
additionalAngle: centerPointLabels ? PI / valueCount : 0
|
|
};
|
|
let area;
|
|
for (let i2 = 0; i2 < valueCount; i2++) {
|
|
itemOpts.padding = padding[i2];
|
|
itemOpts.size = labelSizes[i2];
|
|
const item = createPointLabelItem(scale, i2, itemOpts);
|
|
items.push(item);
|
|
if (display === "auto") {
|
|
item.visible = isNotOverlapped(item, area);
|
|
if (item.visible) {
|
|
area = item;
|
|
}
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
function getTextAlignForAngle(angle) {
|
|
if (angle === 0 || angle === 180) {
|
|
return "center";
|
|
} else if (angle < 180) {
|
|
return "left";
|
|
}
|
|
return "right";
|
|
}
|
|
function leftForTextAlign(x2, w2, align) {
|
|
if (align === "right") {
|
|
x2 -= w2;
|
|
} else if (align === "center") {
|
|
x2 -= w2 / 2;
|
|
}
|
|
return x2;
|
|
}
|
|
function yForAngle(y2, h6, angle) {
|
|
if (angle === 90 || angle === 270) {
|
|
y2 -= h6 / 2;
|
|
} else if (angle > 270 || angle < 90) {
|
|
y2 -= h6;
|
|
}
|
|
return y2;
|
|
}
|
|
function drawPointLabelBox(ctx, opts, item) {
|
|
const { left, top, right, bottom } = item;
|
|
const { backdropColor } = opts;
|
|
if (!isNullOrUndef(backdropColor)) {
|
|
const borderRadius = toTRBLCorners(opts.borderRadius);
|
|
const padding = toPadding(opts.backdropPadding);
|
|
ctx.fillStyle = backdropColor;
|
|
const backdropLeft = left - padding.left;
|
|
const backdropTop = top - padding.top;
|
|
const backdropWidth = right - left + padding.width;
|
|
const backdropHeight = bottom - top + padding.height;
|
|
if (Object.values(borderRadius).some((v2) => v2 !== 0)) {
|
|
ctx.beginPath();
|
|
addRoundedRectPath(ctx, {
|
|
x: backdropLeft,
|
|
y: backdropTop,
|
|
w: backdropWidth,
|
|
h: backdropHeight,
|
|
radius: borderRadius
|
|
});
|
|
ctx.fill();
|
|
} else {
|
|
ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);
|
|
}
|
|
}
|
|
}
|
|
function drawPointLabels(scale, labelCount) {
|
|
const { ctx, options: { pointLabels } } = scale;
|
|
for (let i2 = labelCount - 1; i2 >= 0; i2--) {
|
|
const item = scale._pointLabelItems[i2];
|
|
if (!item.visible) {
|
|
continue;
|
|
}
|
|
const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i2));
|
|
drawPointLabelBox(ctx, optsAtIndex, item);
|
|
const plFont = toFont(optsAtIndex.font);
|
|
const { x: x2, y: y2, textAlign } = item;
|
|
renderText(ctx, scale._pointLabels[i2], x2, y2 + plFont.lineHeight / 2, plFont, {
|
|
color: optsAtIndex.color,
|
|
textAlign,
|
|
textBaseline: "middle"
|
|
});
|
|
}
|
|
}
|
|
function pathRadiusLine(scale, radius, circular, labelCount) {
|
|
const { ctx } = scale;
|
|
if (circular) {
|
|
ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);
|
|
} else {
|
|
let pointPosition = scale.getPointPosition(0, radius);
|
|
ctx.moveTo(pointPosition.x, pointPosition.y);
|
|
for (let i2 = 1; i2 < labelCount; i2++) {
|
|
pointPosition = scale.getPointPosition(i2, radius);
|
|
ctx.lineTo(pointPosition.x, pointPosition.y);
|
|
}
|
|
}
|
|
}
|
|
function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {
|
|
const ctx = scale.ctx;
|
|
const circular = gridLineOpts.circular;
|
|
const { color: color2, lineWidth } = gridLineOpts;
|
|
if (!circular && !labelCount || !color2 || !lineWidth || radius < 0) {
|
|
return;
|
|
}
|
|
ctx.save();
|
|
ctx.strokeStyle = color2;
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.setLineDash(borderOpts.dash);
|
|
ctx.lineDashOffset = borderOpts.dashOffset;
|
|
ctx.beginPath();
|
|
pathRadiusLine(scale, radius, circular, labelCount);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
}
|
|
function createPointLabelContext(parent, index, label) {
|
|
return createContext(parent, {
|
|
label,
|
|
index,
|
|
type: "pointLabel"
|
|
});
|
|
}
|
|
var RadialLinearScale = class extends LinearScaleBase {
|
|
constructor(cfg) {
|
|
super(cfg);
|
|
this.xCenter = void 0;
|
|
this.yCenter = void 0;
|
|
this.drawingArea = void 0;
|
|
this._pointLabels = [];
|
|
this._pointLabelItems = [];
|
|
}
|
|
setDimensions() {
|
|
const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2);
|
|
const w2 = this.width = this.maxWidth - padding.width;
|
|
const h6 = this.height = this.maxHeight - padding.height;
|
|
this.xCenter = Math.floor(this.left + w2 / 2 + padding.left);
|
|
this.yCenter = Math.floor(this.top + h6 / 2 + padding.top);
|
|
this.drawingArea = Math.floor(Math.min(w2, h6) / 2);
|
|
}
|
|
determineDataLimits() {
|
|
const { min, max } = this.getMinMax(false);
|
|
this.min = isNumberFinite(min) && !isNaN(min) ? min : 0;
|
|
this.max = isNumberFinite(max) && !isNaN(max) ? max : 0;
|
|
this.handleTickRangeOptions();
|
|
}
|
|
computeTickLimit() {
|
|
return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
|
|
}
|
|
generateTickLabels(ticks) {
|
|
LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
|
|
this._pointLabels = this.getLabels().map((value, index) => {
|
|
const label = callback(this.options.pointLabels.callback, [
|
|
value,
|
|
index
|
|
], this);
|
|
return label || label === 0 ? label : "";
|
|
}).filter((v2, i2) => this.chart.getDataVisibility(i2));
|
|
}
|
|
fit() {
|
|
const opts = this.options;
|
|
if (opts.display && opts.pointLabels.display) {
|
|
fitWithPointLabels(this);
|
|
} else {
|
|
this.setCenterPoint(0, 0, 0, 0);
|
|
}
|
|
}
|
|
setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
|
|
this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
|
|
this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
|
|
this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
|
|
}
|
|
getIndexAngle(index) {
|
|
const angleMultiplier = TAU / (this._pointLabels.length || 1);
|
|
const startAngle = this.options.startAngle || 0;
|
|
return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));
|
|
}
|
|
getDistanceFromCenterForValue(value) {
|
|
if (isNullOrUndef(value)) {
|
|
return NaN;
|
|
}
|
|
const scalingFactor = this.drawingArea / (this.max - this.min);
|
|
if (this.options.reverse) {
|
|
return (this.max - value) * scalingFactor;
|
|
}
|
|
return (value - this.min) * scalingFactor;
|
|
}
|
|
getValueForDistanceFromCenter(distance) {
|
|
if (isNullOrUndef(distance)) {
|
|
return NaN;
|
|
}
|
|
const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
|
|
return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
|
|
}
|
|
getPointLabelContext(index) {
|
|
const pointLabels = this._pointLabels || [];
|
|
if (index >= 0 && index < pointLabels.length) {
|
|
const pointLabel = pointLabels[index];
|
|
return createPointLabelContext(this.getContext(), index, pointLabel);
|
|
}
|
|
}
|
|
getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
|
|
const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;
|
|
return {
|
|
x: Math.cos(angle) * distanceFromCenter + this.xCenter,
|
|
y: Math.sin(angle) * distanceFromCenter + this.yCenter,
|
|
angle
|
|
};
|
|
}
|
|
getPointPositionForValue(index, value) {
|
|
return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
|
|
}
|
|
getBasePosition(index) {
|
|
return this.getPointPositionForValue(index || 0, this.getBaseValue());
|
|
}
|
|
getPointLabelPosition(index) {
|
|
const { left, top, right, bottom } = this._pointLabelItems[index];
|
|
return {
|
|
left,
|
|
top,
|
|
right,
|
|
bottom
|
|
};
|
|
}
|
|
drawBackground() {
|
|
const { backgroundColor, grid: { circular } } = this.options;
|
|
if (backgroundColor) {
|
|
const ctx = this.ctx;
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
|
|
ctx.closePath();
|
|
ctx.fillStyle = backgroundColor;
|
|
ctx.fill();
|
|
ctx.restore();
|
|
}
|
|
}
|
|
drawGrid() {
|
|
const ctx = this.ctx;
|
|
const opts = this.options;
|
|
const { angleLines, grid, border } = opts;
|
|
const labelCount = this._pointLabels.length;
|
|
let i2, offset, position;
|
|
if (opts.pointLabels.display) {
|
|
drawPointLabels(this, labelCount);
|
|
}
|
|
if (grid.display) {
|
|
this.ticks.forEach((tick, index) => {
|
|
if (index !== 0 || index === 0 && this.min < 0) {
|
|
offset = this.getDistanceFromCenterForValue(tick.value);
|
|
const context = this.getContext(index);
|
|
const optsAtIndex = grid.setContext(context);
|
|
const optsAtIndexBorder = border.setContext(context);
|
|
drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);
|
|
}
|
|
});
|
|
}
|
|
if (angleLines.display) {
|
|
ctx.save();
|
|
for (i2 = labelCount - 1; i2 >= 0; i2--) {
|
|
const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i2));
|
|
const { color: color2, lineWidth } = optsAtIndex;
|
|
if (!lineWidth || !color2) {
|
|
continue;
|
|
}
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.strokeStyle = color2;
|
|
ctx.setLineDash(optsAtIndex.borderDash);
|
|
ctx.lineDashOffset = optsAtIndex.borderDashOffset;
|
|
offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);
|
|
position = this.getPointPosition(i2, offset);
|
|
ctx.beginPath();
|
|
ctx.moveTo(this.xCenter, this.yCenter);
|
|
ctx.lineTo(position.x, position.y);
|
|
ctx.stroke();
|
|
}
|
|
ctx.restore();
|
|
}
|
|
}
|
|
drawBorder() {
|
|
}
|
|
drawLabels() {
|
|
const ctx = this.ctx;
|
|
const opts = this.options;
|
|
const tickOpts = opts.ticks;
|
|
if (!tickOpts.display) {
|
|
return;
|
|
}
|
|
const startAngle = this.getIndexAngle(0);
|
|
let offset, width;
|
|
ctx.save();
|
|
ctx.translate(this.xCenter, this.yCenter);
|
|
ctx.rotate(startAngle);
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
this.ticks.forEach((tick, index) => {
|
|
if (index === 0 && this.min >= 0 && !opts.reverse) {
|
|
return;
|
|
}
|
|
const optsAtIndex = tickOpts.setContext(this.getContext(index));
|
|
const tickFont = toFont(optsAtIndex.font);
|
|
offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
|
|
if (optsAtIndex.showLabelBackdrop) {
|
|
ctx.font = tickFont.string;
|
|
width = ctx.measureText(tick.label).width;
|
|
ctx.fillStyle = optsAtIndex.backdropColor;
|
|
const padding = toPadding(optsAtIndex.backdropPadding);
|
|
ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);
|
|
}
|
|
renderText(ctx, tick.label, 0, -offset, tickFont, {
|
|
color: optsAtIndex.color,
|
|
strokeColor: optsAtIndex.textStrokeColor,
|
|
strokeWidth: optsAtIndex.textStrokeWidth
|
|
});
|
|
});
|
|
ctx.restore();
|
|
}
|
|
drawTitle() {
|
|
}
|
|
};
|
|
__publicField(RadialLinearScale, "id", "radialLinear");
|
|
__publicField(RadialLinearScale, "defaults", {
|
|
display: true,
|
|
animate: true,
|
|
position: "chartArea",
|
|
angleLines: {
|
|
display: true,
|
|
lineWidth: 1,
|
|
borderDash: [],
|
|
borderDashOffset: 0
|
|
},
|
|
grid: {
|
|
circular: false
|
|
},
|
|
startAngle: 0,
|
|
ticks: {
|
|
showLabelBackdrop: true,
|
|
callback: Ticks.formatters.numeric
|
|
},
|
|
pointLabels: {
|
|
backdropColor: void 0,
|
|
backdropPadding: 2,
|
|
display: true,
|
|
font: {
|
|
size: 10
|
|
},
|
|
callback(label) {
|
|
return label;
|
|
},
|
|
padding: 5,
|
|
centerPointLabels: false
|
|
}
|
|
});
|
|
__publicField(RadialLinearScale, "defaultRoutes", {
|
|
"angleLines.color": "borderColor",
|
|
"pointLabels.color": "color",
|
|
"ticks.color": "color"
|
|
});
|
|
__publicField(RadialLinearScale, "descriptors", {
|
|
angleLines: {
|
|
_fallback: "grid"
|
|
}
|
|
});
|
|
var INTERVALS = {
|
|
millisecond: {
|
|
common: true,
|
|
size: 1,
|
|
steps: 1e3
|
|
},
|
|
second: {
|
|
common: true,
|
|
size: 1e3,
|
|
steps: 60
|
|
},
|
|
minute: {
|
|
common: true,
|
|
size: 6e4,
|
|
steps: 60
|
|
},
|
|
hour: {
|
|
common: true,
|
|
size: 36e5,
|
|
steps: 24
|
|
},
|
|
day: {
|
|
common: true,
|
|
size: 864e5,
|
|
steps: 30
|
|
},
|
|
week: {
|
|
common: false,
|
|
size: 6048e5,
|
|
steps: 4
|
|
},
|
|
month: {
|
|
common: true,
|
|
size: 2628e6,
|
|
steps: 12
|
|
},
|
|
quarter: {
|
|
common: false,
|
|
size: 7884e6,
|
|
steps: 4
|
|
},
|
|
year: {
|
|
common: true,
|
|
size: 3154e7
|
|
}
|
|
};
|
|
var UNITS = /* @__PURE__ */ Object.keys(INTERVALS);
|
|
function sorter(a2, b2) {
|
|
return a2 - b2;
|
|
}
|
|
function parse2(scale, input) {
|
|
if (isNullOrUndef(input)) {
|
|
return null;
|
|
}
|
|
const adapter = scale._adapter;
|
|
const { parser, round: round2, isoWeekday } = scale._parseOpts;
|
|
let value = input;
|
|
if (typeof parser === "function") {
|
|
value = parser(value);
|
|
}
|
|
if (!isNumberFinite(value)) {
|
|
value = typeof parser === "string" ? adapter.parse(value, parser) : adapter.parse(value);
|
|
}
|
|
if (value === null) {
|
|
return null;
|
|
}
|
|
if (round2) {
|
|
value = round2 === "week" && (isNumber(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, "isoWeek", isoWeekday) : adapter.startOf(value, round2);
|
|
}
|
|
return +value;
|
|
}
|
|
function determineUnitForAutoTicks(minUnit, min, max, capacity) {
|
|
const ilen = UNITS.length;
|
|
for (let i2 = UNITS.indexOf(minUnit); i2 < ilen - 1; ++i2) {
|
|
const interval = INTERVALS[UNITS[i2]];
|
|
const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
|
|
if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
|
|
return UNITS[i2];
|
|
}
|
|
}
|
|
return UNITS[ilen - 1];
|
|
}
|
|
function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
|
|
for (let i2 = UNITS.length - 1; i2 >= UNITS.indexOf(minUnit); i2--) {
|
|
const unit = UNITS[i2];
|
|
if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
|
|
return unit;
|
|
}
|
|
}
|
|
return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
|
|
}
|
|
function determineMajorUnit(unit) {
|
|
for (let i2 = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i2 < ilen; ++i2) {
|
|
if (INTERVALS[UNITS[i2]].common) {
|
|
return UNITS[i2];
|
|
}
|
|
}
|
|
}
|
|
function addTick(ticks, time, timestamps) {
|
|
if (!timestamps) {
|
|
ticks[time] = true;
|
|
} else if (timestamps.length) {
|
|
const { lo, hi } = _lookup(timestamps, time);
|
|
const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
|
|
ticks[timestamp] = true;
|
|
}
|
|
}
|
|
function setMajorTicks(scale, ticks, map3, majorUnit) {
|
|
const adapter = scale._adapter;
|
|
const first = +adapter.startOf(ticks[0].value, majorUnit);
|
|
const last = ticks[ticks.length - 1].value;
|
|
let major, index;
|
|
for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
|
|
index = map3[major];
|
|
if (index >= 0) {
|
|
ticks[index].major = true;
|
|
}
|
|
}
|
|
return ticks;
|
|
}
|
|
function ticksFromTimestamps(scale, values, majorUnit) {
|
|
const ticks = [];
|
|
const map3 = {};
|
|
const ilen = values.length;
|
|
let i2, value;
|
|
for (i2 = 0; i2 < ilen; ++i2) {
|
|
value = values[i2];
|
|
map3[value] = i2;
|
|
ticks.push({
|
|
value,
|
|
major: false
|
|
});
|
|
}
|
|
return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map3, majorUnit);
|
|
}
|
|
var TimeScale = class extends Scale {
|
|
constructor(props) {
|
|
super(props);
|
|
this._cache = {
|
|
data: [],
|
|
labels: [],
|
|
all: []
|
|
};
|
|
this._unit = "day";
|
|
this._majorUnit = void 0;
|
|
this._offsets = {};
|
|
this._normalized = false;
|
|
this._parseOpts = void 0;
|
|
}
|
|
init(scaleOpts, opts = {}) {
|
|
const time = scaleOpts.time || (scaleOpts.time = {});
|
|
const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
|
|
adapter.init(opts);
|
|
mergeIf(time.displayFormats, adapter.formats());
|
|
this._parseOpts = {
|
|
parser: time.parser,
|
|
round: time.round,
|
|
isoWeekday: time.isoWeekday
|
|
};
|
|
super.init(scaleOpts);
|
|
this._normalized = opts.normalized;
|
|
}
|
|
parse(raw, index) {
|
|
if (raw === void 0) {
|
|
return null;
|
|
}
|
|
return parse2(this, raw);
|
|
}
|
|
beforeLayout() {
|
|
super.beforeLayout();
|
|
this._cache = {
|
|
data: [],
|
|
labels: [],
|
|
all: []
|
|
};
|
|
}
|
|
determineDataLimits() {
|
|
const options = this.options;
|
|
const adapter = this._adapter;
|
|
const unit = options.time.unit || "day";
|
|
let { min, max, minDefined, maxDefined } = this.getUserBounds();
|
|
function _applyBounds(bounds) {
|
|
if (!minDefined && !isNaN(bounds.min)) {
|
|
min = Math.min(min, bounds.min);
|
|
}
|
|
if (!maxDefined && !isNaN(bounds.max)) {
|
|
max = Math.max(max, bounds.max);
|
|
}
|
|
}
|
|
if (!minDefined || !maxDefined) {
|
|
_applyBounds(this._getLabelBounds());
|
|
if (options.bounds !== "ticks" || options.ticks.source !== "labels") {
|
|
_applyBounds(this.getMinMax(false));
|
|
}
|
|
}
|
|
min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
|
|
max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
|
|
this.min = Math.min(min, max - 1);
|
|
this.max = Math.max(min + 1, max);
|
|
}
|
|
_getLabelBounds() {
|
|
const arr = this.getLabelTimestamps();
|
|
let min = Number.POSITIVE_INFINITY;
|
|
let max = Number.NEGATIVE_INFINITY;
|
|
if (arr.length) {
|
|
min = arr[0];
|
|
max = arr[arr.length - 1];
|
|
}
|
|
return {
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
buildTicks() {
|
|
const options = this.options;
|
|
const timeOpts = options.time;
|
|
const tickOpts = options.ticks;
|
|
const timestamps = tickOpts.source === "labels" ? this.getLabelTimestamps() : this._generate();
|
|
if (options.bounds === "ticks" && timestamps.length) {
|
|
this.min = this._userMin || timestamps[0];
|
|
this.max = this._userMax || timestamps[timestamps.length - 1];
|
|
}
|
|
const min = this.min;
|
|
const max = this.max;
|
|
const ticks = _filterBetween(timestamps, min, max);
|
|
this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max));
|
|
this._majorUnit = !tickOpts.major.enabled || this._unit === "year" ? void 0 : determineMajorUnit(this._unit);
|
|
this.initOffsets(timestamps);
|
|
if (options.reverse) {
|
|
ticks.reverse();
|
|
}
|
|
return ticksFromTimestamps(this, ticks, this._majorUnit);
|
|
}
|
|
afterAutoSkip() {
|
|
if (this.options.offsetAfterAutoskip) {
|
|
this.initOffsets(this.ticks.map((tick) => +tick.value));
|
|
}
|
|
}
|
|
initOffsets(timestamps = []) {
|
|
let start = 0;
|
|
let end = 0;
|
|
let first, last;
|
|
if (this.options.offset && timestamps.length) {
|
|
first = this.getDecimalForValue(timestamps[0]);
|
|
if (timestamps.length === 1) {
|
|
start = 1 - first;
|
|
} else {
|
|
start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
|
|
}
|
|
last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
|
|
if (timestamps.length === 1) {
|
|
end = last;
|
|
} else {
|
|
end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
|
|
}
|
|
}
|
|
const limit = timestamps.length < 3 ? 0.5 : 0.25;
|
|
start = _limitValue(start, 0, limit);
|
|
end = _limitValue(end, 0, limit);
|
|
this._offsets = {
|
|
start,
|
|
end,
|
|
factor: 1 / (start + 1 + end)
|
|
};
|
|
}
|
|
_generate() {
|
|
const adapter = this._adapter;
|
|
const min = this.min;
|
|
const max = this.max;
|
|
const options = this.options;
|
|
const timeOpts = options.time;
|
|
const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
|
|
const stepSize = valueOrDefault(options.ticks.stepSize, 1);
|
|
const weekday = minor === "week" ? timeOpts.isoWeekday : false;
|
|
const hasWeekday = isNumber(weekday) || weekday === true;
|
|
const ticks = {};
|
|
let first = min;
|
|
let time, count;
|
|
if (hasWeekday) {
|
|
first = +adapter.startOf(first, "isoWeek", weekday);
|
|
}
|
|
first = +adapter.startOf(first, hasWeekday ? "day" : minor);
|
|
if (adapter.diff(max, min, minor) > 1e5 * stepSize) {
|
|
throw new Error(min + " and " + max + " are too far apart with stepSize of " + stepSize + " " + minor);
|
|
}
|
|
const timestamps = options.ticks.source === "data" && this.getDataTimestamps();
|
|
for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) {
|
|
addTick(ticks, time, timestamps);
|
|
}
|
|
if (time === max || options.bounds === "ticks" || count === 1) {
|
|
addTick(ticks, time, timestamps);
|
|
}
|
|
return Object.keys(ticks).sort(sorter).map((x2) => +x2);
|
|
}
|
|
getLabelForValue(value) {
|
|
const adapter = this._adapter;
|
|
const timeOpts = this.options.time;
|
|
if (timeOpts.tooltipFormat) {
|
|
return adapter.format(value, timeOpts.tooltipFormat);
|
|
}
|
|
return adapter.format(value, timeOpts.displayFormats.datetime);
|
|
}
|
|
format(value, format) {
|
|
const options = this.options;
|
|
const formats = options.time.displayFormats;
|
|
const unit = this._unit;
|
|
const fmt = format || formats[unit];
|
|
return this._adapter.format(value, fmt);
|
|
}
|
|
_tickFormatFunction(time, index, ticks, format) {
|
|
const options = this.options;
|
|
const formatter = options.ticks.callback;
|
|
if (formatter) {
|
|
return callback(formatter, [
|
|
time,
|
|
index,
|
|
ticks
|
|
], this);
|
|
}
|
|
const formats = options.time.displayFormats;
|
|
const unit = this._unit;
|
|
const majorUnit = this._majorUnit;
|
|
const minorFormat = unit && formats[unit];
|
|
const majorFormat = majorUnit && formats[majorUnit];
|
|
const tick = ticks[index];
|
|
const major = majorUnit && majorFormat && tick && tick.major;
|
|
return this._adapter.format(time, format || (major ? majorFormat : minorFormat));
|
|
}
|
|
generateTickLabels(ticks) {
|
|
let i2, ilen, tick;
|
|
for (i2 = 0, ilen = ticks.length; i2 < ilen; ++i2) {
|
|
tick = ticks[i2];
|
|
tick.label = this._tickFormatFunction(tick.value, i2, ticks);
|
|
}
|
|
}
|
|
getDecimalForValue(value) {
|
|
return value === null ? NaN : (value - this.min) / (this.max - this.min);
|
|
}
|
|
getPixelForValue(value) {
|
|
const offsets = this._offsets;
|
|
const pos = this.getDecimalForValue(value);
|
|
return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
|
|
}
|
|
getValueForPixel(pixel) {
|
|
const offsets = this._offsets;
|
|
const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
|
|
return this.min + pos * (this.max - this.min);
|
|
}
|
|
_getLabelSize(label) {
|
|
const ticksOpts = this.options.ticks;
|
|
const tickLabelWidth = this.ctx.measureText(label).width;
|
|
const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
|
|
const cosRotation = Math.cos(angle);
|
|
const sinRotation = Math.sin(angle);
|
|
const tickFontSize = this._resolveTickFontOptions(0).size;
|
|
return {
|
|
w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,
|
|
h: tickLabelWidth * sinRotation + tickFontSize * cosRotation
|
|
};
|
|
}
|
|
_getLabelCapacity(exampleTime) {
|
|
const timeOpts = this.options.time;
|
|
const displayFormats = timeOpts.displayFormats;
|
|
const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
|
|
const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [
|
|
exampleTime
|
|
], this._majorUnit), format);
|
|
const size = this._getLabelSize(exampleLabel);
|
|
const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
|
|
return capacity > 0 ? capacity : 1;
|
|
}
|
|
getDataTimestamps() {
|
|
let timestamps = this._cache.data || [];
|
|
let i2, ilen;
|
|
if (timestamps.length) {
|
|
return timestamps;
|
|
}
|
|
const metas = this.getMatchingVisibleMetas();
|
|
if (this._normalized && metas.length) {
|
|
return this._cache.data = metas[0].controller.getAllParsedValues(this);
|
|
}
|
|
for (i2 = 0, ilen = metas.length; i2 < ilen; ++i2) {
|
|
timestamps = timestamps.concat(metas[i2].controller.getAllParsedValues(this));
|
|
}
|
|
return this._cache.data = this.normalize(timestamps);
|
|
}
|
|
getLabelTimestamps() {
|
|
const timestamps = this._cache.labels || [];
|
|
let i2, ilen;
|
|
if (timestamps.length) {
|
|
return timestamps;
|
|
}
|
|
const labels = this.getLabels();
|
|
for (i2 = 0, ilen = labels.length; i2 < ilen; ++i2) {
|
|
timestamps.push(parse2(this, labels[i2]));
|
|
}
|
|
return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);
|
|
}
|
|
normalize(values) {
|
|
return _arrayUnique(values.sort(sorter));
|
|
}
|
|
};
|
|
__publicField(TimeScale, "id", "time");
|
|
__publicField(TimeScale, "defaults", {
|
|
bounds: "data",
|
|
adapters: {},
|
|
time: {
|
|
parser: false,
|
|
unit: false,
|
|
round: false,
|
|
isoWeekday: false,
|
|
minUnit: "millisecond",
|
|
displayFormats: {}
|
|
},
|
|
ticks: {
|
|
source: "auto",
|
|
callback: false,
|
|
major: {
|
|
enabled: false
|
|
}
|
|
}
|
|
});
|
|
function interpolate3(table, val, reverse) {
|
|
let lo = 0;
|
|
let hi = table.length - 1;
|
|
let prevSource, nextSource, prevTarget, nextTarget;
|
|
if (reverse) {
|
|
if (val >= table[lo].pos && val <= table[hi].pos) {
|
|
({ lo, hi } = _lookupByKey(table, "pos", val));
|
|
}
|
|
({ pos: prevSource, time: prevTarget } = table[lo]);
|
|
({ pos: nextSource, time: nextTarget } = table[hi]);
|
|
} else {
|
|
if (val >= table[lo].time && val <= table[hi].time) {
|
|
({ lo, hi } = _lookupByKey(table, "time", val));
|
|
}
|
|
({ time: prevSource, pos: prevTarget } = table[lo]);
|
|
({ time: nextSource, pos: nextTarget } = table[hi]);
|
|
}
|
|
const span = nextSource - prevSource;
|
|
return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
|
|
}
|
|
var TimeSeriesScale = class extends TimeScale {
|
|
constructor(props) {
|
|
super(props);
|
|
this._table = [];
|
|
this._minPos = void 0;
|
|
this._tableRange = void 0;
|
|
}
|
|
initOffsets() {
|
|
const timestamps = this._getTimestampsForTable();
|
|
const table = this._table = this.buildLookupTable(timestamps);
|
|
this._minPos = interpolate3(table, this.min);
|
|
this._tableRange = interpolate3(table, this.max) - this._minPos;
|
|
super.initOffsets(timestamps);
|
|
}
|
|
buildLookupTable(timestamps) {
|
|
const { min, max } = this;
|
|
const items = [];
|
|
const table = [];
|
|
let i2, ilen, prev, curr, next;
|
|
for (i2 = 0, ilen = timestamps.length; i2 < ilen; ++i2) {
|
|
curr = timestamps[i2];
|
|
if (curr >= min && curr <= max) {
|
|
items.push(curr);
|
|
}
|
|
}
|
|
if (items.length < 2) {
|
|
return [
|
|
{
|
|
time: min,
|
|
pos: 0
|
|
},
|
|
{
|
|
time: max,
|
|
pos: 1
|
|
}
|
|
];
|
|
}
|
|
for (i2 = 0, ilen = items.length; i2 < ilen; ++i2) {
|
|
next = items[i2 + 1];
|
|
prev = items[i2 - 1];
|
|
curr = items[i2];
|
|
if (Math.round((next + prev) / 2) !== curr) {
|
|
table.push({
|
|
time: curr,
|
|
pos: i2 / (ilen - 1)
|
|
});
|
|
}
|
|
}
|
|
return table;
|
|
}
|
|
_generate() {
|
|
const min = this.min;
|
|
const max = this.max;
|
|
let timestamps = super.getDataTimestamps();
|
|
if (!timestamps.includes(min) || !timestamps.length) {
|
|
timestamps.splice(0, 0, min);
|
|
}
|
|
if (!timestamps.includes(max) || timestamps.length === 1) {
|
|
timestamps.push(max);
|
|
}
|
|
return timestamps.sort((a2, b2) => a2 - b2);
|
|
}
|
|
_getTimestampsForTable() {
|
|
let timestamps = this._cache.all || [];
|
|
if (timestamps.length) {
|
|
return timestamps;
|
|
}
|
|
const data = this.getDataTimestamps();
|
|
const label = this.getLabelTimestamps();
|
|
if (data.length && label.length) {
|
|
timestamps = this.normalize(data.concat(label));
|
|
} else {
|
|
timestamps = data.length ? data : label;
|
|
}
|
|
timestamps = this._cache.all = timestamps;
|
|
return timestamps;
|
|
}
|
|
getDecimalForValue(value) {
|
|
return (interpolate3(this._table, value) - this._minPos) / this._tableRange;
|
|
}
|
|
getValueForPixel(pixel) {
|
|
const offsets = this._offsets;
|
|
const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
|
|
return interpolate3(this._table, decimal * this._tableRange + this._minPos, true);
|
|
}
|
|
};
|
|
__publicField(TimeSeriesScale, "id", "timeseries");
|
|
__publicField(TimeSeriesScale, "defaults", TimeScale.defaults);
|
|
|
|
// node_modules/.pnpm/gridjs@6.2.0/node_modules/gridjs/dist/gridjs.module.js
|
|
function t2(t3, n2) {
|
|
for (var e2 = 0; e2 < n2.length; e2++) {
|
|
var r2 = n2[e2];
|
|
r2.enumerable = r2.enumerable || false, r2.configurable = true, "value" in r2 && (r2.writable = true), Object.defineProperty(t3, "symbol" == typeof (o2 = function(t4, n3) {
|
|
if ("object" != typeof t4 || null === t4) return t4;
|
|
var e3 = t4[Symbol.toPrimitive];
|
|
if (void 0 !== e3) {
|
|
var r3 = e3.call(t4, "string");
|
|
if ("object" != typeof r3) return r3;
|
|
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
}
|
|
return String(t4);
|
|
}(r2.key)) ? o2 : String(o2), r2);
|
|
}
|
|
var o2;
|
|
}
|
|
function n(n2, e2, r2) {
|
|
return e2 && t2(n2.prototype, e2), r2 && t2(n2, r2), Object.defineProperty(n2, "prototype", { writable: false }), n2;
|
|
}
|
|
function e() {
|
|
return e = Object.assign ? Object.assign.bind() : function(t3) {
|
|
for (var n2 = 1; n2 < arguments.length; n2++) {
|
|
var e2 = arguments[n2];
|
|
for (var r2 in e2) Object.prototype.hasOwnProperty.call(e2, r2) && (t3[r2] = e2[r2]);
|
|
}
|
|
return t3;
|
|
}, e.apply(this, arguments);
|
|
}
|
|
function r(t3, n2) {
|
|
t3.prototype = Object.create(n2.prototype), t3.prototype.constructor = t3, o(t3, n2);
|
|
}
|
|
function o(t3, n2) {
|
|
return o = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(t4, n3) {
|
|
return t4.__proto__ = n3, t4;
|
|
}, o(t3, n2);
|
|
}
|
|
function i(t3) {
|
|
if (void 0 === t3) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
return t3;
|
|
}
|
|
function u(t3, n2) {
|
|
(null == n2 || n2 > t3.length) && (n2 = t3.length);
|
|
for (var e2 = 0, r2 = new Array(n2); e2 < n2; e2++) r2[e2] = t3[e2];
|
|
return r2;
|
|
}
|
|
function s(t3, n2) {
|
|
var e2 = "undefined" != typeof Symbol && t3[Symbol.iterator] || t3["@@iterator"];
|
|
if (e2) return (e2 = e2.call(t3)).next.bind(e2);
|
|
if (Array.isArray(t3) || (e2 = function(t4, n3) {
|
|
if (t4) {
|
|
if ("string" == typeof t4) return u(t4, n3);
|
|
var e3 = Object.prototype.toString.call(t4).slice(8, -1);
|
|
return "Object" === e3 && t4.constructor && (e3 = t4.constructor.name), "Map" === e3 || "Set" === e3 ? Array.from(t4) : "Arguments" === e3 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e3) ? u(t4, n3) : void 0;
|
|
}
|
|
}(t3)) || n2 && t3 && "number" == typeof t3.length) {
|
|
e2 && (t3 = e2);
|
|
var r2 = 0;
|
|
return function() {
|
|
return r2 >= t3.length ? { done: true } : { done: false, value: t3[r2++] };
|
|
};
|
|
}
|
|
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
}
|
|
var a;
|
|
!function(t3) {
|
|
t3[t3.Init = 0] = "Init", t3[t3.Loading = 1] = "Loading", t3[t3.Loaded = 2] = "Loaded", t3[t3.Rendered = 3] = "Rendered", t3[t3.Error = 4] = "Error";
|
|
}(a || (a = {}));
|
|
var l;
|
|
var c;
|
|
var f;
|
|
var p;
|
|
var d;
|
|
var h3;
|
|
var _;
|
|
var m = {};
|
|
var v = [];
|
|
var y = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
|
|
function g(t3, n2) {
|
|
for (var e2 in n2) t3[e2] = n2[e2];
|
|
return t3;
|
|
}
|
|
function b(t3) {
|
|
var n2 = t3.parentNode;
|
|
n2 && n2.removeChild(t3);
|
|
}
|
|
function w(t3, n2, e2) {
|
|
var r2, o2, i2, u2 = {};
|
|
for (i2 in n2) "key" == i2 ? r2 = n2[i2] : "ref" == i2 ? o2 = n2[i2] : u2[i2] = n2[i2];
|
|
if (arguments.length > 2 && (u2.children = arguments.length > 3 ? l.call(arguments, 2) : e2), "function" == typeof t3 && null != t3.defaultProps) for (i2 in t3.defaultProps) void 0 === u2[i2] && (u2[i2] = t3.defaultProps[i2]);
|
|
return x(t3, u2, r2, o2, null);
|
|
}
|
|
function x(t3, n2, e2, r2, o2) {
|
|
var i2 = { type: t3, props: n2, key: e2, ref: r2, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, __h: null, constructor: void 0, __v: null == o2 ? ++f : o2 };
|
|
return null == o2 && null != c.vnode && c.vnode(i2), i2;
|
|
}
|
|
function S(t3) {
|
|
return t3.children;
|
|
}
|
|
function N(t3, n2) {
|
|
this.props = t3, this.context = n2;
|
|
}
|
|
function P(t3, n2) {
|
|
if (null == n2) return t3.__ ? P(t3.__, t3.__.__k.indexOf(t3) + 1) : null;
|
|
for (var e2; n2 < t3.__k.length; n2++) if (null != (e2 = t3.__k[n2]) && null != e2.__e) return e2.__e;
|
|
return "function" == typeof t3.type ? P(t3) : null;
|
|
}
|
|
function C(t3) {
|
|
var n2, e2;
|
|
if (null != (t3 = t3.__) && null != t3.__c) {
|
|
for (t3.__e = t3.__c.base = null, n2 = 0; n2 < t3.__k.length; n2++) if (null != (e2 = t3.__k[n2]) && null != e2.__e) {
|
|
t3.__e = t3.__c.base = e2.__e;
|
|
break;
|
|
}
|
|
return C(t3);
|
|
}
|
|
}
|
|
function E(t3) {
|
|
(!t3.__d && (t3.__d = true) && d.push(t3) && !I.__r++ || h3 !== c.debounceRendering) && ((h3 = c.debounceRendering) || setTimeout)(I);
|
|
}
|
|
function I() {
|
|
for (var t3; I.__r = d.length; ) t3 = d.sort(function(t4, n2) {
|
|
return t4.__v.__b - n2.__v.__b;
|
|
}), d = [], t3.some(function(t4) {
|
|
var n2, e2, r2, o2, i2, u2;
|
|
t4.__d && (i2 = (o2 = (n2 = t4).__v).__e, (u2 = n2.__P) && (e2 = [], (r2 = g({}, o2)).__v = o2.__v + 1, M(u2, o2, r2, n2.__n, void 0 !== u2.ownerSVGElement, null != o2.__h ? [i2] : null, e2, null == i2 ? P(o2) : i2, o2.__h), F(e2, o2), o2.__e != i2 && C(o2)));
|
|
});
|
|
}
|
|
function T(t3, n2, e2, r2, o2, i2, u2, s2, a2, l2) {
|
|
var c2, f2, p2, d2, h6, _2, y2, g2 = r2 && r2.__k || v, b2 = g2.length;
|
|
for (e2.__k = [], c2 = 0; c2 < n2.length; c2++) if (null != (d2 = e2.__k[c2] = null == (d2 = n2[c2]) || "boolean" == typeof d2 ? null : "string" == typeof d2 || "number" == typeof d2 || "bigint" == typeof d2 ? x(null, d2, null, null, d2) : Array.isArray(d2) ? x(S, { children: d2 }, null, null, null) : d2.__b > 0 ? x(d2.type, d2.props, d2.key, d2.ref ? d2.ref : null, d2.__v) : d2)) {
|
|
if (d2.__ = e2, d2.__b = e2.__b + 1, null === (p2 = g2[c2]) || p2 && d2.key == p2.key && d2.type === p2.type) g2[c2] = void 0;
|
|
else for (f2 = 0; f2 < b2; f2++) {
|
|
if ((p2 = g2[f2]) && d2.key == p2.key && d2.type === p2.type) {
|
|
g2[f2] = void 0;
|
|
break;
|
|
}
|
|
p2 = null;
|
|
}
|
|
M(t3, d2, p2 = p2 || m, o2, i2, u2, s2, a2, l2), h6 = d2.__e, (f2 = d2.ref) && p2.ref != f2 && (y2 || (y2 = []), p2.ref && y2.push(p2.ref, null, d2), y2.push(f2, d2.__c || h6, d2)), null != h6 ? (null == _2 && (_2 = h6), "function" == typeof d2.type && d2.__k === p2.__k ? d2.__d = a2 = L(d2, a2, t3) : a2 = A(t3, d2, p2, g2, h6, a2), "function" == typeof e2.type && (e2.__d = a2)) : a2 && p2.__e == a2 && a2.parentNode != t3 && (a2 = P(p2));
|
|
}
|
|
for (e2.__e = _2, c2 = b2; c2--; ) null != g2[c2] && W(g2[c2], g2[c2]);
|
|
if (y2) for (c2 = 0; c2 < y2.length; c2++) U(y2[c2], y2[++c2], y2[++c2]);
|
|
}
|
|
function L(t3, n2, e2) {
|
|
for (var r2, o2 = t3.__k, i2 = 0; o2 && i2 < o2.length; i2++) (r2 = o2[i2]) && (r2.__ = t3, n2 = "function" == typeof r2.type ? L(r2, n2, e2) : A(e2, r2, r2, o2, r2.__e, n2));
|
|
return n2;
|
|
}
|
|
function A(t3, n2, e2, r2, o2, i2) {
|
|
var u2, s2, a2;
|
|
if (void 0 !== n2.__d) u2 = n2.__d, n2.__d = void 0;
|
|
else if (null == e2 || o2 != i2 || null == o2.parentNode) t: if (null == i2 || i2.parentNode !== t3) t3.appendChild(o2), u2 = null;
|
|
else {
|
|
for (s2 = i2, a2 = 0; (s2 = s2.nextSibling) && a2 < r2.length; a2 += 1) if (s2 == o2) break t;
|
|
t3.insertBefore(o2, i2), u2 = i2;
|
|
}
|
|
return void 0 !== u2 ? u2 : o2.nextSibling;
|
|
}
|
|
function O(t3, n2, e2) {
|
|
"-" === n2[0] ? t3.setProperty(n2, e2) : t3[n2] = null == e2 ? "" : "number" != typeof e2 || y.test(n2) ? e2 : e2 + "px";
|
|
}
|
|
function H(t3, n2, e2, r2, o2) {
|
|
var i2;
|
|
t: if ("style" === n2) if ("string" == typeof e2) t3.style.cssText = e2;
|
|
else {
|
|
if ("string" == typeof r2 && (t3.style.cssText = r2 = ""), r2) for (n2 in r2) e2 && n2 in e2 || O(t3.style, n2, "");
|
|
if (e2) for (n2 in e2) r2 && e2[n2] === r2[n2] || O(t3.style, n2, e2[n2]);
|
|
}
|
|
else if ("o" === n2[0] && "n" === n2[1]) i2 = n2 !== (n2 = n2.replace(/Capture$/, "")), n2 = n2.toLowerCase() in t3 ? n2.toLowerCase().slice(2) : n2.slice(2), t3.l || (t3.l = {}), t3.l[n2 + i2] = e2, e2 ? r2 || t3.addEventListener(n2, i2 ? D : j, i2) : t3.removeEventListener(n2, i2 ? D : j, i2);
|
|
else if ("dangerouslySetInnerHTML" !== n2) {
|
|
if (o2) n2 = n2.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s");
|
|
else if ("href" !== n2 && "list" !== n2 && "form" !== n2 && "tabIndex" !== n2 && "download" !== n2 && n2 in t3) try {
|
|
t3[n2] = null == e2 ? "" : e2;
|
|
break t;
|
|
} catch (t4) {
|
|
}
|
|
"function" == typeof e2 || (null == e2 || false === e2 && -1 == n2.indexOf("-") ? t3.removeAttribute(n2) : t3.setAttribute(n2, e2));
|
|
}
|
|
}
|
|
function j(t3) {
|
|
this.l[t3.type + false](c.event ? c.event(t3) : t3);
|
|
}
|
|
function D(t3) {
|
|
this.l[t3.type + true](c.event ? c.event(t3) : t3);
|
|
}
|
|
function M(t3, n2, e2, r2, o2, i2, u2, s2, a2) {
|
|
var l2, f2, p2, d2, h6, _2, m2, v2, y2, b2, w2, x2, k, P2, C2, E2 = n2.type;
|
|
if (void 0 !== n2.constructor) return null;
|
|
null != e2.__h && (a2 = e2.__h, s2 = n2.__e = e2.__e, n2.__h = null, i2 = [s2]), (l2 = c.__b) && l2(n2);
|
|
try {
|
|
t: if ("function" == typeof E2) {
|
|
if (v2 = n2.props, y2 = (l2 = E2.contextType) && r2[l2.__c], b2 = l2 ? y2 ? y2.props.value : l2.__ : r2, e2.__c ? m2 = (f2 = n2.__c = e2.__c).__ = f2.__E : ("prototype" in E2 && E2.prototype.render ? n2.__c = f2 = new E2(v2, b2) : (n2.__c = f2 = new N(v2, b2), f2.constructor = E2, f2.render = B), y2 && y2.sub(f2), f2.props = v2, f2.state || (f2.state = {}), f2.context = b2, f2.__n = r2, p2 = f2.__d = true, f2.__h = [], f2._sb = []), null == f2.__s && (f2.__s = f2.state), null != E2.getDerivedStateFromProps && (f2.__s == f2.state && (f2.__s = g({}, f2.__s)), g(f2.__s, E2.getDerivedStateFromProps(v2, f2.__s))), d2 = f2.props, h6 = f2.state, p2) null == E2.getDerivedStateFromProps && null != f2.componentWillMount && f2.componentWillMount(), null != f2.componentDidMount && f2.__h.push(f2.componentDidMount);
|
|
else {
|
|
if (null == E2.getDerivedStateFromProps && v2 !== d2 && null != f2.componentWillReceiveProps && f2.componentWillReceiveProps(v2, b2), !f2.__e && null != f2.shouldComponentUpdate && false === f2.shouldComponentUpdate(v2, f2.__s, b2) || n2.__v === e2.__v) {
|
|
for (f2.props = v2, f2.state = f2.__s, n2.__v !== e2.__v && (f2.__d = false), f2.__v = n2, n2.__e = e2.__e, n2.__k = e2.__k, n2.__k.forEach(function(t4) {
|
|
t4 && (t4.__ = n2);
|
|
}), w2 = 0; w2 < f2._sb.length; w2++) f2.__h.push(f2._sb[w2]);
|
|
f2._sb = [], f2.__h.length && u2.push(f2);
|
|
break t;
|
|
}
|
|
null != f2.componentWillUpdate && f2.componentWillUpdate(v2, f2.__s, b2), null != f2.componentDidUpdate && f2.__h.push(function() {
|
|
f2.componentDidUpdate(d2, h6, _2);
|
|
});
|
|
}
|
|
if (f2.context = b2, f2.props = v2, f2.__v = n2, f2.__P = t3, x2 = c.__r, k = 0, "prototype" in E2 && E2.prototype.render) {
|
|
for (f2.state = f2.__s, f2.__d = false, x2 && x2(n2), l2 = f2.render(f2.props, f2.state, f2.context), P2 = 0; P2 < f2._sb.length; P2++) f2.__h.push(f2._sb[P2]);
|
|
f2._sb = [];
|
|
} else do {
|
|
f2.__d = false, x2 && x2(n2), l2 = f2.render(f2.props, f2.state, f2.context), f2.state = f2.__s;
|
|
} while (f2.__d && ++k < 25);
|
|
f2.state = f2.__s, null != f2.getChildContext && (r2 = g(g({}, r2), f2.getChildContext())), p2 || null == f2.getSnapshotBeforeUpdate || (_2 = f2.getSnapshotBeforeUpdate(d2, h6)), C2 = null != l2 && l2.type === S && null == l2.key ? l2.props.children : l2, T(t3, Array.isArray(C2) ? C2 : [C2], n2, e2, r2, o2, i2, u2, s2, a2), f2.base = n2.__e, n2.__h = null, f2.__h.length && u2.push(f2), m2 && (f2.__E = f2.__ = null), f2.__e = false;
|
|
} else null == i2 && n2.__v === e2.__v ? (n2.__k = e2.__k, n2.__e = e2.__e) : n2.__e = R(e2.__e, n2, e2, r2, o2, i2, u2, a2);
|
|
(l2 = c.diffed) && l2(n2);
|
|
} catch (t4) {
|
|
n2.__v = null, (a2 || null != i2) && (n2.__e = s2, n2.__h = !!a2, i2[i2.indexOf(s2)] = null), c.__e(t4, n2, e2);
|
|
}
|
|
}
|
|
function F(t3, n2) {
|
|
c.__c && c.__c(n2, t3), t3.some(function(n3) {
|
|
try {
|
|
t3 = n3.__h, n3.__h = [], t3.some(function(t4) {
|
|
t4.call(n3);
|
|
});
|
|
} catch (t4) {
|
|
c.__e(t4, n3.__v);
|
|
}
|
|
});
|
|
}
|
|
function R(t3, n2, e2, r2, o2, i2, u2, s2) {
|
|
var a2, c2, f2, p2 = e2.props, d2 = n2.props, h6 = n2.type, _2 = 0;
|
|
if ("svg" === h6 && (o2 = true), null != i2) {
|
|
for (; _2 < i2.length; _2++) if ((a2 = i2[_2]) && "setAttribute" in a2 == !!h6 && (h6 ? a2.localName === h6 : 3 === a2.nodeType)) {
|
|
t3 = a2, i2[_2] = null;
|
|
break;
|
|
}
|
|
}
|
|
if (null == t3) {
|
|
if (null === h6) return document.createTextNode(d2);
|
|
t3 = o2 ? document.createElementNS("http://www.w3.org/2000/svg", h6) : document.createElement(h6, d2.is && d2), i2 = null, s2 = false;
|
|
}
|
|
if (null === h6) p2 === d2 || s2 && t3.data === d2 || (t3.data = d2);
|
|
else {
|
|
if (i2 = i2 && l.call(t3.childNodes), c2 = (p2 = e2.props || m).dangerouslySetInnerHTML, f2 = d2.dangerouslySetInnerHTML, !s2) {
|
|
if (null != i2) for (p2 = {}, _2 = 0; _2 < t3.attributes.length; _2++) p2[t3.attributes[_2].name] = t3.attributes[_2].value;
|
|
(f2 || c2) && (f2 && (c2 && f2.__html == c2.__html || f2.__html === t3.innerHTML) || (t3.innerHTML = f2 && f2.__html || ""));
|
|
}
|
|
if (function(t4, n3, e3, r3, o3) {
|
|
var i3;
|
|
for (i3 in e3) "children" === i3 || "key" === i3 || i3 in n3 || H(t4, i3, null, e3[i3], r3);
|
|
for (i3 in n3) o3 && "function" != typeof n3[i3] || "children" === i3 || "key" === i3 || "value" === i3 || "checked" === i3 || e3[i3] === n3[i3] || H(t4, i3, n3[i3], e3[i3], r3);
|
|
}(t3, d2, p2, o2, s2), f2) n2.__k = [];
|
|
else if (_2 = n2.props.children, T(t3, Array.isArray(_2) ? _2 : [_2], n2, e2, r2, o2 && "foreignObject" !== h6, i2, u2, i2 ? i2[0] : e2.__k && P(e2, 0), s2), null != i2) for (_2 = i2.length; _2--; ) null != i2[_2] && b(i2[_2]);
|
|
s2 || ("value" in d2 && void 0 !== (_2 = d2.value) && (_2 !== t3.value || "progress" === h6 && !_2 || "option" === h6 && _2 !== p2.value) && H(t3, "value", _2, p2.value, false), "checked" in d2 && void 0 !== (_2 = d2.checked) && _2 !== t3.checked && H(t3, "checked", _2, p2.checked, false));
|
|
}
|
|
return t3;
|
|
}
|
|
function U(t3, n2, e2) {
|
|
try {
|
|
"function" == typeof t3 ? t3(n2) : t3.current = n2;
|
|
} catch (t4) {
|
|
c.__e(t4, e2);
|
|
}
|
|
}
|
|
function W(t3, n2, e2) {
|
|
var r2, o2;
|
|
if (c.unmount && c.unmount(t3), (r2 = t3.ref) && (r2.current && r2.current !== t3.__e || U(r2, null, n2)), null != (r2 = t3.__c)) {
|
|
if (r2.componentWillUnmount) try {
|
|
r2.componentWillUnmount();
|
|
} catch (t4) {
|
|
c.__e(t4, n2);
|
|
}
|
|
r2.base = r2.__P = null, t3.__c = void 0;
|
|
}
|
|
if (r2 = t3.__k) for (o2 = 0; o2 < r2.length; o2++) r2[o2] && W(r2[o2], n2, e2 || "function" != typeof t3.type);
|
|
e2 || null == t3.__e || b(t3.__e), t3.__ = t3.__e = t3.__d = void 0;
|
|
}
|
|
function B(t3, n2, e2) {
|
|
return this.constructor(t3, e2);
|
|
}
|
|
function q(t3, n2, e2) {
|
|
var r2, o2, i2;
|
|
c.__ && c.__(t3, n2), o2 = (r2 = "function" == typeof e2) ? null : e2 && e2.__k || n2.__k, i2 = [], M(n2, t3 = (!r2 && e2 || n2).__k = w(S, null, [t3]), o2 || m, m, void 0 !== n2.ownerSVGElement, !r2 && e2 ? [e2] : o2 ? null : n2.firstChild ? l.call(n2.childNodes) : null, i2, !r2 && e2 ? e2 : o2 ? o2.__e : n2.firstChild, r2), F(i2, t3);
|
|
}
|
|
function z() {
|
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(t3) {
|
|
var n2 = 16 * Math.random() | 0;
|
|
return ("x" == t3 ? n2 : 3 & n2 | 8).toString(16);
|
|
});
|
|
}
|
|
l = v.slice, c = { __e: function(t3, n2, e2, r2) {
|
|
for (var o2, i2, u2; n2 = n2.__; ) if ((o2 = n2.__c) && !o2.__) try {
|
|
if ((i2 = o2.constructor) && null != i2.getDerivedStateFromError && (o2.setState(i2.getDerivedStateFromError(t3)), u2 = o2.__d), null != o2.componentDidCatch && (o2.componentDidCatch(t3, r2 || {}), u2 = o2.__d), u2) return o2.__E = o2;
|
|
} catch (n3) {
|
|
t3 = n3;
|
|
}
|
|
throw t3;
|
|
} }, f = 0, p = function(t3) {
|
|
return null != t3 && void 0 === t3.constructor;
|
|
}, N.prototype.setState = function(t3, n2) {
|
|
var e2;
|
|
e2 = null != this.__s && this.__s !== this.state ? this.__s : this.__s = g({}, this.state), "function" == typeof t3 && (t3 = t3(g({}, e2), this.props)), t3 && g(e2, t3), null != t3 && this.__v && (n2 && this._sb.push(n2), E(this));
|
|
}, N.prototype.forceUpdate = function(t3) {
|
|
this.__v && (this.__e = true, t3 && this.__h.push(t3), E(this));
|
|
}, N.prototype.render = S, d = [], I.__r = 0, _ = 0;
|
|
var V = /* @__PURE__ */ function() {
|
|
function t3(t4) {
|
|
this._id = void 0, this._id = t4 || z();
|
|
}
|
|
return n(t3, [{ key: "id", get: function() {
|
|
return this._id;
|
|
} }]), t3;
|
|
}();
|
|
function $(t3) {
|
|
return w(t3.parentElement || "span", { dangerouslySetInnerHTML: { __html: t3.content } });
|
|
}
|
|
function G(t3, n2) {
|
|
return w($, { content: t3, parentElement: n2 });
|
|
}
|
|
var K;
|
|
var X = /* @__PURE__ */ function(t3) {
|
|
function n2(n3) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this).data = void 0, e3.update(n3), e3;
|
|
}
|
|
r(n2, t3);
|
|
var e2 = n2.prototype;
|
|
return e2.cast = function(t4) {
|
|
return t4 instanceof HTMLElement ? G(t4.outerHTML) : t4;
|
|
}, e2.update = function(t4) {
|
|
return this.data = this.cast(t4), this;
|
|
}, n2;
|
|
}(V);
|
|
var Z = /* @__PURE__ */ function(t3) {
|
|
function e2(n2) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this)._cells = void 0, e3.cells = n2 || [], e3;
|
|
}
|
|
r(e2, t3);
|
|
var o2 = e2.prototype;
|
|
return o2.cell = function(t4) {
|
|
return this._cells[t4];
|
|
}, o2.toArray = function() {
|
|
return this.cells.map(function(t4) {
|
|
return t4.data;
|
|
});
|
|
}, e2.fromCells = function(t4) {
|
|
return new e2(t4.map(function(t5) {
|
|
return new X(t5.data);
|
|
}));
|
|
}, n(e2, [{ key: "cells", get: function() {
|
|
return this._cells;
|
|
}, set: function(t4) {
|
|
this._cells = t4;
|
|
} }, { key: "length", get: function() {
|
|
return this.cells.length;
|
|
} }]), e2;
|
|
}(V);
|
|
var J = /* @__PURE__ */ function(t3) {
|
|
function e2(n2) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this)._rows = void 0, e3._length = void 0, e3.rows = n2 instanceof Array ? n2 : n2 instanceof Z ? [n2] : [], e3;
|
|
}
|
|
return r(e2, t3), e2.prototype.toArray = function() {
|
|
return this.rows.map(function(t4) {
|
|
return t4.toArray();
|
|
});
|
|
}, e2.fromRows = function(t4) {
|
|
return new e2(t4.map(function(t5) {
|
|
return Z.fromCells(t5.cells);
|
|
}));
|
|
}, e2.fromArray = function(t4) {
|
|
return new e2((t4 = function(t5) {
|
|
return !t5[0] || t5[0] instanceof Array ? t5 : [t5];
|
|
}(t4)).map(function(t5) {
|
|
return new Z(t5.map(function(t6) {
|
|
return new X(t6);
|
|
}));
|
|
}));
|
|
}, n(e2, [{ key: "rows", get: function() {
|
|
return this._rows;
|
|
}, set: function(t4) {
|
|
this._rows = t4;
|
|
} }, { key: "length", get: function() {
|
|
return this._length || this.rows.length;
|
|
}, set: function(t4) {
|
|
this._length = t4;
|
|
} }]), e2;
|
|
}(V);
|
|
var Q = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
this.callbacks = void 0;
|
|
}
|
|
var n2 = t3.prototype;
|
|
return n2.init = function(t4) {
|
|
this.callbacks || (this.callbacks = {}), t4 && !this.callbacks[t4] && (this.callbacks[t4] = []);
|
|
}, n2.listeners = function() {
|
|
return this.callbacks;
|
|
}, n2.on = function(t4, n3) {
|
|
return this.init(t4), this.callbacks[t4].push(n3), this;
|
|
}, n2.off = function(t4, n3) {
|
|
var e2 = t4;
|
|
return this.init(), this.callbacks[e2] && 0 !== this.callbacks[e2].length ? (this.callbacks[e2] = this.callbacks[e2].filter(function(t5) {
|
|
return t5 != n3;
|
|
}), this) : this;
|
|
}, n2.emit = function(t4) {
|
|
var n3 = arguments, e2 = t4;
|
|
return this.init(e2), this.callbacks[e2].length > 0 && (this.callbacks[e2].forEach(function(t5) {
|
|
return t5.apply(void 0, [].slice.call(n3, 1));
|
|
}), true);
|
|
}, t3;
|
|
}();
|
|
function Y(t3, n2) {
|
|
if (typeof t3 != typeof n2) return false;
|
|
if (null === t3 && null === n2) return true;
|
|
if ("object" != typeof t3) return t3 === n2;
|
|
if (Array.isArray(t3) && Array.isArray(n2)) {
|
|
if (t3.length !== n2.length) return false;
|
|
for (var e2 = 0; e2 < t3.length; e2++) if (!Y(t3[e2], n2[e2])) return false;
|
|
return true;
|
|
}
|
|
if (t3.hasOwnProperty("constructor") && n2.hasOwnProperty("constructor") && t3.hasOwnProperty("props") && n2.hasOwnProperty("props") && t3.hasOwnProperty("key") && n2.hasOwnProperty("key") && t3.hasOwnProperty("ref") && n2.hasOwnProperty("ref") && t3.hasOwnProperty("type") && n2.hasOwnProperty("type")) return Y(t3.props, n2.props);
|
|
var r2 = Object.keys(t3), o2 = Object.keys(n2);
|
|
if (r2.length !== o2.length) return false;
|
|
for (var i2 = 0, u2 = r2; i2 < u2.length; i2++) {
|
|
var s2 = u2[i2];
|
|
if (!n2.hasOwnProperty(s2) || !Y(t3[s2], n2[s2])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
!function(t3) {
|
|
t3[t3.Initiator = 0] = "Initiator", t3[t3.ServerFilter = 1] = "ServerFilter", t3[t3.ServerSort = 2] = "ServerSort", t3[t3.ServerLimit = 3] = "ServerLimit", t3[t3.Extractor = 4] = "Extractor", t3[t3.Transformer = 5] = "Transformer", t3[t3.Filter = 6] = "Filter", t3[t3.Sort = 7] = "Sort", t3[t3.Limit = 8] = "Limit";
|
|
}(K || (K = {}));
|
|
var tt = /* @__PURE__ */ function(t3) {
|
|
function o2(n2) {
|
|
var e2;
|
|
return (e2 = t3.call(this) || this).id = void 0, e2._props = void 0, e2._props = {}, e2.id = z(), n2 && e2.setProps(n2), e2;
|
|
}
|
|
r(o2, t3);
|
|
var i2 = o2.prototype;
|
|
return i2.process = function() {
|
|
var t4 = [].slice.call(arguments);
|
|
this.validateProps instanceof Function && this.validateProps.apply(this, t4), this.emit.apply(this, ["beforeProcess"].concat(t4));
|
|
var n2 = this._process.apply(this, t4);
|
|
return this.emit.apply(this, ["afterProcess"].concat(t4)), n2;
|
|
}, i2.setProps = function(t4) {
|
|
var n2 = e({}, this._props, t4);
|
|
return Y(n2, this._props) || (this._props = n2, this.emit("propsUpdated", this)), this;
|
|
}, n(o2, [{ key: "props", get: function() {
|
|
return this._props;
|
|
} }]), o2;
|
|
}(Q);
|
|
var nt = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(e2, t3), e2.prototype._process = function(t4) {
|
|
return this.props.keyword ? (n2 = String(this.props.keyword).trim(), e3 = this.props.columns, r2 = this.props.ignoreHiddenColumns, o2 = t4, i2 = this.props.selector, n2 = n2.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), new J(o2.rows.filter(function(t5, o3) {
|
|
return t5.cells.some(function(t6, u2) {
|
|
if (!t6) return false;
|
|
if (r2 && e3 && e3[u2] && "object" == typeof e3[u2] && e3[u2].hidden) return false;
|
|
var s2 = "";
|
|
if ("function" == typeof i2) s2 = i2(t6.data, o3, u2);
|
|
else if ("object" == typeof t6.data) {
|
|
var a2 = t6.data;
|
|
a2 && a2.props && a2.props.content && (s2 = a2.props.content);
|
|
} else s2 = String(t6.data);
|
|
return new RegExp(n2, "gi").test(s2);
|
|
});
|
|
}))) : t4;
|
|
var n2, e3, r2, o2, i2;
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Filter;
|
|
} }]), e2;
|
|
}(tt);
|
|
function et() {
|
|
var t3 = "gridjs";
|
|
return "" + t3 + [].slice.call(arguments).reduce(function(t4, n2) {
|
|
return t4 + "-" + n2;
|
|
}, "");
|
|
}
|
|
function rt() {
|
|
return [].slice.call(arguments).map(function(t3) {
|
|
return t3 ? t3.toString() : "";
|
|
}).filter(function(t3) {
|
|
return t3;
|
|
}).reduce(function(t3, n2) {
|
|
return (t3 || "") + " " + n2;
|
|
}, "").trim();
|
|
}
|
|
var ot;
|
|
var it;
|
|
var ut;
|
|
var st;
|
|
var at = /* @__PURE__ */ function(t3) {
|
|
function o2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(o2, t3), o2.prototype._process = function(t4) {
|
|
if (!this.props.keyword) return t4;
|
|
var n2 = {};
|
|
return this.props.url && (n2.url = this.props.url(t4.url, this.props.keyword)), this.props.body && (n2.body = this.props.body(t4.body, this.props.keyword)), e({}, t4, n2);
|
|
}, n(o2, [{ key: "type", get: function() {
|
|
return K.ServerFilter;
|
|
} }]), o2;
|
|
}(tt);
|
|
var lt = 0;
|
|
var ct = [];
|
|
var ft = [];
|
|
var pt = c.__b;
|
|
var dt = c.__r;
|
|
var ht = c.diffed;
|
|
var _t = c.__c;
|
|
var mt = c.unmount;
|
|
function vt(t3, n2) {
|
|
c.__h && c.__h(it, t3, lt || n2), lt = 0;
|
|
var e2 = it.__H || (it.__H = { __: [], __h: [] });
|
|
return t3 >= e2.__.length && e2.__.push({ __V: ft }), e2.__[t3];
|
|
}
|
|
function yt(t3) {
|
|
return lt = 1, function(t4, n2, e2) {
|
|
var r2 = vt(ot++, 2);
|
|
if (r2.t = t4, !r2.__c && (r2.__ = [Et(void 0, n2), function(t5) {
|
|
var n3 = r2.__N ? r2.__N[0] : r2.__[0], e3 = r2.t(n3, t5);
|
|
n3 !== e3 && (r2.__N = [e3, r2.__[1]], r2.__c.setState({}));
|
|
}], r2.__c = it, !it.u)) {
|
|
it.u = true;
|
|
var o2 = it.shouldComponentUpdate;
|
|
it.shouldComponentUpdate = function(t5, n3, e3) {
|
|
if (!r2.__c.__H) return true;
|
|
var i2 = r2.__c.__H.__.filter(function(t6) {
|
|
return t6.__c;
|
|
});
|
|
if (i2.every(function(t6) {
|
|
return !t6.__N;
|
|
})) return !o2 || o2.call(this, t5, n3, e3);
|
|
var u2 = false;
|
|
return i2.forEach(function(t6) {
|
|
if (t6.__N) {
|
|
var n4 = t6.__[0];
|
|
t6.__ = t6.__N, t6.__N = void 0, n4 !== t6.__[0] && (u2 = true);
|
|
}
|
|
}), !(!u2 && r2.__c.props === t5) && (!o2 || o2.call(this, t5, n3, e3));
|
|
};
|
|
}
|
|
return r2.__N || r2.__;
|
|
}(Et, t3);
|
|
}
|
|
function gt(t3, n2) {
|
|
var e2 = vt(ot++, 3);
|
|
!c.__s && Ct(e2.__H, n2) && (e2.__ = t3, e2.i = n2, it.__H.__h.push(e2));
|
|
}
|
|
function bt(t3) {
|
|
return lt = 5, wt(function() {
|
|
return { current: t3 };
|
|
}, []);
|
|
}
|
|
function wt(t3, n2) {
|
|
var e2 = vt(ot++, 7);
|
|
return Ct(e2.__H, n2) ? (e2.__V = t3(), e2.i = n2, e2.__h = t3, e2.__V) : e2.__;
|
|
}
|
|
function xt() {
|
|
for (var t3; t3 = ct.shift(); ) if (t3.__P && t3.__H) try {
|
|
t3.__H.__h.forEach(Nt), t3.__H.__h.forEach(Pt), t3.__H.__h = [];
|
|
} catch (n2) {
|
|
t3.__H.__h = [], c.__e(n2, t3.__v);
|
|
}
|
|
}
|
|
c.__b = function(t3) {
|
|
it = null, pt && pt(t3);
|
|
}, c.__r = function(t3) {
|
|
dt && dt(t3), ot = 0;
|
|
var n2 = (it = t3.__c).__H;
|
|
n2 && (ut === it ? (n2.__h = [], it.__h = [], n2.__.forEach(function(t4) {
|
|
t4.__N && (t4.__ = t4.__N), t4.__V = ft, t4.__N = t4.i = void 0;
|
|
})) : (n2.__h.forEach(Nt), n2.__h.forEach(Pt), n2.__h = [])), ut = it;
|
|
}, c.diffed = function(t3) {
|
|
ht && ht(t3);
|
|
var n2 = t3.__c;
|
|
n2 && n2.__H && (n2.__H.__h.length && (1 !== ct.push(n2) && st === c.requestAnimationFrame || ((st = c.requestAnimationFrame) || St)(xt)), n2.__H.__.forEach(function(t4) {
|
|
t4.i && (t4.__H = t4.i), t4.__V !== ft && (t4.__ = t4.__V), t4.i = void 0, t4.__V = ft;
|
|
})), ut = it = null;
|
|
}, c.__c = function(t3, n2) {
|
|
n2.some(function(t4) {
|
|
try {
|
|
t4.__h.forEach(Nt), t4.__h = t4.__h.filter(function(t5) {
|
|
return !t5.__ || Pt(t5);
|
|
});
|
|
} catch (e2) {
|
|
n2.some(function(t5) {
|
|
t5.__h && (t5.__h = []);
|
|
}), n2 = [], c.__e(e2, t4.__v);
|
|
}
|
|
}), _t && _t(t3, n2);
|
|
}, c.unmount = function(t3) {
|
|
mt && mt(t3);
|
|
var n2, e2 = t3.__c;
|
|
e2 && e2.__H && (e2.__H.__.forEach(function(t4) {
|
|
try {
|
|
Nt(t4);
|
|
} catch (t5) {
|
|
n2 = t5;
|
|
}
|
|
}), e2.__H = void 0, n2 && c.__e(n2, e2.__v));
|
|
};
|
|
var kt = "function" == typeof requestAnimationFrame;
|
|
function St(t3) {
|
|
var n2, e2 = function() {
|
|
clearTimeout(r2), kt && cancelAnimationFrame(n2), setTimeout(t3);
|
|
}, r2 = setTimeout(e2, 100);
|
|
kt && (n2 = requestAnimationFrame(e2));
|
|
}
|
|
function Nt(t3) {
|
|
var n2 = it, e2 = t3.__c;
|
|
"function" == typeof e2 && (t3.__c = void 0, e2()), it = n2;
|
|
}
|
|
function Pt(t3) {
|
|
var n2 = it;
|
|
t3.__c = t3.__(), it = n2;
|
|
}
|
|
function Ct(t3, n2) {
|
|
return !t3 || t3.length !== n2.length || n2.some(function(n3, e2) {
|
|
return n3 !== t3[e2];
|
|
});
|
|
}
|
|
function Et(t3, n2) {
|
|
return "function" == typeof n2 ? n2(t3) : n2;
|
|
}
|
|
function It() {
|
|
return function(t3) {
|
|
var n2 = it.context[t3.__c], e2 = vt(ot++, 9);
|
|
return e2.c = t3, n2 ? (null == e2.__ && (e2.__ = true, n2.sub(it)), n2.props.value) : t3.__;
|
|
}(fn);
|
|
}
|
|
var Tt = { search: { placeholder: "Type a keyword..." }, sort: { sortAsc: "Sort column ascending", sortDesc: "Sort column descending" }, pagination: { previous: "Previous", next: "Next", navigate: function(t3, n2) {
|
|
return "Page " + t3 + " of " + n2;
|
|
}, page: function(t3) {
|
|
return "Page " + t3;
|
|
}, showing: "Showing", of: "of", to: "to", results: "results" }, loading: "Loading...", noRecordsFound: "No matching records found", error: "An error happened while fetching the data" };
|
|
var Lt = /* @__PURE__ */ function() {
|
|
function t3(t4) {
|
|
this._language = void 0, this._defaultLanguage = void 0, this._language = t4, this._defaultLanguage = Tt;
|
|
}
|
|
var n2 = t3.prototype;
|
|
return n2.getString = function(t4, n3) {
|
|
if (!n3 || !t4) return null;
|
|
var e2 = t4.split("."), r2 = e2[0];
|
|
if (n3[r2]) {
|
|
var o2 = n3[r2];
|
|
return "string" == typeof o2 ? function() {
|
|
return o2;
|
|
} : "function" == typeof o2 ? o2 : this.getString(e2.slice(1).join("."), o2);
|
|
}
|
|
return null;
|
|
}, n2.translate = function(t4) {
|
|
var n3, e2 = this.getString(t4, this._language);
|
|
return (n3 = e2 || this.getString(t4, this._defaultLanguage)) ? n3.apply(void 0, [].slice.call(arguments, 1)) : t4;
|
|
}, t3;
|
|
}();
|
|
function At() {
|
|
var t3 = It();
|
|
return function(n2) {
|
|
var e2;
|
|
return (e2 = t3.translator).translate.apply(e2, [n2].concat([].slice.call(arguments, 1)));
|
|
};
|
|
}
|
|
var Ot = function(t3) {
|
|
return function(n2) {
|
|
return e({}, n2, { search: { keyword: t3 } });
|
|
};
|
|
};
|
|
function Ht() {
|
|
return It().store;
|
|
}
|
|
function jt(t3) {
|
|
var n2 = Ht(), e2 = yt(t3(n2.getState())), r2 = e2[0], o2 = e2[1];
|
|
return gt(function() {
|
|
return n2.subscribe(function() {
|
|
var e3 = t3(n2.getState());
|
|
r2 !== e3 && o2(e3);
|
|
});
|
|
}, []), r2;
|
|
}
|
|
function Dt() {
|
|
var t3, n2 = yt(void 0), e2 = n2[0], r2 = n2[1], o2 = It(), i2 = o2.search, u2 = At(), s2 = Ht().dispatch, a2 = jt(function(t4) {
|
|
return t4.search;
|
|
});
|
|
gt(function() {
|
|
e2 && e2.setProps({ keyword: null == a2 ? void 0 : a2.keyword });
|
|
}, [a2, e2]), gt(function() {
|
|
r2(i2.server ? new at({ keyword: i2.keyword, url: i2.server.url, body: i2.server.body }) : new nt({ keyword: i2.keyword, columns: o2.header && o2.header.columns, ignoreHiddenColumns: i2.ignoreHiddenColumns || void 0 === i2.ignoreHiddenColumns, selector: i2.selector })), i2.keyword && s2(Ot(i2.keyword));
|
|
}, [i2]), gt(function() {
|
|
if (e2) return o2.pipeline.register(e2), function() {
|
|
return o2.pipeline.unregister(e2);
|
|
};
|
|
}, [o2, e2]);
|
|
var l2, c2, f2, p2 = function(t4, n3) {
|
|
return lt = 8, wt(function() {
|
|
return t4;
|
|
}, n3);
|
|
}((l2 = function(t4) {
|
|
t4.target instanceof HTMLInputElement && s2(Ot(t4.target.value));
|
|
}, c2 = e2 instanceof at ? i2.debounceTimeout || 250 : 0, function() {
|
|
var t4 = arguments;
|
|
return new Promise(function(n3) {
|
|
f2 && clearTimeout(f2), f2 = setTimeout(function() {
|
|
return n3(l2.apply(void 0, [].slice.call(t4)));
|
|
}, c2);
|
|
});
|
|
}), [i2, e2]);
|
|
return w("div", { className: et(rt("search", null == (t3 = o2.className) ? void 0 : t3.search)) }, w("input", { type: "search", placeholder: u2("search.placeholder"), "aria-label": u2("search.placeholder"), onInput: p2, className: rt(et("input"), et("search", "input")), defaultValue: (null == a2 ? void 0 : a2.keyword) || "" }));
|
|
}
|
|
var Mt = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
r(e2, t3);
|
|
var o2 = e2.prototype;
|
|
return o2.validateProps = function() {
|
|
if (isNaN(Number(this.props.limit)) || isNaN(Number(this.props.page))) throw Error("Invalid parameters passed");
|
|
}, o2._process = function(t4) {
|
|
var n2 = this.props.page;
|
|
return new J(t4.rows.slice(n2 * this.props.limit, (n2 + 1) * this.props.limit));
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Limit;
|
|
} }]), e2;
|
|
}(tt);
|
|
var Ft = /* @__PURE__ */ function(t3) {
|
|
function o2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(o2, t3), o2.prototype._process = function(t4) {
|
|
var n2 = {};
|
|
return this.props.url && (n2.url = this.props.url(t4.url, this.props.page, this.props.limit)), this.props.body && (n2.body = this.props.body(t4.body, this.props.page, this.props.limit)), e({}, t4, n2);
|
|
}, n(o2, [{ key: "type", get: function() {
|
|
return K.ServerLimit;
|
|
} }]), o2;
|
|
}(tt);
|
|
function Rt() {
|
|
var t3 = It(), n2 = t3.pagination, e2 = n2.server, r2 = n2.summary, o2 = void 0 === r2 || r2, i2 = n2.nextButton, u2 = void 0 === i2 || i2, s2 = n2.prevButton, a2 = void 0 === s2 || s2, l2 = n2.buttonsCount, c2 = void 0 === l2 ? 3 : l2, f2 = n2.limit, p2 = void 0 === f2 ? 10 : f2, d2 = n2.page, h6 = void 0 === d2 ? 0 : d2, _2 = n2.resetPageOnUpdate, m2 = void 0 === _2 || _2, v2 = bt(null), y2 = yt(h6), g2 = y2[0], b2 = y2[1], x2 = yt(0), k = x2[0], N2 = x2[1], P2 = At();
|
|
gt(function() {
|
|
return e2 ? (v2.current = new Ft({ limit: p2, page: g2, url: e2.url, body: e2.body }), t3.pipeline.register(v2.current)) : (v2.current = new Mt({ limit: p2, page: g2 }), t3.pipeline.register(v2.current)), v2.current instanceof Ft ? t3.pipeline.on("afterProcess", function(t4) {
|
|
return N2(t4.length);
|
|
}) : v2.current instanceof Mt && v2.current.on("beforeProcess", function(t4) {
|
|
return N2(t4.length);
|
|
}), t3.pipeline.on("updated", C2), t3.pipeline.on("error", function() {
|
|
N2(0), b2(0);
|
|
}), function() {
|
|
t3.pipeline.unregister(v2.current), t3.pipeline.off("updated", C2);
|
|
};
|
|
}, []);
|
|
var C2 = function(t4) {
|
|
m2 && t4 !== v2.current && (b2(0), 0 !== v2.current.props.page && v2.current.setProps({ page: 0 }));
|
|
}, E2 = function() {
|
|
return Math.ceil(k / p2);
|
|
}, I2 = function(t4) {
|
|
if (t4 >= E2() || t4 < 0 || t4 === g2) return null;
|
|
b2(t4), v2.current.setProps({ page: t4 });
|
|
};
|
|
return w("div", { className: rt(et("pagination"), t3.className.pagination) }, w(S, null, o2 && k > 0 && w("div", { role: "status", "aria-live": "polite", className: rt(et("summary"), t3.className.paginationSummary), title: P2("pagination.navigate", g2 + 1, E2()) }, P2("pagination.showing"), " ", w("b", null, P2("" + (g2 * p2 + 1))), " ", P2("pagination.to"), " ", w("b", null, P2("" + Math.min((g2 + 1) * p2, k))), " ", P2("pagination.of"), " ", w("b", null, P2("" + k)), " ", P2("pagination.results"))), w("div", { className: et("pages") }, a2 && w("button", { tabIndex: 0, role: "button", disabled: 0 === g2, onClick: function() {
|
|
return I2(g2 - 1);
|
|
}, title: P2("pagination.previous"), "aria-label": P2("pagination.previous"), className: rt(t3.className.paginationButton, t3.className.paginationButtonPrev) }, P2("pagination.previous")), function() {
|
|
if (c2 <= 0) return null;
|
|
var n3 = Math.min(E2(), c2), e3 = Math.min(g2, Math.floor(n3 / 2));
|
|
return g2 + Math.floor(n3 / 2) >= E2() && (e3 = n3 - (E2() - g2)), w(S, null, E2() > n3 && g2 - e3 > 0 && w(S, null, w("button", { tabIndex: 0, role: "button", onClick: function() {
|
|
return I2(0);
|
|
}, title: P2("pagination.firstPage"), "aria-label": P2("pagination.firstPage"), className: t3.className.paginationButton }, P2("1")), w("button", { tabIndex: -1, className: rt(et("spread"), t3.className.paginationButton) }, "...")), Array.from(Array(n3).keys()).map(function(t4) {
|
|
return g2 + (t4 - e3);
|
|
}).map(function(n4) {
|
|
return w("button", { tabIndex: 0, role: "button", onClick: function() {
|
|
return I2(n4);
|
|
}, className: rt(g2 === n4 ? rt(et("currentPage"), t3.className.paginationButtonCurrent) : null, t3.className.paginationButton), title: P2("pagination.page", n4 + 1), "aria-label": P2("pagination.page", n4 + 1) }, P2("" + (n4 + 1)));
|
|
}), E2() > n3 && E2() > g2 + e3 + 1 && w(S, null, w("button", { tabIndex: -1, className: rt(et("spread"), t3.className.paginationButton) }, "..."), w("button", { tabIndex: 0, role: "button", onClick: function() {
|
|
return I2(E2() - 1);
|
|
}, title: P2("pagination.page", E2()), "aria-label": P2("pagination.page", E2()), className: t3.className.paginationButton }, P2("" + E2()))));
|
|
}(), u2 && w("button", { tabIndex: 0, role: "button", disabled: E2() === g2 + 1 || 0 === E2(), onClick: function() {
|
|
return I2(g2 + 1);
|
|
}, title: P2("pagination.next"), "aria-label": P2("pagination.next"), className: rt(t3.className.paginationButton, t3.className.paginationButtonNext) }, P2("pagination.next"))));
|
|
}
|
|
function Ut(t3, n2) {
|
|
return "string" == typeof t3 ? t3.indexOf("%") > -1 ? n2 / 100 * parseInt(t3, 10) : parseInt(t3, 10) : t3;
|
|
}
|
|
function Wt(t3) {
|
|
return t3 ? Math.floor(t3) + "px" : "";
|
|
}
|
|
function Bt(t3) {
|
|
var n2 = t3.tableRef.cloneNode(true);
|
|
return n2.style.position = "absolute", n2.style.width = "100%", n2.style.zIndex = "-2147483640", n2.style.visibility = "hidden", w("div", { ref: function(t4) {
|
|
t4 && t4.appendChild(n2);
|
|
} });
|
|
}
|
|
function qt(t3) {
|
|
if (!t3) return "";
|
|
var n2 = t3.split(" ");
|
|
return 1 === n2.length && /([a-z][A-Z])+/g.test(t3) ? t3 : n2.map(function(t4, n3) {
|
|
return 0 == n3 ? t4.toLowerCase() : t4.charAt(0).toUpperCase() + t4.slice(1).toLowerCase();
|
|
}).join("");
|
|
}
|
|
var zt;
|
|
var Vt = new (/* @__PURE__ */ function() {
|
|
function t3() {
|
|
}
|
|
var n2 = t3.prototype;
|
|
return n2.format = function(t4, n3) {
|
|
return "[Grid.js] [" + n3.toUpperCase() + "]: " + t4;
|
|
}, n2.error = function(t4, n3) {
|
|
void 0 === n3 && (n3 = false);
|
|
var e2 = this.format(t4, "error");
|
|
if (n3) throw Error(e2);
|
|
console.error(e2);
|
|
}, n2.warn = function(t4) {
|
|
console.warn(this.format(t4, "warn"));
|
|
}, n2.info = function(t4) {
|
|
console.info(this.format(t4, "info"));
|
|
}, t3;
|
|
}())();
|
|
!function(t3) {
|
|
t3[t3.Header = 0] = "Header", t3[t3.Footer = 1] = "Footer", t3[t3.Cell = 2] = "Cell";
|
|
}(zt || (zt = {}));
|
|
var $t = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
this.plugins = void 0, this.plugins = [];
|
|
}
|
|
var n2 = t3.prototype;
|
|
return n2.get = function(t4) {
|
|
return this.plugins.find(function(n3) {
|
|
return n3.id === t4;
|
|
});
|
|
}, n2.add = function(t4) {
|
|
return t4.id ? this.get(t4.id) ? (Vt.error("Duplicate plugin ID: " + t4.id), this) : (this.plugins.push(t4), this) : (Vt.error("Plugin ID cannot be empty"), this);
|
|
}, n2.remove = function(t4) {
|
|
var n3 = this.get(t4);
|
|
return n3 && this.plugins.splice(this.plugins.indexOf(n3), 1), this;
|
|
}, n2.list = function(t4) {
|
|
var n3;
|
|
return n3 = null != t4 || null != t4 ? this.plugins.filter(function(n4) {
|
|
return n4.position === t4;
|
|
}) : this.plugins, n3.sort(function(t5, n4) {
|
|
return t5.order && n4.order ? t5.order - n4.order : 1;
|
|
});
|
|
}, t3;
|
|
}();
|
|
function Gt(t3) {
|
|
var n2 = this, r2 = It();
|
|
if (t3.pluginId) {
|
|
var o2 = r2.plugin.get(t3.pluginId);
|
|
return o2 ? w(S, {}, w(o2.component, e({ plugin: o2 }, t3.props))) : null;
|
|
}
|
|
return void 0 !== t3.position ? w(S, {}, r2.plugin.list(t3.position).map(function(t4) {
|
|
return w(t4.component, e({ plugin: t4 }, n2.props.props));
|
|
})) : null;
|
|
}
|
|
var Kt = /* @__PURE__ */ function(t3) {
|
|
function o2() {
|
|
var n2;
|
|
return (n2 = t3.call(this) || this)._columns = void 0, n2._columns = [], n2;
|
|
}
|
|
r(o2, t3);
|
|
var i2 = o2.prototype;
|
|
return i2.adjustWidth = function(t4, n2, r2) {
|
|
var i3 = t4.container, u2 = t4.autoWidth;
|
|
if (!i3) return this;
|
|
var a2 = i3.clientWidth, l2 = {};
|
|
n2.current && u2 && (q(w(Bt, { tableRef: n2.current }), r2.current), l2 = function(t5) {
|
|
var n3 = t5.querySelector("table");
|
|
if (!n3) return {};
|
|
var r3 = n3.className, o3 = n3.style.cssText;
|
|
n3.className = r3 + " " + et("shadowTable"), n3.style.tableLayout = "auto", n3.style.width = "auto", n3.style.padding = "0", n3.style.margin = "0", n3.style.border = "none", n3.style.outline = "none";
|
|
var i4 = Array.from(n3.parentNode.querySelectorAll("thead th")).reduce(function(t6, n4) {
|
|
var r4;
|
|
return n4.style.width = n4.clientWidth + "px", e(((r4 = {})[n4.getAttribute("data-column-id")] = { minWidth: n4.clientWidth }, r4), t6);
|
|
}, {});
|
|
return n3.className = r3, n3.style.cssText = o3, n3.style.tableLayout = "auto", Array.from(n3.parentNode.querySelectorAll("thead th")).reduce(function(t6, n4) {
|
|
return t6[n4.getAttribute("data-column-id")].width = n4.clientWidth, t6;
|
|
}, i4);
|
|
}(r2.current));
|
|
for (var c2, f2 = s(o2.tabularFormat(this.columns).reduce(function(t5, n3) {
|
|
return t5.concat(n3);
|
|
}, [])); !(c2 = f2()).done; ) {
|
|
var p2 = c2.value;
|
|
p2.columns && p2.columns.length > 0 || (!p2.width && u2 ? p2.id in l2 && (p2.width = Wt(l2[p2.id].width), p2.minWidth = Wt(l2[p2.id].minWidth)) : p2.width = Wt(Ut(p2.width, a2)));
|
|
}
|
|
return n2.current && u2 && q(null, r2.current), this;
|
|
}, i2.setSort = function(t4, n2) {
|
|
for (var r2, o3 = s(n2 || this.columns || []); !(r2 = o3()).done; ) {
|
|
var i3 = r2.value;
|
|
i3.columns && i3.columns.length > 0 ? i3.sort = void 0 : void 0 === i3.sort && t4 ? i3.sort = {} : i3.sort ? "object" == typeof i3.sort && (i3.sort = e({}, i3.sort)) : i3.sort = void 0, i3.columns && this.setSort(t4, i3.columns);
|
|
}
|
|
}, i2.setResizable = function(t4, n2) {
|
|
for (var e2, r2 = s(n2 || this.columns || []); !(e2 = r2()).done; ) {
|
|
var o3 = e2.value;
|
|
void 0 === o3.resizable && (o3.resizable = t4), o3.columns && this.setResizable(t4, o3.columns);
|
|
}
|
|
}, i2.setID = function(t4) {
|
|
for (var n2, e2 = s(t4 || this.columns || []); !(n2 = e2()).done; ) {
|
|
var r2 = n2.value;
|
|
r2.id || "string" != typeof r2.name || (r2.id = qt(r2.name)), r2.id || Vt.error('Could not find a valid ID for one of the columns. Make sure a valid "id" is set for all columns.'), r2.columns && this.setID(r2.columns);
|
|
}
|
|
}, i2.populatePlugins = function(t4, n2) {
|
|
for (var r2, o3 = s(n2); !(r2 = o3()).done; ) {
|
|
var i3 = r2.value;
|
|
void 0 !== i3.plugin && t4.add(e({ id: i3.id }, i3.plugin, { position: zt.Cell }));
|
|
}
|
|
}, o2.fromColumns = function(t4) {
|
|
for (var n2, e2 = new o2(), r2 = s(t4); !(n2 = r2()).done; ) {
|
|
var i3 = n2.value;
|
|
if ("string" == typeof i3 || p(i3)) e2.columns.push({ name: i3 });
|
|
else if ("object" == typeof i3) {
|
|
var u2 = i3;
|
|
u2.columns && (u2.columns = o2.fromColumns(u2.columns).columns), "object" == typeof u2.plugin && void 0 === u2.data && (u2.data = null), e2.columns.push(i3);
|
|
}
|
|
}
|
|
return e2;
|
|
}, o2.createFromConfig = function(t4) {
|
|
var n2 = new o2();
|
|
return t4.from ? n2.columns = o2.fromHTMLTable(t4.from).columns : t4.columns ? n2.columns = o2.fromColumns(t4.columns).columns : !t4.data || "object" != typeof t4.data[0] || t4.data[0] instanceof Array || (n2.columns = Object.keys(t4.data[0]).map(function(t5) {
|
|
return { name: t5 };
|
|
})), n2.columns.length ? (n2.setID(), n2.setSort(t4.sort), n2.setResizable(t4.resizable), n2.populatePlugins(t4.plugin, n2.columns), n2) : null;
|
|
}, o2.fromHTMLTable = function(t4) {
|
|
for (var n2, e2 = new o2(), r2 = s(t4.querySelector("thead").querySelectorAll("th")); !(n2 = r2()).done; ) {
|
|
var i3 = n2.value;
|
|
e2.columns.push({ name: i3.innerHTML, width: i3.width });
|
|
}
|
|
return e2;
|
|
}, o2.tabularFormat = function(t4) {
|
|
var n2 = [], e2 = t4 || [], r2 = [];
|
|
if (e2 && e2.length) {
|
|
n2.push(e2);
|
|
for (var o3, i3 = s(e2); !(o3 = i3()).done; ) {
|
|
var u2 = o3.value;
|
|
u2.columns && u2.columns.length && (r2 = r2.concat(u2.columns));
|
|
}
|
|
r2.length && (n2 = n2.concat(this.tabularFormat(r2)));
|
|
}
|
|
return n2;
|
|
}, o2.leafColumns = function(t4) {
|
|
var n2 = [], e2 = t4 || [];
|
|
if (e2 && e2.length) for (var r2, o3 = s(e2); !(r2 = o3()).done; ) {
|
|
var i3 = r2.value;
|
|
i3.columns && 0 !== i3.columns.length || n2.push(i3), i3.columns && (n2 = n2.concat(this.leafColumns(i3.columns)));
|
|
}
|
|
return n2;
|
|
}, o2.maximumDepth = function(t4) {
|
|
return this.tabularFormat([t4]).length - 1;
|
|
}, n(o2, [{ key: "columns", get: function() {
|
|
return this._columns;
|
|
}, set: function(t4) {
|
|
this._columns = t4;
|
|
} }, { key: "visibleColumns", get: function() {
|
|
return this._columns.filter(function(t4) {
|
|
return !t4.hidden;
|
|
});
|
|
} }]), o2;
|
|
}(V);
|
|
var Xt = function() {
|
|
};
|
|
var Zt = /* @__PURE__ */ function(t3) {
|
|
function n2(n3) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this).data = void 0, e3.set(n3), e3;
|
|
}
|
|
r(n2, t3);
|
|
var e2 = n2.prototype;
|
|
return e2.get = function() {
|
|
try {
|
|
return Promise.resolve(this.data()).then(function(t4) {
|
|
return { data: t4, total: t4.length };
|
|
});
|
|
} catch (t4) {
|
|
return Promise.reject(t4);
|
|
}
|
|
}, e2.set = function(t4) {
|
|
return t4 instanceof Array ? this.data = function() {
|
|
return t4;
|
|
} : t4 instanceof Function && (this.data = t4), this;
|
|
}, n2;
|
|
}(Xt);
|
|
var Jt = /* @__PURE__ */ function(t3) {
|
|
function n2(n3) {
|
|
var e2;
|
|
return (e2 = t3.call(this) || this).options = void 0, e2.options = n3, e2;
|
|
}
|
|
r(n2, t3);
|
|
var o2 = n2.prototype;
|
|
return o2.handler = function(t4) {
|
|
return "function" == typeof this.options.handle ? this.options.handle(t4) : t4.ok ? t4.json() : (Vt.error("Could not fetch data: " + t4.status + " - " + t4.statusText, true), null);
|
|
}, o2.get = function(t4) {
|
|
var n3 = e({}, this.options, t4);
|
|
return "function" == typeof n3.data ? n3.data(n3) : fetch(n3.url, n3).then(this.handler.bind(this)).then(function(t5) {
|
|
return { data: n3.then(t5), total: "function" == typeof n3.total ? n3.total(t5) : void 0 };
|
|
});
|
|
}, n2;
|
|
}(Xt);
|
|
var Qt = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
}
|
|
return t3.createFromConfig = function(t4) {
|
|
var n2 = null;
|
|
return t4.data && (n2 = new Zt(t4.data)), t4.from && (n2 = new Zt(this.tableElementToArray(t4.from)), t4.from.style.display = "none"), t4.server && (n2 = new Jt(t4.server)), n2 || Vt.error("Could not determine the storage type", true), n2;
|
|
}, t3.tableElementToArray = function(t4) {
|
|
for (var n2, e2, r2 = [], o2 = s(t4.querySelector("tbody").querySelectorAll("tr")); !(n2 = o2()).done; ) {
|
|
for (var i2, u2 = [], a2 = s(n2.value.querySelectorAll("td")); !(i2 = a2()).done; ) {
|
|
var l2 = i2.value;
|
|
1 === l2.childNodes.length && l2.childNodes[0].nodeType === Node.TEXT_NODE ? u2.push((e2 = l2.innerHTML, new DOMParser().parseFromString(e2, "text/html").documentElement.textContent)) : u2.push(G(l2.innerHTML));
|
|
}
|
|
r2.push(u2);
|
|
}
|
|
return r2;
|
|
}, t3;
|
|
}();
|
|
var Yt = "undefined" != typeof Symbol ? Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator")) : "@@iterator";
|
|
function tn(t3, n2, e2) {
|
|
if (!t3.s) {
|
|
if (e2 instanceof nn) {
|
|
if (!e2.s) return void (e2.o = tn.bind(null, t3, n2));
|
|
1 & n2 && (n2 = e2.s), e2 = e2.v;
|
|
}
|
|
if (e2 && e2.then) return void e2.then(tn.bind(null, t3, n2), tn.bind(null, t3, 2));
|
|
t3.s = n2, t3.v = e2;
|
|
var r2 = t3.o;
|
|
r2 && r2(t3);
|
|
}
|
|
}
|
|
var nn = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
}
|
|
return t3.prototype.then = function(n2, e2) {
|
|
var r2 = new t3(), o2 = this.s;
|
|
if (o2) {
|
|
var i2 = 1 & o2 ? n2 : e2;
|
|
if (i2) {
|
|
try {
|
|
tn(r2, 1, i2(this.v));
|
|
} catch (t4) {
|
|
tn(r2, 2, t4);
|
|
}
|
|
return r2;
|
|
}
|
|
return this;
|
|
}
|
|
return this.o = function(t4) {
|
|
try {
|
|
var o3 = t4.v;
|
|
1 & t4.s ? tn(r2, 1, n2 ? n2(o3) : o3) : e2 ? tn(r2, 1, e2(o3)) : tn(r2, 2, o3);
|
|
} catch (t5) {
|
|
tn(r2, 2, t5);
|
|
}
|
|
}, r2;
|
|
}, t3;
|
|
}();
|
|
function en(t3) {
|
|
return t3 instanceof nn && 1 & t3.s;
|
|
}
|
|
var rn = /* @__PURE__ */ function(t3) {
|
|
function e2(n2) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this)._steps = /* @__PURE__ */ new Map(), e3.cache = /* @__PURE__ */ new Map(), e3.lastProcessorIndexUpdated = -1, n2 && n2.forEach(function(t4) {
|
|
return e3.register(t4);
|
|
}), e3;
|
|
}
|
|
r(e2, t3);
|
|
var o2 = e2.prototype;
|
|
return o2.clearCache = function() {
|
|
this.cache = /* @__PURE__ */ new Map(), this.lastProcessorIndexUpdated = -1;
|
|
}, o2.register = function(t4, n2) {
|
|
if (void 0 === n2 && (n2 = null), !t4) throw Error("Processor is not defined");
|
|
if (null === t4.type) throw Error("Processor type is not defined");
|
|
if (this.findProcessorIndexByID(t4.id) > -1) throw Error("Processor ID " + t4.id + " is already defined");
|
|
return t4.on("propsUpdated", this.processorPropsUpdated.bind(this)), this.addProcessorByPriority(t4, n2), this.afterRegistered(t4), t4;
|
|
}, o2.tryRegister = function(t4, n2) {
|
|
void 0 === n2 && (n2 = null);
|
|
try {
|
|
return this.register(t4, n2);
|
|
} catch (t5) {
|
|
}
|
|
}, o2.unregister = function(t4) {
|
|
if (t4 && -1 !== this.findProcessorIndexByID(t4.id)) {
|
|
var n2 = this._steps.get(t4.type);
|
|
n2 && n2.length && (this._steps.set(t4.type, n2.filter(function(n3) {
|
|
return n3 != t4;
|
|
})), this.emit("updated", t4));
|
|
}
|
|
}, o2.addProcessorByPriority = function(t4, n2) {
|
|
var e3 = this._steps.get(t4.type);
|
|
if (!e3) {
|
|
var r2 = [];
|
|
this._steps.set(t4.type, r2), e3 = r2;
|
|
}
|
|
if (null === n2 || n2 < 0) e3.push(t4);
|
|
else if (e3[n2]) {
|
|
var o3 = e3.slice(0, n2 - 1), i2 = e3.slice(n2 + 1);
|
|
this._steps.set(t4.type, o3.concat(t4).concat(i2));
|
|
} else e3[n2] = t4;
|
|
}, o2.getStepsByType = function(t4) {
|
|
return this.steps.filter(function(n2) {
|
|
return n2.type === t4;
|
|
});
|
|
}, o2.getSortedProcessorTypes = function() {
|
|
return Object.keys(K).filter(function(t4) {
|
|
return !isNaN(Number(t4));
|
|
}).map(function(t4) {
|
|
return Number(t4);
|
|
});
|
|
}, o2.process = function(t4) {
|
|
try {
|
|
var n2 = function(t5) {
|
|
return e3.lastProcessorIndexUpdated = o3.length, e3.emit("afterProcess", i2), i2;
|
|
}, e3 = this, r2 = e3.lastProcessorIndexUpdated, o3 = e3.steps, i2 = t4, u2 = function(t5, n3) {
|
|
try {
|
|
var u3 = function(t6, n4, e4) {
|
|
if ("function" == typeof t6[Yt]) {
|
|
var r3, o4, i3, u4 = t6[Yt]();
|
|
if (function t7(e5) {
|
|
try {
|
|
for (; !(r3 = u4.next()).done; ) if ((e5 = n4(r3.value)) && e5.then) {
|
|
if (!en(e5)) return void e5.then(t7, i3 || (i3 = tn.bind(null, o4 = new nn(), 2)));
|
|
e5 = e5.v;
|
|
}
|
|
o4 ? tn(o4, 1, e5) : o4 = e5;
|
|
} catch (t8) {
|
|
tn(o4 || (o4 = new nn()), 2, t8);
|
|
}
|
|
}(), u4.return) {
|
|
var s2 = function(t7) {
|
|
try {
|
|
r3.done || u4.return();
|
|
} catch (t8) {
|
|
}
|
|
return t7;
|
|
};
|
|
if (o4 && o4.then) return o4.then(s2, function(t7) {
|
|
throw s2(t7);
|
|
});
|
|
s2();
|
|
}
|
|
return o4;
|
|
}
|
|
if (!("length" in t6)) throw new TypeError("Object is not iterable");
|
|
for (var a2 = [], l2 = 0; l2 < t6.length; l2++) a2.push(t6[l2]);
|
|
return function(t7, n5, e5) {
|
|
var r4, o5, i4 = -1;
|
|
return function e6(u5) {
|
|
try {
|
|
for (; ++i4 < t7.length; ) if ((u5 = n5(i4)) && u5.then) {
|
|
if (!en(u5)) return void u5.then(e6, o5 || (o5 = tn.bind(null, r4 = new nn(), 2)));
|
|
u5 = u5.v;
|
|
}
|
|
r4 ? tn(r4, 1, u5) : r4 = u5;
|
|
} catch (t8) {
|
|
tn(r4 || (r4 = new nn()), 2, t8);
|
|
}
|
|
}(), r4;
|
|
}(a2, function(t7) {
|
|
return n4(a2[t7]);
|
|
});
|
|
}(o3, function(t6) {
|
|
var n4 = e3.findProcessorIndexByID(t6.id), o4 = function() {
|
|
if (n4 >= r2) return Promise.resolve(t6.process(i2)).then(function(n5) {
|
|
e3.cache.set(t6.id, i2 = n5);
|
|
});
|
|
i2 = e3.cache.get(t6.id);
|
|
}();
|
|
if (o4 && o4.then) return o4.then(function() {
|
|
});
|
|
});
|
|
} catch (t6) {
|
|
return n3(t6);
|
|
}
|
|
return u3 && u3.then ? u3.then(void 0, n3) : u3;
|
|
}(0, function(t5) {
|
|
throw Vt.error(t5), e3.emit("error", i2), t5;
|
|
});
|
|
return Promise.resolve(u2 && u2.then ? u2.then(n2) : n2());
|
|
} catch (t5) {
|
|
return Promise.reject(t5);
|
|
}
|
|
}, o2.findProcessorIndexByID = function(t4) {
|
|
return this.steps.findIndex(function(n2) {
|
|
return n2.id == t4;
|
|
});
|
|
}, o2.setLastProcessorIndex = function(t4) {
|
|
var n2 = this.findProcessorIndexByID(t4.id);
|
|
this.lastProcessorIndexUpdated > n2 && (this.lastProcessorIndexUpdated = n2);
|
|
}, o2.processorPropsUpdated = function(t4) {
|
|
this.setLastProcessorIndex(t4), this.emit("propsUpdated"), this.emit("updated", t4);
|
|
}, o2.afterRegistered = function(t4) {
|
|
this.setLastProcessorIndex(t4), this.emit("afterRegister"), this.emit("updated", t4);
|
|
}, n(e2, [{ key: "steps", get: function() {
|
|
for (var t4, n2 = [], e3 = s(this.getSortedProcessorTypes()); !(t4 = e3()).done; ) {
|
|
var r2 = this._steps.get(t4.value);
|
|
r2 && r2.length && (n2 = n2.concat(r2));
|
|
}
|
|
return n2.filter(function(t5) {
|
|
return t5;
|
|
});
|
|
} }]), e2;
|
|
}(Q);
|
|
var on = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(e2, t3), e2.prototype._process = function(t4) {
|
|
try {
|
|
return Promise.resolve(this.props.storage.get(t4));
|
|
} catch (t5) {
|
|
return Promise.reject(t5);
|
|
}
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Extractor;
|
|
} }]), e2;
|
|
}(tt);
|
|
var un = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(e2, t3), e2.prototype._process = function(t4) {
|
|
var n2 = J.fromArray(t4.data);
|
|
return n2.length = t4.total, n2;
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Transformer;
|
|
} }]), e2;
|
|
}(tt);
|
|
var sn = /* @__PURE__ */ function(t3) {
|
|
function o2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(o2, t3), o2.prototype._process = function() {
|
|
return Object.entries(this.props.serverStorageOptions).filter(function(t4) {
|
|
return "function" != typeof t4[1];
|
|
}).reduce(function(t4, n2) {
|
|
var r2;
|
|
return e({}, t4, ((r2 = {})[n2[0]] = n2[1], r2));
|
|
}, {});
|
|
}, n(o2, [{ key: "type", get: function() {
|
|
return K.Initiator;
|
|
} }]), o2;
|
|
}(tt);
|
|
var an = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
r(e2, t3);
|
|
var o2 = e2.prototype;
|
|
return o2.castData = function(t4) {
|
|
if (!t4 || !t4.length) return [];
|
|
if (!this.props.header || !this.props.header.columns) return t4;
|
|
var n2 = Kt.leafColumns(this.props.header.columns);
|
|
return t4[0] instanceof Array ? t4.map(function(t5) {
|
|
var e3 = 0;
|
|
return n2.map(function(n3, r2) {
|
|
return void 0 !== n3.data ? (e3++, "function" == typeof n3.data ? n3.data(t5) : n3.data) : t5[r2 - e3];
|
|
});
|
|
}) : "object" != typeof t4[0] || t4[0] instanceof Array ? [] : t4.map(function(t5) {
|
|
return n2.map(function(n3, e3) {
|
|
return void 0 !== n3.data ? "function" == typeof n3.data ? n3.data(t5) : n3.data : n3.id ? t5[n3.id] : (Vt.error("Could not find the correct cell for column at position " + e3 + ".\n Make sure either 'id' or 'selector' is defined for all columns."), null);
|
|
});
|
|
});
|
|
}, o2._process = function(t4) {
|
|
return { data: this.castData(t4.data), total: t4.total };
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Transformer;
|
|
} }]), e2;
|
|
}(tt);
|
|
var ln = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
}
|
|
return t3.createFromConfig = function(t4) {
|
|
var n2 = new rn();
|
|
return t4.storage instanceof Jt && n2.register(new sn({ serverStorageOptions: t4.server })), n2.register(new on({ storage: t4.storage })), n2.register(new an({ header: t4.header })), n2.register(new un()), n2;
|
|
}, t3;
|
|
}();
|
|
var cn = function(t3) {
|
|
var n2 = this;
|
|
this.state = void 0, this.listeners = [], this.isDispatching = false, this.getState = function() {
|
|
return n2.state;
|
|
}, this.getListeners = function() {
|
|
return n2.listeners;
|
|
}, this.dispatch = function(t4) {
|
|
if ("function" != typeof t4) throw new Error("Reducer is not a function");
|
|
if (n2.isDispatching) throw new Error("Reducers may not dispatch actions");
|
|
n2.isDispatching = true;
|
|
var e2 = n2.state;
|
|
try {
|
|
n2.state = t4(n2.state);
|
|
} finally {
|
|
n2.isDispatching = false;
|
|
}
|
|
for (var r2, o2 = s(n2.listeners); !(r2 = o2()).done; ) (0, r2.value)(n2.state, e2);
|
|
return n2.state;
|
|
}, this.subscribe = function(t4) {
|
|
if ("function" != typeof t4) throw new Error("Listener is not a function");
|
|
return n2.listeners = [].concat(n2.listeners, [t4]), function() {
|
|
return n2.listeners = n2.listeners.filter(function(n3) {
|
|
return n3 !== t4;
|
|
});
|
|
};
|
|
}, this.state = t3;
|
|
};
|
|
var fn = function(t3, n2) {
|
|
var e2 = { __c: n2 = "__cC" + _++, __: null, Consumer: function(t4, n3) {
|
|
return t4.children(n3);
|
|
}, Provider: function(t4) {
|
|
var e3, r2;
|
|
return this.getChildContext || (e3 = [], (r2 = {})[n2] = this, this.getChildContext = function() {
|
|
return r2;
|
|
}, this.shouldComponentUpdate = function(t5) {
|
|
this.props.value !== t5.value && e3.some(E);
|
|
}, this.sub = function(t5) {
|
|
e3.push(t5);
|
|
var n3 = t5.componentWillUnmount;
|
|
t5.componentWillUnmount = function() {
|
|
e3.splice(e3.indexOf(t5), 1), n3 && n3.call(t5);
|
|
};
|
|
}), t4.children;
|
|
} };
|
|
return e2.Provider.__ = e2.Consumer.contextType = e2;
|
|
}();
|
|
var pn = /* @__PURE__ */ function() {
|
|
function t3() {
|
|
Object.assign(this, t3.defaultConfig());
|
|
}
|
|
var n2 = t3.prototype;
|
|
return n2.assign = function(t4) {
|
|
return Object.assign(this, t4);
|
|
}, n2.update = function(n3) {
|
|
return n3 ? (this.assign(t3.fromPartialConfig(e({}, this, n3))), this) : this;
|
|
}, t3.defaultConfig = function() {
|
|
return { store: new cn({ status: a.Init, header: void 0, data: null }), plugin: new $t(), tableRef: { current: null }, width: "100%", height: "auto", processingThrottleMs: 100, autoWidth: true, style: {}, className: {} };
|
|
}, t3.fromPartialConfig = function(n3) {
|
|
var e2 = new t3().assign(n3);
|
|
return "boolean" == typeof n3.sort && n3.sort && e2.assign({ sort: { multiColumn: true } }), e2.assign({ header: Kt.createFromConfig(e2) }), e2.assign({ storage: Qt.createFromConfig(e2) }), e2.assign({ pipeline: ln.createFromConfig(e2) }), e2.assign({ translator: new Lt(e2.language) }), e2.plugin = new $t(), e2.search && e2.plugin.add({ id: "search", position: zt.Header, component: Dt }), e2.pagination && e2.plugin.add({ id: "pagination", position: zt.Footer, component: Rt }), e2.plugins && e2.plugins.forEach(function(t4) {
|
|
return e2.plugin.add(t4);
|
|
}), e2;
|
|
}, t3;
|
|
}();
|
|
function dn(t3) {
|
|
var n2, r2 = It();
|
|
return w("td", e({ role: t3.role, colSpan: t3.colSpan, "data-column-id": t3.column && t3.column.id, className: rt(et("td"), t3.className, r2.className.td), style: e({}, t3.style, r2.style.td), onClick: function(n3) {
|
|
t3.messageCell || r2.eventEmitter.emit("cellClick", n3, t3.cell, t3.column, t3.row);
|
|
} }, (n2 = t3.column) ? "function" == typeof n2.attributes ? n2.attributes(t3.cell.data, t3.row, t3.column) : n2.attributes : {}), t3.column && "function" == typeof t3.column.formatter ? t3.column.formatter(t3.cell.data, t3.row, t3.column) : t3.column && t3.column.plugin ? w(Gt, { pluginId: t3.column.id, props: { column: t3.column, cell: t3.cell, row: t3.row } }) : t3.cell.data);
|
|
}
|
|
function hn(t3) {
|
|
var n2 = It(), e2 = jt(function(t4) {
|
|
return t4.header;
|
|
});
|
|
return w("tr", { className: rt(et("tr"), n2.className.tr), onClick: function(e3) {
|
|
t3.messageRow || n2.eventEmitter.emit("rowClick", e3, t3.row);
|
|
} }, t3.children ? t3.children : t3.row.cells.map(function(n3, r2) {
|
|
var o2 = function(t4) {
|
|
if (e2) {
|
|
var n4 = Kt.leafColumns(e2.columns);
|
|
if (n4) return n4[t4];
|
|
}
|
|
return null;
|
|
}(r2);
|
|
return o2 && o2.hidden ? null : w(dn, { key: n3.id, cell: n3, row: t3.row, column: o2 });
|
|
}));
|
|
}
|
|
function _n(t3) {
|
|
return w(hn, { messageRow: true }, w(dn, { role: "alert", colSpan: t3.colSpan, messageCell: true, cell: new X(t3.message), className: rt(et("message"), t3.className ? t3.className : null) }));
|
|
}
|
|
function mn() {
|
|
var t3 = It(), n2 = jt(function(t4) {
|
|
return t4.data;
|
|
}), e2 = jt(function(t4) {
|
|
return t4.status;
|
|
}), r2 = jt(function(t4) {
|
|
return t4.header;
|
|
}), o2 = At(), i2 = function() {
|
|
return r2 ? r2.visibleColumns.length : 0;
|
|
};
|
|
return w("tbody", { className: rt(et("tbody"), t3.className.tbody) }, n2 && n2.rows.map(function(t4) {
|
|
return w(hn, { key: t4.id, row: t4 });
|
|
}), e2 === a.Loading && (!n2 || 0 === n2.length) && w(_n, { message: o2("loading"), colSpan: i2(), className: rt(et("loading"), t3.className.loading) }), e2 === a.Rendered && n2 && 0 === n2.length && w(_n, { message: o2("noRecordsFound"), colSpan: i2(), className: rt(et("notfound"), t3.className.notfound) }), e2 === a.Error && w(_n, { message: o2("error"), colSpan: i2(), className: rt(et("error"), t3.className.error) }));
|
|
}
|
|
var vn = /* @__PURE__ */ function(t3) {
|
|
function e2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
r(e2, t3);
|
|
var o2 = e2.prototype;
|
|
return o2.validateProps = function() {
|
|
for (var t4, n2 = s(this.props.columns); !(t4 = n2()).done; ) {
|
|
var e3 = t4.value;
|
|
void 0 === e3.direction && (e3.direction = 1), 1 !== e3.direction && -1 !== e3.direction && Vt.error("Invalid sort direction " + e3.direction);
|
|
}
|
|
}, o2.compare = function(t4, n2) {
|
|
return t4 > n2 ? 1 : t4 < n2 ? -1 : 0;
|
|
}, o2.compareWrapper = function(t4, n2) {
|
|
for (var e3, r2 = 0, o3 = s(this.props.columns); !(e3 = o3()).done; ) {
|
|
var i2 = e3.value;
|
|
if (0 !== r2) break;
|
|
var u2 = t4.cells[i2.index].data, a2 = n2.cells[i2.index].data;
|
|
r2 |= "function" == typeof i2.compare ? i2.compare(u2, a2) * i2.direction : this.compare(u2, a2) * i2.direction;
|
|
}
|
|
return r2;
|
|
}, o2._process = function(t4) {
|
|
var n2 = [].concat(t4.rows);
|
|
n2.sort(this.compareWrapper.bind(this));
|
|
var e3 = new J(n2);
|
|
return e3.length = t4.length, e3;
|
|
}, n(e2, [{ key: "type", get: function() {
|
|
return K.Sort;
|
|
} }]), e2;
|
|
}(tt);
|
|
var yn = function(t3, n2, r2, o2) {
|
|
return function(i2) {
|
|
var u2, s2 = null != (u2 = i2.sort) && u2.columns ? i2.sort.columns.map(function(t4) {
|
|
return e({}, t4);
|
|
}) : [], a2 = s2.length, l2 = s2.find(function(n3) {
|
|
return n3.index === t3;
|
|
}), c2 = false, f2 = false, p2 = false, d2 = false;
|
|
if (void 0 !== l2 ? r2 ? -1 === l2.direction ? p2 = true : d2 = true : 1 === a2 ? d2 = true : a2 > 1 && (f2 = true, c2 = true) : 0 === a2 ? c2 = true : a2 > 0 && !r2 ? (c2 = true, f2 = true) : a2 > 0 && r2 && (c2 = true), f2 && (s2 = []), c2) s2.push({ index: t3, direction: n2, compare: o2 });
|
|
else if (d2) {
|
|
var h6 = s2.indexOf(l2);
|
|
s2[h6].direction = n2;
|
|
} else if (p2) {
|
|
var _2 = s2.indexOf(l2);
|
|
s2.splice(_2, 1);
|
|
}
|
|
return e({}, i2, { sort: { columns: s2 } });
|
|
};
|
|
};
|
|
var gn = function(t3, n2, r2) {
|
|
return function(o2) {
|
|
var i2 = (o2.sort ? [].concat(o2.sort.columns) : []).find(function(n3) {
|
|
return n3.index === t3;
|
|
});
|
|
return e({}, o2, i2 ? yn(t3, 1 === i2.direction ? -1 : 1, n2, r2)(o2) : yn(t3, 1, n2, r2)(o2));
|
|
};
|
|
};
|
|
var bn = /* @__PURE__ */ function(t3) {
|
|
function o2() {
|
|
return t3.apply(this, arguments) || this;
|
|
}
|
|
return r(o2, t3), o2.prototype._process = function(t4) {
|
|
var n2 = {};
|
|
return this.props.url && (n2.url = this.props.url(t4.url, this.props.columns)), this.props.body && (n2.body = this.props.body(t4.body, this.props.columns)), e({}, t4, n2);
|
|
}, n(o2, [{ key: "type", get: function() {
|
|
return K.ServerSort;
|
|
} }]), o2;
|
|
}(tt);
|
|
function wn(t3) {
|
|
var n2 = It(), r2 = Ht().dispatch, o2 = At(), i2 = yt(0), u2 = i2[0], s2 = i2[1], a2 = n2.sort, l2 = jt(function(t4) {
|
|
return t4.sort;
|
|
}), c2 = "object" == typeof (null == a2 ? void 0 : a2.server) ? K.ServerSort : K.Sort, f2 = function() {
|
|
var t4 = n2.pipeline.getStepsByType(c2);
|
|
if (t4.length) return t4[0];
|
|
};
|
|
return gt(function() {
|
|
var t4 = f2() || (c2 === K.ServerSort ? new bn(e({ columns: l2 ? l2.columns : [] }, a2.server)) : new vn({ columns: l2 ? l2.columns : [] }));
|
|
return n2.pipeline.tryRegister(t4), function() {
|
|
return n2.pipeline.unregister(t4);
|
|
};
|
|
}, [n2]), gt(function() {
|
|
if (l2) {
|
|
var n3, e2 = l2.columns.find(function(n4) {
|
|
return n4.index === t3.index;
|
|
});
|
|
e2 ? (0 === u2 && (e2.direction = null != (n3 = t3.direction) ? n3 : 1), s2(e2.direction)) : s2(0);
|
|
}
|
|
}, [l2]), gt(function() {
|
|
var t4 = f2();
|
|
t4 && l2 && t4.setProps({ columns: l2.columns });
|
|
}, [l2]), w("button", { tabIndex: -1, "aria-label": o2("sort.sort" + (1 === u2 ? "Desc" : "Asc")), title: o2("sort.sort" + (1 === u2 ? "Desc" : "Asc")), className: rt(et("sort"), et("sort", /* @__PURE__ */ function(t4) {
|
|
return 1 === t4 ? "asc" : -1 === t4 ? "desc" : "neutral";
|
|
}(u2)), n2.className.sort), onClick: function(n3) {
|
|
n3.preventDefault(), n3.stopPropagation(), r2(gn(t3.index, true === n3.shiftKey && a2.multiColumn, t3.compare));
|
|
} });
|
|
}
|
|
var xn = function(t3, n2) {
|
|
var e2;
|
|
void 0 === n2 && (n2 = 100);
|
|
var r2 = Date.now(), o2 = function() {
|
|
r2 = Date.now(), t3.apply(void 0, [].slice.call(arguments));
|
|
};
|
|
return function() {
|
|
var t4 = [].slice.call(arguments), i2 = Date.now(), u2 = i2 - r2;
|
|
u2 >= n2 ? o2.apply(void 0, t4) : (e2 && clearTimeout(e2), e2 = setTimeout(function() {
|
|
o2.apply(void 0, t4), e2 = null;
|
|
}, n2 - u2));
|
|
};
|
|
};
|
|
function kn(t3) {
|
|
var n2, e2 = function(t4) {
|
|
return t4 instanceof MouseEvent ? Math.floor(t4.pageX) : Math.floor(t4.changedTouches[0].pageX);
|
|
}, r2 = function(r3) {
|
|
r3.stopPropagation();
|
|
var u2 = parseInt(t3.thRef.current.style.width, 10) - e2(r3);
|
|
n2 = xn(function(t4) {
|
|
return o2(t4, u2);
|
|
}, 10), document.addEventListener("mouseup", i2), document.addEventListener("touchend", i2), document.addEventListener("mousemove", n2), document.addEventListener("touchmove", n2);
|
|
}, o2 = function(n3, r3) {
|
|
n3.stopPropagation();
|
|
var o3 = t3.thRef.current;
|
|
r3 + e2(n3) >= parseInt(o3.style.minWidth, 10) && (o3.style.width = r3 + e2(n3) + "px");
|
|
}, i2 = function t4(e3) {
|
|
e3.stopPropagation(), document.removeEventListener("mouseup", t4), document.removeEventListener("mousemove", n2), document.removeEventListener("touchmove", n2), document.removeEventListener("touchend", t4);
|
|
};
|
|
return w("div", { className: rt(et("th"), et("resizable")), onMouseDown: r2, onTouchStart: r2, onClick: function(t4) {
|
|
return t4.stopPropagation();
|
|
} });
|
|
}
|
|
function Sn(t3) {
|
|
var n2 = It(), r2 = bt(null), o2 = yt({}), i2 = o2[0], u2 = o2[1], s2 = Ht().dispatch;
|
|
gt(function() {
|
|
if (n2.fixedHeader && r2.current) {
|
|
var t4 = r2.current.offsetTop;
|
|
"number" == typeof t4 && u2({ top: t4 });
|
|
}
|
|
}, [r2]);
|
|
var a2, l2 = function() {
|
|
return null != t3.column.sort;
|
|
}, c2 = function(e2) {
|
|
e2.stopPropagation(), l2() && s2(gn(t3.index, true === e2.shiftKey && n2.sort.multiColumn, t3.column.sort.compare));
|
|
};
|
|
return w("th", e({ ref: r2, "data-column-id": t3.column && t3.column.id, className: rt(et("th"), l2() ? et("th", "sort") : null, n2.fixedHeader ? et("th", "fixed") : null, n2.className.th), onClick: c2, style: e({}, n2.style.th, { minWidth: t3.column.minWidth, width: t3.column.width }, i2, t3.style), onKeyDown: function(t4) {
|
|
l2() && 13 === t4.which && c2(t4);
|
|
}, rowSpan: t3.rowSpan > 1 ? t3.rowSpan : void 0, colSpan: t3.colSpan > 1 ? t3.colSpan : void 0 }, (a2 = t3.column) ? "function" == typeof a2.attributes ? a2.attributes(null, null, t3.column) : a2.attributes : {}, l2() ? { tabIndex: 0 } : {}), w("div", { className: et("th", "content") }, void 0 !== t3.column.name ? t3.column.name : void 0 !== t3.column.plugin ? w(Gt, { pluginId: t3.column.plugin.id, props: { column: t3.column } }) : null), l2() && w(wn, e({ index: t3.index }, t3.column.sort)), t3.column.resizable && t3.index < n2.header.visibleColumns.length - 1 && w(kn, { column: t3.column, thRef: r2 }));
|
|
}
|
|
function Nn() {
|
|
var t3, n2 = It(), e2 = jt(function(t4) {
|
|
return t4.header;
|
|
});
|
|
return e2 ? w("thead", { key: e2.id, className: rt(et("thead"), n2.className.thead) }, (t3 = Kt.tabularFormat(e2.columns)).map(function(n3, r2) {
|
|
return function(t4, n4, r3) {
|
|
var o2 = Kt.leafColumns(e2.columns);
|
|
return w(hn, null, t4.map(function(t5) {
|
|
return t5.hidden ? null : function(t6, n5, e3, r4) {
|
|
var o3 = function(t7, n6, e4) {
|
|
var r5 = Kt.maximumDepth(t7), o4 = e4 - n6;
|
|
return { rowSpan: Math.floor(o4 - r5 - r5 / o4), colSpan: t7.columns && t7.columns.length || 1 };
|
|
}(t6, n5, r4);
|
|
return w(Sn, { column: t6, index: e3, colSpan: o3.colSpan, rowSpan: o3.rowSpan });
|
|
}(t5, n4, o2.indexOf(t5), r3);
|
|
}));
|
|
}(n3, r2, t3.length);
|
|
})) : null;
|
|
}
|
|
var Pn = function(t3) {
|
|
return function(n2) {
|
|
return e({}, n2, { header: t3 });
|
|
};
|
|
};
|
|
function Cn() {
|
|
var t3 = It(), n2 = bt(null), r2 = Ht().dispatch;
|
|
return gt(function() {
|
|
n2 && r2(/* @__PURE__ */ function(t4) {
|
|
return function(n3) {
|
|
return e({}, n3, { tableRef: t4 });
|
|
};
|
|
}(n2));
|
|
}, [n2]), w("table", { ref: n2, role: "grid", className: rt(et("table"), t3.className.table), style: e({}, t3.style.table, { height: t3.height }) }, w(Nn, null), w(mn, null));
|
|
}
|
|
function En() {
|
|
var t3 = yt(true), n2 = t3[0], r2 = t3[1], o2 = bt(null), i2 = It();
|
|
return gt(function() {
|
|
0 === o2.current.children.length && r2(false);
|
|
}, [o2]), n2 ? w("div", { ref: o2, className: rt(et("head"), i2.className.header), style: e({}, i2.style.header) }, w(Gt, { position: zt.Header })) : null;
|
|
}
|
|
function In() {
|
|
var t3 = bt(null), n2 = yt(true), r2 = n2[0], o2 = n2[1], i2 = It();
|
|
return gt(function() {
|
|
0 === t3.current.children.length && o2(false);
|
|
}, [t3]), r2 ? w("div", { ref: t3, className: rt(et("footer"), i2.className.footer), style: e({}, i2.style.footer) }, w(Gt, { position: zt.Footer })) : null;
|
|
}
|
|
function Tn() {
|
|
var t3 = It(), n2 = Ht().dispatch, r2 = jt(function(t4) {
|
|
return t4.status;
|
|
}), o2 = jt(function(t4) {
|
|
return t4.data;
|
|
}), i2 = jt(function(t4) {
|
|
return t4.tableRef;
|
|
}), u2 = { current: null }, s2 = xn(function() {
|
|
try {
|
|
n2(function(t4) {
|
|
return e({}, t4, { status: a.Loading });
|
|
});
|
|
var r3 = function(r4, o3) {
|
|
try {
|
|
var i3 = Promise.resolve(t3.pipeline.process()).then(function(t4) {
|
|
n2(/* @__PURE__ */ function(t5) {
|
|
return function(n3) {
|
|
return t5 ? e({}, n3, { data: t5, status: a.Loaded }) : n3;
|
|
};
|
|
}(t4)), setTimeout(function() {
|
|
n2(function(t5) {
|
|
return t5.status === a.Loaded ? e({}, t5, { status: a.Rendered }) : t5;
|
|
});
|
|
}, 0);
|
|
});
|
|
} catch (t4) {
|
|
return o3(t4);
|
|
}
|
|
return i3 && i3.then ? i3.then(void 0, o3) : i3;
|
|
}(0, function(t4) {
|
|
Vt.error(t4), n2(function(t5) {
|
|
return e({}, t5, { data: null, status: a.Error });
|
|
});
|
|
});
|
|
return Promise.resolve(r3 && r3.then ? r3.then(function() {
|
|
}) : void 0);
|
|
} catch (t4) {
|
|
return Promise.reject(t4);
|
|
}
|
|
}, t3.processingThrottleMs);
|
|
return gt(function() {
|
|
return n2(Pn(t3.header)), s2(), t3.pipeline.on("updated", s2), function() {
|
|
return t3.pipeline.off("updated", s2);
|
|
};
|
|
}, []), gt(function() {
|
|
t3.header && r2 === a.Loaded && null != o2 && o2.length && n2(Pn(t3.header.adjustWidth(t3, i2, u2)));
|
|
}, [o2, t3, u2]), w("div", { role: "complementary", className: rt("gridjs", et("container"), r2 === a.Loading ? et("loading") : null, t3.className.container), style: e({}, t3.style.container, { width: t3.width }) }, r2 === a.Loading && w("div", { className: et("loading-bar") }), w(En, null), w("div", { className: et("wrapper"), style: { height: t3.height } }, w(Cn, null)), w(In, null), w("div", { ref: u2, id: "gridjs-temp", className: et("temp") }));
|
|
}
|
|
var Ln = /* @__PURE__ */ function(t3) {
|
|
function n2(n3) {
|
|
var e3;
|
|
return (e3 = t3.call(this) || this).config = void 0, e3.plugin = void 0, e3.config = new pn().assign({ instance: i(e3), eventEmitter: i(e3) }).update(n3), e3.plugin = e3.config.plugin, e3;
|
|
}
|
|
r(n2, t3);
|
|
var e2 = n2.prototype;
|
|
return e2.updateConfig = function(t4) {
|
|
return this.config.update(t4), this;
|
|
}, e2.createElement = function() {
|
|
return w(fn.Provider, { value: this.config, children: w(Tn, {}) });
|
|
}, e2.forceRender = function() {
|
|
return this.config && this.config.container || Vt.error("Container is empty. Make sure you call render() before forceRender()", true), this.destroy(), q(this.createElement(), this.config.container), this;
|
|
}, e2.destroy = function() {
|
|
this.config.pipeline.clearCache(), q(null, this.config.container);
|
|
}, e2.render = function(t4) {
|
|
return t4 || Vt.error("Container element cannot be null", true), t4.childNodes.length > 0 ? (Vt.error("The container element " + t4 + " is not empty. Make sure the container is empty and call render() again"), this) : (this.config.container = t4, q(this.createElement(), t4), this);
|
|
}, n2;
|
|
}(Q);
|
|
|
|
// src/gui/statistics.tsx
|
|
var import_path = __toESM(require("path"));
|
|
var import_vhtml2 = __toESM(require_vhtml());
|
|
Chart.register(
|
|
BarElement,
|
|
BarController,
|
|
plugin_legend,
|
|
plugin_title,
|
|
plugin_tooltip,
|
|
plugin_subtitle,
|
|
CategoryScale,
|
|
LinearScale,
|
|
PieController,
|
|
ArcElement
|
|
);
|
|
var StatisticsView = class {
|
|
constructor(containerEl, osrCore) {
|
|
this.containerEl = containerEl;
|
|
this.osrCore = osrCore;
|
|
}
|
|
render() {
|
|
this.containerEl.style.textAlign = "center";
|
|
this.containerEl.innerHTML += /* @__PURE__ */ (0, import_vhtml2.default)("select", { id: "sr-chart-period" }, /* @__PURE__ */ (0, import_vhtml2.default)("option", { value: "month", selected: true }, t("MONTH")), /* @__PURE__ */ (0, import_vhtml2.default)("option", { value: "quarter" }, t("QUARTER")), /* @__PURE__ */ (0, import_vhtml2.default)("option", { value: "year" }, t("YEAR")), /* @__PURE__ */ (0, import_vhtml2.default)("option", { value: "lifetime" }, t("LIFETIME")));
|
|
const cardStats = this.osrCore.cardStats;
|
|
let maxN = cardStats.delayedDays.getMaxValue();
|
|
for (let dueOffset = 0; dueOffset <= maxN; dueOffset++) {
|
|
cardStats.delayedDays.clearCountIfMissing(dueOffset);
|
|
}
|
|
const dueDatesFlashcardsCopy = { 0: 0 };
|
|
for (const [dueOffset, dueCount] of getTypedObjectEntries(cardStats.delayedDays.dict)) {
|
|
if (dueOffset <= 0) {
|
|
dueDatesFlashcardsCopy[0] += dueCount;
|
|
} else {
|
|
dueDatesFlashcardsCopy[dueOffset] = dueCount;
|
|
}
|
|
}
|
|
const scheduledCount = cardStats.youngCount + cardStats.matureCount;
|
|
maxN = Math.max(maxN, 1);
|
|
this.containerEl.innerHTML += /* @__PURE__ */ (0, import_vhtml2.default)("div", null, /* @__PURE__ */ (0, import_vhtml2.default)("canvas", { id: "forecastChart" }), /* @__PURE__ */ (0, import_vhtml2.default)("span", { id: "forecastChartSummary" }), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("canvas", { id: "intervalsChart" }), /* @__PURE__ */ (0, import_vhtml2.default)("span", { id: "intervalsChartSummary" }), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("canvas", { id: "easesChart" }), /* @__PURE__ */ (0, import_vhtml2.default)("span", { id: "easesChartSummary" }), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("canvas", { id: "cardTypesChart" }), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("span", { id: "cardTypesChartSummary" }), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("br", null), /* @__PURE__ */ (0, import_vhtml2.default)("h1", null, "Notes"), /* @__PURE__ */ (0, import_vhtml2.default)("div", { id: "noteStats" }));
|
|
this.forecastChart = createStatsChart(
|
|
"bar",
|
|
"forecastChart",
|
|
t("FORECAST"),
|
|
t("FORECAST_DESC"),
|
|
Object.keys(dueDatesFlashcardsCopy),
|
|
Object.values(dueDatesFlashcardsCopy),
|
|
t("REVIEWS_PER_DAY", { avg: (scheduledCount / maxN).toFixed(1) }),
|
|
t("SCHEDULED"),
|
|
t("DAYS"),
|
|
t("NUMBER_OF_CARDS")
|
|
);
|
|
maxN = cardStats.intervals.getMaxValue();
|
|
for (let interval = 0; interval <= maxN; interval++) {
|
|
cardStats.intervals.clearCountIfMissing(interval);
|
|
}
|
|
const averageInterval = textInterval(
|
|
Math.round(
|
|
cardStats.intervals.getTotalOfValueMultiplyCount() / scheduledCount * 10
|
|
) / 10 || 0,
|
|
false
|
|
), longestInterval = textInterval(cardStats.intervals.getMaxValue(), false);
|
|
this.intervalsChart = createStatsChart(
|
|
"bar",
|
|
"intervalsChart",
|
|
t("INTERVALS"),
|
|
t("INTERVALS_DESC"),
|
|
Object.keys(cardStats.intervals.dict),
|
|
Object.values(cardStats.intervals.dict),
|
|
t("INTERVALS_SUMMARY", { avg: averageInterval, longest: longestInterval }),
|
|
t("COUNT"),
|
|
t("DAYS"),
|
|
t("NUMBER_OF_CARDS")
|
|
);
|
|
const eases = getKeysPreserveType(cardStats.eases.dict);
|
|
for (let ease = Math.min(...eases); ease <= Math.max(...eases); ease++) {
|
|
cardStats.eases.clearCountIfMissing(ease);
|
|
}
|
|
const averageEase = Math.round(cardStats.eases.getTotalOfValueMultiplyCount() / scheduledCount) || 0;
|
|
this.easesChart = createStatsChart(
|
|
"bar",
|
|
"easesChart",
|
|
t("EASES"),
|
|
"",
|
|
Object.keys(cardStats.eases.dict),
|
|
Object.values(cardStats.eases.dict),
|
|
t("EASES_SUMMARY", { avgEase: averageEase }),
|
|
t("COUNT"),
|
|
t("EASES"),
|
|
t("NUMBER_OF_CARDS")
|
|
);
|
|
const totalCardsCount = this.osrCore.reviewableDeckTree.getDistinctCardCount(
|
|
2 /* All */,
|
|
true
|
|
);
|
|
this.cardTypesChart = createStatsChart(
|
|
"pie",
|
|
"cardTypesChart",
|
|
t("CARD_TYPES"),
|
|
t("CARD_TYPES_DESC"),
|
|
[
|
|
`${t("CARD_TYPE_NEW")} - ${Math.round(cardStats.newCount / totalCardsCount * 100)}%`,
|
|
`${t("CARD_TYPE_YOUNG")} - ${Math.round(
|
|
cardStats.youngCount / totalCardsCount * 100
|
|
)}%`,
|
|
`${t("CARD_TYPE_MATURE")} - ${Math.round(
|
|
cardStats.matureCount / totalCardsCount * 100
|
|
)}%`
|
|
],
|
|
[cardStats.newCount, cardStats.youngCount, cardStats.matureCount],
|
|
t("CARD_TYPES_SUMMARY", { totalCardsCount })
|
|
);
|
|
const noteEases = mapRecord(
|
|
SrsAlgorithm.getInstance().noteStats().dict,
|
|
(key, value) => [
|
|
import_path.default.parse(key).name,
|
|
Math.round(value)
|
|
]
|
|
);
|
|
this.noteStatsGrid = new Ln({
|
|
columns: [
|
|
{
|
|
name: t("NOTE")
|
|
},
|
|
{
|
|
name: t("EASE"),
|
|
sort: true,
|
|
width: "200px"
|
|
}
|
|
],
|
|
search: true,
|
|
autoWidth: false,
|
|
data: Object.entries(noteEases).sort((a2, b2) => b2[1] - a2[1]),
|
|
pagination: {
|
|
limit: 10,
|
|
summary: false
|
|
},
|
|
language: {
|
|
search: {
|
|
placeholder: t("SEARCH")
|
|
},
|
|
pagination: {
|
|
previous: t("PREVIOUS"),
|
|
next: t("NEXT")
|
|
}
|
|
}
|
|
});
|
|
this.noteStatsGrid.render(document.getElementById("noteStats"));
|
|
}
|
|
destroy() {
|
|
this.forecastChart.destroy();
|
|
this.intervalsChart.destroy();
|
|
this.easesChart.destroy();
|
|
this.cardTypesChart.destroy();
|
|
this.noteStatsGrid.destroy();
|
|
}
|
|
};
|
|
function createStatsChart(type, canvasId, title, subtitle, labels, data, summary, seriesTitle = "", xAxisTitle = "", yAxisTitle = "") {
|
|
const style = getComputedStyle(document.body);
|
|
const textColor = style.getPropertyValue("--text-normal");
|
|
let scales = {}, backgroundColor = ["#2196f3"];
|
|
if (type !== "pie") {
|
|
scales = {
|
|
x: {
|
|
title: {
|
|
display: true,
|
|
text: xAxisTitle,
|
|
color: textColor
|
|
}
|
|
},
|
|
y: {
|
|
title: {
|
|
display: true,
|
|
text: yAxisTitle,
|
|
color: textColor
|
|
}
|
|
}
|
|
};
|
|
} else {
|
|
backgroundColor = ["#2196f3", "#4caf50", "green"];
|
|
}
|
|
const shouldFilter = canvasId === "forecastChart" || canvasId === "intervalsChart";
|
|
const statsChart = new Chart(document.getElementById(canvasId), {
|
|
type,
|
|
data: {
|
|
labels: shouldFilter ? labels.slice(0, 31) : labels,
|
|
datasets: [
|
|
{
|
|
label: seriesTitle,
|
|
backgroundColor,
|
|
data: shouldFilter ? data.slice(0, 31) : data
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
scales,
|
|
plugins: {
|
|
title: {
|
|
display: true,
|
|
text: title,
|
|
font: {
|
|
size: 22
|
|
},
|
|
color: textColor
|
|
},
|
|
subtitle: {
|
|
display: true,
|
|
text: subtitle,
|
|
font: {
|
|
size: 16,
|
|
style: "italic"
|
|
},
|
|
color: textColor
|
|
},
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
aspectRatio: 2
|
|
}
|
|
});
|
|
if (shouldFilter) {
|
|
const chartPeriodEl = document.getElementById("sr-chart-period");
|
|
chartPeriodEl.addEventListener("click", () => {
|
|
let filteredLabels, filteredData;
|
|
const chartPeriod = chartPeriodEl.value;
|
|
if (chartPeriod === "month") {
|
|
filteredLabels = labels.slice(0, 31);
|
|
filteredData = data.slice(0, 31);
|
|
} else if (chartPeriod === "quarter") {
|
|
filteredLabels = labels.slice(0, 91);
|
|
filteredData = data.slice(0, 91);
|
|
} else if (chartPeriod === "year") {
|
|
filteredLabels = labels.slice(0, 366);
|
|
filteredData = data.slice(0, 366);
|
|
} else {
|
|
filteredLabels = labels;
|
|
filteredData = data;
|
|
}
|
|
statsChart.data.labels = filteredLabels;
|
|
statsChart.data.datasets[0] = {
|
|
label: seriesTitle,
|
|
backgroundColor,
|
|
data: filteredData
|
|
};
|
|
statsChart.update();
|
|
});
|
|
}
|
|
document.getElementById(`${canvasId}Summary`).innerText = summary;
|
|
return statsChart;
|
|
}
|
|
|
|
// src/gui/tabs.tsx
|
|
var import_obsidian9 = require("obsidian");
|
|
var import_vhtml3 = __toESM(require_vhtml());
|
|
function createTabs(containerElement, tabs, activateTabId) {
|
|
const tabHeader = containerElement.createEl("div", {
|
|
attr: { class: "sr-tab-header" }
|
|
});
|
|
const tabContentContainers = {};
|
|
const tabButtons = {};
|
|
const tabStructure = {
|
|
header: tabHeader,
|
|
// Indicate that the first tab is active.
|
|
// This does not affect what tab is active in practice, it just reports the active tab.
|
|
activeTabId: Object.keys(tabs)[0],
|
|
buttons: tabButtons,
|
|
contentContainers: tabContentContainers,
|
|
contentGeneratorPromises: {}
|
|
};
|
|
let firstButton;
|
|
for (const tabId in tabs) {
|
|
const tab = tabs[tabId];
|
|
const button = tabHeader.createEl("button", {
|
|
attr: {
|
|
class: "sr-tab-header-button",
|
|
activateTab: "sr-tab-" + tabId
|
|
}
|
|
});
|
|
button.onclick = function(event) {
|
|
var _a;
|
|
const tabButton = this;
|
|
let maxWidth = 0;
|
|
let maxHeight = 0;
|
|
const tabHeader2 = tabButton.parentElement;
|
|
if (null === tabHeader2) {
|
|
throw new Error("Tab header is missing. Did not get a parent from tab button.");
|
|
}
|
|
const containerElement2 = tabHeader2.parentElement;
|
|
if (null === containerElement2) {
|
|
throw new Error(
|
|
"Container element is missing. Did not get a parent from tab header."
|
|
);
|
|
}
|
|
const tabContents = containerElement2.findAll("div.sr-tab-content");
|
|
const isMainSettingsModal = containerElement2.hasClass("vertical-tab-content");
|
|
for (const index in tabContents) {
|
|
const tabContent2 = tabContents[index];
|
|
if (!isMainSettingsModal) {
|
|
tabContent2.addClass("sr-tab-active");
|
|
if (tabContent2.offsetHeight > maxHeight) {
|
|
maxHeight = tabContent2.offsetHeight;
|
|
}
|
|
if (tabContent2.offsetWidth > maxWidth) {
|
|
maxWidth = tabContent2.offsetWidth;
|
|
}
|
|
}
|
|
tabContent2.removeClass("sr-tab-active");
|
|
}
|
|
const adjacentTabButtons = tabHeader2.findAll(".sr-tab-header-button");
|
|
for (const index in adjacentTabButtons) {
|
|
const tabButton2 = adjacentTabButtons[index];
|
|
tabButton2.removeClass("sr-tab-active");
|
|
}
|
|
tabButton.addClass("sr-tab-active");
|
|
const activateTabAttribute = tabButton.attributes.getNamedItem("activateTab");
|
|
if (null === activateTabAttribute) {
|
|
throw new Error("Tab button has no 'activateTab' HTML attribute! Murr!");
|
|
}
|
|
const activateTabId2 = activateTabAttribute.value;
|
|
const tabContent = document.getElementById(activateTabId2);
|
|
if (null === tabContent) {
|
|
throw new Error(
|
|
"No tab content was found with activate_tab_id '" + activateTabId2 + "'! Hmph!"
|
|
);
|
|
}
|
|
tabContent.addClass("sr-tab-active");
|
|
tabStructure.activeTabId = activateTabId2.replace(/^sr-tab-/, "");
|
|
(_a = tabContent.find(".sr-focus-element-on-tab-opening")) == null ? void 0 : _a.focus();
|
|
if (!isMainSettingsModal) {
|
|
tabContent.style.width = maxWidth + "px";
|
|
tabContent.style.height = maxHeight + "px";
|
|
}
|
|
event.preventDefault();
|
|
};
|
|
if (tab.icon) (0, import_obsidian9.setIcon)(button, tab.icon);
|
|
button.insertAdjacentHTML("beforeend", /* @__PURE__ */ (0, import_vhtml3.default)("span", { style: "padding-left: 5px;" }, tab.title));
|
|
tabButtons[tabId] = button;
|
|
tabContentContainers[tabId] = containerElement.createEl("div", {
|
|
attr: { class: "sr-tab-content", id: "sr-tab-" + tabId }
|
|
});
|
|
tabStructure.contentGeneratorPromises[tabId] = tab.contentGenerator(
|
|
tabContentContainers[tabId]
|
|
);
|
|
if (void 0 === firstButton) {
|
|
firstButton = button;
|
|
}
|
|
}
|
|
tabButtons[activateTabId].click();
|
|
return tabStructure;
|
|
}
|
|
|
|
// src/gui/settings.tsx
|
|
var applyDebounceTimer = 0;
|
|
function applySettingsUpdate(callback2) {
|
|
clearTimeout(applyDebounceTimer);
|
|
applyDebounceTimer = window.setTimeout(callback2, 512);
|
|
}
|
|
var SRSettingTab = class extends import_obsidian10.PluginSettingTab {
|
|
constructor(app, plugin) {
|
|
super(app, plugin);
|
|
this.lastPosition = {
|
|
scrollPosition: 0,
|
|
tabName: "main-flashcards"
|
|
};
|
|
this.plugin = plugin;
|
|
}
|
|
display() {
|
|
const { containerEl } = this;
|
|
containerEl.empty();
|
|
const header = containerEl.createEl("h4", {
|
|
text: `${t("SETTINGS_HEADER")}`
|
|
});
|
|
header.addClass("sr-centered");
|
|
this.tabStructure = createTabs(
|
|
containerEl,
|
|
{
|
|
"main-flashcards": {
|
|
title: t("FLASHCARDS"),
|
|
icon: "SpacedRepIcon",
|
|
contentGenerator: (containerElement) => this.tabFlashcards(containerElement)
|
|
},
|
|
"main-notes": {
|
|
title: t("NOTES"),
|
|
icon: "book-text",
|
|
contentGenerator: (containerElement) => this.tabNotes(containerElement)
|
|
},
|
|
"main-algorithm": {
|
|
title: t("SCHEDULING"),
|
|
icon: "calendar",
|
|
contentGenerator: (containerElement) => this.tabScheduling(containerElement)
|
|
},
|
|
"main-ui-preferences": {
|
|
title: t("UI"),
|
|
icon: "presentation",
|
|
contentGenerator: (containerElement) => this.tabUiPreferences(containerElement)
|
|
},
|
|
"main-statistics": {
|
|
title: t("STATS_TITLE"),
|
|
icon: "bar-chart-3",
|
|
contentGenerator: async (containerElement) => {
|
|
if (this.plugin.osrAppCore.cardStats == null) {
|
|
await this.plugin.sync();
|
|
}
|
|
this.statistics = new StatisticsView(
|
|
containerElement,
|
|
this.plugin.osrAppCore
|
|
);
|
|
this.statistics.render();
|
|
}
|
|
},
|
|
"main-help": {
|
|
title: t("HELP"),
|
|
icon: "badge-help",
|
|
contentGenerator: (containerElement) => this.tabHelp(containerElement)
|
|
}
|
|
},
|
|
this.lastPosition.tabName
|
|
);
|
|
this.tabStructure.contentGeneratorPromises[this.tabStructure.activeTabId].then(() => {
|
|
this.rememberLastPosition(containerEl);
|
|
});
|
|
}
|
|
hide() {
|
|
this.statistics.destroy();
|
|
this.containerEl.empty();
|
|
}
|
|
async tabFlashcards(containerEl) {
|
|
containerEl.createEl("h3", { text: t("GROUP_TAGS_FOLDERS") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("FLASHCARD_TAGS")).setDesc(t("FLASHCARD_TAGS_DESC")).addTextArea(
|
|
(text) => text.setValue(this.plugin.data.settings.flashcardTags.join(" ")).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.flashcardTags = value.split(/\s+/);
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("CONVERT_FOLDERS_TO_DECKS")).setDesc(t("CONVERT_FOLDERS_TO_DECKS_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.convertFoldersToDecks).onChange(async (value) => {
|
|
this.plugin.data.settings.convertFoldersToDecks = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
this.createSettingFoldersToIgnore(containerEl);
|
|
containerEl.createEl("h3", { text: t("GROUP_FLASHCARD_REVIEW") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("BURY_SIBLINGS_TILL_NEXT_DAY")).setDesc(t("BURY_SIBLINGS_TILL_NEXT_DAY_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.burySiblingCards).onChange(async (value) => {
|
|
this.plugin.data.settings.burySiblingCards = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("REVIEW_CARD_ORDER_WITHIN_DECK")).addDropdown(
|
|
(dropdown) => dropdown.addOptions({
|
|
NewFirstSequential: t("REVIEW_CARD_ORDER_NEW_FIRST_SEQUENTIAL"),
|
|
DueFirstSequential: t("REVIEW_CARD_ORDER_DUE_FIRST_SEQUENTIAL"),
|
|
NewFirstRandom: t("REVIEW_CARD_ORDER_NEW_FIRST_RANDOM"),
|
|
DueFirstRandom: t("REVIEW_CARD_ORDER_DUE_FIRST_RANDOM"),
|
|
EveryCardRandomDeckAndCard: t("REVIEW_CARD_ORDER_RANDOM_DECK_AND_CARD")
|
|
}).setValue(this.plugin.data.settings.flashcardCardOrder).onChange(async (value) => {
|
|
this.plugin.data.settings.flashcardCardOrder = value;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
})
|
|
);
|
|
const deckOrderEnabled = this.plugin.data.settings.flashcardCardOrder != "EveryCardRandomDeckAndCard";
|
|
new import_obsidian10.Setting(containerEl).setName(t("REVIEW_DECK_ORDER")).addDropdown(
|
|
(dropdown) => dropdown.addOptions(
|
|
deckOrderEnabled ? {
|
|
// eslint-disable-next-line camelcase
|
|
PrevDeckComplete_Sequential: t(
|
|
"REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_SEQUENTIAL"
|
|
),
|
|
// eslint-disable-next-line camelcase
|
|
PrevDeckComplete_Random: t(
|
|
"REVIEW_DECK_ORDER_PREV_DECK_COMPLETE_RANDOM"
|
|
)
|
|
} : {
|
|
EveryCardRandomDeckAndCard: t(
|
|
"REVIEW_DECK_ORDER_RANDOM_DECK_AND_CARD"
|
|
)
|
|
}
|
|
).setValue(
|
|
deckOrderEnabled ? this.plugin.data.settings.flashcardDeckOrder : "EveryCardRandomDeckAndCard"
|
|
).setDisabled(!deckOrderEnabled).onChange(async (value) => {
|
|
this.plugin.data.settings.flashcardDeckOrder = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
containerEl.createEl("h3", { text: t("GROUP_FLASHCARD_SEPARATORS") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("CONVERT_HIGHLIGHTS_TO_CLOZES")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.convertHighlightsToClozes).onChange(async (value) => {
|
|
const hightlightPattern = "==[123;;]answer[;;hint]==";
|
|
const clozePatternSet = new Set(this.plugin.data.settings.clozePatterns);
|
|
if (value) {
|
|
clozePatternSet.add(hightlightPattern);
|
|
} else {
|
|
clozePatternSet.delete(hightlightPattern);
|
|
}
|
|
this.plugin.data.settings.clozePatterns = [...clozePatternSet];
|
|
this.plugin.data.settings.convertHighlightsToClozes = value;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("CONVERT_BOLD_TEXT_TO_CLOZES")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.convertBoldTextToClozes).onChange(async (value) => {
|
|
const boldPattern = "**[123;;]answer[;;hint]**";
|
|
const clozePatternSet = new Set(this.plugin.data.settings.clozePatterns);
|
|
if (value) {
|
|
clozePatternSet.add(boldPattern);
|
|
} else {
|
|
clozePatternSet.delete(boldPattern);
|
|
}
|
|
this.plugin.data.settings.clozePatterns = [...clozePatternSet];
|
|
this.plugin.data.settings.convertBoldTextToClozes = value;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("CONVERT_CURLY_BRACKETS_TO_CLOZES")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.convertCurlyBracketsToClozes).onChange(async (value) => {
|
|
const curlyBracketsPattern = "{{[123;;]answer[;;hint]}}";
|
|
const clozePatternSet = new Set(this.plugin.data.settings.clozePatterns);
|
|
if (value) {
|
|
clozePatternSet.add(curlyBracketsPattern);
|
|
} else {
|
|
clozePatternSet.delete(curlyBracketsPattern);
|
|
}
|
|
this.plugin.data.settings.clozePatterns = [...clozePatternSet];
|
|
this.plugin.data.settings.convertCurlyBracketsToClozes = value;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
})
|
|
);
|
|
const clozePatternsEl = new import_obsidian10.Setting(containerEl).setName(t("CLOZE_PATTERNS"));
|
|
clozePatternsEl.descEl.insertAdjacentHTML(
|
|
"beforeend",
|
|
t("CLOZE_PATTERNS_DESC", {
|
|
docsUrl: "https://www.stephenmwangi.com/obsidian-spaced-repetition/flashcards/cloze-cards/#cloze-types"
|
|
})
|
|
);
|
|
clozePatternsEl.addTextArea(
|
|
(text) => text.setPlaceholder(
|
|
"Example:\n==[123;;]answer[;;hint]==\n**[123;;]answer[;;hint]**\n{{[123;;]answer[;;hint]}}"
|
|
).setValue(this.plugin.data.settings.clozePatterns.join("\n")).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
const hightlightPattern = "==[123;;]answer[;;hint]==";
|
|
const boldPattern = "**[123;;]answer[;;hint]**";
|
|
const curlyBracketsPattern = "{{[123;;]answer[;;hint]}}";
|
|
const clozePatternSet = new Set(
|
|
value.split(/\n+/).map((v2) => v2.trim()).filter((v2) => v2)
|
|
);
|
|
if (clozePatternSet.has(hightlightPattern)) {
|
|
this.plugin.data.settings.convertHighlightsToClozes = true;
|
|
} else {
|
|
this.plugin.data.settings.convertHighlightsToClozes = false;
|
|
}
|
|
if (clozePatternSet.has(boldPattern)) {
|
|
this.plugin.data.settings.convertBoldTextToClozes = true;
|
|
} else {
|
|
this.plugin.data.settings.convertBoldTextToClozes = false;
|
|
}
|
|
if (clozePatternSet.has(curlyBracketsPattern)) {
|
|
this.plugin.data.settings.convertCurlyBracketsToClozes = true;
|
|
} else {
|
|
this.plugin.data.settings.convertCurlyBracketsToClozes = false;
|
|
}
|
|
this.plugin.data.settings.clozePatterns = [...clozePatternSet];
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("INLINE_CARDS_SEPARATOR")).setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.singleLineCardSeparator).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.singleLineCardSeparator = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.singleLineCardSeparator = DEFAULT_SETTINGS.singleLineCardSeparator;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("INLINE_REVERSED_CARDS_SEPARATOR")).setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.singleLineReversedCardSeparator).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.singleLineReversedCardSeparator = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.singleLineReversedCardSeparator = DEFAULT_SETTINGS.singleLineReversedCardSeparator;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("MULTILINE_CARDS_SEPARATOR")).setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.multilineCardSeparator).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.multilineCardSeparator = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.multilineCardSeparator = DEFAULT_SETTINGS.multilineCardSeparator;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("MULTILINE_REVERSED_CARDS_SEPARATOR")).setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.multilineReversedCardSeparator).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.multilineReversedCardSeparator = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.multilineReversedCardSeparator = DEFAULT_SETTINGS.multilineReversedCardSeparator;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("MULTILINE_CARDS_END_MARKER")).setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.multilineCardEndMarker).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.multilineCardEndMarker = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.multilineCardEndMarker = DEFAULT_SETTINGS.multilineCardEndMarker;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
}
|
|
async tabNotes(containerEl) {
|
|
containerEl.createEl("h3", { text: t("GROUP_TAGS_FOLDERS") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("TAGS_TO_REVIEW")).setDesc(t("TAGS_TO_REVIEW_DESC")).addTextArea(
|
|
(text) => text.setValue(this.plugin.data.settings.tagsToReview.join(" ")).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.tagsToReview = value.split(/\s+/);
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
);
|
|
this.createSettingFoldersToIgnore(containerEl);
|
|
containerEl.createEl("h3", { text: t("NOTES_REVIEW_QUEUE") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("AUTO_NEXT_NOTE")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.autoNextNote).onChange(async (value) => {
|
|
this.plugin.data.settings.autoNextNote = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("OPEN_RANDOM_NOTE")).setDesc(t("OPEN_RANDOM_NOTE_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.openRandomNote).onChange(async (value) => {
|
|
this.plugin.data.settings.openRandomNote = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("REVIEW_PANE_ON_STARTUP")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.enableNoteReviewPaneOnStartup).onChange(async (value) => {
|
|
this.plugin.data.settings.enableNoteReviewPaneOnStartup = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("MAX_N_DAYS_REVIEW_QUEUE")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.maxNDaysNotesReviewQueue.toString()).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
const numValue = Number.parseInt(value);
|
|
if (!isNaN(numValue)) {
|
|
if (numValue < 1) {
|
|
new import_obsidian10.Notice(t("MIN_ONE_DAY"));
|
|
text.setValue(
|
|
this.plugin.data.settings.maxNDaysNotesReviewQueue.toString()
|
|
);
|
|
return;
|
|
}
|
|
this.plugin.data.settings.maxNDaysNotesReviewQueue = numValue;
|
|
await this.plugin.savePluginData();
|
|
} else {
|
|
new import_obsidian10.Notice(t("VALID_NUMBER_WARNING"));
|
|
}
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.maxNDaysNotesReviewQueue = DEFAULT_SETTINGS.maxNDaysNotesReviewQueue;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
}
|
|
async createSettingFoldersToIgnore(containerEl) {
|
|
new import_obsidian10.Setting(containerEl).setName(t("FOLDERS_TO_IGNORE")).setDesc(t("FOLDERS_TO_IGNORE_DESC")).addTextArea(
|
|
(text) => text.setValue(this.plugin.data.settings.noteFoldersToIgnore.join("\n")).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.noteFoldersToIgnore = value.split(/\n+/).map((v2) => v2.trim()).filter((v2) => v2);
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
})
|
|
);
|
|
}
|
|
async tabUiPreferences(containerEl) {
|
|
containerEl.createEl("h3", { text: t("OBSIDIAN_INTEGRATION") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("SHOW_RIBBON_ICON")).setDesc(t("SHOW_RIBBON_ICON_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showRibbonIcon).onChange(async (value) => {
|
|
this.plugin.data.settings.showRibbonIcon = value;
|
|
await this.plugin.savePluginData();
|
|
this.plugin.showRibbonIcon(value);
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("SHOW_STATUS_BAR")).setDesc(t("SHOW_STATUS_BAR_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showStatusBar).onChange(async (value) => {
|
|
this.plugin.data.settings.showStatusBar = value;
|
|
await this.plugin.savePluginData();
|
|
this.plugin.showStatusBar(value);
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("ENABLE_FILE_MENU_REVIEW_OPTIONS")).setDesc(t("ENABLE_FILE_MENU_REVIEW_OPTIONS_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(!this.plugin.data.settings.disableFileMenuReviewOptions).onChange(async (value) => {
|
|
this.plugin.data.settings.disableFileMenuReviewOptions = !value;
|
|
await this.plugin.savePluginData();
|
|
this.plugin.showFileMenuItems(value);
|
|
})
|
|
);
|
|
containerEl.createEl("h3", { text: t("FLASHCARDS") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("INITIALLY_EXPAND_SUBDECKS_IN_TREE")).setDesc(t("INITIALLY_EXPAND_SUBDECKS_IN_TREE_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.initiallyExpandAllSubdecksInTree).onChange(async (value) => {
|
|
this.plugin.data.settings.initiallyExpandAllSubdecksInTree = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("SHOW_CARD_CONTEXT")).setDesc(t("SHOW_CARD_CONTEXT_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showContextInCards).onChange(async (value) => {
|
|
this.plugin.data.settings.showContextInCards = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("SHOW_INTERVAL_IN_REVIEW_BUTTONS")).setDesc(t("SHOW_INTERVAL_IN_REVIEW_BUTTONS_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showIntervalInReviewButtons).onChange(async (value) => {
|
|
this.plugin.data.settings.showIntervalInReviewButtons = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("CARD_MODAL_HEIGHT_PERCENT")).setDesc(t("CARD_MODAL_SIZE_PERCENT_DESC")).addSlider(
|
|
(slider) => slider.setLimits(10, 100, 5).setValue(this.plugin.data.settings.flashcardHeightPercentage).setDynamicTooltip().onChange(async (value) => {
|
|
this.plugin.data.settings.flashcardHeightPercentage = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.flashcardHeightPercentage = DEFAULT_SETTINGS.flashcardHeightPercentage;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("CARD_MODAL_WIDTH_PERCENT")).setDesc(t("CARD_MODAL_SIZE_PERCENT_DESC")).addSlider(
|
|
(slider) => slider.setLimits(10, 100, 5).setValue(this.plugin.data.settings.flashcardWidthPercentage).setDynamicTooltip().onChange(async (value) => {
|
|
this.plugin.data.settings.flashcardWidthPercentage = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.flashcardWidthPercentage = DEFAULT_SETTINGS.flashcardWidthPercentage;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
containerEl.createEl("h3", { text: t("GROUP_FLASHCARDS_NOTES") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("FLASHCARD_EASY_LABEL")).setDesc(t("FLASHCARD_EASY_DESC")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.flashcardEasyText).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.flashcardEasyText = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.flashcardEasyText = DEFAULT_SETTINGS.flashcardEasyText;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("FLASHCARD_GOOD_LABEL")).setDesc(t("FLASHCARD_GOOD_DESC")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.flashcardGoodText).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.flashcardGoodText = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.flashcardGoodText = DEFAULT_SETTINGS.flashcardGoodText;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("FLASHCARD_HARD_LABEL")).setDesc(t("FLASHCARD_HARD_DESC")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.flashcardHardText).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
this.plugin.data.settings.flashcardHardText = value;
|
|
await this.plugin.savePluginData();
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.flashcardHardText = DEFAULT_SETTINGS.flashcardHardText;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("REVIEW_BUTTON_DELAY")).setDesc(t("REVIEW_BUTTON_DELAY_DESC")).addSlider(
|
|
(slider) => slider.setLimits(0, 5e3, 100).setValue(this.plugin.data.settings.reviewButtonDelay).setDynamicTooltip().onChange(async (value) => {
|
|
this.plugin.data.settings.reviewButtonDelay = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.reviewButtonDelay = DEFAULT_SETTINGS.reviewButtonDelay;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
}
|
|
async tabScheduling(containerEl) {
|
|
containerEl.createEl("h3", { text: t("ALGORITHM") });
|
|
const algoSettingEl = new import_obsidian10.Setting(containerEl).setName(t("ALGORITHM"));
|
|
algoSettingEl.descEl.insertAdjacentHTML(
|
|
"beforeend",
|
|
t("CHECK_ALGORITHM_WIKI", {
|
|
algoUrl: "https://www.stephenmwangi.com/obsidian-spaced-repetition/algorithms/"
|
|
})
|
|
);
|
|
algoSettingEl.addDropdown(
|
|
(dropdown) => dropdown.addOptions({
|
|
"SM-2-OSR": t("SM2_OSR_VARIANT")
|
|
}).setValue(this.plugin.data.settings.algorithm).onChange(async (value) => {
|
|
this.plugin.data.settings.algorithm = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("BASE_EASE")).setDesc(t("BASE_EASE_DESC")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.baseEase.toString()).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
const numValue = Number.parseInt(value);
|
|
if (!isNaN(numValue)) {
|
|
if (numValue < 130) {
|
|
new import_obsidian10.Notice(t("BASE_EASE_MIN_WARNING"));
|
|
text.setValue(this.plugin.data.settings.baseEase.toString());
|
|
return;
|
|
}
|
|
this.plugin.data.settings.baseEase = numValue;
|
|
await this.plugin.savePluginData();
|
|
} else {
|
|
new import_obsidian10.Notice(t("VALID_NUMBER_WARNING"));
|
|
}
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.baseEase = DEFAULT_SETTINGS.baseEase;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("LAPSE_INTERVAL_CHANGE")).setDesc(t("LAPSE_INTERVAL_CHANGE_DESC")).addSlider(
|
|
(slider) => slider.setLimits(1, 99, 1).setValue(this.plugin.data.settings.lapsesIntervalChange * 100).setDynamicTooltip().onChange(async (value) => {
|
|
this.plugin.data.settings.lapsesIntervalChange = value / 100;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.lapsesIntervalChange = DEFAULT_SETTINGS.lapsesIntervalChange;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("EASY_BONUS")).setDesc(t("EASY_BONUS_DESC")).addText(
|
|
(text) => text.setValue((this.plugin.data.settings.easyBonus * 100).toString()).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
const numValue = Number.parseInt(value) / 100;
|
|
if (!isNaN(numValue)) {
|
|
if (numValue < 1) {
|
|
new import_obsidian10.Notice(t("EASY_BONUS_MIN_WARNING"));
|
|
text.setValue(
|
|
(this.plugin.data.settings.easyBonus * 100).toString()
|
|
);
|
|
return;
|
|
}
|
|
this.plugin.data.settings.easyBonus = numValue;
|
|
await this.plugin.savePluginData();
|
|
} else {
|
|
new import_obsidian10.Notice(t("VALID_NUMBER_WARNING"));
|
|
}
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.easyBonus = DEFAULT_SETTINGS.easyBonus;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("LOAD_BALANCE")).setDesc(t("LOAD_BALANCE_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.loadBalance).onChange(async (value) => {
|
|
this.plugin.data.settings.loadBalance = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("MAX_INTERVAL")).setDesc(t("MAX_INTERVAL_DESC")).addText(
|
|
(text) => text.setValue(this.plugin.data.settings.maximumInterval.toString()).onChange((value) => {
|
|
applySettingsUpdate(async () => {
|
|
const numValue = Number.parseInt(value);
|
|
if (!isNaN(numValue)) {
|
|
if (numValue < 1) {
|
|
new import_obsidian10.Notice(t("MAX_INTERVAL_MIN_WARNING"));
|
|
text.setValue(
|
|
this.plugin.data.settings.maximumInterval.toString()
|
|
);
|
|
return;
|
|
}
|
|
this.plugin.data.settings.maximumInterval = numValue;
|
|
await this.plugin.savePluginData();
|
|
} else {
|
|
new import_obsidian10.Notice(t("VALID_NUMBER_WARNING"));
|
|
}
|
|
});
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.maximumInterval = DEFAULT_SETTINGS.maximumInterval;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
new import_obsidian10.Setting(containerEl).setName(t("MAX_LINK_CONTRIB")).setDesc(t("MAX_LINK_CONTRIB_DESC")).addSlider(
|
|
(slider) => slider.setLimits(0, 100, 1).setValue(this.plugin.data.settings.maxLinkFactor * 100).setDynamicTooltip().onChange(async (value) => {
|
|
this.plugin.data.settings.maxLinkFactor = value / 100;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
).addExtraButton((button) => {
|
|
button.setIcon("reset").setTooltip(t("RESET_DEFAULT")).onClick(async () => {
|
|
this.plugin.data.settings.maxLinkFactor = DEFAULT_SETTINGS.maxLinkFactor;
|
|
await this.plugin.savePluginData();
|
|
this.display();
|
|
});
|
|
});
|
|
containerEl.createEl("h3", { text: t("GROUP_DATA_STORAGE") });
|
|
new import_obsidian10.Setting(containerEl).setName(t("GROUP_DATA_STORAGE")).setDesc(t("GROUP_DATA_STORAGE_DESC")).addDropdown(
|
|
(dropdown) => dropdown.addOptions({
|
|
NOTES: t("STORE_IN_NOTES")
|
|
}).setValue(this.plugin.data.settings.dataStore).onChange(async (value) => {
|
|
this.plugin.data.settings.dataStore = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("INLINE_SCHEDULING_COMMENTS")).setDesc(t("INLINE_SCHEDULING_COMMENTS_DESC")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.cardCommentOnSameLine).onChange(async (value) => {
|
|
this.plugin.data.settings.cardCommentOnSameLine = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
}
|
|
async tabHelp(containerEl) {
|
|
containerEl.createEl("h3", { text: `${t("HELP")}` });
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("CHECK_WIKI", {
|
|
wikiUrl: "https://www.stephenmwangi.com/obsidian-spaced-repetition/"
|
|
})
|
|
);
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("GITHUB_DISCUSSIONS", {
|
|
discussionsUrl: "https://github.com/st3v3nmw/obsidian-spaced-repetition/discussions/"
|
|
})
|
|
);
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("GITHUB_ISSUES", {
|
|
issuesUrl: "https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/"
|
|
})
|
|
);
|
|
containerEl.createEl("h3", { text: `${t("LOGGING")}` });
|
|
new import_obsidian10.Setting(containerEl).setName(t("DISPLAY_SCHEDULING_DEBUG_INFO")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showSchedulingDebugMessages).onChange(async (value) => {
|
|
this.plugin.data.settings.showSchedulingDebugMessages = value;
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
new import_obsidian10.Setting(containerEl).setName(t("DISPLAY_PARSER_DEBUG_INFO")).addToggle(
|
|
(toggle) => toggle.setValue(this.plugin.data.settings.showParserDebugMessages).onChange(async (value) => {
|
|
this.plugin.data.settings.showParserDebugMessages = value;
|
|
setDebugParser(this.plugin.data.settings.showParserDebugMessages);
|
|
await this.plugin.savePluginData();
|
|
})
|
|
);
|
|
containerEl.createEl("h3", { text: t("GROUP_CONTRIBUTING") });
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("GITHUB_SOURCE_CODE", {
|
|
githubProjectUrl: "https://github.com/st3v3nmw/obsidian-spaced-repetition"
|
|
})
|
|
);
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("CODE_CONTRIBUTION_INFO", {
|
|
codeContributionUrl: "https://www.stephenmwangi.com/obsidian-spaced-repetition/contributing/#code"
|
|
})
|
|
);
|
|
containerEl.createEl("p").insertAdjacentHTML(
|
|
"beforeend",
|
|
t("TRANSLATION_CONTRIBUTION_INFO", {
|
|
translationContributionUrl: "https://www.stephenmwangi.com/obsidian-spaced-repetition/contributing/#translating"
|
|
})
|
|
);
|
|
}
|
|
rememberLastPosition(containerElement) {
|
|
const lastPosition = this.lastPosition;
|
|
this.tabStructure.buttons[lastPosition.tabName].click();
|
|
containerElement.scrollTo({
|
|
top: this.lastPosition.scrollPosition,
|
|
behavior: "auto"
|
|
});
|
|
containerElement.addEventListener("scroll", (_2) => {
|
|
this.lastPosition.scrollPosition = containerElement.scrollTop;
|
|
});
|
|
for (const tabName in this.tabStructure.buttons) {
|
|
const button = this.tabStructure.buttons[tabName];
|
|
button.onClickEvent((_2) => {
|
|
lastPosition.tabName = tabName;
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/gui/sidebar.tsx
|
|
var OsrSidebar = class {
|
|
get app() {
|
|
return this.plugin.app;
|
|
}
|
|
constructor(plugin, settings, nextNoteReviewHandler) {
|
|
this.plugin = plugin;
|
|
this.settings = settings;
|
|
this.nextNoteReviewHandler = nextNoteReviewHandler;
|
|
}
|
|
redraw() {
|
|
this.reviewQueueListView.redraw();
|
|
}
|
|
getActiveLeaf(type) {
|
|
const leaves = this.app.workspace.getLeavesOfType(type);
|
|
if (leaves.length == 0) {
|
|
return this.app.workspace.getRightLeaf(false);
|
|
}
|
|
return leaves[0];
|
|
}
|
|
init() {
|
|
this.plugin.registerView(REVIEW_QUEUE_VIEW_TYPE, (leaf) => {
|
|
return this.reviewQueueListView = new ReviewQueueListView(
|
|
leaf,
|
|
this.nextNoteReviewHandler,
|
|
this.settings
|
|
);
|
|
});
|
|
}
|
|
async activateReviewQueueViewPanel() {
|
|
if (this.settings.enableNoteReviewPaneOnStartup) {
|
|
await this.getActiveLeaf(REVIEW_QUEUE_VIEW_TYPE).setViewState({
|
|
type: REVIEW_QUEUE_VIEW_TYPE,
|
|
active: true
|
|
});
|
|
}
|
|
}
|
|
async openReviewQueueView() {
|
|
const reviewQueueLeaf = this.getActiveLeaf(REVIEW_QUEUE_VIEW_TYPE);
|
|
this.app.workspace.revealLeaf(reviewQueueLeaf);
|
|
}
|
|
};
|
|
|
|
// src/icons/app-icon.ts
|
|
var import_obsidian11 = require("obsidian");
|
|
function appIcon() {
|
|
(0, import_obsidian11.addIcon)(
|
|
"SpacedRepIcon",
|
|
`<path fill="currentColor" stroke="currentColor" d="M 88.960938 17.257812 L 47.457031 17.257812 C 45.679688 17.257812 44.230469 18.703125 44.230469 20.484375 L 44.230469 86.558594 C 44.230469 88.335938 45.679688 89.785156 47.457031 89.785156 L 88.960938 89.785156 C 90.738281 89.785156 92.1875 88.335938 92.1875 86.558594 L 92.1875 20.484375 C 92.1875 18.703125 90.738281 17.257812 88.960938 17.257812 Z M 88.28125 85.878906 L 48.136719 85.878906 L 48.136719 21.164062 L 88.28125 21.164062 Z M 88.28125 85.878906 "/>
|
|
<path fill="currentColor" stroke="currentColor" d="M 88.960938 9.445312 L 61.667969 9.445312 C 59.925781 3.816406 54.011719 0.515625 48.269531 2.054688 L 8.183594 12.796875 C 2.304688 14.371094 -1.199219 20.4375 0.378906 26.316406 L 17.476562 90.140625 C 18.796875 95.066406 23.269531 98.324219 28.144531 98.324219 C 29.085938 98.324219 30.046875 98.199219 31 97.945312 L 40.765625 95.328125 C 42.625 96.75 44.941406 97.597656 47.457031 97.597656 L 88.960938 97.597656 C 95.046875 97.597656 100 92.644531 100 86.558594 L 100 20.484375 C 100 14.398438 95.046875 9.445312 88.960938 9.445312 Z M 29.988281 94.171875 C 26.1875 95.191406 22.269531 92.925781 21.25 89.128906 L 4.152344 25.304688 C 3.132812 21.507812 5.394531 17.585938 9.195312 16.570312 L 49.28125 5.828125 C 52.578125 4.945312 55.960938 6.53125 57.464844 9.445312 L 47.457031 9.445312 C 41.371094 9.445312 36.417969 14.398438 36.417969 20.484375 L 36.417969 86.558594 C 36.417969 88.558594 36.957031 90.433594 37.890625 92.054688 Z M 96.09375 86.558594 C 96.09375 90.492188 92.894531 93.691406 88.960938 93.691406 L 47.457031 93.691406 C 43.523438 93.691406 40.324219 90.492188 40.324219 86.558594 L 40.324219 20.484375 C 40.324219 16.550781 43.523438 13.351562 47.457031 13.351562 L 88.960938 13.351562 C 92.894531 13.351562 96.09375 16.550781 96.09375 20.484375 Z M 96.09375 86.558594 "/>
|
|
<path fill="currentColor" stroke="currentColor" d="M 54.101562 53.09375 L 60.070312 57.410156 L 57.789062 64.378906 C 56.90625 67.074219 59.996094 69.320312 62.285156 67.648438 L 68.210938 63.324219 L 74.132812 67.648438 C 76.421875 69.320312 79.511719 67.074219 78.628906 64.378906 L 76.347656 57.410156 L 82.320312 53.09375 C 84.613281 51.433594 83.441406 47.804688 80.605469 47.804688 L 73.242188 47.804688 L 70.988281 40.839844 C 70.117188 38.144531 66.300781 38.144531 65.429688 40.839844 L 63.179688 47.804688 L 55.8125 47.804688 C 52.980469 47.804688 51.804688 51.433594 54.101562 53.09375 Z M 54.101562 53.09375 "/>
|
|
`
|
|
);
|
|
}
|
|
|
|
// src/next-note-review-handler.ts
|
|
var import_obsidian13 = require("obsidian");
|
|
|
|
// src/gui/review-deck-selection-modal.tsx
|
|
var import_obsidian12 = require("obsidian");
|
|
var ReviewDeckSelectionModal = class extends import_obsidian12.FuzzySuggestModal {
|
|
constructor(app, deckKeys) {
|
|
super(app);
|
|
this.deckKeys = [];
|
|
this.deckKeys = deckKeys;
|
|
}
|
|
getItems() {
|
|
return this.deckKeys;
|
|
}
|
|
getItemText(item) {
|
|
return item;
|
|
}
|
|
onChooseItem(deckKey, _2) {
|
|
this.close();
|
|
this.submitCallback(deckKey);
|
|
}
|
|
};
|
|
|
|
// src/next-note-review-handler.ts
|
|
var NextNoteReviewHandler = class {
|
|
get lastSelectedReviewDeck() {
|
|
return this._lastSelectedReviewDeck;
|
|
}
|
|
get noteReviewQueue() {
|
|
return this._noteReviewQueue;
|
|
}
|
|
constructor(app, settings, noteReviewQueue) {
|
|
this.app = app;
|
|
this.settings = settings;
|
|
this._noteReviewQueue = noteReviewQueue;
|
|
}
|
|
async autoReviewNextNote() {
|
|
if (this.settings.autoNextNote) {
|
|
if (!this._lastSelectedReviewDeck) {
|
|
const reviewDeckKeys = this._noteReviewQueue.reviewDeckNameList;
|
|
if (reviewDeckKeys.length > 0) this._lastSelectedReviewDeck = reviewDeckKeys[0];
|
|
else {
|
|
new import_obsidian13.Notice(t("ALL_CAUGHT_UP"));
|
|
return;
|
|
}
|
|
}
|
|
this.reviewNextNote(this._lastSelectedReviewDeck);
|
|
}
|
|
}
|
|
async reviewNextNoteModal() {
|
|
const reviewDeckNames = this._noteReviewQueue.reviewDeckNameList;
|
|
if (reviewDeckNames.length === 1) {
|
|
this.reviewNextNote(reviewDeckNames[0]);
|
|
} else {
|
|
const deckSelectionModal = new ReviewDeckSelectionModal(this.app, reviewDeckNames);
|
|
deckSelectionModal.submitCallback = (deckKey) => this.reviewNextNote(deckKey);
|
|
deckSelectionModal.open();
|
|
}
|
|
}
|
|
async reviewNextNote(deckKey) {
|
|
if (!this._noteReviewQueue.reviewDeckNameList.contains(deckKey)) {
|
|
new import_obsidian13.Notice(t("NO_DECK_EXISTS", { deckName: deckKey }));
|
|
return;
|
|
}
|
|
this._lastSelectedReviewDeck = deckKey;
|
|
const deck = this._noteReviewQueue.reviewDecks.get(deckKey);
|
|
const notefile = deck.determineNextNote(this.settings.openRandomNote);
|
|
if (notefile) {
|
|
await this.openNote(deckKey, notefile.tfile);
|
|
} else {
|
|
new import_obsidian13.Notice(t("ALL_CAUGHT_UP"));
|
|
}
|
|
}
|
|
async openNote(deckName, file) {
|
|
this._lastSelectedReviewDeck = deckName;
|
|
await this.app.workspace.getLeaf().openFile(file);
|
|
}
|
|
};
|
|
|
|
// src/note-review-deck.ts
|
|
var SchedNote = class {
|
|
constructor(note, dueUnix) {
|
|
this.note = note;
|
|
this.dueUnix = dueUnix;
|
|
}
|
|
isDue(todayUnix) {
|
|
return this.dueUnix <= todayUnix;
|
|
}
|
|
};
|
|
var NoteReviewDeck = class {
|
|
constructor(name) {
|
|
this._newNotes = [];
|
|
this._scheduledNotes = [];
|
|
this._dueNotesCount = 0;
|
|
this._deckName = name;
|
|
this._activeFolders = /* @__PURE__ */ new Set([this._deckName, t("TODAY")]);
|
|
}
|
|
get deckName() {
|
|
return this._deckName;
|
|
}
|
|
get newNotes() {
|
|
return this._newNotes;
|
|
}
|
|
get scheduledNotes() {
|
|
return this._scheduledNotes;
|
|
}
|
|
get dueNotesCount() {
|
|
return this._dueNotesCount;
|
|
}
|
|
get activeFolders() {
|
|
return this._activeFolders;
|
|
}
|
|
calcDueNotesCount(todayUnix) {
|
|
this._dueNotesCount = 0;
|
|
this.scheduledNotes.forEach((scheduledNote) => {
|
|
if (scheduledNote.isDue(todayUnix)) {
|
|
this._dueNotesCount++;
|
|
}
|
|
});
|
|
}
|
|
sortNotesByDateAndImportance(pageranks) {
|
|
this._newNotes = this.newNotes.sort(
|
|
(a2, b2) => (pageranks[b2.path] || 0) - (pageranks[a2.path] || 0)
|
|
);
|
|
this._scheduledNotes = this.scheduledNotes.sort((a2, b2) => {
|
|
const result = a2.dueUnix - b2.dueUnix;
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
return (pageranks[b2.note.path] || 0) - (pageranks[a2.note.path] || 0);
|
|
});
|
|
}
|
|
determineNextNote(openRandomNote) {
|
|
const todayUnix = globalDateProvider.today.valueOf();
|
|
const dueNotes = this.scheduledNotes.filter((note) => note.isDue(todayUnix));
|
|
if (dueNotes.length > 0) {
|
|
const index = openRandomNote ? globalRandomNumberProvider.getInteger(0, dueNotes.length - 1) : 0;
|
|
return dueNotes[index].note;
|
|
}
|
|
if (this.newNotes.length > 0) {
|
|
const index = openRandomNote ? globalRandomNumberProvider.getInteger(0, this.newNotes.length - 1) : 0;
|
|
return this.newNotes[index];
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// src/note-review-queue.ts
|
|
var NoteReviewQueue = class {
|
|
get reviewDecks() {
|
|
return this._reviewDecks;
|
|
}
|
|
get dueNotesCount() {
|
|
return this._dueNotesCount;
|
|
}
|
|
get reviewDeckNameList() {
|
|
return [...this._reviewDecks.keys()];
|
|
}
|
|
init() {
|
|
this._reviewDecks = /* @__PURE__ */ new Map();
|
|
}
|
|
calcDueNotesCount(todayUnix) {
|
|
this._dueNotesCount = 0;
|
|
this._reviewDecks.forEach((reviewDeck) => {
|
|
reviewDeck.calcDueNotesCount(todayUnix);
|
|
this._dueNotesCount += reviewDeck.dueNotesCount;
|
|
});
|
|
}
|
|
addNoteToQueue(noteFile, noteSchedule, matchedNoteTags) {
|
|
for (const matchedNoteTag of matchedNoteTags) {
|
|
if (!this.reviewDecks.has(matchedNoteTag)) {
|
|
this.reviewDecks.set(matchedNoteTag, new NoteReviewDeck(matchedNoteTag));
|
|
}
|
|
}
|
|
if (noteSchedule == null) {
|
|
for (const matchedNoteTag of matchedNoteTags) {
|
|
this.reviewDecks.get(matchedNoteTag).newNotes.push(noteFile);
|
|
}
|
|
} else {
|
|
for (const matchedNoteTag of matchedNoteTags) {
|
|
this.reviewDecks.get(matchedNoteTag).scheduledNotes.push(new SchedNote(noteFile, noteSchedule.dueDateAsUnix));
|
|
}
|
|
}
|
|
}
|
|
updateScheduleInfo(note, scheduleInfo) {
|
|
this.reviewDecks.forEach((reviewDeck) => {
|
|
let wasDueInDeck = false;
|
|
for (const scheduledNote of reviewDeck.scheduledNotes) {
|
|
if (scheduledNote.note.path === note.path) {
|
|
scheduledNote.dueUnix = scheduleInfo.dueDate.valueOf();
|
|
wasDueInDeck = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!wasDueInDeck) {
|
|
reviewDeck.newNotes.splice(
|
|
reviewDeck.newNotes.findIndex((newNote) => newNote.path === note.path),
|
|
1
|
|
);
|
|
reviewDeck.scheduledNotes.push(new SchedNote(note, scheduleInfo.dueDate.valueOf()));
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/plugin-data.ts
|
|
var DEFAULT_DATA = {
|
|
settings: DEFAULT_SETTINGS,
|
|
buryDate: "",
|
|
buryList: [],
|
|
historyDeck: null
|
|
};
|
|
|
|
// src/question-postponement-list.ts
|
|
var QuestionPostponementList = class {
|
|
constructor(plugin, settings, list) {
|
|
this.plugin = plugin;
|
|
this.settings = settings;
|
|
this.list = list;
|
|
}
|
|
async clearIfNewDay(data) {
|
|
const now2 = window.moment(Date.now());
|
|
const todayDate = now2.format("YYYY-MM-DD");
|
|
const isNewDay = todayDate !== data.buryDate;
|
|
if (isNewDay) {
|
|
data.buryDate = todayDate;
|
|
this.clear();
|
|
await this.write();
|
|
}
|
|
}
|
|
clear() {
|
|
this.list.splice(0);
|
|
}
|
|
add(question) {
|
|
if (!this.includes(question)) this.list.push(question.questionText.textHash);
|
|
}
|
|
includes(question) {
|
|
return this.list.includes(question.questionText.textHash);
|
|
}
|
|
async write() {
|
|
if (this.plugin == null) return;
|
|
await this.plugin.savePluginData();
|
|
}
|
|
};
|
|
|
|
// src/main.ts
|
|
var SRPlugin = class _SRPlugin extends import_obsidian14.Plugin {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.ribbonIcon = null;
|
|
this.statusBar = null;
|
|
}
|
|
async onload() {
|
|
await this.loadPluginData();
|
|
const noteReviewQueue = new NoteReviewQueue();
|
|
this.nextNoteReviewHandler = new NextNoteReviewHandler(
|
|
this.app,
|
|
this.data.settings,
|
|
noteReviewQueue
|
|
);
|
|
this.osrSidebar = new OsrSidebar(this, this.data.settings, this.nextNoteReviewHandler);
|
|
this.osrSidebar.init();
|
|
this.app.workspace.onLayoutReady(async () => {
|
|
await this.osrSidebar.activateReviewQueueViewPanel();
|
|
setTimeout(async () => {
|
|
if (!this.osrAppCore.syncLock) {
|
|
await this.sync();
|
|
}
|
|
}, 2e3);
|
|
});
|
|
const questionPostponementList = new QuestionPostponementList(
|
|
this,
|
|
this.data.settings,
|
|
this.data.buryList
|
|
);
|
|
const osrNoteLinkInfoFinder = new ObsidianVaultNoteLinkInfoFinder(this.app.metadataCache);
|
|
this.osrAppCore = new OsrAppCore(this.app);
|
|
this.osrAppCore.init(
|
|
questionPostponementList,
|
|
osrNoteLinkInfoFinder,
|
|
this.data.settings,
|
|
this.onOsrVaultDataChanged.bind(this),
|
|
noteReviewQueue
|
|
);
|
|
appIcon();
|
|
this.showStatusBar(this.data.settings.showStatusBar);
|
|
this.showRibbonIcon(this.data.settings.showRibbonIcon);
|
|
this.showFileMenuItems(!this.data.settings.disableFileMenuReviewOptions);
|
|
this.addPluginCommands();
|
|
this.addSettingTab(new SRSettingTab(this.app, this));
|
|
}
|
|
showFileMenuItems(status) {
|
|
if (this.fileMenuHandler === void 0) {
|
|
this.fileMenuHandler = (menu, fileish) => {
|
|
if (fileish instanceof import_obsidian14.TFile && fileish.extension === "md") {
|
|
menu.addItem((item) => {
|
|
item.setTitle(
|
|
t("REVIEW_DIFFICULTY_FILE_MENU", {
|
|
difficulty: this.data.settings.flashcardEasyText
|
|
})
|
|
).setIcon("SpacedRepIcon").onClick(() => {
|
|
this.saveNoteReviewResponse(fileish, 0 /* Easy */);
|
|
});
|
|
});
|
|
menu.addItem((item) => {
|
|
item.setTitle(
|
|
t("REVIEW_DIFFICULTY_FILE_MENU", {
|
|
difficulty: this.data.settings.flashcardGoodText
|
|
})
|
|
).setIcon("SpacedRepIcon").onClick(() => {
|
|
this.saveNoteReviewResponse(fileish, 1 /* Good */);
|
|
});
|
|
});
|
|
menu.addItem((item) => {
|
|
item.setTitle(
|
|
t("REVIEW_DIFFICULTY_FILE_MENU", {
|
|
difficulty: this.data.settings.flashcardHardText
|
|
})
|
|
).setIcon("SpacedRepIcon").onClick(() => {
|
|
this.saveNoteReviewResponse(fileish, 2 /* Hard */);
|
|
});
|
|
});
|
|
}
|
|
};
|
|
}
|
|
if (status) {
|
|
this.registerEvent(this.app.workspace.on("file-menu", this.fileMenuHandler));
|
|
} else {
|
|
this.app.workspace.off("file-menu", this.fileMenuHandler);
|
|
}
|
|
}
|
|
addPluginCommands() {
|
|
this.addCommand({
|
|
id: "srs-note-review-open-note",
|
|
name: t("OPEN_NOTE_FOR_REVIEW"),
|
|
callback: async () => {
|
|
if (!this.osrAppCore.syncLock) {
|
|
await this.sync();
|
|
this.nextNoteReviewHandler.reviewNextNoteModal();
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-note-review-easy",
|
|
name: t("REVIEW_NOTE_DIFFICULTY_CMD", {
|
|
difficulty: this.data.settings.flashcardEasyText
|
|
}),
|
|
callback: () => {
|
|
const openFile = this.app.workspace.getActiveFile();
|
|
if (openFile && openFile.extension === "md") {
|
|
this.saveNoteReviewResponse(openFile, 0 /* Easy */);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-note-review-good",
|
|
name: t("REVIEW_NOTE_DIFFICULTY_CMD", {
|
|
difficulty: this.data.settings.flashcardGoodText
|
|
}),
|
|
callback: () => {
|
|
const openFile = this.app.workspace.getActiveFile();
|
|
if (openFile && openFile.extension === "md") {
|
|
this.saveNoteReviewResponse(openFile, 1 /* Good */);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-note-review-hard",
|
|
name: t("REVIEW_NOTE_DIFFICULTY_CMD", {
|
|
difficulty: this.data.settings.flashcardHardText
|
|
}),
|
|
callback: () => {
|
|
const openFile = this.app.workspace.getActiveFile();
|
|
if (openFile && openFile.extension === "md") {
|
|
this.saveNoteReviewResponse(openFile, 2 /* Hard */);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-review-flashcards",
|
|
name: t("REVIEW_ALL_CARDS"),
|
|
callback: async () => {
|
|
if (!this.osrAppCore.syncLock) {
|
|
await this.sync();
|
|
this.openFlashcardModal(
|
|
this.osrAppCore.reviewableDeckTree,
|
|
this.osrAppCore.remainingDeckTree,
|
|
1 /* Review */
|
|
);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-cram-flashcards",
|
|
name: t("CRAM_ALL_CARDS"),
|
|
callback: async () => {
|
|
await this.sync();
|
|
this.openFlashcardModal(
|
|
this.osrAppCore.reviewableDeckTree,
|
|
this.osrAppCore.reviewableDeckTree,
|
|
0 /* Cram */
|
|
);
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-review-flashcards-in-note",
|
|
name: t("REVIEW_CARDS_IN_NOTE"),
|
|
callback: async () => {
|
|
const openFile = this.app.workspace.getActiveFile();
|
|
if (openFile && openFile.extension === "md") {
|
|
this.openFlashcardModalForSingleNote(openFile, 1 /* Review */);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-cram-flashcards-in-note",
|
|
name: t("CRAM_CARDS_IN_NOTE"),
|
|
callback: async () => {
|
|
const openFile = this.app.workspace.getActiveFile();
|
|
if (openFile && openFile.extension === "md") {
|
|
this.openFlashcardModalForSingleNote(openFile, 0 /* Cram */);
|
|
}
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: "srs-open-review-queue-view",
|
|
name: t("OPEN_REVIEW_QUEUE_VIEW"),
|
|
callback: async () => {
|
|
await this.osrSidebar.openReviewQueueView();
|
|
}
|
|
});
|
|
}
|
|
onunload() {
|
|
this.app.workspace.getLeavesOfType(REVIEW_QUEUE_VIEW_TYPE).forEach((leaf) => leaf.detach());
|
|
}
|
|
async openFlashcardModalForSingleNote(noteFile, reviewMode) {
|
|
const note = await this.loadNote(noteFile);
|
|
const deckTree = new Deck2("root", null);
|
|
note.appendCardsToDeck(deckTree);
|
|
const remainingDeckTree = DeckTreeFilter.filterForRemainingCards(
|
|
this.osrAppCore.questionPostponementList,
|
|
deckTree,
|
|
reviewMode
|
|
);
|
|
this.openFlashcardModal(deckTree, remainingDeckTree, reviewMode);
|
|
}
|
|
openFlashcardModal(fullDeckTree, remainingDeckTree, reviewMode) {
|
|
const deckIterator = _SRPlugin.createDeckTreeIterator(this.data.settings);
|
|
const reviewSequencer = new FlashcardReviewSequencer(
|
|
reviewMode,
|
|
deckIterator,
|
|
this.data.settings,
|
|
SrsAlgorithm.getInstance(),
|
|
this.osrAppCore.questionPostponementList,
|
|
this.osrAppCore.dueDateFlashcardHistogram
|
|
);
|
|
reviewSequencer.setDeckTree(fullDeckTree, remainingDeckTree);
|
|
new FlashcardModal(this.app, this, this.data.settings, reviewSequencer, reviewMode).open();
|
|
}
|
|
static createDeckTreeIterator(settings) {
|
|
let cardOrder = CardOrder[settings.flashcardCardOrder];
|
|
if (cardOrder === void 0) cardOrder = 2 /* DueFirstSequential */;
|
|
let deckOrder = DeckOrder[settings.flashcardDeckOrder];
|
|
if (deckOrder === void 0) deckOrder = 0 /* PrevDeckComplete_Sequential */;
|
|
const iteratorOrder = {
|
|
deckOrder,
|
|
cardOrder
|
|
};
|
|
return new DeckTreeIterator(iteratorOrder, null);
|
|
}
|
|
async sync() {
|
|
if (this.osrAppCore.syncLock) {
|
|
return;
|
|
}
|
|
const now2 = window.moment(Date.now());
|
|
this.osrAppCore.defaultTextDirection = this.getObsidianRtlSetting();
|
|
await this.osrAppCore.loadVault();
|
|
if (this.data.settings.showSchedulingDebugMessages) {
|
|
console.log(`SR: ${t("DECKS")}`, this.osrAppCore.reviewableDeckTree);
|
|
console.log(
|
|
"SR: " + t("SYNC_TIME_TAKEN", {
|
|
t: Date.now() - now2.valueOf()
|
|
})
|
|
);
|
|
}
|
|
}
|
|
onOsrVaultDataChanged() {
|
|
this.statusBar.setText(
|
|
t("STATUS_BAR", {
|
|
dueNotesCount: this.osrAppCore.noteReviewQueue.dueNotesCount,
|
|
dueFlashcardsCount: this.osrAppCore.remainingDeckTree.getCardCount(
|
|
2 /* All */,
|
|
true
|
|
)
|
|
})
|
|
);
|
|
if (this.data.settings.enableNoteReviewPaneOnStartup) this.osrSidebar.redraw();
|
|
}
|
|
async loadNote(noteFile) {
|
|
const loader = new NoteFileLoader(this.data.settings);
|
|
const srFile = this.createSrTFile(noteFile);
|
|
const folderTopicPath = TopicPath.getFolderPathFromFilename(
|
|
srFile,
|
|
this.data.settings
|
|
);
|
|
const note = await loader.load(
|
|
this.createSrTFile(noteFile),
|
|
this.getObsidianRtlSetting(),
|
|
folderTopicPath
|
|
);
|
|
if (note.hasChanged) {
|
|
note.writeNoteFile(this.data.settings);
|
|
}
|
|
return note;
|
|
}
|
|
getObsidianRtlSetting() {
|
|
const v2 = this.app.vault.getConfig("rightToLeft");
|
|
return convertToStringOrEmpty(v2) == "true" ? 2 /* Rtl */ : 1 /* Ltr */;
|
|
}
|
|
async saveNoteReviewResponse(note, response) {
|
|
const noteSrTFile = this.createSrTFile(note);
|
|
if (SettingsUtil.isPathInNoteIgnoreFolder(this.data.settings, note.path)) {
|
|
new import_obsidian14.Notice(t("NOTE_IN_IGNORED_FOLDER"));
|
|
return;
|
|
}
|
|
const tags = noteSrTFile.getAllTagsFromCache();
|
|
if (!SettingsUtil.isAnyTagANoteReviewTag(this.data.settings, tags)) {
|
|
new import_obsidian14.Notice(t("PLEASE_TAG_NOTE"));
|
|
return;
|
|
}
|
|
await this.osrAppCore.saveNoteReviewResponse(noteSrTFile, response, this.data.settings);
|
|
new import_obsidian14.Notice(t("RESPONSE_RECEIVED"));
|
|
if (this.data.settings.autoNextNote) {
|
|
this.nextNoteReviewHandler.autoReviewNextNote();
|
|
}
|
|
}
|
|
createSrTFile(note) {
|
|
return new SrTFile(this.app.vault, this.app.metadataCache, note);
|
|
}
|
|
async loadPluginData() {
|
|
const loadedData = await this.loadData();
|
|
if (loadedData == null ? void 0 : loadedData.settings) upgradeSettings(loadedData.settings);
|
|
this.data = Object.assign({}, DEFAULT_DATA, loadedData);
|
|
this.data.settings = Object.assign({}, DEFAULT_SETTINGS, this.data.settings);
|
|
setDebugParser(this.data.settings.showParserDebugMessages);
|
|
this.setupDataStoreAndAlgorithmInstances(this.data.settings);
|
|
}
|
|
setupDataStoreAndAlgorithmInstances(settings) {
|
|
DataStore.instance = new StoreInNotes(settings);
|
|
SrsAlgorithm.instance = new SrsAlgorithmOsr(settings);
|
|
DataStoreAlgorithm.instance = new DataStoreInNoteAlgorithmOsr(settings);
|
|
}
|
|
async savePluginData() {
|
|
await this.saveData(this.data);
|
|
}
|
|
showRibbonIcon(status) {
|
|
if (!this.ribbonIcon) {
|
|
this.ribbonIcon = this.addRibbonIcon("SpacedRepIcon", t("REVIEW_CARDS"), async () => {
|
|
if (!this.osrAppCore.syncLock) {
|
|
await this.sync();
|
|
this.openFlashcardModal(
|
|
this.osrAppCore.reviewableDeckTree,
|
|
this.osrAppCore.remainingDeckTree,
|
|
1 /* Review */
|
|
);
|
|
}
|
|
});
|
|
}
|
|
if (status) {
|
|
this.ribbonIcon.style.display = "";
|
|
} else {
|
|
this.ribbonIcon.style.display = "none";
|
|
}
|
|
}
|
|
showStatusBar(status) {
|
|
if (!this.statusBar) {
|
|
this.statusBar = this.addStatusBarItem();
|
|
this.statusBar.classList.add("mod-clickable");
|
|
this.statusBar.setAttribute("aria-label", t("OPEN_NOTE_FOR_REVIEW"));
|
|
this.statusBar.setAttribute("aria-label-position", "top");
|
|
this.statusBar.addEventListener("click", async () => {
|
|
if (!this.osrAppCore.syncLock) {
|
|
await this.sync();
|
|
this.nextNoteReviewHandler.reviewNextNoteModal();
|
|
}
|
|
});
|
|
}
|
|
if (status) {
|
|
this.statusBar.style.display = "";
|
|
} else {
|
|
this.statusBar.style.display = "none";
|
|
}
|
|
}
|
|
};
|
|
/*! Bundled license information:
|
|
|
|
moment/moment.js:
|
|
(*! moment.js *)
|
|
(*! version : 2.30.1 *)
|
|
(*! authors : Tim Wood, Iskren Chernev, Moment.js contributors *)
|
|
(*! license : MIT *)
|
|
(*! momentjs.com *)
|
|
|
|
@kurkle/color/dist/color.esm.js:
|
|
(*!
|
|
* @kurkle/color v0.3.2
|
|
* https://github.com/kurkle/color#readme
|
|
* (c) 2023 Jukka Kurkela
|
|
* Released under the MIT License
|
|
*)
|
|
|
|
chart.js/dist/chunks/helpers.segment.js:
|
|
(*!
|
|
* Chart.js v4.4.4
|
|
* https://www.chartjs.org
|
|
* (c) 2024 Chart.js Contributors
|
|
* Released under the MIT License
|
|
*)
|
|
|
|
chart.js/dist/chart.js:
|
|
(*!
|
|
* Chart.js v4.4.4
|
|
* https://www.chartjs.org
|
|
* (c) 2024 Chart.js Contributors
|
|
* Released under the MIT License
|
|
*)
|
|
*/
|
|
|
|
|
|
/* nosourcemap */ |