AJAX Bookmarking System, JavaScript Menu
演示地址http://www.vibe.to/js/stew/ajaxmenu.php
代码
Yesterday I was immersed in code throughout the day. I was on the task of creating an AJAX bookmarking system (I freaking love AJAX by the way.) There are four parts to the current system:
* Adding Bookmarks
* Viewing Quick Bookmarks
* Viewing All Bookmarks
* Deleting Bookmarks
Soon to be added:
* Tag Bookmarks
* Arrange Bookmarks
Languages/Tools Used
PHP, DOM, AJAX, JavaScript, MySQL
The Table (MySQL)
CREATE TABLE `favs` (
`id` int(10) unsigned NOT NULL auto_increment,
`userid` int(10) unsigned NOT NULL default '0',
`url` varchar(100) NOT NULL default '',
`title` varchar(100) NOT NULL default '',
`favtime` timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY(`id`),
KEY `userid` (`userid`)
)
If you’re curious, I called the table favs because of poor planning, no other reason. bookmarks would be preferred.
Adding Bookmarks
A very easy step. The button sends the document title and document url through AJAX to a php file that will save the row in the database.
var isActive;
var timeout;
function add2Fav(userid)
{
if (!userid)
{
alert("You must login before you can bookmark pages");
return
}
xmlHttp = GetXmlHttpObject();
var docURL = document.location;
var docTitle = document.title;
var url = "_ajax.add2Fav.php";
url = url + "?userid=" + userid;
url = url + "&url=" + escape(docURL);
url = url + "&title=" + escape(docTitle);
url = url + "&rand=" + Math.random();
xmlHttp.onreadystatechange=doOutput;
xmlHttp.open("GET",url,true);
xmlHttp.send(null);
function doOutput()
{
if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete")
{
isActive = null; // deactivate the bookmark menu
if (xmlHttp.responseText == "1")
{
alert("You have successfully bookmarked this page.nn" + docTitle);
}
else
{
alert("We couldn't save the page to your favourites list because of an error");
}
}
}
}
Fairly straightforward. Users must be logged in to save bookmarks, I was thinking about implementing cookies, but that would just make things much more confusing. If they’re not logged in we just prompt them to log in. The PHP file returns “1″ (string) if the row is saved.
AJAX=>PHP: Add Bookmark
<~?
# db connection
$user_id = intval($_GET['userid']);
if ($user_id == 0) exit("0"); // invalid userID!
mysql_query("INSERT INTO favs (userid, url, title) VALUES ('{$user_id}', '".mysql_escape_string($_GET['url'])."', '".mysql_escape_string($_GET['title'])."')");
if (mysql_affected_rows() > 0) echo “1″;
else echo mysql_error();
?~>
Quick Bookmarks
This is the cream of the crop. I needed a way to implement the bookmarking system on the site that was unobtrusive, but would still be easy enough to load up that they would be useful. My solution was to offer a drop down menu right next to the “Add Bookmark” button. The menu has to load up relative to the button, so I had to find its coordinates using clientX and clientY, as well as offsetLeft, OffsetTop and offsetParent. Because Internet Explorer and FireFox read these different I had to use quirksmode findPos function to bridge the browser differences. Then, after I had it working, I decided a snazzy fade effect would look brilliant, so I coded a fadeIn() and fadeOut() function to play with the CSS alpha.
function showBookmarks(e, userid)
{
var divid = 'favmenu';
var heightPX = 27; // define the elements height in PX
var widthPX = -301;
if (!isActive) // make sure they've only clicked the link once
{
isActive = 1; // the menu is active
e = e ? e : window.event; // ff : ie
var obj = e.target ? e.target : e.srcElement; // ff : ie
xmlHttp = GetXmlHttpObject();
xmlHttp.onreadystatechange = doBookmarksAJAX;
xmlHttp.open("GET","_ajax.getBookmarks.php?userid="+userid+"&rand="+Math.random(),true);
xmlHttp.send(null);
}
function doBookmarksAJAX()
{
if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete")
{
var parent = document.getElementById('topRightDiv');
var absOffset = findPos(parent);
var menu = document.createElement('div');
menu.setAttribute('id', divid);
//menu.className = 'favMenu';
var leftPX = parseInt(absOffset) + widthPX;
menu.style.left =leftPX + 'px';
var topPX = parseInt(absOffset) + heightPX; // top of object + object size
menu.style.top = topPX + 'px'
parent.appendChild(menu)
document.getElementById(divid).innerHTML = xmlHttp.responseText;
fadeIn(0, divid);
menu.onmouseout = function()
{
timeout = window.setTimeout("hideBookmarks(1)", 3000);
}
menu.onmouseover = function()
{
if (timeout)
{
clearTimeout(timeout);
} // else they haven't put their mouse over the menu yet
}
}
} // end
}
function hideBookmarks(fade)
{
var ms = fade ? 350 : 1; // 350 = fade delay, 1 = instant
if (!fade)
{
if (timeout)
{
clearTimeout(timeout);
}
isActive = 0;
var menu = document.getElementById('favmenu');
var parent = document.getElementById('topRightDiv');
parent.removeChild(menu);
}
else
{
fadeOut(100, 'favmenu');
setTimeout("hideBookmarks(0)", ms);
}
}
function findPos(obj)
{
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
}
return ;
}
function fadeIn(opacity, objname)
{
obj = document.getElementById(objname);
if (obj)
{
if (opacity <= 100)
{
if (obj.style.MozOpacity != null)
{
/* Mozilla's pre-CSS3 proprietary rule */
obj.style.MozOpacity = (opacity/100)-.001;
/* the .001 fixes a glitch in the opacity calculation which normally results in a flash when reaching 1 */
} else if (obj.style.opacity != null)
{
/* CSS3 compatible */
obj.style.opacity = (opacity/100)-.001;
} else if (obj.style.filter != null)
{
/* IE's proprietary filter */
obj.style.filter = "alpha(opacity="+opacity+")";
/* worth noting: IE's opacity needs values in a range of 0-100, not 0.0 - 1.0 */
}
opacity += 10;
window.setTimeout("fadeIn("+opacity+", '"+objname+"')", 35);
}
}
}
function fadeOut(opacity, objname)
{
obj = document.getElementById(objname);
if (obj)
{
if (opacity >= 0)
{
if (obj.style.MozOpacity != null)
{
/* Mozilla’s pre-CSS3 proprietary rule */
obj.style.MozOpacity = (opacity/100)-.001;
/* the .001 fixes a glitch in the opacity calculation which normally results in a flash when reaching 1 */
} else if (obj.style.opacity != null)
{
/* CSS3 compatible */
obj.style.opacity = (opacity/100)-.001;
} else if (obj.style.filter != null)
{
/* IE’s proprietary filter */
obj.style.filter = “alpha(opacity=”+opacity+”)”;
/* worth noting: IE’s opacity needs values in a range of 0-100, not 0.0 - 1.0 */
}
opacity -= 10;
window.setTimeout(”fadeOut(”+opacity+”, ‘”+objname+”‘)”, 35);
}
}
}
Call to action: onClick=”showBookmarks(event, ‘{$userID}’);”
event = passes the event information to the function (same as window.event)
$userID = userID from $_SESSION
Viewing/deleting the full bookmark list is a standard page, but to keep the AJAX trend I made it delete in real time via AJAX. Last block of code, I swear!
function deleteBookmark(obj, userid, id)
{
var row = obj.parentNode.parentNode; // two steps up
if (row.nodeName.toUpperCase() == 'TR')
{
row.parentNode.removeChild(row);
ajaxStatus('Deleting bookmark...');
xmlHttp = GetXmlHttpObject();
xmlHttp.onreadystatechange=doDelete;
xmlHttp.open("GET","http://www.vibe.to/_ajax.deleteBookmark.php?userid="+userid+"&id="+id,true);
xmlHttp.send(null);
}
function doDelete()
{
if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete")
{
if (xmlHttp.responseText == "1")
{
// done... don't need to do anything
} else alert(xmlHttp.responseText);
ajaxStatus();
}
}
}
Call to action: onClick=”javascript:deleteBookmark(this, ‘{$userID}’, ‘{$bookmarkID}’);”
this = references the link or button that is clicked
$userID = is the users unique number (from $_SESSION)
$bookmarkID = the bookmark row (from the query result)
I implemented this system on my social networking site so users can bookmark their favourite forum threads, people and, well, basically any page. Example of quick view available here ע:ż
页:
[1]