2,733
edits
Red Leader (talk | contribs) (Tiny fixes, etc.) |
Red Leader (talk | contribs) (Version 0.19 of script. Most transformation functions re-factored) |
||
Line 55: | Line 55: | ||
== Issues/limitations == | == Issues/limitations == | ||
* The JavaScript {{Func link|prompt()|ext=https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt}} boxes used are typically restricted to a max size of about 10 KB; other options should be looked at. {{Not done}} | * The JavaScript {{Func link|window.prompt()|ext=https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt}} boxes used are typically restricted to a max size of about 10 KB; other options should be looked at. {{Not done}} | ||
== Feature requests & ideas == | == Feature requests & ideas == | ||
* Add support for [http://sourceforge.net/p/flightgear/codetickets/ tickets], merge requests comments and [http://www.fguk.eu/index.php/forum/index FGUK forum]. | |||
* GET-encoded SID arguments should be stripped from forum URLs. {{Not done}} | * GET-encoded SID arguments should be stripped from forum URLs. {{Not done}} | ||
* Links to repositories should be converted to use wiki templates. {{Not done}} | * Links to repositories should be converted to use wiki templates. {{Not done}} | ||
Line 74: | Line 75: | ||
// ==UserScript== | // ==UserScript== | ||
// @name Instant-Cquotes | // @name Instant-Cquotes | ||
// @version 0. | // @version 0.19 | ||
// @description Automatically converts mailing list and forum quotes into Mediawiki markup. | // @description Automatically converts mailing list and forum quotes into Mediawiki markup. | ||
// @author Hooray, bigstones, Philosopher & Red Leader | // @author Hooray, bigstones, Philosopher & Red Leader | ||
Line 90: | Line 91: | ||
// ==/UserScript== | // ==/UserScript== | ||
// Check if Greasemonkey/Tampermonkey is available | |||
try { | try { | ||
GM_addStyle(GM_getResourceText("jQUI_CSS")); | GM_addStyle(GM_getResourceText("jQUI_CSS")); | ||
Line 98: | Line 100: | ||
// Define constants | // Define constants | ||
var DEBUG = | var DEBUG = true; | ||
var CONFIG = { | var CONFIG = { | ||
" | "Mailing list": { | ||
url_reg: /http:\/\/sourceforge\.net\/p\/flightgear\/mailman\/.*/, | |||
content: { | content: { | ||
selection: getSelectedText, | selection: getSelectedText, | ||
idStyle: /msg[0-9]{8}/, | idStyle: /msg[0-9]{8}/, | ||
parentTag: ["tagName", "PRE" | parentTag: ["tagName", "PRE"] | ||
}, | }, | ||
author: { | author: { | ||
Line 126: | Line 127: | ||
}, | }, | ||
"forum | "FlightGear forum": { | ||
url_reg: /http:\/\/forum\.flightgear\.org\/.*/, | |||
content: { | content: { | ||
selection: getSelectedHtml, | selection: getSelectedHtml, | ||
idStyle: /p[0-9]{6}/, | idStyle: /p[0-9]{6}/, | ||
parentTag: ["className", "content", "postbody"], | parentTag: ["className", "content", "postbody"], | ||
transform: [removeComments, | transform: [removeComments, forum_quote2cquote, forum_smilies2text, | ||
forum_fontstyle2wikistyle, forum_code2syntaxhighlight, img2link, | |||
a2wikilink, vid2wiki, list2wiki, forum_br2newline] | |||
}, | }, | ||
author: { | author: { | ||
Line 159: | Line 161: | ||
}, | }, | ||
// Show a jQuery dialog | |||
jQueryDiag: function(msg) { | jQueryDiag: function(msg) { | ||
var diagDiv = $('<div id="MyDialog"><textarea id="quotedtext" rows="10"cols="80" style="width: 290px; height: 290px">' + msg + '</textarea></div>'); | var diagDiv = $('<div id="MyDialog"><textarea id="quotedtext" rows="10"cols="80" style="width: 290px; height: 290px">' + msg + '</textarea></div>'); | ||
Line 176: | Line 179: | ||
}; | }; | ||
var | var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; | ||
var | // Conversion for forum emoticons | ||
var EMOTICONS = [ | |||
[/:shock:/g, "O_O"], | |||
[/:lol:/g, "(lol)"], | |||
[/:oops:/g, ":$"], | |||
[/:cry:/g, ";("], | |||
[/:evil:/g, ">:)"], | |||
[/:twisted:/g, "3:)"], | |||
[/:roll:/g, "(eye roll)"], | |||
[/:wink:/g, ";)"], | |||
[/:!:/g, "(!)"], | |||
[/:\?:/g, "(?)"], | |||
[/:idea:/g, "(idea)"], | |||
[/:arrow:/g, "(->)"], | |||
[/:mrgreen:/g, "xD"] | |||
]; | |||
// ################## | // ################## | ||
Line 186: | Line 204: | ||
window.addEventListener('load', init); | window.addEventListener('load', init); | ||
// Initialize | |||
function init() { | function init() { | ||
document.onmouseup = instantCquote; | document.onmouseup = instantCquote; | ||
Line 191: | Line 210: | ||
} | } | ||
// The main function | |||
function instantCquote() { | function instantCquote() { | ||
var profile = | var profile = getProfile(), | ||
selection = document.getSelection(), | selection = document.getSelection(), | ||
output = {}, | output = {}, | ||
Line 229: | Line 249: | ||
} | } | ||
output.content = stripWhitespace(output.content); | |||
output = createCquote(output); | output = createCquote(output); | ||
outputText(output); | |||
} | |||
// Gets to correct profile | |||
function getProfile(){ | |||
for (var profile in CONFIG){ | |||
if(window.location.href.match(CONFIG[profile].url_reg) !== null){ | |||
return CONFIG[profile]; | |||
} | |||
} | |||
} | } | ||
// Get the HTML code that is selected | |||
function getSelectedHtml() { | function getSelectedHtml() { | ||
// From http://stackoverflow.com/a/6668159 | // From http://stackoverflow.com/a/6668159 | ||
Line 253: | Line 285: | ||
} | } | ||
// | // Gets the selected text | ||
function getSelectedText() { | function getSelectedText() { | ||
return document.getSelection().toString(); | return document.getSelection().toString(); | ||
} | } | ||
// Get the ID of the post | |||
function getPostId(selection, profile, focus) { | function getPostId(selection, profile, focus) { | ||
if (focus !== undefined) { | if (focus !== undefined) { | ||
Line 272: | Line 305: | ||
} | } | ||
// Checks that the selection is valid | |||
function checkValid(selection, profile) { | function checkValid(selection, profile) { | ||
var ret = true, | var ret = true, | ||
Line 311: | Line 345: | ||
} | } | ||
// Extracts the raw text from a certain place, using an XPath | |||
function extractFieldInfo(profile, id, field) { | function extractFieldInfo(profile, id, field) { | ||
if (field === "content") { | if (field === "content") { | ||
Line 320: | Line 355: | ||
} | } | ||
// Change the text using spcified transformations | |||
function applyTransformations(fieldInfo, trans) { | function applyTransformations(fieldInfo, trans) { | ||
if (typeof trans === "function") { | if (typeof trans === "function") { | ||
return trans(fieldInfo); | return trans(fieldInfo); | ||
} else if (Array.isArray(trans)) { | } else if (Array.isArray(trans)) { | ||
Line 333: | Line 368: | ||
} | } | ||
// Formats the quote | |||
function createCquote(data) { | function createCquote(data) { | ||
var wikiText = "{{FGCquote\n" + | var wikiText = "{{FGCquote\n" + | ||
"|" + data.content + "\n" + | ((data.content.match(/^\s*?{{cquote/) === null) ? "|1= " : "| ") + data.content + "\n" + | ||
"| {{cite web\n" + | "|2= {{cite web\n" + | ||
" | url = " + data.url + "\n" + | " | url = " + data.url + "\n" + | ||
" | title = " + nowiki(data.title) + "\n" + | " | title = " + nowiki(data.title) + "\n" + | ||
Line 345: | Line 381: | ||
return wikiText; | return wikiText; | ||
} | |||
// Output the text. | |||
// Tries the jQuery dialog, and falls back to window.prompt() | |||
function outputText(msg){ | |||
try { | |||
METHODS.jQueryDiag(msg); | |||
} | |||
catch(err){ | |||
METHODS.msgbox(msg); | |||
} | |||
} | } | ||
Line 367: | Line 414: | ||
} | } | ||
function escapePipes( | // Not currently used (as of June 2015), but kept just in case | ||
function escapePipes(html) { | |||
html = html.replace(/\|\|/g,"{{!!}}"); | |||
return | html = html.replace(/\|\-/g,"{{!-}}"); | ||
return html.replace(/\|/g,"{{!}}"); | |||
} | } | ||
// Converts HTML <a href="...">...</a> tags to wiki links, internal if possible. | // Converts HTML <a href="...">...</a> tags to wiki links, internal if possible. | ||
function a2wikilink(html){ | function a2wikilink(html){ | ||
// Links to wiki images, because | // Links to wiki images, because | ||
// they need special treatment, or else they get displayed. | // they need special treatment, or else they get displayed. | ||
Line 407: | Line 456: | ||
} | } | ||
// Converts images, including images in <a> links | |||
function img2link(html) { | function img2link(html) { | ||
html = html.replace(/<a[^<]*?href="([^<]*?)"[^<]*?><img.*?src="http:\/\/wiki\.flightgear\.org\/images\/.*?\/.*?\/(.*?)".*?><\/a>/g, "[[File:$2|250px|link=$1]]"); | |||
html = html.replace(/<img.*?src="http:\/\/wiki\.flightgear\.org\/images\/.*?\/.*?\/(.*?)".*?>/g, "[[File:$1|250px]]"); | html = html.replace(/<img.*?src="http:\/\/wiki\.flightgear\.org\/images\/.*?\/.*?\/(.*?)".*?>/g, "[[File:$1|250px]]"); | ||
html = html.replace(/<a[^<]*?href="([^<]*?)"[^<]*?><img.*?src="(.*?)".*?><\/a>/g, "(see [$2 image], links to [$1 here])"); | |||
return html.replace(/<img.*?src="(.*?)".*?>/g, "(see the [$1 linked image])"); | return html.replace(/<img.*?src="(.*?)".*?>/g, "(see the [$1 linked image])"); | ||
} | } | ||
function | // Converts smilies | ||
function forum_smilies2text(html) { | |||
html = html.replace(/<img src="\.\/images\/smilies\/icon_.*?\.gif" alt="(.*?)".*?>/g, "$1"); | |||
for (var i = 0; i < EMOTICONS.length; i++){ | |||
html = html.replace(EMOTICONS[i][0], EMOTICONS[i][1]); | |||
} | |||
return html; | |||
} | } | ||
function | // Converts font formatting | ||
function forum_fontstyle2wikistyle(html) { | |||
html = html.replace(/<span style="font-weight: bold">(.*?)<\/span>/g, "'''$1'''"); | html = html.replace(/<span style="font-weight: bold">(.*?)<\/span>/g, "'''$1'''"); | ||
html = html.replace(/<span style="text-decoration: underline">(.*?)<\/span>/g, "<u>$1</u>"); | html = html.replace(/<span style="text-decoration: underline">(.*?)<\/span>/g, "<u>$1</u>"); | ||
Line 423: | Line 481: | ||
} | } | ||
function | // Converts code blocks | ||
function forum_code2syntaxhighlight(html) { | |||
var list = html.match(/<dl class="codebox">.*?<code>(.*?)<\/code>.*?<\/dl>/g), | |||
data = []; | |||
if (list === null) return html; | |||
for(var n = 0; n < list.length; n++){ | |||
data = html.match(/<dl class="codebox">.*?<code>(.*?)<\/code>.*?<\/dl>/); | |||
html = html.replace(data[0], processCode(data)); | |||
} | |||
return html; | |||
} | |||
// Strips any whitespace from the beginning and end of a string | |||
function stripWhitespace(html){ | |||
html = html.replace(/^\s*?(\S)/, "$1") | |||
return html.replace(/(\S)\s*?\z/, "$1"); | |||
} | |||
// Process code, including basic detection of language | |||
function processCode(data){ | |||
var lang = "", | |||
code = data[1]; | |||
code = code.replace(/ /g, " "); | |||
if (code.match(/=?.*?\(?.*?\)?;/) !== null) lang = "nasal"; | |||
if (code.match(/<.*?>.*?<\/.*?>/) !== null || code.match(/<!--.*?-->/) !== null) lang = "xml"; | |||
code = code.replace(/<br\/?>/g, "\n"); | |||
return '<syntaxhighlight lang="' + lang + '" enclose="div">\n' + code + '\n</syntaxhighlight>'; | |||
} | } | ||
function | // Converts quote blocks to Cquotes | ||
function forum_quote2cquote(html) { | |||
html = html.replace(/<blockquote class="uncited"><div>(.*?)<\/div><\/blockquote>/g, "{{cquote|$1}}"); | |||
if (html.match(/<blockquote>/g) === null) return html; | |||
var numQuotes = html.match(/<blockquote>/g).length; | |||
for(var n = 0; n < numQuotes; n++){ | |||
html = html.replace(/<blockquote><div><cite>(.*?) wrote.*?:<\/cite>(.*?)<\/div><\/blockquote>/, "{{cquote|$2|$1}}"); | |||
} | |||
return html; | |||
} | } | ||
// Converts videos to wiki style | |||
function vid2wiki(html){ | function vid2wiki(html){ | ||
// YouTube | // YouTube | ||
html = html.replace(/<div.*?><iframe width="(.*?)" height="(.*?)" src="http:\/\/www\.youtube\.com\/embed\/(.*?)".*?><\/iframe><\/div>/g, "{{#ev:youtube|$3|$1x$2}} | html = html.replace(/<div class="video-wrapper">\s.*?<div class="video-container">\s*?<iframe class="youtube-player".*?width="(.*?)" height="(.*?)" src="http:\/\/www\.youtube\.com\/embed\/(.*?)".*?><\/iframe>\s*?<\/div>\s*?<\/div>/g, "{{#ev:youtube|$3|$1x$2}}"); | ||
// Vimeo | // Vimeo | ||
html = html.replace(/<iframe src="http:\/\/player\.vimeo\.com\/video\/(.*?)\?.*?" width="(.*?)" height="(.*?)".*?>.*?<\/iframe>/g, "{{#ev:vimeo|$ | html = html.replace(/<iframe src="http:\/\/player\.vimeo\.com\/video\/(.*?)\?.*?" width="(.*?)" height="(.*?)".*?>.*?<\/iframe>/g, "{{#ev:vimeo|$1|$2x$3}}"); | ||
return html.replace(/\[.*? Watch on Vimeo\]/g, ""); | return html.replace(/\[.*? Watch on Vimeo\]/g, ""); | ||
} | } | ||
// Not currently used (as of June 2015), but kept just in case | |||
function escapeEquals(html) { | function escapeEquals(html) { | ||
return html.replace(/=/g,"{{=}}"); | return html.replace(/=/g,"{{=}}"); | ||
} | } | ||
function | // <br> to newline. | ||
html = html.replace(/<br\/?>/g, "<br/>\n"); | function forum_br2newline(html) { | ||
html = html.replace(/(<\/ | html = html.replace(/<br\/?><br\/?>/g, "\n"); | ||
return html.replace(/<br\/?>/g, "\n\n"); | |||
} | |||
// Forum list to wiki style | |||
function list2wiki(html) { | |||
var list = html.match(/<ul>(.*?)<\/ul>/g); | |||
if (list !== null){ | |||
for(var i = 0; i < list.length; i++){ | |||
html = html.replace(/<li>(.*?)<\/li>/g, "* $1\n"); | |||
} | |||
} | |||
list = html.match(/<ol.*?>(.*?)<\/ol>/g); | |||
if (list !== null){ | |||
for(var i = 0; i < list.length; i++){ | |||
html = html.replace(/<li>(.*?)<\/li>/g, "# $1\n"); | |||
} | |||
} | |||
html = html.replace(/<\/?[uo]l>/g, ""); | |||
return html; | |||
} | } | ||
Line 456: | Line 578: | ||
// Returns the correct ordinal adjective | // Returns the correct ordinal adjective | ||
function ordAdj(date){ | function ordAdj(date) { | ||
date = date.toString(); | date = date.toString(); | ||
if(date == "11" || date == "12" || date == "13"){ | if(date == "11" || date == "12" || date == "13"){ | ||
Line 479: | Line 601: | ||
function underscore2Space(str){ | function underscore2Space(str){ | ||
return str.replace(/_/g, " "); | return str.replace(/_/g, " "); | ||
} | } | ||