Other AJAX/Blogsome functions

Really, I don’t like the term AJAX. However, technically, I think that’s what my DeleteComment function does. It sends a request to the server, and updates the current DOM to reflect this. There’s no reason why normal Comments can’t be added or edited in the same way. Instead of the Edit Comment/Post opening up a new page, I might just make them turn the area into a textarea, and allow editing. Then, when clicking out (or perhaps, Save), the data is uploaded back to the server, and the page updated. This would make it very cool to edit posts in-place. For this, I might be better off investigating other options rather than re-building my own. Although that is kind of fun.

Post Page Comment Deleting

I’ve implemented the ability to delete a Comment while viewing it on a normal (user) post page. It will only appear if you are an admin. There are some issues: the first is that it doesn’t work under Internet Explorer. I didn’t realise until I read Using the XML HTTP Request object that IE uses a different way of initialising the XMLHttpRequest() object. I’ll build that in later. The second is that any user can (try to) delete a Comment when logged in - currently this script doesn’t check to see what is returned, and removes the Comment from the Post page regardless. What I need to do is examine the resulting HTML code, and find out if the request to delete the comment was successful. I’ll need to do some experiments to check this, but an xmlhttp.status might do the trick. To use it, just include <script type="text/javascript" src="http://schinckel.net/images/toolbox.js"> </script> in your <head>, and have a button/link with class="delete", inside your Comment <li> definition. Else, you can download the script, and examine how it works: http://schinckel.net/images/toolbox.js. The actual function that deletes the comment is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    function DeleteComment(e){
        li = parentWithTagName(eventTarget(e),'LI');
        id = li.id.split('-')[1];
        if (!getById(li.id)) return true; //Fallback to Link!
        if (!confirm("Delete Comment #"+id+"?\nCannot be undone.")) return false;  
        var admin = "http://" + document.domain + "/wp-admin/";
        var delreq = new XMLHttpRequest();
        delreq.open("GET",admin+"post.php?action=deletecomment&comment="+id);
        delreq.setRequestHeader("Referer",admin);
        delreq.send("");
        li.parentNode.removeChild(li);
        return false; //Stop Link being followed
    }

With the function:

1
2
3
4
5
    function parentWithTagName(node, tagName){
        if (node==document) return false;
        if (node.tagName==tagName) return node;
        return parentWithTagName(node.parentNode, tagName)
    }

existing elsewhere, and being used in this case. I like the neatness of this recursive function, which I originally wrote for finding a parent <form> element. I’ve also got a function getById(), which is a cross-browser wrapper for document.getElementById(), and eventTarget() which is the same for finding the target of an event. To add the function to the button, I use a script that just finds all elements with class="delete", and add onclick=DeleteComment. That’s all that needs to be done!

Spoofing Referer Headers from XMLHttpRequest

I couldn’t find a simple explanation of how to do this, so here is one. First, a bit of background. I wanted to be able to delete a comment from a standard post page, without having to a) go to a confirmation page, and b) have to navigate back to the original page afterwards. The following code creates an HTTP request, opens the required page, then fakes the header so it looks like it came from an admin page, before sending the request. When the request is complete, it refreshes the current page, so as to update the display.

1
2
3
4
5
    del = new XMLHttpRequest();
    del.open("GET","{$siteurl}/wp-admin/post.php?action=deletecomment&comment={comment_ID}");
    del.setRequestHeader("Referer", "{$siteurl}/wp-admin/post.php");
    del.send("");
    document.location.reload();

A better option might be to just hide the deleted comment from view - that would be immediate, and if the user refreshed the page it would reflect reality.

1
    document.getElementById('{comment_ID}').style.display='none';

However, if the user was to somehow cause the comment to become visible again, it doesn’t get it’s number back, at least in Firefox. There are a multitude of other ways to handle this case: .style.visibility = 'hidden' hides the object, but leaves the space. You could also delete the object from the whole DOM structure, using:

1
    document.getElementById('{comment_ID}').parentNode.deleteChild(document.getElementById('{comment_ID}'));

Blogsome Post Parser

A bit down the track, I want to fix some things with the way Posts are parsed when they are created or edited using Blogsome. I’m loath to change too much the stuff in the actual edit box: people need to be able to put Raw HTML code in there if they want, and if they don’t, they can use the WYSI-editor. However, the Title field needs to be escaped before being saved to the database. Having an & in the title generates invalid XHTML code. This is basically the same issue as what causes the errors when extended (non-latin) characters are used in the title, and transferred into the post-slug. This should be fairly easy to fix: just a function that looks at this field on posting (and perhaps the post-slug field also, just to check), and replaces any invalid characters with the escaped version. I only thought about this again, as I had two posts with & in their titles in the past week.

Enable Sending Referrers

Occasionally, people report a particular error when trying to delete posts or comments.

Sorry, you need to enable sending referrers for this feature to work.

I came across this twice in the past week. Once was when I changed my $siteurl variable, and this disappeared when I returned it to the normal value. The other was when I tried to set up a shortcut to delete a comment from the post page. The original shortcut was: {$siteurl}/wp-admin/post.php?action=confirmdeletecomment&comment;={$comment_ID} Which worked, but loaded a confirmation page. I replaced it with: {$siteurl}/wp-admin/post.php?action=deletecomment&comment;={$comment_ID} And made the confirmation a confirm dialog instead: return confirm("Delete Comment by {$comment_author}?\nThis cannot be undone.");, which is the way it is done in the Edit Comment page (not the Mass Edit though, I don’t think). This is when I received the error page. I think what is happening is that the referrer of the second page must be within the {$siteurl}/wp-admin/ domain for it to be accepted. I wonder if I can fake the referrer, and make it work. This also explains why the error appeared when changing the {$siteurl} variable, since it’s looking for a referrer and obviously getting the wrong one. Knowing this may help me to a fix so that I can change the {$siteurl} variable, and avoid the referrer errors.

Blogsome and Searching

Blogsome Search has never quite been right, and now I think I know how to fix it. At the moment, my Search code looks like:

1
2
3
4
    <form id="searchform" method="post" action="/">
        <input type="text" name="s" id="s" size="12" />
        <input type="submit" class="button" name="submit" value="Search" />
    </form>

This works, to a certain extent. It will only properly display the first page of results. It is possible to use URLs of the form: http://schinckel.net/category/?s=searchterm which will give results, and if there are more hits than are visible, will display the Next Page link, which is of the form: http://schinckel.net/category/?s=searchterm/page/2/, and works. Knowing this, it’s possible to hack up a JavaScript function that will display the search results, but the Next Page link still fails. You can, however, pop an &paged=n on the end of the URL, which will work in this case. I think this would be much nicer with a RewriteRule. I’ll have to play around a bit and see what makes a working one for .../search/term1/term2/, I think. The JavaScript I am using at the moment is (shown in context):

1
2
3
4
    <form id="searchform" method="post" action="/" onsubmit="location.href='/category&s='+document.getElementById('s').value.replace(/ /g,'+');return false;">
        <input type="text" name="s" id="s" size="12" />
        <input type="submit" class="button" name="submit" value="Search" />
    </form>

&amp;order=asc

A Blogsome user wanted to use the URL switch ?order=asc to get an ascending list of posts by date. I suggested it would’t work, but they tried it in the form: http://schinckel.net/category&order=asc And it worked! It only seems to work for category pages, although I think the above URL will actually catch every post, as each post lives in at least one place within the /category hierarchy. This opens up huge opportunities to use other URL switches to get other effects under Blogsome. I’m off to the Wordpress Codex, to see what else I can use!

I Wasted Time • Paul Kelly • …Nothing But A Dream ★★★★

Resizing/Deleting Images

Now that it’s possible to view which images have been uploaded to a Blogsome blog, and it’s possible to delete unwanted images, I’m going to go through and remove any unused images, and resize some of the larger images I uploaded a while ago. I’ve also found a way to upload any type of file: such as JavaScript.js, Python.py and AdobeAcrobat.pdf documents.

Image Browser

It’s now possible to find the names of images you have uploaded to Blogsome: http://schinckel.net/wp-admin/iimage-browser.php Allows me to browse all of the images I have uploaded. I don’t think I can delete them, but I can see what files are there, and then reference these in a blog post. You’ll want to replace schinckel with whatever word you chose for your blog. This function was added with the WYSIWYG editor plugin.

Stealth Forwarding &amp; {$siteurl}

I’ve got my own domain (http://schinckel.net), which just so happens to point towards this blog. It would be cool if I could replace the _http://schinckel.net _with _http://schinckel.net _everywhere it appears. I have gotten ever so close to achieving this. I have made it so that {$siteurl} is equal to http://schinckel.net, using a hidden options page. This means that all of the links and so forth on my blog now look like: http://schinckel.net/2006/03/15/coffee-physics/ Then, in theory, if I make http://schinckel.net “Stealth Forwarding” instead of “Standard Forwarding”, then it will keep these addresses in the address bar, and people copy-pasting them would grab my nicer address. However, there is on issue. Stealth forwarding actually uses a frameset to work, and this interferes with the proper passing through of data. Thus, on http://www.schinckel.net/, which does use Stealth forwarding, when I click on a link that goes to another page, the original URL stays in the address bar. If I turn on Stealth for http://schinckel.net, this bug seems to go away - clicking on a link to another page puts the correct address into the page, but since the frameset exists, then two other problems appear: Cookies for logging into the site fail (as it’s actually a different site), and the StyleSheet file fails to load, as instead of it being http://schinckel.net/templates/wp-layout.css, which is a CSS file, it is a page, in HTML, with a frame with the CSS file inside of it that loads. Which fails to be interpreted by the browser, resulting in dodgy looking pages. I could overcome the second issue by hard-coding the CSS file path into my template, but the first one is a biggie. I can’t just login to http://schinckel.net/wp-admin/, as all of the links inside of the page that use {$siteurl} now point to http://schinckel.net/wp-admin/yada-yada-yada.php, which the login session isn’t valid for. So, I can’t access anything inside the Dashboard. I’ve settled on a middle ground for now: I’ve set the {$siteurl} to http://schinckel.net, but left forwarding mode as Standard. Now, anything in the page which writes a URL as src="/yada" will give a schinckel.net address, but anything that uses {$siteurl} will give a nice schinckel.net address. I might be able to post-process some stuff so it looks even nicer, but the address bar will always be http://schinckel.net/yada/. Unless I can outsmart the cookies. The outsmarting can be done one of two ways: firstly using JavaScript, and secondly using Smarty Tags. I think JavaScript will be better, as it will automatically get every location, whereas the Smarty Tag solution would requires some serious {capture} ... {$var|replace} action. The bestmethod may be to tweak my DNS settings, so that the location of schinckel.net is the same as that of schinckel.net, however I don’t yet know enough about this to even try.