Skip to content

Instantly share code, notes, and snippets.

@kdnk
Last active May 19, 2022 02:13
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 kdnk/9958fa5f508bc59cff4b4e7c6dd34caa to your computer and use it in GitHub Desktop.
Save kdnk/9958fa5f508bc59cff4b4e7c6dd34caa to your computer and use it in GitHub Desktop.
/* ======= AUTOTAG MODE v0.4.1========
* Pre-requisites -
* For NLP dates: Roam42 https://roamjs.com/extensions/roam42
* For PageSynonyms: Page Synonyms https://roamjs.com/extensions/page-synonyms
* Hat-tips: Azlen for arrive.js idea; Tyler Wince for Unlink Finder; Chris TftHacker for Roam42; Murf for demystifying JS and refactoring the regex; David Vargas for everything!
*/
/* ======= OPTIONS ======= */
let caseinsensitive = !0, // change to 0 to only tag references with exact case, otherwise it will alias, e.g., [book]([[Book]])
processdates = !1, // change to 0 to not process roam42 NLP dates
processalias = !0, // change to 0 to not process Page Synonyms JS aliases
minpagelength = 1; // change to whatever the minimum page length should be to be tagged
// Exclusions: Create an [[autotag-exclude]] page. Add pages you want to exclude, comma-spaced without [[ ]], to the first block on that page
// Change line 134 to change the keyboard shortcut to toggle on and off (default is alt+i)
/* ======= ARRIVE.JS v2.4.1 ========
* https://github.com/uzairfarooq/arrive
* MIT licensed
* Copyright (c) 2014-2017 Uzair Farooq
*/
var Arrive = (function (e, t, n) {
"use strict";
function r(e, t, n) {
l.addMethod(t, n, e.unbindEvent),
l.addMethod(t, n, e.unbindEventWithSelectorOrCallback),
l.addMethod(t, n, e.unbindEventWithSelectorAndCallback);
}
function i(e) {
(e.arrive = f.bindEvent),
r(f, e, "unbindArrive"),
(e.leave = d.bindEvent),
r(d, e, "unbindLeave");
}
if (e.MutationObserver && "undefined" != typeof HTMLElement) {
var o = 0,
l = (function () {
var t =
HTMLElement.prototype.matches ||
HTMLElement.prototype.webkitMatchesSelector ||
HTMLElement.prototype.mozMatchesSelector ||
HTMLElement.prototype.msMatchesSelector;
return {
matchesSelector: function (e, n) {
return e instanceof HTMLElement && t.call(e, n);
},
addMethod: function (e, t, r) {
var i = e[t];
e[t] = function () {
return r.length == arguments.length
? r.apply(this, arguments)
: "function" == typeof i
? i.apply(this, arguments)
: n;
};
},
callCallbacks: function (e, t) {
t &&
t.options.onceOnly &&
1 == t.firedElems.length &&
(e = [e[0]]);
for (var n, r = 0; (n = e[r]); r++)
n && n.callback && n.callback.call(n.elem, n.elem);
t &&
t.options.onceOnly &&
1 == t.firedElems.length &&
t.me.unbindEventWithSelectorAndCallback.call(
t.target,
t.selector,
t.callback
);
},
checkChildNodesRecursively: function (e, t, n, r) {
for (var i, o = 0; (i = e[o]); o++)
n(i, t, r) &&
r.push({ callback: t.callback, elem: i }),
i.childNodes.length > 0 &&
l.checkChildNodesRecursively(
i.childNodes,
t,
n,
r
);
},
mergeArrays: function (e, t) {
var n,
r = {};
for (n in e) e.hasOwnProperty(n) && (r[n] = e[n]);
for (n in t) t.hasOwnProperty(n) && (r[n] = t[n]);
return r;
},
toElementsArray: function (t) {
return (
n === t ||
("number" == typeof t.length && t !== e) ||
(t = [t]),
t
);
},
};
})(),
c = (function () {
var e = function () {
(this._eventsBucket = []),
(this._beforeAdding = null),
(this._beforeRemoving = null);
};
return (
(e.prototype.addEvent = function (e, t, n, r) {
var i = {
target: e,
selector: t,
options: n,
callback: r,
firedElems: [],
};
return (
this._beforeAdding && this._beforeAdding(i),
this._eventsBucket.push(i),
i
);
}),
(e.prototype.removeEvent = function (e) {
for (
var t, n = this._eventsBucket.length - 1;
(t = this._eventsBucket[n]);
n--
)
if (e(t)) {
this._beforeRemoving && this._beforeRemoving(t);
var r = this._eventsBucket.splice(n, 1);
r && r.length && (r[0].callback = null);
}
}),
(e.prototype.beforeAdding = function (e) {
this._beforeAdding = e;
}),
(e.prototype.beforeRemoving = function (e) {
this._beforeRemoving = e;
}),
e
);
})(),
a = function (t, r) {
var i = new c(),
o = this,
a = { fireOnAttributesModification: !1 };
return (
i.beforeAdding(function (n) {
var i,
l = n.target;
(l === e.document || l === e) &&
(l = document.getElementsByTagName("html")[0]),
(i = new MutationObserver(function (e) {
r.call(this, e, n);
}));
var c = t(n.options);
i.observe(l, c), (n.observer = i), (n.me = o);
}),
i.beforeRemoving(function (e) {
e.observer.disconnect();
}),
(this.bindEvent = function (e, t, n) {
t = l.mergeArrays(a, t);
for (
var r = l.toElementsArray(this), o = 0;
o < r.length;
o++
)
i.addEvent(r[o], e, t, n);
}),
(this.unbindEvent = function () {
var e = l.toElementsArray(this);
i.removeEvent(function (t) {
for (var r = 0; r < e.length; r++)
if (this === n || t.target === e[r]) return !0;
return !1;
});
}),
(this.unbindEventWithSelectorOrCallback = function (e) {
var t,
r = l.toElementsArray(this),
o = e;
(t =
"function" == typeof e
? function (e) {
for (var t = 0; t < r.length; t++)
if (
(this === n ||
e.target === r[t]) &&
e.callback === o
)
return !0;
return !1;
}
: function (t) {
for (var i = 0; i < r.length; i++)
if (
(this === n ||
t.target === r[i]) &&
t.selector === e
)
return !0;
return !1;
}),
i.removeEvent(t);
}),
(this.unbindEventWithSelectorAndCallback = function (e, t) {
var r = l.toElementsArray(this);
i.removeEvent(function (i) {
for (var o = 0; o < r.length; o++)
if (
(this === n || i.target === r[o]) &&
i.selector === e &&
i.callback === t
)
return !0;
return !1;
});
}),
this
);
},
s = function () {
function e(e) {
var t = { attributes: !1, childList: !0, subtree: !0 };
return (
e.fireOnAttributesModification && (t.attributes = !0), t
);
}
function t(e, t) {
e.forEach(function (e) {
var n = e.addedNodes,
i = e.target,
o = [];
null !== n && n.length > 0
? l.checkChildNodesRecursively(n, t, r, o)
: "attributes" === e.type &&
r(i, t, o) &&
o.push({ callback: t.callback, elem: i }),
l.callCallbacks(o, t);
});
}
function r(e, t) {
return l.matchesSelector(e, t.selector) &&
(e._id === n && (e._id = o++),
-1 == t.firedElems.indexOf(e._id))
? (t.firedElems.push(e._id), !0)
: !1;
}
var i = {
fireOnAttributesModification: !1,
onceOnly: !1,
existing: !1,
};
f = new a(e, t);
var c = f.bindEvent;
return (
(f.bindEvent = function (e, t, r) {
n === r
? ((r = t), (t = i))
: (t = l.mergeArrays(i, t));
var o = l.toElementsArray(this);
if (t.existing) {
for (var a = [], s = 0; s < o.length; s++)
for (
var u = o[s].querySelectorAll(e), f = 0;
f < u.length;
f++
)
a.push({ callback: r, elem: u[f] });
if (t.onceOnly && a.length)
return r.call(a[0].elem, a[0].elem);
setTimeout(l.callCallbacks, 1, a);
}
c.call(this, e, t, r);
}),
f
);
},
u = function () {
function e() {
var e = { childList: !0, subtree: !0 };
return e;
}
function t(e, t) {
e.forEach(function (e) {
var n = e.removedNodes,
i = [];
null !== n &&
n.length > 0 &&
l.checkChildNodesRecursively(n, t, r, i),
l.callCallbacks(i, t);
});
}
function r(e, t) {
return l.matchesSelector(e, t.selector);
}
var i = {};
d = new a(e, t);
var o = d.bindEvent;
return (
(d.bindEvent = function (e, t, r) {
n === r
? ((r = t), (t = i))
: (t = l.mergeArrays(i, t)),
o.call(this, e, t, r);
}),
d
);
},
f = new s(),
d = new u();
t && i(t.fn),
i(HTMLElement.prototype),
i(NodeList.prototype),
i(HTMLCollection.prototype),
i(HTMLDocument.prototype),
i(Window.prototype);
var h = {};
return r(f, h, "unbindAllArrive"), r(d, h, "unbindAllLeave"), h;
}
})(window, "undefined" == typeof jQuery ? null : jQuery, void 0);
/* ======= CODE ======== */
let blockUid = "initial",
attoggle = !1,
blockText = "initial";
function updateMainButtonIcon() {
if (attoggle) {
blockUid = "initial";
document
.getElementById("autotag-icon")
.classList.replace("bp3-icon-eye-on", "bp3-icon-eye-off");
} else {
document
.getElementById("autotag-icon")
.classList.replace("bp3-icon-eye-off", "bp3-icon-eye-on");
}
}
function autotag() {
attoggle = !attoggle;
}
function onClickMainButton() {
autotag();
updateMainButtonIcon();
}
function onMounted() {
// eslint-disable-next-line
console.log("[roam.js:356] loaded: ");
updateMainButtonIcon();
}
function getAllExcludes() {
return window.roamAlphaAPI
.q(
'[ :find (pull ?e [* {:block/children [*]}]) :where [?e :node/title "autotag-exclude"]]'
)[0][0]
.children[0].string.split(",")
.map((e) => e.trim());
}
function getAllPages() {
return window.roamAlphaAPI
.q("[:find ?t :where [?e :node/title ?t] ]")
.map((e) => e[0])
.sort(function (e, t) {
return t.length - e.length;
});
}
const showLogger = false;
function logger(title, value) {
if (showLogger) {
console.log(title, value);
}
}
function linkReferences(e) {
if (!e) {
return;
}
logger("[roam.js:363] e: ", e);
let t = getAllPages(),
l = [];
0 !==
window.roamAlphaAPI.q(
'[:find (pull ?e [*]) :where [?e :node/title "autotag-exclude"] ]'
).length && (l = getAllExcludes());
let n = t.filter((t) => {
let n = t.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
if (l.includes(t) || t.length <= minpagelength) return !1;
let g = new RegExp(n, "i");
let bool = false;
if (e.match(g)) {
bool = true;
// g = new RegExp(`\\[\\[${n}\\]\\]|#${n}`);
// // eslint-disable-next-line
// logger("[roam.js:379] g: ", g);
// // eslint-disable-next-line
// logger("[roam.js:381] !e.match(g): ", !e.match(g));
// bool = !e.match(g);
}
if (e.includes("東京") && t.includes("May 9th, 2022")) {
// eslint-disable-next-line
logger("[roam.js:379] bool: ", bool);
// eslint-disable-next-line
logger("[roam.js:380] e: ", e);
// eslint-disable-next-line
logger("[roam.js:384] t: ", t);
// eslint-disable-next-line
logger("[roam.js:386] n: ", n);
}
return bool;
});
n = n.sort((e, t) => t.length - e.length);
// eslint-disable-next-line
logger("[roam.js:379] n: ", n);
let g = new RegExp(
"(\\[[^\\]]+\\]\\([^ ]+\\)|{{[^}]+}}|\\S*::|\\[\\[[^\\]]+\\]\\]|\\[[^\\]]+\\]|\\[[^\\]]+$|https?://[^\\s]+|www\\.[^\\s]+)",
"g"
),
i = e,
a = [];
return (
n.forEach((e) => {
let t = e.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"),
l = i.split(g),
n = "";
// eslint-disable-next-line
logger("[roam.js:390] t: ", t);
// eslint-disable-next-line
logger("[roam.js:390] : l", l);
l.forEach((l) => {
let i = l;
if (!l.match(g) && !a.includes(e)) {
let l = new RegExp(`^${t}|[^\\[]${t}`, "i");
// eslint-disable-next-line
logger("[roam.js:403] l(regex): ", l);
// if (i.match(l)) {
while (i.match(l)) {
let n = i.length;
(l = new RegExp(`(^|[^\\[])(${t})`, "g")),
logger(">>>>>>>>>>>l ", l),
i.match(l)
? (i = i.replace(l, "$1[[$2]]"))
: caseinsensitive &&
((l = new RegExp(`(^|[^\\[])(${t})`, "i")),
(i = i.replace(l, `$1[$2]([[${e}]])`))),
i.length !== n && a.push(e);
// eslint-disable-next-line
logger("[roam.js:410] i: ", i);
}
}
n += i;
// eslint-disable-next-line
logger("[roam.js:415] n: ", n);
}),
(i = n);
}),
i
);
}
function NLPdates(e) {
if (!e) {
return e;
}
return "object" == typeof roam42 && 1 == processdates
? roam42.dateProcessing.parseTextForDates(e)
: e;
}
function blockUpdate(e, t) {
window.roamAlphaAPI.updateBlock({
block: {
uid: e,
string: t,
},
});
}
function blockAlias(e) {
if (1 != processalias) return e;
window.roamjs.extension.pageSynonyms.aliasBlock({
blockUid: e,
});
}
(window.onkeydown = function (e) {
if ((e = e || event).ctrlKey && 73 === e.keyCode) {
if ((attoggle = !attoggle))
(blockUid = "initial"),
document
.getElementById("autotag-icon")
.classList.replace("bp3-icon-eye-on", "bp3-icon-eye-off");
else {
let e = window.roamAlphaAPI.ui.getFocusedBlock();
null !== e && (blockUid = e["block-uid"]),
document
.getElementById("autotag-icon")
.classList.replace("bp3-icon-eye-off", "bp3-icon-eye-on");
}
}
}),
document.leave("textarea.rm-block-input", function () {
if (!attoggle) {
(blockText = NLPdates(
(blockText = linkReferences(
(blockText = window.roamAlphaAPI.q(
" [:find ?s :in $ ?b :where [?e :block/uid ?b] [?e :block/string ?s] ]",
blockUid
)[0]?.[0]),
blockUid
))
)),
blockUpdate(blockUid, blockText);
let e = blockUid;
setTimeout(function () {
blockAlias(e);
}, 100);
}
}),
document.arrive("textarea.rm-block-input", function () {
attoggle ||
(blockUid = window.roamAlphaAPI.ui.getFocusedBlock()["block-uid"]);
});
var nameToUse = "autotag",
bpIconName = "eye-off",
checkForButton = document.getElementById(nameToUse + "-icon");
if (!checkForButton) {
var mainButton = document.createElement("span");
(mainButton.id = nameToUse + "-button"),
mainButton.classList.add("bp3-popover-wrapper");
var spanTwo = document.createElement("span");
spanTwo.classList.add("bp3-popover-target"),
mainButton.appendChild(spanTwo);
var mainIcon = document.createElement("span");
(mainIcon.id = nameToUse + "-icon"),
mainIcon.classList.add(
"bp3-icon-" + bpIconName,
"bp3-button",
"bp3-minimal",
"bp3-small"
),
spanTwo.appendChild(mainIcon);
var roamTopbar = document.getElementsByClassName("rm-topbar"),
nextIconButton = roamTopbar[0].lastElementChild,
flexDiv = document.createElement("div");
(flexDiv.id = nameToUse + "-flex-space"),
(flexDiv.className = "rm-topbar__spacer-sm"),
nextIconButton.insertAdjacentElement("afterend", mainButton),
mainButton.insertAdjacentElement("afterend", flexDiv),
mainButton.addEventListener("click", onClickMainButton);
onMounted();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment