// ==UserScript== // @name Mangadex Preview Post // @description Preview new forum/comment posts and edits on MangaDex. // @namespace https://github.com/Brandon-Beck // @version 0.0.2 // @grant unsafeWindow // @grant GM.getValue // @grant GM.setValue // @grant GM_getValue // @grant GM_setValue // @require https://gitcdn.xyz/repo/Brandon-Beck/Mangadex-Userscripts/a480c30b64fba63fad4e161cdae01e093bce1e4c/common.js // @require https://gitcdn.xyz/repo/Brandon-Beck/Mangadex-Userscripts/21ec54406809722c425c39a0f5b6aad59fb3d88d/uncommon.js // @require https://gitcdn.xyz/repo/Brandon-Beck/Mangadex-Userscripts/0d46bb0b3fa43f11ea904945e7baef7c6e2a6a5b/settings-ui.js // @match https://mangadex.org/* // @author Brandon Beck // @icon https://mangadex.org/images/misc/default_brand.png // @license MIT // @downloadURL none // ==/UserScript== // // class BBCode { /* Taken from https://github.com/DasRed/js-bbcode-parser * Distributed under MIT license */ /** * @param {Object} codes * @param {Object} [options] */ constructor(codes, options) { this.codes = []; options = options || {}; // copy options for (let optionName in options) { if (optionName === 'events') { continue; } this[optionName] = options[optionName]; } this.setCodes(codes); } /** * parse * * @param {String} text * @returns {String} */ parse(text) { return this.codes.reduce((text, code) => text.replace(code.regexp, code.replacement), text); } /** * add bb codes * * @param {String} regex * @param {String} replacement * @returns {BBCode} */ add(regex, replacement) { this.codes.push({ regexp: new RegExp(regex, 'igm'), replacement: replacement }); return this; } /** * set bb codes * * @param {Object} codes * @returns {BBCode} */ setCodes(codes) { this.codes = Object.keys(codes).map(function (regex) { const replacement = codes[regex]; return { regexp: new RegExp(regex, 'igm'), replacement: replacement }; }, this); return this; } } // create the Default const bbCodeParser = new BBCode({ '\n': '
', '\\[b\\](.*?)\\[/b\\]': '$1', '\\[i\\](.*?)\\[/i\\]': '$1', '\\[u\\](.*?)\\[/u\\]': '$1', '\\[s\\](.*?)\\[/s\\]': '$1', '\\[h1\\](.*?)\\[/h1\\]': '

$1

', '\\[h2\\](.*?)\\[/h2\\]': '

$1

', '\\[h3\\](.*?)\\[/h3\\]': '

$1

', '\\[h4\\](.*?)\\[/h4\\]': '

$1

', '\\[h5\\](.*?)\\[/h5\\]': '
$1
', '\\[h6\\](.*?)\\[/h6\\]': '
$1
', '\\[sub\\](.*?)\\[/sub\\]': '$1', '\\[sup\\](.*?)\\[/sup\\]': '$1', '\\[quote\\](.*?)\\[/quote\\]': '
$1
', '\\[spoiler\\](.*?)\\[/spoiler\\]': '', '\\[center\\](.*?)\\[/center\\]': '

$1

', '\\[left\\](.*?)\\[/left\\]': '

$1

', '\\[right\\](.*?)\\[/right\\]': '

$1

', '\\[img\\](.*?)\\[/img\\]': '', '\\[hr\\](.*?)\\[/hr\\]': '
$1', '\\[url\\](.*?)\\[/url\\]': '$1', '\\[url=(.*?)\\](.*?)\\[/url\\]': '$2', '\\[list\\](.*?)\\[/list\\]': '', '\\[ol\\](.*?)\\[/ol\\]': '
    $1
', '\\[ul\\](.*?)\\[/ul\\]': '', '\\[\\*\\](.*?)\\[/\\*\\]': '
  • $1
  • ' }); // define configuration function for default bbCodeParser.create = BBCode; /* main code */ function makePreview(txt) { return bbCodeParser.parse(txt) } let previewDivTempl = document.createElement("div") function createPreviewCallbacks() { let forms = Object.values(document.querySelectorAll(".post_edit_form")) forms = forms.concat( Object.values(document.querySelectorAll("#post_reply_form"))) forms.forEach((forum)=>{ let previewDiv = previewDivTempl.cloneNode() forum.parentElement.insertBefore(previewDiv,forum) // Try to make it side by side //e.parentElement.parentElement.insertBefore(previewDiv,e.parentElement) //e.parentElement.classList.add("sticky-top", "pt-5", "col-6") let textarea = forum.querySelector("textarea") function refreshPreview() { let preview = makePreview(textarea.value) // Remember scroll position var old_height = $(document).height(); //store document height before modifications var old_scroll = $(window).scrollTop(); //remember the scroll position // Update Preview previewDiv.innerHTML = preview // Scroll back to position $(document).scrollTop(old_scroll + $(document).height() - old_height); } previewDiv.innerHTML = makePreview(textarea.value) let buttons = Object.values(forum.querySelectorAll("button")) buttons.forEach((btn)=>{ btn.addEventListener('click',refreshPreview) }) textarea.oninput = refreshPreview }) } createPreviewCallbacks()