MetaFilter's site and server can always use upgrades of hardware, software, and bandwidth, as well as more stable funding for continued support of its small but high-skilled moderation and backend team! If you'd like to chip in, you can donate to Metafilter. |
UserNotes
From Mefi Wiki
Jump to navigationJump to search
For instructions on using this Greasemonkey script, see Greasemonkey Scripts and Plugins.
// ==UserScript== // @name UserNotes // @namespace jacalata // @description adds ajaxy viewing of user notes whenever their id is shown // @include *.metafilter.com/* // @version 3.1 (firefox 8.0 support) // 2.0 (optional marking added to usernames sitewide to indicate notes // 1.5 (pressing enter in the text input box now submits the new note) // 1.4 (fixed buttons into text-like pieces of ajaxy goodness) // 1.3 (fixed bug that was not saving the first note on each page) // 1.2 (added autoclear of textbox on focus) // 1.1 (changed to handle multiple notes with individual deletion) // ==/UserScript== // chrome doesn't support GM_getValue, using replacement localStorage // this code borrowed from http://devign.me/greasemonkey-gm_getvaluegm_setvalue-functions-for-google-chrome/ if (!this.GM_getValue || (this.GM_getValue.toString && this.GM_getValue.toString().indexOf("not supported")>-1)) { this.GM_getValue=function (key,def) { return localStorage[key] || def; }; this.GM_setValue=function (key,value) { return localStorage[key]=value; }; this.GM_deleteValue=function (key) { return delete localStorage[key]; }; } var currentUserID = "User"+location.href.substring(31); numUserNotes = GM_getValue(currentUserID, 0); var isAjaxOn = "ajaxSetting"; var ajaxSetting = GM_getValue(isAjaxOn, false); var currentBalloon; // adding a button to turn on/off the sitewide notes // (off means they are only visible on the profiles, no markings around the rest of the site) ajaxButton = createButton("ajaxButton", "ajaxButton", "##", "sitewide notes off", "_self", toggleAjax); //create an invisible div that will show the notes in a popup // this is from http://blog.kung-foo.tv/archives/001614.html, with the style stuff based on the bookburro extension code var notesBox = document.createElement('div'); notesBox.setAttribute("id", "balloon"); notesBox.setAttribute("style", "background-color:#778899;text-align:left;"); notesBox.style.position = "absolute"; notesBox.style.border = "1px solid navy"; notesBox.style.margin = "10"; notesBox.style.zIndex = "99"; notesBox.style.font = "8pt sans-serif"; notesBox.style.overflow = "hidden"; notesBox.style.opacity = "85"; notesBox.style.padding = "4px"; notesBox.style.display = "none"; var searchPattern = "//div[@class='mefimessages']"; var options = document.evaluate( searchPattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var i; for (var targetClass = null, i=0; (targetClass = options.snapshotItem(i)); i++) { targetClass.innerHTML += " | "; targetClass.appendChild(ajaxButton); targetClass.appendChild(notesBox); } // if this is a profile page, add all the note-taking elements if (location.href.match("metafilter.com/user") ) { takeNotes(); } if (ajaxSetting == true) { ajaxButton.innerHTML = ajaxButton.innerHTML.replace("off", "on"); showLinkedNotes(); } // called on loading a page with ajaxNotes set, or when turning on the ajax notes. // searches for links to user profiles, and makes a mark next to those you have given notes function showLinkedNotes() { // find every spot where a user profile is linked var profileSearch = "//a[contains(@href, '/user/') and not(contains(./text(), 'My')) and not(contains(@href, 'rss' ))]"; var profiles = document.evaluate( profileSearch, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var j; for (var targetClass = null, j=0; (targetClass = profiles.snapshotItem(j)); j++) { var thisUserID = "User"+targetClass.href.substring(31); var thisUserNotes = GM_getValue(thisUserID, 0); if (thisUserNotes > 0) { targetClass.innerHTML += " <i>i</i> "; targetClass.addEventListener("mouseover", viewNotes, false); targetClass.addEventListener("click", hideBalloon, false); } } } // function showLinkedNotes // the user has just turned off the ajax notes feature - hide the little 'i' icons (ie; reverse what showLinkedNotes did) function removeLinkedNotes() { hideBalloon(); //just in case it is currently displayed // find every spot where a user profile is linked var profileSearch = "//a[contains(@href, '/user/') and not(contains(./text(), 'My')) and not(contains(@href, 'rss' ))]"; var profiles = document.evaluate( profileSearch, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var j; for (var targetClass = null, j=0; (targetClass = profiles.snapshotItem(j)); j++) { var thisUserID = "User"+targetClass.href.substring(31); var thisUserNotes = GM_getValue(thisUserID, 0); if (thisUserNotes > 0) { targetClass.innerHTML = targetClass.innerHTML.replace(" <i>i</i> ", ""); targetClass.removeEventListener("mouseover", viewNotes, false); } } }//funtion removeLinkedNotes // displays the info balloon, containing the notes for the user whose profile you mousedover // from http://blog.kung-foo.tv/archives/001614.html function viewNotes() { var thisUserID = "User"+this.href.substring(31); if ( thisUserID == currentBalloon ) { return false; } currentBalloon = thisUserID; // global variable to track which info balloon is currently displayed var objX = findPosX(this); var objY = findPosY(this); var balloon = document.getElementById("balloon"); if ( balloon && balloon.childNodes ) { while ( balloon.childNodes.length > 0 ) { balloon.removeChild(balloon.childNodes[0]); // remove anything in the current balloon } } var closeElt = document.createElement('img'); closeElt.setAttribute("id","closebox"); closeElt.setAttribute("src","http://images.metafilter.com/mefi/icons/stockholm_mini/close.gif"); closeElt.addEventListener('click', hideBalloon, false); balloon.appendChild(closeElt); var newElt = document.createElement('div'); newElt.setAttribute("id","balloon_contents"); var thisUserID = "User"+this.href.substring(31); var thisUserNotes = GM_getValue(thisUserID, 0); var k; var height = 13; for (k=0; k<thisUserNotes; k++) { var newLine = "-" + GM_getValue(thisUserID+k, ""); newElt.innerHTML += newLine; newElt.innerHTML += "<br>"; var nRows = Math.ceil( (newLine.length)/30); console.log("line Lenght = " + newLine.length + "nRows = " + nRows); height += 13 * nRows; } balloon.style.width = "150px"; balloon.style.height = height; balloon.appendChild(newElt); balloon.style.top = (objY-0) + 'px'; balloon.style.left = (objX+45) + 'px'; balloon.style.display = 'block'; } // function viewNotes // make the info balloon disappear // from http://blog.kung-foo.tv/archives/001614.html function hideBalloon() { var balloon = document.getElementById("balloon"); if ( balloon ) { balloon.style.display = 'none'; currentBalloon = null; } return false; } // function hideBalloon // find the position of an object along the x axis of the page // from http://blog.kung-foo.tv/archives/001614.html function findPosX(obj) { var curleft = 0; if (obj.offsetParent) { while (obj.offsetParent) { curleft += obj.offsetLeft; obj = obj.offsetParent; } if ( obj != null ) { curleft += obj.offsetLeft; } } else if (obj.x) { curleft += obj.x; } return curleft; } // function findPosX // finds the position of an object along the y axis of the page // from http://blog.kung-foo.tv/archives/001614.html function findPosY(obj) { var curtop = 0; if (obj.offsetParent) { while (obj.offsetParent) { curtop += obj.offsetTop; obj = obj.offsetParent; } if ( obj != null ) { curtop += obj.offsetTop; } } else if (obj.y) { curtop += obj.y; } return curtop; } // funcion findYPos // creates a button element that calls a function on this page function createButton(id, name, href, words, target, clickFunction) { //ajaxButton = createButton("ajaxButton", "ajaxButton", "##", "ajax notes", "_self", toggleAjax); newButton = document.createElement("a"); newButton.setAttribute("id", id); newButton.setAttribute("name", name); newButton.setAttribute("href", href); newButton.innerHTML = words; newButton.setAttribute("target", target); newButton.addEventListener("click", clickFunction, false); return newButton; } // function createButton // toggles the value of our 'is ajax on?' boolean function toggleAjax() { ajaxSetting = !ajaxSetting; GM_setValue(isAjaxOn, ajaxSetting); if (ajaxSetting) // turning it on { ajaxButton.innerHTML = ajaxButton.innerHTML.replace("off", "on"); showLinkedNotes(); } else //turning it off { ajaxButton.innerHTML = ajaxButton.innerHTML.replace("on", "off"); removeLinkedNotes(); } } // function toggleAjax // for profile pages: create and display all the notes for this user. function takeNotes() { anchor = document.getElementById('contact'); if (anchor == null) // this is your own profile - no notes about yourself, because the 'contact' element doesn't exist { return; } outputDiv = anchor.parentNode; if (numUserNotes > 0) { notesHeadline = document.createElement("div"); notesHeadline.setAttribute("id", "headline"); notesHeadline.innerHTML = "<b>My Notes</b>"; delNotes = createButton("delBut", "DelNotes", "##", " [delete all]", "_self", delAllNotes); outputDiv.appendChild(notesHeadline); notesHeadline.appendChild(delNotes); for (var i = 0; i < numUserNotes; i++) { note = GM_getValue(currentUserID+i, ""); currentNotes = document.createElement("div"); currentNotes.setAttribute("id", "currentNotes"+i); currentNotes.innerHTML = note; delCurrent = createButton("delBut"+i, "DelNote", "##", " [x]", "_self", delOneNote); outputDiv.appendChild(currentNotes); currentNotes.appendChild(delCurrent); } } inputForm = document.createElement("form"); inputForm.setAttribute("method", "post"); inputForm.addEventListener("submit", addNote, false); inputForm.setAttribute("target", "_self"); newNotes = document.createElement("input"); newNotes.setAttribute("type", "text"); newNotes.setAttribute("value", "new note..."); newNotes.setAttribute("id", "noteInput"); newNotes.addEventListener("focus", clearValue, true); newNotes.innerHTML = "<br>"; addNotes = document.createElement("input"); addNotes.setAttribute("type", "submit"); addNotes.setAttribute("id", "addBut"); addNotes.setAttribute("value", "Add Note"); addNotes.setAttribute("target", "_self"); inputForm.appendChild(newNotes); inputForm.appendChild(addNotes); outputDiv.appendChild(inputForm); } // function takeNotes // clears the default text in the textbox when the user clicks on it function clearValue() { textbox = document.getElementById("noteInput"); if (textbox.value == "new note...") { textbox.setAttribute("value", ""); } } // function clearValue // creates and displays a new note, from the text in the textbox function addNote() { var note = document.getElementById("noteInput"); var noteNum = numUserNotes; if (note.value == "") { return; } if (numUserNotes == 0) { notesHeadline = document.createElement("div"); notesHeadline.setAttribute("id", "headline"); notesHeadline.innerHTML = "<b>My Notes</b>"; delNotes = createButton("delBut", "DelNotes", "##", " [delete all]", "_self", delAllNotes); //alert(note); note.parentNode.insertBefore(notesHeadline, note); notesHeadline.appendChild(delNotes); } numUserNotes++; GM_setValue(currentUserID, numUserNotes); GM_setValue(currentUserID+noteNum, note.value); currentNoteNew = document.createElement("div"); currentNoteNew.setAttribute("id", "currentNotes"+noteNum); currentNoteNew.innerHTML = note.value; delCurrentNew = createButton("delBut"+noteNum, "DelNote", "##", " [x]", "_self", delOneNote); note.parentNode.insertBefore(currentNoteNew, note); currentNoteNew.appendChild(delCurrentNew); }//function addNotes // delete a single note function delOneNote() { var newID = (+this.id.substring(6)); var nextID = newID + 1; while (nextID < numUserNotes) { var thisNoteID = currentUserID+newID; var nextNoteID = currentUserID+nextID; nextNoteValue = GM_getValue(nextNoteID, ""); currentNotes = document.getElementById("currentNotes"+nextID); currentNotes.setAttribute("id", "currentNotes"+newID); delCurrent = document.getElementById("delBut"+nextID); delCurrent.setAttribute("id", "delBut"+newID); GM_setValue(thisNoteID, nextNoteValue); newID++; nextID++; } numUserNotes--; GM_setValue(currentUserID, numUserNotes); noteText = this.parentNode; noteText.removeChild(this); noteText.parentNode.removeChild(noteText); if (numUserNotes == 0) { headline = document.getElementById("headline"); headline.parentNode.removeChild(headline); } } // fucntion delOneNote // delete all notes about this user function delAllNotes() { var newID; for (newID = 0; newID < numUserNotes; newID++) { note = document.getElementById("currentNotes"+newID); note.parentNode.removeChild(note); } headline = document.getElementById("headline"); headline.parentNode.removeChild(headline); numUserNotes = 0; GM_setValue(currentUserID, numUserNotes); return false; } // function delAll Notes