JQuery and MarkLogic Mashup for Photo Gallery
posted by Steve on
I've been fooling around with a thumbnail gallery that pulls up either an associated video or image. Here is how I got the workings to work.
Our embedded video was a little tricky and I tried for many hours to just update the video player parameters using javascript based on which image is selected. I finally punted and wrote a webservice that refreshes the <div> with the output of a MarkLogic query.
This is the MarkLogic juice:
let $portrait-media := /portrait-media[@profileId eq $content/@profileId]/*
let $imgInd := fn:string($content/@imgIndex)
let $index := if (fn:string-length($imgInd) < 1) then
1
else
xs:integer($imgInd)
return
(
<div id="profile-head">
<h1>{ixd:string('dashboard-name-intro')} {fn:data($content/@name)} </h1>
<p>{$content/intro}<strong> I'm a Mormon.</strong></p>
</div>,
<div id="hero">
<div>
{
let $default := $portrait-media[$index]
return if(fn:string(fn:node-name($default)) eq 'video')
then
ixd:render('/content/pages/widgets/medium-video-player.ixd', $default)
else
<img src="{$content/@imgPath}" id="screenImage" />
}
<ul class="gallery galleria">
{
let $count := fn:count($portrait-media)
for $media at $i in $portrait-media
return
<li class="show-video {if ($i=$count)then 'last' else ()}" xmlns="http://www.w3.org/1999/xhtml">
<img class="thumb noscale selected borderPatrol {if ($i=$index) then 'opeth' else ()}" alt="{fn:data($media/@thumbnail)}" src="{fn:data($media/@thumbnail)}" index="{$i}" path="{$media/@main}"/>
</li>
}
</ul>
</div>
<!-- END GALLERY -->
<div xmlns="http://www.w3.org/1999/xhtml" class="clear"> </div>
</div>
)
The gallery gets built towards the end in the last for loop. That is the area where most time was spent. It seems easy enough but the devil is in the details.
For example, using the blueprint.css requires the last element to have a class=" last" attribute. See how I had to do that with the MarkLogic directive {if ($i=$count)then 'last' else ()}
Next I had to make sure that my javascript would pick up the element on a click. I did that with this piece of delectability:
$('.gallery li').live("click",(function(selected){{
var theImg = $(this).children("img");
var index = theImg.attr("index");
var imgPath = theImg.attr("path");
profileHead.loadImg('{$Id}',index,imgPath);
}}));
profileHead.loadImg calls the webservice with an Id the index of which video or image thumbnail was clicked and the path to the big image to display.
Ok none of this was really the hard part. Maybe the hardest of this was remembering to bind using the live method from JQuery since the bind can't happen before the div is populated.
The next part was the hardest. First binding the mouseover and mouseout to the images so they change as they are rolled over:
$('.gallery li img').live("mouseover",function(){{
$(this).removeClass("borderPatrol");
}} );
$('.gallery li img').live("mouseout",function(){{
$(this).addClass("borderPatrol");
}});
Jolly good show. The border patrol class used to add a border, but the behavior changed to just add opacity and I liked the name so I kept it.
.borderPatrol {
border:none;
opacity:.3;
cursor:pointer;
}
Ok so that works pretty good, except for thumbnail stickiness.
Thumbnail stickiness keeps the thumbnail of the selected image in the state that indicates the thumbnail is being displayed. In this case, opacity of 1.0, or clear.
But that doesn't happen correctly because as soon as the thumbnail is displayed and you mouse off of the dang thing, the borderPatrol class is added and opacity:.3 comes into play.
Heck, that is one stinky pickle.
To fix this I added this code into the MarkLogic piece at the beginning of this article:
{if ($i=$index) then 'opeth' else ()}
Opeth is the name of the class that I add to the img that was selected.
The opeth class:
.opeth {
opacity:1.0;
}
This didn't work because of the mouseout event which would through borderControl back on and the was css works, the latest class gets to determine the property, and that property is opacity and the value is .3 on borderPatrol. So that nullifies the earlier opeth class opacity of 1.0.
So I made this change:
.opeth{
opacity:1.0 !important;
}
And then life was good and lo, the page began working and I was amazed.