{{roam/js}}
const CARD_MODE_VERSION = "53e3a57";
window.URLScriptServer = `https://raw.githack.com/JimmyLv/styled-roam/${CARD_MODE_VERSION}/`;
var existing = document.getElementById("styled-roam");
if (!existing) {
var extension = document.createElement("script");
extension.src = window.URLScriptServer + "js/index.js";
extension.id = "styled-roam";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Page Synonyms
{{roam/js}}
var existing = document.getElementById("page-synonyms");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/page-synonyms.js";
extension.id = "page-synonyms";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Todont
{{roam/js}}
var existing = document.getElementById("todont");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/todont.js";
extension.id = "todont";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Article
{{roam/js}}
var existing = document.getElementById("roamjs-article");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/article.js";
extension.id = "roamjs-article";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Image Tagging
{{roam/js}}
var existing = document.getElementById("roamjs-image-tagging");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/image-tagging.js";
extension.id = "roamjs-image-tagging";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Google Calendar - Usage: {{import google calendar}}
{{roam/js}}
var existing = document.getElementById("roamjs-google-calendar");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/google-calendar.js";
extension.id = "roamjs-google-calendar";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Mouseless - CTRL+SHIFT+? Shortcuts Helper
{{roam/js}}
var existing = document.getElementById("roamjs-mouseless");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/mouseless.js";
extension.id = "roamjs-mouseless";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Pull References - Usage: {{pull references}}
{{roam/js}}
var existing = document.getElementById("roamjs-pull-references");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/pull-references.js";
extension.id = "roamjs-pull-references";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Query Builder - Usage: {{query builder}}
{{roam/js}}
var existing = document.getElementById("roamjs-query-builder");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/query-builder.js";
extension.id = "roamjs-query-builder";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Video
{{roam/js}}
var existing = document.getElementById("roamjs-video");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/video.js";
extension.id = "roamjs-video";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Wiki - Usage: {{wiki}}
{{roam/js}}
var existing = document.getElementById("roamjs-wiki-data");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/wiki-data.js";
extension.id = "roamjs-wiki-data";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
WYSIWYG
To edit a block in WYSIWYG (what you see is what you get) mode, hold on the ALT key while clicking on it. Now you should be able to edit the content just like how it will be when rendered!
While in a block, you could hit ALT+w to toggle the block to and from WYSIWYG mode.
{{roam/js}}
var existing = document.getElementById("roamjs-wysiwyg-mode");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/wysiwyg-mode.js";
extension.id = "roamjs-wysiwyg-mode";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Emojis disabled
{{roam/js}}
var existing = document.getElementById("emojis");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/emojis.js";
extension.id = "emojis";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Sort References disabled
{{roam/js}}
var existing = document.getElementById("sort-references");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/sort-references.js";
extension.id = "sort-references";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Mindmap disabled
{{roam/js}}
var existing = document.getElementById("mindmap");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/mindmap.js";
extension.id = "mindmap";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
Checkbox Strikeout
{{roam/js}}
// roam/js code snippet to add crossing out completed todos
// also adds the CSS classname custom-strikethrough for css mods
;(()=>{
if( typeof window.roamhacker_checkboxStrikeout != 'undefined') return;
window.roamhacker_checkboxStrikeout = {};
const scanCheckboxes = () => {
document.querySelectorAll('.check-container input').forEach( (element)=>{
var span = element.parentElement.parentElement.parentElement
if(element.checked) {
span.classList.add('custom-strikethrough')
span.style.textDecoration='line-through'
} else {
span.classList.remove('custom-strikethrough')
span.style.textDecoration='none'
}
})
}
scanCheckboxes()
var observerCheckBoxes = new MutationObserver(scanCheckboxes);
observerCheckBoxes.observe(document.querySelector('#app'), {
childList: true,
subtree: true
})
})();
Show Weekday Under Page Titles
{{roam/js}}
// Roam42 is a prerequisite for this code, as it uses Roam42 libraries
// Install & Config:
// Add the code from this gist to a roam/js block in your roam graph and enable it
// If you prefer foreign day names, modify the english in the Javascript below
// CSS can be customized using #roam-title-day-banner CSS selector. Example:
// #roam-title-day-banner {
// color:silver;
// }
// to exclude sidebars, change 'var includeSidebars = true;' in the code o
// var includeSidebars = false;
;(()=>{
if( typeof window.roamhacker_daytitle != 'undefined') return;
window.roamhacker_daytitle = ()=> {
var includeSidebars = true;
var querystring = includeSidebars ? '.rm-title-display, .sidebar-content .level2 a' : '.rm-title-display';
const addDateToRoamTitleBanners = ()=> {
setTimeout(()=>{
document.querySelectorAll(querystring).forEach(title=>{
try {
if(title.nextElementSibling.classList.contains('roam-title-day-banner')) {
return;
}
} catch(e) {}
let pageDate = chrono.parseDate( title.innerText );
if( pageDate!=null ) {
var weekdays = new Array( "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday" );
var day = pageDate.getDay();
var div = document.createElement('DIV');
div.className = 'roam-title-day-banner';
div.innerText = weekdays[day];
div.style.fontSize="10pt";
div.style.top = -(Number(getComputedStyle(title).marginBottom.replace('px','')) + 6) + 'px';
div.style.position="relative";
div.style.fontStyle="oblique";
title.insertAdjacentElement('afterend', div);
}
});
},300)
};
setTimeout(()=>{
addDateToRoamTitleBanners();
const observerHeadings = new MutationObserver(addDateToRoamTitleBanners);
observerHeadings.observe(document.querySelector('.roam-body'), {
childList: true,
subtree: true
});
},10000);
}
window.roamhacker_daytitle();
})();
Mobile JS
Mobile Todos
{{roam/js}}
var existing = document.getElementById("mobile-todos");
if (!existing) {
var extension = document.createElement("script");
extension.src = "https://roamjs.com/mobile-todos.js";
extension.id = "mobile-todos";
extension.async = true;
extension.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(extension);
}
{{roam/js}}
/*
* Viktor's Roam Mobile Double tap to Exluce Filters and Right click on bullets
* version: 0.2
* author: @ViktorTabori
*
* How to install it:
* - go to page [[roam/js]]
* - create a node with: { {[[roam/js]]}}
* - create a clode block under it, and change its type from clojure to javascript
* - allow the running of the javascript on the {{[[roam/js]]}} node
* - double tap a filter and it gets excluded
* - double tap on bullets to simulate right click
*/
window.ViktorMobileTap = window.ViktorMobileTap || (function(){
// max wait for second tap in ms
var maxWait = 200;
var added;
addListener();
return {
added: added,
addListener: addListener,
removeListener: removeListener,
};
function addListener() {
if (added) return;
added = true;
document.addEventListener('touchstart', process, {passive: false, capture: true});
console.log('** double tap installed **');
}
function removeListener() {
if (!added) return;
added = false;
document.removeEventListener('touchstart', process, {passive: false, capture: true});
console.log('** double tap STOPPED **');
}
function process(e) {
var target = e.target;
// check click on elements we plan to modify
var action = [];
try {
// filter double tap to exclude
if (target.classList.contains('bp3-button') && target.parentNode.parentNode.parentNode.parentNode.classList.contains('bp3-popover-content')) {
action = [target, ['mousedown', 'click', 'mouseup'], true, {shiftKey:true}];
} else
// bullet double tap to right click
if (target.className && target.className.match(/simple-bullet-(inner|outer)|controls|block-expand|rm-caret/i)) {
// make clicking on the controls element
while (target.classList && !target.classList.contains('controls') && target.parentNode) target = target.parentNode;
var bound = target.getBoundingClientRect();
action = [target, ['contextmenu'], false, {clientX:(bound.left+bound.width/2) , clientY:(bound.top+bound.height/2)}];
}
} catch(_) {
return;
}
if (!action.length) return;
// prevent propagation of event
e.preventDefault();
e.stopPropagation();
// first tap
if(!target.dataset.doubleTap) {
target.dataset.doubleTap = 1;
setTimeout( function() {
if (target.dataset.doubleTap) {
// click on the original target if no double tap happened
simulateClick(e.target, ['mousedown', 'click', 'mouseup'], true);
}
delete target.dataset.doubleTap;
}, maxWait );
return false;
}
//action on double tap goes below
//console.log('*** Double tap detected ***',target);
delete target.dataset.doubleTap;
simulateClick.apply(null, action);
// mouse click emulation
function simulateClick(element, events, leftButton, opts) {
events.forEach(function(type){
element.dispatchEvent(new MouseEvent(type, {
view: window,
bubbles: true,
cancelable: true,
buttons: leftButton?1:2,
...opts,
}))
});
}
}
})();
{{roam/js}}
window.onhashchange = function () {
var isPage = window.location.hash.split('/')[3] == 'page'
if (isPage) {
setTimeout(function () {
var topBlock = document.getElementsByClassName("roam-block")[0].children[0]
var blockValue = topBlock.innerText.split(':')
if (blockValue.length == 2 && blockValue[0] == 'forward') {
var attrs = topBlock.children[1].attributes[1]
if (attrs.name == 'data-link-uid') {
var newUrl = window.location.href.slice(0, -9) + attrs.value
window.location.assign(newUrl)
}
}
}, 1)
}
}
For Studying disabled
{{roam/js}}
/* Image Occlusion in Roam Research
Author: Adam Krivka
https://roamresearch.com/#/app/roam-depot-developers/page/fIR-UkBAL
*/
if (window.imageocclusion) {
document.removeEventListener("click", imageocclusion.buttonClickHandler);
} else window.imageocclusion = {};
/* ====== SETTINGS (edit here!) ====== */
imageocclusion.COLORS = {
primaryColor: "gray",
secondaryColor: "#FEE8A6"
}
imageocclusion.HELPMESSAGE = "You can draw rectangles of two colors on the image with your left and right mouse buttons.";
imageocclusion.SUCCESSMESSAGE = "Image copied to clipboard.";
imageocclusion.FAILUREMESSAGE = "Copying unsuccessful. Right click the image to copy manually.";
/* ======= HELPER FUNCTIONS ====== */
imageocclusion.sleep = m => {
var t = m ? m : 50;
return new Promise(r => setTimeout(r, t))
};
imageocclusion.loadColors = () => {
if (imageocclusion.COLORS &&
imageocclusion.COLORS.primaryColor && imageocclusion.COLORS.primaryColor != "" && imageocclusion.COLORS.secondaryColor && imageocclusion.COLORS.secondaryColor != "")
return [imageocclusion.COLORS.primaryColor, imageocclusion.COLORS.secondaryColor];
else
return ["gray", "#FEE8A6"];
};
/* ====== STYLES ====== */
imageocclusion.textColor = "#eeeeee";
imageocclusion.addBasicStyles = () => {
var style = `
.roam-lift-modal .bp3-dialog-container {
flex-direction: column;
}
.roam-lift-modal .bp3-dialog {
margin: 5px;
}
.imageocclusion-button {
margin: 5px;
height: 40px;
}
.imageocclusion-help-text {
color: ${imageocclusion.textColor};
width: 300px;
height: 80px;
}
`
var basicStyles = Object.assign(document.createElement("style"), {
id: "imageocclusion-css-basic",
innerHTML: style
});
document.getElementsByTagName("head")[0].appendChild(basicStyles);
};
// Actually loading them
imageocclusion.addBasicStyles();
/* ====== CLICK LISTENER ====== */
imageocclusion.buttonClickHandler = async (e) => {
if (e.target.tagName === "IMG" && !e.target.classList.contains("rm-modal-img")) {
await imageocclusion.sleep(500);
var parentDiv = document.querySelector(".roam-lift-modal .bp3-dialog-container");
if (!parentDiv) return;
let container = Object.assign(document.createElement("div"), {
classList: "flex-h-box imageocclusion-container",
});
container.style.cssText = `justify-content: space-between; pointer-events: all;`
var startButton = Object.assign(document.createElement("button"), {
classList: "bp3-button bp3-minimal imageocclusion-button",
innerHTML: "Start Image Occlusion",
onclick: () => { imageocclusion.start(startButton, container, parentDiv) }
});
startButton.style.cssText = "color: #aaaaaa";
container.append(startButton);
parentDiv.append(container);
}
};
// Adding click listener
document.addEventListener("click", imageocclusion.buttonClickHandler, false);
/* ======= KEYBOARD LISTENER ====== */
imageocclusion.keyboardHandler = async (e) => {
console.log("Key");
console.log(e);
if (e.ctrlKey && e.key === "z") {
console.log("Trying to go back.");
imageocclusion.rects.pop();
imageocclusion.clear();
imageocclusion.drawRects();
}
}
// Adding keyboard listener
document.addEventListener("keydown", imageocclusion.keyboardHandler);
/* ====== MAIN ====== */
// Variables
imageocclusion.rects = [];
imageocclusion.canvas;
imageocclusion.draw;
// Functions
imageocclusion.start = (startButton, container, parentDiv) => {
imageocclusion.rects = [];
// Common
let img = document.querySelector(".roam-lift-modal .bp3-dialog img");
img.crossOrigin = "anonymous";
const IMG = img
// Removing start button
startButton.remove();
// Appending canvas
let canvas = Object.assign(document.createElement("canvas"), {
classList: "image-occlusion-canvas",
width: IMG.width,
height: IMG.height
});
canvas.style.cssText = `
border: 1px solid #FEE8A6;
z-index: 1000;
position:absolute;
`
canvas.oncontextmenu = () => { return false };
document.querySelector(".roam-lift-modal .bp3-dialog").append(canvas);
imageocclusion.canvas = canvas;
// Appending new UI elements
let saveButton = Object.assign(document.createElement("button"), {
classList: "bp3-button imageocclusion-button",
innerHTML: "Save to Clipboard",
onclick: () => { imageocclusion.save() }
});
let clearButton = Object.assign(document.createElement("button"), {
classList: "bp3-button imageocclusion-button",
innerHTML: "Clear canvas",
onclick: () => { imageocclusion.clear(); imageocclusion.rects = []; }
});
let helpText = Object.assign(document.createElement("p"), {
classList: "imageocclusion-help-text",
innerHTML: imageocclusion.HELPMESSAGE
});
container.append(helpText, clearButton, saveButton);
// Enabling drawing
imageocclusion.startDrawing(IMG);
};
imageocclusion.drawRects = (draw) => {
imageocclusion.rects.forEach((rect) => {
imageocclusion.draw.fillStyle = rect.color;
imageocclusion.draw.fillRect(rect.start.x, rect.start.y, rect.dim.x, rect.dim.y);
})
};
imageocclusion.startDrawing = (IMG) => {
imageocclusion.draw = imageocclusion.canvas.getContext("2d");
imageocclusion.draw.fillStyle = "gray"
var colors = imageocclusion.loadColors();
var isDown;
var rects = imageocclusion.rects;
// Helper function
var getMousePos = (canvas, e) => {
var rect = canvas.getBoundingClientRect();
return {
x: Math.floor(e.clientX - rect.left),
y: Math.floor(e.clientY - rect.top)
};
};
var stop = (e) => {
e.preventDefault();
e.stopPropagation();
};
imageocclusion.canvas.addEventListener("mousedown", (e) => {
stop(e);
isDown = true;
var color = (() => {
switch (e.button) {
case 2:
return colors[1];
default:
return colors[0];
}
})();
imageocclusion.rects.push({
start: getMousePos(imageocclusion.canvas, e),
dim: { x: 0, y: 0 },
color: color
})
});
imageocclusion.canvas.addEventListener("mouseup", (e) => {
stop(e);
isDown = false;
});
imageocclusion.canvas.addEventListener("mousemove", (e) => {
stop(e);
if (!isDown) return;
imageocclusion.canvas.oncontextmenu = () => { return false; };
var last = imageocclusion.rects[imageocclusion.rects.length - 1];
var mousePos = getMousePos(imageocclusion.canvas, e)
var newDim = {
x: mousePos.x - last.start.x,
y: mousePos.y - last.start.y
};
imageocclusion.draw.clearRect(last.start.x, last.start.y, last.dim.x, last.dim.y);
imageocclusion.draw.drawImage(IMG, 0, 0, IMG.width, IMG.height);
last.dim = newDim;
imageocclusion.drawRects();
});
};
imageocclusion.clear = () => {
imageocclusion.draw.clearRect(0, 0, imageocclusion.canvas.width, imageocclusion.canvas.height);
};
imageocclusion.log = async (message, color) => {
var helpText = document.querySelector(".imageocclusion-help-text");
if (!helpText) return;
helpText.innerHTML = message;
helpText.style.color = color;
await imageocclusion.sleep(3000);
helpText.innerHTML = imageocclusion.HELPMESSAGE;
helpText.style.color = imageocclusion.textColor;
};
imageocclusion.save = async () => {
// Copy to clipboard
try {
const response = await fetch(imageocclusion.canvas.toDataURL());
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);
imageocclusion.log(imageocclusion.SUCCESSMESSAGE, "#AAE171")
} catch (e) {
imageocclusion.log(imageocclusion.FAILUREMESSAGE, "#F17E8E")
imageocclusion.canvas.oncontextmenu = () => { };
}
};
{{roam/js}}
var handleKeyEvent = async ev => {
// console.log("alt: " + ev.altKey + " shift: " + ev.shiftKey + " ctrl: " + ev.ctrlKey + " code: " + ev.code);
if (ev.key == "$") {
// Suppress default action
ev.preventDefault();
ev.stopImmediatePropagation();
ev.stopPropagation();
var txtarea = document.activeElement;
var s = txtarea.selectionStart;
// Check if next two characters are dollar signs "$$"
if(txtarea.value.slice(s, s+2) == "$$") {
// Move cursor
txtarea.selectionStart = s + 2;
return;
} else {
// Check if not in the middle of equation
var dollarSplit = txtarea.value.split("$$");
var counter = 0;
var inEquation = false;
for (let i = 0; i < dollarSplit.length; i++) {
var l = dollarSplit[i].length;
if (s > counter + 2 && s < counter + l) {
inEquation = i % 2 == 1;
break;
}
counter += l + 2;
}
if(!inEquation){
// If not, add dollar signs
var contentArray = txtarea.value.split("");
contentArray.splice(txtarea.selectionStart,0,"$$$$");
var setValue = Object.getOwnPropertyDescriptor(
window.HTMLTextAreaElement.prototype, "value").set;
setValue.call(txtarea, contentArray.join(""));
var e = new Event("input", { bubbles: true });
txtarea.dispatchEvent(e);
await new Promise(r => setTimeout(r, 10));
// Move cursor
txtarea.selectionStart = s + 2;
txtarea.selectionEnd = s + 2;
}
}
}
};
// Add keybindings
document.addEventListener("keydown", handleKeyEvent);