User:V111P/js/smartLinking.js
Appearance
< User:V111P | js
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:V111P/js/smartLinking. |
// <nowiki>
/*
* smartLinking.js
* Ver. 2015-10-05
*
* A tool for linking articles and previewing the linked pages
* while source-editing Wikipedia/MediaWiki articles.
*
* Home: http://en.wikipedia.org/wiki/User:V111P/js/Smart_Linking
*
* requires: msgDisplay.js and wikiParserV.js,
* both of which are auto loaded from this script and can also be
* found here: http://en.wikipedia.org/wiki/User:V111P/js
*
* CC0 Public Domain Dedication:
* http://creativecommons.org/publicdomain/zero/1.0/
* If you use large parts of this code, please let me know.
* You should also let others know where the code originates:
* http://en.wikipedia.org/wiki/User:V111P/js/smartLinking.js
* Thanks.
*/
window.smartLinking = (function ($) {
"use strict";
var articleNamesCapitalized = true; // always true for Wikipedia, but not for Wiktionary
var whitelistedTags = 'sup, sub, i, b, br, em, strong, tt, kbd'; // del, ins, u, mark, s, strike
var maxAgeSeconds = {
forArticles: 5, sForArticles: 1,
forOtherMeanings: 300, sForOtherMeanings: 60
};
var allPossibleOtherMeaningTemplates = false; // for testing - for checking for other templates
var linkFocusTimeoutId; // used in the function focusFn
var msgs = {
scriptName: 'Smart Linking',
noValidLink: 'No valid link was selected or focused.',
error: 'Error',
help: 'Help',
openInNewWin: 'Open in a new window',
editInNewWin: 'Edit in a new window',
editIntro: 'Edit the introduction',
history: 'History',
talk: 'Talk',
watch: 'Watch',
unwatch: 'Unwatch',
disambigPage: 'Disambiguation page',
nonExistingPage: 'Non-existing page',
errorLoadingScript: 'Error loading required script {required script}.',
backTo: 'Back to [[%1]]', // Back to [[<the previous page's title>]]
relatedArticles: 'Related articles',
tableOfContents: 'Table of contents',
tocAndOtherAndMainArticles: 'ToC and other meanings and main articles:',
backToTop: 'Back to top',
focusTextarea: 'Focus the textarea', // title attr of the button that collapses the display
close: 'Close',
toggleSectionLinks: 'Toggle displaying the section links',
aSpecialNSLink: 'A link to a page in the Special namespace.',
aLinkToSecInCurrEdPg: 'A link to a section in the page you are currently editing.',
errorOnLoading: 'Could not load page. Check your Internet connection.',
unsupportedBrowser: 'Unsupported browser'
};
var locale = {
helpUrl: '//en.wikipedia.org/wiki/User:V111P/js/Smart_Linking',
// en.wikipedia.org/wiki/Category:Disambiguation_and_redirection_templates
otherMeaningTemplateNames: ['about', 'hatnote', 'rellink', 'other uses(\\d| of)?',
'(two|three) other uses', 'see', 'see also\\d?', 'also', 'main( list)?', 'details\\d',
'for\\d?', 'redirect(-synonym|text|-distinguish)?\\d?\\d?', 'further\\d?',
'consider disambiguation', 'other people\\d?', 'other places\\d?', 'other hurricanes',
'other ships', 'distinguish\\d?', 'elect',
'year dab', 'more information'],
// not needed if disambig pages/templates have the __DISAMBIG__ magic word:
// disambigTemplateNames: ['dab', 'disamb(ig)?'],
disambigPgSuffix: ' (disambiguation)', // used to give link to that page
// in case other-meanings template is used on page
anchorTemplateNames: ['anchor']
};
var requiredScripts = [{
objLocation: mediaWiki.libs,
objName: 'msgDisplay', // [[User:V111P/js/msgDisplay.js]]
url: '//en.wikipedia.org/w/index.php?title='
+ 'User:V111P/js/msgDisplay.js&action=raw'
+ '&ctype=text/javascript&smaxage=3600&maxage=3600'
}, {
objLocation: mediaWiki.libs,
objName: 'wikiParserV', // [[User:V111P/js/wikiParserV.js]]
url: '//en.wikipedia.org/w/index.php?title='
+ 'User:V111P/js/wikiParserV.js&action=raw'
+ '&ctype=text/javascript&smaxage=3600&maxage=3600'
}];
var commonsUrl = '//upload.wikimedia.org/wikipedia/commons/';
var buttonIconUrl = commonsUrl + '9/96/Interpage_icon.png';
var buttonIconUrlClassic = commonsUrl + '5/5a/Interpage_button.png';
var imageProps = { // text messages updated in init()
attentionImg: {
src: commonsUrl + 'thumb/b/ba/Symbol_opinion_vote.svg/30px-Symbol_opinion_vote.svg.png',
alt: '!',
width: 15,
height: 15,
css: {width: '1.2em', height: '1.2em'}
},
editImg: {
src: commonsUrl + '3/31/WG.Icon.edit.png',
width: 13,
height: 13,
css: {width: '1em', height: '1em'}
},
anchorImg: { // not currently used
src: commonsUrl + 'thumb/6/62/Anchor_pictogram.svg/26px-Anchor_pictogram.svg.png',
width: 12,
height: 12,
alt: '@',
css: {width: '1em', height: '1em'}
},
newWinImg: {
src: commonsUrl
+ '/thumb/c/c1/Inkscape_icons_window_new.svg/26px-Inkscape_icons_window_new.svg.png',
width: 12,
height: 12,
alt: 'new window',
css: {width: '1em', height: '1em'}
},
externalLinkImg: { // not currently used
src: commonsUrl + 'thumb/4/44/Icon_External_Link.svg/26px-Icon_External_Link.svg.png',
width: 12,
height: 12,
css: {width: '1em', height: '1em'}
},
relatedImg: {
src: commonsUrl + '7/72/OSM_relation.png',
width: 12,
height: 12,
css: {width: '1em', height: '1em'}
},
tocImg: {
src: commonsUrl + 'f/f7/Plan.png',
width: 12,
height: 12,
css: {width: '1em', height: '1em'}
},
upImg: {
src: commonsUrl + '5/56/Icon_Arrow_Up_26x26.png',
width: 12,
height: 12,
css: {width: '1em', height: '1em'}
},
okImg: {
src: commonsUrl + 'thumb/a/ac/Approve_icon.svg/26px-Approve_icon.svg.png',
width: 12,
height: 12,
alt: '[_]',
css: {width: '1em', height: '1em'}
}
};
var images = {}; // set in setup() and init()
var toolbarButton = {
id: 'smartLinkingButton',
tooltip: msgs.scriptName, // text messages updated in init()
section: 'main',
group: 'insert',
callback: smartLinkingFn,
iconUrl: buttonIconUrl // updated in init()
};
var miscStyle = {
noDataReceivedLinkColor: '#900', // the link at the beginning that opens the article in a new window
visitedPgLinkColor: '#9370db',
notExistingPgLinkColor: '#f08080',
normalPgLinkColor: 'blue'
};
var re = {
// en:Wikipedia:Page_name#Invalid_page_names :
// ASCII 0–31 (dec), the del char 127, the Unicode replacement character U+FFFD
wikiLinkIllegalChars: /[\[\]{}<>|\u0000-\u001f\u007f\ufffd]/,
// "." or "..", or beginning "./" or "../", or containing "/./" or "/../" or 3 or more continuous tildes ~,
// or ending "/." or "/..", or exceeding 255 bytes in length (at least for ANSI names)
wikiLinkIllegalNames:
/^(\.\.?\/|\s|_|.{256,})|^(\.\.?|:)$|(\/\.\.?\/|~~\~)|(\s|\_|\/\.\.?)$/,
trimBracketsG: /^\[\[|]]$/g,
addrSectionPart: /#.*/, // includes the # // re.addrTitlePart = /(?:(?!#).)*/;
titleDisabigPart: /\s\([^)]+\)$/,
redirect: /^(#[^\[]{1,25}\[\[)([^|\]]+)(\|.*|\]\][\S\s]*)/,
textBeforeFirstBullet: /\n\*[\S\s]*/,
oneOrMoreEmptyLinesG: /([^\S\n]*\n){2,}/g,
divideSectionHeading: /^(=+)([\S\s]+)\1$/,
otherMeaningNoTemplG: /(^|=|})([^\S\n]*\n)+:[^\n]+\n/g,
otherMeaningNoTemplTrimG: /(^|\n):\s*('')?|('')?\s*$/g,
wikiLinkAddrAndLabelG: /\[\[([^\]|]+)\|?([^\]]*)]]/g, // linkifyText
wikiLinkAddr: /^\[\[([^|\]]*)/, // insertLink()
linkAddrsIn$1G: /\[\[([^|\]]+)\|[^\]]*\]\]/g,
wikiLinkRemoveOpeningBracketsAndUpToAndInclPipe: /^\[\[(.+?\|)?/, // insertLink(),
possibleOtherMeaningTemplatesG: /^\{\{[^}|\n]+\|[^}\n]+}}[^\S\n]*$/gm,
splitTemplateParamsG: /(?:[^|[{}]|\[[^\]]*]|\{\{[^}]*}}|\{[^{]|}[^}])+|(?=\|\|)/g,
pipeTemplateToEndOfParam: /{{!}}[^|}]+/,
nAsteriskG: /\n\*/g, nHashSymbolG: /\n#/g, nSemicolonG: /\n;/g, nColonG: /\n:/g, nG: /\n/g
};
// time to wait for a required script to load before error msg:
var moduleLoadingTimeout = 15000;
var wikiParser; // = wikiParser - loaded in another .js file
var display; // = msgDisplay - loaded in another .js file
var visitedPages = {}; // '+' for visited/loaded pages, '' for visited non-existing pages
var pgHistory = []; // page pgHistory for the << button
var lastLinkAddr = ''; // last inserted or found addr in the textarea.
var linkStartPos = -1; // need to save it for IE, and also if user clicks outside of link
// in the textarea and then wants to continue browsing
var sectIdPrefix = 'smrtL_section_' + Math.ceil(Math.random() * 9999) + '_'; // not really needed
// unless in the future two smartLinking windows can exist at the same time on the page
var textarea;
// prints a message to the console, and if it's an error message, to the display too
function prt(msg, isErrorMsg) {
if (typeof msg != 'object') {
msg = (isErrorMsg ? msgs.error + ': ' : '') + msg;
if (isErrorMsg && display) {
if (images.attention)
display.append(images.attention.clone().attr('title', msgs.error));
display.appendTextWrite(' ' + msg);
}
msg = msgs.scriptName + ': ' + msg;
}
if (isErrorMsg && window.console && console.error)
console.error(msg);
else if (window.console && console.log)
console.log(msg);
} // prt
function setup() {
images.attention = $('<img/>', imageProps.attentionImg);
images.edit = $('<img/>', imageProps.editImg);
images.open = $('<img/>', imageProps.newWinImg);
images.related = $('<img/>', imageProps.relatedImg);
images.toc = $('<img/>', imageProps.tocImg);
images.up = $('<img/>', imageProps.upImg);
images.ok = $('<img/>', imageProps.okImg);
var c = window.smartLinkingConfig || {};
$.extend(msgs, c.msgs || {});
// save the Special namespace names
locale.specialNsPrefixes = [];
$.each(mw.config.get('wgNamespaceIds'), function (key, val) {
if (val == '-1') { // 'special'
if ($.inArray(key, locale.specialNsPrefixes) == -1)
locale.specialNsPrefixes.push(key);
}
});
init();
} // setup
// public function, to be called after updating the config object
function init() {
var c = window.smartLinkingConfig;
if (c) {
$.extend(locale, c.locale || {});
$.extend(msgs, c.msgs || {});
allPossibleOtherMeaningTemplates = c.allPossibleOtherMeaningTemplates
|| allPossibleOtherMeaningTemplates;
}
if (locale.disambigTemplateNames)
locale.disambigTemplateNameRegEx
= new RegExp('\\{\\{\\s*(' + locale.disambigTemplateNames.join('|')
+ ')\\s*(\\||})', 'i');
locale.otherMeaningTemplateNamesRegExG
= new RegExp('\\{\\{\\s*(' + locale.otherMeaningTemplateNames.join('|')
+ ')\\s*(\\|[^}{]*|([^}{]*\\{\\{[^}]+}}[^}{]*)*)}}', 'gi');
locale.anchorTemplateRegExG = new RegExp('\\{\\{((?:'
+ locale.anchorTemplateNames.join('|') + ')\\|[\\S\\s]+?)}}', 'gi');
} // init
// get and set the text and selection in the textarea
function valParts($el, textBefore, selText, textAfter) {
if (typeof textBefore == 'string') {
$el.val(textBefore + selText + textAfter);
var beforeLen = textBefore.length;
$el.textSelection('setSelection', {
'start': beforeLen,
'end': beforeLen + selText.length
});
return;
}
else {
var s = $el.textSelection('getCaretPosition', {startAndEnd: true} );
var text = $el.val().replace(/\r/g, '');
return [text.slice(0, s[0]), text.slice(s[0], s[1]), text.slice(s[1])];
}
}; // valParts
function correctLinking(justLoadScripts) {
function allLoaded() {
// check for regexp support
if ('<a><bd</e></b>'.replace(/<(?!\/?(a|b)>)/g, '<') != '<a><bd</e></b>') {
correctLinking = function () { prt('** ' + msg.unsupportedBrowser + ' **', true); }
return;
}
textarea = $('#wpTextbox1');
textarea.off('focus.smartLinking');
textarea.on('focus.smartLinking', function () {
display && display.collapse();
});
display = display || mediaWiki.libs.msgDisplay('edit');
display.config(window.smartLinkingConfig);
correctLinking = correctLinkingNow;
wikiParser = wikiParser || mediaWiki.libs.wikiParserV;
if (!justLoadScripts)
correctLinking();
}
function waitToExecute(again) {
var TimeoutToExecute = 250; // milliseconds
var notExecuted = null;
$.each(requiredScripts, function (index, val) {
if (!val.objLocation[val.objName]) {
// script not executed yet?
notExecuted = val.objName;
return false; // break
}
});
if (notExecuted) {
if (!again) {
errorOnLoadingModule(notExecuted);
return;
}
setTimeout(function () {
waitToExecute(again - 1);
},
TimeoutToExecute);
}
else
allLoaded();
}
function errorOnLoadingModule(scriptName) {
var msg = msgs.errorLoadingScript.replace('{required script}', scriptName);
prt(msg, true);
}
function loadNext(n) {
var callback;
if (n == requiredScripts.length - 1) {
callback = waitToExecute;
}
else
callback = function () { loadNext(n + 1); };
var reqScr = requiredScripts[n];
if (reqScr.objLocation[reqScr.objName])
callback(); // this one already loaded
else {
$.ajax({
url: reqScr.url,
dataType: 'script',
cache: true,
success: callback
});
setTimeout(function () {
if (!reqScr.objLocation[reqScr.objName])
errorOnLoadingModule(reqScr.objName);
}, moduleLoadingTimeout); // jQuery's fail callback is not called
// for cross-domain scripts, so can't use it.
}
}
if (!window.wikEd || !wikEd.useWikEd) {
// hopefully it was already loaded or will download while downloading the other scripts:
mw.loader.using('jquery.textSelection');
}
else if (wikEd.config && wikEd.config.offHook
&& typeof wikEd.config.offHook.push == 'function') {
wikEd.config.offHook.push(function () {
mw.loader.using('jquery.textSelection');
});
}
if (requiredScripts.length > 0)
loadNext(0);
else
allLoaded();
} // correctLinking
// points to correctLinking after the required scripts are loaded
function correctLinkingNow() {
if (window.wikEd && wikEd.useWikEd) {
wikEdCorrectLinking();
return;
}
var before, linkText, after;
var parts = valParts(textarea);
var focusLink = wikiParser.focusedSegment(parts, 'wikilink');
linkStartPos = -1;
if (focusLink) {
before = focusLink[0];
linkText = focusLink[1];
after = focusLink[2];
linkStartPos = before.length;
}
else {
linkText = parts[1];
// if some text was selected and it does not contain illegal chars:
if (linkText) {
// separate the beginning and ending spaces
before = parts[0];
after = parts[2];
var spaces = linkText.match(/^\s*/)[0];
before += spaces;
linkText = linkText.slice(spaces.length);
spaces = linkText.match(/\s*$/)[0];
after = spaces + after;
(spaces.length > 0) && (linkText = linkText.slice(0, -spaces.length));
linkText = '[[' + linkText + ']]';
linkStartPos = before.length;
}
}
focusTextarea();
var page = linkText.split('|')[0].replace(re.trimBracketsG, ''); // ^\[\[|]]$/g
if (page && !re.wikiLinkIllegalChars.test(page)
&& !re.wikiLinkIllegalNames.test(page)) {
valParts(textarea, before + linkText, '', after);
var histL = pgHistory.length;
if (pgHistory[histL - 1] === page)
pgHistory.length = histL - 1;
else
pgHistory = []; // clear the back button pgHistory
lastLinkAddr = page;
loadAndDisplay(page);
linkStartPos = before.length;
}
else
noValidLinkError();
} // correctLinkingNow
function noValidLinkError() {
clearDisplay();
display.append(images.attention.attr('title', msgs.noValidLink))
.appendText(' ' + msgs.noValidLink).write();
}
function wikEdCorrectLinking() {
var sel = wikEd.frameWindow.getSelection().getRangeAt(0).toString();
var before = sel.match(/^\s*/)[0];
var after = sel.match(/\s*$/)[0];
var hasTextAfterTheBar = false;
var page = sel = $.trim(sel);
var hasBracketsBefore = /^\[\[/.test(sel);
var hasBracketsAfter = /\]\]$/.test(sel);
if (hasBracketsBefore && hasBracketsAfter) {
sel = sel.slice(2, -2);
before += '[[';
after = ']]' + after;
var barLen = (sel.match(/\|.*/) || [''])[0].length;
page = (barLen > 0) ? sel.slice(0, -barLen) : sel;
}
if (page && !re.wikiLinkIllegalChars.test(page)
&& !re.wikiLinkIllegalNames.test(page))
{
//if (!hasBracketsBefore)
// wikEd.FrameExecCommand('inserthtml',
// before + '[[' + page + ']]' + after);
var histL = pgHistory.length;
if (pgHistory[histL - 1] === page)
pgHistory.length = histL - 1;
else
pgHistory = []; // clear the back button pgHistory
lastLinkAddr = page;
loadAndDisplay(page);
wikEd.frameWindow.focus();
}
else
noValidLinkError();
wikEd.frameWindow.focus();
} // wikEdCorrectLinking
function clearDisplay() {
display.show().keypress(keyPressed).helpUrl(locale.helpUrl)
.onCloseOnUserAction(function () {
textarea.off('focus.smartLinking');
});
}
function loadAndDisplay(articleTitle, noRedir) {
// is it a link to a section in the currently displayed page?
if (articleTitle.charAt(0) == '#') {
clearDisplay();
addBackLink();
display.appendTextWrite(articleTitle + ' - ' + msgs.aLinkToSecInCurrEdPg);
return;
}
// is it a link to a special page?
var pgNs = articleTitle.split(':')[0];
if (pgNs != articleTitle && $.inArray(pgNs.toLowerCase(), locale.specialNsPrefixes) > -1) {
clearDisplay();
addBackLink();
display.appendTextWrite(articleTitle + ' - ' + msgs.aSpecialNSLink);
return;
}
$.ajax({
url: '/w/api.php?action=query&prop=revisions|pageprops&rvprop=content'
+ '&ppprop=disambiguation&format=json&smaxage=' + maxAgeSeconds.sForArticles
+ '&maxage=' + maxAgeSeconds.forArticles
+ '&titles=' + encodeURIComponent(articleTitle),
dataType: 'json',
success: function (result) {
receiveArticle(result, articleTitle, noRedir);
},
error: function () {
clearDisplay();
prt(msgs.errorOnLoading, true);
}
});
} // loadAndDisplay
function receiveArticle(result, articleTitle, noRedir) {
var data, isDisambig;
var section = (articleTitle.match(re.addrSectionPart) || [''])[0]; // #.*
var norm = result.query.normalized;
if (norm && norm[0].from == articleTitle)
articleTitle = norm[0].to + section;
var pageN, p, pages = result.query.pages;
if (typeof pages == 'undefined') {
clearDisplay();
addBackLink();
return;
}
else if (pages[-1]) {
data = '';
}
else {
for (p in pages)
(pages.hasOwnProperty(p)) && (pageN = p);
var page = pages[pageN];
var data = page.revisions[0]['*'];
isDisambig = page.pageprops && page.pageprops.disambiguation === '';
}
processAndDisplayArticle(data, articleTitle, noRedir, isDisambig);
} // receiveArticle
function addBackLink(currArticleTitle) {
var histL = pgHistory.length;
if (histL == 0)
return;
var prevArticleTitle = pgHistory[histL - 1];
if (typeof currArticleTitle != 'undefined'
&& prevArticleTitle === currArticleTitle) {
if (histL == 1)
return;
else
prevArticleTitle = pgHistory[histL - 2];
}
var bkLinkTitle = msgs.backTo.replace(/%1/, prevArticleTitle);
var bkLink = $('<a/>', {
text: '<<',
href: '# ' + bkLinkTitle,
tabindex: 0,
css: {cursor: 'pointer'},
title: bkLinkTitle,
click: function (e) {
e.preventDefault();
// if curr pg is not in arr, prev pg is removed, but it will be re-added
pgHistory.length = histL - 1;
insertLink(prevArticleTitle);
loadAndDisplay(prevArticleTitle, true);
},
keypress: keyPressed
});
display.appendText('(')
.append(bkLink)
.appendText(') ')
.write();
display.focus(bkLink);
} // addBackLink
function processAndDisplayArticle(data, articleTitle, noRedir, isDisambigPg) {
var maxTextLength = 2000;
var formatUrl = wikiParser.formatUrl;
var fullText = true; // whether to show the whole article or only maxTextLength chars of it
var otherMeaningTemplates = [];
var otherMeaningPages = [];
var articleUrl; // = formatUrl(articleTitle);
var disambigLinks;
var redir; // is the page a redirect?
var section; // the part after # in articleTitle
var sectionHeadingIdsNoPrefix = [];
var sections = [];
var noData = (data.length == 0); // article does not exist
var $topMenu; // the menu span with the buttons after the article title at the beginning
function shorten(text, proportionOfMax) {
var origText = text;
text = text.slice(0, maxTextLength * (proportionOfMax || 1));
var lastLinkStart = text.lastIndexOf('[[');
if (lastLinkStart > text.lastIndexOf(']]'))
text = text.slice(0, lastLinkStart);
var lastSpace = text.lastIndexOf(' ');
if (text.length < origText.length && lastSpace > text.length - 20)
text = text.slice(0, lastSpace);
(text.length < origText.length) && (text = text + ' ...');
return text;
} // shorten
function addTocAndOtherMeaningLinks(otherMeaningTemplates, sectionHeadingIds, articleTitle) {
var sectionHeadingsNum = sectionHeadingIds.length;
var $mainDiv = $('<div/>', {'class': 'smrtL_tocAndOtherDiv'});
var $div1;
var $div = $div1 = $('<div/>');
$mainDiv.append('<br/><br/>')
.append($('<span/>', {
text: msgs.tocAndOtherAndMainArticles,
css: {color: '#050', fontWeight: 'bold', textDecoration: 'underline'}
}));
// back-to-top button
$mainDiv.append($('<a/>', {
href: '# ' + msgs.backToTop,
'class': 'smrtL_tocHeadingLink',
title: msgs.backToTop,
css: {margin: '0 2px'},
click: function (e) {
e.preventDefault();
var target = display.find('.smrtL_topTocLink');
if (target.length == 0)
target = display.find('.smrtL_otherAndMainArticlesLink');
display.scrollTo(target, true);
},
keypress: keyPressed
})
.append(images.up));
// show/hide the section links button
if (sectionHeadingIds.length > 0) {
$mainDiv.append($('<a/>', {
href: '# ' + msgs.toggleSectionLinks,
title: msgs.toggleSectionLinks,
css: {margin: '0 2px'},
click: function (e) {
e.preventDefault();
$('.smrtL_tocAndOtherDiv div.smrtL_tocLinkDiv').toggle();
display.scrollTo('.smrtL_tocHeadingLink', false);
},
keypress: keyPressed
})
.append(images.toc.clone()));
}
$mainDiv.append('<br/>');
var text = function (str) { return document.createTextNode(str); }
var pgsArr = [];
var $div_;
var $span;
for (var j = 0; j < otherMeaningTemplates.length; j++) {
if (otherMeaningTemplates[j] == '----') {
$div_ = $div;
$div = $('<div/>', {css: {'background-color': 'gray'}});
continue;
}
if (otherMeaningTemplates[j] == '----/') {
$div_.append($div);
$div = $div_;
continue;
}
if (otherMeaningTemplates[j].charAt(0) == '=') {
var tocLinkId = sectionHeadingIds.shift();
$div.append('<div class="smrtL_tocLinkDiv">'
+ '<a href="#" id="' + sectIdPrefix + tocLinkId
+ 'Link" class="smrtL_tocLink smrtL_' + tocLinkId + 'Link" '
+ 'style="color:green; font-weight:bold;">'
+ otherMeaningTemplates[j] + '</a></div>');
continue;
}
var spl = otherMeaningTemplates[j].slice(2, -2)
.match(re.splitTemplateParamsG); // split on |, except within links & templates:
// (?:[^|[{}]|\[[^\]]*]|\{\{[^}]*}}|\{[^{]|}[^}])+|(?=\|\|)/g
$span = $('<span/>', {'class': 'smrtL_otherMeaningOrMainTempl'});
$span.append(text('{{' + spl[0]));
for (var k = 1; k < spl.length; k++) {
var param = $.trim(spl[k]);
$span.append(text(' | '));
if (param === '')
continue;
if (param.indexOf('[[') > -1) {
param = param.replace(re.linkAddrsIn$1G, '[[$1]]'); // \[\[([^|\]]+)\|[^\]]*\]\]/g
param = wikiParser.removeElements(param, 'bold/italic');
var linkifyObj = linkifyText(param, articleTitle, true);
pgsArr.push.apply(pgsArr, linkifyObj.pageNames);
$span.append(linkifyObj.$collection);
}
else {
var p = param.split('=');
if (p.length > 1) {
$span.append(text($.trim(p[0]) + ' = '));
}
var paramVal = p[1] || param;
if (paramVal !== articleTitle) {
pgsArr.push(paramVal);
$span.append(browsableLink(paramVal));
}
else
$span.append(paramVal);
}
}
$span.append(text('}}')).append('<br/>');
$div.append($span);
}
// check for some additional titles, but only if at least some other-meaning
// templates exist on the page (some such templates auto-add a link to a disambig page)
if (otherMeaningTemplates.length - sectionHeadingsNum > 0) {
var altPages = [];
// auto add link to the same page name without text in parentheses at the end
var titleNoDisamb = articleTitle.replace(re.titleDisabigPart, ''); // \s\([^)]+\)$
if (titleNoDisamb != articleTitle) {
altPages.push(titleNoDisamb);
}
// auto add link to the title with disambig suffix
// or, if this page already has that suffix, add the title without it:
if (locale.disambigPgSuffix !== '') {
var suff = locale.disambigPgSuffix;
var suffIndex = articleTitle.indexOf(suff);
// only if this page does not itself have the disambig suffix:
if (suffIndex == -1 // doesn't have it
|| suffIndex != articleTitle.length - suff.length) // doesn't have it at the end
altPages.push(articleTitle + suff);
else { // remove the disamb suffix from end
var withoutDisambSuffix = articleTitle.slice(0, -suff.length);
if (withoutDisambSuffix != titleNoDisamb)
altPages.push(withoutDisambSuffix);
}
}
$.each(altPages, function (i, val) {
if ($.inArray(val, pgsArr) == -1) {
$div1.prepend(
$('<span/>', {'class': 'smrtL_otherMeaningOrMainTempl'})
.append(browsableLink(val)).append('<br/>')
);
pgsArr.push(val);
}
});
}
$mainDiv.append($div1).append($div).append('<hr/>');
display.append($mainDiv);
return pgsArr;
} // addTocAndOtherMeaningLinks
function processStr(str) {
str = $.trim(str);
str = wikiParser.escCharsForNowikiTags(str);
str = str.replace(locale.anchorTemplateRegExG, '<$1>'); // {{(anchor\|[\S\s]+?)}}/g
str = wikiParser.removeElements(str,
'tables, files, references, templates, behavior switches, others');
// wikiCode bold and italic to html ('' to <i>, ''' to <b>):
str = str.replace(/<(anchor\|[\S\s]+?)>/g, '{{$1}}');
str = wikiParser.boldAndItalicToHtml(str);
// rem all tags except the whitelisted ones:
try {str = wikiParser.sanitizeHtml(str, whitelistedTags);}
catch (e) {
if (typeof e != 'number') throw e;
prt('Error while html-sanitizing the page. Error code: ' + e, true);
return '';
}
return $.trim(str);
} // processStr
section = (articleTitle.match(re.addrSectionPart) || [''])[0]; // #.*
if (section !== '') {
articleTitle = articleTitle.slice(0, -section.length);
// remove the # and encode to be used to scroll to that section at the end of this function:
section = wikiParser.encodeSectionNameForId(section.slice(1));
}
articleUrl = formatUrl(articleTitle);
visitedPages[articleTitle] = (noData ? '' : '+');
clearDisplay();
addBackLink(articleTitle);
if (!(pgHistory.length > 0 && pgHistory[pgHistory.length - 1] === articleTitle))
pgHistory.push(articleTitle);
data = $.trim(wikiParser.removeElements(data, 'comments'));
if (!isDisambigPg && locale.disambigTemplateNameRegEx)
isDisambigPg = (locale.disambigTemplateNameRegEx.test(data));
// redir[1] is "#Redirect", redir[2] is the link addr, redir[3] is the rest:
redir = data.match(re.redirect); // ^(#[^\[]{1,25}\[\[)([^|\]]+)(\|.*|\]\][\S\s]*)
if (noData)
display.append(images.attention.attr('title', msgs.nonExistingPage)).appendText(' ');
if (isDisambigPg) {
display.append(images.attention.attr('title', msgs.disambigPage)).appendText(' ');
}
display.append($('<strong/>', {
text: articleTitle,
css: {color: (noData ? miscStyle.noDataReceivedLinkColor : 'green')}
}));
$topMenu = $('<span/>', {
'class': 'smrtL_topMenu'
})
.append($('<a/>', { // Open in new window
href: articleUrl,
title: articleTitle + ': ' + msgs.openInNewWin,
target: '_blank',
css: {margin: '0 2px'}
}).keypress(keyPressed).append(images.open))
.append($('<a/>', { // Edit in new window
href: formatUrl(articleTitle, false, true),
title: articleTitle + ': ' + msgs.editInNewWin,
target: '_blank',
css: {margin: '0 2px'}
}).keypress(keyPressed).append(images.edit));
if (isDisambigPg)
$topMenu.append($('<a/>', { // OK / Return focus to the textarea
'class': 'smrtL_topMenuOkButton',
href: '# ' + msgs.focusTextarea,
title: msgs.focusTextarea,
css: {margin: '0 2px'},
click: function (e) {
e.preventDefault();
$(this).remove();
display.collapse();
focusTextarea();
},
keypress: keyPressed
}).append(images.ok));
display.appendWrite($topMenu);
if (data.length == 0)
;
else if (!wikiParser.checkRegexSupport()) {
prt(msgs.error + ': ' + 'Unsupported browser. (No regex support)', true);
data = '';
}
else if (!redir) {
// keep only the text before the start of the first section title
if (!fullText) {
data = wikiParser.beforeTheFirstSection(data);
data = processStr(data); // sanitize, etc.
data = shorten(data);
}
sections = wikiParser.divideSections(data);
display.appendText(' ');
var emptyLineDiv = '<div style="font-size:50%;"><br/></div>';
var sectionNames = {}; // two or more sections can have the same heading
var sectionUrls = [];
$.each(sections, function (i, val) {
var unsafeContents = val.contents;
var unsafeHeading = val.heading;
var eq = val.eq; // the equal signs before (and after) the heading in the wiki code
var safeHeading;
if (eq !== '') {
var h = wikiParser.removeElements(unsafeHeading, 'comments, references, templates');
h = wikiParser.boldAndItalicToHtml(h); // convert '' and ''' to <i> and <b>
try {h = wikiParser.sanitizeHtml(h, '', true);} catch (e) {return;} // remove all html tags
h = wikiParser.unlink(h); // remove wiki links
h = wikiParser.unescapeCharEntities(h);
h = $.trim(h);
if (h === '')
h = '?';
var headingId = wikiParser.encodeSectionNameForId(h);
var sectionUrl = wikiParser.encodeSectionNameForUrl(h);
var nOfSectionsWithThatName = sectionNames[sectionUrl];
if (typeof nOfSectionsWithThatName == 'undefined')
sectionNames[sectionUrl] = 1;
else {
nOfSectionsWithThatName++;
sectionNames[sectionUrl] = nOfSectionsWithThatName;
sectionUrl += '_' + nOfSectionsWithThatName;
headingId += '_' + nOfSectionsWithThatName;
}
sectionHeadingIdsNoPrefix.push(headingId);
sectionUrls.push(sectionUrl);
safeHeading = processStr(unsafeHeading) || '?';
otherMeaningTemplates.push(eq + safeHeading);
}
var othr = getOtherMeaningTemplates(unsafeContents, processStr);
var otherMeaningTemplatesInThisSection = othr.templates;
var safeContents = processStr(othr.str);
otherMeaningTemplates.push.apply(otherMeaningTemplates, otherMeaningTemplatesInThisSection);
var sectionHtmlCode = (eq !== '' ? '<span class="smrtL_sectionHeading'
+ (otherMeaningTemplatesInThisSection.length > 0
? ' smrtL_hasOtherMeaningOrMain' : '')
+ '"><b>' + eq + safeHeading + eq + '</b></span> ' : '')
+ (safeContents.replace(re.oneOrMoreEmptyLinesG, emptyLineDiv) // ([^\S\n]*\n){2,}/g
.replace(re.nAsteriskG, '<br/>*') // \n\*/g
.replace(re.nHashSymbolG, '<br/>#') // \n#/g
.replace(re.nSemicolonG, '<br/>;') // \n;/g
.replace(re.nColonG, '<br/>:') // \n:/g
.replace(re.nG, ' ')) // \n/g
+ emptyLineDiv;
display.append(linkifyText(sectionHtmlCode, articleTitle, false).$collection);
});
var sectionHeadingIdsNoPrefixTemp = sectionHeadingIdsNoPrefix.slice();
var totalSections = sectionHeadingIdsNoPrefix.length;
display.find('.smrtL_sectionHeading').each(function (i, el) {
var $span = $(el);
var otherMeaningOrMainTemplInSection = $span.hasClass('smrtL_hasOtherMeaningOrMain');
var headingId = sectionHeadingIdsNoPrefixTemp.shift();
var sectionUrl = sectionUrls.shift();
$span.append($('<a/>', {
href: articleUrl + '#' + sectionUrl,
target: '_blank',
title: msgs.openInNewWin,
css: {margin: '0 2px'}
}).append(images.open.clone())
).append($('<a/>', {
href: formatUrl(articleTitle, false, true)
+ '§ion=' + (totalSections - sectionHeadingIdsNoPrefixTemp.length),
target: '_blank',
title: msgs.editInNewWin,
css: {margin: '0 2px'}
}).append(images.edit.clone())
).append($('<a/>', {
href: '#',
id: sectIdPrefix + headingId,
'class': 'smrtL_headingAnchor smrtL_section_' + headingId,
title: msgs.tableOfContents,
css: {margin: '0 2px'}
}).append((otherMeaningOrMainTemplInSection ? images.related.clone() : images.toc.clone()))
);
});
// add the ToC icon-link at the top
if (sectionHeadingIdsNoPrefix.length > 0) {
$topMenu
.append($('<a/>', { // Table of contents
'class': 'smrtL_topTocLink',
href: '# ' + msgs.tableOfContents,
title: msgs.tableOfContents,
css: {margin: '0 2px'},
click: function f (e) {
e.preventDefault();
display.find('.smrtL_tocAndOtherDiv div.smrtL_tocLinkDiv').toggle(true);
display.expand();
display.scrollTo('.smrtL_tocHeadingLink', true);
},
keypress: keyPressed
}).append(images.toc))
}
if (otherMeaningTemplates.length > 0 || sectionHeadingIdsNoPrefix.length > 0) {
otherMeaningPages = addTocAndOtherMeaningLinks(otherMeaningTemplates,
sectionHeadingIdsNoPrefix, articleTitle);
display.write();
if (otherMeaningPages.length > 0) {
// add the OtherMeanings icon-link at the top
$topMenu.append($('<a/>', { // Related articles
'class': 'smrtL_otherAndMainArticlesLink',
title: msgs.relatedArticles,
css: {margin: '0 2px'},
href: '# ' + msgs.relatedArticles,
click: function f (e) {
e.preventDefault();
display.find('.smrtL_tocAndOtherDiv div.smrtL_tocLinkDiv')
.toggle(false);
display.expand();
display.scrollTo('.smrtL_tocHeadingLink', true);
},
keypress: keyPressed
}).append(images.related));
// check for articles in the other-meaning template arguments
otherMeaningCheckLinks(otherMeaningPages);
}
}
} // if (data && !redir)
else { // REDIRECTING PAGE
// don't auto redirect to sections because section title may change, etc.
// don't redirect back to the previous page either
if (!noRedir && redir[2].indexOf('#') == -1
&& !(pgHistory.length > 1 && pgHistory[pgHistory.length - 2] === redir[2])) {
insertLink(redir[2]);
loadAndDisplay(redir[2], true); // don't redir next time to avoid infinite loops
return;
}
display.appendText(': ' + redir[1]);
var $lnk = browsableLink(redir[2], redir[2]);
display.append($lnk);
$lnk[0].focus();
display.appendText(shorten(redir[3]));
} // else if (redir)
display.write();
// attach events to some links:
display.find('.smrtL_headingAnchor').click(function (e) {
e.preventDefault();
display.find('.smrtL_tocAndOtherDiv div.smrtL_tocLinkDiv').toggle(true);
display.expand();
display.scrollTo('#' + this.id + 'Link', true);
})
.keypress(keyPressed);
display.find('a.smrtL_tocHeadingLink').click(function (e) {
e.preventDefault();
display.scrollTo('.smrtL_topTocLink' + this.id.slice(0, -4), true);
})
display.find('a.smrtL_tocLink').click(function (e) {
e.preventDefault();
display.scrollTo('#' + this.id.slice(0, -4), true);
})
.keypress(keyPressed);
if (isDisambigPg) {
display.expand(true);
display.focus('.smrtL_topMenuOkButton');
}
if (section !== '') {
var s = $('#' + sectIdPrefix + section).after($('<a/>', {
href: '# ' + msgs.backToTop,
title: msgs.backToTop,
css: {margin: '0 2px'},
click: function (e) {
e.preventDefault();
var target = display.find('.smrtL_topTocLink');
if (target.length == 0)
target = display.find('.smrtL_otherAndMainArticlesLink');
display.scrollTo(target, true);
},
keypress: keyPressed
}).append(images.up.clone()));
display.scrollTo(s);
}
} // processAndDisplayArticle
function getOtherMeaningTemplates(unsafeStr, processStrFn) {
var templates = [];
var tempArr;
if (!allPossibleOtherMeaningTemplates) {
while (tempArr = locale.otherMeaningTemplateNamesRegExG.exec(unsafeStr)) {
templates.push('{{'
+ processStrFn(tempArr[0].slice(2)
.replace(re.pipeTemplateToEndOfParam, '')) // {{!}}[^|}]+
);
}
}
else { // need to check for all other possible templates later, so need to remove these
unsafeStr = unsafeStr.replace(locale.otherMeaningTemplateNamesRegExG,
function (match) {
templates.push('{{'
+ processStrFn(match.slice(2)
.replace(re.pipeTemplateToEndOfParam, '')) // {{!}}[^|}]+
);
return '';
});
}
if (unsafeStr.charAt(0) == ':')
unsafeStr = '\n' + unsafeStr; // for the regex
// (^|=|})([^\S\n]*\n)+:[^\n]+\n/g
unsafeStr = unsafeStr.replace(re.otherMeaningNoTemplG, function(match, $1) {
if ($1)
match = match.slice(2);
templates.push('{{:|'
+ processStrFn(
match.replace(re.otherMeaningNoTemplTrimG, '') // (^|\n):\s*('')?|''\s*$/g
) + '}}');
return $1;
});
// other possible other-meaning templates (one-line templates with at least one parameter)
if (allPossibleOtherMeaningTemplates) {
templates.push('----');
while (tempArr = re.possibleOtherMeaningTemplatesG.exec(unsafeStr)) {
// ^\{\{[^}|\n]+\|[^}\n]+}}[^\S\n]*$/gm
templates.push('{{'
+ processStrFn(tempArr[0].slice(2)
.replace(re.pipeTemplateToEndOfParam, '')) // {{!}}[^|}]+
);
}
var l = templates.length;
if (templates[l - 1] == '----')
templates.length = l - 1;
else
templates.push('----/');
}
return {templates: templates, str: unsafeStr};
} // getOtherMeaningTemplates
function otherMeaningCheckLinks(otherMeaningPages) {
for (var i = otherMeaningPages.length; i--; ) {
otherMeaningPages[i] = encodeURIComponent(otherMeaningPages[i]);
}
var requestStr = '/w/api.php?action=query&titles='
+ otherMeaningPages.join('|') + '&prop=pageprops&ppprop=disambig&format=json'
+ '&smaxage=' + maxAgeSeconds.sForOtherMeanings + '&maxage='
+ maxAgeSeconds.forOtherMeanings;
// prop=info&format=json' also works
$.ajax({
url: requestStr,
dataType: 'json',
success: function (result) {
otherMeaningCheckLinksReceiveAnswer(result);
}
});
function otherMeaningCheckLinksReceiveAnswer(result) {
var pages = result.query.pages;
var norm = result.query.normalized || [];
var denormMap = {};
for (var i = norm.length - 1; i >= 0; i--) {
denormMap[norm[i].to] = norm[i].from;
}
var missing = [], p;
for (var i = -1; p = pages[i]; i--)
missing.push( denormMap[p.title] || p.title );
// replace all links to non-existing pages with plain text
var $links = display.find('.smrtL_tocAndOtherDiv '
+ 'span.smrtL_otherMeaningOrMainTempl a');
$links.each(function (i, l) {
var $l = $(this);
var text = $l.text();
if ($.inArray(text, missing) > -1) {
$l.after(text);
$l.remove();
}
});
// remove all templates without links
display.find('.smrtL_tocAndOtherDiv '
+ 'span.smrtL_otherMeaningOrMainTempl:not(:has(a))').remove();
// if no templates remain, remove top button
if (display.find('.smrtL_tocAndOtherDiv '
+ 'span.smrtL_otherMeaningOrMainTempl').length == 0) {
display.find('.smrtL_otherAndMainArticlesLink').remove();
var $div = display.find('.smrtL_tocAndOtherDiv');
if ($div.text().indexOf('=') == -1) {
$div.remove();
}
}
}
} // otherMeaningCheckLinks
function linkifyText(text, currArticle, insertLinkAddr) {
var pageNames = [];
var linkEventFns = [];
var html = text.replace(re.wikiLinkAddrAndLabelG, // \[\[([^\]|]+)\|?([^\]]*)]]/g
function (match, prePipe, postPipe) {
var link = browsableLinkAndEventFns(prePipe, postPipe, currArticle, insertLinkAddr);
pageNames.push(prePipe);
linkEventFns.push(link.eventHandlers);
return link.$link[0].outerHTML;
});
var $span = $('<span/>');
$span[0].innerHTML = html;
// attach the event handlers to all the links in the intro
$span.find('a.browsableLink').each(function (i, el) {
var e = linkEventFns[i];
$(el).keypress(keyPressed)
.click(e.clickFn).focus(e.focusFn).blur(e.blurFn);
});
return {$collection: $span.contents(), pageNames: pageNames};
} // linkifyText
// returns a jQuery anchor element with a link that can be opened in the display
// Used by DisambigMenu and OtherMeanings
function browsableLink(linkAddr, linkText, currArticle) {
if (!linkText && linkAddr.indexOf('|') > -1) {
var arr = linkAddr.split('|');
linkAddr = arr[0];
linkText = arr[1];
}
var lnk = browsableLinkAndEventFns(linkAddr, linkText, currArticle, true);
var e = lnk.eventHandlers;
lnk.$link.click(e.clickFn)
.focus(e.focusFn).blur(e.blurFn).keypress(keyPressed);
return lnk.$link;
} // browsableLink
// used within the article intro and in a few other places
// linkText is printed as html and must be a presanitized sting
// insertLinkAddr - insert into the textarea, or only follow the link in the msgDisplay?
function browsableLinkAndEventFns(linkAddr, linkText, currArticle, insertLinkAddr) {
insertLinkAddr = true; // ignore this for now, always insert it
linkText = $.trim(linkText);
if (!linkAddr && !linkText)
return null;
var linkAddrNormalized = (articleNamesCapitalized
? linkAddr.charAt(0).toUpperCase() + linkAddr.slice(1)
: linkAddr);
var visited = visitedPages[linkAddrNormalized];
var linkColor = (visited
? miscStyle.visitedPgLinkColor
: (visited === ''
? miscStyle.notExistingPgLinkColor
: miscStyle.normalPgLinkColor));
linkText = linkText || linkAddr;
var unescapedLinkAddr = wikiParser.unescapeCharEntities(linkAddr);
var $link = $('<a/>', {
html: linkText,
title: unescapedLinkAddr,
href: '# ' + unescapedLinkAddr,
tabindex: 0,
css: {color: linkColor, cursor: 'pointer'},
'class': 'browsableLink'
});
var clickFn = function (event) {
event.preventDefault();
if (linkAddr.charAt(0) == '#') {
display.scrollTo('#' + sectIdPrefix
+ wikiParser.encodeSectionNameForId(linkAddr.slice(1)), true);
}
else {
if (insertLinkAddr)
insertLink(linkAddr);
else
lastLinkAddr = ''; // don't insert links in textarea until next smartLinking() call
loadAndDisplay(linkAddr);
}
};
var focusFn = function () {
$('#smrtL_linkFocusHint').remove();
if (linkAddr != linkText) { // add a tooltip at the bottom right corner of the screen
$(document.body).append($('<div/>', {
text: unescapedLinkAddr,
id: 'smrtL_linkFocusHint',
css: {
position: 'fixed',
bottom: 0,
right: 0,
border: '1px solid silver',
background: '#dddddd',
fontSize: 'small'
},
click: function () { $(this).remove(); }
}));
clearTimeout(linkFocusTimeoutId);
linkFocusTimeoutId = setTimeout(function () {
$('#smrtL_linkFocusHint').remove();
}, 7000);
}
};
var blurFn = function () {
$('#smrtL_linkFocusHint').remove();
};
return {
$link: $link,
eventHandlers: {clickFn: clickFn, focusFn: focusFn, blurFn: blurFn}
};
} // browsableLinkAndEventsFn
function keyPressed(event) {
var charCode = event.charCode || event.keyCode;
//var character = String.fromCharCode(charCode);
if (charCode == 13) { // Enter
event.preventDefault(); // don't follow the link (in IE)
// - but that also cancels the onclick event
$(this).trigger('click');
$('#smrtL_linkFocusHint').remove();
}
} // keyPressed
function focusTextarea() {
if (window.wikEd && wikEd.useWikEd)
wikEd.frameWindow.focus();
else {
var scroll = $(window).scrollTop();
textarea.focus();
$(window).scrollTop(scroll); // focus() causes IE to scroll the page
}
}
function insertLink(addr) {
if (window.wikEd && wikEd.useWikEd) {
return;
}
// Internet Explorer loses the cursor position on onclick.
function restoreCursorPos() {
var currSel = textarea.textSelection( 'getCaretPosition', { startAndEnd: true } );
if (currSel[0] == currSel[1]) // no selection - put cursor at start of link (+ 2)
textarea.textSelection( 'setSelection', { start: linkStartPos + 2 } );
}
if (lastLinkAddr === '')
return;
restoreCursorPos();
var ar = wikiParser.focusedSegment(valParts(textarea), 'wikilink');
if (!ar)
return;
var link = ar[1];
var oldAddr = ( link.match(re.wikiLinkAddr) || ['', ''] )[1]; // ^\[\[([^|\]]*)
if (oldAddr.toLowerCase() !== lastLinkAddr.toLowerCase())
return; // if a different link is at this position - abort
link = link.replace(re.wikiLinkRemoveOpeningBracketsAndUpToAndInclPipe, ''); // ^\[\[(.+?\|)?
if (addr) {
var addrCapitalized = addr.charAt(0).toUpperCase() + addr.slice(1);
var linkCapitalized = link.charAt(0).toUpperCase() + link.slice(1);
if (addr && addrCapitalized + ']]' != linkCapitalized)
link = addr + '|' + link;
}
lastLinkAddr = addr || link.slice(0, -2);
link = '[[' + link;
valParts(textarea, ar[0] + link, '', ar[2]);
} // insertLink
// the function/object exposed to the outside world
function smartLinkingFn() {
correctLinking();
}
// add the function for updating the messages and locale data:
smartLinkingFn.init = init;
setup();
return smartLinkingFn;
})(jQuery);
window.smartLinking.version = 1000;
// </nowiki>