Monthly Archives: June 2006

kfm – logs and forms

I’ve refined the KFM file browser. The submit button of any form is not needed until the form is valid, so I set the Upload button for teh file-upload form to display:none. The button is displayed once the file selection input actually contains something.

That helps with the amount of space used by the file browser.

Also, instead of showing alerts for errors and announcements, I’ve introduced a small logger. Errors are shown with high contrast colours, and normal messages are muted slightly (they don’t need to be too visible – they’re just log messages).

demo (Image or Link icon, then Browse Server)

the plugin source

today's KFM work

Today, I implemented the following for KFM.

  • Multiple file deletion. If you have several files selected, you can delete them all in one go with either the context menu (right-click), or with the Delete key.
  • File selection using the shift key. If the third file of a list is selected, and file seven is clicked with the shift key held, then the file selection is changed to files three to seven inclusive.
  • CTRL-A selection. If you press CTRL and A at the same time, all files are selected.

As usual, the demo is here (click the Image icon on the second row then click Browse Server).

The source can be downloaded here.

drag and drop for kfm

I had a bit of fun today. I finished off the list of outstanding bugs in KFM’s bug-tracker, and added the ability to move files around the directories by dragging them.

To select multiple files, you click one file, then click others with the CTRL key pressed down.

demo (click the Image icon on the second row, then click Browse Server)

Once I had the drag’n’drop coded, I realised that there was no real indication to the user of what had just happened (files just vanished, with no real explanation of why), so I added a visible indication – what I call “boxdrop tracers”; when you do the drag and release, pseudo icons appear where the selected files where, and move to the drop location (the directory you’re dropping the files into), helping the user to visualise that files have “moved” into the directories, instead of just vanishing.

I have two Firefox questions, which maybe some JavaScript guru type can answer. No rush, as I don’t actually /need/ to know, but:

If I click on an element, triggering an onclick event, which sets off a setTimeout which calls a function, is there a way for that function to know that I have the CTRL key pressed down? After all, the way everyone seems to do it is to check e.ctrlKey, where e is the event which triggered the function call – but in this case, the function is called by a setTimeout, not a trigger. Any way to check?

Another question which can possibly be answered: When a mouse is in “drag” mode (ie; the mouse button is clicked while the mouse is moving), no onmouseover or onmouseout events seem to be triggered on any elements – is this a bug in Firefox?

Today’s work can be downloaded here.

interesting phishing method

You’ve all seen those scams where an email claims that your ebay or paypal account is violated, and gives a link directly to the login, which you can easily see is fake because a hover over the link shows an IP address in the status bar of your email client.

I just received an email which had me puzzled for a few minutes. It was obviously a phishing attempt, but a quick glance through the page didn’t show anything fake-looking. Hovering over the provided links showed a proper paypal address (https://www.paypal.com/cgi-bin/webscr?cmd=_login-run). Even right-click->copy on the links provided the right address in a browser. Puzzling.

Then I looked in the source, and found that the links were actually surrounding a submit input which was made to look like a plain link. Clicking that input would submit a form going to a nastier place.

The fact that a submit button can look so much like a link and not give any warning, is a security bug in my eyes. Here is the suspicious code:

<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_login-run">
			<font size="2" face="Arial, Verdana">


<INPUT style="BORDER-RIGHT: 0pt;
BORDER-TOP: 0pt; FONT-SIZE: 10pt; BORDER-LEFT: 0pt; CURSOR:
hand; COLOR:
blue; BORDER-BOTTOM: 0pt; BACKGROUND-COLOR: transparent;
TEXT-DECORATION: underline" type=submit
value="click here and process your login." tabindex="1"></font></a>

What I think is vexing about this is that it took a look at the source to find this out. In my opinion, hovering over an input button should definitely not show a surrounding link’s url on the status-bar.

I’m submitting a bug to Thunderbird at the moment (although it’s probably more apt to submit to Firefox – it’ll all end up right, anyway) asking that a hover over a Submit input show the form target’s url in the status bar.

automating fake watermarks

To give one of our clients a moderate amount of security, I was asked to add a watermark facility to an ajax shoppingcart. For full security, it makes sense to edit the actual image, but for less pressing security, I had to come up with something clientside.

The trick I built is based on a small hack which gives basic security for images – overlay the image with a transparent image:

<img src="blank.gif" style="background:url(actual_image.jpg)" width="120" height="100" />

When a person right-clicks and saves the image, they actually get a blank image instead.

To extend on this, I was asked to use a watermark image instead of a blank image

Here is an example of the watermark (on a blue background to make it more clear):

Unfortunately, you cannot simply apply the same trick as before:

As you can see, the watermark stretches to fill the image with and height. What we actually want is for the watermark to be centered.

In Firefox, this is dead simple:

<img src="/wp-content/uploads/2006/06/watermark.gif" style="background:url(/wp-content/uploads/2006/06/beatles.jpg);padding:112px 138px" width="124" height="124" />

Unfortunately, that does not always work in IE (read: very rarely), as it ignores padding on images unless the browser is in “standards mode”.

A half-solution then for IE is this:

<span style="position:relative;padding:112px 138px;height:349px;background:url(original_image.jpg);">
  <img src="watermark.gif" width="124" height="124" />
</span>

That places the watermark in the right position, but you can get the background image by right-clicking and saving when the mouse is not directly above the watermark.

So, we need to use yet another level of hackery, and draft in the original blank image in yet another level of elements:

<span style="background:url(original_image.jpg);">
  <span style="position:relative;padding:112px 138px;height:349px;background:url(blank.gif);">
    <img src="watermark.gif" width="124" height="124" />
  </span>
</span>

FSCKing ugly!

Anyway, to automate this, I wrote this thing here:

if(vals.watermark&&!browser.isSafari){
	widget='<img src="'+vals.watermark+'" id="sc_counter_'+sc_counter+'" />';
	var img=new Image();
	img.id='sc_imageloader_'+sc_counter;
	img.callback='callback'+sc_counter;
	window['callback'+sc_counter]=new Function(
		"var el=$('sc_counter_"+sc_counter+"'),el2=$('sc_imageloader_"+sc_counter+"');"
		+"if(browser.isIE){"
			+"var el4=newEl('span');"
			+"el4.style.background='url(/i/blank.gif)';"
			+"el4.style.position='relative';"
			+"el4.style.height=el2.height;"
			+"el4.style.padding=((el2.height-el.height)/2)+'px '+((el2.width-el.width)/2)+'px';"
			+"var el3=newEl('span',0,0,el4);"
			+"el3.style.background='url("+vals.src+")';"
			+"el.parentNode.insertBefore(el3,el);"
			+"el4.appendChild(el)"
		+"}else{"
			+"el.style.background='url("+vals.src+")';"
			+"el.style.padding=((el2.height-el.height)/2)+'px '+((el2.width-el.width)/2)+'px';"
		+"}"
		+"delEl(el2);"
	);
	img.onload=function(){setTimeout("window."+this.callback+"();window."+this.callback+"=null;",1);}
	img.style.display='none';
	img.src=vals.src+'?'+sc_counter;
	document.body.appendChild(img);
}
else widget='<img src="'+vals.src+'" />';

The above is part of a HTML generation thing, which is then passed through a html2dom parser before being added to the document.

The code is basically told “draw an image img1, using image img2 as a watermark”. It must then work out all the widths and sizes itself.

You cannot simply leave out the width and height, as the image will end up being the size of the watermark, with only the top left of the actual image displaying. Therefore, we must work out what width and height to resize the image to.

To do that, we tell the browser to load the actual image, and set an “onload” on it to retroactively resize the watermarked version to the correct dimensions. You’ll note that I’ve told it to forget about the watermark in Safari’s case. That’s because Safari does not have an onload event for images.

A much simpler example of the above code (if I was allowed to tell IE to go screw itself 😉 ) would have been this:

if(vals.watermark&&!browser.isSafari&&!browser.isIE){
	widget='<img src="'+vals.watermark+'" id="sc_counter_'+sc_counter+'" />';
	var img=new Image();
	img.onload=new Function(
		"var el=$('sc_counter_"+sc_counter+"');"
		+"el.style.background='url("+vals.src+")';"
		+"el.style.padding=((this.height-el.height)/2)+'px '+((this.width-el.width)/2)+'px';"
		+"delEl(this);"
	);
	img.style.display='none';
	img.src=vals.src;
}
else widget='<img src="'+vals.src+'" />';

icons for kfm

Images now have auto-generated icons for them.

It was interesting developing these – a major difference between Internet programming and desktop applications, is the extreme slowness of the Internet at times.

As an example, I’ll walk through an experience of loading up the Test directory in the demo (click the image icon, then Browse Server), while my computer is under a heavy network load (I have discovered the treasure of public domain films).

  1. Initial file directory, with icons depending on the extension of the file:
  2. The browser then requests the addresses of different icons for those files that might be images (again, based on the extension):
  3. The browser finally finishes replacing the icons.
  4. On a slow network, the major bottleneck was step 2 above. The reason for this was that when a browser is asked to replace the background image of an element, it does it immediately, whether that image is in its memory yet or not. Notice that there are two empty spaces there – those oare icons where the original default icon has been cleared, but the new replacements have not yet loaded.

    So, the solution was to first load the image, then replace the element’s background.

    How? Simple:

        var img=newImg(image_data.icon);
        setStyles(img,'width:1px;height:1px');
        img.onload=function(){
          var p=this.parentNode;
          setStyles(p,'backgroundImage:url("'+p.kfm_attributes.image_data.icon+'")');
          p.removeChild(this);
        }
        el.appendChild(img);
        el.kfm_attributes.image_data=image_data;
    

    Obviously in the above, el is the icon element, and image_data is some data retrieved from the server about the image.

    Now, that’s all nice and dandy, and solves the huge “blank space” issue, but it still takes a little bit of time to load. What if you need to go back to that directory at some future time?

    Obviously, a bit of caching is needed. If you need to view that directory again, load up the file list as normal, then see if there is a cached copy of that file’s data. In the kfm, I store this data in kfm_filesCache. For example, the line directly after the above block is this:

        kfm_filesCache[kfm_cwd+'/'+file]=el.kfm_attributes;
    

    There is a subtle problem here, though, which can trip up even the most experienced web developers every now and then – what if the image changes? Obviously, if you change an image (rotate, etc), then you want the icon to also change. This can be tricky if you only refer to the image as “blah.png”.

    Solution to this is to change the src of the image to “blah.png?5897451” (a random number) or similar, and cache /that/ address, then when the image changes, simply remove the cached copy (set it equal to null), then rebuild the data. The new icon will have a different random number, so will reload.

    For example, the line directly preceding the block above is this one:

       if(!kfm_filesCache[kfm_cwd+'/'+file])image_data.icon=image_data.icon+'?'+Math.random();
    

    I hope this was helpful to someone, and not just of interest to myself 😉

mantis bugtracker for kfm

I’m on holiday at the moment, so I thought I’d put a bit of work into something which, though it will eventually be of use in my regular work, is actually just a personal obsession at the moment. To help keep track of it, I’ve installed a bug tracker. We use Mantis in work, and, while it’s a bit of overkill sometimes, it’s still very very useful. Apparently, it will be skinnable soon, which will help quite a bit with its usability.

broken cd?

In Linux, if you cd /; pwd, cd ///; pwd or cd ////; pwd, you will always be given this result:

/

However, if you cd //; pwd, you will be given this:

//

That’s also true of cd //usr/share

//usr/share

But not true of cd //usr//share

//usr/share

/me ponders that for a moment, then gets another can of carlsberg from the fridge and goes to mow the lawn.

multiple text-shadows

I was reading my blogs today and came across this post, which mentioned that Konqueror is the only browser around that can handle multiple text-shadows, as per the W3C CSS3 draft.

In the post, Allan provided an example of a secret code displayable only in Konqueror (well, and text-browsers as well, I suppose).

I took that as a challenge, and have upgraded my old text-shadow hack to handle multiple shadows.

As an example, here is a copy of Allan’s demo, with my script attached.

This works in Firefox and Konqueror. I don’t have IE on this machine, so can’t test that, but I expect it will.

file upload security problem

Check this out (but only if you trust me):

demo (source)

It relies on a bug in some browsers, where the “type” of an input box can be changed into “file” without clearing the value of the input.

Fixed in the latest version of Firefox (1.5.0.4). Couldn’t test IE, as it sucks and couldn’t handle the JavaScript.

Tried this out on the lucky denizens of #linux (irc:irc.linux.ie), and was immediately rewarded with some exclamations of surprise that I’d gotten through their defenses.

Script works in Konqueror (tested 3.5.2) and Safari (1.3.2). Causes a strange rendering problem in Opera.

For those of you that are concerned that I know “ownz” your computer – /etc/passwd is safe. Passwords are stored in /etc/shadow. Anyway, I don’t store any of the files you’ve unwittingly uploaded.