// ==UserScript==
// @name WaniKani Open Framework Date Filters
// @namespace https://www.wanikani.com
// @description Additional date filters for the WaniKani Open Framework
// @author prouleau
// @version 1.3.1
// @include https://www.wanikani.com/*
// @license MIT; http://opensource.org/licenses/MIT
// @grant none
// ==/UserScript==
(function(wkof) {
'use strict';
var wkofMinimumVersion = '1.0.52';
if (!wkof) {
var response = confirm('WaniKani Open Framework Date Filters requires WaniKani Open Framework.\n Click "OK" to be forwarded to installation instructions.');
if (response) {
window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
}
return;
}
var settingsDialog;
var settingsScriptId = 'dateFilters';
var settingsTitle = 'Date Filters';
var needToRegisterFilters = true;
var filterNamePrefix = 'dateFilters_';
var reviewIsScheduledFilterName = filterNamePrefix + 'reviewIsScheduled';
var reviewAfterFilterName = filterNamePrefix + 'reviewAfter';
var reviewBeforeFilterName = filterNamePrefix + 'reviewBefore';
var hadLastReviewFilterName = filterNamePrefix + 'hadLastReviewScheduled';
var lastReviewAfterFilterName = filterNamePrefix + 'lastReviewAfter';
var lastReviewBeforeFilterName = filterNamePrefix + 'lastReviewBefore';
var hadLessonFilterName = filterNamePrefix + 'hadLesson';
var lessonAfterFilterName = filterNamePrefix + 'lessonAfter';
var lessonBeforeFilterName = filterNamePrefix + 'lessonBefore';
var hadPassedGuruFilterName = filterNamePrefix + 'hadPassedGuru';
var passedGuruAfterFilterName = filterNamePrefix + 'passedGuruAfter';
var passedGuruBeforeFilterName = filterNamePrefix + 'passedGuruBefore';
var burnedAfterFilterName = filterNamePrefix + 'burnedAfter';
var burnedBeforeFilterName = filterNamePrefix + 'burnedBefore';
var hadResurrectedFilterName = filterNamePrefix + 'hadResurrected';
var resurrectedAfterFilterName = filterNamePrefix + 'resurrectedAfter';
var resurrectedBeforeFilterName = filterNamePrefix + 'resurrectedBefore';
var isUnlLockedFilterName = filterNamePrefix + 'isUnlocked';
var unlockedAfterFilterName = filterNamePrefix + 'unlockedAfter';
var unlockedBeforeFilterName = filterNamePrefix + 'unlockedBefore';
var supportedFilters = [reviewIsScheduledFilterName, reviewAfterFilterName, reviewBeforeFilterName, hadLessonFilterName, lessonAfterFilterName, lessonBeforeFilterName,
hadPassedGuruFilterName, passedGuruAfterFilterName, passedGuruBeforeFilterName, burnedAfterFilterName, burnedBeforeFilterName,
hadResurrectedFilterName, resurrectedAfterFilterName, resurrectedBeforeFilterName,
isUnlLockedFilterName, unlockedAfterFilterName, unlockedBeforeFilterName,
hadLastReviewFilterName, lastReviewAfterFilterName, lastReviewBeforeFilterName];
function updateFiltersWhenReady() {
wkof.set_state(settingsScriptId, 'loading');
needToRegisterFilters = true;
waitForItemDataRegistry().then(registerFilters);
}
function waitForItemDataRegistry() {
return wkof.wait_state('wkof.ItemData.registry', 'ready');
}
function registerFilters() {
if (!needToRegisterFilters) {
return;
}
supportedFilters.forEach(function(filterName) {
delete wkof.ItemData.registry.sources.wk_items.filters[filterName];
});
registerReviewIsScheduledFilter();
registerReviewAfterFilter();
registerReviewBeforeFilter();
registerHadLastReviewFilter();
registerLastReviewAfterFilter();
registerLastReviewBeforeFilter();
registerHadLessonFilter();
registerLessonAfterFilter();
registerLessonBeforeFilter();
registerHadPassedGuruFilter();
registerPassedGuruAfterFilter();
registerPassedGuruBeforeFilter();
registerBurnedAfterFilter();
registerBurnedBeforeFilter();
registerHadResurrectedFilter();
registerResurrectedAfterFilter();
registerResurrectedBeforeFilter();
registerHadUnlockedFilter();
registerUnockedAfterFilter();
registerUnockedBeforeFilter();
needToRegisterFilters = false;
wkof.set_state(settingsScriptId, 'ready');
}
//=======================================
// Date Validation and Parsing Functions
//=======================================
//=======================================
// All time validation functions and the parsing function accept
// YYYY-MM-DD 24:00 to mean next day at 00:00
// According to wikipedia this is part of the 24 hours time comvention
//=======================================
//=======================================
// This group of functions nails the format to YYYY-MM-DD something
//=======================================
// Error messages
const errorWrongDateTimeFormat = 'Use YYYY-MM-DD HH:MM [24h, 12h]';
const errorWrongDateTimeRelativeFormat = 'Use YYYY-MM-DD HH:MM [24h, 12h]<br>Or +10d3h45m or -4h12h30m<br>+- needed, rest may be omitted';
const errorWrongDateTimeFullFormat = 'Use YYYY-MM-DD HH:MM:SS.mmm<br>Seconds and milliseconds optional';
const errorWrongDateTimeFullRelativeFormat = 'Use YYYY-MM-DD HH:MM:SS.mmm<br>Seconds and milliseconds optional<br>Or +10d3h45m12s -4h12h30m10s<br>+- needed, rest may be omitted';
const errorWrongDateFormat = 'Invalid date - Use YYYY-MM-DD';
const errorWrongDateRelativeFormat = 'Invalid date - Use YYYY-MM-DD<br>Or +10d or -2d';
const errorOutOfRange = 'Number out of range';
//=======================================
// Validates datetime in YYYY-MM-DD HH:MM format
// Accepts both 24h and 12h formats (am pm)
// Accepts YYYY-MM-DD (HH:MM omitted)
// Bissextile years are properly processed
// Suitable for use as validate callback in a text component of a setting
function validateDateTime(dateString, config){
dateString = dateString.trim();
if (dateString.length > 18){
return errorWrongDateTimeFormat;
} else {
let result = validateDate(dateString.slice(0,10), config);
if (result === errorOutOfRange) return errorOutOfRange;
if (result !== true) return errorWrongDateTimeFormat;
if (dateString.length === 10) return true; //Valid YYY-MM-DD and nothing else
result = validateTime(dateString.slice(0,16));
if (result === errorOutOfRange) return errorOutOfRange;
if (result !== true) return errorWrongDateTimeFormat;
if (dateString.length === 16){
return true
} else {
if (dateString.length === 18){
let suffix = dateString.slice(16)
if (suffix === 'am' || suffix === 'pm'){
let hh = Number(dateString.slice(11, 13))
if (hh < 1 || hh > 12){return errorOutOfRange}
return true
} else {
return errorWrongDateTimeFormat;
}
}
return errorWrongDateTimeFormat;
};
};
return errorWrongDateTimeFormat;
};
//=======================================
// Validates datetime in YYYY-MM-DD HH:MM format or relative time format
// Accepts both 24h and 12h formats (am pm)
// Accepts YYYY-MM-DD (HH:MM omitted)
// Bissextile years are properly processed
// Suitable for use as validate callback in a text component of a setting
function validateDateTimeRelative(dateString, config){
dateString = dateString.trim();
if (dateString.match(/^([+-])(?:(\d+)[dD])?(?:(\d+)[hH])?(?:(\d+)[mM])?$/) !== null){
if (dateString === '+' || dateString === '-') return errorWrongDateTimeRelativeFormat
return true;
} else {
let result = validateDateTime(dateString, config)
if (result === true || result === errorOutOfRange) return result;
return errorWrongDateTimeRelativeFormat;
}
};
//=======================================
// Validates dates in YYYY-MM-DD format
// Bissextile years are properly processed
// Suitable for use as validate callback in a text component of a setting
function validateDate(dateString, config, keyword) {
dateString = dateString.trim();
let regEx = /^\d{4}-\d{2}-\d{2}$/;
if(!dateString.match(regEx)) return errorWrongDateFormat; // Invalid format
let d = new Date(dateString);
let dNum = d.getTime();
if(!dNum && dNum !== 0) return errorOutOfRange; // NaN value, Invalid date
let r = d.toISOString().slice(0,10) === dateString;
if (r) {
return true
} else {
return errorOutOfRange
};
}
//=======================================
// Helper function to validate time in HH:MM format
// It should not be publicly exposed
function validateTime(timeString) {
let regEx = /^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/;
if(!timeString.match(regEx)) return 'No match'; // Invalid format
let d = new Date(timeString);
let dNum = d.getTime();
if(!dNum && dNum !== 0) return errorOutOfRange; // NaN value, Invalid date
return true
}
//=======================================
// Parses a validated date in YYYY-MM-DD format
// Also parse a validated datetime in YYYY-MM-DD HH:MM format
// Parses datetime in both 12h and 24h formats
// Parses optional seconds and milliseconds
// Returns the corresponding date object for this date/datetime in the local time zone
// May return an invalid date if presented with empty or invalid data - but not always
// If there is doubt about the quality of the data, validate first
// Suitable to parse a validated date from a text component in a setting
function parseDateTime(dateString) {
dateString = dateString.trim(); // validation allows leading and trailing blanks
try {
if (dateString === '') return new Date('###'); // returns an invalid date
let match = dateString.match(/^([+-])(?:(\d+)[dD])?(?:(\d+)[hH])?(?:(\d+)[mM])?(?:(\d+)[sS])?$/);
if (match !== null){
if (dateString === '+' || dateString === '-') return new Date('###'); // returns an invalid date
let date = Date.now();
let sign = (match[1] === '+' ? 1 : -1);
let days = (match[2] || 0) * 86400000;
let hrs = (match[3] || 0) * 3600000;
let min = (match[4] || 0) * 60000;
let sec = (match[5] || 0) * 1000;
return new Date(date + sign * (days + hrs + min + sec));
}
// new Date() uses local time zone when the parameters are separated
let YY = Number(dateString.substring(0, 4));
let MM = Number(dateString.substring(5, 7))-1;
let DD = Number(dateString.substring(8, 10));
let hh = (dateString.length >= 13) ? Number(dateString.substring(11, 13)) : 0;
let mm = (dateString.length >= 16) ? Number(dateString.substring(14, 16)) : 0;
let ss = (dateString.length >= 19) ? Number(dateString.substring(17, 19)) : 0;
let ml = (dateString.length === 23) ? Number(dateString.substring(20, 23)) : 0;
let suffix = (dateString.length === 18) ? dateString.substring(16, 18) : ''
if (suffix === 'am' || suffix === 'pm'){ // if 12 hours format, convert to 24 hours
if (hh === 12) hh = 0;
if (suffix === 'pm') hh += 12;
}
return new Date(YY, MM, DD, hh, mm, ss, ml);
} catch (e) {
return new Date('###'); // returns an invalid date in case of error
}
}
function filter_value_map_wrapper(funct){
return function(param){return funct(param).getTime()}
}
// BEGIN Reviews
let reviewIsScheduledHover_tip = 'If checked selects items for which a review is scheduled.\nIf unchecked selects the items for which no review is scheduled.';
let reviewAfterFilterHover_tip = 'Selects items whose review date is at or after this date';
let reviewBeforeFilterHover_tip = 'Selects items whose review date is at or before this date';
function registerReviewIsScheduledFilter() {
wkof.ItemData.registry.sources.wk_items.filters[reviewIsScheduledFilterName] = {
type: 'checkbox',
label: 'Review Is Scheduled',
default: true,
filter_func: reviewIsScheduledFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: reviewIsScheduledHover_tip,
};
}
function reviewIsScheduledFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
};
return filterValue ? (item.assignments.available_at !== null) : (item.assignments.available_at === null);
}
function registerReviewAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[reviewAfterFilterName] = {
type: 'text',
label: 'Review After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: reviewAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: reviewAfterFilterHover_tip,
};
}
function reviewAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.available_at === null) {
return false;
}
let d = new Date(item.assignments.available_at)
d = d.getTime();
return d >= filterValue;
}
function registerReviewBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[reviewBeforeFilterName] = {
type: 'text',
label: 'Review Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: reviewBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: reviewBeforeFilterHover_tip,
};
}
function reviewBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.available_at === null) {
return false;
}
let d = new Date(item.assignments.available_at)
d = d.getTime();
return d <= filterValue;
}
// END Reviews
// BEGIN Last Reviews
const regularSrsIntervals = [0, 4, 8, 23, 47, 167, 335, 719, 2879];
const acceleratedSrsIntervals = [0, 2, 4, 8, 23, 167, 335, 719, 2879];
const acceleratedLevels = [1, 2];
function computeLastReviewDate(item){
let srsStage = item.assignments.srs_stage;
if (srsStage === 0 || srsStage === 9) return false;
let srsInvervals = acceleratedLevels.includes(item.data.level) ? acceleratedSrsIntervals : regularSrsIntervals;
let deltaTime = parseInt(srsInvervals[srsStage]) * 1000 * 60 * 60; // convert hours to in milliseconds
return new Date(item.assignments.available_at) - deltaTime;
}
let hadLastReviewHover_tip = 'If checked selects items for which you had a review.\nIf unchecked selects the items for which you never had a review.';
let lastReviewAfterFilterHover_tip = 'Selects items whose last review date is at or after this date';
let lastReviewBeforeFilterHover_tip = 'Selects items whose last review date is at or before this date';
function registerHadLastReviewFilter() {
wkof.ItemData.registry.sources.wk_items.filters[hadLastReviewFilterName] = {
type: 'checkbox',
label: 'Had a Review',
default: true,
filter_func: hadLastReviewFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: hadLastReviewHover_tip,
};
}
function hadLastReviewFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
};
return filterValue ? (item.assignments.available_at !== null) : (item.assignments.available_at === null);
}
function registerLastReviewAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[lastReviewAfterFilterName] = {
type: 'text',
label: 'Last Review After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: lastReviewAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: lastReviewAfterFilterHover_tip,
};
}
function lastReviewAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.available_at === null) {
return false;
}
let d = computeLastReviewDate(item);
if (d === false) return false;
return d >= filterValue;
}
function registerLastReviewBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[lastReviewBeforeFilterName] = {
type: 'text',
label: 'Last Review Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: lastReviewBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: lastReviewBeforeFilterHover_tip,
};
}
function lastReviewBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.available_at === null) {
return false;
}
let d = computeLastReviewDate(item);
if (d === false) return false;
return d <= filterValue;
}
// END Last Reviews
// BEGIN Lessons
let hadLessonFilterHover_tip = 'If checked selects items for which a lesson has been taken.\nIf unchecked selects the items for which no lesson were taken.';
let lessonAfterFilterHover_tip = 'Selects items whose lesson date is at or after this date';
let lessonBeforeFilterHover_tip = 'Selects items whose lesson date is at or before this date';
function registerHadLessonFilter() {
wkof.ItemData.registry.sources.wk_items.filters[hadLessonFilterName] = {
type: 'checkbox',
label: 'Had Lessons',
default: true,
filter_func: hadLessonFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: hadLessonFilterHover_tip,
};
}
function hadLessonFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
}
return filterValue ? (item.assignments.started_at !== null) : (item.assignments.started_at === null);
}
function registerLessonAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[lessonAfterFilterName] = {
type: 'text',
label: 'Lesson After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: lessonAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: lessonAfterFilterHover_tip,
};
}
function lessonAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.started_at === null) {
return false;
}
let d = new Date(item.assignments.started_at)
d = d.getTime()
return d >= filterValue;
}
function registerLessonBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[lessonBeforeFilterName] = {
type: 'text',
label: 'Lesson Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: lessonBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: lessonBeforeFilterHover_tip,
};
}
function lessonBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.started_at === null) {
return false;
}
let d = new Date(item.assignments.started_at)
d = d.getTime()
return d <= filterValue;
}
// END Lessons
// BEGIN Passed Guru
let hadPassedGuruFilterHover_tip = 'If checked selects items that have passed guru.\nIf unchecked selects the items that have never passed guru.';
let passedGuruAfterFilterHover_tip = 'Selects items whose passed guru date is at or after this date';
let passedGuruBeforeFilterHover_tip = 'Selects items whose passed guru date is at or before this date';
function registerHadPassedGuruFilter() {
wkof.ItemData.registry.sources.wk_items.filters[hadPassedGuruFilterName] = {
type: 'checkbox',
label: 'Had Passed Guru',
default: true,
filter_func: hadPassedGuruFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: hadPassedGuruFilterHover_tip,
};
}
function hadPassedGuruFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
}
return filterValue ? (item.assignments.passed_at !== null) : (item.assignments.passed_at === null);
}
function registerPassedGuruAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[passedGuruAfterFilterName] = {
type: 'text',
label: 'Passed Guru After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: passedGuruAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: passedGuruAfterFilterHover_tip,
};
}
function passedGuruAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.passed_at === null) {
return false;
}
let d = new Date(item.assignments.passed_at)
d = d.getTime()
return d >= filterValue;
}
function registerPassedGuruBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[passedGuruBeforeFilterName] = {
type: 'text',
label: 'Passed Guru Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: passedGuruBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: passedGuruBeforeFilterHover_tip,
};
}
function passedGuruBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.passed_at === null) {
return false;
}
let d = new Date(item.assignments.passed_at)
d = d.getTime()
return d <= filterValue;
}
// END Passed Guru
// BEGIN Burned
//let hadPassedGuruFilterHover_tip = 'If checked selects items that have passed guru.\nIf unchecked selects the items that have never passed guru.';
let burnedAfterFilterHover_tip = 'Selects items who were burned at or after this date';
let burnedBeforeFilterHover_tip = 'Selects items who were burned at or before this date';
function registerBurnedAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[burnedAfterFilterName] = {
type: 'text',
label: 'Burned After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: burnedAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: burnedAfterFilterHover_tip,
};
}
function burnedAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.burned_at === null) {
return false;
}
let d = new Date(item.assignments.burned_at)
d = d.getTime()
return d >= filterValue;
}
function registerBurnedBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[burnedBeforeFilterName] = {
type: 'text',
label: 'Burned Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: burnedBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: burnedBeforeFilterHover_tip,
};
}
function burnedBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.burned_at === null) {
return false;
}
let d = new Date(item.assignments.burned_at)
d = d.getTime()
return d <= filterValue;
}
// END Burned
// BEGIN Resurrected
let hadResurrectedFilterHover_tip = 'If checked selects items that have been resurrected.\nIf unchecked selects the items that have never been resurrected.';
let resurrectedAfterFilterHover_tip = 'Selects items who were resurrected at or after this date';
let resurrectedBeforeFilterHover_tip = 'Selects items who were resurrected at or before this date';
function registerHadResurrectedFilter() {
wkof.ItemData.registry.sources.wk_items.filters[hadResurrectedFilterName] = {
type: 'checkbox',
label: 'Has Been Resurrected',
default: true,
filter_func: hadResurrectedFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: hadResurrectedFilterHover_tip,
};
}
function hadResurrectedFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
}
return filterValue ? (item.assignments.resurrected_at !== null) : (item.assignments.resurrected_at === null);
}
function registerResurrectedAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[resurrectedAfterFilterName] = {
type: 'text',
label: 'Resurrected After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: resurrectedAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: resurrectedAfterFilterHover_tip,
};
}
function resurrectedAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.resurrected_at === null) {
return false;
}
let d = new Date(item.assignments.resurrected_at)
d = d.getTime()
return d >= filterValue;
}
function registerResurrectedBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[resurrectedBeforeFilterName] = {
type: 'text',
label: 'Resurrected Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: resurrectedBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: resurrectedBeforeFilterHover_tip,
};
}
function resurrectedBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.resurrected_at === null) {
return false;
}
let d = new Date(item.assignments.resurrected_at)
d = d.getTime()
return d <= filterValue;
}
// END Resurrected
// BEGIN Unlocked
let hadUnlockedFFilterHover_tip = 'If checked selects items that have been unlocked.\nIf unchecked selects the items that are locked.';
let unlockedAfterFilterHover_tip = 'Selects items who were unlocked at or after this date';
let unlockedBeforeFilterHover_tip = 'Selects items who were unlocked at or before this date';
function registerHadUnlockedFilter() {
wkof.ItemData.registry.sources.wk_items.filters[isUnlLockedFilterName] = {
type: 'checkbox',
label: 'Has Been Unlocked',
default: true,
filter_func: hadUnlockedFilter,
set_options: function(options) { options.assignments = true; },
hover_tip: hadUnlockedFFilterHover_tip,
};
}
function hadUnlockedFilter(filterValue, item) {
if (item.assignments === undefined) {
return !filterValue;
}
return filterValue ? (item.assignments.unlocked_at !== null) : (item.assignments.unlocked_at === null);
}
function registerUnockedAfterFilter() {
wkof.ItemData.registry.sources.wk_items.filters[unlockedAfterFilterName] = {
type: 'text',
label: 'Unlocked After',
default: '2000-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: unlockedAfterFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: unlockedAfterFilterHover_tip,
};
}
function unlockedAfterFilter(filterValue, item) {
if (item.assignments === undefined) {
return false;
}
if (item.assignments.unlocked_at === null) {
return false;
}
let d = new Date(item.assignments.unlocked_at)
d = d.getTime()
return d >= filterValue;
}
function registerUnockedBeforeFilter() {
wkof.ItemData.registry.sources.wk_items.filters[unlockedBeforeFilterName] = {
type: 'text',
label: 'Unlocked Before',
default: '2100-01-01',
placeholder: 'YYYY-MM-DD HH:MM [24h 12h]',
validate: validateDateTimeRelative,
filter_func: unlockedBeforeFilter,
filter_value_map: filter_value_map_wrapper(parseDateTime),
set_options: function(options) { options.assignments = true; },
hover_tip: unlockedBeforeFilterHover_tip,
};
}
function unlockedBeforeFilter(filterValue, item) {
let r = new Date(filterValue);
if (item.assignments === undefined) {
return false;
}
if (item.assignments.unlocked_at === null) {
return false;
}
let d = new Date(item.assignments.unlocked_at)
d = d.getTime()
return d <= filterValue;
}
// END Unlocked
updateFiltersWhenReady();
})(window.wkof);