Set your custom intervals and export a spaced repetitions calendar in ics format
online: https://tsaihsing3.github.io/Spaced_Repetition2.ics/
Hermann Ebbinghaus indentified Spacing Effect and published his well-known Forgetting Curve in 1885. Numerous further studies together with learning techniques and tools based on this effect —— Spaced repetition —— have thrived ever since.
According to Spaced Repetition Method, learners shall repeatly relearn the learning material after certain time intervals. ( Actival Recall Principle is often adviced for effectiv re-learning)
Both expanding and uniform interval could be adopted in Spaced Repetition.
- Hermann Ebbinghaus tested 20 minutes,1 hour, 9 hours, 1 day, 2 days, 6 days and 31 days intervals in his work;
- Paul Pimsleur set intervals as 5 seconds, 25 seconds, 2 minutes, 10 minutes, 1 hour, 5 hours, 1 day, 5 days, 25 days, 4 months, and 2 years;
- Interval pattern 12 hours, 1 day, 2 days, 4 days, 7 days, 15 days is introduced for GRE vocabulary recognition by Yang Peng in his best-selling Nailing GRE Words in 17 Day ;
Those 3 interval patterns are already preset so you can choose them via a radio section yet repetitions within a day or longer than a year is neglected. Besides custom 4. uniform intervals or 5. expanding (even shrinking) intervals are also allowed.
A standard canlendar file (.ics) would be generated and exported via this lightweight tool.
If you need only custom uniform intervals, a much easier way is to directly create recurring events in your calendar service. Offical instruction links for recurring event in some popluar calenar services are as follows:
- Google Calendar : Create a recurring event
- Outlook : Schedule repeating appointments as recurring events in Outlook
- Apple Calendar :Add an event to a calendar on iCloud.com
If you are looking for learning more than 100 words each day intensively, tools developed based on GRE Words in 17 Day Method(17GRE) are recommended. 17GRE Method allows you to set a series of tasks (so called "lists") that start sequentialy.
Also, Spaced Repetition software programs as Anki, SuperMemo, etc dynamicsly set subsequent intervals based on recall tests' performance. However tests and performance results are not considered in this tool.
This tool is featured to set custom non-uniform intervals.
For example, to learn 4 times within 10 days,‘1,3,5', '2,3,3','1,5,2' (days) or any interval pattern you like can be processed.
A 'day' as the unit, all repetitions ( relearning ) would be created as a all-day event( VEVENT
item in iCalendar Format Standard), task' name and repetition's time count in the event's 'summary' ( SUMMARY
Property). All events are wrapped in a calendar called 'Spaced Repetition'( VCALENDAR
item) to be downloaded as a file named 'Spaced_Repetition.ics'
- Add a Task
- Preview in Tasks List
- Each coloured list item include a task's name, start date and repetition times( learning + re-learning ).
- Preview in a 5-week Calendar
- Weeks start on a Monday, which is in the same week with the Calendar's start date.
- Repetitions in the range of display would be listed on the right to their date.
- repetitions out of the range exist and are included in the exported ics file. If need, change the calendar's display range to see them.
- Modify the calendar's Start Date and click button to change the calendar's display range .
- Export .ics file
- Import to Any Calendar Service You Like.
- Although
COLOR
Property is defined and can be used on aVEVENT
item since rfc7986(2016) , colours are always used to distinguish different calendars in commen calendar services. Therefore usually events' colours are not displayed.
- Although
This tool is based on Javascript. Scripts are placed at the <head>
part of the page. Data is processed by users' browsers at the front-end. Bootstrap is used for decoration.
- A
tasks
Array is created to storetask
objects in the future - A
tasksContent
Array is created to store content required for a .ics file needs. - When the window is loaded, call three functions as Initialization.
//the new task is given a random CSS3 Standard colour
setEventColor();
//set task's and calendar's default start date as today
setStartDate();
//find the monday when this first week begins
//delete ,if any, all displayed dates and list all new 7 * 5 = 35 dates
updateCal();
At the end of updateCal()
function, an addCalEvent()
function is called to process tasks
Array's items. tasks
being void so far, this call has no effect.
Only names of CSS3 standard colours are supported in iCalendar standard as value of the COLOR
Property for event VEVENT.
A addTask()
function is called when button is clicked.
- A
task
object is created. Data would be stored as its attributes. - To begin with, its
name
,color
,startDate
attributes are attained throughdocument.getElementById()
.
let taskName = document.getElementById("inputTaskName").value;
let taskColor = document.getElementById("inputTaskColor").innerHTML;
//get startDate
let startDateString = document.getElementById("inputStartDate").value;
var startDate1 = new Date();
startDate1.setFullYear(startDateString.slice(0,4), startDateString.slice(4,6) - 1, startDateString.slice(6,8));
- For the
intervals
attribute, radios are iterated.id
of the checked radio reveals the interval pattern selected and, if custom interval pattern, other necessary parameter(s).
let radios = document.getElementsByName("selectInterval");
var intervalArray = new Array();
for (var i = 0; i < radios.length; i++)
{
if(radios[i].checked == true)
{
let inputInterval = radios[i];
if a programmed interval mode
if (["Ebbinghaus","Pimsleur","17gre"].indexOf(radios[i].id) > -1 ){
...
}
else if ( radios[i].id == "UniformIntervalsRadio"){
...
}
else if (radios[i].id == "CustomIntervalsRadio" ){
...
}
}
}
- Via methods of
Date
Objects in JavaScript, dates for relearning is calculated. Dates for learning(Start Date) and for relearning are then stored intask["repetitions"]
. - The
task
object is pushed to a Array namedtasks
for later use.
tasks.push(task);
setEventColor()
is called again to generate a new random colour for the next task.
Afterwards task's information is displayed in two preview sections.
The Task List section is a Bootstrap card
component.
<div class="card col-4" style="width: 18rem;" >
<div class="card-header bg-transparent text-center mb-2" >Tasks</div>
<div>
<ul class="list-group mb-3 list-group-flush" id="tasksList">
<li class="list-group-item">Task Name-StartDate
<span class="badge">repetition times</span>
</li>
</ul>
</div>
...
</div>
To update this card
, addTask()
calls a addTaskList()
function, passing the task
object as a parameter.
addTaskList(task);
addTask()
function do as follows:
- find the
<ul>
element whoseid
="tasksList"
. - create s new
<li>
element that includes name, start date, repetition times of the task.
HTML code required:
<li class="list-group-item">Task Name-StartDate<span class="badge">repetition times </span> </li>
JavaScript code:
let taskListItem = document.createElement("li");
taskListItem.innerHTML = task["name"] +"-" +formatDate(task["startDate"]);
var classNode = document.createAttribute("class");
classNode.value = "list-group-item";
taskListItem.setAttributeNode(classNode);
// add a badge display
var spanNode = document.createElement("span");
var classNode = document.createAttribute("class");
classNode.value = "badge";
spanNode.innerHTML = (task.repetitions.length ).toString();
spanNode.setAttributeNode(classNode);
- Insert the
<li>
element as child of the<ul>
element.
This calendar is a Bootstrap card-group
component, in which there is 5 card
components. Each components represents a week. All 35 days' date has been inserted in Initialization step and marked with id
.
<tbody id="week1body">
<tr>
<th scope="row" id="20200601th">06.01</th>
<td id="20200601td" style="color: purple;">Biology(1)</td>
</tr>
<tr>
<th scope="row" id="20200602th">06.02</th>
</tr>
...
</tbody>
To update these card
s, addTask()
calls a addCalEvent()
function, passing a task
object as a parameter
addCalEvent(task);
addCalEvent()
function do as follows:
- Iterate
<td>
element for whoseid
indicates that the day of the repetition is shown on the calendar, i.e. this repetition date is (1)inside the range of calendar preview and (2) there is/are already repetition(s) on the same day. - if the
<td>
element is found:- Generate a
<tr>
element with a void<th>
child element and a<td>
child element that contains this repetition's information. - Insert this new
<tr>
element after the parent<tr>
element of the found<td>
element.
- Generate a
- if the
<td>
element is not found yet a<th>
element represent the same day is found, i.e. the day this repetition date is inside the range but this day has no repetition yet.- Generate a
<td>
element that contains this repetition's information - Insert this new
<td>
element after the found<th>
element.
- Generate a
The <td>
element, if inserted, should look like this:
<td id="20200601td" style="color: purple;">Biology(3)</td>
Modify the Calendar's Start Date and click button.
A updateCal()
function is called. It would :
<table class="table table-borderless week-table" >
<thead>
<tr>
<th scope="col">Day</th>
<th scope="col">Task</th>
</tr>
</thead>
<tbody id="week1body">
<!-- Old Dates Elements Begin Here -->
<tr>
<th scope="row" id="20200601th">06.01</th>
<td id="20200601td" style="color: purple;">Biology(1)</td>
</tr>
...
<!-- Old Dates Elements End Here -->
</tbody>
</table>
- Delete displayed dates and other items by removing everthing inside the
<tbody>
tags.
weekDates = new Array();
var weekbody = document.getElementById("week"+(i+1)+"body");
// remove all children elements
weekbody.innerHTML = ""
- New 7 * 5 = 35 dates are displayed by inserting new
<tr>
and<th>
tags. - An
addCalEvent()
function is called to processtasks
. Repetitions inside the range are displayed.
To generate a addTask()
,
- Call
taskEventsString()
function which iterates dates in alltask["repetitions]
, create a string for aVEVNET
item in iCalendar format.
function taskEventsString(task)
{
let eventsArray = new Array();
for (var i = 0; i < task["repetitions"].length; i++)
{
let eventArray = new Array();
eventArray.push(VEVENT_BEGIN_STRING);
eventArray.push("DTSTART;VALUE=DATE:" + formatDate(task["repetitions"][i]));
eventArray.push("DTEND;VALUE=DATE:" + formatDate(task["repetitions"][i]));
eventArray.push("DTSTAMP:" + formatDate(task["repetitions"][i])+ "T000000Z");
eventArray.push("UID:" + createUUID());
eventArray.push("COLOR:"+ task["color"]);
eventArray.push("SUMMARY:" + task["name"] +"(" + (i + 1).toString() + ")");
eventArray.push(VEVENT_END_STRING);
eventArray.push("\n");
let eventString = eventArray.join("\n");
eventsArray.push(eventString);
}
eventsArray.push("\n");
let eventsString = eventsArray.join("\n");
return eventsString;
}
- Push the string to
tasksContent
Array.
// add events to second to last place, aka, insert before VCAL_END_STRING
tasksContent.splice((tasksContent.length - 1), 0, taskEventsString(task));
5.Update URL of File based on the updated tasksContent
Array.
updateFile(tasksContent,"Spaced_Repetition.ics");
Here updateFile()
function uses a HTML5 feature. A Blob
Object is created based on tasksContent
Array and a new URL for the Blob
Object is created and set as the button's href
.
function updateFile(contentArray,filename)
{
let txtBlob = new Blob(contentArray,{type:"text/calendar"});
let txtURL = URL.createObjectURL(txtBlob);
let exportBth = document.getElementById("ExportBtn");
exportBth.setAttribute("download", filename);
exportBth.setAttribute("href", txtURL );
}
Effect:
<a class="btn btn-link" href="txtURLExample" role="button" id="ExportBtn" download="Spaced_Repetition.ics">Export to iCalendar File (.ics)</a>
The button is essentially a link <a>
disguised as a button. Download begins as it is clicked.