Search

Rss Posts

Rss Comments

Login

 

Posts in ‘codin’’

dateSlider jQuery plugin

Feb 18

This is actually the third version, as the first two didn’t quite hit the mark on the requirements… This jQuery dateslider is based on the slick and cool Ajaxorized version, originally written for Prototype.js. What I didn’t like was that it’s zoom in/out feature didn’t really scale very well (what unit I am looking at? and why don’t these lines line up?), and made it hard to pick a date and time.

I used jQueryUI because it handily had all the things I need: draggable, resizable things. The hardest part was, of course, the actual date-times (as anyone who has to work with Javascript dates knows). I used the super handy date.js like the original as well.

To use it, include jquery, jqueryui, date.js, and the plugin:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script>
<script src="date.js"></script>
<script src="jquery.dateRanger.js" type="text/javascript"></script>

Then, initalize the plugin:


<script type="text/javascript">
$(function(){
$("#my-date-slider").dateRanger({
"dateFormat": "MMM dd yyyy HH:mm:ss",
"timeStart": Date.today().set({
day: 1,
month: 0,
year: 2011
}),"timeEnd": Date.today().set({
day: 30,
month: 11,
year: 2012
}),
"startDate": Date.parse("1/17/2011"),
"endDate": Date.parse("4/2/2011"),
"zoomLevel": "month",
"unitwidth": 20
})
});
</script>
The options:

  • dateFormat : a string or date.js format specified (check it!) (i.e. “MMM dd”, “u”, “yyyy-MM-d ht”)
  • timeStart: the first available date; You can pass in anything recognized by date.js (i.e. “today”, “yesterday”, “+2weeks”, “-18years”, etc.)
  • timeEnd: the last available date
  • startDate: beginning of the selected range
  • endDate: the end of the selected range
  • zoomLevel: what time unit you see on load: accepts “year”,”month”,”day”, or “hour”
  • unitwidth: how wide is a unit? If you change this, be sure to change the css for .day to match

Download plugin: jquery.dateRanger.js:
(function($){
$.fn.dateRanger = function(options){
var settings = {
"startDate": Date.parse('-7days'),
"endDate": Date.parse('-1days'),
"dateFormat": 'MMM dd yyyy HH:mm:ss',
"timeStart": Date.today().set({
day: 1,
month: 0,
year: 2011
}).clearTime(),
"timeEnd": Date.today().set({
day: 31,
month: 11,
year: 2012
}).clearTime(),
"zoomLevel": "day",
"unitwidth": 20
};
var config = $.extend(settings, options);
var zoom = config.zoomLevel, rangeStart = config.startDate, rangeStop = config.endDate, timeStart = config.timeStart, timeEnd = config.timeEnd, f = config.dateFormat, w = config.unitwidth, one = new Array();
one["second"] = 1000;
one["minute"] = 1000 * 60;
one["hour"] = 1000 * 60 * 60;
one["day"] = 1000 * 60 * 60 * 24;
one["month"] = 1000 * 60 * 60 * 24 * 30;
one["year"] = 1000 * 60 * 60 * 24 * 365;
function mapDates(ui){
var range = ui.width() / w;
var s = ui.position().left / w;
var e = s + range - 1;
var startDate = $j(".day").eq(s).attr("data-date");
var endDate = $j(".day").eq(e).attr("data-date");
$j("#datestart").val(startDate.toString(f))
$j("#dateend").val(inclusiveRange(endDate, zoom).toString(f))
centerSelection();
}
function centerSelection(){
$j("#dragger").css('left', -1 * ($j("#resizer").position().left - .5 * ($j("#mask").width() - $j("#resizer").width())))
}
function difference(a, b, z){
A = a.getTime() / one[z];
B = b.getTime() / one[z];
return Math.floor(B - A);
}
function unitsbetween(a, b, z){
A = a.getTime() / one[z];
B = b.getTime() / one[z];
return (B - A);
}
function inclusiveRange(d, zoom){
var $fullrange = (Date.parse(d)) ? Date.parse(d) : Date.parse(d.substring(0, d.length - 1));
var compare = $fullrange.clone();
switch (zoom) {
case "year":
return compare.set({
month: 0,
day: 1
}).clearTime().add(1).years().add(-1).seconds();
break;
case "month":
return compare.moveToLastDayOfMonth().add(1).days().add(-1).seconds();
break;
case "day":
return compare.add(1).days().add(-1).seconds();
break;
case "hour":
return compare.add(1).hours().add(-1).seconds();
break;
case "minute":
return compare.add(1).minute().add(-1).seconds();
break;
case "second":
return compare.add(1).seconds().add(-1).milliseconds();
break;
default:
return $fullrange;
break;
}
}
function buildDates(zoom){
$j("#dragger").css('left', '0')
$j("#dragger .day").remove();
$j("#resizer").css({
left: 0,
width: w + "px"
})
var visibleArea, format1, format2, tempDate;
switch (zoom) {
case "hour":
var tempDateHS = Date.parse($j("#datestart").val()).clone().add(-1).days();
var tempDateHE = Date.parse($j("#dateend").val()).clone().clearTime().add(2).days();
visibleArea = difference(tempDateHS, tempDateHE, zoom);
format1 = "MMM dd yy ht";
format2 = "ht";
tempDate = tempDateHS.clone()
break;
case "day":
visibleArea = difference(config.timeStart, timeEnd, zoom);
format1 = "MMM dd yy";
format2 = " dd";
tempDate = timeStart.clone()
break;
case "month":
visibleArea = difference(config.timeStart, timeEnd, zoom);
format1 = "MMM 'yy";
format2 = "MMM 'yy";
tempDate = timeStart.clone()
break;
case "year":
visibleArea = Math.max(timeEnd.getFullYear() - config.timeStart.getFullYear(), 1);
format1 = "yyyy";
tempDate = timeStart.clone()
break;
}
$j("#dragger").css('width', visibleArea * w)
for (i = 0; i < visibleArea; i++) {
if ((zoom == "day" && tempDate.getDate() == 1) || (zoom == "hour" && tempDate.getHours() == 0)) {
format = format1;
cl = " fdotm"
}
else
if (zoom == "month" && tempDate.getMonth() == 0) {
format = format1;
cl = " fmoty"
}
else
if (zoom == "year") {
format = format1;
cl = " yrot"
}
else {
format = format2;
cl = "";
}
$j("#dragger").append('<div data-date="' + tempDate.toString(f) + '">' + tempDate.toString(format) + '</div>')
tempDate.add(1)[zoom]()
}
}
function setScroller(s, r){
if (r > 1)
r = Math.ceil(r);
else
r = Math.round(r);
$j("#resizer").css({
left: $j(".day[data-date='" + s + "']").position().left,
width: r * w + "px"
})
}
function u2Date(u){
if (u.indexOf("Z") != -1)
return Date.parse(u.substring(0, u.length - 1));
else
return Date.parse(u);
}
$j("#datestart").live("change", function(e){
if (Date.parse($j(this).val())) {
var inpS = Date.parse($j(this).val());
var inpE = u2Date($j("#dateend").val())
if (inpS.compareTo(inpE) == 1) {
inpE = inpS;
}
$j("#datestart").val(inpS.toString(f));
setScroller($j("#datestart").val(), Math.max(difference(inpS, inpE, zoom), 1))
mapDates($j("#resizer"));
}
else {
$j(this).addClass("error").effect("pulsate", {
times: 2
}, 500, function(){
$j(this).removeClass("error").focus()
});
}
});
$j("#dateend").live("change", function(e){
if (Date.parse($j(this).val())) {
var inpE = Date.parse($j(this).val());
var inpS = u2Date($j("#datestart").val())
if (inpS.compareTo(inpE) == 1) {
inpE = inpS;
}
$j("#dateend").val(inpE.toString(f));
setScroller($j("#datestart").val(), Math.max(difference(inpS, inpE, zoom), 1))
mapDates($j("#resizer"));
}
else {
$j(this).addClass("error").effect("pulsate", {
times: 2
}, 500, function(){
$j(this).removeClass("error").focus()
});
}
});
$j("div.zoomMenu div").live("click", function(){
$t = $j(this);
zoom = $t.html();
$j("div.zoomMenu div").removeClass("selectedZoom")
$t.addClass("selectedZoom");
buildDates(zoom)
inpS = u2Date($j("#datestart").val());
inpE = u2Date($j("#dateend").val());
switch (zoom) {
case "hour":
inpS.set({
"hour": 0
});
inpE = inclusiveRange(inpE, zoom);
break;
case "day":
inpS.set({
"hour": 0
});
inpE = inclusiveRange(inpE, zoom);
break;
case "month":
inpS.moveToFirstDayOfMonth();
inpE.moveToLastDayOfMonth();
break;
case "year":
inpS.set({
month: 0,
day: 1
});
inpE.set({
month: 0,
day: 1
}).add(1).years().add(-1).seconds();
break;
}
$j("#datestart").val(inpS.toString(f));
$j("#dateend").val(inpE.toString(f));
setScroller($j("#datestart").val(), difference(inpS, inpE, zoom))
mapDates($j("#resizer"));
});
return this.each(function(){
var zooms = {
"year": "yyyy",
"month": "MMM",
"day": "dd",
"hour": "HH"
};
var structure = '<div id="range">';
structure += '<div id="dragDate">';
structure += '<label for="datestart">Start</label><input id="datestart" name="datestart" type="text" /> ';
structure += '<label for="dateend">Stop</label><input id="dateend" type="text" name="dateend"/>';
structure += '</div>';
structure += '<div id="mask"><div id="dragger"><div id="resizer"></div></div>';
structure += '</div>';
structure += '<div>';
var cla = '';
for (b in zooms) {
cla = (b == zoom) ? '' : '';
structure += '<div' + cla + '>' + b + '</div>';
}
structure += '</div></div>';
$j(this).append(structure);
buildDates(zoom);
$j("#dragger").draggable({
grid: [w, 0],
axis: 'x',
addClasses: false
});
$j("#resizer").resizable({
handles: 'e, w',
grid: [w, 0],
containment: '#dragger',
stop: function(event, ui){
if (ui.position.left < 0) {
$j("#resizer").css('left', '0px')
}
mapDates($j(this))
},
addClasses: false
}).draggable({
grid: [w, 0],
axis: 'x',
containment: '#dragger',
stop: function(event, ui){
mapDates($j(this))
},
addClasses: false
}).css({
left: $j(".day[data-date='" + rangeStart.toString(f) + "']").position().left,
width: difference(rangeStart, rangeStop, zoom) * w + "px"
});
mapDates($j("#resizer"));
centerSelection();
});
};
})(jQuery);

And some useful CSS to finish up with:

#range {
position: relative;
}
.day {
color: #8997a5;
padding: 10px 0 0;
font-size: 9px;
width: 19px;
float: left;
height: 25px;
border-left: 1px solid #eee;
text-align: center;
}
.fdotm {
padding: 1px 0 0 0;
border-left: 1px solid #bbb;
height: 35px;
}
.fmoty {
padding: 10px 0 0 0;
border-left: 1px solid #888;
height: 25px;
}
.yrot {
font-size: 8px
}
#mask {
width: 100%;
overflow: hidden;
height: 80px;
position: absolute;
left: 0;
top: 50px;
}
#dragger{
width: 10000em;
position: absolute;
left: 0;
top: 10px;
z-index: 2;
height: 75px;
cursor: move;
padding: 10px 0 0 0;
background: none;
border: none;
color: #000;
}
#dragger #resizer{
background: rgba(0, 137, 206, 0.2);
width: 200px;
position: absolute;
top: 10px;
z-index: 6;
height: 40px;
cursor: move;
padding: 0;
margin: 0;
}
.error {
background: #ff0013;
}
.zoomMenu {
padding: 10px 0 0 0;
text-align: center;
}
.zoomMenu div {
display: inline;
color: #0089ce;
text-align: center;
cursor: pointer;
margin-right: 5px;
padding: 2px 6px;
position: relative;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.zoomMenu div:hover {
background: #e5f3fb;
color: #333;
}
.zoomMenu div.selectedZoom {
background: #0089ce;
color: #fff;
}

jQuery quick slideshow

Aug 04

Ok, so I’ve been playing more and more with jQuery. Here’s my take on showing off my portfolio, where I give a brief on each project and include a screen-shot.  This also uses the cool reflection.js for the images, and provides a simple progress stepper.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">// <![CDATA[
$(function() {
$('#mainContent img').addClass("reflect rheight10");
$('#mainContent img').css("float","right"); //reflect messes up floats, so add back in here
$(".H").append('<span>&laquo; Prev</span> | <span>Next &raquo;</span>');
var g=1;
$(".H").each(function(){
perc = (g/$(".H").length)*100;
$(this).append('
<div>
<div style="width:'+perc+'%"></div>
</div>
')
g++;
});
$(".next").css('cursor','pointer').click(function(){    slideShow();    })
$(".prev").css('cursor','pointer').click(function(){    slideShowPrev();})
$(".H").filter(':not(:last)').hide();
$(".H").filter(':last').addClass('show'); //'show' the last slide because when we call slideshow(), it will loop around to the first slide
$('#port a').attr('target','_blank');
slideShow();
});

function slideShow() {
var current = $('#port .show');
var next = current.next().length ? current.next() : current.parent().children(':first');
current.fadeOut('slow').removeClass('show');
next.fadeIn('slow').addClass('show');
}
function slideShowPrev() {
var current = $('#port .show');
var prev = current.prev().length ? current.prev() : current.parent().children(':first');
current.fadeOut('slow').removeClass('show');
prev.fadeIn('slow').addClass('show');
}
// ]]></script>
<script src="scripts/reflection/reflection.js" type="text/javascript"></script>

This works with the structure I already had–classed div’s holding each project.

Mootools Noobslide Hover/mouseover/mouseenter good times

Sep 08

I’ve had the Noobslide (slideshow “class” for Mootools (great tutorial here) for awhile, but I needed to added some basic functionality: when you hover (or mouseover) a slide, it stops the show so you can read it. When you rollout (mouseleave or mouseout), the show starts up again. Great!

Note that this assumes you have your slides in generic <span> tags inside something with an id of ‘box1′.


window.addEvent('domready',function(){
var nS1 = new noobSlide({
box: $('box1'),
items: [0,1,2,3,4],
size: 400,
autoPlay: true,
interval: 8000,
fxOptions: {
duration: 1000,
transition: Fx.Transitions.Expo.easeInOut,
wait: false
}
});
//add mousein/out behaviors for all slides
$$('#box1 span').addEvents({
'mouseover':function(){
nS1.stop();
},
'mouseleave':function(){
//make sure the first argument matches your 'interval' value above
//this will set the delay,go to the next slide, without waiting for the delay (rolloff, immediately transitions to next slide)
nS1.play(8000,"next",false);
}
});
//end domready
});

Cool. Another thing I wanted was some text links to jump around the slide show. I’ve got my slides in a container with an id of’slidefloater.’ Here it is: (this would be inserted before the last ‘});’, inside the domready function )

var clinker=new Element('div',{'id':'clinker','styles':{'width':400}});
clinker.inject($('slidefloater'));
var labels = Array("label 0","label 1","label 2","label 3","label 4");
var i=0;
labels.each(function(el){
var linkto=new Element('a',{'html':el,'href':'#','styles':{'margin-right':4}});
linkto.j = i; //localize
linkto.addEvent('click', function(){
nS1.stop();
nS1.walk(this.j);
nS1.play(8000,"next",true); //go to next slide after normal interval (wait to go)
} );
i++;
linkto.inject($('clinker'));
});

Good times!

Mo’ Mashup

Sep 01

OK, so now the Facebook API is integrated, and seems to be working as expected. You plug in a city/state or ZIP, and the app finds folks you know in a 150 mile radius. It’s a little slow because I am loading all friends right now. It also only knows what people have put in their ‘current location,’ so you won’t see anyone who hasn’t provided that info. Still pretty good.

Also cleaned up some links with some logic (i.e. no longer gives a link to the next page of job search when there are no results!).

Found a nice function I adapted for PHP to compare two geocodes:

function ToRadian( $val) { return $val * ( pi() / 180); }
function DiffRadian( $val1,  $val2) { return ToRadian($val2) - ToRadian($val1); }
function  CalcDistance( $lat1,  $lng1,  $lat2,  $lng2, $m='') {
$radius = ($m == 'km')? 6367.0:3956.0;
return $radius * 2 * asin( min(1, sqrt( ( pow(sin((DiffRadian($lat1, $lat2)) / 2.0), 2.0) + cos(ToRadian($lat1)) * cos(ToRadian($lat2)) * pow(sin((DiffRadian($lng1, $lng2)) / 2.0), 2.0) ) ) ) );
}

Which I found at this nice person’s blog (thanks to Chris Pietschmann!)

I am using it to compare the friend’s location with the city/state/zip of the job search. So far, so good!

Creating a mashup

Aug 24

Fun and troublesome!
Mashup in progress

Issues:

  1. Installing PEAR on shared GoDaddy server, thanks to Abby and Win’s Blog
  2. Getting Zillow data (easy!)
  3. Altering GoogleMapAPI.class.php (from phpinsider.com)
    1. Moving from PEAR DB to MDB2 (what I used for reference because DB is deprecated in the latest version of PEAR)
    2. changed function getCache:
      function getCache($address) {
      if(!isset($this->dsn)) return false;
      $_ret = array();
      // PEAR MDB2
      require_once("MDB2.php");
      $_db =& MDB2::connect($this->dsn);
      if (PEAR::isError($_db)) {
      die($_db->getMessage() . ', ' . $_db->getDebugInfo());
      }
      if (PEAR::isError($_db)) {
      die($_db->getMessage(). ', ' . $_db->getDebugInfo());
      }
      $_res =& $_db->query("SELECT lon,lat FROM {$this->_db_cache_table} where address = '$address'");
      if (PEAR::isError($_res)) {
      die($_res->getMessage(). ', ' . $_res->getDebugInfo());
      }
      if($_row = $_res->fetchRow()) {
      $_ret['lon'] = $_row[0];
      $_ret['lat'] = $_row[1];
      }
      $_db->free();
      return !empty($_ret) ? $_ret : false;
      }
    3. changed function putCache:
      function putCache($address, $lon, $lat) {
      if(!isset($this->dsn) || (strlen($address) == 0 || strlen($lon) == 0 || strlen($lat) == 0))
      return false;
      // PEAR MDB2
      require_once("MDB2.php");
      $_db =& MDB2::connect($this->dsn);
      if (PEAR::isError($_db)) {
      die($_db->getMessage() . ', ' . $_db->getDebugInfo());
      }
      $_res =& $_db->query("insert into ".$this->_db_cache_table." values ('$address', $lon, $lat)");
      if (PEAR::isError($_res)) {
      die($_res->getMessage());
      }
      $_db->free();
      return true;
      }
    4. GoogleMap API (easy once I figured it liked addresses better than the lat/long Zillow was returning…)

Stay tuned for more developments…

To do:

  1. fix line-height of superscripted registration mark
  2. integrate multiple listings
  3. integrate search
  4. integrate 2 other (maybe 3?) API’s to be named later

Sorting Content (client side!)

Jul 07

If you’ve got some content organized on your page, but you want it to be in a different order, here’s a quick fix:

//grab elements (in this case, all elements with class="bl"
var tasksC = $$('.bl');
//reorder on page in alpha
tasksC.sort(sortByTitleText);
//add back in new order
$$(tasksC).each(function(el){
el.inject($('catList'));
});

function sortByTitleText(a, b) {
/*
the value you're sorting can also be innerHTML. Mine had special formatting, so just using the text itself.
*/
var x = a.textContent;
var y = b.textContent;
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

Rewrite Document Titles and Fix Orphans with Javascript

Feb 04

One more doozy… let’s say your LMS was built without attaching id’s to anything.  How about one class for every piece of text on-screen? Enormous tables? Check. Please.

I wrote some classes I put around titles, which were nice enough to be duplicated from ‘display’ to ‘navigation’, cool! But now my title bar looks like this: <span class=”noShow”>Totally Uncool</span>

Which is weak. I had three classes I was using to further differentiate items on the naviation bar.  Here’s how I repaired it.

fix = document.title;
if (fix.indexOf(‘<span class=”noShow”>’) != -1){
fixMe = fix.split(‘<span class=”noShow”>’);
good = fixMe[1].substr(0, fixMe[1].indexOf(‘</span>’));
document.title = good;
}else if(fix.indexOf(‘<span class=”tC”>’) != -1){
fixMe = fix.split(‘<span class=”tC”>’);
good = fixMe[1].substr(0, fixMe[1].indexOf(‘</span>’));
document.title = good;
}else if(fix.indexOf(‘<span class=”stC”>’) != -1){
fixMe = fix.split(‘<span class=”stC”>’);
good = fixMe[1].substr(0, fixMe[1].indexOf(‘</span>’));
document.title = good;
}

Also, if you’ve worked with Print Layout People (you know who I am talking about… Kerning Snobs, etc.) or have some layout experience yourself, you’re familar with orphans.  Oh, woe unto them as they stand alone in a cold (line) world by their lonesome. I was just concerned with fixing them in titles, where they really attract unwanted attention.

(this does require Mootools)

//fix orphaned words in titles
var ti = $(document.body).getElement(‘h3.ti’);
if($(ti)){

//make sure we have something, otherwise IE freaks right out
var tiSize = $(ti).getSize();
var output;

//if it’s larger than two lines, attach a nbsp between last two words

/* In this case, my h3 is 18px. I am sure there is a clever way to get the info out of the style sheet, but I don’t know of it (yet). 28 accounts for padding and the fact that IE has different sized pixels than everybody else.*/
if (tiSize.y>28){
var tiText = $(ti).get(‘html’).split(‘ ‘);
if (tiText.length > 2){
for (r=2; r<=tiText.length-1; r++){
if(tiText[r].length > 0){
output += tiText[r];
if(r==tiText.length-2){
output += ‘ ’;
}else{
output += ‘ ‘;
}

}

}
he = tiText[0]+’ ‘+tiText[1]+’ ‘;
po = output.split(‘undefined’).join(”);

//just in case!!!
$(ti).set(‘html’, he+”+po);
}
}
}

So yeah, Mootools pretty much saved my bacon all over the place on this project.

Replace Images with Links with Javascipt

Feb 03

So, in this project I am working on, I’ve had to code around a fairly annoying LMS (Learning Management System). Most recently, in our user testing we discovered that the images were too small to be useful. To remedy that, I painstakingly remade all the images from PDF’s. Problem now is they’re too big to fit in the layout.  No problem, right? We just whip up some Mootools usage and replace the image with a link that launches a popup window.

window.addEvent(‘domready’, function() {
//replace images with pop-up style links

//content2 is the div where the images are
var images = $$($(‘content2′).getElementsByTagName(‘img’));
for (i=0; i<=images.length-1; i++){
linkto = images[i].src;
var thelink  = new Element(‘a’,
{‘id’: ‘image’+i,
‘events’: {
‘mouseover’: function(){
opnwinImage(‘”‘+linkto+’”‘);
}
},
‘class’:'popup’,
‘html’:'view image’,
‘href’:'#’
}
);
$(thelink).replaces(images[i]);
}
}

/* here’s the popup window: it sizes itself to the image, with a little extra for the close and print buttons. */

function opnwinImage(url){
url = url.split(‘”‘).join(”);
sz = getImgSize(url).split(‘,’);
newwindow2=window.open(”,’name’,'height=’+(Number(sz[1])+120)+’,width=’+(Number(sz[0])+20)+’,scrollbars=1,resizable=1′);
var tmp = newwindow2.document;
tmp.write(‘<html><head><title>Image PopUp</title>’);
tmp.write(‘<link href=”/css/style.css” rel=”stylesheet” type=”text/css” />’);
tmp.write(‘</head><body>’);
tmp.write(‘<div class=”popUpControls”><span><a href=”javascript:window.print()”>print</a></span>’);
tmp.write(‘<span><a href=”javascript:self.close()”>close</a></span>’);
tmp.write(‘</div>’);
tmp.write(‘<div class=”popUpContent”>’);
tmp.write(‘<img src=”‘+url+’” alt=”" align=”center” />’);
tmp.write(‘</div>’);
tmp.write(‘<div class=”popUpControls”><span><a href=”javascript:window.print()”>print</a></span>’);
tmp.write(‘<span><a href=”javascript:self.close()”>close</a></span>’);
tmp.write(‘</div>’);

tmp.write(‘</body></html>’);
if (window.focus) {newwindow2.focus()}

tmp.close();

}

//and of course, we need to know how big the image is…

function getImgSize(imgSrc)
{
var newImg = new Image();
newImg.src = imgSrc;
var height = newImg.height;
var width = newImg.width;
return (width+’,'+height);
}