Skip to content

Instantly share code, notes, and snippets.

@patarapolw
Last active April 4, 2022 14:49
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 patarapolw/5d47bf4823a1ca6c0396255bcd7efaa4 to your computer and use it in GitHub Desktop.
Save patarapolw/5d47bf4823a1ca6c0396255bcd7efaa4 to your computer and use it in GitHub Desktop.
How do get Markdown-it plugins like https://github.com/lostandfound/markdown-it-ruby inside Discourse
// ==UserScript==
// @name markdown-it-plugin for WaniKani Community
// @namespace https://community.wanikani.com
// @version 0.1
// @description markdown-it-ruby for WaniKani Community. Nothing more than necessary
// @author polv
// @match https://community.wanikani.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=wanikani.com
// @grant none
// ==/UserScript==
;(function () {
'use strict'
const plugin = (function () {
//...
function ruby_plugin(md) {
md.inline.ruler.before('text', 'ddmd_ruby', ddmd_ruby)
}
return ruby_plugin
})()
const markdownIt = require('pretty-text/engines/discourse-markdown-it')
const oldCook = markdownIt.cook
markdownIt.cook = function (raw, opts) {
opts.engine.use(plugin)
return oldCook.bind(this)(raw, opts)
}
})()
// ==UserScript==
// @name markdown-it-ruby for WaniKani Community
// @namespace https://community.wanikani.com
// @version 0.1
// @description markdown-it-ruby for WaniKani Community. Nothing more than necessary
// @author polv
// @match https://community.wanikani.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=wanikani.com
// @grant none
// ==/UserScript==
;(function () {
'use strict'
const plugin = (function () {
// Copied from https://github.com/lostandfound/markdown-it-ruby
function ddmd_ruby(state, silent) {
var token,
tokens,
max = state.posMax,
start = state.pos,
devPos,
closePos,
baseText,
rubyText,
baseArray,
rubyArray
if (silent) {
return false
}
if (state.src.charCodeAt(start) !== 0x7b /* { */) {
return false
}
if (start + 4 >= max) {
return false
}
state.pos = start + 1
while (state.pos < max) {
if (devPos) {
if (
state.src.charCodeAt(state.pos) === 0x7d /* } */ &&
state.src.charCodeAt(state.pos - 1) !== 0x5c /* \ */
) {
closePos = state.pos
break
}
} else if (
state.src.charCodeAt(state.pos) === 0x7c /* | */ &&
state.src.charCodeAt(state.pos - 1) !== 0x5c /* \ */
) {
devPos = state.pos
}
state.pos++
}
if (!closePos || start + 1 === state.pos) {
state.pos = start
return false
}
state.posMax = state.pos
state.pos = start + 1
token = state.push('ruby_open', 'ruby', 1)
token.markup = '{'
baseText = state.src.slice(start + 1, devPos)
rubyText = state.src.slice(devPos + 1, closePos)
baseArray = baseText.split('')
rubyArray = rubyText.split('|')
if (baseArray.length === rubyArray.length) {
baseArray.forEach(function (content, idx) {
state.md.inline.parse(content, state.md, state.env, (tokens = []))
tokens.forEach(function (t) {
state.tokens.push(t)
})
token = state.push('rt_open', 'rt', 1)
state.md.inline.parse(
rubyArray[idx],
state.md,
state.env,
(tokens = [])
)
tokens.forEach(function (t) {
state.tokens.push(t)
})
token = state.push('rt_close', 'rt', -1)
})
} else {
state.md.inline.parse(baseText, state.md, state.env, (tokens = []))
tokens.forEach(function (t) {
state.tokens.push(t)
})
token = state.push('rt_open', 'rt', 1)
state.md.inline.parse(rubyText, state.md, state.env, (tokens = []))
tokens.forEach(function (t) {
state.tokens.push(t)
})
token = state.push('rt_close', 'rt', -1)
}
token = state.push('ruby_close', 'ruby', -1)
token.markup = '}'
state.pos = state.posMax + 1
state.posMax = max
return true
}
function ruby_plugin(md) {
md.inline.ruler.before('text', 'ddmd_ruby', ddmd_ruby)
}
return ruby_plugin
})()
const markdownIt = require('pretty-text/engines/discourse-markdown-it')
const oldCook = markdownIt.cook
markdownIt.cook = function (raw, opts) {
opts.engine.use(plugin)
return oldCook.bind(this)(raw, opts)
}
})()
// ==UserScript==
// @name Editor overlay for WaniKani Community
// @namespace https://community.wanikani.com
// @version 0.1
// @description Editor overlay for WaniKani Community.
// @author polv
// @match https://community.wanikani.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=wanikani.com
// @grant none
// ==/UserScript==
;(function () {
'use strict'
/**
*
* @param {string} raw
* @returns
*/
function fromVanilla(raw) {
return raw
}
/**
*
* @param {string} raw
* @returns
*/
function toVanilla(raw) {
return raw
}
/** @type {HTMLTextAreaElement} */
let elTextArea = null
const getTextArea = () => document.querySelector('textarea.d-editor-input')
function initTextArea() {
if (!(elTextArea = getTextArea())) {
const obs = new MutationObserver(() => {
if ((elTextArea = getTextArea())) {
obs.disconnect()
onNewTextArea()
}
})
obs.observe(document.body, {
childList: true,
subtree: true
})
} else {
onNewTextArea()
}
}
function onNewTextArea() {
elTextArea.value = fromVanilla(elTextArea.value)
const endObs = new MutationObserver(() => {
if (!getTextArea()) {
elTextArea = null
endObs.disconnect()
onCloseTextArea()
}
})
endObs.observe(document.body, {
childList: true,
subtree: true
})
}
function onCloseTextArea() {
initTextArea()
}
let alreadyInjected = false
function injectIntoDiscourse() {
if (alreadyInjected) return
alreadyInjected = true
// greasemonkey workaround: unsafeWindow + exportFunction
let w = typeof unsafeWindow === 'undefined' ? window : unsafeWindow
let e = typeof exportFunction === 'undefined' ? (o) => o : exportFunction
injectCustomCook(w, e)
injectCustomSave(w, e)
let oldCook = w.require('pretty-text/engines/discourse-markdown-it').cook
w.require('pretty-text/engines/discourse-markdown-it').cook = e(
(raw, opts) => oldCook(toVanilla(raw), opts),
w
)
let oldSave = w.require('discourse/controllers/composer').default.prototype
.save
w.require('discourse/controllers/composer').default.prototype.save = e(
function (t) {
tText.value = toVanilla(tText.value)
tText.dispatchEvent(
new Event('change', { bubbles: true, cancelable: true })
)
oldSave.call(this, t)
},
w
)
}
injectIntoDiscourse()
initTextArea()
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment