<html>
<head>
<title>Please wait...</title>
</head>
<body>
<div>Please wait... redirecting.</div>
<div style="font-size: 80%" style="display: none" id="alt-redirect-link-para">or <a href id="manual-redirect-link">click here</a></div>
<script type="text/javascript">
//
// URL Title with Slash Redirect
// for Wikidot
//
// by @tsangk
//
// First published: 4 Apr 2010
//
// Revised 4 Jan 2017:
// - Adopts provided URI schema
// - Makes sures other URI special characters like `%` are properly escaped
//
//
/* URL class for JavaScript
* Copyright (C) 2003 Johan Känngård, <johan AT kanngard DOT net>
* http://dev.kanngard.net/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GPL is located at: http://www.gnu.org/licenses/gpl.txt
*/
/* Creates a new URL object with the specified url String. */
function URL(url){
if(url.length==0) eval('throw "Invalid URL ['+url+'];');
this.url=url;
this.port=-1;
this.query=(this.url.indexOf('?')>=0)?this.url.substring(this.url.indexOf('?')+1):'';
if(this.query.indexOf('#')>=0) this.query=this.query.substring(0,this.query.indexOf('#'));
this.protocol='';
this.host='';
var protocolSepIndex=this.url.indexOf('://');
if(protocolSepIndex>=0){
this.protocol=this.url.substring(0,protocolSepIndex).toLowerCase();
this.host=this.url.substring(protocolSepIndex+3);
if(this.host.indexOf('/')>=0) this.host=this.host.substring(0,this.host.indexOf('/'));
var atIndex=this.host.indexOf('@');
if(atIndex>=0){
var credentials=this.host.substring(0,atIndex);
var colonIndex=credentials.indexOf(':');
if(colonIndex>=0){
this.username=credentials.substring(0,colonIndex);
this.password=credentials.substring(colonIndex);
}else{
this.username=credentials;
}
this.host=this.host.substring(atIndex+1);
}
var portColonIndex=this.host.indexOf(':');
if(portColonIndex>=0){
this.port=this.host.substring(portColonIndex);
this.host=this.host.substring(0,portColonIndex);
}
this.file=this.url.substring(protocolSepIndex+3);
this.file=this.file.substring(this.file.indexOf('/'));
}else{
this.file=this.url;
}
if(this.file.indexOf('?')>=0) this.file=this.file.substring(0, this.file.indexOf('?'));
var refSepIndex=url.indexOf('#');
if(refSepIndex>=0){
this.file=this.file.substring(0,refSepIndex);
this.reference=this.url.substring(this.url.indexOf('#'));
}else{
this.reference='';
}
this.path=this.file;
if(this.query.length>0) this.file+='?'+this.query;
if(this.reference.length>0) this.file+='#'+this.reference;
this.getPort=getPort;
this.getQuery=getQuery;
this.getProtocol=getProtocol;
this.getHost=getHost;
this.getUserName=getUserName;
this.getPassword=getPassword;
this.getFile=getFile;
this.getReference=getReference;
this.getPath=getPath;
this.getArgumentValue=getArgumentValue;
this.getArgumentValues=getArgumentValues;
this.toString=toString;
/* Returns the port part of this URL, i.e. '8080' in the url 'http://server:8080/' */
function getPort(){
return this.port;
}
/* Returns the query part of this URL, i.e. 'Open' in the url 'http://server/?Open' */
function getQuery(){
return this.query;
}
/* Returns the protocol of this URL, i.e. 'http' in the url 'http://server/' */
function getProtocol(){
return this.protocol;
}
/* Returns the host name of this URL, i.e. 'server.com' in the url 'http://server.com/' */
function getHost(){
return this.host;
}
/* Returns the user name part of this URL, i.e. 'joe' in the url 'http://joe@server.com/' */
function getUserName(){
return this.username;
}
/* Returns the password part of this url, i.e. 'secret' in the url 'http://joe:secret@server.com/' */
function getPassword(){
return this.password;
}
/* Returns the file part of this url, i.e. everything after the host name. */
function getFile(){
return this.file;
}
/* Returns the reference of this url, i.e. 'bookmark' in the url 'http://server/file.html#bookmark' */
function getReference(){
return this.reference;
}
/* Returns the file path of this url, i.e. '/dir/file.html' in the url 'http://server/dir/file.html' */
function getPath(){
return this.path;
}
/* Returns the FIRST matching value to the specified key in the query.
If the url has a non-value argument, like 'Open' in '?Open&bla=12', this method
returns the same as the key: 'Open'...
The url must be correctly encoded, ampersands must encoded as &
I.e. returns 'value' if the key is 'key' in the url 'http://server/?Open&key=value' */
function getArgumentValue(key){
var a=this.getArgumentValues();
if(a.length<1) return '';
for(i=0;i<a.length;i++){
if(a[i][0]==key) return a[i][1];
}
return '';
}
/* Returns all key / value pairs in the query as a two dimensional array */
function getArgumentValues(){
var a=new Array();
var b=this.query.split('&');
var c='';
if(b.length<1) return a;
for(i=0;i<b.length;i++){
c=b[i].split('=');
a[i]=new Array(c[0],((c.length==1)?c[0]:c[1]));
}
return a;
}
/* Returns a String representation of this url */
function toString(){
return this.url;
}
}
var url=new URL(window.location.hash.substring(1));
var path=escape(unescape(url.getPath()));
var str=path.split("/");
var xtest;
var link = "";
for (var x in str) {
if(x>0){
xtest=x%2;
if(!xtest){
if(str[x]=="edit"){
link+="/"+str[x];
}
else if(str[x]=="parentPage"){
link+="/"+str[x];
}
else if(str[x]=="tags"){
link+="/"+str[x];
}
else if(str[x]=="title"){
link+="/"+str[x];
}
else
{
link+="%2F"+str[x];
}
}
else
{
link+="/"+str[x];
}
}
}
var newLink = url.getProtocol() + "://" + url.getHost() + link;
document.getElementById("manual-redirect-link").href = newLink;
document.getElementById("alt-redirect-link-para").style.display = "block";
window.location = newLink;
// Just in case the location wasn't set above, we'll try again once the page loads
window.onload = function(){
window.location.href = newLink;
}
</script>
</body>
</html>
I have used this to create comment pages in a forum build:
It has worked fine for years, until someone just created a thread called "Expect a 15% performance loss coming soon". On that page, the button produces a 400 error. The URL it produces is:
The "%" not quoted, which it should be.
Wow. That was some pretty terrible code 😂
Gone back and made some changes. The modified version shouldn't break any existing code (unless the use case is to generate broken URL encoding).
If anyone else is experiencing new problems as a result of this change, please reply below with an example :)
Kenneth Tsang (@jxeeno)
Sorry, that's worse.
The problem is that there are already bona-fide % characters in the URL replacing space characters in the page title:
…/title/Re:%20Expect%20a%2015%%20performance%20loss%20coming%20soon
The fix to escape the % in "15%" also escapes all the others, with the result that the new page title has all the escapes in.
The only way I can think to fix this is to go back to the original and make a special case of a "%" that is not followed by a hexadecimal digit:
(Warning: I have made it a career ambition never to learn Javascript.)
That will lead to odd behaviour when the % is followed by a digit, but I can't see an obvious solution.
On reflection, I think this is a Wikidot problem. I've filed a bug report there: http://feedback.wikidot.com/bug:1152
Ah, dang. Didn't test that.
I've just updated it to use escape(unescape()) — let me know if it's working better. Based on that link on feedback.wikidot.com, looks like it's working now.
escape(unescape()): the first unescape will ensure any encoded entities are correctly decoded first, and then encode all special characters except / unless it's after the /title/. I think this solves it.
There's still an edge case where the user might provide a page title with a substring that is in the URI encoding format. For example, if the title was to be: Problem with encoding %20. I don't think it's possible to fix that though.
Kenneth Tsang (@jxeeno)
That's got it. Thanks.
I think it's still a Wikidot bug though; there's no good reason why % should be invalid in titles.
Great!
Hmm, not sure if it's something that Wikidot can do. The error is likely being thrown somewhere lower in the stack (i.e. not in Wikidot's codebase).
Most web servers will trip over trying to parse a URI with % but not followed by two hex characters. What happens when that occurs isn't defined. But when it happens after the hash, you're at the discretion of the browser's implementation.
See recommendations on w3.org:
The ideal solution is for Wikidot to provide a way of variables with percent encoding — e.g. %%title|urlencode%%.
Kenneth Tsang (@jxeeno)
The second code block is currently useless. It was used to redirect to parent (:
Kenneth Tsang (@jxeeno)
Why are there two code blocks here? I notice the second was added recently. Maybe there should be some documentation describing when to use each?
Edit: Nevermind… I think you told me exactly what to do xD Will just mess around with it for a bit and if I can't figure it out by then I'll reply back here again.
[ in regards to http://feedback.wikidot.com/bug:115 ]
~ Leiger - Wikidot Community Admin - Volunteer
Wikidot: Official Documentation | Wikidot Discord server | NEW: Wikiroo, backup tool (in development)
Okay, works perfectly so far! Thanks! :)
~ Leiger - Wikidot Community Admin - Volunteer
Wikidot: Official Documentation | Wikidot Discord server | NEW: Wikiroo, backup tool (in development)