By Elad Ossadon
Has no other scripts.
// Author: Elad Ossadon (www.devign.co.il / elado7@gmail.com)
// ==UserScript==
// @name Google Reader Filter
// @namespace devign.co.il
// @description Filters duplicated entries and unwanted content or highlight chosen content based on keywords (with regex support).
// @include http://reader.google.com/reader/*
// @include http://www.google.co.jp/reader/*
// @include https://www.google.co.jp/reader/*
// @include http://www.google.com/reader/*
// @include https://www.google.com/reader/*
// ==/UserScript==
/*
v0.53 - Apr 20, 08
* Fixed minification regexp (added a few characters)
v0.52 - Apr 2, 08
* Fixed some design issues - excluded/highlighted entries doesn't affect the content of the entry (thanks Paul Irish!)
v0.51 - Mar 31, 08
* Fixed minification regexp (old one omitted numbers)
v0.5 - Mar 30, 08
* Fixed some bugs
* Enhanced filter
* UTF-8 characters support
v0.4 - Mar 26, 08
* Added the ability to hide duplicates/excluded entries, new checkboxes added in settings window.
v0.3 - Mar 19, 08
* Duplicates also marked as excluded. Duplicate is an entry whose url or title were already printed.
v0.2 - Mar 16, 08
* Added "Quick Add" window, which lets you add new exclude/highlight to the list from within an entry ([#] button is added to each entry on its right)
* RegExps are compiled only at initialization and after saving, not like before
v0.1 - Mar 8, 08
* First Release
*/
if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}if(typeof value.toJSON==='function'){return stringify(value.toJSON());}a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}return'['+a.join(',')+']';}if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}return'{'+a.join(',')+'}';}}return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}else{delete v[i];}}}}return filter(k,v);}if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}throw new SyntaxError('parseJSON');}};}();}
function addStyleSheet(css) {
var link=document.createElement("link");
link.rel="stylesheet";
link.href="data:text/css,"+escape(css);
document.getElementsByTagName("head")[0].appendChild(link);
}
function findPosition(element) {
var point={x:0,y:0};
var parent=element;
while (parent) {
point.x+=parent.offsetLeft;
point.y+=parent.offsetTop;
parent=parent.offsetParent;
}
return point;
}
function trim(s) {
return s ? s.replace(/^\s+|\s+$/g,"") : "";
}
var GRF={
excludes:[],
highlights:[],
init:function () {
GRF.excludes=JSON.parse(decodeURI(trim(GM_getValue("excludes",JSON.stringify(GRF.excludes)))));
GRF.highlights=JSON.parse(decodeURI(trim(GM_getValue("highlights",JSON.stringify(GRF.highlights)))));
GRF.hideExcluds=+GM_getValue("hideExcluds",0);
GRF.hideDuplicates=+GM_getValue("hideDuplicates",0);
GRF.excludes.sort(GRF._stringSort);
GRF.highlights.sort(GRF._stringSort);
GRF._initInterface();
GRF._setRegExps();
if (GRF.excludes.length || GRF.highlights.length) {
document.body.addEventListener("DOMNodeInserted",GRF.filterEntries,false);
}
},
_setRegExps:function () {
if (GRF.excludes.length) GRF.rxExcludes=GRF._getRegExp(GRF.excludes);
if (GRF.highlights.length) GRF.rxHighlights=GRF._getRegExp(GRF.highlights);
},
// (0) all until 0 (2f) , [0-9], above 9 (3a) to @ (40), [A-Z], above Z (5b) to a (60), [a-z], above z (7b) to european characters (bf), another unicode character
// this regex contains all symbols between 0-255 char codes, such as ~!@#$%^&*()_+- etc in order to replace them with a single space
// that way, both "hello: world!" and "hello.world" become "hello world" and than regex in exclude/highlight stays simple
minifiyRx:/[\u0000-\u002f\u003a-\u0040\u005b-\u0060\u007b-\u00bf\u201d\u202b]+/g,
_getRegExp:function (items) {
return new RegExp("(^| )("+items.join("|")+")($| )","i");
},
_stringSort:function (a,b) { if (a>b)return 1;if (a<b)return -1;return 0; },
_initInterface:function () {
addStyleSheet("\
.filter-settings-button,.filter-settings-window *,.filter-settings-entry-window *{font-family:verdana;font-size:11px;color:#000;}\
.filter-settings-window textarea,.filter-settings-entry-window input[type=text]{font-family:'courier new';border:1px solid #669CB9;}\
\
.filter-settings-button{cursor:pointer;background-color:#ADCBDA;padding:4px;position:absolute;top:30px;right:10px;z-index:1000;}\
.filter-settings-button:hover{background-color:#B46B8F;}\
.filter-settings-window{background-color:#ADCBDA;border:1px solid #669CB9;padding:4px;position:absolute;top:30px;right:10px;z-index:1000;}\
.filter-settings-window label.ta{float:left;width:250px;}\
.filter-settings-window textarea{height:300px;width:250px;}\
\
.filter-settings-entry-window{width:300px;background-color:#ADCBDA;border:1px solid #669CB9;font-size:11px;padding:4px;position:fixed;top:30px;right:10px;z-index:1000;}\
.filter-settings-entry-window input[type=text]{width:300px;}\
\
.filter-settings-window button,.filter-settings-entry-window button{margin-top:5px;margin-right:5px;background-color:#669CB9;color:#fff;font-size:11px;border:1px solid #000;}\
\
.entry-filtered div.collapsed *{color:#BCBCBC!important;}\
.entry-filtered:hover div.collapsed *{color:#6A6A6A!important;}\
\
.entry-highlighted div.collapsed{background-color:#E6EFCF!important;}\
.entry-highlighted div.collapsed *{color:#000!important;background-color:#E6EFCF;}\
\
.entry-duplicate *{color:#C7D0D8!important;}\
\
.filter-configure-entry{background-color:#daa;color:#fff;padding:2px;cursor:pointer;position:absolute;top:0;right:90px}\
");
var div=document.createElement("div");
div.innerHTML="Filter settings";
div.className="filter-settings-button";
div.addEventListener("click",GRF.openSettings,false);
document.body.appendChild(div);
},
_formatListToTextArea:function (list) {
return list.join("\n").replace(/(\r?\n){2,}/,"");
},
openSettings:function () {
if (!GRF._settings) {
var settings=document.createElement("div");
settings.className="filter-settings-window";
settings.innerHTML="<label class='ta'>Excludes</label><label class='ta'>Highlights</label><div style='clear:both'></div>";
var excludeTextarea=document.createElement("textarea");
settings.appendChild(excludeTextarea);
var highlightTextarea=document.createElement("textarea");
settings.appendChild(highlightTextarea);
settings.appendChild(document.createElement("br"));
// hide dups
var hideDuplicates=document.createElement("input");
hideDuplicates.type="checkbox";
hideDuplicates.id="grf-hideDuplicates";
settings.appendChild(hideDuplicates);
var hideDuplicatesLabel=document.createElement("label");
hideDuplicatesLabel.innerHTML="Hide Duplicates"
hideDuplicatesLabel.setAttribute("for","grf-hideDuplicates");
settings.appendChild(hideDuplicatesLabel);
hideDuplicatesLabel.style.paddingRight="20px;";
// hide excluded
var hideExcluds=document.createElement("input");
hideExcluds.id="grf-hideExcluds";
hideExcluds.type="checkbox";
settings.appendChild(hideExcluds);
var hideExcludsLabel=document.createElement("label");
hideExcludsLabel.setAttribute("for","grf-hideExcluds");
hideExcludsLabel.innerHTML="Hide Excluds"
settings.appendChild(hideExcludsLabel);
settings.appendChild(document.createElement("br"));
/// buttons
var update=document.createElement("button");
update.textContent="Update";
update.addEventListener("click",function () {
GRF.saveSettings(excludeTextarea.value,highlightTextarea.value);
settings.style.display="none";
},false);
settings.appendChild(update);
var close=document.createElement("button");
close.textContent="Close";
close.addEventListener("click",function () {
settings.style.display="none";
},false);
settings.appendChild(close);
document.body.appendChild(settings);
// globalize elements
GRF._settings=settings;
GRF._excludeTextarea=excludeTextarea;
GRF._highlightTextarea=highlightTextarea;
GRF._hideDuplicates=hideDuplicates;
GRF._hideExcluds=hideExcluds;
}
GRF._settings.style.display="";
GRF._excludeTextarea.value=GRF._formatListToTextArea(GRF.excludes);
GRF._highlightTextarea.value=GRF._formatListToTextArea(GRF.highlights);
GRF._hideDuplicates.checked=!!GRF.hideDuplicates;
GRF._hideExcluds.checked=!!GRF.hideExcluds;
},
openSettingsForEntry:function (relative,title) {
if (!GRF._settingsForEntry) {
var settingsForEntry=document.createElement("div");
settingsForEntry.className="filter-settings-entry-window";
settingsForEntry.innerHTML="<label>Quick Add</label><div style='clear:both'></div>";
var input=document.createElement("input");
input.type="text";
settingsForEntry.appendChild(input);
settingsForEntry.appendChild(document.createElement("br"));
var excludeRadio=document.createElement("input");
excludeRadio.name="ex"; excludeRadio.type="radio"; excludeRadio.value=1;
excludeRadio.checked=true;
settingsForEntry.appendChild(excludeRadio);
settingsForEntry.appendChild(document.createTextNode("Exclude"));
var highlightRadio=document.createElement("input");
highlightRadio.name="ex"; highlightRadio.type="radio"; highlightRadio.value=2;
settingsForEntry.appendChild(highlightRadio);
settingsForEntry.appendChild(document.createTextNode("Highlight"));
settingsForEntry.appendChild(document.createElement("br"));
var update=document.createElement("button");
update.textContent="Add";
update.addEventListener("click",function () {
var coll;
coll=highlightRadio.checked ? GRF.highlights : GRF.excludes;
coll.push(input.value);
GRF.saveCollections();
settingsForEntry.style.display="none";
},false);
settingsForEntry.appendChild(update);
var close=document.createElement("button");
close.textContent="Close";
close.addEventListener("click",function () {
settingsForEntry.style.display="none";
},false);
settingsForEntry.appendChild(close);
document.body.appendChild(settingsForEntry);
GRF._settingsForEntry=settingsForEntry;
GRF._settingsForEntryInput=input;
}
GRF._settingsForEntry.style.display="";
var point=findPosition(relative);
GRF._settingsForEntry.style.left=(point.x-250)+"px";
var y=point.y+21-document.getElementById("entries").scrollTop;
if (y+GRF._settingsForEntry.offsetHeight>document.documentElement.offsetHeight) {
GRF._settingsForEntry.style.top="auto";
GRF._settingsForEntry.style.bottom=(document.documentElement.offsetHeight-y+10)+"px";
}
else {
GRF._settingsForEntry.style.top=y+"px";
GRF._settingsForEntry.style.bottom="auto";
}
GRF._settingsForEntryInput.value=title;
},
saveSettings:function (excludesString,highlightsString) {
GRF.excludes=excludesString.replace(/\r/,"").split(/\n+/);
GRF.highlights=highlightsString.replace(/\r/,"").split(/\n+/);
GRF.hideExcluds=+GRF._hideExcluds.checked;
GRF.hideDuplicates=+GRF._hideDuplicates.checked;
GM_setValue("hideExcluds",GRF.hideExcluds ? 1 : "");
GM_setValue("hideDuplicates",GRF.hideDuplicates ? 1 : "");
GRF.saveCollections();
},
saveCollections:function () {
GM_setValue("excludes",encodeURI(JSON.stringify(GRF.excludes)));
GM_setValue("highlights",encodeURI(JSON.stringify(GRF.highlights)));
GRF._setRegExps();
},
filterEntries:function (e) {
var element=e.target;
if (element.className!="entry") return;
// reset the dups list when entries inserted again
if (element.parentNode.id=="entries") {
var l=document.getElementById("entries").childNodes.length;
if (l<=2) GRF.list={};
}
var title=element.getElementsByTagName("h2")[0];
var url=element.getElementsByTagName("a")[0].href;
var minifiedTitle=GRF.minifyTitle(title.textContent);
var configure=document.createElement("span");
configure.className="filter-configure-entry";
configure.textContent="#";
element.appendChild(configure,element);
configure.title=minifiedTitle;
configure.addEventListener("click",GRF.configureCurrent,false);
var escapedTitle=encodeURI(minifiedTitle);
var b=false;
if (GRF.list[escapedTitle]/* || GRF.list[url]*/) {
element.className+=" entry-duplicate";
if (GRF.hideDuplicates) element.parentNode.removeChild(element);//element.style.display="none";
return;
}
if (GRF.excludes.length) {
b=GRF.checkEntry(minifiedTitle,element,GRF.rxExcludes,"entry-filtered");
if (GRF.hideExcluds && b) element.parentNode.removeChild(element);//element.style.display="none";
}
if (!b && GRF.highlights.length) {
GRF.checkEntry(minifiedTitle,element,GRF.rxHighlights,"entry-highlighted");
}
GRF.list[escapedTitle]=/*GRF.list[url]=*/true;
},
minifyTitle:function (title) {
return trim(title.replace(GRF.minifiyRx," ").replace(/ +/g," ").toLowerCase());
},
list:{},
configureCurrent:function (e) {
GRF.openSettingsForEntry(e.target,e.target.title);
e.preventDefault();
e.stopPropagation();
},
checkEntry:function (title,element,rx,className) {
if (rx.test(title)) {
element.className+=" "+className;
return true;
}
return false;
}
};
addEventListener("load",function () {
GRF.init();
},false);