Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Thanks to Foxfirefey for Dreamwidth Dynamic Reading Page Expand/Collapse
- * on which this is somewhat based.
- */
- // ==UserScript==
- // @name DW Entry Screening
- // @namespace wiring.io
- // @version 0.1
- // @description Cuts entries based on keywords/journals (present or absent). Works with Core2 styles.
- // @include http://*.dreamwidth.org/*
- // @exclude http://www.dreamwidth.org/*
- // @exclude http://*.dreamwidth.org/manage*
- // @exclude http://*.dreamwidth.org/inbox*
- // @exclude http://*.dreamwidth.org/update*
- // @exclude http://*.dreamwidth.org/profile*
- // @exclude http://*.dreamwidth.org/calendar*
- // @exclude http://*.dreamwidth.org/tag*
- // @exclude http://*.dreamwidth.org/*.html*
- // @copyright 2011+, Lian (http://wiring.io/)
- // @require http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
- // ==/UserScript==
- /**
- * TODO/Known Bugs:
- * - UI/UX improvements?
- * - multiple filtering-- order of action: whitelist > blacklist, don't cut/collapse if already hidden, etc
- * - BUG: fix cut text display so doesn't say entry contains if mode is set to include
- */
- (function(){
- /* ENUMS ---------------*/
- var NodeState = {
- EXPANDED : { name: "expanded", value: 0 },
- COLLAPSED : { name: "collapsed", value: 1 },
- HIDDEN : { name: "hidden", value: 2 },
- CUT : { name: "cut", value: 3 }
- };
- var ListType = {
- KEYWORDS : { name: "Keywords", value: 0 },
- USERS : { name: "Users", value: 1 },
- COMMUNITIES : { name: "Communities", value: 2 }
- };
- var FilterType = {
- INCLUDE : { name: "Include", value: 0 },
- EXCLUDE : { name: "Exclude", value: 1 }
- };
- /* SETTINGS -----------*/
- // default state of all entries-- if you want to change this, you can start
- // with all entries collapsed/hidden/cut and whitelist the ones you want visible/open
- var globalState = NodeState.EXPANDED;
- // put classes of things you'd like to be hidden in 'collapsed' state here
- var collapseables = new Array("entry-content", "metadata", "userpic", "entry-management-links");
- // fill in items with words/usernames you want to filter by
- // if you use EXCLUDE, the state will apply to whatever you list in items
- // if you use INCLUDE, the state will apply to everything BUT those items
- // you can add more filters or remove the examples you're not using
- var filters = [
- {
- items: ["anything_you", "want_warning_of"],
- listType: ListType.KEYWORDS,
- filterType: FilterType.EXCLUDE,
- state: NodeState.CUT
- },
- {
- items: ["anything_you", "don't_want_to_see"],
- listType: ListType.KEYWORDS,
- filterType: FilterType.EXCLUDE,
- state: NodeState.COLLAPSE
- },
- {
- items: ["individual_name"],
- listType: ListType.USERS,
- filterType: FilterType.EXCLUDE,
- state: NodeState.COLLAPSED
- },
- {
- items: ["community_name"],
- listType: ListType.COMMUNITIES,
- filterType: FilterType.EXCLUDE,
- state: NodeState.COLLAPSED
- }
- ];
- /* MAIN ------------*/
- var Utilities = function() {
- };
- Utilities.prototype = {
- getNodeState:
- function (value) {
- switch(value) {
- case 0:
- return NodeState.EXPANDED;
- case 1:
- return NodeState.COLLAPSED;
- case 2:
- return NodeState.HIDDEN;
- case 3:
- return NodeState.CUT;
- }
- }
- };
- // XPath Constructor
- var XPath = function() {
- this._path = "//div[@class='entry-content']";
- this._resultType = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
- this.init();
- };
- XPath.prototype = {
- _path: null,
- _resultType: null,
- _result: null,
- _resultArray: null,
- init:
- function () {
- this._result = this.getResult(this._path, document, this._resultType);
- this._resultArray = this.getResultArray(this._result);
- },
- getResult:
- function (path, scope, resultType) {
- return document.evaluate(path, scope, null, resultType, null);
- },
- getResultArray:
- function (result) {
- var temp = result.iterateNext(),
- array = [];
- while(temp) {
- array.push(temp);
- temp = result.iterateNext();
- }
- return array;
- }
- };
- // Generic Filter object
- var Filter = function() {
- this._xpath = new XPath();
- this._utils = new Utilities();
- this.createEntryList();
- };
- Filter.prototype = {
- _xpath: null,
- _entryList: null,
- _savedEntryList: null,
- createEntryList:
- function () {
- this._entryList = {};
- this._savedEntryList = {};
- for (var i = 0; i < this._xpath._resultArray.length; i++) {
- var entry = new Entry(this._xpath._resultArray[i]);
- var storedValue = GM_getValue(entry._uid);
- if (storedValue) {
- entry.setState(this._utils.getNodeState(storedValue.value));
- this._savedEntryList[entry._uid] = entry;
- } else {
- entry.setState(globalState);
- }
- this._entryList[entry._uid] = entry;
- }
- },
- match:
- function (listType, type, nodeState, items) {
- var matches = {};
- for (var x in this._entryList) {
- var entry = this._entryList[x];
- var matchPattern = null;
- var entryMatches = [];
- for (var j = 0, len = items.length; j < len; j++) {
- switch(listType)
- {
- case "Keywords":
- matchPattern = entry._innerHtml.match(new RegExp(items[j], "i"));
- if (matchPattern) { console.log("keyword: " + items[j]+ " (" + entry._uid + ")");}
- break;
- case "Users":
- matchPattern = entry.matchPoster(items[j]);
- if (matchPattern) { console.log("user: " + items[j]+ " (" + entry._uid + ")");}
- break;
- case "Communities":
- matchPattern = entry.matchJournal(items[j]);
- if (matchPattern) { console.log("comm: " + items[j] + " (" + entry._uid + ")");}
- break;
- }
- matchPattern = (type == FilterType.EXCLUDE) ? matchPattern : !matchPattern;
- if(matchPattern) {
- entry._matchedArray.push(items[j]);
- entryMatches.push(items[j]); // todo: do I need both of these?
- }
- if ((entryMatches.length > 0) && (j == len-1) && !matches[entry._uid]) {
- entry.setState(nodeState);
- matches[entry._uid] = entry;
- console.log(entry);
- }
- }
- }
- return matches;
- }
- };
- // Entry constructor
- var Entry = function(content, state) {
- this._content = content;
- this._state = state;
- this._node = this.getEntry();
- this._innerHtml = this._content.innerHTML;
- this._url = this.getEntryLink();
- this._matchedArray = [];
- this._matchedString = "";
- this._poster = this.getPoster();
- this._journal = this.getJournal();
- this._uid = this.getEntryId();
- this._hasLinks = this.insertInteraction();
- };
- Entry.prototype = {
- _content: null,
- _node: null,
- _state: null,
- _url: null,
- _matchedArray: null,
- _matchedString: null,
- _uid: null,
- _innerHtml: null,
- _poster: null,
- _journal: null,
- _hasLinks: false,
- setMatchedString:
- function() {
- for (var i = 0; i < this._matchedArray.length; i++) {
- var connector = "";
- if (i !== 0) { connector = ", "; }
- this._matchedString += connector + this._matchedArray[i];
- }
- },
- getEntry:
- function() {
- return $(this._content).parents(".entry-wrapper");
- },
- matchPoster:
- function(poster) {
- return this._poster == poster;
- //return this._poster.match(new RegExp(poster + "$", "i"));
- },
- matchJournal:
- function(journal) {
- return this._journal == journal;
- //return this._journal.match(new RegExp(journal + "$", "i"));
- },
- getPoster:
- function() {
- var classes = this._node.attr("class");
- var regex = new RegExp("poster-[a-z]*", "i");
- return classes.match(regex)[0].split("-")[1];
- },
- getJournal:
- function() {
- var classes = this._node.attr("class");
- console.log(this._journal);
- var regex = new RegExp(/journal-[a-z0-9\_]+/g);
- var jMatches = classes.match(regex);
- for (var i = 0, len = jMatches.length; i < len; i++) {
- if (jMatches[i] !== "journal-type") {
- return jMatches[i].split("-")[1];
- }
- }
- return false;
- },
- getEntryLink:
- function() {
- return this._node.find(".entry-permalink a").attr("href");
- },
- getEntryId:
- function() {
- return this._poster + this._node.attr("id").match(new RegExp("[0-9]*$"))[0];
- },
- setState:
- function(state) {
- switch(state){
- case NodeState.CUT:
- this.cut();
- break;
- case NodeState.COLLAPSED:
- this.collapse();
- break;
- case NodeState.HIDDEN:
- this.hide();
- break;
- default:
- this.expand();
- break;
- }
- },
- // sets up the links on the title of the entry to manually collapse/expand/hide an entry: mostly from foxfirefey's code
- insertInteraction:
- function() {
- var that = this;
- if (!this._hasLinks) {
- // This is so people can customize it to be [] or {}
- var link_left_bracket = "[";
- var link_right_bracket = "]";
- // This is so people can customize to say "collapse" or "expand" or "delete"
- var link_collapse = "-";
- var link_expand = "+";
- var link_hide = "x";
- // Create a span containing the collapse and hide link
- // foxfirefey's code:
- var span, collapse_link, collapse_link_text, hide_link, state_link_text;
- var link_span = document.createElement("span");
- link_span.className = "entryCollapseState";
- link_span.id = "entryCollapseState-" + this._uid;
- var state_link = document.createElement("a");
- state_link.href = "#";
- // Figure out which action link to create -- collapse or expand
- if ( this._state == NodeState.COLLAPSED ) {
- state_link.addEventListener('click', function(event) {
- event.stopPropagation(); event.preventDefault();
- GM_deleteValue(that._uid);
- that.expand();
- }, true);
- state_link_text = link_expand;
- state_link.className = "entry-expand-link";
- state_link.title = "Expand entry";
- }
- else {
- state_link.addEventListener('click', function(event) {
- GM_setValue(that._uid, NodeState.COLLAPSED);
- that.collapse(); event.stopPropagation(); event.preventDefault(); }, true);
- state_link_text = link_collapse;
- state_link.className = "entry-collapse-link";
- state_link.title = "Collapse entry";
- }
- state_link.appendChild( document.createTextNode(state_link_text) );
- link_span.appendChild( document.createTextNode(" "));
- link_span.appendChild( document.createTextNode(link_left_bracket) );
- link_span.appendChild( state_link );
- link_span.appendChild( document.createTextNode(link_right_bracket ));
- hide_link = document.createElement("a");
- hide_link.href = "#";
- hide_link.addEventListener('click', function(event) {
- GM_setValue(that._uid, NodeState.HIDDEN);
- that.hide(); event.stopPropagation(); event.preventDefault(); }, true);
- hide_link.title = "Hide entry";
- hide_link.appendChild( document.createTextNode(link_hide) );
- link_span.appendChild( document.createTextNode(" "));
- link_span.appendChild( document.createTextNode(link_left_bracket) );
- link_span.appendChild( hide_link );
- link_span.appendChild( document.createTextNode(link_right_bracket ));
- this._node.find(".entry-title").append( link_span );
- this._hasLinks = true;
- } else {
- this._node.find("span.entryCollapseState").remove();
- this._hasLinks = false;
- this.insertInteraction();
- }
- return this._hasLinks;
- },
- // uses a DW-esque cut to cut an entry
- // can't use an actual dw cut atm ($.dw.cuttag)
- cut:
- function() {
- this._state = NodeState.CUT;
- this.setMatchedString();
- this._content.innerHTML = '<span class="cuttag_container"><span style="display: inline;" id="span-cuttag_autogen_'+this._uid+'" class="cuttag"><a href="#" id="cuttag_autogen_'+this._uid+'" class="cuttag-action cuttag-action-before"><img style="border:0;" aria-controls="div-cuttag_autogen_'+this._uid+'" src="http://www.dreamwidth.org/img/collapse.gif" alt="Expand" title="Expand"></a></span><b>( <a href="'+this._url+'">entry text contains: '+ this._matchedString +'</a> )</b><div class="keyword-hidden-entry" style="display: none;">' + this._content.innerHTML + '</div><div style="display: none;" id="div-cuttag_autogen_'+this._uid+'" aria-live="assertive"></div></span>';
- this.initCut();
- },
- // make the button clickable
- initCut:
- function() {
- var linkButton = $(this._content).find("a.cuttag-action-before");
- var hiddenContent = $(this._content).find("div.keyword-hidden-entry");
- linkButton.bind("click", function(e) {
- e.preventDefault();
- var isHidden = ($(this._content).find(".keyword-hidden-entry:hidden").length > 0);
- var buttonState = isHidden ? "expand" : "collapse";
- linkButton.find("img").attr("src", "http://www.dreamwidth.org/img/" + buttonState + ".gif");
- hiddenContent.toggle();
- });
- },
- // completely hides an entry from view on the page
- hide:
- function() {
- this._state = NodeState.HIDDEN;
- this._node.hide();
- },
- // hides "collapseable" values in an entry instead of making a cut-- smaller footprint
- collapse:
- function() {
- this._state = NodeState.COLLAPSED;
- for ( var collapse_index in collapseables ) {
- var collapse = this._node.find("." + collapseables[collapse_index]);
- if (collapse.length > 0) {
- collapse.hide();
- }
- }
- this.insertInteraction();
- },
- // expand collapsed entries
- expand:
- function() {
- this._state = NodeState.EXPANDED;
- for ( var expand_index in collapseables ) {
- var expand = this._node.find("." + collapseables[expand_index]);
- if( expand.length > 0 ) {
- expand[0].style.display = '';
- }
- }
- this.insertInteraction();
- }
- };
- function clearCollapsed() {
- var listVals = GM_listValues();
- for (var i = 0, len = listVals.length; i < len; i++) {
- var val = listVals[i];
- var state = GM_getValue(val);
- if (state.value == NodeState.COLLAPSED.value) {
- GM_deleteValue(val);
- }
- }
- GM_notification("Cleared collapsed. Please refresh to see changes.");
- }
- function clearHidden() {
- var listVals = GM_listValues();
- for (var i = 0, len = listVals.length; i < len; i++) {
- var val = listVals[i];
- var state = GM_getValue(val);
- if (state.value == NodeState.HIDDEN.value) {
- GM_deleteValue(val);
- }
- }
- GM_notification("Cleared hidden. Please refresh to see changes.");
- }
- function clearAll() {
- var listVals = GM_listValues();
- for (var i = 0, len = listVals.length; i < len; i++) {
- var val = listVals[i];
- GM_deleteValue(val);
- }
- GM_notification("Cleared all. Please refresh to see changes.");
- }
- // Object to actually instantiate and pull everything together
- var Init = function() {
- var filter = new Filter();
- GM_registerMenuCommand("Clear stored hidden entries.", clearHidden);
- GM_registerMenuCommand("Clear stored collapsed entries.", clearCollapsed);
- GM_registerMenuCommand("Clear all stored entries.", clearAll);
- for (var f = 0, len = filters.length; f < len; f++) {
- var current = filters[f];
- filter.match(current.listType.name, current.filterType, current.state, current.items);
- }
- };
- Init();
- })();
Advertisement
Add Comment
Please, Sign In to add comment