Page_Bookmarker
By Descriptor
—
Last update Mar 18, 2008
—
Installed
331 times.
// ==UserScript==
// @name Page_Bookmarker
// @namespace http://gmscripts.bigsleep.net
// @description Adds hash "bookmarks" with the middle-click
// @homepage http://userscripts.org/scripts/show/23012
// @version 1.3
// @date 2008-03-17
// @timestamp 1205818710015
// @include http://*
// ==/UserScript==
/* ** Configurable preferences **
Key prefs
button: left mouse = 0, middle = 1, right mouse = 2
key: key or unicode number values for any key
Modifier keys = true or false
replaceHistory: true or false
- true will replace "#Page_Bookmark_1" with "#Page_Bookmark_2"
- false will add every "#Page_Bookmark_#" to your history,
so that you can use the Back/Forward buttons
styles: list of CSS styles to be added to a style sheet
! Be careful to not remove the commas !
*/
var PB_Prefs = {
mouse: {
button: 1,
shiftKey: true,
altKey: false,
ctrlKey: false,
metaKey: false,
},
next: {
key: "N",
altKey: false,
ctrlKey: false,
metaKey: false,
},
prev: {
key: "P",
altKey: false,
ctrlKey: false,
metaKey: false,
},
replaceHistory: true,
// Mark and Target Styles - bullet (escaped) unicode = '\u2022'
styles: [
"/* Page_Bookmarker Mark styles */",
".Page_Bookmarker_Mark:before { content: '\u2022';",
" color: blue; background-color: ivory; }",
"/* Colorize the target */",
"*:target { background-color: ivory; }",
] // end of styles
}; // end of prefs
/* Venture beyond at your own risk */
// current marker position
var PB_Marker = -1;
// list of markers
var PB_Markers = [];
// for creating unique ids
var PB_Count = 0;
PB_setMarker = {
handleEvent: function(evt){
/*GM_log(evt.type + " - button: " + evt.button + ", shiftKey: " +
evt.shiftKey + ", nodeName: " + evt.target.nodeName);*/
// ignore links, area
if(document.evaluate("ancestor-or-self::*[@href]", evt.target,
null, 3, null).booleanValue) return;
// ignore form inputs
if(/^(textarea|input|button)$/i .test(evt.target.nodeName)) return;
// check which mouse button
if(evt.button != PB_Prefs.mouse.button) return;
// check modifier keys
for(var meta in PB_Prefs.mouse){
if(meta == 'button') continue;
if(PB_Prefs.mouse[meta] != evt[meta]) return;
}
evt.preventDefault();
evt.stopPropagation();
// check if evt.target has been bookmarked
if(evt.target.hasAttribute('id')){
var pbid = evt.target.id;
// JavaScript 1.6 accessor method
var pbindex = PB_Markers.indexOf(pbid);
if(pbindex != -1){
this.remove(evt.target, pbindex);
return;
}
}
this.add(evt.target);
this.addStyle();
},
add: function(elm){
PB_Count++;
PB_Marker = PB_Markers.length;
if(!elm.hasAttribute('id')){
// set bookmarker id name
var pbid = "Page_Bookmark_" + PB_Count;
elm.id = pbid;
}
PB_Markers.push(elm.id);
elm.className = (elm.hasAttribute('class'))
? elm.className + " Page_Bookmarker_Mark": "Page_Bookmarker_Mark";
},
remove: function(elm, Index){
var pbid = elm.id;
if(pbid.indexOf("Page_Bookmark_") != -1){
elm.removeAttribute('id');
}
if(elm.className == "Page_Bookmarker_Mark"){
elm.removeAttribute('class');
}else{
elm.className = elm.className.replace(" Page_Bookmarker_Mark", "");
}
// If its the last mark, subtract count
if(Index == PB_Markers.length-1) PB_Count--;
PB_Markers.splice(Index, 1);
if(Index <= PB_Marker) PB_Marker--;
},
addStyle: function(){
// So it does not add styles twice
if(document.getElementById('page_bookmarker_styles')) return;
// Make it readable with line breaks
US_addStyleTag("\n" + PB_Prefs.styles.join("\n") + "\n")
.id = "page_bookmarker_styles";
}
}
PB_getMarker = {
handleEvent: function(kyd){
//GM_log("trapped key: " + kyd.charCode + ", shiftKey: " + kyd.shiftKey);
// wrong key
if(kyd.charCode == 0) return true;
// ignore form inputs
if(/^(textarea|input|button)$/i .test(kyd.target.nodeName)) return true;
// Unicode value of any key
switch(kyd.which){
case PB_Prefs.next.key:
if(this.checkMeta(PB_Prefs.next, kyd)) this.next();
break;
case PB_Prefs.prev.key:
if(this.checkMeta(PB_Prefs.prev, kyd)) this.prev();
}
},
checkMeta: function(pref, key){
for(var meta in pref){
if(meta == 'key') continue;
if(pref[meta] != key[meta]) return false;
}
return true;
},
next: function(){
if(PB_Markers.length == 0) return;
PB_Marker++;
if(PB_Marker == PB_Markers.length) PB_Marker = 0;
this.goTo(PB_Markers[PB_Marker]);
},
prev: function(){
if(PB_Markers.length == 0) return;
if(PB_Marker == -1) PB_Marker = PB_Markers.length-1;
this.goTo(PB_Markers[PB_Marker]);
PB_Marker--;
},
goTo: function(Hash){
if(PB_Prefs.replaceHistory){ location.replace("#" + Hash) }
else{ location.hash = Hash }
}
}
document.body.addEventListener("mousedown", PB_setMarker, true);
// Convert key options to char code, if not already
PB_Prefs.next.key = PB_charToCode(PB_Prefs.next.key);
PB_Prefs.prev.key = PB_charToCode(PB_Prefs.prev.key);
function PB_charToCode(Key){
if(typeof Key == 'string'){
// allow Unicode values
if(/^\d\d+$/.test(Key)) return parseInt(Key, 10);
return Key.charCodeAt(0);
}
return Key; // assume its already a number
}
document.addEventListener("keypress", PB_getMarker, true);
// Add a style tag, add css and return element
function US_addStyleTag(css){
var Style = document.createElement('style');
Style.type = 'text/css';
if(document.contentType == "application/xhtml+xml"){
Style.appendChild( document.createCDATASection(css) );
}else{
Style.appendChild( document.createTextNode(css) );
}
// Return element so properties can be added
// Note: Mozilla creates head if it doesnt exist (unless XML)
return (document.getElementsByTagName('head').length)
? document.getElementsByTagName('head').item(0).appendChild(Style): null;
}