// ==UserScript==
// @name        Redirect to up to date documentation
// @namespace   sieradzki.it
// @description Detects if currently viewed online documentation page is the most recent version available, and if not, redirects user to the latest version.
// @version     1.0.0
// @match       *://docs.oracle.com/*
// @match       *://wiki.eclipse.org/Jetty*
// @match       *://www.postgresql.org/docs/*
// @match       *://docs.spring.io/*
// ==/UserScript==

(function () {
	'use strict';

	var documentations = {
		javaSE: {
			currentVersion: '8',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javase\/([0-9\.]+)\/docs\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				url = url.replace(/\/javase\/([0-9\.]+)\/docs\/api\//, '/javase/' + this.currentVersion + '/docs/api/');
				return url.replace(/%2[8-9]|\(|\)/g, '-');
			}
		},
		javaEE: {
			currentVersion: '7',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javaee\/([0-9\.]+)\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/javaee\/([0-9\.]+)\/api\//, '/javaee/' + this.currentVersion + '/api/');
			}
		},
		jetty: {
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/wiki\.eclipse\.org\/Jetty/);
				var messageBoxLinks =
					document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]');
				return matches !== null && messageBoxLinks !== null && messageBoxLinks.length === 2;
			},
			rewriteUrl: function () {
				return document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]')[1].href;
			}
		},
		postgreSQL: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/www\.postgresql\.org\/docs\/([0-9\.]+)\/(static|interactive)\//);
				return matches !== null && matches[2] !== this.currentVersion && matches[2] !== 'devel';
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.]+)\//, '/docs/' + this.currentVersion + '/');
			}
		},
		springFramework: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\/docs\/([0-9\.A-Zx]+)\/(javadoc\-)?api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.A-Zx]+)\/(javadoc\-)?api\//, '/docs/' + this.currentVersion +
					'/javadoc-api/');
			}
		}
	};

	var DocumentationRedirect = function () {

		for (var key in documentations) {
			if (documentations.hasOwnProperty(key)) {
				if (documentations[key].isDocumentationPageOutdated(window.location.href)) {
					var rewrittenUrl = documentations[key].rewriteUrl(window.location.href);

					this.ifPageExists(rewrittenUrl, function (url) {
						window.location.replace(url);
					});

					break;
				}
			}
		}
	};

	DocumentationRedirect.prototype.ifPageExists = function (url, callback) {

		GM_xmlhttpRequest({
			method: 'HEAD',
			url: url,
			'onload': function (response) {
				if (response.status < 400) {
					callback(url);
				}
			}
		});
	};

	window.DocumentationRedirect = new DocumentationRedirect();
})();

@@ -2479,32 +2479,34 @@
 ocs%5C/(%5B0-9%5C.A-Zx
+%5C-
 %5D+)%5C/(javadoc%5C-)
@@ -2663,16 +2663,18 @@
 -9%5C.A-Zx
+%5C-
 %5D+)%5C/(ja

Add matching versions like "4.0.0.CI-SNAPSHOT"