// ==UserScript== // @name RZD Ticket export to calendars // @description Exports information from RZD (Russian Railroad) ticket description to Google Calendar and Yandex Calendar // @author Mikhail Dvorkin, mikhail.dvorkin@gmail.com // @namespace http://dvorkin.me/ // @website http://dvorkin.me/ // @version 2.0.0 // @include http://ticket.rzd.ru/* // @include https://ticket.rzd.ru/* // ==/UserScript== // a function that loads jQuery and calls a callback function when jQuery has finished loading // http://erikvold.com/blog/index.cfm/2010/6/14/using-jquery-with-a-user-script function addJQuery(callback) { var script = document.createElement("script"); script.setAttribute("src", "http://yandex.st/jquery/1.8.2/jquery.min.js"); // TODO add Google-hosted one, if Yandex doesn't load script.addEventListener('load', function() { var script = document.createElement("script"); script.textContent = "(" + callback.toString() + ")();"; document.body.appendChild(script); }, false); document.body.appendChild(script); } function eventor_main() { if ($(".tstatus").length && $(".tstatus").html().match(/запрос/i)) { setTimeout(eventor_main, 300); return; } elreg = $(".money").html().match(/Пройдена электронная регистрация/im); year = $("body").html().match(/Год совершения поездки: (\d+)/im)[1]; depart = rzd_findDateTime("Departure", year); arrive = rzd_findDateTime("Arrival", year); car = $(".traindata-cdat").html().trim().split(/\s+/)[0]; train = $(".traindata-tdat").html().trim().match(/\d+/)[0]; event = "Поезд " + parseInt(train, 10) + ", вагон " + parseInt(car, 10); details = $(".topinfo-ticketnum").html().trim(); place = $(".route-data .route-points tr:eq(0)"); place = $("td:eq(0)", place).html() + " — " + $("td:eq(1)", place).html().replace(/- > /, ""); busy = "true"; if (elreg) { details = "Номер заказа: " + details + "\nЭлектронная регистрация"; } else { event += ", заказ " + details; details = ""; } $(".trainfin-carr").append(handleEvent(event, depart, arrive, details, place, busy)); function rzd_findDateTime(s, year) { td = $("td.route-action:contains('" + s + "')"); table = td.closest("table"); date = $("td.route-date", table).html().trim(); time = $("td.route-time", table).html().trim(); return parseDate(date + "." + year + " " + time); } function addTime(timeObj, millis) { return new Date(timeObj.getTime() + millis); } function parseTime(s) { ss = s.replace(/^[\D]+/, "").split(/[\D]+/); hour = parseInt(ss[0], 10); minute = parseInt(ss[1], 10); return hour * 60 + minute; } // 15.09.1987 16:55 function parseDate(s) { ss = s.replace(/^[\D]+/, "").split(/[\D]+/); day = parseInt(ss[0], 10); month = parseInt(ss[1], 10); year = parseInt(ss[2], 10); if (year < 100) { year += 2000; } hour = parseInt(ss[3], 10); minute = parseInt(ss[4], 10); return new Date(year, month - 1, day, hour, minute); } function handleEvent(event, start, end, desc, place, busy) { return button(event, start, end, desc, place, busy); } function button(event, start, end, desc, place, busy) { links = document.createElement("div"); links.appendChild(make_a("\"Add", href = href_google(event, start, end, desc, place, busy))); // links.appendChild(document.createElement("br")); links.appendChild(make_a("\"Добавить", href_yandex(event, start, end, desc, place, busy))); // links.appendChild(document.createElement("br")); links.appendChild(make_a("Download iCal file", href_ical(event, start, end, desc, place, busy))); links.style.display = "none"; links.style.position = "absolute"; links.style.backgroundColor = "white"; links.style.left = "0px"; links.style.top = "0px"; links.style.padding = "0px"; links.style.margin = "4px"; links.style.border = "3px solid #E05000"; links.style.textAlign = "center"; links.id = "cal_links_" + start + "_" + Math.floor(Math.random() * 1000000000); links.style.zIndex = "1"; img = document.createElement("img"); img.src = "http://infrared.als.lbl.gov/content/images/stories/calendar_icon.gif"; img.alt = "Add to calendar"; img.style.border = "none"; a = document.createElement("a"); a.href = href; a.target = "_blank"; a.style.border = "none"; a.setAttribute("oncontextmenu", "return false;"); a.setAttribute("onmousedown", "if (event.button == 2) {" + "s = document.getElementById(\'" + links.id + "\').style;" + "s.display = (s.display == \'block\' ? \'none\' : \'block\');" + "}" + "return false;"); links.setAttribute("oncontextmenu", a.getAttribute("oncontextmenu")); links.setAttribute("onmousedown", a.getAttribute("onmousedown")); a.appendChild(img); span = document.createElement("div"); span.style.display = "inline"; span.style.position = "relative"; span.appendChild(a); span.appendChild(links); return span; } function make_a(html, url) { a = document.createElement("a"); a.href = url; a.target = "_blank"; a.innerHTML = html; a.style.display = "block"; a.style.margin = "inherit"; a.style.padding = "inherit"; //a.appendChild(document.createTextNode(text)); return a; } function href_google(event, start, end, desc, place, busy) { url = "http://www.google.com/calendar/event?action=TEMPLATE"; url += "&text=" + urlFormat(event); url += "&dates=" + icalDate(start) + "/" + icalDate(end); url += "&details=" + urlFormat(desc); url += "&location=" + urlFormat(place); url += "&trp=" + busy; url += "&sprop=" + urlFormat("http://dvorkin.me/"); url += "&sprop=name:" + urlFormat("Mikhail Dvorkin"); return url; } function href_yandex(event, start, end, desc, place, busy) { url = "http://calendar.yandex.ru/event-add?"; url += "name=" + urlFormat(event); url += "&description=" + urlFormat(desc); url += "&location=" + urlFormat(place); url += "&start_ts=" + yandexDate(start); url += "&end_ts=" + yandexDate(end); return url; } function href_ical(event, start, end, desc, place, busy) { ical = "BEGIN:VCALENDAR"; ical += "\nVERSION:2.0"; ical += "\nMETHOD:PUBLISH"; ical += "\nBEGIN:VEVENT"; ical += "\nDTSTART:" + icalDate(start); ical += "\nDTEND:" + icalDate(end); ical += "\nDTSTAMP:" + icalDate(new Date()); ical += "\nUID:" + urlFormat(document.URL); ical += "\nCREATED:19000101T120000Z"; ical += "\nDESCRIPTION:" + desc; ical += "\nLAST-MODIFIED:" + icalDate(new Date()); ical += "\nLOCATION:" + place; ical += "\nSEQUENCE:0"; ical += "\nSTATUS:CONFIRMED"; ical += "\nSUMMARY:" + event; ical += "\nTRANSP:" + (busy ? "OPAQUE" : "TRANSPARENT"); ical += "\nEND:VEVENT"; ical += "\nEND:VCALENDAR"; return "data:text/calendar;charset=utf-8," + urlFormat(ical); } function icalDate(timeObj) { var dateStr = "" + timeObj.getUTCFullYear(); dateStr += f2(timeObj.getUTCMonth() + 1); dateStr += f2(timeObj.getUTCDate()); dateStr += "T" + f2(timeObj.getUTCHours()); dateStr += f2(timeObj.getUTCMinutes()) + "00Z"; return dateStr; } function yandexDate(timeObj) { var dateStr = "" + timeObj.getFullYear(); dateStr += "-" + f2(timeObj.getMonth() + 1); dateStr += "-" + f2(timeObj.getDate()); dateStr += "T" + f2(timeObj.getHours()); dateStr += ":" + f2(timeObj.getMinutes()) + ":00Z"; return dateStr; } function f2(s) { s = "" + s; return (s.length == 1) ? "0" + s : s; } function urlFormat(s) { return encodeURIComponent(trim(s)); } function strip(s) { // TODO it doesn't process return trim(s.replace(/(<([^>]+)>)/g, "").replace(/[\n|\r| |\s]+/g, " ")); } function trim(s) { return s.replace(/^\s+/, "").replace(/\s+$/, ""); } } addJQuery(eventor_main);