I have 4 puzzle pieces on left side and another 4 on right side. I need to drag the pieces from right side to the left side and make them join...The problem is that, my content is scaleable so if I drop a piece onto dropspot, when I resize the page it will remain there and wont be fitted with the left side puzzle piece. I have read something about offset,shall help in this case?
Here's what i have tried with divs as drop spot but i can't make pieces fit in drop spots when im over them and if I resize page, pieces aren't joined:
http://jsfiddle.net/zf66b/7/
Code:
$(function() {
for(var i = 0; i < piesedrag.length; i++)
{
$(piesedrag[i]).draggable
({
containment: "#decor",
cursor: "move",
revert: "invalid",
});
}
for(var i = 0; i < dropspot.length; i++)
{
$( dropspot[i] ).droppable({
/* tolerance: "intersect",*/
drop: function( event, ui )
{
tolerance: 'intersect'
}
});
}
});
To make it work correctly you have to change size and position from percents to fixed values, here are few fixes:
right {
left:400px;
width:200px
}
.left {
left: 0px;
width: 200px;
}
#dropspot3 {
/* margin-left: 34%; */
width: 150px;
}
Set for every dropspot fixed width and remove percent margin.
Related
I am using JQuery Draggable function and Touch Punch to produce a list of horizontal sliders that can be scrolled by clicking and dragging. It works great in touch and click devices. The problem I am facing is that if I try to scroll up or down in touch devices, it doesn't work.
I have looked through SO and found that removing "event.preventDefault" from TouchPunch allows vertical scrolling, the problem with this fix is, that it only works on some devices, and not all.
I am wondering if anyone has any other solutions, or alternative way of producing the same horizontal sliders that work on both touch and click events.
Here is Example code (JQuery Draggable):
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$("#list1 ul").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
$("#list2 ul").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
});
#list1 {
position: relative;
height: 16em;
width: 100%;
text-align: middle;
white-space: nowrap;
overflow-x: hidden;
overflow-y: hidden;
}
#list1 .floating-box {
margin: auto;
display: inline-block;
width: 15em;
height: 13.5em;
margin: 0.1em;
border: 0.2em solid black;
background-color: white;
}
#list2 {
position: relative;
height: 16em;
width: 100%;
text-align: middle;
white-space: nowrap;
overflow-x: hidden;
overflow-y: hidden;
}
#lis2 .floating-box {
margin: auto;
display: inline-block;
width: 15em;
height: 13.5em;
margin: 0.1em;
border: 0.2em solid black;
background-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="list1">
<ul>
<p>One</p>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
</ul>
</div>
<div id="list2">
<ul>
<p>Two</p>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
</ul>
</div>
If I touch list1 or list2 div and try to scroll up or down, it doesn't recognize the movement. Any help or direction would be appreciated.
EDIT
Based on the idea to determine theswipe direction based on the pageY propertie of touchemove.
I think it's a good idea to avoid the annoying double tap (see first answer below) on the long run.
There is still a compromise on it, but it is much more reasonable.
I tried many things... The best result I got is when I gave up on simulating a scroll on touchmove.
So here is the way to I now use each of the three touch events:
touchstart gets the initial variables like: window scrollTop and pageY.
touchmove determines the swipe direction and gets the last pageY.
touchend does the math as to were the page should scrollTo.
For the cuteness, I've put that result value in an .animate().
I was pleasantly surprised to see that it compensates quite really smoothly the fact that the page scrolls only on touchend.
I think that very few users will notice it ;).
Since "Touch-Punch" is working by default for horizontal swipes, the "compromise" only affects the vertical scroll.
Here is the code:
And a live link to try it on a touche-enabled device.
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$(".draggable").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
var startTouchX=0;
var startTouchY=0;
var actualPosX;
var actualPosY;
var eventCounter=0;
var directionDetermined=false;
var direction;
var thisTouchX;
var thisTouchY;
var lastTouchY;
$(document).on("touchstart", function(e) {
// Actual document position
actualPosX = $(document).scrollLeft();
actualPosY = $(document).scrollTop();
// StartTouches
startTouchX = parseInt(e.originalEvent.touches[0].pageX);
startTouchY = parseInt(e.originalEvent.touches[0].pageY);
});
$(document).on("touchmove", function(e) {
// Arbitrary considering ONLY the fourth event...
// Touchmove fires way too many times!
// We only need to determine the main direction ONCE.
// This prevents an "s" swipe from messing this code.
eventCounter++;
if(eventCounter==4 && !directionDetermined){
thisTouchX = parseInt(e.originalEvent.touches[0].pageX);
thisTouchY = parseInt(e.originalEvent.touches[0].pageY);
if ( (Math.abs(thisTouchX - startTouchX)) / Math.abs(thisTouchY - startTouchY) > 1){ //check swipe direction
// HORIZONTAL
$("#debug").html("HORIZONTAL");
directionDetermined=true;
// NO NEED here. This is re-enabled on touchend, if it has been disabled.
//$(".draggable").draggable('enable');
}
else{
// VERTICAL
$("#debug").html("VERTICAL");
directionDetermined=true;
direction="vertical";
$(".draggable").draggable('disable'); // Disable draggable.
}
}
// Getting all the Y touches...
// The "last" value will be used on touchend.
lastTouchY = parseInt(e.originalEvent.touches[0].pageY);
//$("#debug").html(lastTouchY);
});
$(document).on("touchend", function(e) {
if(direction=="vertical"){
//$("#debug").html(lastTouchY);
var thisMoveY = -parseInt(lastTouchY - startTouchY);
//$("#debug").html(thisMoveY);
var newPosY = (actualPosY + thisMoveY);
//$("#debug").html(actualPosX+ " " +newPosY);
//window.scrollTo(actualPosX, newPosY);
$("html,body").animate({ scrollTop: newPosY },400);
}
// Reset everything for a future swipe.
startTouchX=0;
startTouchY=0;
eventCounter=0;
directionDetermined=false;
direction="";
$("#debug").html("");
// Re-enable draggable.
$(".draggable").draggable('enable');
});
});
First answer, using a "double-tap" to switch direction.
First, the Touch Punch website states that it's basically a jQuery-UI hack to handle some cases actually unhandled by jQuery-UI...
And that it is possible to find cases where Touch Punch fails.
Your issue was reported to the Touch Punch developpers here.
As an answer to that (in my words here), they said that it isn't really bug or an issue...
But a usage "conflict" on two different "wished" actions that are using the same touch events.
Sometimes to scroll the page, and sometimes to drag an element.
As a solution hint, they posted this Fiddle.
It suggests to find a way to disable draggable when needed.
But in this solution, the scrollable section is within the draggable element.
Which is not your case.
And you use almost all the mobile screen space for your draggable elements, so there is not enougth space left to trigger a draggable("disable") around them.
So... I had this idea, which I hope will help.
What if you'd find an elegant way to inform your users that a "double-tap" changes the movement orientation.
Here, I suggest a quite simple "double arrow" showing the movement direction.
Maybe you'll find something better.
This sure is a little compromise user experience, to ask them to double tap...
But if your layout really needs it, maybe it's ok.
So here, I reproduced your initial issue.
And here is the fix that I suggest.
I only tryed it on a Samsung Galaxy S3, but should work on every touch device.
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$(".draggable").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
// Flag
var draggableEnabled=true;
// Find the doubletap position (to show a nice double arrow)
var tapPosition=[];
$(document).on("touchstart",function(e){
tapPosition[0] = parseInt(e.touches[0].pageX) - $(document).scrollLeft() - ($("#arrows img").width()/2);
tapPosition[1] = parseInt(e.touches[0].pageY) - $(document).scrollTop() - ($("#arrows img").width()/2);
});
Hammer(document).on("doubletap", function() {
//alert("Double tap");
draggableEnabled = !draggableEnabled; // Toggle
if(!draggableEnabled){
$(".draggable").draggable('disable'); // Disables draggable (and touch Punch)
$("#arrows img").css({
"transform":"rotate(90deg)", // Nice vertical double arrow
"top":tapPosition[1],
left:tapPosition[0]
}).fadeIn(600, function(){
$(this).fadeOut(600);
});
}else{
$(".draggable").draggable('enable'); // Enables draggable (and touch Punch)
$("#arrows img").css({
"transform":"rotate(0deg)", // Nice horizontal double arrow
"top":tapPosition[1],
left:tapPosition[0]
}).fadeIn(600, function(){
$(this).fadeOut(600);
});
}
});
});
Notice that it uses the Hammer.js (CDN) to detect the double tap.
And some extra CSS for the double arrow.
#arrows img{
width: 60vw;
height: 60vw;
position: fixed;
top:calc( 50vh - 60vw );
left:calc( 50vh - 60vw );
z-index:1000;
display:none;
}
This is the closest I have come to it, I wonder if someone could refine this code:
$(watchlist).on("touchstart", function(e) {
touchY = e.originalEvent.touches[0].pageY;
touchX = e.originalEvent.touches[0].pageX;
});
$(watchlist).on("touchmove", function(e) {
var fTouchY = e.originalEvent.touches[0].pageY;
var fTouchX = e.originalEvent.touches[0].pageX;
if ((Math.abs(fTouchX - touchX)) / Math.abs(fTouchY - touchY) > 1){ //check swipe direction
$("#watchlist ul").draggable( 'enable'); //if swipe is horizontal
}
else{
$("#watchlist ul").draggable( 'disable'); //if swipe is horizontal
}
});
The problem with this code is, that it deactivates the draggable function only after the touch move has been finished rather than during. If anyone could modify this code so that the draggable function is deactivated during as soon as the condition is met, during touchmove, rather than after, I would give them the bounty.
I want to calculate and select drop area in my drag&drop application.
What I want to make:
When i drag box to top or bottom of the droppable div, width must be 100%
When i drag box to near the other box, (if one box in a row) their widths must be 50% - 50%
If a drag box and change place which box is already in wrapper, they must be calculated like that again.
Here is my example code
$(".box").draggable({
snap: '#droppable',
snapMode: 'outer',
revert: "invalid",
cursor: "move",
helper: "clone"
//connectToSortable: "#droppable"
});
$("#wrapper").droppable({
drop: function(event, ui) {
var dropped = $(ui.draggable).clone();
var droppedOn = $(this);
$(dropped).detach().css({
top: 0,
left: 0
}).appendTo(droppedOn);
$(this).addClass("ui-state.highlight").find("p").html("");
}
});
Can you please tell me the way how can I do that?
Thanks
Take a look at this JQFAQ.com topic, this will help you to set the calculated width and we can drop the elements in specified area. There are few more sample FAQs too.
I am using jQuery droppable (in conjunction with jQuery draggable) to allow the user to add rows to an HTML table by dragging items from a list and dropping them on the table.
This works well, however at present the logic is that when the user drag-drops on a table row the new row gets added below the row they dropped on.
It would be better if the new row's add position was based on whether the user dropped in the upper or lower half of an existing row.
This is easy enough to calculate in the drop event, but I need to give UI feedback as the user drags (which I would do by means of two CSS classes droppable-above and droppable-below for example).
This doesn't seem to be possible, as the over event only fires once; when the user initially drags over the droppable element.
Is it possible to get the over event to fire for every mouse move while the user is over a droppable element?
If so, then I'd be able to do this:
$("tr.droppable").droppable({
over: function(event, ui) {
if (/* mouse is in top half of row */) {
$(this).addClass("droppable-above").removeClass("droppable-below");
}
else {
$(this).removeClass("droppable-above").addClass("droppable-below");
}
},
out: function(event, ui) {
$(this).removeClass("droppable-above").removeClass("droppable-below");
},
drop: function(event, ui) {
$(this).removeClass("droppable-above").removeClass("droppable-below");
if (/* mouse is in top half of row */) {
// Add new row above the dropped row
}
else {
// Add new row below the dropped row
}
}
});
The CSS styles would be something like...
droppable-above { border-top: solid 3px Blue; }
droppable-below { border-bottom: solid 3px Blue; }
As you said, over (like its counterpart out) is only raised once on the droppable. On the other hand, the drag event of the draggable is raised every time the mouse moves, and seems appropriate for the task. There are, however, two problems with this strategy:
drag is raised whether or not the draggable actually lies over a droppable,
even in that case, the droppable is not passed to the event handler.
One way to solve both problems is to associate the droppable and the draggable in the over handler, using jQuery's data() facility, and disassociate them in the out and drop handlers:
$("tr.droppable").droppable({
over: function(event, ui) {
if (/* mouse is in top half of row */) {
$(this).removeClass("droppable-below")
.addClass("droppable-above");
}
else {
$(this).removeClass("droppable-above")
.addClass("droppable-below");
}
ui.draggable.data("current-droppable", $(this)); // Associate.
},
out: function(event, ui) {
ui.draggable.removeData("current-droppable"); // Break association.
$(this).removeClass("droppable-above droppable-below");
},
drop: function(event, ui) {
ui.draggable.removeData("current-droppable"); // Break association.
$(this).removeClass("droppable-above droppable-below");
if (/* mouse is in top half of row */) {
// Add new row above the dropped row.
}
else {
// Add new row below the dropped row.
}
}
});
Now that the draggable knows the droppable it's lying over, we can update the element's appearance in a drag event handler:
$(".draggable").draggable({
drag: function(event, ui) {
var $droppable = $(this).data("current-droppable");
if ($droppable) {
if (/* mouse is in top half of row */) {
$droppable.removeClass("droppable-below")
.addClass("droppable-above");
} else {
$droppable.removeClass("droppable-above")
.addClass("droppable-below");
}
}
}
});
The code that follows is a simple test case that demonstrates this solution (it basically fills the commented gaps above and refactors common patterns into helper functions). The droppable setup is a little more intricate than in the previous example, mainly because the newly created table rows have to be made droppable like their siblings.
You can see the results in this fiddle.
HTML:
<div class="draggable">New item 1</div>
<div class="draggable">New item 2</div>
<div class="draggable">New item 3</div>
<div class="draggable">New item 4</div>
<div class="draggable">New item 5</div>
<p>Drag the items above into the table below.</p>
<table>
<tr class="droppable"><td>Item 1</td></tr>
<tr class="droppable"><td>Item 2</td></tr>
<tr class="droppable"><td>Item 3</td></tr>
<tr class="droppable"><td>Item 4</td></tr>
<tr class="droppable"><td>Item 5</td></tr>
</table>
CSS:
p {
line-height: 32px;
}
table {
width: 100%;
}
.draggable {
background-color: #d0ffff;
border: 1px solid black;
cursor: pointer;
padding: 6px;
}
.droppable {
background-color: #ffffd0;
border: 1px solid black;
}
.droppable td {
padding: 10px;
}
.droppable-above {
border-top: 3px solid blue;
}
.droppable-below {
border-bottom: 3px solid blue;
}
Javascript:
$(document).ready(function() {
$(".draggable").draggable({
helper: "clone",
drag: function(event, ui) {
var $droppable = $(this).data("current-droppable");
if ($droppable) {
updateHighlight(ui, $droppable);
}
}
});
initDroppable($(".droppable"));
function initDroppable($elements)
{
$elements.droppable({
over: function(event, ui) {
var $this = $(this);
updateHighlight(ui, $this);
ui.draggable.data("current-droppable", $this);
},
out: function(event, ui) {
cleanupHighlight(ui, $(this));
},
drop: function(event, ui) {
var $this = $(this);
cleanupHighlight(ui, $this);
var $new = $this.clone().children("td:first")
.html(ui.draggable.html()).end();
if (isInUpperHalf(ui, $this)) {
$new.insertBefore(this);
} else {
$new.insertAfter(this);
}
initDroppable($new);
}
});
}
function isInUpperHalf(ui, $droppable)
{
var $draggable = ui.draggable || ui.helper;
return (ui.offset.top + $draggable.outerHeight() / 2
<= $droppable.offset().top + $droppable.outerHeight() / 2);
}
function updateHighlight(ui, $droppable)
{
if (isInUpperHalf(ui, $droppable)) {
$droppable.removeClass("droppable-below")
.addClass("droppable-above");
} else {
$droppable.removeClass("droppable-above")
.addClass("droppable-below");
}
}
function cleanupHighlight(ui, $droppable)
{
ui.draggable.removeData("current-droppable");
$droppable.removeClass("droppable-above droppable-below");
}
});
I am hitting the same issue and have been thinking about two solutions which I will share in case they give direction to others who find this relatively rare need.
Two div solution: Add two divs into each cell of the row, positioned to be stacked and each 50% high and full width with z-index set to -1 to protect from UI interference. Now make these droppables and use their 'over' and 'out' events to toggle the classes of the parent cell or row.
Abandon droppable and roll your own collision detection: Write your own collision detection to mimic the droppable effect. This which would give more freedom but would lead to some serious coding and so is not for the casual requirement. Would also be susceptible to performance issues. That said, there should be some obvious case-based shortcuts that would work in your favour.
I would be interested to hear of any other approaches to low-code solution.
I just hit this problem. Not much is required if you just implement hit testing in the 'drag' event. Here I've just tagged all my drop targets with .myDropTarget, so it's easy to find them all, loop through them and check whether the mouse is over them.
Something like this:
thingToBeDragged.draggable({
drag: function(evt) {
$('.myDropTarget').removeClass('topHalf bottomHalf').each(function() {
var target = $(this), o = target.offset(),
x = evt.pageX - o.left, y = evt.pageY - o.top;
if (x > 0 && y > 0 && x < target.width() && y < target.height()) {
// mouse is over this drop target, but now you can get more
// particular: is it in the top half, bottom half, etc.
if (y > target.height() * 0.5) {
target.addClass('topHalf');
} else {
target.addClass('bottomHalf');
}
}
});
},
stop: function() {
var droppedOn = $('.topHalf, .bottomHalf');
}
});
Another method is to add a class or other elector to the hint element. Then in the draggable definition, on the drag handler, update the hint position:
$('#dropArea').droppable({
over: function(event, ui)
// Create a clone 50 pixels above and 100 to the left of drop area
$('#someHint').clone()
.css({
position: 'absolute',
top: ui.offset.top+50,
left: ui.offset.left-50
})
.addClass("clone") // Mark this as a clone, for hiding on drop or out
.addClass("dragHelper") // Mark this as a hint, for moving with drag
.appendTo(document.body)
},
out: function(event, ui) {
$('.clone').remove(); // Remove any hints showing
},
drop: function(event, ui) {
$('.clone').remove(); // Remove any hints showing
}
});
$("#mydiv").draggable({
drag: function(event, ui) {
$('.dragHelper').css('left',ui.offset.left);
$('.dragHelper').css('top',ui.offset.top);
}
});
This is a rather crude (and codeless) solution, but you could try using the hoverClass option with your Droppable and creating a new class called "hovering" to set Droppable behavior that only happens when the Draggable is hovering over the Droppable. This "hovering" class could then (this is the crude bit) run some sort of endless loop or some other sort of checker; I haven't used these classes before, so I can't think of any more specifics past this point. =/
Edit: Even cruder, you could alternate disabling and enabling the Droppable using the "hovering" class; I would definitely do this synchronously though, and with a generous time delineation as well. The alternating disable and enable calls should trigger one of the events, though which one you'll have to experiment with to find out.
JQuery UI's .resizable function does not support position: fixed; elements. The moment you try to resize them it switches their position attribute to absolute. Any recommended fixes?
I have some chat windows that pop up and are draggable around the document. They are position fixed so that they don't scroll with the page behind them. They all work perfectly until you try to resize a window, that's when it transitions to position: absolute; and then gets left behind when the page scrolls.
I tried handling the resize stop event and changing the position to fixed:
stop: function (event, ui)
{
$(chatWindow).css('position', 'fixed');
}
This doesn't work because the positioning (top: and left:) are not correct for the fixed element and when you stop resizing the element switches to fixed positioning and jumps to weird places on the page. Sometimes jumps out of the page boundries and is lost forever.
Any suggestions?
To get over this problem I wrapped the .resizable() block with the .draggable() block:
<div id="draggable-dealie">
<div id="resizable-dealie">
</div>
</div>
the corresponding js:
$("#draggable-dealie").draggable();
$("#resizable-dealie").resizable();
and ensure you have the property position:fixed !important; set in the #draggable-dealie CSS:
#draggable-dealie {
position:fixed !important;
width:auto;
height:auto;
}
I have a demonstration at: http://jsfiddle.net/smokinjoe/FfRRW/8/
If, like me, you have a fixed div at the bottom of the page, then you can just add !important to these css rules to make it stick at the bottom :
.fixed {
position: fixed !important;
top: auto !important;
bottom: 0 !important;
left: 0;
right: 0;
}
And just make it resizable by its north border :
$('.fixed').resizable({
handles: "n"
});
Simply force position:fixed on the element when resizing starts and when resizing stops.
$(".e").draggable().resizable({
start: function(event, ui) {
$(".e").css("position", "fixed");
},
stop: function(event, ui) {
$(".e").css("position", "fixed");
}
});
JSFiddle: http://jsfiddle.net/5feKU/
No beauty but how about saving the position (top and left) in separate vars on the start of the resize (I think the method is called "start")?
UPDATE (Thank you for the comment... The event fires too late):
As JqueryUI generates a second object "ui" on making a object resizable it gives that ui-object a field: ui.originalPosition... That should be the position of the fixed element before the resizing...
Here's the solution I came up with, it's a little more code than I'd like, but it fixes the problem:
$("#test").resizable({stop:function(e, ui) {
var pane = $(e.target);
var left = pane.attr("startLeft");
var top = pane.attr("startTop");
pane.css("position", "fixed");
pane.css("top", top);
pane.css("left", left);
}});
$("#test").draggable({create: function(e, ui) {
var pane = $(e.target);
var pos = pane.position();
pane.attr("startLeft", pos.left + "px");
pane.attr("startTop", pos.top + "px");
}, stop: function(e, ui) {
var pane = $(e.target);
pane.attr("startLeft", ui.position.left + "px");
pane.attr("startTop", ui.position.top + "px");
}});
This stores the top and left position in the html element (needs xhtml doctype to be valid) and uses that information to set the position at the end of the resizing event.
This is a dirty solution but works for me.
this.resizable({
start:function (event, ui){
x =ui.originalPosition.left+ $(ui.originalElement).parent().scrollLeft()
y = ui.originalPosition.top+ $(ui.originalElement).parent().scrollTop()
},
resize:function (event, ui){
$(ui.originalElement).css('left' , x);
$(ui.originalElement).css('top' , y);
}
I had that problem today, and I absolutely hate "un-aesthetic" workarounds... So I decided to experiment a little to see if there wasn't a "better" solution ...and at some point I had a hunch:
html:
<div class="fixed"></div>
javascript (jquery):
$('.fixed').resizable();
$('.fixed').draggable();
css:
.fixed{
position: fixed !important;
}
Jquery just got outplayed by CSS, damn!
I implemented the Coda Slider tutorial successfully that is located here: http://jqueryfordesigners.com/coda-slider-effect/
The slider works great but I am getting a javascript error that I am not sure how to fix. The error says:
'0.offsetWidth' is null or not an object
coda-slider.js, line 19 character 3
Not sure how to fix it. Anyone have any ideas? Here is my js and css (don't think I need to upload the HTML but let me know if that helps).
JS (coda-slider.js)
// when the DOM is ready...
$(document).ready(function () {
var $panels = $('#slider .scrollContainer > div');
var $container = $('#slider .scrollContainer');
// if false, we'll float all the panels left and fix the width
// of the container
var horizontal = true;
// float the panels left if we're going horizontal
if (horizontal) {
$panels.css({
'float' : 'left',
'position' : 'relative' // IE fix to ensure overflow is hidden
});
// calculate a new width for the container (so it holds all panels)
$container.css('width', $panels[0].offsetWidth * $panels.length); <------line 19
}
// collect the scroll object, at the same time apply the hidden overflow
// to remove the default scrollbars that will appear
var $scroll = $('#slider .scroll').css('overflow', 'hidden');
// apply our left + right buttons
$scroll
.before('<img class="scrollButtons left" src="/images/layout/navigation/scroll_left.png" />')
.after('<img class="scrollButtons right" src="/images/layout/navigation/scroll_right.png" />');
// handle nav selection
function selectNav() {
$(this)
.parents('ul:first')
.find('a')
.removeClass('selected')
.end()
.end()
.addClass('selected');
}
$('#slider .navigation').find('a').click(selectNav);
// go find the navigation link that has this target and select the nav
function trigger(data) {
var el = $('#slider .navigation').find('a[href$="' + data.id + '"]').get(0);
selectNav.call(el);
}
if (window.location.hash) {
trigger({ id : window.location.hash.substr(1) });
} else {
$('ul.navigation a:first').click();
}
// offset is used to move to *exactly* the right place, since I'm using
// padding on my example, I need to subtract the amount of padding to
// the offset. Try removing this to get a good idea of the effect
var offset = parseInt((horizontal ?
$container.css('paddingTop') :
$container.css('paddingLeft'))
|| 0) * -1;
var scrollOptions = {
target: $scroll, // the element that has the overflow
// can be a selector which will be relative to the target
items: $panels,
navigation: '.navigation a',
// selectors are NOT relative to document, i.e. make sure they're unique
prev: 'img.left',
next: 'img.right',
// allow the scroll effect to run both directions
axis: 'xy',
onAfter: trigger, // our final callback
offset: offset,
// duration of the sliding effect
duration: 500,
// easing - can be used with the easing plugin:
// http://gsgd.co.uk/sandbox/jquery/easing/
easing: 'swing'
};
// apply serialScroll to the slider - we chose this plugin because it
// supports// the indexed next and previous scroll along with hooking
// in to our navigation.
$('#slider').serialScroll(scrollOptions);
// now apply localScroll to hook any other arbitrary links to trigger
// the effect
$.localScroll(scrollOptions);
// finally, if the URL has a hash, move the slider in to position,
// setting the duration to 1 because I don't want it to scroll in the
// very first page load. We don't always need this, but it ensures
// the positioning is absolutely spot on when the pages loads.
scrollOptions.duration = 1;
$.localScroll.hash(scrollOptions);
});
CSS
#slider {
margin-left: 35px;
position: relative;
width: 875px;
}
.scroll {
position: relative;
width: 875px;
height: 268px;
overflow: auto; /* fix for IE to respect overflow */
background: #FFFFFF scroll 0;
}
.scrollContainer div.panel {
position: relative;
height: 210px;
width: 875px; /* change to 560px if not using JS to remove rh.scroll */
}
.scrollButtons {
position: absolute;
top: 115px;
cursor: pointer;
}
.scrollButtons.left {
left: -20px;
}
.scrollButtons.right {
right: -20px;
}
Figured it out. Stupid error on my part. I was including the coda-slider.js in the head that was delivered with every page and therefore every page that did not have the slider was displaying the error. Just took it out to include only on the page where the slider was displayed and fixed.