I'm using bootstrap for website. I include Ajax, css and PHP to show Auto Suggestions for mp3 search. Everything is working fine but an issue happened. I tried with different way but the issue is still there.
The Issue
When type keyword it show suggestion. (OK)
When you click on keyword from suggestion it works. (OK)
But when we erase keyword and click on anywhere at page then page content reload and shown as u can see in picture.
Url of website is http://www.4songs.pk
Code in header
<script src="http://www.4songs.pk/js/jquery-1.10.2.js"></script>
<script>
$(function(){
$(document).on( 'scroll', function(){
if ($(window).scrollTop() > 100) {
$('.scroll-top-wrapper').addClass('show');
} else {
$('.scroll-top-wrapper').removeClass('show');
}
});
$('.scroll-top-wrapper').on('click', scrollToTop);
});
function scrollToTop() {
verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
element = $('body');
offset = element.offset();
offsetTop = offset.top;
$('html, body').animate({scrollTop: offsetTop}, 500, 'linear');
}
</script>
<script type="text/javascript">
var myAjax = ajax();
function ajax() {
var ajax = null;
if (window.XMLHttpRequest) {
try {
ajax = new XMLHttpRequest();
}
catch(e) {}
}
else if (window.ActiveXObject) {
try {
ajax = new ActiveXObject("Msxm12.XMLHTTP");
}
catch (e){
try{
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
return ajax;
}
function request(str) {
//Don't forget to modify the path according to your theme
myAjax.open("POST", "/suggestions", true);
myAjax.onreadystatechange = result;
myAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myAjax.setRequestHeader("Content-length", str .length);
myAjax.setRequestHeader("Connection", "close");
myAjax.send("search="+str);
}
function result() {
if (myAjax.readyState == 4) {
var liste = myAjax.responseText;
var cible = document.getElementById('tag_update').innerHTML = liste;
document.getElementById('tag_update').style.display = "block";
}
}
function selected(choice){
var cible = document.getElementById('s');
cible.value = choice;
document.getElementById('tag_update').style.display = "none";
}
</script>
The 2nd issue
When auto suggestions load it also include some empty tags as you can see in picture
I take this picture as doing Inspect Elements
PHP Code are clean
<?php
include('config.php');
if(isset($_POST['search']))
{
$q = $_POST['search'];
$sql_res=mysql_query("SELECT * FROM dump_songs WHERE (song_name LIKE '%$q%') OR (CONCAT(song_name) LIKE '%$q%') LIMIT 10");
while($row=mysql_fetch_array($sql_res))
{?>
<li><a href="javascript:void(0);" onclick="selected(this.innerHTML);"><?=$row['song_name'];?></li>
<?php
}
}?>
In the function request(str) put an if statement to check if str length is greater than zero.
function request(str) {
if(str.length > 0)
{
// Your existing code
}
else
{
document.getElementById('tag_update').innerHTML = '';
}
}
In short words the problem you are describing is happping because the str parameter in the data that you send to /suggestions is empty. The server returns 304 error which causes a redirect to the root page. Your js script places the returned html into the suggestion container. And thats why you are seeing this strange view.
-UPDATE 1-
Added the following code after user request in comments
else
{
document.getElementById('tag_update').innerHTML = '';
}
-UPDATE 2- (16/07/2014)
In order to handle the second issue (after the user updated his question)
Υou forgot to close the a tag in this line of code
<li><a href="javascript:void(0);" onclick="selected(this.innerHTML);"><?=$row['song_name'];?></li>
I am running the javascript function shoh() below on page load to hide div's. This works fine on html hard coded divs but appears not to be working on divs that are created via php. Am I correct in assuming that the javascript runs first before the php creates the divs and that is why they aren't being hidden? If so, is there any other way to hide these divs after they are created? They need to be shown by default in case javascript is disabled?
code which runs with onload:
<script type="text/javascript">
function closeAllDivs() {
shoh('g1');
shoh('g2');
shoh('g3');
shoh('g4');
}
</script>
<BODY onLoad="closeAllDivs();">
javascript to hide divs:
function shoh(id) {
if (document.getElementById) { // DOM3 = IE5, NS6
if (document.getElementById(id).style.display == "none"){
document.getElementById(id).style.display = 'block';
filter(("img"+id),'imgin');
} else {
filter(("img"+id),'imgout');
document.getElementById(id).style.display = 'none';
}
} else {
if (document.layers) {
if (document.id.display == "none"){
document.id.display = 'block';
filter(("img"+id),'imgin');
} else {
filter(("img"+id),'imgout');
document.id.display = 'none';
}
} else {
if (document.all.id.style.visibility == "none"){
document.all.id.style.display = 'block';
} else {
filter(("img"+id),'imgout');
document.all.id.style.display = 'none';
}
}
}
}
php code which creates divs:
for ($i=0; $i < count($this->items); $i++){
<div style="display: block;" id="g<? echo $i ?>">
... code that displays items
</div>
}
It shouldn't really matter so much whether the php made the divs or whether they're hardcoded - by the time the HTML hits the browser, it's already the same thing. The server processes the PHP - by the time it leaves the server and heads to the browser, there is no PHP anymore.
I'd recommend using window.onload instead of a <body onload="">
window.onload = function() {
closeAllDivs();
};
Thanks to Wolfman Joe for letting me know the problem was likely not with the order of things. This told me the shoh() function was likely failing and therefore interrupting execution... so the code to close the divs was never executed. The solution was to build a check into the shoh() function to first make sure the div existed before attempting to change its property. As it turns out, not all divs $i were being created.
function shoh(id) {
if (document.getElementById) { // DOM3 = IE5, NS6
if (document.getElementById(id)){
if (document.getElementById(id).style.display == "none"){
document.getElementById(id).style.display = 'block';
filter(("img"+id),'imgin');
} else {
filter(("img"+id),'imgout');
document.getElementById(id).style.display = 'none';
}
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am new to Jquery and ajax.
I need to upload multiple images to server folder and store the details in a db table. After uploading, I need to display all images which set as 'active' in database.( I have looked into many codes which are not working for me)
After that I need to drag some images to an area and also need to store dragged images information in an another table.
Anyone have any idea?Please help me?
Thanks
Nowadays Dropzone.js is the best js plugin to upload multiple images using drag and drop.
official site. https://www.dropzonejs.com/
A complete example of the demo is here.
https://learncodeweb.com/web-development/drag-drop-images-with-bootstrap-4-and-reorder-using-php-jquery-and-ajax/
For uploading multiple images you can use this script. By using single browse button you can upload multiple images
$(function(){
var btnUpload=$('#photo_0'); // id of browse button
new AjaxUpload(btnUpload, {
action: 'url_to_upload_function',
name: 'uploadfile',
onSubmit: function(file, ext){
if (! (ext && /^(jpg|png|jpeg|gif|JPG|PNG|GIF|JPEG)$/.test(ext))){
$("#photo_div1").html('Only JPG,PNG,GIF files are allowed'); //
return false;
}
var path="<?=base_url()?>images/wait.gif"; //losding image
$("#photo_div1").html("<img src="+path+" width='32' height='32' style='border:#b6b6b6 solid 1px;'>");
},
onComplete: function(file, response){
response = jQuery.trim(response);
if(response=="error")
{
$("#photo_error").css("display","block");
$("#upload_photo1").html("");
}
else if(response!="error")
{
$("#photo_error").css("display","none");
$("#photo_div1").html("");
var path="uploads/"+response; //echo the image name from the upload function
var img="<table><tr><td ><img src="+path+" style='border:#b6b6b6 solid 1px;'></td></tr></table>";
$("#img_div1").html(img);// display the image in a div it will display only one image. If you want to add more you can code according to that by using append or something like that
$("#upload_photo1").val(response);
$("#photo_hid1").val(response);
} else
{
alert("error");
}
}
});
});
YOU HAVE TO INCLUDE THIS FILE ALSO ajaxupload.js
/**
* Ajax upload
* Project page - http://valums.com/ajax-upload/
* Copyright (c) 2008 Andris Valums, http://valums.com
* Licensed under the MIT license (http://valums.com/mit-license/)
* Version 3.5 (23.06.2009)
*/
/**
* Changes from the previous version:
* 1. Added better JSON handling that allows to use 'application/javascript' as a response
* 2. Added demo for usage with jQuery UI dialog
* 3. Fixed IE "mixed content" issue when used with secure connections
*
* For the full changelog please visit:
* http://valums.com/ajax-upload-changelog/
*/
(function(){
var d = document, w = window;
/**
* Get element by id
*/
function get(element){
if (typeof element == "string")
element = d.getElementById(element);
return element;
}
/**
* Attaches event to a dom element
*/
function addEvent(el, type, fn){
if (w.addEventListener){
el.addEventListener(type, fn, false);
} else if (w.attachEvent){
var f = function(){
fn.call(el, w.event);
};
el.attachEvent('on' + type, f)
}
}
/**
* Creates and returns element from html chunk
*/
var toElement = function(){
var div = d.createElement('div');
return function(html){
div.innerHTML = html;
var el = div.childNodes[0];
div.removeChild(el);
return el;
}
}();
function hasClass(ele,cls){
return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
// getOffset function copied from jQuery lib (http://jquery.com/)
if (document.documentElement["getBoundingClientRect"]){
// Get Offset using getBoundingClientRect
// http://ejohn.org/blog/getboundingclientrect-is-awesome/
var getOffset = function(el){
var box = el.getBoundingClientRect(),
doc = el.ownerDocument,
body = doc.body,
docElem = doc.documentElement,
// for ie
clientTop = docElem.clientTop || body.clientTop || 0,
clientLeft = docElem.clientLeft || body.clientLeft || 0,
// In Internet Explorer 7 getBoundingClientRect property is treated as physical,
// while others are logical. Make all logical, like in IE8.
zoom = 1;
if (body.getBoundingClientRect) {
var bound = body.getBoundingClientRect();
zoom = (bound.right - bound.left)/body.clientWidth;
}
if (zoom > 1){
clientTop = 0;
clientLeft = 0;
}
var top = box.top/zoom + (window.pageYOffset || docElem && docElem.scrollTop/zoom || body.scrollTop/zoom) - clientTop,
left = box.left/zoom + (window.pageXOffset|| docElem && docElem.scrollLeft/zoom || body.scrollLeft/zoom) - clientLeft;
return {
top: top,
left: left
};
}
} else {
// Get offset adding all offsets
var getOffset = function(el){
if (w.jQuery){
return jQuery(el).offset();
}
var top = 0, left = 0;
do {
top += el.offsetTop || 0;
left += el.offsetLeft || 0;
}
while (el = el.offsetParent);
return {
left: left,
top: top
};
}
}
function getBox(el){
var left, right, top, bottom;
var offset = getOffset(el);
left = offset.left;
top = offset.top;
right = left + el.offsetWidth;
bottom = top + el.offsetHeight;
return {
left: left,
right: right,
top: top,
bottom: bottom
};
}
/**
* Crossbrowser mouse coordinates
*/
function getMouseCoords(e){
// pageX/Y is not supported in IE
// http://www.quirksmode.org/dom/w3c_cssom.html
if (!e.pageX && e.clientX){
// In Internet Explorer 7 some properties (mouse coordinates) are treated as physical,
// while others are logical (offset).
var zoom = 1;
var body = document.body;
if (body.getBoundingClientRect) {
var bound = body.getBoundingClientRect();
zoom = (bound.right - bound.left)/body.clientWidth;
}
return {
x: e.clientX / zoom + d.body.scrollLeft + d.documentElement.scrollLeft,
y: e.clientY / zoom + d.body.scrollTop + d.documentElement.scrollTop
};
}
return {
x: e.pageX,
y: e.pageY
};
}
/**
* Function generates unique id
*/
var getUID = function(){
var id = 0;
return function(){
return 'ValumsAjaxUpload' + id++;
}
}();
function fileFromPath(file){
return file.replace(/.*(\/|\\)/, "");
}
function getExt(file){
return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
}
// Please use AjaxUpload , Ajax_upload will be removed in the next version
Ajax_upload = AjaxUpload = function(button, options){
if (button.jquery){
// jquery object was passed
button = button[0];
} else if (typeof button == "string" && /^#.*/.test(button)){
button = button.slice(1);
}
button = get(button);
this._input = null;
this._button = button;
this._disabled = false;
this._submitting = false;
// Variable changes to true if the button was clicked
// 3 seconds ago (requred to fix Safari on Mac error)
this._justClicked = false;
this._parentDialog = d.body;
if (window.jQuery && jQuery.ui && jQuery.ui.dialog){
var parentDialog = jQuery(this._button).parents('.ui-dialog');
if (parentDialog.length){
this._parentDialog = parentDialog[0];
}
}
this._settings = {
// Location of the server-side upload script
action: 'upload.php',
// File upload name
name: 'userfile',
// Additional data to send
data: {},
// Submit file as soon as it's selected
autoSubmit: true,
// The type of data that you're expecting back from the server.
// Html and xml are detected automatically.
// Only useful when you are using json data as a response.
// Set to "json" in that case.
responseType: false,
// When user selects a file, useful with autoSubmit disabled
onChange: function(file, extension){},
// Callback to fire before file is uploaded
// You can return false to cancel upload
onSubmit: function(file, extension){},
// Fired when file upload is completed
// WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
onComplete: function(file, response) {}
};
// Merge the users options with our defaults
for (var i in options) {
this._settings[i] = options[i];
}
this._createInput();
this._rerouteClicks();
}
// assigning methods to our class
AjaxUpload.prototype = {
setData : function(data){
this._settings.data = data;
},
disable : function(){
this._disabled = true;
},
enable : function(){
this._disabled = false;
},
// removes ajaxupload
destroy : function(){
if(this._input){
if(this._input.parentNode){
this._input.parentNode.removeChild(this._input);
}
this._input = null;
}
},
/**
* Creates invisible file input above the button
*/
_createInput : function(){
var self = this;
var input = d.createElement("input");
input.setAttribute('type', 'file');
input.setAttribute('name', this._settings.name);
var styles = {
'position' : 'absolute'
,'margin': '-5px 0 0 -175px'
,'padding': 0
,'width': '220px'
,'height': '30px'
,'fontSize': '14px'
,'opacity': 0
,'cursor': 'pointer'
,'display' : 'none'
,'zIndex' : 2147483583 //Max zIndex supported by Opera 9.0-9.2x
// Strange, I expected 2147483647
};
for (var i in styles){
input.style[i] = styles[i];
}
// Make sure that element opacity exists
// (IE uses filter instead)
if ( ! (input.style.opacity === "0")){
input.style.filter = "alpha(opacity=0)";
}
this._parentDialog.appendChild(input);
addEvent(input, 'change', function(){
// get filename from input
var file = fileFromPath(this.value);
if(self._settings.onChange.call(self, file, getExt(file)) == false ){
return;
}
// Submit form when value is changed
if (self._settings.autoSubmit){
self.submit();
}
});
// Fixing problem with Safari
// The problem is that if you leave input before the file select dialog opens
// it does not upload the file.
// As dialog opens slowly (it is a sheet dialog which takes some time to open)
// there is some time while you can leave the button.
// So we should not change display to none immediately
addEvent(input, 'click', function(){
self.justClicked = true;
setTimeout(function(){
// we will wait 3 seconds for dialog to open
self.justClicked = false;
}, 3000);
});
this._input = input;
},
_rerouteClicks : function (){
var self = this;
// IE displays 'access denied' error when using this method
// other browsers just ignore click()
// addEvent(this._button, 'click', function(e){
// self._input.click();
// });
var box, dialogOffset = {top:0, left:0}, over = false;
addEvent(self._button, 'mouseover', function(e){
if (!self._input || over) return;
over = true;
box = getBox(self._button);
if (self._parentDialog != d.body){
dialogOffset = getOffset(self._parentDialog);
}
});
// we can't use mouseout on the button,
// because invisible input is over it
addEvent(document, 'mousemove', function(e){
var input = self._input;
if (!input || !over) return;
if (self._disabled){
removeClass(self._button, 'hover');
input.style.display = 'none';
return;
}
var c = getMouseCoords(e);
if ((c.x >= box.left) && (c.x <= box.right) &&
(c.y >= box.top) && (c.y <= box.bottom)){
input.style.top = c.y - dialogOffset.top + 'px';
input.style.left = c.x - dialogOffset.left + 'px';
input.style.display = 'block';
addClass(self._button, 'hover');
} else {
// mouse left the button
over = false;
if (!self.justClicked){
input.style.display = 'none';
}
removeClass(self._button, 'hover');
}
});
},
/**
* Creates iframe with unique name
*/
_createIframe : function(){
// unique name
// We cannot use getTime, because it sometimes return
// same value in safari :(
var id = getUID();
// Remove ie6 "This page contains both secure and nonsecure items" prompt
// http://tinyurl.com/77w9wh
var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
iframe.id = id;
iframe.style.display = 'none';
d.body.appendChild(iframe);
return iframe;
},
/**
* Upload file without refreshing the page
*/
submit : function(){
var self = this, settings = this._settings;
if (this._input.value === ''){
// there is no file
return;
}
// get filename from input
var file = fileFromPath(this._input.value);
// execute user event
if (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {
// Create new iframe for this submission
var iframe = this._createIframe();
// Do not submit if user function returns false
var form = this._createForm(iframe);
form.appendChild(this._input);
form.submit();
d.body.removeChild(form);
form = null;
this._input = null;
// create new input
this._createInput();
var toDeleteFlag = false;
addEvent(iframe, 'load', function(e){
if (// For Safari
iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||
// For FF, IE
iframe.src == "javascript:'<html></html>';"){
// First time around, do not delete.
if( toDeleteFlag ){
// Fix busy state in FF3
setTimeout( function() {
d.body.removeChild(iframe);
}, 0);
}
return;
}
var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;
// fixing Opera 9.26
if (doc.readyState && doc.readyState != 'complete'){
// Opera fires load event multiple times
// Even when the DOM is not ready yet
// this fix should not affect other browsers
return;
}
// fixing Opera 9.64
if (doc.body && doc.body.innerHTML == "false"){
// In Opera 9.64 event was fired second time
// when body.innerHTML changed from false
// to server response approx. after 1 sec
return;
}
var response;
if (doc.XMLDocument){
// response is a xml document IE property
response = doc.XMLDocument;
} else if (doc.body){
// response is html document or plain text
response = doc.body.innerHTML;
if (settings.responseType && settings.responseType.toLowerCase() == 'json'){
// If the document was sent as 'application/javascript' or
// 'text/javascript', then the browser wraps the text in a <pre>
// tag and performs html encoding on the contents. In this case,
// we need to pull the original text content from the text node's
// nodeValue property to retrieve the unmangled content.
// Note that IE6 only understands text/html
if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE'){
response = doc.body.firstChild.firstChild.nodeValue;
}
if (response) {
response = window["eval"]("(" + response + ")");
} else {
response = {};
}
}
} else {
// response is a xml document
var response = doc;
}
settings.onComplete.call(self, file, response);
// Reload blank page, so that reloading main page
// does not re-submit the post. Also, remember to
// delete the frame
toDeleteFlag = true;
// Fix IE mixed content issue
iframe.src = "javascript:'<html></html>';";
});
} else {
// clear input to allow user to select same file
// Doesn't work in IE6
// this._input.value = '';
d.body.removeChild(this._input);
this._input = null;
// create new input
this._createInput();
}
},
/**
* Creates form, that will be submitted to iframe
*/
_createForm : function(iframe){
var settings = this._settings;
// method, enctype must be specified here
// because changing this attr on the fly is not allowed in IE 6/7
var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
form.style.display = 'none';
form.action = settings.action;
form.target = iframe.name;
d.body.appendChild(form);
// Create hidden input element for each data key
for (var prop in settings.data){
var el = d.createElement("input");
el.type = 'hidden';
el.name = prop;
el.value = settings.data[prop];
form.appendChild(el);
}
return form;
}
};
})();
and for drag and drop you need to write another function for that you can refer this site or this
http://www.plupload.com/example_queuewidget.php
Here you can find a nice plugin that will help you to upload multiple images.I have used this and works well for me.
I'm wanting to make my own small webpage, I've got a domain Saoo.eu
As you see there is a small play button in the corner witch plays a playlist. Is there anyway to have that playbutton on each page I'd add in the future without resetting every time the page changes?
Am I forced to use iFrames for that?
This is my player code
<button id="audioControl" style="width:30px;height:25px;"></button>
<audio id="aud" src="" autoplay autobuffer />
Script:
$(document).ready(function() {
$('#audioControl').html('II');
if(Modernizr.audio && Modernizr.audio.mp3) {
audio.setAttribute("src",'http://daokun.webs.com/play0.mp3');
} else if(Modernizr.audio && Modernizr.audio.wav) {
audio.setAttribute("src", 'http://daokun.webs.com/play0.ogg');
}
});
var audio = document.getElementById('aud'),
count = 0;
$('#audioControl').toggle(
function () {
audio.pause();
$('#audioControl').html('>');
},
function () {
audio.play();
$('#audioControl').html('II');
}
);
audio.addEventListener("ended", function() {
count++;
if(count == 4){count = 0;}
if(Modernizr.audio && Modernizr.audio.mp3) {
audio.setAttribute("src",'http://daokun.webs.com/play'+count+'.mp3');
} else if(Modernizr.audio && Modernizr.audio.wav) {
audio.setAttribute("src", 'http://daokun.webs.com/play'+count+'.ogg');
}
audio.load();
});
I have just come a little bit unstuck, I have a list which I populate with PHP, and a javascript file which creates the scrolling effect on the list so I can scroll up and down.
But I need three of these list boxes on the same page, and when I go to put another 2 of the lists in, they are not generated only the first is. I need to be able to have all three on the page. Any help with this would be fantastic!
Kind regards,
Alistair
<div id="mContainer">
<div id="upArrow"></div>
<div id="nContainer">
<ul id="listContainer">
<?php
connect();
$sql="SELECT drivers_id, firstname,image FROM drivers";
$result=mysql_query($sql);
while ($row=mysql_fetch_array($result)){
echo "<li><a id='".$row['drivers_id']."' onclick='return showPic(this)' onfocus='this.hideFocus=true;' href='".$row['image']."'>".$row['firstname']."</a></li>";
}
?>
</ul>
</div>
<div id="downArrow">
</div>
</div>
**JAVASRIPT FILE BELOW**
window.onload=init;
var d=document;
var lContainer; // object reference for the UL
var currentTop=0; // the current Y position of the UL
var zInterval = null; // animation thread interval
var direction; // direction we're scrolling the UL. 0==up, 1==down
var startTop=0; // the starting top of the UL
var scrollRate=8; // initial rate of scrolling
var scrollTick=0; // keeps track of long we've scrolled so we can slow it down accordingly
var listHeight=60; // the current height of the UL
var MAX_SCROLL_TICK=4; // the maximum value of scrollTick before it's reset
var MIN_LIST_HEIGHT=145; // contracted height of the list
var REBOUND = 0; // the value of scrollRate when we stop scrolling
function init() {
if(!d.getElementById)return; // bail out if this is an older browser
up=d.getElementById("upArrow");
down=d.getElementById("downArrow");
// apply onclick behaviors to the up arrow, down arrow and expansion control elements
down.onmousedown=function(){
scrollObjects(0);
}
up.onmousedown=function(){
scrollObjects(1);
}
lContainer = d.getElementById("listContainer");
d.getElementById("nContainer").style.height=MIN_LIST_HEIGHT+"px";
}
function scrollObjects(dir) {
if(zInterval)return; // already scrolling.
if((!dir && currentTop<=-300) || (dir && currentTop==0))
return; // dont scroll up if we're at the top or down if at the bottom of the list
direction=dir;
zInterval=setInterval("animate()",20);
}
function animate() {
// increment or decrement currentTop based on direction
if(!direction) {
currentTop-=scrollRate;
} else {
currentTop+=scrollRate;
}
scrollTick++;
if(scrollTick>=MAX_SCROLL_TICK) {
scrollRate--; // slow the scroll rate down for a little style
scrollTick=0;
}
lContainer.style.top=currentTop+"px";
if(scrollRate<=REBOUND) {
// scroll is finished. clear the interval and reset vars for the next scroll
clearInterval(zInterval);
zInterval=null;
startTop=currentTop;
scrollTick=0;
scrollRate=8;
}
}
First, step up to jQuery. You'll eventually be immensely glad you did.
Next, don't use inline JavaScript! Ditto on the gladness part.
Here's the existing functionality in jQuery. The multi-list version is below the fold.
Add:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
(or load a version of the jQuery file to your own website.)
PHP:
<div id="mContainer">
<div id="upArrow"></div>
<div id="nContainer">
<ul id="listContainer">
<?php
connect();
$sql = "SELECT drivers_id, firstname, image FROM drivers";
$result = mysql_query($sql);
while ($row=mysql_fetch_array($result) ) {
echo "<li><a id='".$row['drivers_id']."' href='".$row['image']."'>".$row['firstname']."</a></li>";
}
?>
</ul>
</div>
<div id="downArrow"></div>
</div>
Additional CSS:
ul#listContainer li > a:focus {
outline: none;
}
JavaScript:
$(document).ready (init);
//--- Global variables!
var lContainer; // object reference for the UL
var currentTop = 0; // the current Y position of the UL
var zInterval = null; // animation thread interval
var direction; // direction we're scrolling the UL. 0==up, 1==down
var startTop = 0; // the starting top of the UL
var scrollRate = 8; // initial rate of scrolling
var scrollTick = 0; // keeps track of long we've scrolled so we can slow it down accordingly
var listHeight = 60; // the current height of the UL
var MAX_SCROLL_TICK = 4; // the maximum value of scrollTick before it's reset
var MIN_LIST_HEIGHT = 145; // contracted height of the list
var REBOUND = 0; // the value of scrollRate when we stop scrolling
function init() {
//-- Activate click and focus handlers on the li elements.
$("ul#listContainer li > a").click ( function () { showPic (this); } )
// This next is IE only! use CSS.
.focus ( function () { this.hideFocus=true; } );
//-- Apply onclick behaviors to the up/down arrow and expansion control elements.
$("#downArrow").mousedown ( function () { scrollObjects (0); } );
$("#upArrow") .mousedown ( function () { scrollObjects (1); } );
lContainer = $("#listContainer");
$("#nContainer").css ('height', MIN_LIST_HEIGHT + "px");
}
function scrollObjects(dir) {
if (zInterval) return; // already scrolling.
// dont scroll up if we're at the top or down if at the bottom of the list
if ((!dir && currentTop <= -300) || (dir && currentTop == 0)) return;
direction = dir;
zInterval = setInterval (animate, 20);
}
function animate() {
// increment or decrement currentTop based on direction
if (!direction) {
currentTop -= scrollRate;
} else {
currentTop += scrollRate;
}
scrollTick++;
if (scrollTick >= MAX_SCROLL_TICK) {
scrollRate--; // slow the scroll rate down for a little style
scrollTick = 0;
}
lContainer.css ('top', currentTop + "px");
if (scrollRate <= REBOUND) {
// scroll is finished. clear the interval and reset vars for the next scroll
clearInterval(zInterval);
zInterval = null;
startTop = currentTop;
scrollTick = 0;
scrollRate = 8;
}
}
See this in action at jsFiddle.
Multi-List Version:
And now, with the awesome might of jQuery, we will:
Enable multi-list operation.
Reduce the dependence on "magic number" dimensions.
Fix the apparent over-scroll problem.
Make click-and-hold work the way the user expects.
First, change all the container and arrow ids to classes, like so:
<div class="mContainer">
<div class="upArrow"></div>
<div class="nContainer">
<ul class="listContainer">
... ...
</ul>
</div>
<div class="downArrow"></div>
</div>
Be sure to change the CSS to match, and don't use inline JS, that's handled below.
Then the JavaScript becomes:
$(document).ready (init);
function init() {
//-- Activate click and focus handlers on the li elements.
$("ul.listContainer li > a").click ( function () { showPic (this); } )
// This next is IE only! use CSS.
.focus ( function () { this.hideFocus=true; } );
//-- Initialize the scroll controls for every list in an mContainer.
$("div.mContainer").each ( function (J) {
var jNode = $(this);
jNode.data ('OurScrollObject', new ListScroll (jNode) );
} );
}
/*--- ListScroll object. This lets us (1) avoid global variables, and (2) keep each
each list's data separate.
*/
function ListScroll ( contNode, //--Required: jQuery wrapper of the container node.
INIT_SCROLL_RATE, //--Optional: Initial rate of scrolling.
MAX_SCROLL_TICK, //--Optional: The maximum value of scrollTick before it's reset.
MIN_LIST_HEIGHT, //--Optional: Contracted height of the list.
REBOUND //--Optional: The value of scrollRate when we stop scrolling.
)
{
//--- Set constants to default values as needed.
var INIT_SCROLL_RATE = INIT_SCROLL_RATE || 8;
var MAX_SCROLL_TICK = MAX_SCROLL_TICK || 4;
var MIN_LIST_HEIGHT = MIN_LIST_HEIGHT || 145;
var REBOUND = REBOUND || 0;
var listHeight = contNode.find ("ul.listContainer").outerHeight (true);
var scrollUpLimit = MIN_LIST_HEIGHT - listHeight;
//--- Init state variables.
var currentTop = 0; // The current Y position of the UL.
var startTop = 0; // The starting top of the UL.
var scrollTick = 0; // Keeps track of how long we've scrolled so we can slow down accordingly.
var scrollRate = INIT_SCROLL_RATE;
var bGoDown = true; // Are we scrolling down?
var zInterval = null; // Tracks the animation, interval timer.
var bStopRequested = false;
//--- Apply onclick behaviors to the up/down arrow elements.
contNode.find (".upArrow, .downArrow").bind ("mousedown mouseup", scrollObjects);
//--- Set the list's visible height.
contNode.find (".nContainer").height (MIN_LIST_HEIGHT);
function scrollObjects (zEvent) //-- zEvent is sent to event listeners automatically.
{
var bClickUpBtn = $(this).hasClass ('upArrow');
var bMouseUp = (zEvent.type == 'mouseup');
/*--- Here are the states we want to act on:
1) Were we already scrolling this list?
2) Has the user signaled a desire to scroll (mousedown)?
3) Has the user signaled to scroll scrolling (mouseup)?
4) Has the user signaled to STOP RIGHT NOW, by clicking the opposite direction
from the scroll direction?
*/
if (bMouseUp && ! zInterval) {
//--- Already stopped before user released the mouse.
return;
}
if (! bMouseUp && zInterval && bGoDown != bClickUpBtn) {
//--- Already scrolling in the currently-commanded direction.
return;
}
if (zInterval) {
//--- Already scrolling
if (bMouseUp) {
//--- Soft stop commanded (can coast down).
bStopRequested = true;
}
else {
//--- User must clicked in the opposite direction of the current scroll.
stopScroll ();
return;
}
}
else {
//--- Not scrolling yet
if (bBoundsCheck (bClickUpBtn) ) {
//--- Don't scroll beyond the top or bottom of the list.
return;
}
bGoDown = ! bClickUpBtn;
zInterval = setInterval (scrollList, 20);
}
}
function bBoundsCheck (bGoingUp) {
/*--- Keeps the list from scrolling out of bounds.
returns true if clipping (would have) occured.
*/
if (bGoingUp && currentTop <= scrollUpLimit) {
currentTop = scrollUpLimit;
return true;
}
if ( ! bGoingUp && currentTop >= 0) {
currentTop = 0;
return true;
}
return false;
}
function stopScroll () {
//--- Resets the state variables and clears the animation timer.
clearInterval (zInterval);
zInterval = null;
startTop = currentTop;
scrollTick = 0;
scrollRate = INIT_SCROLL_RATE;
bStopRequested = false;
}
function scrollList () {
//--- Increment or decrement currentTop based on direction.
if (bGoDown) currentTop += scrollRate;
else currentTop -= scrollRate;
if (bBoundsCheck ( ! bGoDown) ) {
stopScroll ();
contNode.find (".listContainer").css ('top', currentTop + "px");
return;
}
contNode.find (".listContainer").css ('top', currentTop + "px");
scrollTick++;
//if (scrollTick >= MAX_SCROLL_TICK || bStopRequested) { NO! Not ergo.
if (bStopRequested) {
scrollRate--; // slow the scroll rate down for a little style
scrollTick = 0;
}
if (scrollRate <= REBOUND) {
// Scroll is finished. clear the interval and reset vars for the next scroll.
stopScroll ();
}
}
}
See it in action at jsFiddle.
Here's a handy jQuery Reference.
Update:
To change which arrow goes what direction, change this line:
var bClickUpBtn = $(this).hasClass ('upArrow');
To:
var bClickUpBtn = $(this).hasClass ('downArrow');
See the Fiddle.