您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows a XenForo user to add a custom BBCode template to their posts. Optional automatic formatting and keyboard shortcut included.
// ==UserScript== // @name XenForo Post Style // @namespace Makaze // @include * // @grant none // @version 5.0.4 // @description Allows a XenForo user to add a custom BBCode template to their posts. Optional automatic formatting and keyboard shortcut included. // ==/UserScript== /* XENFORO POST TEMPLATE SCRIPT PRESS Alt+T TO APPLY ON ANY PAGE AUTOMATIC FORMATTING OPTIONAL */ function getPosition(element) { var xPosition = 0, yPosition = 0; while (element) { xPosition += (element.offsetLeft + element.clientLeft); yPosition += (element.offsetTop + element.clientTop); element = element.offsetParent; } return {x: xPosition, y: yPosition}; } Math.easeInOutQuad = function (time, start, change, duration) { time /= duration / 2; if (time < 1) { return change / 2 * time * time + start; } time--; return -change / 2 * (time * (time - 2) - 1) + start; }; function scrollTo(element, to, duration) { var start = element.scrollTop, change = to - start, currentTime = 0, increment = 1; var animateScroll = function() { var val = Math.easeInOutQuad(currentTime, start, change, duration); element.scrollTop = val; currentTime += increment; if (currentTime < duration) { setTimeout(animateScroll, increment); } }; animateScroll(); } function selectRange(elem, start, end) { var range; if (elem.setSelectionRange) { elem.focus(); elem.setSelectionRange(start, end); } else if (elem.createTextRange) { range = elem.createTextRange(); range.collapse(true); range.moveEnd('character', end); range.moveStart('character', start); range.select(); } } function cursor(elem, position) { selectRange(elem, position, position); } function applyTemplate(elem) { var formContext = elem, opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {}, htmlPrefix = (opts.hasOwnProperty('xf_template_htmlPrefix')) ? opts.xf_template_htmlPrefix : '', htmlSuffix = (opts.hasOwnProperty('xf_template_htmlSuffix')) ? opts.xf_template_htmlSuffix : '', bbPrefix = (opts.hasOwnProperty('xf_template_bbPrefix')) ? opts.xf_template_bbPrefix : '', bbSuffix = (opts.hasOwnProperty('xf_template_bbSuffix')) ? opts.xf_template_bbSuffix : '', thisList, thisLink, instance, postForm, plainText, i = 0; var applyTemplateEvent = function(event) { var parent = event.target; applyToChildren(parent); event.target.removeEventListener('keydown', applyTemplateEvent, false); }; var applyToChildren = function(parent) { var thisChild, applyTo, i = 0; for (i = 0; i < parent.childNodes.length; i++) { thisChild = parent.childNodes[i]; if (thisChild.innerHTML) { applyTo = thisChild.innerHTML.replace( /\[quote([^]+)\[\/quote\]/gi, htmlSuffix + '[quote$1[/quote]' + htmlPrefix ); thisChild.innerHTML = htmlPrefix + applyTo + htmlSuffix; } } }; while (formContext.getElementsByClassName('redactor_box')[0] == null && formContext.parentNode) { formContext = formContext.parentNode; } if (opts.hasOwnProperty('xf_template_auto')) { for (i = 0; i < formContext.getElementsByClassName('redactor_MessageEditor').length; i++) { instance = formContext.getElementsByClassName('redactor_MessageEditor')[i]; postForm = instance.contentWindow.document; if (!postForm.body.textContent.length) { postForm.body.addEventListener('keydown', applyTemplateEvent, false); } else { applyToChildren(postForm.body); } } for (i = 0; i < formContext.getElementsByClassName('bbCodeEditorContainer').length; i++) { plainText = formContext.getElementsByClassName('bbCodeEditorContainer')[i].getElementsByTagName('textarea')[0]; plainText.value = bbPrefix + plainText.value + bbSuffix; cursor(plainText, plainText.value.length - bbSuffix.length); } } else { thisList = document.getElementById('AccountMenu').getElementsByClassName('blockLinksList')[0]; for (i = 0; i < thisList.getElementsByTagName('a').length; i++) { thisLink = thisList.getElementsByTagName('a')[i]; if (thisLink.href.match(/account\/personal\-details/gi) && thisLink.href.substr(window.location.href.length - 14, 14) !== '#Post_Template') { thisLink.href = thisLink.href + '#Post_Template'; thisLink.click(); break; } } } } function xenForoMessage(msg, success) { if (success) { $('#templateMessage .content').html(msg); console.log(msg); } else { $('#templateMessage .content').html('<strong>Error:</strong> ' + msg); console.log('Error:', msg); } $('#templateMessage').slideDown('medium'); $('#templateMessage .content').animate({ 'opacity': 1 }, 'fast'); setTimeout(function() { $('#templateMessage').slideUp('medium'); $('#templateMessage .content').animate({ 'opacity': 0 }, 'fast'); }, 1500); } function runInGlobal(code) { var scripts = document.createElement('script'); scripts.type = 'text/javascript'; scripts.id = 'runInGlobal'; scripts.appendChild(document.createTextNode( code + '\n\n' + 'document.getElementById(\'runInGlobal\').remove();' )); (document.head || document.body || document.documentElement).appendChild(scripts); } function saveTemplateSettings() { if (!document.getElementById('htmlPrefixField').value.length) { xenForoMessage('HTML prefix required.', false); return false; } if (!document.getElementById('htmlSuffixField').value.length) { xenForoMessage('HTML suffix required.', false); return false; } if (!document.getElementById('bbPrefixField').value.length) { xenForoMessage('BBCode prefix required.', false); return false; } if (!document.getElementById('bbSuffixField').value.length) { xenForoMessage('BBCode suffix required.', false); return false; } var opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {}; opts.xf_template_auto = (document.getElementById('autoApplyField').options[document.getElementById('autoApplyField').selectedIndex].value === 'true'); opts.xf_template_htmlPrefix = document.getElementById('htmlPrefixField').value; opts.xf_template_htmlSuffix = document.getElementById('htmlSuffixField').value; opts.xf_template_bbPrefix = document.getElementById('bbPrefixField').value; opts.xf_template_bbSuffix = document.getElementById('bbSuffixField').value; localStorage.setItem('MakazeScriptOptions', JSON.stringify(opts)); xenForoMessage('Your settings have been saved.', true); } var applyHandler = function() { applyTemplate(this); }; if (document.documentElement.id === "XenForo") { var opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {}, autoApply = (opts.hasOwnProperty('xf_template_auto')) ? opts.xf_template_auto : false, htmlPrefix = (opts.hasOwnProperty('xf_template_htmlPrefix')) ? opts.xf_template_htmlPrefix : '', htmlSuffix = (opts.hasOwnProperty('xf_template_htmlSuffix')) ? opts.xf_template_htmlSuffix : '', bbPrefix = (opts.hasOwnProperty('xf_template_bbPrefix')) ? opts.xf_template_bbPrefix : '', bbSuffix = (opts.hasOwnProperty('xf_template_bbSuffix')) ? opts.xf_template_bbSuffix : '', instance, buttonsContext, richInstance, richDoc, field, i = 0; // Button creation and auto-application if (document.getElementsByClassName('MessageEditor')[0] != null) { for (i = 0; i < document.getElementsByClassName('MessageEditor').length; i++) { instance = document.getElementsByClassName('MessageEditor')[i]; buttonsContext = instance; while (buttonsContext.getElementsByClassName('submitUnit')[0] == null && buttonsContext.parentNode) { buttonsContext = buttonsContext.parentNode; } buttonsContext = buttonsContext.getElementsByClassName('submitUnit')[0].getElementsByClassName('button primary')[0].parentNode; var applyButton = document.createElement('input'), applyButtonSpacer = document.createTextNode(String.fromCharCode(160)); applyButton.type = 'button'; applyButton.value = 'Apply Style'; applyButton.className = 'button JsOnly applyButton'; applyButton.onclick = applyHandler; buttonsContext.appendChild(applyButtonSpacer); buttonsContext.appendChild(applyButton); if (autoApply.toString() === 'true') { applyTemplate(instance); } } document.addEventListener('keydown', function(e) { var i = 0, keyInstance; if (e.keyCode == 84 && e.altKey) { for (i = 0; i < document.getElementsByClassName('MessageEditor').length; i++) { keyInstance = document.getElementsByClassName('MessageEditor')[i]; applyTemplate(keyInstance); } } }, false); var applyToRichHandler = function(e) { if (e.keyCode == 84 && e.altKey) { applyTemplate(richInstance); } }; if (document.getElementsByClassName('redactor_MessageEditor')[0] != null) { for (i = 0; i < document.getElementsByClassName('redactor_MessageEditor').length; i++) { richInstance = document.getElementsByClassName('redactor_MessageEditor')[i]; richDoc = richInstance.contentWindow.document; richDoc.addEventListener('keydown', applyToRichHandler, false); } } } if (window.location.href.match(/account\/personal\-details/gi)) { // Define xenForoMessage and saveTemplateSettings runInGlobal( xenForoMessage.toString() + saveTemplateSettings.toString() ); // Settings creation var optionsContainer = document.createElement('fieldset'), header = document.createElement('dl'), headerDT = document.createElement('dt'), headerDD = document.createElement('dd'), headerDD_Text = document.createTextNode('Post Style'), autoApplyField = document.createElement('dl'), autoApplyFieldDT = document.createElement('dt'), autoApplyFieldDT_Text = document.createTextNode('Auto-apply:'), autoApplyFieldDD = document.createElement('dd'), autoApplyFieldDD_Select = document.createElement('select'), autoApplyFieldDD_Select_true = document.createElement('option'), autoApplyFieldDD_Select_true_Text = document.createTextNode('True'), autoApplyFieldDD_Select_false = document.createElement('option'), autoApplyFieldDD_Select_false_Text = document.createTextNode('False'), htmlPrefixField = document.createElement('dl'), htmlPrefixFieldDT = document.createElement('dt'), htmlPrefixFieldDT_Text = document.createTextNode('HTML Prefix:'), htmlPrefixFieldDD = document.createElement('dd'), htmlPrefixFieldDD_input = document.createElement('input'), htmlSuffixField = document.createElement('dl'), htmlSuffixFieldDT = document.createElement('dt'), htmlSuffixFieldDT_Text = document.createTextNode('HTML Suffix:'), htmlSuffixFieldDD = document.createElement('dd'), htmlSuffixFieldDD_input = document.createElement('input'), bbPrefixField = document.createElement('dl'), bbPrefixFieldDT = document.createElement('dt'), bbPrefixFieldDT_Text = document.createTextNode('BBCode Prefix:'), bbPrefixFieldDD = document.createElement('dd'), bbPrefixFieldDD_input = document.createElement('input'), bbSuffixField = document.createElement('dl'), bbSuffixFieldDT = document.createElement('dt'), bbSuffixFieldDT_Text = document.createTextNode('BBCode Suffix:'), bbSuffixFieldDD = document.createElement('dd'), bbSuffixFieldDD_input = document.createElement('input'), submitField = document.createElement('dl'), submitFieldDT = document.createElement('dt'), submitFieldDD = document.createElement('dd'), submitFieldDD_input = document.createElement('input'), templateMessage = document.createElement('div'), templateMessage_content = document.createElement('div'), templateMessage_content_Text = document.createTextNode('Your settings have been saved.'); // Load input settings htmlPrefixFieldDD_input.value = htmlPrefix; htmlSuffixFieldDD_input.value = htmlSuffix; bbPrefixFieldDD_input.value = bbPrefix; bbSuffixFieldDD_input.value = bbSuffix; // Header headerDD.setAttribute('style', 'font-weight: bolder; font-size: 130%; width: 40%; text-decoration: underline;'); headerDD.appendChild(headerDD_Text); header.className = 'ctrlUnit'; header.appendChild(headerDT); header.appendChild(headerDD); // Auto apply field autoApplyFieldDT.appendChild(autoApplyFieldDT_Text); autoApplyFieldDD_Select_true.value = true; autoApplyFieldDD_Select_true.appendChild(autoApplyFieldDD_Select_true_Text); autoApplyFieldDD_Select_false.value = false; autoApplyFieldDD_Select_false.appendChild(autoApplyFieldDD_Select_false_Text); autoApplyFieldDD_Select.id = 'autoApplyField'; autoApplyFieldDD_Select.className = 'textCtrl'; autoApplyFieldDD_Select.appendChild(autoApplyFieldDD_Select_true); autoApplyFieldDD_Select.appendChild(autoApplyFieldDD_Select_false); autoApplyFieldDD.appendChild(autoApplyFieldDD_Select); autoApplyField.className = 'ctrlUnit'; autoApplyField.appendChild(autoApplyFieldDT); autoApplyField.appendChild(autoApplyFieldDD); // HTML prefix field htmlPrefixFieldDT.appendChild(htmlPrefixFieldDT_Text); htmlPrefixFieldDD_input.type = 'text'; htmlPrefixFieldDD_input.id = 'htmlPrefixField'; htmlPrefixFieldDD_input.className = 'textCtrl OptOut'; htmlPrefixFieldDD.appendChild(htmlPrefixFieldDD_input); htmlPrefixField.className = 'ctrlUnit'; htmlPrefixField.appendChild(htmlPrefixFieldDT); htmlPrefixField.appendChild(htmlPrefixFieldDD); // HTML suffix field htmlSuffixFieldDT.appendChild(htmlSuffixFieldDT_Text); htmlSuffixFieldDD_input.type = 'text'; htmlSuffixFieldDD_input.id = 'htmlSuffixField'; htmlSuffixFieldDD_input.className = 'textCtrl OptOut'; htmlSuffixFieldDD.appendChild(htmlSuffixFieldDD_input); htmlSuffixField.className = 'ctrlUnit'; htmlSuffixField.appendChild(htmlSuffixFieldDT); htmlSuffixField.appendChild(htmlSuffixFieldDD); // BBCode prefix field bbPrefixFieldDT.appendChild(bbPrefixFieldDT_Text); bbPrefixFieldDD_input.type = 'text'; bbPrefixFieldDD_input.id = 'bbPrefixField'; bbPrefixFieldDD_input.className = 'textCtrl OptOut'; bbPrefixFieldDD.appendChild(bbPrefixFieldDD_input); bbPrefixField.className = 'ctrlUnit'; bbPrefixField.appendChild(bbPrefixFieldDT); bbPrefixField.appendChild(bbPrefixFieldDD); // BBCode suffix field bbSuffixFieldDT.appendChild(bbSuffixFieldDT_Text); bbSuffixFieldDD_input.type = 'text'; bbSuffixFieldDD_input.id = 'bbSuffixField'; bbSuffixFieldDD_input.className = 'textCtrl OptOut'; bbSuffixFieldDD.appendChild(bbSuffixFieldDD_input); bbSuffixField.className = 'ctrlUnit'; bbSuffixField.appendChild(bbSuffixFieldDT); bbSuffixField.appendChild(bbSuffixFieldDD); // Submit field submitFieldDD_input.type = 'button'; submitFieldDD_input.id = 'submitTemplate'; submitFieldDD_input.className = 'button'; submitFieldDD_input.value = 'Save'; submitFieldDD_input.setAttribute('onClick', 'saveTemplateSettings();'); submitFieldDD.appendChild(submitFieldDD_input); submitField.className = 'ctrlUnit'; submitField.appendChild(submitFieldDT); submitField.appendChild(submitFieldDD); // Template message templateMessage_content.className = 'content baseHtml'; templateMessage_content.style.opacity = 0; templateMessage_content.appendChild(templateMessage_content_Text); templateMessage.id = 'templateMessage'; templateMessage.className = 'xenOverlay timedMessage'; templateMessage.setAttribute('style', 'top: 0px; left: 0px; position: fixed; display: none;'); templateMessage.appendChild(templateMessage_content); // Build it all optionsContainer.id = 'templateOptionsContainer'; optionsContainer.appendChild(header); optionsContainer.appendChild(autoApplyField); optionsContainer.appendChild(htmlPrefixField); optionsContainer.appendChild(htmlSuffixField); optionsContainer.appendChild(bbPrefixField); optionsContainer.appendChild(bbSuffixField); optionsContainer.appendChild(submitField); document.getElementsByClassName('OptOut')[document.getElementsByClassName('OptOut').length - 1].parentNode.insertBefore(optionsContainer, document.getElementsByClassName('OptOut')[document.getElementsByClassName('OptOut').length - 1]); (document.body || document.documentElement).appendChild(templateMessage); // Load auto apply setting for (i = 0, field = document.getElementById('autoApplyField'); i < field.options.length; i++) { if (field.options[i].value === autoApply.toString()) { field.selectedIndex = i; } } if (window.location.href.substr(window.location.href.length - 14, 14) === '#Post_Template') { scrollTo(document.body, getPosition(document.getElementById('templateOptionsContainer')).y, 100); runInGlobal('xenForoMessage(\'Post Template installed. Customize your settings.\', true);'); } } }