Skip to content

Instantly share code, notes, and snippets.

@unimonkiez
Last active March 4, 2020 14:21
Show Gist options
  • Save unimonkiez/37732ff625e3cf282813cfff82c39ff6 to your computer and use it in GitHub Desktop.
Save unimonkiez/37732ff625e3cf282813cfff82c39ff6 to your computer and use it in GitHub Desktop.
var inbarCalendarByUv = () => {
const CONTINUE_TEXT = 'המשך';
const GOOGLE_CAL_IMPORT_URL = 'https://calendar.google.com/calendar/r/settings/export';
const BTN_ID = 'uv-cal-btn';
const meetTypes = {
lecture: 1,
exercise: 2,
lab: 3,
freeHours: 4,
};
const textToMeetType = {
'הרצאה': meetTypes.lecture,
'תרגיל': meetTypes.exercise,
'מעבדה': meetTypes.lab,
'ש.מחלקה': meetTypes.freeHours,
};
const meetTypeToText = {
[meetTypes.lecture] : 'הרצאה',
[meetTypes.exercise] : 'תרגיל',
[meetTypes.lab] : 'מעבדה',
}
const openInNewTab = url => {
const win = window.open(url, '_blank');
win.focus();
};
const getEndSemesterDate = (onChange) => {
const select = document.querySelector('.ToolBarCell1 select');
const getValue = () => {
const date = new Date();
date.setDate(1);
let month;
switch (select.value) {
case '1':
default:
month = 1;
break;
case '2':
month = 6;
break;
case '3':
month = 9;
break;
}
date.setMonth(month);
return date;
};
const defaultValue = getValue();
if (onChange) {
select.addEventListener('change', () => {
onChange(getValue());
});
}
return defaultValue;
};
const getEventName = (course, meet) => {
if (meet.type === meetTypes.freeHours) {
return `${course.name} (${course.number})`;
}
return `${meetTypeToText[meet.type]} - ${course.name} (${course.number})`;
};
const addButton = () => {
const td = document.createElement('td');
const button = document.createElement('button');
td.appendChild(button);
button.id = BTN_ID;
button.innerText = 'ייצוא ליומן ע"י יובל';
document.querySelector('.ToolBarCell1 tr').appendChild(td);
return button;
};
const addDatePicker = () => {
const td = document.createElement('td');
const input = document.createElement('input');
td.innerText = 'תאריך סוף סמסטר: ';
td.appendChild(input);
input.type = 'date';
const setValue = date => {
const local = new Date(date);
local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
input.value = local.toJSON().slice(0,10);
};
const defaultValue = getEndSemesterDate(newValue => {
setValue(newValue);
});
setValue(defaultValue);
document.querySelector('.ToolBarCell1 tr').appendChild(td);
return input;
};
const getTds = () => {
return Array.from(document.querySelectorAll('#ContentPlaceHolder1_matrixA_gvMatrixPeriodSchedule td'));
};
const getDataTds = () => {
const tds = getTds();
return tds.filter(td => td.innerHTML !== ' ');
}
const modTable = () => {
const tds = getDataTds();
tds.forEach(td => {
const html = td.innerHTML;
td.innerHTML = `${html.replace(/<span/g, '<div><span').replace('br><div>', 'br></div><div>')}</div>`;
});
};
const getCourseElements = () => {
return Array.from(document.querySelectorAll('#ContentPlaceHolder1_matrixA_gvMatrixPeriodSchedule td div'));
};
const getCourses = () => {
const elms = getCourseElements();
const courses = [];
const coursesNamesToIndex = {};
elms.forEach(elm => {
const rowIndex = elm.parentElement.parentElement.rowIndex;
const columnIndex = elm.parentElement.cellIndex;
const text = elm.innerText;
const lines = text.split('\n');
const headline = lines[0];
const headlineNoNumber = headline.replace(/\(\d.*/, '').trim();
let index = coursesNamesToIndex[headlineNoNumber];
if (index === undefined) {
index = courses.length;
coursesNamesToIndex[headlineNoNumber] = index;
const courseNumber = headline.match(/\((.*)\-/)[1];
courses[index] = {
name: headlineNoNumber,
number: courseNumber,
meets: [],
}
}
const course = courses[index];
const day = columnIndex - 1;
const startTime = rowIndex + 7;
const endTime = rowIndex + 8;
const isContinueMeet = [lines[0], lines[1]].some(line => line.indexOf(CONTINUE_TEXT) !== -1);
if (!isContinueMeet) {
const meetType = textToMeetType[lines[1]];
course.meets.push({
type: meetType,
day,
startTime,
endTime,
lecturers: lines[2],
location: lines[3],
elements: [elm],
});
} else {
const meet = course.meets.find(meet => {
return (meet.endTime === startTime) && (meet.day === day);
});
meet.endTime = endTime;
meet.elements.push(elm);
}
});
return courses;
};
if (!document.querySelector(`#${BTN_ID}`)) {
const datePicker = addDatePicker();
const button = addButton();
modTable();
button.addEventListener('click', () => {
var saveAs = saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})}
var ics = function (e, t) { "use strict"; { if (!(navigator.userAgent.indexOf("MSIE") > -1 && -1 == navigator.userAgent.indexOf("MSIE 10"))) { void 0 === e && (e = "default"), void 0 === t && (t = "Calendar"); var r = -1 !== navigator.appVersion.indexOf("Win") ? "\r\n" : "\n", n = [], i = ["BEGIN:VCALENDAR", "PRODID:" + t, "VERSION:2.0"].join(r), o = r + "END:VCALENDAR", a = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]; return { events: function () { return n }, calendar: function () { return i + r + n.join(r) + o }, addEvent: function (t, i, o, l, u, s) { if (void 0 === t || void 0 === i || void 0 === o || void 0 === l || void 0 === u) return !1; if (s && !s.rrule) { if ("YEARLY" !== s.freq && "MONTHLY" !== s.freq && "WEEKLY" !== s.freq && "DAILY" !== s.freq) throw "Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'"; if (s.until && isNaN(Date.parse(s.until))) throw "Recurrence rrule 'until' must be a valid date string"; if (s.interval && isNaN(parseInt(s.interval))) throw "Recurrence rrule 'interval' must be an integer"; if (s.count && isNaN(parseInt(s.count))) throw "Recurrence rrule 'count' must be an integer"; if (void 0 !== s.byday) { if ("[object Array]" !== Object.prototype.toString.call(s.byday)) throw "Recurrence rrule 'byday' must be an array"; if (s.byday.length > 7) throw "Recurrence rrule 'byday' array must not be longer than the 7 days in a week"; s.byday = s.byday.filter(function (e, t) { return s.byday.indexOf(e) == t }); for (var c in s.byday) if (a.indexOf(s.byday[c]) < 0) throw "Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'" } } var g = new Date(l), d = new Date(u), f = new Date, S = ("0000" + g.getFullYear().toString()).slice(-4), E = ("00" + (g.getMonth() + 1).toString()).slice(-2), v = ("00" + g.getDate().toString()).slice(-2), y = ("00" + g.getHours().toString()).slice(-2), A = ("00" + g.getMinutes().toString()).slice(-2), T = ("00" + g.getSeconds().toString()).slice(-2), b = ("0000" + d.getFullYear().toString()).slice(-4), D = ("00" + (d.getMonth() + 1).toString()).slice(-2), N = ("00" + d.getDate().toString()).slice(-2), h = ("00" + d.getHours().toString()).slice(-2), I = ("00" + d.getMinutes().toString()).slice(-2), R = ("00" + d.getMinutes().toString()).slice(-2), M = ("0000" + f.getFullYear().toString()).slice(-4), w = ("00" + (f.getMonth() + 1).toString()).slice(-2), L = ("00" + f.getDate().toString()).slice(-2), O = ("00" + f.getHours().toString()).slice(-2), p = ("00" + f.getMinutes().toString()).slice(-2), Y = ("00" + f.getMinutes().toString()).slice(-2), U = "", V = ""; y + A + T + h + I + R != 0 && (U = "T" + y + A + T, V = "T" + h + I + R); var B, C = S + E + v + U, j = b + D + N + V, m = M + w + L + ("T" + O + p + Y); if (s) if (s.rrule) B = s.rrule; else { if (B = "rrule:FREQ=" + s.freq, s.until) { var x = new Date(Date.parse(s.until)).toISOString(); B += ";UNTIL=" + x.substring(0, x.length - 13).replace(/[-]/g, "") + "000000Z" } s.interval && (B += ";INTERVAL=" + s.interval), s.count && (B += ";COUNT=" + s.count), s.byday && s.byday.length > 0 && (B += ";BYDAY=" + s.byday.join(",")) } (new Date).toISOString(); var H = ["BEGIN:VEVENT", "UID:" + n.length + "@" + e, "CLASS:PUBLIC", "DESCRIPTION:" + i, "DTSTAMP;VALUE=DATE-TIME:" + m, "DTSTART;VALUE=DATE-TIME:" + C, "DTEND;VALUE=DATE-TIME:" + j, "LOCATION:" + o, "SUMMARY;LANGUAGE=en-us:" + t, "TRANSP:TRANSPARENT", "END:VEVENT"]; return B && H.splice(4, 0, B), H = H.join(r), n.push(H), H }, download: function (e, t) { if (n.length < 1) return !1; t = void 0 !== t ? t : ".ics", e = void 0 !== e ? e : "calendar"; var a, l = i + r + n.join(r) + o; if (-1 === navigator.userAgent.indexOf("MSIE 10")) a = new Blob([l]); else { var u = new BlobBuilder; u.append(l), a = u.getBlob("text/x-vCalendar;charset=" + document.characterSet) } return saveAs(a, e + t), l }, build: function () { return !(n.length < 1) && i + r + n.join(r) + o } } } console.log("Unsupported Browser") } };
var cal = ics();
const now = new Date();
const untilDate = new Date(datePicker.value);
const courses = getCourses();
courses.forEach(course => {
course.meets.forEach(meet => {
const dayDiff = meet.day - now.getDay();
const dayOffset = dayDiff >= 0 ? dayDiff : (7 + dayDiff);
const beginDate = new Date(now.valueOf());
beginDate.setDate(beginDate.getDate() + dayOffset);
beginDate.setMilliseconds(0);
beginDate.setSeconds(0);
beginDate.setMinutes(0);
beginDate.setHours(meet.startTime);
const endDate = new Date(now.valueOf());
endDate.setDate(endDate.getDate() + dayOffset);
endDate.setMilliseconds(0);
endDate.setSeconds(0);
endDate.setMinutes(0);
endDate.setHours(meet.endTime);
cal.addEvent(
getEventName(course, meet),
meet.lecturers,
meet.location,
beginDate,
endDate,
{
freq: 'WEEKLY',
until: untilDate,
}
);
});
})
cal.download();
openInNewTab(GOOGLE_CAL_IMPORT_URL);
// alert(`You have ${courses.length} courses.`);
});
}
};
inbarCalendarByUv();
@unimonkiez
Copy link
Author

  1. Add bookmark with name "הוצאה ליומן" and address - javascript:(function(){var%20t=document.createElement("script");t.src="//gist.github.com/unimonkiez/37732ff625e3cf282813cfff82c39ff6/raw/5dfd130b50840ab479df8ad54053321abdcc1663/inbar-add-matrix-to-calendar.js",document.getElementsByTagName("head")[0].appendChild(t)})();.
  2. Login to Inbar and press "מערכת שעות - מטריצה".
  3. Choose the current semester
  4. Click on the bookmark you added
  5. ???
  6. Profit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment