Sharing is Caring- Using JavaScript to Enable Image Sharing
People hijack my images all over the web. Yes. It’s true. While I’m not 100% happy about it, I’m also not 100% upset about it since I’m glad that people like my images enough to swipe them. So I tolerate it.
One thing that would make it all a lot more palatable is if people who were taking my images would link back to my site. The link would serve as credit, would drive traffic, and would increase my page rank. What’s not to love?
To that end, I wrote up a little script last week that I attached to all my gallery images to maybe, just maybe, help people to do just that.
Want to try it out? Click through to view the glory of my “trouble” graffiti canvas. When you’re there, right click on the image- as if you were going to “Copy Image Location.”
Wasn’t that cool?
For the lazybones in the audience who haven’t actually clicked through, right clicking on the image triggers a little JavaScript function that throws this at the user

As you can see it’s a fairly friendly option to grab some easy-to- paste code in order to share the image. How nice am I?
If anyone actually uses it instead of just stealing the image then the whole process would be a resounding success. Traffic + page rank = good times.
Want to know how it’s done? The code follows. For what it’s worth, I’ve translated this into plain old JavaScript. There are some shortcuts that my actual code uses that I’ve turned back into native objects and methods so that it should be more readily grasped by folks no matter what style or library they might use in their day-to-day coding:
Anyway, on page load (either window.onload or whatever enhanced version you use- I use this ) I run this block:
if (document.body.id=="grafpg" || document.body.id=="comicspg" || document.body.id=="artpg" ) {
document.body.innerHTML+="<div id='msg'><div id='msg-body'><h3>Want to share this image?</h3><label for='grablink'>Here's the code to paste into your blog, forum post, myspace, etc :</label> <textarea name='textarea' id='grablink'></textarea><p id='download'></p><p>All images © Rob Larsen</p></div><div id='clear-msg'></div></div><div id='cloak'></div>";
createShareLinks();
}
In my specific case I know that pages with ids of grafpg, comicspg and artpg are the page types that will have gallery images I want to manipulate. If any of those three page IDs show up, I use innerHTML to append the basic structure of the overlay to the page. As a note, because I have this structure already in place, this script is completely unobtrusive. I didn’t need to change the HTML at all to implement this functionality. Such is the benefit of thinking a little bit about the semantic meaning of ID and CLASS attributes. Since went so far as to separate the three “types” of art page, even though they display exactly the same, I could conceivably present three separate versions of the interface depending on the site section, still without touching the underlying HTML. Structure is cool.
I should mention I love this sledgehammer approach to appending content to a page. I admit it wholeheartedly. It’s just so damned direct I can’t help but smile. Don’t get me wrong, I love createElement, appendChild, etc. and use them all the time. It’s just, being an HTML guy at heart I love to be able to mock up a display like this and then just drop it into a page with very little fuss. HTML source to JavaScript flashiness in no time flat
Anyway, after appending the overlay divs, I initiate the guts of the behavior with the createShareLinks() function. The source of which follows:
function createShareLinks(){
// there can be more than one img on a gallery page. Get the full nodeList of images
var theImg = document.getElementById("artimg").getElementsByTagName("img");
// and loop through
for ( var i=0;i<theImg.length;i++ ){
// attach an event to the contextmenu event
// did you know there was such a thing?
theImg[i].oncontextmenu = function() {
// do come calculations to create the proper
// height and width for the cloak and msg divs;
document.getElementById("cloak").style.width = document.getElementById("msg").style.width = this.offsetWidth + 2 + "px";
document.getElementById("cloak").style.height = document.getElementById("msg").style.height = this.offsetHeight + 2 + "px";
// there's some padding we need to take into account
document.getElementById("msg-body").style.height = this.offsetHeight - 32 + "px";
// get the x and y of the image and set the
// top and left of the divs accordingly
document.getElementById("cloak").style.left = document.getElementById("msg").style.left = (findX(this) -1) +"px";
document.getElementById("cloak").style.top = document.getElementById("msg").style.top = (findY(this) - 1) +"px";
// build the link text.
document.getElementById("grablink").value="<a href='http://www.drunkenfist.com/'><img src='"+this.src+"' alt='image copyright rob larsen' /></a>";
// I just like this
document.getElementById("grablink").onfocus = function() {
this.select();
};
document.getElementById("download").innerHTML="<a href='"+this.src+"'>Download this file</a>";
document.getElementById("clear-msg").onclick= clearShareLinks;
// show the divs
document.getElementById("cloak").style.display = document.getElementById("msg").style.display = "block";
return false;
}
}
};
//a simple function to hide the overlay;
function clearShareLinks() {
document.getElementById("cloak").style.display = document.getElementById("msg").style.display = "none";
}
First I create a nodeList of all images contained in div id=”artimg.” Once I have that nodeList, which will contain either one or two nodes, I loop through and attach an oncontextmenu event handler to the image. Did you know there was an oncontextmenu event handler before reading this article? If not, now you do
In the function that fires when a user right clicks (or control clicks) on an image I do some basic dHTML goodness. First I set the height and width of the two divs to equal the height and width of the target image and then I use the target image to calculate the left and top of the divs so that they sit right on top of the image. Once that’s all set I do some string manipulations to build out the link, some random other housekeeping and then I flip the switch and show the divs to the world in all of their glory.
By the way- are you thinking… “why two divs?”
Well, the one div, the one you’d expect to be the parent, I want to be semi-opaque in order to cloak the image. Thing is, one of the properties of CSS opacity is that all child elements inherit the parent’s opacity. Meaning I couldn’t have 100% opaque text inside a DIV with 80% opacity. Which would suck since it would be tougher to read. Instead, I fake it with two DIVs styled to act as one. Fun times.
Want to see the CSS?
Here it is:
#msg, #cloak {
position:absolute;
width:0;
height:0;
left:0;
top:0;
display:none;
}
#cloak {
opacity: .50;
/* IE, if you need this to validate, move into a separate IE sheet */
/* and hide from other browsers/ the validator with conditional comments */
filter:Alpha(opacity=50);
z-index:9998;
background-color: #0099FF;
}
#msg {
z-index:9999;
}
#msg-body {
width:75%;
margin:auto;
padding-top:35px;
}
#msg-body h3 {
background: #ddd;
padding:5px;
width:100%;
color:#000;
border:1px solid #000;
border-bottom:3px solid #000;
border-right:3px solid #000;
}
#msg-body p {
width:100%;
background: #ddd;
padding:5px;
border:1px solid #000;
border-bottom:3px solid #000;
border-right:3px solid #000;
}
#msg-body label {
font-size:.82em;
font-weight:bold
display:block;
padding:5px;
background: #ddd;
width:100%;
margin-bottom:10px;
border:1px solid #000;
border-bottom:3px solid #000;
border-right:3px solid #000;
}
#grablink {
width:100%;
height:100px;
background:#efefef;
border:1px solid #000;
border-bottom:3px solid #000;
border-right:3px solid #000;
overflow:hidden;
font-size:10pt;
padding:4px;
}
#clear-msg {
position:absolute;
right:5px;
top:5px;
width:30px;
height:30px;
/* sprites are my friend */
background: url(http://media.drunkenfist.com/img/sprite.1.png) -597px -185px no-repeat;
/* make it look clickable */
cursor:pointer;
cursor:hand
}
And that’s that. Will it get used? I hope so. If not, it’s the thought that counts, right?