Skip to content

Instantly share code, notes, and snippets.

@Fawers
Last active June 6, 2018 02:57
Show Gist options
  • Select an option

  • Save Fawers/6cf968d77e1796571d1d5762dc181f26 to your computer and use it in GitHub Desktop.

Select an option

Save Fawers/6cf968d77e1796571d1d5762dc181f26 to your computer and use it in GitHub Desktop.
WaniKani Reorder
/**
* 2018-04-25
* WaniKani Reorder - wkreorder
* Reorder your review items on the fly
* (Optimized for phones)
*
* With wk-reorder, you're able to - tada - reorder your review items by some criteria.
* As of this script, you're able to reorder them by SRS level, and type.
* The script works by getting your current queue, and applying a sort function to make it
* show items in the order you want them to - either ascendingly or descendingly.
* For this first version, there isn't a nice, clean UI from which you can select the
* ordering, but you'll be presented a prompt asking to enter how you want to order it.
* Type sorting order is radical, kanji, and then vocab items.
* Example sorting strings:
* ・ st
* ・ Sorts by SRS level, and type (all ascending)
* ・ t-s
* ・ Sorts by type ascending, and SRS level descending
* ・ -st
* ・ Sorts by SRS level descending, and type ascending.
* By default, readings will come first and meanings second. Radicals are meaning-only
* items.
*/
// Item types
var RADICAL = 'rad',
KANJI = 'kan',
VOCABULARY = 'voc';
// Question types
var READING = 'reading', // N/A for radicals
MEANING = 'meaning';
// Sorting regex
var SORTING_PATTERN = /-?[st]/g;
function WaniKaniReorder() {
this.repeatCurrentItem = false;
this.items = null;
this.currentItem = null;
this.currentQType = null;
this.lastUpdated = 0;
}
WaniKaniReorder.prototype.init = function() {
var aq = $.jStorage.get('activeQueue'),
rq = $.jStorage.get('reviewQueue');
var sorting;
this.items = aq.concat(rq);
$.jStorage.listenKeyChange('currentItem', this.setItem.bind(this));
$.jStorage.listenKeyChange('wrongCount', this.flagWrongItem.bind(this));
sorting = (function() {
var userInput;
do {
userInput = prompt(
'Tell me your sorting method.', 'ts').match(SORTING_PATTERN) || [];
} while (userInput.length !== 2);
return userInput;
})();
this.sort(sorting);
}
WaniKaniReorder.prototype.setItem = function() {
// since this method changes the current item, it triggers itself.
// this.lastUpdated is here to prevent just that.
var now = new Date().getTime();
if ((now - this.lastUpdated) <= 600) return;
this.lastUpdated = now;
// on the occasion of an item being answered wrongly, this.repeatCurrentItem
// will be set to true. this section handles it, and also sets repeatCurrentItem
// back to false.
if (this.repeatCurrentItem) {
$.jStorage.set('questionType', this.currentQType);
$.jStorage.set('currentItem', this.currentItem);
this.repeatCurrentItem = false;
return;
}
if (!this.currentItem) { // first run
this.currentItem = this.items.shift();
this.currentQType = this.currentItem[RADICAL] ? MEANING : READING;
$.jStorage.set('questionType', this.currentQType);
$.jStorage.set('currentItem', this.currentItem);
return;
}
if (!this.currentItem[RADICAL]) {
if (this.currentQType === READING) {
this.currentQType = MEANING;
}
else {
this.removeCurrentFromQueue();
this.currentItem = this.items.shift() || {};
this.currentQType = this.currentItem[RADICAL] ? MEANING : READING;
}
}
else {
this.removeCurrentFromQueue();
this.currentItem = this.items.shift() || {};
this.currentQType = this.currentItem[RADICAL] ? MEANING : READING;
}
$.jStorage.set('questionType', this.currentQType);
$.jStorage.set('currentItem', this.currentItem);
}
WaniKaniReorder.prototype.flagWrongItem = function() {
this.repeatCurrentItem = true;
}
WaniKaniReorder.prototype.removeCurrentFromQueue = function() {
// because items are not actually removed from WaniKani's queue,
// so we do it ourselves.
// (context: WaniKani auto-removes items from its ACTIVE queue. it doesn't
// "know" the user is answering items not present in ↑it↑.)
var rq = $.jStorage.get('reviewQueue');
$.jStorage.set('reviewQueue', rq.filter((function(i) {
return i.id !== this.currentItem.id;
}).bind(this)));
}
WaniKaniReorder.prototype.sort = function(sortingOrder) {
var SRSWeight = 0,
typeWeight = 0;
var badSortingOrder = function () { alert('Bad sorting order.'); throw new Error('Bad sorting order.'); };
sortingOrder.forEach(function(item, position) {
var weight = position === 0 ? 10 : 1;
if (item.indexOf('s') !== -1 && SRSWeight === 0) {
SRSWeight = item[0] === '-' ? -weight : weight;
}
else if (item.indexOf('t') !== -1 && typeWeight === 0) {
typeWeight = item[0] === '-' ? -weight : weight;
}
else {
badSortingOrder();
}
});
this.items.sort(function(a, b) {
var itemOrder = 0, s, t;
if (a.srs < b.srs) {
s = -1;
}
else if (a.srs > b.srs) {
s = 1;
}
else {
s = 0;
}
if (a[RADICAL] && !b[RADICAL] || a[KANJI] && b[VOCABULARY]) {
t = -1;
}
else if (b[RADICAL] && !a[RADICAL] || b[KANJI] && a[VOCABULARY]) {
t = 1;
}
else {
t = 0;
}
return s * SRSWeight + t * typeWeight;
});
}
wkr = new WaniKaniReorder();
wkr.init();
wkr.setItem();
javascript:var RADICAL="rad",KANJI="kan",VOCABULARY="voc",READING="reading",MEANING="meaning",SORTING_PATTERN=/-?[st]/g;function WaniKaniReorder(){this.repeatCurrentItem=!1,this.items=null,this.currentItem=null,this.currentQType=null,this.lastUpdated=0}WaniKaniReorder.prototype.init=function(){var t,e=$.jStorage.get("activeQueue"),r=$.jStorage.get("reviewQueue");this.items=e.concat(r),$.jStorage.listenKeyChange("currentItem",this.setItem.bind(this)),$.jStorage.listenKeyChange("wrongCount",this.flagWrongItem.bind(this)),t=function(){for(var t;2!==(t=prompt("Tell me your sorting method.","ts").match(SORTING_PATTERN)||[]).length;);return t}(),this.sort(t)},WaniKaniReorder.prototype.setItem=function(){var t=(new Date).getTime();if(!(t-this.lastUpdated<=600)){if(this.lastUpdated=t,this.repeatCurrentItem)return $.jStorage.set("questionType",this.currentQType),$.jStorage.set("currentItem",this.currentItem),void(this.repeatCurrentItem=!1);if(!this.currentItem)return this.currentItem=this.items.shift(),this.currentQType=this.currentItem[RADICAL]?MEANING:READING,$.jStorage.set("questionType",this.currentQType),void $.jStorage.set("currentItem",this.currentItem);this.currentItem[RADICAL]?(this.removeCurrentFromQueue(),this.currentItem=this.items.shift()||{},this.currentQType=this.currentItem[RADICAL]?MEANING:READING):this.currentQType===READING?this.currentQType=MEANING:(this.removeCurrentFromQueue(),this.currentItem=this.items.shift()||{},this.currentQType=this.currentItem[RADICAL]?MEANING:READING),$.jStorage.set("questionType",this.currentQType),$.jStorage.set("currentItem",this.currentItem)}},WaniKaniReorder.prototype.flagWrongItem=function(){this.repeatCurrentItem=!0},WaniKaniReorder.prototype.removeCurrentFromQueue=function(){var t=$.jStorage.get("reviewQueue");$.jStorage.set("reviewQueue",t.filter(function(t){return t.id!==this.currentItem.id}.bind(this)))},WaniKaniReorder.prototype.sort=function(t){var n=0,s=0;t.forEach(function(t,e){var r=0===e?10:1;-1!==t.indexOf("s")&&0===n?n="-"===t[0]?-r:r:-1!==t.indexOf("t")&&0===s?s="-"===t[0]?-r:r:function(){throw alert("Bad sorting order."),new Error("Bad sorting order.")}()}),this.items.sort(function(t,e){var r,i;return r=t.srs<e.srs?-1:t.srs>e.srs?1:0,i=t[RADICAL]&&!e[RADICAL]||t[KANJI]&&e[VOCABULARY]?-1:e[RADICAL]&&!t[RADICAL]||e[KANJI]&&t[VOCABULARY]?1:0,r*n+i*s})},wkr=new WaniKaniReorder,wkr.init(),wkr.setItem();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment