Skip to content

Instantly share code, notes, and snippets.

@sonota88
Created June 18, 2020 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sonota88/3187c5f60f67c3eafd31fbf0b457035f to your computer and use it in GitHub Desktop.
Save sonota88/3187c5f60f67c3eafd31fbf0b457035f to your computer and use it in GitHub Desktop.
bhatena-hcalendar.user.js
// ==UserScript==
// @name bhatena-hcalendar
// @namespace anbt
// @include *
// ==/UserScript==
/*
dt: DateTime
*/
function puts(){ console.log(arguments); }
function strip(str){
return str.replace( /^[\s\t\n\r\n]+/, "" ).replace( /[\s\t\r\n]+$/, "" );
}
function xid(){
return document.getElementById(arguments[0]);
}
function include(array, target){
var result = [];
for(var a=0; a<array.length; a++){
if( target === array[a] ){
return true;
}
}
return false;
}
function hasClass(elem, className){
return elem.getAttribute("class")
&& include( elem.getAttribute("class").split(" "), className);
}
function xclass( root, className ){
var elems = root.getElementsByTagName("*");
var result = [];
for(var a in elems){
if( elems[a].getAttribute && hasClass(elems[a], className)
){
result.push(elems[a]);
}
}
return result;
}
function createElement(parent, tagName, attributes, styles, innerHTML){
var e = document.createElement(tagName);
if(attributes){
for(var key in attributes){
e.setAttribute(key, attributes[key]); }}
if(styles){
for(var key in styles){
e.style[key] = styles[key]; }}
if(innerHTML){
e.innerHTML = innerHTML; }
if(parent){
parent.appendChild(e); }
return e;
}
////////////////////////////////
var doc = document;
var DefaultDiff = 1000 * 60 * 60; // 1h
var veventStyle = {
border: "solid 1px #ddd"
, backgroundColor: "#f8f8f8"
, padding: "1ex"
, fontSize: "80%"
, marginLeft: "8ex"
};
////////////////////////////////
function zeroPadding(num, digit){
var str = num.toString();
while(str.length < digit){
str = "0" + str;
}
return str;
}
function formatDate(date){
return ""
+ date.getFullYear()
+ "-" + zeroPadding( date.getMonth() + 1, 2 )
+ "-" + zeroPadding( date.getDate(), 2 );
}
function formatDateTime(dt){
if( ! dt
|| dt === YMDError
|| dt === HMError )
{
throw "invalid";
}
return formatDate(dt)
+ " " + dig2(dt.getHours())
+ ":" + dig2(dt.getMinutes());
}
function formatDateTimeRange(parsed){
return formatDateTime(parsed.start) + "--" + formatDateTime(parsed.end);
}
function parseYMD(str){
var year, month, date;
if( str.match(/^(\d{4})[\.\-/]([01]?\d)[\.\-/]([0-3]?\d)$/)
|| str.match(/^(\d{4})([01]\d)([0-3]\d)$/)
)
{
year = RegExp.$1;
month = RegExp.$2;
date = RegExp.$3;
}else if( str.match(/^([01]?\d)[\.\-/]([0-3]?\d)$/) ){
year = (new Date()).getFullYear();
month = RegExp.$1;
date = RegExp.$2;
}else{
throw "invalid YMD";
}
return {
year: year
, month: month
, date: date
};
}
function parseHM(hm, dtStart){
var hours, minutes;
if( ! hm ){
if(dtStart){
hours = 23;
minutes = 59;
}else{
hours = 0;
minutes = 0;
}
}else if( hm.match(/^([0-2]?\d):([0-5]?\d)$/)
|| hm.match(/^([0-2]\d)([0-5]\d)$/)
)
{
hours = RegExp.$1;
minutes = RegExp.$2;
}else{
throw "must not happen";
}
return {
hours: hours
, minutes: minutes
};
}
function parseDateTime(str, dtStart){
var baseDT;
if(dtStart){
baseDT = dtStart;
}else{
baseDT = new Date();
}
var ymd, hm;
var year, month, date, hours, minutes;
if( str.match(/^(.+?) (.+)$/) ){ // date and time
ymd = RegExp.$1;
hm = RegExp.$2;
}else{ // date or time
if( str.match(/^([0-2]?\d):?([0-5]?\d)$/) ){ // time
ymd = formatDate(baseDT);
hm = str;
}else{ // date
ymd = str;
hm = null;
}
}
try{
var _ymd = parseYMD(ymd);
year = _ymd.year;
month = _ymd.month;
date = _ymd.date;
}catch(e){
if(dtStart){
throw "end:date";
}else{
throw "start:date";
};
}
try{
var _hm = parseHM(hm, dtStart);
hours = _hm.hours;
minutes = _hm.minutes;
}catch(e){
if(dtStart){
throw "end:time";
}else{
throw "start:time";
};
}
return new Date(year, month-1, date, hours, minutes);
}
function parseDateTimeRange(str){
var strStart, strEnd;
var dtStart, dtEnd;
if( str.match(/^(.+?)\+(.+)$/) ){
strStart = RegExp.$1;
var tempDiff = RegExp.$2;
var unit;
if( tempDiff.match( /^(\d+)([dhm])$/ ) ){
tempDiff = parseInt(RegExp.$1);
unit = RegExp.$2;
}else{
throw "invalid diff";
}
var diff;
switch(unit){
case "d":
diff = tempDiff * 24 * 60 * 60 * 1000; break;
case "h":
diff = tempDiff * 60 * 60 * 1000; break;
case "m":
diff = tempDiff * 60 * 1000; break;
default:
throw "must not happen";
}
dtStart = parseDateTime(strStart);
dtEnd = new Date( dtStart.getTime() + diff );
}else if( str.match(/^(.+?)--(.+)$/) ){
strStart = RegExp.$1;
strEnd = RegExp.$2;
dtStart = parseDateTime(strStart);
dtEnd = parseDateTime(strEnd, dtStart);
}else{
if( str.match(/^(.+)--$/) ){
str = RegExp.$1;
}
dtStart = parseDateTime(str);
if( str.match(/^(.+) (.+)$/)
|| str.match(/^(\d?\d):?(\d?\d)$/) ){
dtEnd = new Date( dtStart.getTime() + DefaultDiff );
}else{
dtEnd = parseDateTime(str, dtStart);
}
}
return {
start: dtStart
, end: dtEnd
};
}
////////////////////////////////
function findUserMetaData(bm, key){
var re = new RegExp( "<" + key + ":(.+?)>");
if( bm.comment.match(re) ){
return strip( RegExp.$1 );
}else{
return null;
}
}
////////////////////////////////
function getDateTime(bm){
var dateText = findUserMetaData(bm, "dt");
return parseDateTimeRange(dateText);
}
function getSummary(bm){
return xid( "head-entry-link" ).innerHTML;
}
// todo: #entry-extract-content が取れない時があるので対処すべき
function getDescription(bm){
var description;
if( xid( "entry-extract-content" ) ){
description = xid( "entry-extract-content" ).textContent.substr(0, 140);
}else{
description = "description not found";
}
return description;
}
function getLocation(bm){
var value = findUserMetaData(bm, "at");
if( value ){
return value;
}else{
return null;
}
}
function getURL(){
return xid("head-entry-link").href;
}
////////////////////////////////
function date2rfc3339(date){
var result = "";
result = date.getFullYear()
+ "-" + zeroPadding( date.getMonth()+1, 2 )
+ "-" + zeroPadding( date.getDate(), 2 );
result += "T";
result += zeroPadding( date.getHours(), 2);
result += ":" + zeroPadding( date.getMinutes(), 2);
result += ":00+09:00";
return result;
}
function shortDateTime(date){
var result = "";
if( date.getFullYear() !== (new Date()).getFullYear() ){
result += date.getFullYear() + "-";
}
result += zeroPadding( date.getMonth()+1, 2 )
+ "-" + zeroPadding( date.getDate(), 2 );
result += " ";
result += zeroPadding( date.getHours(), 2);
result += ":" + zeroPadding( date.getMinutes(), 2);
return result;
}
////////////////////////////////
function getInnerHTML(bm){
var summary = getSummary(bm);
var description = getDescription(bm);
var location = getLocation(bm);
var url = getURL();
var html = "";
html += "<p>";
html += "<span class='summary' style='font-weight: bold; display: none;'>"
+ summary + "</span>";
if(location){
html += " (at <span class='location'>"
+ location + "</span>)";
}
html += "</p>";
html += '<p>';
try{
var dt = getDateTime(bm);
var sDateText = date2rfc3339(dt.start);
var eDateText = date2rfc3339(dt.end);
html += "<span class='dtstart' style='font-family: monospace; background-color: #ffa;' title='"+ sDateText +"'>"
+ shortDateTime(dt.start) + "</span>";
html += "--<span class='dtend' style='font-family: monospace; background-color: #ffa;' title='"+ eDateText +"'>"
+ shortDateTime(dt.end) + "</span>";
}catch(e){
html += "(" + e + ") ";
}
html += "</p>";
html += "<p class='description' style='padding-left: 2ex; display: none;'>"
+ description + "</p>";
html += "<a class='url' style='display: none;' href='"+url+"'>url</a>";
return html;
}
function procBookmark(bm){
if( findUserMetaData( bm, "dt" ) ){
var hCalendar = createElement(
bm, "div", { "class": "vcalendar" }
);
createElement(
hCalendar
, "div"
, { "class": "vevent" }
, veventStyle
, getInnerHTML(bm)
);
}
}
////////////////////////////////
// for my bookmark
function getSelfBM(){
var temp_ul = xid("bookmarked_user");
var selfBookmark = xclass( temp_ul, "self" )[0];
if(selfBookmark){
selfBookmark.comment = xclass(selfBookmark, "comment")[0].innerHTML
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">");
return selfBookmark;
}else{
return null;
}
}
function refreshVEvent(bm, comment){
if(comment){ bm.comment = comment; }
var vevent = xclass(bm, "vevent")[0];
if( ! findUserMetaData( bm, "dt" ) ){
vevent.innerHTML = "";
vevent.style.display = "none";
return;
}
vevent.innerHTML = getInnerHTML(bm);
vevent.style.display = "block";
}
var selfbm = getSelfBM();
if(selfbm){
var hCalendar = createElement(
selfbm, "div", { "class": "vcalendar" }
);
var vevent = createElement(
hCalendar
, "div"
, { "class": "vevent" }
, veventStyle
, getInnerHTML(selfbm)
);
if( ! findUserMetaData( selfbm, "dt" ) ){
vevent.style.display = "none";
}
selfbm.addEventListener(
"change"
, function(e){
refreshVEvent(selfbm, e.target.value);
}
, false
);
}
////////////////////////////////
// for other bookmarks
function getOtherBookmarks(){
var temp = xid("bookmarked_user").childNodes;
var bookmarks = [];
for(var a=0; a<temp.length; a++){
if(temp[a].tagName === "LI"
&& ! hasClass(temp[a], "self") )
{
bookmarks.push(temp[a]);
}
}
return bookmarks;
}
var others = getOtherBookmarks();
var bm;
for(var a=0; a<others.length; a++){
bm = others[a];
// if(a==0){ // for debug
// xclass(bm, "comment")[0].style.display = "inline";
// xclass(bm, "comment")[0].style.visibility = "visible";
// xclass(bm, "comment")[0].innerHTML = "&lt;dt: 20010102 1234&gt;";
// }
bm.comment = xclass(bm, "comment")[0].innerHTML
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">");
if(bm.comment){ procBookmark(bm); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment