// ==UserScript==
// @name ранобэ.рф trello integration (add comment of current page into a card)
// @namespace https://raw.githubusercontent.com/adelobosko/xn--80ac9aeh6f.xn--p1ai/master/script.js
// @description ранобэ.рф trello integration (add comment (current page of novel) into a card)
// @include https://ранобэ.рф/*
// @include https://xn--80ac9aeh6f.xn--p1ai/*
// @grant none
// @author Alexey Delobosko
// @version 1.3.1
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-idle
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// ==/UserScript==
/* jshint -W097 */
'use strict';
var program = {
'TrelloStatus': {
'NOT_ALLOWED': 0,
'ALLOWED_NOT_CONFIGURED': 1,
'ALLOWED_CONFIGURED': 2
},
'Trello': {
'Token': '',
'CardId': '',
'Key': '7d0d6fa3ed4fe0b723201010a2b0dc19',
'GetAccessUrl': function() {
return 'https://trello.com/1/authorize?expiration=never&name=Ранобэ.рф&scope=read,write&response_type=token&key='
+this.Key+'&return_url='+encodeURIComponent(document.location.toString());
},
'Status': 0,
'RedirectToGettingAccess': function() {
var url = this.GetAccessUrl();
document.location = url;
},
'AddComment': function (cardid, text) {
var xhr = new XMLHttpRequest();
var body = 'text=' + encodeURIComponent(text)+'&key='+this.Key+'&token='+this.Token;
xhr.open("POST", 'https://api.trello.com/1/cards/'+this.CardId+'/actions/comments', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(body);
},
'GetCards': function (boardId) {
var config = this.config;
var xhr = new XMLHttpRequest();
var body = 'key='+this.Key+'&token='+this.Token;
xhr.open("GET", 'https://api.trello.com/1/boards/'+boardId+'/cards?' + body, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var cards = JSON.parse(xhr.responseText);
var cardsHtml = '';
for(var i = 0; i < cards.length; i++){
var card = cards[i];
cardsHtml += '<option value="'+card.id+'">'+card.name+'</option>';
}
$('#'+config.Page.Builder.Ids.TrelloCardSelect).html(cardsHtml);
}
};
xhr.send();
},
'GetBoards': function getBoards(){
var trello = this;
var config = this.config;
var xhr = new XMLHttpRequest();
var body = 'key='+this.Key+'&token='+this.Token;
xhr.open("GET", 'https://api.trello.com/1/members/me/boards?' + body, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var boards = JSON.parse(xhr.responseText);
config.Page.Builder.CreateMainMenu(boards);
config.Page.Menu.SwitchVisibility();
}
};
xhr.send();
}
},
'Cookies':{
'Names':{
'TrelloToken': 'trelloAccessToken',
'TrelloCardId': 'trelloCardId',
'CurrentChapterText': 'currentChapterText',
'CurrentScrollPosition': 'currentScrollPosition'
},
'GetCookie': function(name) {
var matches = document.cookie.match(new RegExp(
"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
));
return matches ? decodeURIComponent(matches[1]) : undefined;
},
'ClearCookie': function (name, domain, path){
var domain = domain || document.domain;
var path = path || "/";
document.cookie = name + "=; expires=" + +new Date + "; domain=" + domain + "; path=" + path;
},
'SetCookie': function (name, value, options = {}) {
options = {
path: '/',
...options
};
if (options.expires instanceof Date) {
options.expires = options.expires.toUTCString();
}
var updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);
for (var optionKey in options) {
updatedCookie += "; " + optionKey;
var optionValue = options[optionKey];
if (optionValue !== true) {
updatedCookie += "=" + optionValue;
}
}
document.cookie = updatedCookie;
}
},
'Page': {
'DomainName': 'xn--80ac9aeh6f.xn--p1ai',
'CurrentChapterText': '',
'CurrentScrollPosition': 0.0,
'Builder':{
'AddCsses': function(){
this.CreateCssLink('fontawesome', 'https://use.fontawesome.com/releases/v5.0.13/css/all.css');
},
'Ids':{
'MainMenuIcon': 'mainIcon',
'MainMenu': 'menuIcons',
'TrelloCardSelectionMenu': 'trelloCardSelectionMenu',
'TrelloBoardSelect': 'trelloBoardSelect',
'TrelloCardSelect': 'trelloCardSelect'
},
'MainMenuOnClickHandler': function(config) {
if(config.Trello.Status === config.TrelloStatus.ALLOWED_CONFIGURED){
config.Trello.GetBoards();
}
else if(config.Trello.Status === config.TrelloStatus.ALLOWED_NOT_CONFIGURED){
config.Trello.GetBoards();
}
else if(config.Trello.Status === config.TrelloStatus.NOT_ALLOWED) {
config.Trello.RedirectToGettingAccess();
}
},
'CreateMainMenuOnClickHandler': function(){
var config = this.config;
var builder = this;
$('#'+this.Ids.MainMenuIcon).unbind();
$('#'+this.Ids.MainMenuIcon).click(function () {return builder.MainMenuOnClickHandler(config);});
},
'CrateMainMenuIcon': function() {
var src = 'https://github.com/adelobosko/images/raw/master/trelloUnchecked.png';
if(this.config.Trello.Status === this.config.TrelloStatus.ALLOWED_NOT_CONFIGURED){
src = 'https://raw.githubusercontent.com/adelobosko/images/master/trelloConfigure.png';
}
else if(this.config.Trello.Status === this.config.TrelloStatus.ALLOWED_CONFIGURED){
src = 'https://github.com/adelobosko/images/raw/master/trelloChecked.png';
}
if($('#'+this.Ids.MainMenuIcon).length > 0){
$('#'+this.Ids.MainMenuIcon).attr('src',src);
}
else {
var imgHtml = '<img id="'+this.Ids.MainMenuIcon+'" style="height:48px;cursor:pointer;" src="'+src+'"></img>';
var menuHtml = '<li class="MobileMenu__item MobileMenu__item_chapters"><div class="Chapters MobileMenu__part MobileMenu__part_disabled">'
+'<div class="PopupButton PopupButton_disabled Chapters__toggler" data-id="chapters_popup_mobile" tabindex="0" role="button">'
+imgHtml+'</div></div></li>';
$('ul.MobileMenu__list').append(menuHtml);
}
this.CreateMainMenuOnClickHandler();
},
'CreateMainMenu': function (boards) {
this.CrateMainMenuIcon();
if(boards){
this.CreateCardSelectionMenu(boards);
}
this.CreateMainMenuSubIcons();
},
'CreateCardSelectionMenu': function(boards) {
var boardsHtml = 'Select board:<br><select id="'+this.Ids.TrelloBoardSelect+'" value="undefined">';
var cardsHtml = '<br>Select card:<br><select id="'+this.Ids.TrelloCardSelect+'" value="undefined"></select>';
console.log('boards', boards);
for(var i = 0; i < boards.length; i++){
var board = boards[i];
if(board.closed === false){
boardsHtml += '<option value="'+board.id+'">'+board.name+'</option>';
}
}
boardsHtml += '</select>';
var cardSelectionStyle = 'style="font-size:24px;color:green;display:'
+ ($('#trelloSelectCard').css('display') === 'block' && this.isShown ? 'block' : 'none')
+ ';width:80%;height:90%;position:fixed;top:10px;left:10px;"';
var cardSelectionMenuHtml = '<div id="'+this.Ids.TrelloCardSelectionMenu+'" '+cardSelectionStyle+'>'+boardsHtml+cardsHtml+'</div>';
if($('#'+this.Ids.TrelloCardSelectionMenu).length > 0){
$('#'+this.Ids.TrelloCardSelectionMenu).remove();
}
$('#root').append(cardSelectionMenuHtml);
this.CreateOnBoardSelectIndexChangeHandler();
this.CreateOnCardSelectIndexChangeHandler();
},
'CreateOnBoardSelectIndexChangeHandler': function (){
var config = this.config;
$('#'+this.Ids.TrelloBoardSelect).unbind();
$('#'+this.Ids.TrelloBoardSelect).on('change', function() {
config.Trello.GetCards(this.value);
});
},
'CreateOnCardSelectIndexChangeHandler': function (){
var config = this.config;
$('#'+this.Ids.TrelloCardSelect).unbind();
$('#'+this.Ids.TrelloCardSelect).on('change', function() {
config.Cookies.SetCookie(
config.Cookies.Names.TrelloCardId,
this.value,
{
domain: config.Page.DomainName,
'max-age': 31536000
}
);
config.Trello.CardId = this.value;
});
},
'CreateMainMenuSubIcons': function() {
var logoutSubItem = {
'ID': 'trelloLogoutSubItem',
'GetHtml': function(parent){
var style = 'style="font-size:24px;padding-left:5px;float:left;color:red;cursor:pointer;"';
var html = '<i id="'+this.ID+'" '+style+' class="fas fa-sign-out-alt"></i>';
return html;
},
'CreateOnClickHandler': function(parent) {
$('#'+this.ID).unbind();
$('#'+this.ID).click(function(){
if(confirm('Do you want to delete access token?')){
var cookieNames = parent.config.Cookies.Names;
parent.config.Cookies.ClearCookie(cookieNames.TrelloAccess, parent.config.Page.DomainName);
parent.config.Cookies.ClearCookie(cookieNames.TrelloCardId, parent.config.Page.DomainName);
parent.Trello.CardId = '';
parent.Trello.Token = '';
parent.Page.Builder.CreateMainMenu();
parent.Page.Menu.SwitchVisibility(false);
}
});
}
};
var cardSelectSubItem = {
'ID': 'trelloCardSubItem',
'GetHtml': function(parent){
var cardIconColor = parent.config.Trello.CardId ? 'green' : 'white';
var style = 'style="font-size:24px;padding-left:10px;float:left;color:' + cardIconColor + ';cursor:pointer;"';
var html = '<i id="'+this.ID+'" ' + style + ' class="far fa-credit-card"></i>';
return html;
},
'CreateOnClickHandler': function(parent){
var id = this.ID;
$('#'+id).unbind();
$('#'+id).click(function(){
var displayValue = ($('#'+parent.Ids.TrelloCardSelectionMenu).css('display') === 'none' ? 'block' : 'none');
$('#'+parent.Ids.TrelloCardSelectionMenu).css('display', displayValue);
});
}
};
var subItems = [logoutSubItem, cardSelectSubItem];
var menuHtml = '<div id="'+this.Ids.MainMenu+'" style="display:'+(this.config.Page.Menu.IsShown ? 'block' : 'none')
+';width:120px;position:fixed;bottom:64px;">';
for(var i = 0; i < subItems.length; i++){
menuHtml += subItems[i].GetHtml(this);
}
menuHtml += '</div>';
if($('#'+this.Ids.MainMenu).length > 0){
$('#'+this.Ids.MainMenu).remove();
}
$('#'+this.Ids.MainMenuIcon).parent().append(menuHtml);
for(var i = 0; i < subItems.length; i++){
menuHtml += subItems[i].CreateOnClickHandler(this);
}
},
'CreateCssLink': function (id, href){
var cssId = id;
if (!document.getElementById(cssId))
{
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.id = cssId;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = href;
link.media = 'all';
head.appendChild(link);
}
}
},
'Menu': {
'SwitchVisibility': function(force){
var ids = this.config.Page.Builder.Ids;
if($('#'+ids.MainMenu).length > 0){
if(force === true || force === false){
this.IsShown = force;
}
else {
this.IsShown = !this.IsShown;
}
$('#'+ids.MainMenu).css('display', this.IsShown ? 'block' : 'none');
$('#'+ids.TrelloCardSelectionMenu).css('display',
(this.IsShown && $('#'+ids.TrelloCardSelectionMenu).css('display') === 'none' ? 'block' : 'none'));
}
},
'IsShown': false
},
'GetTokenByUrl': function (){
var urlStartText = '?token=';
var url = document.location.toString();
var startIndex = url.indexOf(urlStartText);
if(startIndex < 0){
urlStartText = '#token=';
startIndex = url.indexOf(urlStartText);
if(startIndex < 0){
return undefined;
}
}
var token = url.substring(startIndex+urlStartText.length);
return token;
},
'SetTrelloStatusByCookie': function (config){
config.Trello.Token = config.Cookies.GetCookie(config.Cookies.Names.TrelloToken);
if(config.Trello.Token){
config.Trello.Status = config.TrelloStatus.ALLOWED_NOT_CONFIGURED;
config.Trello.CardId = config.Cookies.GetCookie(config.Cookies.Names.TrelloCardId);
if(config.Trello.CardId){
config.Trello.Status = config.TrelloStatus.ALLOWED_CONFIGURED;
}
}
},
'GetChapterText': function (){
var chapter = $('.ChapterContent__title');
if(chapter.length > 0) {
return chapter[0].innerText;
}
return this.CurrentChapterText;
},
'UpdatePageStatus': function (config){
if(config.Trello.Status !== config.TrelloStatus.ALLOWED_CONFIGURED){
return;
}
var chapterText = config.Page.GetChapterText();
if(config.TimerTickCount === 0){
var cursorPos = parseFloat(config.Cookies.GetCookie(config.Cookies.Names.CurrentScrollPosition));
var lastChapterText = config.Cookies.GetCookie(config.Cookies.Names.CurrentChapterText);
if(cursorPos !== NaN && lastChapterText && chapterText === lastChapterText){
config.Page.CurrentScrollPos = cursorPos;
$(document).scrollTop(config.Page.CurrentScrollPos);
}
}
config.Page.CurrentScrollPos = $(document).scrollTop();
config.Cookies.SetCookie(
config.Cookies.Names.CurrentScrollPosition,
config.Page.CurrentScrollPos,
{domain: config.Page.DomainName, 'max-age': 31536000}
);
config.Cookies.SetCookie(
config.Cookies.Names.CurrentChapterText,
chapterText,
{domain: config.Page.DomainName, 'max-age': 31536000}
);
if(config.Page.CurrentChapterText === chapterText){
return;
}
var text = chapterText+'\r\n'+document.location.toString();
config.Trello.AddComment(config.Trello.CardId, text);
config.Page.CurrentChapterText = chapterText;
}
},
'TimerTickHandler': function(config){
if(config.Trello.Status === config.TrelloStatus.NOT_ALLOWED){
var token = config.Page.GetTokenByUrl();
if(token && token != ''){
config.Cookies.SetCookie(config.Cookies.Names.TrelloToken, token, {domain: config.Page.DomainName, 'max-age': 31536000});
}
}
config.Page.SetTrelloStatusByCookie(config);
config.Page.Builder.CreateMainMenu();
config.Page.UpdatePageStatus(config);
config.TimerTickCount = config.TimerTickCount + 1;
setTimeout(config.TimerTickHandler, config.TimerTickDelay, config);
},
'TimerTickDelay': 3000,
'TimerTickCount': 0,
'Main': function(config) {
config.Page.Builder.AddCsses();
setTimeout(config.TimerTickHandler, config.TimerTickDelay, config);
},
init : function() {
this.Trello.config = this;
this.Page.Menu.config = this;
this.Page.Builder.config = this;
delete this.init;
return this;
}
}.init();
program.Main(program);