window.onload = function() { var sl = new SocialHistory(); alert(sl.doesVisit("www.jb51.net")); } 如果用户曾经使用过www.jb51.net,那么该函数就会返回真,否则返回假。 其实原理并不复杂,它利用了链接的 a:visited 伪类的属性。首先在页面上生成一个iframe,并在这个iframe中设置 a 和 a:visited 为不同的样式。然后将网站的链接插入到 iframe 中。浏览器就会根据用户的访问历史,为访问过的链接设置 a:visited 的样式。最后再获得链接的最终样式,如果是 a:visited,就可以认为用户访问过该网站了。具体的实现方式可以参考源代码。 这个脚本主要用于显示社会性书签的图标,可以恰到好处地显示用户所使用的网站。但我担心,这样的做法是不是有盗取用户隐私之嫌?虽然这个方法只能判断用户有无访问特定的网站,并不能无限制地得到所有访问历史。 /* |
* Social Limit - Only the social you care about. |
* |
* Enables your site to know which social bookmarking badges to display to your |
* visitors. It tells you all social sites the user has gone to, or you can |
* query for a specific one. |
* |
* For example: |
* |
* var sl = SocialHistory(); |
* alert( sl.doesVisit("Digg") ); // Returns true/false, -1 if unknown. |
* var listOfVisitedSites = sl.visitedSites(); |
* var checkedSites = sl.checkedSites(); |
* |
* If you want to add more sites to check, you can pass that in as a dictionary |
* to History: |
* |
* var more = { "Humanized": "http://humanized.com", |
* "Azarask.in": ["http://azarask.in", "http://azarask.in/blog"] |
* }; |
* var sl = SocialHistory(more); |
* alert( sl.doesVisit("Humanized") ); |
* |
* For a list of built-in sites, see the sites variable below. |
* |
* Copyright (c) 2008 Aza Raskin (http://azarask.in/blog) |
* |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
* of this software and associated documentation files (the "Software"), to deal |
* in the Software without restriction, including without limitation the rights |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
* copies of the Software, and to permit persons to whom the Software is |
* furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
* THE SOFTWARE. |
* |
*/ |
var SocialHistory = function( moreSites ){ |
var sites = { |
"Digg": ["http://digg.com", "http://digg.com/login"], |
"Reddit": ["http://reddit.com", "http://reddit.com/new/", "http://reddit.com/controversial/", "http://reddit.com/top/", "http://reddit.com/r/reddit.com/", "http://reddit.com/r/programming/"], |
"StumbleUpon": ["http://stumbleupon.com"], |
"Yahoo Buzz": ["http://buzz.yahoo.com"], |
"Facebook": ["http://facebook.com/home.php", "http://facebook.com", "https://login.facebook.com/login.php"], |
"Del.icio.us": ["https://secure.del.icio.us/login", "http://del.icio.us/"], |
"MySpace": ["http://www.myspace.com/"], |
"Technorati": ["http://www.technorati.com"], |
"Newsvine": ["https://www.newsvine.com", "https://www.newsvine.com/_tools/user/login"], |
"Songza": ["http://songza.com"], |
"Slashdot": ["http://slashdot.org/"], |
"Ma.gnolia": ["http://ma.gnolia.com/"], |
"Blinklist": ["http://www.blinklist.com"], |
"Furl": ["http://furl.net", "http://furl.net/members/login"], |
"Mister Wong": ["http://www.mister-wong.com"], |
"Current": ["http://current.com", "http://current.com/login.html"], |
"Menaeme": ["http://meneame.net", "http://meneame.net/login.php"], |
"Oknotizie": ["http://oknotizie.alice.it", "http://oknotizie.alice.it/login.html.php"], |
"Diigo": ["http://www.diigo.com/", "https://secure.diigo.com/sign-in"], |
"Funp": ["http://funp.com", "http://funp.com/account/loginpage.php"], |
"Blogmarks": ["http://blogmarks.net"], |
"Yahoo Bookmarks": ["http://bookmarks.yahoo.com"], |
"Xanga": ["http://xanga.com"], |
"Blogger": ["http://blogger.com"], |
"Last.fm": ["http://www.last.fm/", "https://www.last.fm/login/"], |
"N4G": ["http://www.n4g.com"], |
"Faves": ["http://faves.com", "http://faves.com/home", "https://secure.faves.com/signIn"], |
"Simpy": ["http://www.simpy.com", "http://www.simpy.com/login"], |
"Yigg": ["http://www.yigg.de"], |
"Kirtsy": ["http://www.kirtsy.com", "http://www.kirtsy.com/login.php"], |
"Fark": ["http://www.fark.com", "http://cgi.fark.com/cgi/fark/users.pl?self=1"], |
"Mixx": ["https://www.mixx.com/login/dual", "http://www.mixx.com"], |
"Google Bookmarks": ["http://www.google.com/bookmarks", "http://www.google.com/ig/add?moduleurl=bookmarks.xml&hl=en"], |
"Subbmitt": ["http://subbmitt.com/"] |
}; |
for( var site in moreSites ) { |
// If we don't have the site, create the URL list. |
if( typeof( sites[site] ) == "undefined" ) sites[site] = []; |
// If the value is string, just push that onto the URL list. |
if( typeof( moreSites[site] ) == "string" ) |
sites[site].push( moreSites[site] ); |
else |
sites[site] = sites[site].concat( moreSites[site] ); |
} |
var visited = {}; |
function getStyle(el, scopeDoc,styleProp) { |
if (el.currentStyle) |
var y = el.currentStyle[styleProp]; |
else if (window.getComputedStyle) |
var y = scopeDoc.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp); |
return y; |
} |
function remove( el ) { |
el.parentNode.removeChild( el ); |
} |
// Code inspired by: |
// bindzus.wordpress.com/2007/12/24/adding-dynamic-contents-to-iframes |
function createIframe() { |
var iframe = document.createElement("iframe"); |
iframe.style.position = "absolute"; |
iframe.style.visibility = "hidden"; |
document.body.appendChild(iframe); |
// Firefox, Opera |
if(iframe.contentDocument) iframe.doc = iframe.contentDocument; |
// Internet Explorer |
else if(iframe.contentWindow) iframe.doc = iframe.contentWindow.document; |
// Magic: Force creation of the body (which is null by default in IE). |
// Also force the styles of visited/not-visted links. |
iframe.doc.open(); |
iframe.doc.write(''); |
iframe.doc.close(); |
// Return the iframe: iframe.doc contains the iframe. |
return iframe; |
} |
var iframe = createIframe(); |
function embedLinkInIframe( href, text ) { |
var a = iframe.doc.createElement("a"); |
a.href = href; |
a.innerHTML = site; |
iframe.doc.body.appendChild( a ); |
} |
for( var site in sites ) { |
var urls = sites[site]; |
for( var i=0; i<urls.length; i++ ) { |
// You have to create elements in the scope of the iframe for IE. |
embedLinkInIframe( urls[i], site ); |
// Automatically try variations of the URLS with and without the "www" |
if( urls[i].match(/www\./) ){ |
var sansWWW = urls[i].replace(/www\./, ""); |
embedLinkInIframe( sansWWW, site ); |
} else { |
// 2 = 1 for length of string + 1 for slice offset |
var httpLen = urls[i].indexOf("//") + 2; |
var withWWW = urls[i].substring(0, httpLen ) + "www." + urls[i].substring( httpLen ); |
embedLinkInIframe( withWWW, site ); |
} |
} |
} |
var links = iframe.doc.body.childNodes; |
for( var i=0; i<links.length; i++) { |
// Handle both Firefox/Safari, and IE (respectively) |
var displayValue = getStyle(links[i], iframe.doc, "display"); |
var didVisit = displayValue != "none"; |
if( didVisit ){ |
visited[ links[i].innerHTML ] = true; |
} |
} |
remove( iframe ); |
return new (function(){ |
var usedSites = []; |
for( var site in visited ){ |
usedSites.push( site ); |
} |
// Return an array of visited sites. |
this.visitedSites = function() { |
return usedSites; |
} |
// Return true/false. If we didn't check the site, return -1. |
this.doesVisit = function( site ) { |
if( typeof( sites[site] ) == "undefined" ) |
return -1; |
return typeof( visited[site] ) != "undefined"; |
} |
var checkedSites = []; |
for( var site in sites ){ |
checkedSites.push( site ); |
} |
// Return a list of the sites checked. |
this.checkedSites = function(){ |
return checkedSites; |
} |
})(); |
} |