Delicious tag suggest

By Kishore Senji Last update Jan 13, 2006 — Installed 798 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
// ==UserScript==
// @name           Delicious tag suggest
// @namespace      http://myjavaserver.com/~ksenji
// @description    Delicious tag suggest while searching one's own bookmarks. This script suggests the tags on keypress similar to google suggest
// @include        http://del.icio.us/*
// ==/UserScript==


function xpath(query) {
  return document.evaluate(query, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}

/** function to add global styles from http://diveintogreasemonkey.org/ */
function addGlobalStyle(css) {
  var head, style;
  head = document.getElementsByTagName('head')[0];
  if (!head) { return; }
  style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = css;
  head.appendChild(style);
}

function trim(str) {
  return str.replace(/^\s*|\s*$/g, "");
}

function Tag(tagName, url, freq) {
  this.tagName = tagName;
  this.url = url;
  this.freq = freq;
}
 
function getMatchedTags(tags, input, ignoreCase) {
  var matchedTags = [];
  var regexp = new RegExp("^" + (ignoreCase ? input.toLowerCase() : input));
  for(var i=0; i<tags.length; i++) {
    var tag = ignoreCase ? (tags[i].tagName).toLowerCase() : (tags[i].tagName);
    if(tag.match(regexp)) {
      matchedTags.push(tags[i]);
    }
  }
  return matchedTags;
}

function substrNotBetween(str, a, b) {
  var max = str.length;
  if((a>=0 && b>=0) && (a<=max && b<=max)) {
    return str.substring(0, a) + str.substring(b, max);
  }
  return str;
}

function setClassNameForTagDiv(div, index, className) {
  var childNodes = div.childNodes;
  for(var i=0; i<childNodes.length; i++) {
    childNodes[i].className = 'delicious_search_tag_suggestion_onmouseout';
  }
  if(index < childNodes.length) {
    childNodes[index].className = className;
  }
}


function suggest(event, input, inputSelected, div, tags) {
  var keyCode = event.which;
  var inputValue = input.value;
  if(keyCode && keyCode != 13) {
    var key = String.fromCharCode(keyCode);
    inputValue = trim((keyCode != 8) ? (inputValue + key) : (inputSelected ? (substrNotBetween(inputValue, input.selectionStart, input.selectionEnd)) : inputValue.substring(0, inputValue.length-1)));
  }
  div.innerHTML = '';
  var hasSuggestedTags = false;
  if(inputValue != '') {
    var matchedTags = getMatchedTags(tags, inputValue, true);
    hasSuggestedTags = (matchedTags.length > 0);
    for(var i=0; i<matchedTags.length; i++) {
      var tagDiv = document.createElement("div");
      tagDiv.innerHTML = matchedTags[i].tagName;
      tagDiv.className = 'delicious_search_tag_suggestion_onmouseout';
      tagDiv.setAttribute("onmouseover", "this.className='delicious_search_tag_suggestion_onmouseover';");
      tagDiv.setAttribute("onmouseout", "this.className='delicious_search_tag_suggestion_onmouseout';");
      tagDiv.setAttribute("onmousedown", "window.document.location.href='"+matchedTags[i].url+"';");
      
      var freqDiv = document.createElement("div");
      freqDiv.setAttribute("style", "position:absolute;display:inline;right:0px");
      freqDiv.innerHTML = matchedTags[i].freq;
      tagDiv.appendChild(freqDiv);
      
      div.appendChild(tagDiv);
    }
  }
  setClassNameForTagDiv(div, 0, 'delicious_search_tag_suggestion_onmouseover');
  div.style.display = hasSuggestedTags ? '' : 'none';
}

(function() {
  var result = xpath("//div[@id='sidebar']//li[@class='bundle fold']//a");
  var tags = (function() {
    var tags = [];
    for(var i=0; i<result.snapshotLength; i++) {
      var item = result.snapshotItem(i);
      tags.push(new Tag(item.firstChild.nodeValue, item.href, trim(item.previousSibling.firstChild.nodeValue)));
    }
    return tags.sort(function(aTag, bTag){
      return (aTag.tagName>bTag.tagName) ? 1 : (aTag.tagName<bTag.tagName) ? -1 : (function(){return bTag.freq-aTag.freq;})(); 
    });
  })();
  
  /** Get the top level input element and suggest tags when the user types in something in to it */
  var crumb = document.getElementById("crumb");
  var input = crumb.firstChild;
  var inputSelected = false;
  var index = 0;
  
  // suggestion div
  var div = document.createElement("div");
  div.id = "delicious_search_tag_suggestion";
  div.style.display = "none";
  document.body.appendChild(div);
  addGlobalStyle("#delicious_search_tag_suggestion{background:#fff;width:200px;border:1px solid;position:absolute;top:"+(crumb.offsetTop+crumb.offsetHeight)+"px;left:"+crumb.offsetLeft+"px;overflow:hidden}");
  addGlobalStyle(".delicious_search_tag_suggestion_onmouseover{font-size:70%;padding-top:2px;padding-bottom:2px;padding-right:2px;padding-left:2px;width:100%;color:#fff;background:#00f;}");
  addGlobalStyle(".delicious_search_tag_suggestion_onmouseout{font-size:70%;padding-top:2px;padding-bottom:2px;padding-right:2px;padding-left:2px;width:100%;color:#000;background:#fff;}");
  
  input.addEventListener("keypress", 
    function(event) {
      suggest(event, input, inputSelected, div, tags);
      inputSelected = false;
      var keyCode = event.keyCode;
      if(keyCode == 38) {
        if(index > 0) {
          index --; 
        }
        setClassNameForTagDiv(div, index, 'delicious_search_tag_suggestion_onmouseover');
      } else if(keyCode == 40) {
        if(index < div.childNodes.length-1) {
          index ++;
        }
        setClassNameForTagDiv(div, index, 'delicious_search_tag_suggestion_onmouseover');
      } else if(keyCode == 13) {
         eval(div.childNodes[index].getAttribute("onmousedown"));
      }
    }
  ,false);
  
  input.addEventListener("blur", 
    function(event) {
      div.style.display = 'none';
      inputSelected = false;
    }
  ,false);
  
  input.addEventListener("focus", 
    function(event) {
      suggest(event, input, inputSelected, div, tags);
      inputSelected = false;
    }
  ,false);  
  
  input.addEventListener("select", 
    function(event) {
      inputSelected = true;
    }
  ,false);      
})();