diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..7fb690e6fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +IE/Debug/* +IE/Release/* +Chrome.pem +XPI/reddit_res.xpi + +/Chrome/*.js +/Chrome/*.css +!/Chrome/background.js +/RES.safariextension/*.js +/RES.safariextension/*.css +/Opera/includes/*.js +/Opera/includes/*.css +/Opera/modules/*.js +/XPI/data/*.js +/XPI/data/*.css +!/XPI/lib/main.js +!/lib/* +/commentBoxes.css +/nightmode.css +/res.css + + +.DS_Store diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000000..0587ddbc8f --- /dev/null +++ b/BUILD.md @@ -0,0 +1,17 @@ +### Building release versions of the extension ### + +This document is here for RES developer reference/testing. Please do not distribute your own binaries unofficially - see README.md for an explanation as to why. Thanks! + +**Chrome** + 1. Go to ``Settings->Extensions`` and choose ``Pack extension``. Choose the ``Chrome`` folder for RES. You can also choose to sign the extension with a private key. + 2. This will generate a ``.crx`` and ``.pem`` file for your extension that you can install by dropping the ``.crx`` file in ``Chrome``. + +**Firefox** + 1. Make sure you have the addons SDK installed as described in the development section. + 2. In your terminal, ``cd`` to the ``XPI`` folder and run ``cfx xpi``. This should build an ``.xpi`` file that you can use to install RES. + +**Opera** + 1. Opera extensions are simply zip files. So all you need to do is zip up the contents of the ``Opera`` folder, but not the folder itself. So the zip should contain everything inside the ``Opera`` folder. Rename the ``.zip`` file to have the extension ``.oex`` instead. See [here](http://dev.opera.com/articles/view/opera-extensions-hello-world/#packaging) for more information. + +**Safari** + 1. Navigate to the ``Extension Builder`` panel as described in the development instructions. Assuming you have followed those instructions and installed RES, you can now choose ``build`` in the top right. This will generate a ``.safariextz`` file (signed by your certificate) that you can use to install RES. diff --git a/Chrome/background.html b/Chrome/background.html deleted file mode 100644 index 7111fefd93..0000000000 --- a/Chrome/background.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Chrome/background.js b/Chrome/background.js new file mode 100644 index 0000000000..dd37fbb8f6 --- /dev/null +++ b/Chrome/background.js @@ -0,0 +1,245 @@ +/* + + RES is released under the GPL. However, I do ask a favor (obviously I don't/can't require it, I ask out of courtesy): + + Because RES auto updates and is hosted from a central server, I humbly request that if you intend to distribute your own + modified Reddit Enhancement Suite, you name it something else and make it very clear to your users that it's your own + branch and isn't related to mine. + + RES is updated very frequently, and I get lots of tech support questions/requests from people on outdated versions. If + you're distributing RES via your own means, those recipients won't always be on the latest and greatest, which makes + it harder for me to debug things and understand (at least with browsers that auto-update) whether or not people are on + a current version of RES. + + I can't legally hold you to any of this - I'm just asking out of courtesy. + + Thanks, I appreciate your consideration. Without further ado, the all-important GPL Statement: + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +XHRCache = { + forceCache: false, + capacity: 250, + entries: {}, + count: 0, + check: function(key) { + if (key in this.entries) { +// console.count("hit"); + this.entries[key].hits++; + return this.entries[key].data; + } else { +// console.count("miss"); + return null; + } + }, + add: function(key, value) { + if (key in this.entries) { + return; + } else { +// console.count("add"); + this.entries[key] = {data: value, timestamp: new Date(), hits: 1}; + this.count++; + } + if (this.count > this.capacity) { + this.prune(); + } + }, + prune: function() { + var now = new Date(); + var bottom = []; + for (var key in this.entries) { +// if (this.entries[key].hits == 1) { +// delete this.entries[key]; +// this.count--; +// continue; +// } + + //Weight by hits/age which is similar to reddit's hit/controversial sort orders + bottom.push({ + key: key, + weight: this.entries[key].hits/(now - this.entries[key].timestamp) + }); + } + bottom.sort(function(a,b){return a.weight-b.weight;}); + var count = this.count - Math.floor(this.capacity / 2); + for (var i = 0; i < count; i++) { + delete this.entries[bottom[i].key]; + this.count--; + } +// console.count("prune"); + }, + clear: function() { + this.entries = {}; + this.count = 0; + } +}; + +chrome.extension.onMessage.addListener( + function(request, sender, sendResponse) { + switch(request.requestType) { + case 'deleteCookie': + // Get chrome cookie handler + if (!chrome.cookies) { + chrome.cookies = chrome.experimental.cookies; + } + chrome.cookies.remove({'url': 'http://reddit.com', 'name': request.cname}); + break; + case 'GM_xmlhttpRequest': + if (request.aggressiveCache || XHRCache.forceCache) { + var cachedResult = XHRCache.check(request.url); + if (cachedResult) { + sendResponse(cachedResult); + return; + } + } + var xhr = new XMLHttpRequest(); + xhr.open(request.method, request.url, true); + if (request.method == "POST") { + xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + xhr.onreadystatechange = function(a) { + if (xhr.readyState == 4) { + //Only store `status` and `responseText` fields + var response = {status: xhr.status, responseText: xhr.responseText}; + sendResponse(response); + //Only cache on HTTP OK and non empty body + if ((request.aggressiveCache || XHRCache.forceCache) && (xhr.status == 200 && xhr.responseText)) { + XHRCache.add(request.url, response); + } + } + }; + xhr.send(request.data); + return true; + break; + case 'singleClick': + var button = !((request.button == 1) || (request.ctrl == 1)); + // Get the selected tab so we can get the index of it. This allows us to open our new tab as the "next" tab. + var newIndex = sender.tab.index+1; + // handle requests from singleClick module + if (request.openOrder == 'commentsfirst') { + // only open a second tab if the link is different... + if (request.linkURL != request.commentsURL) { + chrome.tabs.create({url: request.commentsURL, selected: button, index: newIndex, openerTabId: sender.tab.id}); + } + chrome.tabs.create({url: request.linkURL, selected: button, index: newIndex+1, openerTabId: sender.tab.id}); + } else { + chrome.tabs.create({url: request.linkURL, selected: button, index: newIndex, openerTabId: sender.tab.id}); + // only open a second tab if the link is different... + if (request.linkURL != request.commentsURL) { + chrome.tabs.create({url: request.commentsURL, selected: button, index: newIndex+1, openerTabId: sender.tab.id}); + } + } + sendResponse({status: "success"}); + break; + case 'keyboardNav': + var button = !(request.button == 1); + // handle requests from keyboardNav module + thisLinkURL = request.linkURL; + if (thisLinkURL.toLowerCase().substring(0,4) != 'http') { + (thisLinkURL.substring(0,1) == '/') ? thisLinkURL = 'http://www.reddit.com' + thisLinkURL : thisLinkURL = location.href + thisLinkURL; + } + // Get the selected tab so we can get the index of it. This allows us to open our new tab as the "next" tab. + var newIndex = sender.tab.index+1; + chrome.tabs.create({url: thisLinkURL, selected: button, index: newIndex, openerTabId: sender.tab.id}); + sendResponse({status: "success"}); + break; + case 'openLinkInNewTab': + var focus = (request.focus === true); + // handle requests from keyboardNav module + thisLinkURL = request.linkURL; + if (thisLinkURL.toLowerCase().substring(0,4) != 'http') { + (thisLinkURL.substring(0,1) == '/') ? thisLinkURL = 'http://www.reddit.com' + thisLinkURL : thisLinkURL = location.href + thisLinkURL; + } + // Get the selected tab so we can get the index of it. This allows us to open our new tab as the "next" tab. + var newIndex = sender.tab.index+1; + chrome.tabs.create({url: thisLinkURL, selected: focus, index: newIndex, openerTabId: sender.tab.id}); + sendResponse({status: "success"}); + break; + case 'compareVersion': + var xhr = new XMLHttpRequest(); + xhr.open("GET", request.url, true); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + // JSON.parse does not evaluate the attacker's scripts. + var resp = JSON.parse(xhr.responseText); + sendResponse(resp); + } + }; + xhr.send(); + return true; + break; + case 'loadTweet': + var xhr = new XMLHttpRequest(); + xhr.open("GET", request.url, true); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + // JSON.parse does not evaluate the attacker's scripts. + var resp = JSON.parse(xhr.responseText); + sendResponse(resp); + } + }; + xhr.send(); + return true; + break; + case 'getLocalStorage': + sendResponse(localStorage); + break; + case 'saveLocalStorage': + for (var key in request.data) { + localStorage.setItem(key,request.data[key]); + } + localStorage.setItem('importedFromForeground',true); + sendResponse(localStorage); + break; + case 'localStorage': + switch (request.operation) { + case 'getItem': + sendResponse({status: true, value: localStorage.getItem(request.itemName)}); + break; + case 'removeItem': + localStorage.removeItem(request.itemName); + sendResponse({status: true, value: null}); + break; + case 'setItem': + localStorage.setItem(request.itemName, request.itemValue); + sendResponse({status: true, value: null}); + var thisTabID = sender.tab.id; + chrome.tabs.query({}, function(tabs){ + for (var i = 0; i < tabs.length; i++) { + if (thisTabID != tabs[i].id) { + chrome.tabs.sendMessage(tabs[i].id, { requestType: "localStorage", itemName: request.itemName, itemValue: request.itemValue }); + } + } + }); + break; + } + break; + case 'addURLToHistory': + chrome.history.addUrl({url: request.url}); + break; + case 'XHRCache': + switch (request.operation) { + case 'clear': + XHRCache.clear(); + break; + } + break; + default: + sendResponse({status: "unrecognized request type"}); + break; + } + } +); diff --git a/Chrome/icon128.png b/Chrome/icon128.png index 11a223d02a..ce1db3b43b 100644 Binary files a/Chrome/icon128.png and b/Chrome/icon128.png differ diff --git a/Chrome/icon48.png b/Chrome/icon48.png index d51a6c0b5f..c9cb7661ff 100644 Binary files a/Chrome/icon48.png and b/Chrome/icon48.png differ diff --git a/Chrome/jquery-1.6.4.min.js b/Chrome/jquery-1.6.4.min.js deleted file mode 100644 index 628ed9b316..0000000000 --- a/Chrome/jquery-1.6.4.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ -(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/Chrome/manifest.json b/Chrome/manifest.json index ae4bf7ca40..91fd7ecfe2 100644 --- a/Chrome/manifest.json +++ b/Chrome/manifest.json @@ -1,9 +1,13 @@ { "name": "Reddit Enhancement Suite", - "version": "4.0.2", + "version": "4.2.0.2", + "manifest_version": 2, + "minimum_chrome_version": "20.0", "description": "Reddit Enhancement Suite - a group of enhancements for browsing Reddit", - "update_url": "http://redditenhancementsuite.com/update-chrome.php", - "background_page": "background.html", + "background": { + "scripts": ["background.js"] + }, + "homepage_url": "http://redditenhancementsuite.com", "content_scripts": [ { "matches": [ @@ -14,7 +18,22 @@ "http://*.reddit.com/*", "https://*.reddit.com/*" ], - "js": ["reddit_enhancement_suite.user.js", "jquery-1.6.4.min.js"] + "js": [ + "jquery-1.9.1.min.js", + "guiders-1.2.8.js", + "jquery.dragsort-0.4.3.min.js", + "jquery-fieldselection.min.js", + "tinycon.js", + "jquery.tokeninput.js", + "snuownd.js", + "reddit_enhancement_suite.user.js" + ], + "css": [ + "nightmode.css", + "commentBoxes.css", + "res.css" + ], + "run_at": "document_start" } ], "icons": { @@ -22,6 +41,7 @@ "128": "icon128.png" }, "permissions": [ + "cookies", "tabs", "history", "http://redditenhancementsuite.com/", @@ -36,6 +56,9 @@ "http://min.us/api/*", "http://*.flickr.com/photos/*", "http://img.photobucket.com/*", - "http://gdata.youtube.com/*" + "http://imgclean.com/*", + "http://gdata.youtube.com/*", + "http://backend.deviantart.com/oembed?url=*", + "http://api.tumblr.com/v2/blog/*/posts?api_key=*&id=*" ] -} \ No newline at end of file +} diff --git a/Chrome/reddit_enhancement_suite.user.js b/Chrome/reddit_enhancement_suite.user.js deleted file mode 100644 index 182115f927..0000000000 --- a/Chrome/reddit_enhancement_suite.user.js +++ /dev/null @@ -1,17361 +0,0 @@ -// ==UserScript== -// @name Reddit Enhancement Suite -// @namespace http://reddit.honestbleeps.com/ -// @description A suite of tools to enhance reddit... -// @author honestbleeps -// @include http://redditenhancementsuite.com/* -// @include http://reddit.honestbleeps.com/* -// @include http://reddit.com/* -// @include https://reddit.com/* -// @include http://*.reddit.com/* -// @include https://*.reddit.com/* -// ==/UserScript== - -var RESVersion = "4.0.2"; - -/* - Reddit Enhancement Suite - a suite of tools to enhance Reddit - Copyright (C) 2010-2011 - honestbleeps (steve@honestbleeps.com) - - RES is released under the GPL. However, I do ask a favor (obviously I don't/can't require it, I ask out of courtesy): - - Because RES auto updates and is hosted from a central server, I humbly request that if you intend to distribute your own - modified Reddit Enhancement Suite, you name it something else and make it very clear to your users that it's your own - branch and isn't related to mine. - - RES is updated very frequently, and I get lots of tech support questions/requests from people on outdated versions. If - you're distributing RES via your own means, those recipients won't always be on the latest and greatest, which makes - it harder for me to debug things and understand (at least with browsers that auto-update) whether or not people are on - a current version of RES. - - I can't legally hold you to any of this - I'm just asking out of courtesy. - - Thanks, I appreciate your consideration. Without further ado, the all-important GPL Statement: - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -*/ - -var tokenizeCSS = 'ul.token-input-list-facebook { overflow: hidden; height: auto !important; height: 1%; width: 400px; border: 1px solid #8496ba; cursor: text; font-size: 12px; font-family: Verdana; min-height: 1px; z-index: 1010; margin: 0; padding: 0; background-color: #fff; list-style-type: none; clear: left; }'; -tokenizeCSS += 'ul.token-input-list-facebook li input { border: 0; width: 100px; padding: 3px 8px; background-color: white; margin: 2px 0; -webkit-appearance: caret; }'; -tokenizeCSS += 'li.token-input-token-facebook { overflow: hidden; height: auto !important; height: 15px; margin: 3px; padding: 1px 3px; background-color: #eff2f7; color: #000; cursor: default; border: 1px solid #ccd5e4; font-size: 11px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; float: left; white-space: nowrap; }'; -tokenizeCSS += 'li.token-input-token-facebook p { display: inline; padding: 0; margin: 0;}'; -tokenizeCSS += 'li.token-input-token-facebook span { color: #a6b3cf; margin-left: 5px; font-weight: bold; cursor: pointer;}'; -tokenizeCSS += 'li.token-input-selected-token-facebook { background-color: #5670a6; border: 1px solid #3b5998; color: #fff;}'; -tokenizeCSS += 'li.token-input-input-token-facebook { float: left; margin: 0; padding: 0; list-style-type: none;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook { position: absolute; width: 400px; background-color: #fff; overflow: hidden; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; cursor: default; font-size: 11px; font-family: Verdana; z-index: 1001; }'; -tokenizeCSS += 'div.token-input-dropdown-facebook p { margin: 0; padding: 5px; font-weight: bold; color: #777;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul { margin: 0; padding: 0;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul li { background-color: #fff; padding: 3px; margin: 0; list-style-type: none;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook { background-color: #fff;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook { background-color: #fff;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul li em { font-weight: bold; font-style: normal;}'; -tokenizeCSS += 'div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook { background-color: #3b5998; color: #fff;}'; - - -var guidersCSS = '.guider { background: #FFF; border: 1px solid #666; font-family: arial; position: absolute; outline: none; z-index: 100000005 !important; padding: 4px 12px; width: 500px; z-index: 100; -moz-box-shadow: 0 0px 8px #111; -webkit-box-shadow: 0 0px 8px #111; box-shadow: 0 0px 8px #111; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px;}'; -guidersCSS += '.guider_buttons { height: 36px; position: relative; width: 100%; }'; -guidersCSS += '.guider_content { position: relative; }'; -guidersCSS += '.guider_description { margin-bottom: 10px; }'; -guidersCSS += '.guider_content h1 { color: #1054AA; float: left; font-size: 21px; }'; -guidersCSS += '.guider_close { float: right; padding: 10px 0 0; }'; -// guidersCSS += '.x_button { background-image: url(\'x_close_button.jpg\'); cursor: pointer; height: 13px; width: 13px; }'; -guidersCSS += '.x_button { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/4QOzRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAcAAAAcgEyAAIAAAAUAAAAjodpAAQAAAABAAAApAAAANAACvyAAAAnEAAK/IAAACcQQWRvYmUgUGhvdG9zaG9wIENTNCBXaW5kb3dzADIwMTA6MDk6MjQgMDg6MzY6NDEAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADaADAAQAAAABAAAADQAAAAAAAAAGAQMAAwAAAAEABgAAARoABQAAAAEAAAEeARsABQAAAAEAAAEmASgAAwAAAAEAAgAAAgEABAAAAAEAAAEuAgIABAAAAAEAAAJ9AAAAAAAAAEgAAAABAAAASAAAAAH/2P/gABBKRklGAAECAABIAEgAAP/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgADQANAwEiAAIRAQMRAf/dAAQAAf/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A74ehRj023172WNEODju36n3S76L0Q4p9RrdjfUNbnlm522Q5nt3bv3Hbd6jiueG17qqi70fabLHAbPz4b6Lmf8aoF7oafSb6PpOgeo/6G9n53o7/AE/7P8yip//Z/+0IRFBob3Rvc2hvcCAzLjAAOEJJTQQlAAAAAAAQAAAAAAAAAAAAAAAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQABAEgAAAABAAE4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAAAHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAAAAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4QklNBBoAAAAAA0kAAAAGAAAAAAAAAAAAAAANAAAADQAAAAoAVQBuAHQAaQB0AGwAZQBkAC0AMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAADQAAAA0AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAAA0AAAAAUmdodGxvbmcAAAANAAAABnNsaWNlc1ZsTHMAAAABT2JqYwAAAAEAAAAAAAVzbGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAAAAAAAAZvcmlnaW5lbnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVlbnVtAAAACkVTbGljZVR5cGUAAAAA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bnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNCBXaW5kb3dzIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMC0wOS0yNFQwODozNjo0MS0wNTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxMC0wOS0yNFQwODozNjo0MS0wNTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTAtMDktMjRUMDg6MzY6NDEtMDU6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxQ0Q5QUNCNzQ4QzdERjExOUMyQkU4QkIzMTY5NzZDMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxQUQ5QUNCNzQ4QzdERjExOUMyQkU4QkIzMTY5NzZDMCIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjFDRDlBQ0I3NDhDN0RGMTE5QzJCRThCQjMxNjk3NkMwIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiIHRpZmY6T3JpZW50YXRpb249IjEiIHRpZmY6WFJlc29sdXRpb249IjcyMDAwMC8xMDAwMCIgdGlmZjpZUmVzb2x1dGlvbj0iNzIwMDAwLzEwMDAwIiB0aWZmOlJlc29sdXRpb25Vbml0PSIyIiB0aWZmOk5hdGl2ZURpZ2VzdD0iMjU2LDI1NywyNTgsMjU5LDI2MiwyNzQsMjc3LDI4NCw1MzAsNTMxLDI4MiwyODMsMjk2LDMwMSwzMTgsMzE5LDUyOSw1MzIsMzA2LDI3MCwyNzEsMjcyLDMwNSwzMTUsMzM0MzI7NEZDNkYxNUZCODNCMjY3MjY4NzRCNjRFRTEzRkY2QjgiIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSIxMyIgZXhpZjpQaXhlbFlEaW1lbnNpb249IjEzIiBleGlmOkNvbG9yU3BhY2U9IjEiIGV4aWY6TmF0aXZlRGlnZXN0PSIzNjg2NCw0MDk2MCw0MDk2MSwzNzEyMSwzNzEyMiw0MDk2Miw0MDk2MywzNzUxMCw0MDk2NCwzNjg2NywzNjg2OCwzMzQzNCwzMzQzNywzNDg1MCwzNDg1MiwzNDg1NSwzNDg1NiwzNzM3NywzNzM3OCwzNzM3OSwzNzM4MCwzNzM4MSwzNzM4MiwzNzM4MywzNzM4NCwzNzM4NSwzNzM4NiwzNzM5Niw0MTQ4Myw0MTQ4NCw0MTQ4Niw0MTQ4Nyw0MTQ4OCw0MTQ5Miw0MTQ5Myw0MTQ5NSw0MTcyOCw0MTcyOSw0MTczMCw0MTk4NSw0MTk4Niw0MTk4Nyw0MTk4OCw0MTk4OSw0MTk5MCw0MTk5MSw0MTk5Miw0MTk5Myw0MTk5NCw0MTk5NSw0MTk5Niw0MjAxNiwwLDIsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMjAsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMzA7NkFFQjM0Q0IwNUE5MkY5RjlCMEU2RjQ1NTQxOUVCRkUiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjFDRDlBQ0I3NDhDN0RGMTE5QzJCRThCQjMxNjk3NkMwIiBzdEV2dDp3aGVuPSIyMDEwLTA5LTI0VDA4OjM2OjQxLTA1OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M0IFdpbmRvd3MiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/eHBhY2tldCBlbmQ9InciPz7/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////7gAOQWRvYmUAZEAAAAAB/9sAhAABAQEBAQEBAQEBAgEBAQICAQEBAQICAgICAgICAwIDAwMDAgMDBAQEBAQDBQUFBQUFBwcHBwcICAgICAgICAgIAQEBAQICAgQDAwQHBQQFBwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAj/wAARCAANAA0DAREAAhEBAxEB/90ABAAC/8QBogAAAAYCAwEAAAAAAAAAAAAABwgGBQQJAwoCAQALAQAABgMBAQEAAAAAAAAAAAAGBQQDBwIIAQkACgsQAAIBAgUCAwQGBgUFAQMGbwECAwQRBQYhEgAHMUETCFEiYRRxgTKRCaEj8MFCsRXRFuHxUjMXJGIYQzQlggoZclMmY5JENaJUshpzNsLSJ0U3RuLyg5Ojs2RVKMPTKTjj80dIVmUqOTpJSldYWVpmdHWEhWd2d2iGh5SVpKW0tcTF1NXk5fT1lpemp7a3xsfW1+bn9vdpanh5eoiJipiZmqipqri5usjJytjZ2ujp6vj5+hEAAQMCAwQHBgMEAwYHBwFpAQIDEQAEIQUSMQZB8FFhBxMicYGRobHBCDLRFOEj8UIVUgkWM2LSciSCwpKTQxdzg6KyYyU0U+KzNSZEVGRFVScKhLQYGRooKSo2Nzg5OkZHSElKVldYWVplZmdoaWp0dXZ3eHl6hYaHiImKlJWWl5iZmqOkpaanqKmqtba3uLm6w8TFxsfIycrT1NXW19jZ2uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDbqppMjZDyF09zh1BymuP5ezjhcMUOLUOI1seKHHzHLUeXOk9ZHG0NQi+7Ku0RMCZLIdyvYk01hFK+p6Y1UePYPhyZXwpcy1eWsSzXU5WGI4x/KXqKfGqFY4TUfM7/ADFppniE9tu87/L2+7zWqtxX/9Db/wCmOKYrFRZUjrsjZYr8VTKCLhNZnrNeLUkEuAh5fm2hhly9U00bEbfnFjkYhdm8lbcdVTaaTlTimImjwWV8jUK5BXLGKR09Cua81FWwA5lw8ySNOcuiqWjVQgVBEValJJZQoDbrVf/Z); cursor: pointer; height: 13px; width: 13px; }'; -guidersCSS += '.guider_content p { clear: both; color: #333; font-size: 13px; }'; -guidersCSS += '.guider_button { background: -moz-linear-gradient(top, #5CA9FF 0%, #3D79C3 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5CA9FF), color-stop(100%, #3D79C3)); background-color: #4A95E0; border: solid 1px #4B5D7E; color: #FFF; cursor: pointer; display: inline-block; float: right; font-size: 75%; font-weight: bold; margin-left: 6px; min-width: 40px; padding: 3px 5px; text-align: center; text-decoration: none; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; }'; -guidersCSS += '#guider_overlay { background-color: #000; width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; opacity: 0.5; filter: alpha(opacity=50); z-index: 1000; }'; - /** - * For optimization, the arrows image is inlined in the css below. - * - * To use your own arrows image, replace this background-image with your own arrows. - * It should have four arrows, top, right, left, and down. - */ -guidersCSS += '.guider_arrow { width: 42px; height: 42px; position: absolute; display: none; background-repeat: no-repeat; z-index: 100000006 !important; background-image: url(data:image/png;base64,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); } '; -guidersCSS += '.guider_arrow_right { display: block; background-position: 0px 0px; right: -42px; }'; -guidersCSS += '.guider_arrowdown { display: block; background-position: 0px -42px; bottom: -42px; }'; -guidersCSS += '.guider_arrow_up { display: block; background-position: 0px -126px; top: -42px; }'; -guidersCSS += '.guider_arrow_left { display: block; background-position: 0px -84px; left: -42px;}'; - - - - -// DOM utility functions -function insertAfter( referenceNode, newNode ) { - if ((typeof(referenceNode) == 'undefined') || (referenceNode == null)) { - console.log(arguments.callee.caller); - } else if ((typeof(referenceNode.parentNode) != 'undefined') && (typeof(referenceNode.nextSibling) != 'undefined')) { - if (referenceNode.parentNode == null) { - console.log(arguments.callee.caller); - } else { - referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling ); - } - } -}; -function createElementWithID(elementType, id, classname) { - obj = document.createElement(elementType); - if (id != null) { - obj.setAttribute('id', id); - } - if ((typeof(classname) != 'undefined') && (classname != '')) { - obj.setAttribute('class', classname); - } - return obj; -}; - -// sigh.. opera just has to be a pain in the ass... check for navigator object... -if (typeof(navigator) == 'undefined') navigator = window.navigator; - -var BrowserDetect = { - init: function () { - this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; - this.version = this.searchVersion(navigator.userAgent) - || this.searchVersion(navigator.appVersion) - || "an unknown version"; - this.OS = this.searchString(this.dataOS) || "an unknown OS"; - }, - searchString: function (data) { - for (var i=0;i' + data + '
RES can delete this data to stop errors from happening, but you might want to copy/paste it to a text file so you can more easily re-enter any lost information.'; - alert(msg, function() { - // back up a copy of the corrupt data - localStorage.setItem(localStorageSource + '.error', data); - // delete the corrupt data - RESStorage.removeItem(localStorageSource); - }); - } else { - alert('Error caught: JSON parse failure on the following data: ' + data); - } - return {}; - } - } -} - -// array compare utility function for keyCode arrays -function keyArrayCompare(fromArr, toArr) { - // if we've passed in a number, fix that and make it an array with alt, shift and ctrl set to false. - if (typeof(toArr) == 'number') { - toArr = Array(toArr,false,false,false); - } else if (toArr.length == 4) { - toArr.push(false); - } - if (fromArr.length != toArr.length) return false; - for (var i = 0; i < toArr.length; i++) { - if (fromArr[i].compare) { - if (!fromArr[i].compare(toArr[i])) return false; - } - if (fromArr[i] !== toArr[i]) return false; - } - return true; -} - -function operaUpdateCallback(obj) { - RESUtils.compareVersion(obj); -} -function operaForcedUpdateCallback(obj) { - RESUtils.compareVersion(obj, true); -} - -/* DOM utility functions */ -function hasClass(ele,cls) { - if ((typeof(ele) == 'undefined') || (ele == null)) { - if (typeof(console) != 'undefined') console.log(arguments.callee.caller); - return false; - } - return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); -} -function addClass(ele,cls) { - if (ele == null) console.log(arguments.callee.caller); - if (!hasClass(ele,cls)) ele.className += " "+cls; -} -function removeClass(ele,cls) { - if (hasClass(ele,cls)) { - var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); - ele.className=ele.className.replace(reg,' '); - } -} - -// This object will store xmlHTTPRequest callbacks for Safari because Safari's extension architecture seems stupid. -// This really shouldn't be necessary, but I can't seem to hold on to an onload function that I pass to the background page... -xhrQueue = { count: 0, onloads: [] }; - - -// if this is a jetpack addon, add an event listener like Safari's message handler... -if (typeof(self.on) == 'function') { - self.on('message', function(msgEvent) { - switch (msgEvent.name) { - case 'GM_xmlhttpRequest': - // Fire the appropriate onload function for this xmlhttprequest. - xhrQueue.onloads[msgEvent.XHRID](msgEvent.response); - break; - case 'compareVersion': - var forceUpdate = false; - if (typeof(msgEvent.message.forceUpdate) != 'undefined') forceUpdate = true; - RESUtils.compareVersion(msgEvent.message, forceUpdate); - break; - case 'loadTweet': - var tweet = msgEvent.response; - var thisExpando = modules['styleTweaks'].tweetExpando; - thisExpando.innerHTML = '
' + tweet.user.screen_name + ': ' + tweet.text + '
'; - thisExpando.style.display = 'block'; - break; - case 'getLocalStorage': - // TODO: this needs to be done for jetpack - // Does RESStorage have actual data in it? If it doesn't, they're a legacy user, we need to copy - // old schol localStorage from the foreground page to the background page to keep their settings... - if (typeof(msgEvent.message.importedFromForeground) == 'undefined') { - // it doesn't exist.. copy it over... - var thisJSON = { - requestType: 'saveLocalStorage', - data: localStorage - } - self.postMessage(thisJSON); - } else { - setUpRESStorage(msgEvent.message); - RESInit(); - } - break; - case 'saveLocalStorage': - // TODO: this needs to be done for jetpack - // Okay, we just copied localStorage from foreground to background, let's set it up... - setUpRESStorage(msgEvent.message); - RESInit(); - break; - case 'localStorage': - RESStorage.setItem(msgEvent.itemName, msgEvent.itemValue, true); - break; - default: - // console.log('unknown event type in self.on'); - // console.log(msgEvent.toSource()); - break; - } - }); -} - -// This is the message handler for Safari - the background page calls this function with return data... -function safariMessageHandler(msgEvent) { - switch (msgEvent.name) { - case 'GM_xmlhttpRequest': - // Fire the appropriate onload function for this xmlhttprequest. - xhrQueue.onloads[msgEvent.message.XHRID](msgEvent.message); - break; - case 'compareVersion': - var forceUpdate = false; - if (typeof(msgEvent.message.forceUpdate) != 'undefined') forceUpdate = true; - RESUtils.compareVersion(msgEvent.message, forceUpdate); - break; - case 'loadTweet': - var tweet = msgEvent.message; - var thisExpando = modules['styleTweaks'].tweetExpando; - thisExpando.innerHTML = '
' + tweet.user.screen_name + ': ' + tweet.text + '
'; - thisExpando.style.display = 'block'; - break; - case 'getLocalStorage': - // Does RESStorage have actual data in it? If it doesn't, they're a legacy user, we need to copy - // old schol localStorage from the foreground page to the background page to keep their settings... - if (typeof(msgEvent.message.importedFromForeground) == 'undefined') { - // it doesn't exist.. copy it over... - var thisJSON = { - requestType: 'saveLocalStorage', - data: localStorage - } - safari.self.tab.dispatchMessage('saveLocalStorage', thisJSON); - } else { - setUpRESStorage(msgEvent.message); - RESInit(); - } - break; - case 'saveLocalStorage': - // Okay, we just copied localStorage from foreground to background, let's set it up... - setUpRESStorage(msgEvent.message); - RESInit(); - break; - case 'localStorage': - RESStorage.setItem(msgEvent.message.itemName, msgEvent.message.itemValue, true); - break; - default: - // console.log('unknown event type in safariMessageHandler'); - break; - } -} - -// This is the message handler for Opera - the background page calls this function with return data... -function operaMessageHandler(msgEvent) { - var eventData = msgEvent.data; - switch (eventData.msgType) { - case 'GM_xmlhttpRequest': - // Fire the appropriate onload function for this xmlhttprequest. - xhrQueue.onloads[eventData.XHRID](eventData.data); - break; - case 'compareVersion': - var forceUpdate = false; - if (typeof(eventData.data.forceUpdate) != 'undefined') forceUpdate = true; - RESUtils.compareVersion(eventData.data, forceUpdate); - break; - case 'loadTweet': - var tweet = eventData.data; - var thisExpando = modules['styleTweaks'].tweetExpando; - thisExpando.innerHTML = '
' + tweet.user.screen_name + ': ' + tweet.text + '
'; - thisExpando.style.display = 'block'; - break; - case 'getLocalStorage': - // Does RESStorage have actual data in it? If it doesn't, they're a legacy user, we need to copy - // old schol localStorage from the foreground page to the background page to keep their settings... - if (typeof(eventData.data.importedFromForeground) == 'undefined') { - // it doesn't exist.. copy it over... - var thisJSON = { - requestType: 'saveLocalStorage', - data: localStorage - } - opera.extension.postMessage(JSON.stringify(thisJSON)); - } else { - if (location.hostname.match('reddit')) { - setUpRESStorage(eventData.data); - RESInit(); - } - } - break; - case 'saveLocalStorage': - // Okay, we just copied localStorage from foreground to background, let's set it up... - setUpRESStorage(eventData.data); - if (location.hostname.match('reddit')) { - RESInit(); - } - break; - case 'localStorage': - if ((typeof(RESStorage) != 'undefined') && (typeof(RESStorage.setItem) == 'function')) { - RESStorage.setItem(eventData.itemName, eventData.itemValue, true); - } else { - // great, opera has screwed some shit up. let's wait until RESStorage is defined, then try again... - function waitForRESStorage(eData) { - if ((typeof(RESStorage) != 'undefined') && (typeof(RESStorage.setItem) == 'function')) { - RESStorage.setItem(eData.itemName, eData.itemValue, true); - } else { - setTimeout(function() { waitForRESStorage(eData); }, 200); - } - } - var savedEventData = { - itemName: eventData.itemName, - itemValue: eventData.itemValue - }; - waitForRESStorage(savedEventData); - } - break; - default: - // console.log('unknown event type in operaMessageHandler'); - break; - } -} - -// listen for requests from chrome background page -if (typeof(chrome) != 'undefined') { - chrome.extension.onRequest.addListener( - function(request, sender, sendResponse) { - switch(request.requestType) { - case 'localStorage': - RESStorage.setItem(request.itemName, request.itemValue, true); - break; - default: - // sendResponse({status: "unrecognized request type"}); - break; - } - } - ); -} - -if (typeof(safari) != 'undefined') { - safari.self.addEventListener("message", safariMessageHandler, false); -} -// we can't do this check for opera here because we need to wait until DOMContentLoaded is triggered, I think. Putting this in RESinit(); - -// opera compatibility -if (typeof(opera) != 'undefined') { - // removing this line for new localStorage methodology (store in extension localstorage) - localStorage = window.localStorage; - location = window.location; - XMLHttpRequest = window.XMLHttpRequest; -} - -// Firebug stopped showing console.log for some reason. Need to use unsafeWindow if available. Not sure if this was due to a Firebug version update or what. -if (typeof(unsafeWindow) != 'undefined') { - if ((typeof(unsafeWindow.console) != 'undefined') && (typeof(self.on) != 'function')) { - console = unsafeWindow.console; - } else if (typeof(console) == 'undefined') { - console = { - log: function(str) { - return false; - } - }; - } -} - - - -// GreaseMonkey API compatibility for non-GM browsers (Chrome, Safari, Firefox) -// @copyright 2009, 2010 James Campos -// @modified 2010 Steve Sobel - added some missing gm_* functions -// @license cc-by-3.0; http://creativecommons.org/licenses/by/3.0/ -if ((typeof GM_deleteValue == 'undefined') || (typeof GM_addStyle == 'undefined')) { - GM_addStyle = function(css) { - var style = document.createElement('style'); - style.textContent = css; - var head = document.getElementsByTagName('head')[0]; - if (head) { - head.appendChild(style); - } - } - - GM_deleteValue = function(name) { - localStorage.removeItem(name); - } - - GM_getValue = function(name, defaultValue) { - var value = localStorage.getItem(name); - if (!value) - return defaultValue; - var type = value[0]; - value = value.substring(1); - switch (type) { - case 'b': - return value == 'true'; - case 'n': - return Number(value); - default: - return value; - } - } - - GM_log = function(message) { - console.log(message); - } - - GM_registerMenuCommand = function(name, funk) { - //todo - } - - GM_setValue = function(name, value) { - value = (typeof value)[0] + value; - localStorage.setItem(name, value); - } - - if (typeof(chrome) != 'undefined') { - GM_xmlhttpRequest = function(obj) { - var crossDomain = (obj.url.indexOf(location.hostname) == -1); - - if ((typeof(obj.onload) != 'undefined') && (crossDomain)) { - obj.requestType = 'GM_xmlhttpRequest'; - if (typeof(obj.onload) != 'undefined') { - chrome.extension.sendRequest(obj, function(response) { - obj.onload(response); - }); - } - } else { - var request=new XMLHttpRequest(); - request.onreadystatechange=function() { if(obj.onreadystatechange) { obj.onreadystatechange(request); }; if(request.readyState==4 && obj.onload) { obj.onload(request); } } - request.onerror=function() { if(obj.onerror) { obj.onerror(request); } } - try { request.open(obj.method,obj.url,true); } catch(e) { if(obj.onerror) { obj.onerror( {readyState:4,responseHeaders:'',responseText:'',responseXML:'',status:403,statusText:'Forbidden'} ); }; return; } - if(obj.headers) { for(name in obj.headers) { request.setRequestHeader(name,obj.headers[name]); } } - request.send(obj.data); return request; - } - } - } else if (typeof(safari) != 'undefined') { - GM_xmlhttpRequest = function(obj) { - obj.requestType = 'GM_xmlhttpRequest'; - // Safari is a bastard. Since it doesn't provide legitimate callbacks, I have to store the onload function here - // in the main userscript in a queue (see xhrQueue), wait for data to come back from the background page, then call the onload. Damn this sucks. - // See how much easier it was up there in the Chrome statement? Damn. - if (typeof(obj.onload) != 'undefined') { - obj.XHRID = xhrQueue.count; - xhrQueue.onloads[xhrQueue.count] = obj.onload; - safari.self.tab.dispatchMessage("GM_xmlhttpRequest", obj); - xhrQueue.count++; - } - } - } else if (typeof(opera) != 'undefined') { - GM_xmlhttpRequest = function(obj) { - obj.requestType = 'GM_xmlhttpRequest'; - // Turns out, Opera works this way too, but I'll forgive them since their extensions are so young and they're awesome people... - // Really though, we need callbacks like Chrome has! This is such a hacky way to emulate GM_xmlhttpRequest. - - // oy vey... another problem. When Opera sends xmlhttpRequests from the background page, it loses the cookies etc that it'd have - // had from the foreground page... so we need to write a bit of a hack here, and call different functions based on whether or - // not the request is cross domain... For same-domain requests, we'll call from the foreground... - var crossDomain = (obj.url.indexOf(location.hostname) == -1); - - if ((typeof(obj.onload) != 'undefined') && (crossDomain)) { - obj.XHRID = xhrQueue.count; - xhrQueue.onloads[xhrQueue.count] = obj.onload; - opera.extension.postMessage(JSON.stringify(obj)); - xhrQueue.count++; - } else { - var request=new XMLHttpRequest(); - request.onreadystatechange=function() { if(obj.onreadystatechange) { obj.onreadystatechange(request); }; if(request.readyState==4 && obj.onload) { obj.onload(request); } } - request.onerror=function() { if(obj.onerror) { obj.onerror(request); } } - try { request.open(obj.method,obj.url,true); } catch(e) { if(obj.onerror) { obj.onerror( {readyState:4,responseHeaders:'',responseText:'',responseXML:'',status:403,statusText:'Forbidden'} ); }; return; } - if(obj.headers) { for(name in obj.headers) { request.setRequestHeader(name,obj.headers[name]); } } - request.send(obj.data); return request; - } - } - } else if (typeof(self.on) == 'function') { - // we must be in a Firefox / jetpack addon... - GM_xmlhttpRequest = function(obj) { - obj.requestType = 'GM_xmlhttpRequest'; - // okay, firefox's jetpack addon does this same stuff... le sigh.. - if (typeof(obj.onload) != 'undefined') { - obj.XHRID = xhrQueue.count; - xhrQueue.onloads[xhrQueue.count] = obj.onload; - self.postMessage(obj); - xhrQueue.count++; - } - } - } -} else { - // this hack is to avoid an unsafeWindow error message if a gm_xhr is ever called as a result of a jQuery-induced ajax call. - // yes, it's ugly, but it's necessary if we're using Greasemonkey together with jQuery this way. - var oldgmx = GM_xmlhttpRequest; - GM_xmlhttpRequest = function(params) { - setTimeout(function() { - oldgmx(params); - }, 0); - } -} - - -var RESConsoleContainer = ''; -var modalOverlay = ''; -var RESMenuItems = new Array(); -var RESConsolePanels = new Array(); -var modules = new Array(); - -// define common RESUtils - reddit related functions and data that may need to be accessed... -var RESUtils = { - // imgur API key - imgurAPIKey: 'fe266bc9466fe69aa1cf0904e7298eda', - // A cache variable to store CSS that will be applied at the end of execution... - css: '', - addCSS: function(css) { - this.css += css; - }, - // checks if script should run on current URL using exclude / include. - isMatchURL: function (moduleID) { - var currURL = location.href; - // get includes and excludes... - var excludes = modules[moduleID].exclude; - var includes = modules[moduleID].include; - // first check excludes... - if (typeof(excludes) != 'undefined') { - for (i=0, len = excludes.length; i span.user > a'); - if ((userLink != null) && (!hasClass(userLink,'login-required'))) { - this.loggedInUserCached = userLink.innerHTML; - } else { - this.loggedInUserCached = null; - } - } - return this.loggedInUserCached; - }, - loggedInUserInfo: function(callback) { - if (RESUtils.loggedInUser() == null) return false; - RESUtils.loggedInUserInfoCallbacks.push(callback); - var cacheData = RESStorage.getItem('RESUtils.userInfoCache.' + RESUtils.loggedInUser()) || '{}'; - var userInfoCache = safeJSON.parse(cacheData); - var lastCheck = (userInfoCache != null) ? parseInt(userInfoCache.lastCheck) || 0 : 0; - var now = new Date(); - // 300000 = 5 minutes - if ((now.getTime() - lastCheck) > 300000) { - if (!RESUtils.loggedInUserInfoRunning) { - RESUtils.loggedInUserInfoRunning = true; - GM_xmlhttpRequest({ - method: "GET", - url: location.protocol + "//"+ location.hostname+ "/user/" + RESUtils.loggedInUser() + "/about.json", - onload: function(response) { - var thisResponse = JSON.parse(response.responseText); - var userInfoCache = { - lastCheck: now.getTime(), - userInfo: thisResponse - } - RESStorage.setItem('RESUtils.userInfoCache.' + RESUtils.loggedInUser(),JSON.stringify(userInfoCache)); - while (RESUtils.loggedInUserInfoCallbacks.length) { - var thisCallback = RESUtils.loggedInUserInfoCallbacks.pop(); - thisCallback(userInfoCache.userInfo); - } - RESUtils.loggedInUserInfoRunning = false; - } - }); - } - } else { - while (RESUtils.loggedInUserInfoCallbacks.length) { - var thisCallback = RESUtils.loggedInUserInfoCallbacks.pop(); - thisCallback(userInfoCache.userInfo); - } - } - }, - loggedInUserInfoCallbacks: [], - pageType: function() { - if (typeof(this.pageTypeSaved) == 'undefined') { - var pageType = ''; - var currURL = location.href.split('#')[0]; - var commentsRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/[-\w\.\/]*comments\/[-\w\.\/]*/i); - var friendsCommentsRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/r\/friends\/*comments\/?/i); - var inboxRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/message\/[-\w\.\/]*/i); - // var profileRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/user\/[-\w\.]*\/?(comments)?\/?$/i); - var profileRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/user\/[-\w\.#=]*\/?(comments)?\/?(\?([a-z]+=[a-zA-Z0-9_%]*&?)*)?$/i); // fix to regex contributed by s_quark - var submitRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/[-\w\.\/]*\/submit\/?$/i); - var prefsRegex = new RegExp(/https?:\/\/([a-z]+).reddit.com\/prefs\/?/i); - if (profileRegex.test(currURL)) { - pageType = 'profile'; - } else if ((commentsRegex.test(currURL)) || (friendsCommentsRegex.test(currURL))) { - pageType = 'comments' - } else if (inboxRegex.test(currURL)) { - pageType = 'inbox'; - } else if (submitRegex.test(currURL)) { - pageType = 'submit'; - } else if (prefsRegex.test(currURL)) { - pageType = 'prefs'; - } else { - pageType = 'linklist'; - } - this.pageTypeSaved = pageType; - } - return this.pageTypeSaved; - }, - currentSubreddit: function(check) { - if (typeof(this.curSub) == 'undefined') { - var match = location.href.match(/https?:\/\/(?:[a-z]+).reddit.com\/r\/([\w\.]+).*/i); - if (match != null) { - this.curSub = match[1]; - if (check) return (match[1].toLowerCase() == check.toLowerCase()); - return match[1]; - } else { - if (check) return false; - return null; - } - } else { - if (check) return (this.curSub.toLowerCase() == check.toLowerCase()); - return this.curSub; - } - }, - currentUserProfile: function() { - if (typeof(this.curUserProfile) == 'undefined') { - var match = location.href.match(/https?:\/\/(?:[a-z]+).reddit.com\/user\/([\w\.]+).*/i); - if (match != null) { - this.curUserProfile = match[1]; - return match[1]; - } else { - return null; - } - } else { - return this.curUserProfile; - } - }, - getXYpos: function (obj) { - var topValue= 0,leftValue= 0; - while(obj){ - leftValue+= obj.offsetLeft; - topValue+= obj.offsetTop; - obj= obj.offsetParent; - } - finalvalue = { 'x': leftValue, 'y': topValue }; - return finalvalue; - }, - elementInViewport: function (obj) { - // check the headerOffset - if we've pinned the subreddit bar, we need to add some pixels so the "visible" stuff is lower down the page. - var headerOffset = this.getHeaderOffset(); - var top = obj.offsetTop - headerOffset; - var left = obj.offsetLeft; - var width = obj.offsetWidth; - var height = obj.offsetHeight; - while(obj.offsetParent) { - obj = obj.offsetParent; - top += obj.offsetTop; - left += obj.offsetLeft; - } - return ( - top >= window.pageYOffset && - left >= window.pageXOffset && - (top + height) <= (window.pageYOffset + window.innerHeight - headerOffset) && - (left + width) <= (window.pageXOffset + window.innerWidth) - ); - }, - setMouseXY: function(e) { - e = e || window.event; - var cursor = {x:0, y:0}; - if (e.pageX || e.pageY) { - cursor.x = e.pageX; - cursor.y = e.pageY; - } else { - cursor.x = e.clientX + - (document.documentElement.scrollLeft || - document.body.scrollLeft) - - document.documentElement.clientLeft; - cursor.y = e.clientY + - (document.documentElement.scrollTop || - document.body.scrollTop) - - document.documentElement.clientTop; - } - RESUtils.mouseX = cursor.x; - RESUtils.mouseY = cursor.y; - }, - elementUnderMouse: function (obj) { - var top = obj.offsetTop; - var left = obj.offsetLeft; - var width = obj.offsetWidth; - var height = obj.offsetHeight; - var right = left + width; - var bottom = top + height; - if ((RESUtils.mouseX >= left) && (RESUtils.mouseX <= right) && (RESUtils.mouseY >= top) && (RESUtils.mouseY <= bottom)) { - return true; - } else { - return false; - } - }, - scrollTo: function(x,y) { - var headerOffset = this.getHeaderOffset(); - window.scrollTo(x,y-headerOffset); - }, - getHeaderOffset: function() { - if (typeof(this.headerOffset) == 'undefined') { - this.headerOffset = 0; - switch (modules['betteReddit'].options.pinHeader.value) { - case 'none': - break; - case 'sub': - this.theHeader = document.querySelector('#sr-header-area'); - break; - case 'header': - this.theHeader = document.querySelector('#header'); - break; - } - if (this.theHeader) { - this.headerOffset = this.theHeader.offsetHeight + 6; - } - } - return this.headerOffset; - }, - setSelectValue: function(obj, value) { - for (var i=0, len=obj.length; i < len; i++) { - // for some reason in firefox, obj[0] is undefined... weird. adding a test for existence of obj[i]... - if ((obj[i]) && (obj[i].value == value)) { - obj[i].selected = true; - } - } - }, - stripHTML: function(str) { - var regExp = /<\/?[^>]+>/gi; - str = str.replace(regExp,""); - return str; - }, - fadeElementOut: function(obj, speed, callback) { - if (obj.getAttribute('isfading') == 'in') { - return false; - } - obj.setAttribute('isfading','out'); - speed = speed || 0.1; - if (obj.style.opacity == '') obj.style.opacity = '1'; - if (obj.style.opacity <= 0) { - obj.style.display = 'none'; - obj.setAttribute('isfading',false); - if (callback) callback(); - return true; - } else { - var newOpacity = parseFloat(obj.style.opacity) - speed; - if (newOpacity < speed) newOpacity = 0; - obj.style.opacity = newOpacity; - setTimeout(function() { RESUtils.fadeElementOut(obj, speed, callback) }, 100); - } - }, - fadeElementIn: function(obj, speed, finalOpacity) { - finalOpacity = finalOpacity || 1; - if (obj.getAttribute('isfading') == 'out') { - return false; - } - obj.setAttribute('isfading','in'); - speed = speed || 0.1; - if ((obj.style.display == 'none') || (obj.style.display == '')) { - obj.style.opacity = 0; - obj.style.display = 'block'; - } - if (obj.style.opacity >= finalOpacity) { - obj.setAttribute('isfading',false); - obj.style.opacity = finalOpacity; - return true; - } else { - var newOpacity = parseFloat(obj.style.opacity) + parseFloat(speed); - if (newOpacity > finalOpacity) newOpacity = finalOpacity; - obj.style.opacity = newOpacity; - setTimeout(function() { RESUtils.fadeElementIn(obj, speed, finalOpacity) }, 100); - } - }, - setNewNotification: function() { - $('#RESSettingsButton, .gearIcon').addClass('newNotification').click(function() { - location.href = '/r/RESAnnouncements'; - }); - }, - firstRun: function() { - // if this is the first time this version has been run, pop open the what's new tab, background focused. - if (RESStorage.getItem('RES.firstRun.'+RESVersion) == null) { - RESStorage.setItem('RES.firstRun.'+RESVersion,'true'); - RESUtils.openLinkInNewTab('http://redditenhancementsuite.com/whatsnew.html#'+RESVersion, false); - } - }, - // checkForUpdate: function(forceUpdate) { - checkForUpdate: function() { - if (RESUtils.currentSubreddit('RESAnnouncements')) { - RESStorage.removeItem('RES.newAnnouncement','true'); - } - var now = new Date(); - var lastCheck = parseInt(RESStorage.getItem('RESLastUpdateCheck')) || 0; - // if we haven't checked for an update in 24 hours, check for one now! - // if (((now.getTime() - lastCheck) > 86400000) || (RESVersion > RESStorage.getItem('RESlatestVersion')) || ((RESStorage.getItem('RESoutdated') == 'true') && (RESVersion == RESStorage.getItem('RESlatestVersion'))) || forceUpdate) { - if ((now.getTime() - lastCheck) > 86400000) { - // now we're just going to check /r/RESAnnouncements for new posts, we're not checking version numbers... - var lastID = RESStorage.getItem('RES.lastAnnouncementID'); - $.getJSON('/r/RESAnnouncements/.json?limit=1', function(data) { - RESStorage.setItem('RESLastUpdateCheck',now.getTime()); - var thisID = data.data.children[0].data.id; - if (thisID != lastID) { - RESStorage.setItem('RES.newAnnouncement','true'); - RESUtils.setNewNotification(); - } - RESStorage.setItem('RES.lastAnnouncementID', thisID); - }); - /* - var jsonURL = 'http://reddit.honestbleeps.com/update.json?v=' + RESVersion; - // mark off that we've checked for an update... - RESStorage.setItem('RESLastUpdateCheck',now.getTime()); - var outdated = false; - if (typeof(chrome) != 'undefined') { - // we've got chrome, so we need to hit up the background page to do cross domain XHR - thisJSON = { - requestType: 'compareVersion', - url: jsonURL - } - chrome.extension.sendRequest(thisJSON, function(response) { - // send message to background.html to open new tabs... - outdated = RESUtils.compareVersion(response, forceUpdate); - }); - } else if (typeof(safari) != 'undefined') { - // we've got safari, so we need to hit up the background page to do cross domain XHR - thisJSON = { - requestType: 'compareVersion', - url: jsonURL, - forceUpdate: forceUpdate - } - safari.self.tab.dispatchMessage("compareVersion", thisJSON); - } else if (typeof(opera) != 'undefined') { - // we've got opera, so we need to hit up the background page to do cross domain XHR - thisJSON = { - requestType: 'compareVersion', - url: jsonURL, - forceUpdate: forceUpdate - } - opera.extension.postMessage(JSON.stringify(thisJSON)); - } else { - // we've got greasemonkey, so we can do cross domain XHR. - GM_xmlhttpRequest({ - method: "GET", - url: jsonURL, - onload: function(response) { - outdated = RESUtils.compareVersion(JSON.parse(response.responseText), forceUpdate); - } - }); - } - */ - } - }, - /* - compareVersion: function(response, forceUpdate) { - if (RESVersion < response.latestVersion) { - RESStorage.setItem('RESoutdated','true'); - RESStorage.setItem('RESlatestVersion',response.latestVersion); - RESStorage.setItem('RESmessage',response.message); - if (forceUpdate) { - RESConsole.RESCheckUpdateButton.innerHTML = 'You are out of date! [click to update]'; - } - return true; - } else { - RESStorage.setItem('RESlatestVersion',response.latestVersion); - RESStorage.setItem('RESoutdated','false'); - if (forceUpdate) { - RESConsole.RESCheckUpdateButton.innerHTML = 'You are up to date!'; - } - return false; - } - }, - */ - proEnabled: function() { - return ((typeof(modules['RESPro']) != 'undefined') && (modules['RESPro'].isEnabled())); - }, - niceKeyCode: function(charCode) { - keyComboString = ''; - if (typeof(charCode) == 'string') { - var tempArray = charCode.split(','); - if (tempArray.length) { - if (tempArray[1] == 'true') keyComboString += 'alt-'; - if (tempArray[2] == 'true') keyComboString += 'ctrl-'; - if (tempArray[3] == 'true') keyComboString += 'shift-'; - if (tempArray[4] == 'true') keyComboString += 'command-'; - } - testCode = parseInt(charCode); - } else if (typeof(charCode) == 'object') { - testCode = parseInt(charCode[0]); - if (charCode[1]) keyComboString += 'alt-'; - if (charCode[2]) keyComboString += 'ctrl-'; - if (charCode[3]) keyComboString += 'shift-'; - if (charCode[4]) keyComboString += 'command-'; - } - switch(testCode) { - case 8: - niceString = "backspace"; // backspace - break; - case 9: - niceString = "tab"; // tab - break; - case 13: - niceString = "enter"; // enter - break; - case 16: - niceString = "shift"; // shift - break; - case 17: - niceString = "ctrl"; // ctrl - break; - case 18: - niceString = "alt"; // alt - break; - case 19: - niceString = "pause/break"; // pause/break - break; - case 20: - niceString = "caps lock"; // caps lock - break; - case 27: - niceString = "escape"; // escape - break; - case 33: - niceString = "page up"; // page up, to avoid displaying alternate character and confusing people - break; - case 34: - niceString = "page down"; // page down - break; - case 35: - niceString = "end"; // end - break; - case 36: - niceString = "home"; // home - break; - case 37: - niceString = "left arrow"; // left arrow - break; - case 38: - niceString = "up arrow"; // up arrow - break; - case 39: - niceString = "right arrow"; // right arrow - break; - case 40: - niceString = "down arrow"; // down arrow - break; - case 45: - niceString = "insert"; // insert - break; - case 46: - niceString = "delete"; // delete - break; - case 91: - niceString = "left window"; // left window - break; - case 92: - niceString = "right window"; // right window - break; - case 93: - niceString = "select key"; // select key - break; - case 96: - niceString = "numpad 0"; // numpad 0 - break; - case 97: - niceString = "numpad 1"; // numpad 1 - break; - case 98: - niceString = "numpad 2"; // numpad 2 - break; - case 99: - niceString = "numpad 3"; // numpad 3 - break; - case 100: - niceString = "numpad 4"; // numpad 4 - break; - case 101: - niceString = "numpad 5"; // numpad 5 - break; - case 102: - niceString = "numpad 6"; // numpad 6 - break; - case 103: - niceString = "numpad 7"; // numpad 7 - break; - case 104: - niceString = "numpad 8"; // numpad 8 - break; - case 105: - niceString = "numpad 9"; // numpad 9 - break; - case 106: - niceString = "multiply"; // multiply - break; - case 107: - niceString = "add"; // add - break; - case 109: - niceString = "subtract"; // subtract - break; - case 110: - niceString = "decimal point"; // decimal point - break; - case 111: - niceString = "divide"; // divide - break; - case 112: - niceString = "F1"; // F1 - break; - case 113: - niceString = "F2"; // F2 - break; - case 114: - niceString = "F3"; // F3 - break; - case 115: - niceString = "F4"; // F4 - break; - case 116: - niceString = "F5"; // F5 - break; - case 117: - niceString = "F6"; // F6 - break; - case 118: - niceString = "F7"; // F7 - break; - case 119: - niceString = "F8"; // F8 - break; - case 120: - niceString = "F9"; // F9 - break; - case 121: - niceString = "F10"; // F10 - break; - case 122: - niceString = "F11"; // F11 - break; - case 123: - niceString = "F12"; // F12 - break; - case 144: - niceString = "num lock"; // num lock - break; - case 145: - niceString = "scroll lock"; // scroll lock - break; - case 186: - niceString = ";"; // semi-colon - break; - case 187: - niceString = "="; // equal-sign - break; - case 188: - niceString = ","; // comma - break; - case 189: - niceString = "-"; // dash - break; - case 190: - niceString = "."; // period - break; - case 191: - niceString = "/"; // forward slash - break; - case 192: - niceString = "`"; // grave accent - break; - case 219: - niceString = "["; // open bracket - break; - case 220: - niceString = "\\"; // back slash - break; - case 221: - niceString = "]"; // close bracket - break; - case 222: - niceString = "'"; // single quote - break; - default: - niceString = String.fromCharCode(testCode); - break; - } - return keyComboString + niceString; - }, - niceDate: function(d, usformat) { - d = d || new Date(); - var year = d.getFullYear(); - var month = (d.getMonth() + 1); - month = (month < 10) ? '0'+month : month; - var day = d.getDate(); - day = (day < 10) ? '0'+day : day; - var fullString = year+'-'+month+'-'+day; - if (usformat) { - fullString = month+'-'+day+'-'+year; - } - return fullString; - }, - niceDateTime: function(d, usformat) { - d = d || new Date(); - var dateString = RESUtils.niceDate(d); - var hours = d.getHours(); - hours = (hours < 10) ? '0'+hours : hours; - var minutes = d.getMinutes(); - minutes = (minutes < 10) ? '0'+minutes : minutes; - var seconds = d.getSeconds(); - seconds = (seconds < 10) ? '0'+seconds : seconds; - var fullString = dateString + ' ' + hours + ':'+minutes+':'+seconds; - return fullString; - }, - niceDateDiff: function(origdate, newdate) { - // Enter the month, day, and year below you want to use as - // the starting point for the date calculation - var amonth = origdate.getMonth()+1; - var aday = origdate.getDate(); - var ayear = origdate.getFullYear(); - - if (newdate == null) newdate = new Date(); - var dyear; - var dmonth; - var dday; - var tyear = newdate.getFullYear(); - var tmonth = newdate.getUTCMonth()+1; - var tday = newdate.getUTCDate(); - var y=1; - var mm=1; - var d=1; - var a2=0; - var a1=0; - var f=28; - - if ((tyear/4)-parseInt(tyear/4)==0) { - f=29; - } - - m = new Array(31, f, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); - - dyear = tyear-(ayear); - - dmonth = tmonth-amonth; - if (dmonth<0) { - dmonth = dmonth+12; - dyear--; - } - - dday = tday-aday; - if (dday<0) { - if (dmonth>0) { - var ma = amonth+tmonth; - // console.log('amonth: ' + amonth + ' -- tmonth: ' +tmonth); - if (ma>12) {ma = ma-12} - if (ma=0) {ma = ma+12} - dday = dday+m[ma]; - dmonth--; - if (dmonth < 0) { - dyear--; - dmonth = dmonth+12; - } - } else { - dday=0; - } - } - - var returnString = ''; - - if (dyear==0) {y=0} - if (dmonth==0) {mm=0} - if (dday==0) {d=0} - if ((y==1) && (mm==1)) {a1=1} - if ((y==1) && (d==1)) {a1=1} - if ((mm==1) && (d==1)) {a2=1} - if (y==1){ - if (dyear == 1) { - returnString += dyear + " year"; - } else { - returnString += dyear + " years"; - } - } - if ((a1==1) && (a2==0)) { returnString += " and "; } - if ((a1==1) && (a2==1)) { returnString += ", "; } - if (mm==1){ - if (dmonth == 1) { - returnString += dmonth + " month"; - } else { - returnString += dmonth + " months"; - } - } - if (a2==1) { returnString += " and "; } - if (d==1){ - if (dday == 1) { - returnString += dday + " day"; - } else { - returnString += dday + " days"; - } - } - if (returnString == '') { - returnString = '0 days'; - } - return returnString; - }, - checkIfSubmitting: function() { - this.checkedIfSubmitting = true; - if ((location.href.match(/\/r\/[\w]+\/submit\/?/i)) || (location.href.match(/reddit.com\/submit\/?/i))) { - var thisSubRedditInput = document.getElementById('sr-autocomplete'); - if (thisSubRedditInput) { - var thisSubReddit = thisSubRedditInput.value; - var title = document.querySelector('textarea[name=title]'); - if (typeof(this.thisSubRedditInputListener) == 'undefined') { - this.thisSubRedditInputListener = true; - thisSubRedditInput.addEventListener('change', function(e) { - RESUtils.checkIfSubmitting(); - }, false); - } - if (thisSubReddit.toLowerCase() == 'enhancement') { - RESUtils.addCSS('#submittingToEnhancement { display: none; min-height: 300px; font-size: 14px; line-height: 15px; margin-top: 10px; width: 518px; position: absolute; z-index: 999; } #submittingToEnhancement ol { margin-left: 10px; margin-top: 15px; list-style-type: decimal; } #submittingToEnhancement li { margin-left: 25px; }'); - RESUtils.addCSS('.submittingToEnhancementButton { border: 1px solid #444444; border-radius: 2px; padding: 3px 6px; cursor: pointer; display: inline-block; margin-top: 12px; }'); - RESUtils.addCSS('#RESBugReport, #RESFeatureRequest { display: none; }'); - RESUtils.addCSS('#RESSubmitOptions .submittingToEnhancementButton { margin-top: 30px; }'); - var textDesc = document.getElementById('text-desc'); - this.submittingToEnhancement = createElementWithID('div','submittingToEnhancement','RESDialogSmall'); - this.submittingToEnhancement.innerHTML = " \ -

Submitting to r/Enhancement

\ -
\ -
\ - What kind of a post do you want to submit to r/Enhancement? So that we can better support you, please choose from the options below, and please take care to read the instructions, thanks!
\ -
I want to submit a bug report

\ -
I want to submit a feature request

\ -
I want to submit a general question or other item
\ -
\ -
\ - Are you sure you want to submit a bug report? \ - If so, please consider the following:
\ -
    \ -
  1. Have you searched /r/Enhancement to see if someone else has reported it?
  2. \ -
  3. Have you checked the Wiki yet to see if it has already been reported?
  4. \ -
  5. Are you sure it's a bug with RES specifically? Do you have any other userscripts/extensions running? How about addons like BetterPrivacy, Ghostery, CCleaner, etc?
  6. \ -
  7. Okay - if you still want to report a bug, go ahead and report it! RES will automatically place your browser info in the selftext box - please leave it there to aid in debugging!
  8. \ -
\ - I still want to submit a bug! \ -
\ -
\ - So you want to request a feature, great! Please just consider the following, first:
\ -
    \ -
  1. Have you searched /r/Enhancement to see if someone else has requested it?
  2. \ -
  3. Are you sure it's a bug with RES specifically? Do you have any other Reddit-related userscripts/extensions running?
  4. \ -
  5. Okay - if you've answered \"yes\" to all of the above, go ahead and report it. Please be sure to specify: your browser (with version), version of RES, operating system, anything showing up in your Javascript error console, and any special settings you may have that might help debug.
  6. \ -
\ - I still want to submit a feature request! \ -
\ -
"; - insertAfter(textDesc, this.submittingToEnhancement); - setTimeout(function() { - $('#RESSubmitBug').click( - function() { - $('#RESSubmitOptions').fadeOut( - function() { $('#RESBugReport').fadeIn(); } - ); - } - ); - $('#RESSubmitFeatureRequest').click( - function() { - $('#RESSubmitOptions').fadeOut( - function() { $('#RESFeatureRequest').fadeIn(); } - ); - } - ); - $('#submittingBug').click( - function() { - $('li a.text-button').click(); - $('#submittingToEnhancement').fadeOut(); - var thisBrowser; - if (typeof(self.on) == 'function') { - thisBrowser = 'Firefox'; - } else if (typeof(chrome) != 'undefined') { - thisBrowser = 'Chrome'; - } else if (typeof(safari) != 'undefined') { - thisBrowser = 'Safari'; - } else if (typeof(opera) != 'undefined') { - thisBrowser = 'Opera'; - } else { - thisBrowser = 'Unknown'; - } - var txt = "- RES Version: " + RESVersion + "\n"; - // turns out this is pretty useless info, commenting it out. - // txt += "- Browser: " + navigator.appCodeName + " " + navigator.appName + "\n"; - // txt += "- Browser: " + thisBrowser + "\n"; - txt += "- Browser: " + BrowserDetect.browser + "\n"; - if (typeof(navigator) == 'undefined') navigator = window.navigator; - txt+= "- Browser Version: " + BrowserDetect.version + "\n"; - txt+= "- Cookies Enabled: " + navigator.cookieEnabled + "\n"; - txt+= "- Platform: " + BrowserDetect.OS + "\n\n"; - $('.usertext-edit textarea').val(txt); - title.value = '[bug] Please describe your bug here. If you have screenshots, please link them in the selftext.'; - } - ); - $('#submittingFeature').click( - function() { - $('#submittingToEnhancement').fadeOut(); - title.value = '[feature request] Please summarize your feature request here, and elaborate in the selftext.'; - } - ); - $('#RESSubmitOther').click( - function() { - $('#submittingToEnhancement').fadeOut(); - title.value = ''; - } - ); - $('#submittingToEnhancement').fadeIn(); - }, 1000); - } else if (typeof(this.submittingToEnhancement) != 'undefined') { - this.submittingToEnhancement.parentNode.removeChild(this.submittingToEnhancement); - if (title.value == 'Submitting a bug? Please read the box above...') { - title.value = ''; - } - } - } - } - }, - urlencode: function(string) { - // Javascript's escape function is stupid, and ignores the + character. Why? I have no idea. - // string = string.replace('+', '%2B'); - return escape(this._utf8_encode(string)).replace('+', '%2B'); - }, - urldecode: function(string) { - return this._utf8_decode(unescape(string)); - }, - // private method for UTF-8 encoding - _utf8_encode: function (string) { - string = string.replace(/\r\n/g,"\n"); - var utftext = ""; - for (var n = 0; n < string.length; n++) { - var c = string.charCodeAt(n); - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } - } - return utftext; - }, - - // private method for UTF-8 decoding - _utf8_decode: function (utftext) { - var string = ""; - var i = 0; - var c = c1 = c2 = 0; - while ( i < utftext.length ) { - c = utftext.charCodeAt(i); - if (c < 128) { - string += String.fromCharCode(c); - i++; - } - else if((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i+1); - string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); - i += 2; - } - else { - c2 = utftext.charCodeAt(i+1); - c3 = utftext.charCodeAt(i+2); - string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - } - return string; - }, - isEmpty: function(obj) { - for(var prop in obj) { - if(obj.hasOwnProperty(prop)) - return false; - } - return true; - }, - openLinkInNewTab: function(url, focus) { - if (typeof(chrome) != 'undefined') { - thisJSON = { - requestType: 'openLinkInNewTab', - linkURL: url, - button: focus - } - chrome.extension.sendRequest(thisJSON, function(response) { - // send message to background.html to open new tabs... - return true; - }); - } else if (typeof(safari) != 'undefined') { - thisJSON = { - requestType: 'openLinkInNewTab', - linkURL: url, - button: focus - } - safari.self.tab.dispatchMessage("openLinkInNewTab", thisJSON); - } else if (typeof(opera) != 'undefined') { - thisJSON = { - requestType: 'openLinkInNewTab', - linkURL: url, - button: focus - } - opera.extension.postMessage(JSON.stringify(thisJSON)); - } else if (typeof(self.on) == 'function') { - thisJSON = { - requestType: 'openLinkInNewTab', - linkURL: url, - button: focus - } - self.postMessage(thisJSON); - } else { - window.open(url); - } - }, - notification: function(contentObj, delay) { - var content; - if (typeof(contentObj.message) == 'undefined') { - if (typeof(contentObj) == 'string') { - content = contentObj; - } else { - return false; - } - } else { - content = contentObj.message; - } - var header = (typeof(contentObj.header) == 'undefined') ? 'Notification:' : contentObj.header; - if (typeof(this.notificationCount) == 'undefined') { - this.adFrame = document.body.querySelector('#ad-frame'); - if (this.adFrame) { - this.adFrame.style.display = 'none'; - } - this.notificationCount = 0; - this.notificationTimers = new Array(); - this.RESNotifications = createElementWithID('div','RESNotifications'); - document.body.appendChild(this.RESNotifications); - } - var thisNotification = document.createElement('div'); - addClass(thisNotification, 'RESNotification'); - thisNotification.setAttribute('id','RESNotification-'+this.notificationCount); - thisNotification.innerHTML = '

'+header+'

X
'; - thisNotification.innerHTML += '
'+content+'
'; - var thisNotificationCloseButton = thisNotification.querySelector('.RESNotificationClose'); - thisNotificationCloseButton.addEventListener('click',function(e) { - var thisNotification = e.target.parentNode.parentNode; - RESUtils.closeNotification(thisNotification); - }, false); - this.setCloseNotificationTimer(thisNotification, delay); - this.RESNotifications.style.display = 'block'; - this.RESNotifications.appendChild(thisNotification); - RESUtils.fadeElementIn(thisNotification, 0.2, 1); - this.notificationCount++; - }, - setCloseNotificationTimer: function(e, delay) { - delay = delay || 3000; - var thisNotification = (typeof(e.currentTarget) != 'undefined') ? e.currentTarget : e; - var thisNotificationID = thisNotification.getAttribute('id').split('-')[1]; - addClass(thisNotification,'timerOn'); - clearTimeout(RESUtils.notificationTimers[thisNotificationID]); - var thisTimer = setTimeout(function() { - RESUtils.closeNotification(thisNotification); - }, delay); - RESUtils.notificationTimers[thisNotificationID] = thisTimer; - thisNotification.addEventListener('mouseover',RESUtils.cancelCloseNotificationTimer, false); - thisNotification.removeEventListener('mouseout',RESUtils.setCloseNotification,false); - }, - cancelCloseNotificationTimer: function(e) { - var thisNotificationID = e.currentTarget.getAttribute('id').split('-')[1]; - removeClass(e.currentTarget,'timerOn'); - clearTimeout(RESUtils.notificationTimers[thisNotificationID]); - e.target.removeEventListener('mouseover',RESUtils.cancelCloseNotification,false); - e.currentTarget.addEventListener('mouseout',RESUtils.setCloseNotificationTimer, false); - }, - closeNotification: function(ele) { - RESUtils.fadeElementOut(ele, 0.1, RESUtils.notificationClosed); - }, - notificationClosed: function(ele) { - var notifications = RESUtils.RESNotifications.querySelectorAll('.RESNotification'); - var destroyed = 0; - for (var i=0, len=notifications.length; i'+offText+''; - thisToggle.innerHTML = ''+onText+''+offText+''; - thisToggle.addEventListener('click',function(e) { - var thisCheckbox = this.querySelector('input[type=checkbox]'); - var enabled = thisCheckbox.checked; - thisCheckbox.checked = !enabled; - (!enabled) ? addClass(this,'enabled') : removeClass(this,'enabled'); - }, false); - if (enabled) addClass(thisToggle,'enabled'); - return thisToggle; - }, - addCommas: function(nStr) { - nStr += ''; - x = nStr.split('.'); - x1 = x[0]; - x2 = x.length > 1 ? '.' + x[1] : ''; - var rgx = /(\d+)(\d{3})/; - while (rgx.test(x1)) { - x1 = x1.replace(rgx, '$1' + ',' + '$2'); - } - return x1 + x2; - } -} -// end RESUtils; - -// Create a nice alert function... -var gdAlert = { - container: false, - overlay: "", - - init: function(callback) { - //init - var alertCSS = '#alert_message { ' + - 'display: none;' + - 'opacity: 0.0;' + - 'background-color: #EFEFEF;' + - 'border: 1px solid black;' + - 'color: black;' + - 'font-size: 10px;' + - 'padding: 20px;' + - 'padding-left: 60px;' + - 'padding-right: 60px;' + - 'position: fixed!important;' + - 'position: absolute;' + - 'width: 400px;' + - 'float: left;' + - 'z-index: 10000;' + - 'text-align: left;' + - 'left: auto;' + - 'top: auto;' + - '}' + - '#alert_message .button {' + - 'border: 1px solid black;' + - 'font-weight: bold;' + - 'font-size: 10px;' + - 'padding: 4px;' + - 'padding-left: 7px;' + - 'padding-right: 7px;' + - 'float: left;' + - 'background-color: #DFDFDF;' + - 'cursor: pointer;' + - '}' + - '#alert_message span {' + - 'display: block;' + - 'margin-bottom: 15px; ' + - '}'; - - GM_addStyle(alertCSS); - - gdAlert.populateContainer(callback); - - }, - - populateContainer: function(callback) { - gdAlert.container = createElementWithID('div','alert_message'); - gdAlert.container.appendChild(document.createElement('span')); - if (typeof(callback) == 'function') { - this.okButton = document.createElement('input'); - this.okButton.setAttribute('type','button'); - this.okButton.setAttribute('value','confirm'); - this.okButton.addEventListener('click',callback, false); - this.okButton.addEventListener('click',gdAlert.close, false); - var closeButton = document.createElement('input'); - closeButton.setAttribute('type','button'); - closeButton.setAttribute('value','cancel'); - closeButton.addEventListener('click',gdAlert.close, false); - gdAlert.container.appendChild(this.okButton); - gdAlert.container.appendChild(closeButton); - } else { - /* if (this.okButton) { - gdAlert.container.removeChild(this.okButton); - delete this.okButton; - } */ - var closeButton = document.createElement('input'); - closeButton.setAttribute('type','button'); - closeButton.setAttribute('value','ok'); - closeButton.addEventListener('click',gdAlert.close, false); - gdAlert.container.appendChild(closeButton); - } - var br = document.createElement('br'); - br.setAttribute('style','clear: both'); - gdAlert.container.appendChild(br); - document.body.appendChild(gdAlert.container); - - }, - - open: function(text, callback) { - if (gdAlert.isOpen) { - console.log('there is already an alert open. break out.'); - return; - } - gdAlert.isOpen = true; - gdAlert.populateContainer(callback); - - //set message - gdAlert.container.getElementsByTagName("SPAN")[0].innerHTML = text; - gdAlert.container.getElementsByTagName("INPUT")[0].focus(); - gdAlert.container.getElementsByTagName("INPUT")[0].focus(); - - //create site overlay - gdAlert.overlay = document.createElement("DIV"); - gdAlert.overlay.style.width = gdAlert.getPageSize()[0] + "px"; - gdAlert.overlay.style.height = gdAlert.getPageSize()[1] + "px"; - gdAlert.overlay.style.backgroundColor = '#333333'; - gdAlert.overlay.style.top = '0'; - gdAlert.overlay.style.left = '0'; - gdAlert.overlay.style.position = 'absolute'; - gdAlert.overlay.style.zIndex = '9999'; - - document.body.appendChild(gdAlert.overlay); - - // center messagebox (requires prototype functions we don't have, so we'll redefine...) - // var arrayPageScroll = document.viewport.getScrollOffsets(); - // var winH = arrayPageScroll[1] + (document.viewport.getHeight()); - // var lightboxLeft = arrayPageScroll[0]; - var arrayPageScroll = [ document.documentElement.scrollLeft , document.documentElement.scrollTop ]; - var winH = arrayPageScroll[1] + (window.innerHeight); - var lightboxLeft = arrayPageScroll[0]; - - gdAlert.container.style.top = ((winH / 2) - 90) + "px"; - gdAlert.container.style.left = ((gdAlert.getPageSize()[0] / 2) - 155) + "px"; - - /* - new Effect.Appear(gdAlert.container, {duration: 0.2}); - new Effect.Opacity(gdAlert.overlay, {duration: 0.2, to: 0.8}); - */ - RESUtils.fadeElementIn(gdAlert.container, 0.3); - RESUtils.fadeElementIn(gdAlert.overlay, 0.3); - }, - - close: function() { - gdAlert.isOpen = false; - /* - new Effect.Fade(gdAlert.container, {duration: 0.3}); - new Effect.Fade(gdAlert.overlay, {duration: 0.3, afterFinish: function() { - document.body.removeChild(gdAlert.overlay); - }}); - */ - RESUtils.fadeElementOut(gdAlert.container, 0.3); - RESUtils.fadeElementOut(gdAlert.overlay, 0.3); - }, - - getPageSize: function() { - - var xScroll, yScroll; - - if (window.innerHeight && window.scrollMaxY) { - xScroll = window.innerWidth + window.scrollMaxX; - yScroll = window.innerHeight + window.scrollMaxY; - } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac - xScroll = document.body.scrollWidth; - yScroll = document.body.scrollHeight; - } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari - xScroll = document.body.offsetWidth; - yScroll = document.body.offsetHeight; - } - - var windowWidth, windowHeight; - - if (self.innerHeight) { // all except Explorer - if(document.documentElement.clientWidth){ - windowWidth = document.documentElement.clientWidth; - } else { - windowWidth = self.innerWidth; - } - windowHeight = self.innerHeight; - } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode - windowWidth = document.documentElement.clientWidth; - windowHeight = document.documentElement.clientHeight; - } else if (document.body) { // other Explorers - windowWidth = document.body.clientWidth; - windowHeight = document.body.clientHeight; - } - - // for small pages with total height less then height of the viewport - if(yScroll < windowHeight){ - pageHeight = windowHeight; - } else { - pageHeight = yScroll; - } - - // for small pages with total width less then width of the viewport - if(xScroll < windowWidth){ - pageWidth = xScroll; - } else { - pageWidth = windowWidth; - } - - return [pageWidth,pageHeight]; - } -} - -//overwrite the alert function -var alert = function(text, callback) { - if (gdAlert.container == false) { - gdAlert.init(callback); - } - gdAlert.open(text, callback); -} - -localStorageFail = false; - -// Check for localStorage functionality... -try { - localStorage.setItem('RES.localStorageTest','test'); - // if this is a firefox addon, check for the old lsTest to see if they used to use the Greasemonkey script... - // if so, present them with a notification explaining that they should download a new script so they can - // copy their old settings... - if (typeof(self.on) == 'function') { - if ((localStorage.getItem('RES.lsTest') == 'test') && (localStorage.getItem('copyComplete') != 'true')) { - RESUtils.notification('

Important Alert for Greasemonkey Users!

Hey! It looks like you have upgraded to RES 4.0, but used to use the Greasemonkey version of RES. You\'re going to see double until you uninstall the Greasemonkey script. However, you should first copy your settings by clicking the blue button. After installing, refresh this page! GM->FF Import Tool', 15000); - localStorage.removeItem('RES.lsTest'); - document.body.addEventListener('DOMNodeInserted', function(event) { - if ((event.target.tagName == 'DIV') && (event.target.getAttribute('id') && event.target.getAttribute('id').indexOf('copyToSimpleStorage') != -1)) { - GMSVtoFFSS(); - } - }, true); - } - } -} catch(e) { - localStorageFail = true; - /* - localStorage = { - getItem: function() { - return false; - }, - setItem: function() { - return false; - }, - removeItem: function() { - return false; - } - } - */ -} - -// this function copies localStorage (from the GM import script) to FF addon simplestorage... -function GMSVtoFFSS() { - var console = unsafeWindow.console; - for (key in localStorage) { - RESStorage.setItem(key, localStorage[key]); - } - localStorage.setItem('copyComplete','true'); - localStorage.removeItem('RES.lsTest'); - RESUtils.notification('Data transfer complete. You may now uninstall the Greasemonkey script'); -} - -// jquery plugin CSS -RESUtils.addCSS(tokenizeCSS); -RESUtils.addCSS(guidersCSS); -// RES Console CSS -RESUtils.addCSS(' \ -#RESConsole { \ - visibility: hidden; \ - color: #000; \ - font-size: 12px; \ - z-index: 1000; \ - position: fixed; \ - margin: auto; \ - top: -1500px; \ - left: 1.5%; \ - width: 95%; \ - height: 85%; \ - overflow: hidden; \ - padding: 10px; \ - box-shadow: 10px 10px 10px #aaa; \ - -moz-box-shadow: 10px 10px 10px #aaa; \ - -webkit-box-shadow: 10px 10px 10px #aaa; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - /* border: 4px solid #CCCCCC; */ \ - background-color: #ffffff; \ - -webkit-transition:top 0.5s ease-in-out; \ - -moz-transition:top 0.5s ease-in-out; \ - -o-transition:top 0.5s ease-in-out; \ - -ms-transition:top 0.5s ease-in-out; \ - -transition:top 0.5s ease-in-out; \ -} \ -#RESConsole.slideIn { \ - visibility: visible; \ - top: 30px; \ -} \ -#RESConsole.slideOut { \ - visibility: visible; \ - top: -1500px; \ -} \ -#modalOverlay { \ - display: none; \ - z-index: 999; \ - position: fixed; \ - top: 0px; \ - left: 0px; \ - width: 100%; \ - height: 100%; \ - background-color: #c9c9c9; \ - opacity: 0; \ - -webkit-transition:opacity 0.4s ease-in-out; \ - -moz-transition:opacity 0.4s ease-in-out; \ - -o-transition:opacity 0.4s ease-in-out; \ - -ms-transition:opacity 0.4s ease-in-out; \ - -transition:opacity 0.4s ease-in-out; \ -} \ -#modalOverlay.fadeIn { \ - display: block; \ - opacity: 0.9; \ -} \ -#modalOverlay.fadeOut { \ - display: block; \ - opacity: 0; \ - height: 0; \ -} \ -#RESSettingsButton { \ - display: inline-block; \ - margin: auto; \ - margin-bottom: -2px; \ - width: 15px; \ - height: 15px; \ - background-image: url(\'http://f.thumbs.redditmedia.com/ykyGgtUvyXldPc3A.png\'); \ - background-repeat: no-repeat; \ - background-position: 0px -209px; \ - vertical-align: bottom; \ -} \ -#RESSettingsButton.newNotification, .gearIcon.newNotification { \ - cursor: pointer; \ - background-position: 0px -135px; \ -} \ -#DashboardLink a { \ - display: block; \ - width: auto; \ - height: auto; \ -} \ -#RESMainGearOverlay { \ - position: relative; \ - width: 27px; \ - height: 22px; \ - border: 1px solid #336699; \ - border-bottom: 1px solid #5f99cf; \ - background-color: #5f99cf; \ - border-radius: 3px 3px 0px 0px; \ -} \ -.gearIcon { \ - position: absolute; \ - top: 3px; \ - left: 6px; \ - width: 15px; \ - height: 15px; \ - background-image: url(\'http://f.thumbs.redditmedia.com/ykyGgtUvyXldPc3A.png\'); \ - background-repeat: no-repeat; \ - background-position: 0px -209px; \ -} \ -#RESPrefsDropdown { \ - display: none; \ - position: absolute; \ - z-index: 10000; \ -} \ -#RESPrefsDropdown ul { \ - list-style-type: none; \ - background-color: #5f99cf; \ - width: 180px; \ - border-radius: 0px 0px 3px 3px; \ - border: 1px solid #336699; \ - margin-top: -1px; \ -} \ -#RESPrefsDropdown li { \ - cursor: pointer; \ - border-bottom: 1px solid #336699; \ - height: 35px; \ - line-height: 34px; \ - font-weight: bold; \ - color: #c9def2; \ - padding-left: 10px; \ -} \ -#RESPrefsDropdown a:visited { \ - color: #c9def2; \ -} \ -#RESPrefsDropdown li:hover, #RESPrefsDropdown li a:hover { \ - background-color: #9cc6ec; \ - color: #336699; \ -} \ -#openRESPrefs { \ - display: inline; \ -} \ -#RESConsoleHeader { \ - width: 100%; \ -} \ -#RESLogo { \ - margin-right: 5px; \ - float: left; \ -} \ -#RESConsoleTopBar { \ - border-radius: 3px 3px 0px 0px; \ - -moz-border-radius: 3px 3px 0px 0px; \ - -webkit-border-radius: 3px 3px 0px 0px; \ - position: absolute; \ - top: 0px; \ - left: 0px; \ - right: 0px; \ - height: 40px; \ - margin-bottom: 10px; \ - padding-top: 10px; \ - padding-left: 10px; \ - padding-right: 10px; \ - border-bottom: 1px solid #c7c7c7; \ - background-color: #F0F3FC; \ - float: left; \ -} \ -#RESConsoleTopBar h1 { \ - float: left; \ - margin-top: 6px; \ - padding: 0px; \ - font-size: 14px; \ -} \ -#RESConsoleSubredditLink { \ - float: right; \ - margin-right: 34px; \ - margin-top: 7px; \ - font-size: 11px; \ -} \ -.RESCloseButton { \ - position: absolute; \ - top: 7px; \ - right: 7px; \ - font: 12px Verdana, sans-serif; \ - background-color: #ffffff; \ - border: 1px solid #d7d9dc; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - color: #9a958e; \ - text-align: center; \ - line-height: 22px; \ - width: 24px; \ - height: 24px; \ - cursor: pointer; \ -} \ -#RESConsoleTopBar .RESCloseButton { \ - top: 9px; \ - right: 9px; \ -} \ -.RESCloseButton:hover { \ - border: 1px solid #999999; \ - background-color: #dddddd; \ -} \ -#RESClose { \ - float: right; \ - margin-top: 2px; \ - margin-right: 0px; \ -} \ -.RESDialogSmall { \ - background-color: #ffffff; \ - border: 1px solid #c7c7c7; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - font-size: 12px; \ - color: #666666; \ - position: relative; \ -} \ -.RESDialogSmall > h3 { \ - color: #000000; \ - font-size: 14px; \ - margin-top: 6px; \ - margin-bottom: 10px; \ - font-weight: normal; \ - position: absolute; \ - top: -5px; \ - left: 0px; \ - right: 0px; \ - background-color: #f0f3fc; \ - border-bottom: 1px solid #c7c7c7; \ - width: auto; \ - z-index: 10; \ - height: 28px; \ - padding-left: 10px; \ - padding-top: 12px; \ -} \ -.RESDialogSmall .RESDialogContents { \ - padding: 56px 12px 12px 12px; \ -} \ -#RESHelp { \ - background-image: url("http://f.thumbs.redditmedia.com/ykyGgtUvyXldPc3A.png"); \ - background-position: -16px -120px; \ - margin-right: 8px; \ - width: 16px; \ - height: 16px; \ - float: right; \ - cursor: pointer; \ -} \ -#RESMenu { \ - position: absolute; \ - top: 60px; \ - left: 15px; \ - right: 0px; \ - height: 30px; \ -} \ -#RESMenu li { \ - float: left; \ - text-align: center; \ - /* min-width: 80px; */ \ - height: 22px; \ - margin-right: 15px; \ - border: 1px solid #c7c7c7; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - padding-top: 6px; \ - padding-bottom: 0px; \ - padding-left: 8px; \ - padding-right: 8px; \ - cursor: pointer; \ - background-color: #dddddd; \ - color: #6c6c6c; \ -} \ -#RESMenu li.active { \ - border-color: #000000; \ - background-color: #7f7f7f; \ - color: #ffffff; \ -} \ -#RESMenu li:hover { \ - border-color: #000000; \ -} \ -#RESConsoleContent { \ - clear: both; \ - padding: 6px; \ - position: absolute; \ - top: 100px; \ - left: 0px; \ - right: 0px; \ - bottom: 0px; \ - border-top: 1px solid #DDDDDD; \ - overflow: auto; \ -} \ -#RESConfigPanelOptions, #RESAboutDetails { \ - margin-top: 15px; \ - display: block; \ - margin-left: 220px; \ -} \ -#allOptionsContainer { \ - position: relative; \ -} \ -#moduleOptionsScrim { \ - display: none; \ - position: absolute; \ - top: 1px; \ - left: 4px; \ - right: 13px; \ - bottom: 1px; \ - border-radius:2px \ - z-index: 1500; \ - background-color: #DDDDDD; \ - opacity: 0.7; \ -} \ -#moduleOptionsScrim.visible { \ - display: block; \ -} \ -#RESConfigPanelModulesPane, #RESAboutPane { \ - float: left; \ - width: 195px; \ - padding-right: 15px; \ - border-right: 1px solid #dedede; \ - height: 100%; \ -} \ -.moduleButton { \ - font-size: 12px; \ - color: #868686; \ - text-align: right; \ - padding-bottom: 3px; \ - padding-top: 3px; \ - margin-bottom: 12px; \ - cursor: pointer; \ - opacity: 0.5; \ -} \ -.moduleButton.enabled { \ - opacity: 1; \ -} \ -.moduleButton:hover { \ - text-decoration: underline; \ -} \ -.moduleButton.active, .moduleButton.active:hover { \ - opacity: 1; \ - font-weight: bold; \ -} \ -.RESPanel { \ - display: none; \ -} \ -.clear { \ - clear: both; \ -} \ -#keyCodeModal { \ - display: none; \ - width: 200px; \ - height: 40px; \ - position: absolute; \ - z-index: 1000; \ - background-color: #FFFFFF; \ - padding: 4px; \ - border: 2px solid #CCCCCC; \ -} \ -p.moduleListing { \ - padding-left: 5px; \ - padding-right: 5px; \ - padding-top: 5px; \ - padding-bottom: 15px; \ - border: 1px solid #BBBBBB; \ - -moz-box-shadow: 3px 3px 3px #BBB; \ - -webkit-box-shadow: 3px 3px 3px #BBB; \ -} \ -#RESConsoleModulesPanel label { \ - float: left; \ - width: 15%; \ - padding-top: 6px; \ -} \ -#RESConsoleModulesPanel input[type=checkbox] { \ - float: left; \ - margin-left: 10px; \ -} \ -#RESConsoleModulesPanel input[type=button] { \ - float: right; \ - padding: 3px; \ - margin-left: 20px; \ - font-size: 12px; \ - border: 1px solid #DDDDDD; \ - -moz-box-shadow: 3px 3px 3px #BBB; \ - -webkit-box-shadow: 3px 3px 3px #BBB; \ - background-color: #F0F3FC; \ - margin-bottom: 10px; \ -} \ -#RESConsoleModulesPanel p { \ - overflow: auto; \ - clear: both; \ - margin-bottom: 10px; \ -} \ -.moduleDescription { \ - float: left; \ - width: 500px; \ - margin-left: 10px; \ - padding-top: 6px; \ -} \ -#RESConfigPanelOptions .moduleDescription { \ - margin-left: 0px; \ - margin-top: 10px; \ - padding-top: 0px; \ - clear: both; \ - width: auto; \ -} \ -.moduleToggle, .toggleButton { \ - float: left; \ - width: 60px; \ - height: 20px; \ - cursor: pointer; \ -} \ -.moduleHeader { \ - border: 1px solid #c7c7c7; \ - border-radius: 2px 2px 2px 2px; \ - padding: 12px; \ - background-color: #f0f3fc; \ - display: block; \ - margin-bottom: 12px; \ - margin-right: 12px; \ - margin-left: 3px; \ - overflow: auto; \ -} \ -.moduleName { \ - font-size: 16px; \ - float: left; \ - margin-right: 15px; \ -} \ -#RESConsole .toggleButton { \ - margin-left: 10px; \ -} \ -.toggleButton input[type=checkbox] { \ - display: none; \ -} \ -.moduleToggle span, .toggleButton span { \ - margin-top: -3px; \ - font-size: 11px; \ - padding-top: 3px; \ - width: 28px; \ - height: 17px; \ - float: left; \ - display: inline-block; \ - text-align: center; \ -} \ -.moduleToggle .toggleOn, .toggleButton .toggleOn { \ - background-color: #dddddd; \ - color: #636363; \ - border-left: 1px solid #636363; \ - border-top: 1px solid #636363; \ - border-bottom: 1px solid #636363; \ - border-radius: 3px 0px 0px 3px; \ -} \ -.moduleToggle.enabled .toggleOn, .toggleButton.enabled .toggleOn { \ - background-color: #107ac4 ; \ - color: #ffffff; \ -} \ -.moduleToggle.enabled .toggleOff, .toggleButton.enabled .toggleOff { \ - background-color: #dddddd; \ - color: #636363; \ -} \ -.moduleToggle .toggleOff, .toggleButton .toggleOff { \ - background-color: #d02020; \ - color: #ffffff; \ - border-right: 1px solid #636363; \ - border-top: 1px solid #636363; \ - border-bottom: 1px solid #636363; \ - border-radius: 0px 3px 3px 0px; \ -} \ -.optionContainer { \ - position: relative; \ - border: 1px solid #c7c7c7; \ - border-radius: 2px 2px 2px 2px; \ - padding: 12px; \ - background-color: #f0f3fc; \ - display: block; \ - margin-bottom: 12px; \ - margin-right: 12px; \ - margin-left: 3px; \ - overflow: auto; \ -} \ -.optionContainer table { \ - clear: both; \ - width: 650px; \ - margin-top: 20px; \ -} \ -.optionContainer label { \ - float: left; \ - width: 175px; \ -} \ -.optionContainer input[type=text], .optionContainer input[type=password], div.enum { \ - margin-left: 10px; \ - float: left; \ - width: 140px; \ -} \ -.optionContainer input[type=checkbox] { \ - margin-left: 10px; \ - margin-top: 0px; \ - float: left; \ -} \ -.optionContainer .optionsTable input[type=text], .optionContainer .optionsTable input[type=password] { \ - margin-left: 0px; \ -} \ -.optionsTable th, .optionsTable td { \ - padding-bottom: 7px; \ -} \ -.optionDescription { \ - margin-left: 255px; \ -} \ -.optionDescription.textInput { \ - margin-left: 340px; \ -} \ -.optionDescription.table { \ - position: relative; \ - top: auto; \ - left: auto; \ - right: auto; \ - float: left; \ - width: 100%; \ - margin-left: 0px; \ - margin-top: 12px; \ - margin-bottom: 12px; \ -} \ -#RESConsoleVersion { \ - float: left; \ - font-size: 10px; \ - color: f0f3fc; \ - margin-left: 6px; \ - margin-top: 7px; \ -} \ -#moduleOptionsSave { \ - display: none; \ - position: fixed; \ - z-index: 1100; \ - top: 98px; \ - right: 4%; \ - cursor: pointer; \ - padding-top: 3px; \ - padding-bottom: 3px; \ - padding-left: 5px; \ - padding-right: 5px; \ - font-size: 12px; \ - color: #ffffff; \ - border: 1px solid #636363; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - background-color: #5cc410; \ - margin-bottom: 10px; \ -} \ -#moduleOptionsSave:hover { \ - background-color: #73e81e; \ -} \ -.addRowButton { \ - cursor: pointer; \ - padding-top: 2px; \ - padding-bottom: 2px; \ - padding-right: 5px; \ - padding-left: 5px; \ - color: #ffffff; \ - border: 1px solid #636363; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - background-color: #107ac4; \ -} \ -.addRowButton:hover { \ - background-color: #289dee; \ -} \ -#moduleOptionsSaveBottom { \ - float: right; \ - margin-top: 10px; \ - margin-right: 30px; \ - cursor: pointer; \ - padding: 3px; \ - font-size: 12px; \ - border: 1px solid #DDDDDD; \ - -moz-box-shadow: 3px 3px 3px #BBB; \ - -webkit-box-shadow: 3px 3px 3px #BBB; \ - background-color: #F0F3FC; \ - margin-bottom: 10px; \ -} \ -#moduleOptionsSaveStatus { \ - display: none; \ - position: fixed; \ - top: 98px; \ - right: 160px; \ - width: 180px; \ - padding: 5px; \ - text-align: center; \ - background-color: #FFFACD; \ -} \ -#moduleOptionsSaveStatusBottom { \ - display: none; \ - float: right; \ - margin-top: 10px; \ - width: 180px; \ - padding: 5px; \ - text-align: center; \ - background-color: #FFFACD; \ -} \ -#RESConsoleAboutPanel p { \ - margin-bottom: 10px; \ -} \ -#RESConsoleAboutPanel ul { \ - margin-bottom: 10px; \ - margin-top: 10px; \ -} \ -#RESConsoleAboutPanel li { \ - list-style-type: disc; \ - margin-left: 15px; \ -} \ -.aboutPanel { \ - background-color: #f0f3fc; \ - border: 1px solid #c7c7c7; \ - border-radius: 3px 3px 3px 3px; \ - padding: 10px; \ -} \ -.aboutPanel h3 { \ - margin-top: 0px; \ - margin-bottom: 10px; \ -} \ -#DonateRES { \ - display: block; \ -} \ -#RESTeam { \ - display: none; \ -} \ -#AboutRESTeamImage { \ - width: 100%; \ - background-color: #000000; \ - margin-bottom: 12px; \ -} \ -#AboutRESTeamImage img { \ - display: block; \ - margin: auto; \ -} \ -#AboutRES { \ - display: none; \ -} \ -.outdated { \ - float: right; \ - font-size: 11px; \ - margin-right: 15px; \ - margin-top: 5px; \ -} \ -#RESNotifications { \ - position: fixed; \ - top: 0px; \ - right: 10px; \ - height: auto; \ - width: 360px; \ - background: none; \ -} \ -.RESNotification { \ - opacity: 0; \ - position: relative; \ - font: 12px/14px Arial, Helvetica, Verdana, sans-serif; \ - z-index: 99999; \ - width: 360px; \ - margin-top: 6px; \ - border: 1px solid #ccccff; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - color: #000000; \ - background-color: #ffffff; \ -} \ -.RESNotification a { \ - color: orangered; \ -} \ -.RESNotification a:hover { \ - text-decoration: underline; \ -} \ -.RESNotification.timerOn { \ - border: 1px solid #c7c7c7; \ -} \ -.RESNotificationContent { \ - overflow: auto; \ - padding: 10px; \ - color: #999999; \ -} \ -.RESNotificationContent h2 { \ - color: #000000; \ - margin-bottom: 10px; \ -} \ -.RESNotificationHeader { \ - padding-left: 10px; \ - padding-right: 10px; \ - background-color: #f0f3fc; \ - border-bottom: #c7c7c7; \ - height: 38px; \ -} \ -.RESNotificationHeader h3 { \ - padding-top: 12px; \ - font-size: 15px; \ -} \ -.RESNotificationClose { \ - position: absolute; \ - right: 0px; \ - top: 0px; \ - margin-right: 12px; \ - margin-top: 6px; \ -} \ -a.RESNotificationButtonBlue { \ - clear: both; \ - float: right; \ - cursor: pointer; \ - margin-top: 12px; \ - padding-top: 3px; \ - padding-bottom: 3px; \ - padding-left: 5px; \ - padding-right: 5px; \ - font-size: 12px; \ - color: #ffffff !important; \ - border: 1px solid #636363; \ - border-radius: 3px 3px 3px 3px; \ - -moz-border-radius: 3px 3px 3px 3px; \ - -webkit-border-radius: 3px 3px 3px 3px; \ - background-color: #107ac4; \ -} \ -#baconBit { \ - position: fixed; \ - width: 32px; \ - height: 32px; \ - background-image: url("http://thumbs.reddit.com/t5_2s10b_6.png"); \ - top: -5%; \ - left: -5%; \ - z-index: 999999; \ - -webkit-transform: rotate(0deg); \ - -moz-transform: rotate(0deg); \ - transform: rotate(0deg); \ - -webkit-transition: all 2s linear; \ - -moz-transition: all 2s linear; \ - -o-transition: all 2s linear; \ - -ms-transition: all 2s linear; \ - -transition: all 2s linear; \ -} \ -#baconBit.makeitrain { \ - top: 100%; \ - left: 100%; \ - -webkit-transform: rotate(2000deg); \ - -moz-transform: rotate(2000deg); \ - transform: rotate(2000deg); \ -} \ -.RESButton { margin: 5px; padding: 3px; border: 1px solid #999999; width: 120px; cursor: pointer; border-radius: 5px 5px 5px 5px; -moz-border-radius: 5px 5px 5px 5px; -webkit-border-radius: 5px 5px 5px 5px; } \ -.RESButton:hover { background-color: #DDDDDD; } \ -'); - - -// define the RESConsole class -var RESConsole = { - // make the modules panel accessible to this class for updating (i.e. when preferences change, so we can redraw it) - RESConsoleModulesPanel: createElementWithID('div', 'RESConsoleModulesPanel', 'RESPanel'), - RESConsoleConfigPanel: createElementWithID('div', 'RESConsoleConfigPanel', 'RESPanel'), - RESConsoleAboutPanel: createElementWithID('div', 'RESConsoleAboutPanel', 'RESPanel'), - RESConsoleProPanel: createElementWithID('div', 'RESConsoleProPanel', 'RESPanel'), - addConsoleLink: function() { - this.userMenu = document.querySelector('#header-bottom-right'); - if (this.userMenu) { - var preferencesUL = this.userMenu.querySelector('UL'); - var separator = document.createElement('span'); - separator.setAttribute('class','separator'); - separator.innerHTML = '|'; - this.RESPrefsLink = document.createElement('span'); - this.RESPrefsLink.setAttribute('id','openRESPrefs'); - /* - if (RESStorage.getItem('RESoutdated') == 'true') { - // this.RESPrefsLink.innerHTML = '[RES](u)'; - this.RESPrefsLink.innerHTML = '(u)'; - } else { - // this.RESPrefsLink.innerHTML = '[RES]'; - this.RESPrefsLink.innerHTML = ''; - } - */ - this.RESPrefsLink.innerHTML = ''; - /* - this.RESPrefsLink.addEventListener('click', function(e) { - e.preventDefault(); - // RESConsole.open(); - RESConsole.showPrefsDropdown(); - }, true); - */ - // this.RESPrefsLink.addEventListener('click', RESConsole.showPrefsDropdown, true); - $(this.RESPrefsLink).mouseenter(RESConsole.showPrefsDropdown); - insertAfter(preferencesUL, this.RESPrefsLink); - insertAfter(preferencesUL, separator); - } - }, - addConsoleDropdown: function() { - this.prefsDropdown = createElementWithID('div','RESPrefsDropdown'); - this.prefsDropdown.innerHTML = '
  • settings console
'; - var thisSettingsButton = this.prefsDropdown.querySelector('#SettingsConsole'); - thisSettingsButton.addEventListener('click', function() { - RESConsole.hidePrefsDropdown(); - RESConsole.open(); - }, true); - $(this.prefsDropdown).mouseleave(function() { - RESConsole.hidePrefsDropdown(); - }); - document.body.appendChild(this.prefsDropdown); - if (RESStorage.getItem('RES.newAnnouncement','true')) { - RESUtils.setNewNotification(); - } - }, - showPrefsDropdown: function(e) { - var thisTop = parseInt($(RESConsole.userMenu).offset().top); - var thisRight = parseInt($(window).width() - $(RESConsole.RESPrefsLink).offset().left); - thisRight = 175-thisRight; - $('#RESMainGearOverlay').css('left',thisRight+'px'); - RESConsole.prefsDropdown.style.top = thisTop+'px'; - RESConsole.prefsDropdown.style.right = '0px'; - RESConsole.prefsDropdown.style.display = 'block'; - }, - hidePrefsDropdown: function(e) { - removeClass(RESConsole.RESPrefsLink, 'open'); - RESConsole.prefsDropdown.style.display = 'none'; - }, - resetModulePrefs: function() { - prefs = { - 'userTagger': true, - 'betteReddit': true, - 'singleClick': true, - 'subRedditTagger': true, - 'uppersAndDowners': true, - 'keyboardNav': true, - 'commentPreview': true, - 'showImages': true, - 'showKarma': true, - 'usernameHider': false, - 'accountSwitcher': true, - 'styleTweaks': true, - 'filteReddit': true, - 'RESPro': false - }; - this.setModulePrefs(prefs); - return prefs; - }, - getAllModulePrefs: function(force) { - // if we've done this before, just return the cached version - if ((!force) && (typeof(this.getAllModulePrefsCached) != 'undefined')) return this.getAllModulePrefsCached; - // get the stored preferences out first. - if (RESStorage.getItem('RES.modulePrefs') != null) { - var storedPrefs = safeJSON.parse(RESStorage.getItem('RES.modulePrefs'), 'RES.modulePrefs'); - } else if (RESStorage.getItem('modulePrefs') != null) { - // Clean up old moduleprefs. - var storedPrefs = safeJSON.parse(RESStorage.getItem('modulePrefs'), 'modulePrefs'); - RESStorage.removeItem('modulePrefs'); - this.setModulePrefs(storedPrefs); - } else { - // looks like this is the first time RES has been run - set prefs to defaults... - storedPrefs = this.resetModulePrefs(); - } - if (storedPrefs == null) { - storedPrefs = {}; - } - // create a new JSON object that we'll use to return all preferences. This is just in case we add a module, and there's no pref stored for it. - var prefs = {}; - // for any stored prefs, drop them in our prefs JSON object. - for (i in modules) { - if (storedPrefs[i]) { - prefs[i] = storedPrefs[i]; - } else if (storedPrefs[i] == null) { - // looks like a new module, or no preferences. We'll default it to on. - prefs[i] = true; - } else { - prefs[i] = false; - } - } - if ((typeof(prefs) != 'undefined') && (prefs != 'undefined') && (prefs)) { - this.getAllModulePrefsCached = prefs; - return prefs; - } - }, - getModulePrefs: function(moduleID) { - if (moduleID) { - var prefs = this.getAllModulePrefs(); - return prefs[moduleID]; - } else { - alert('no module name specified for getModulePrefs'); - } - }, - setModulePrefs: function(prefs) { - if (prefs != null) { - RESStorage.setItem('RES.modulePrefs', JSON.stringify(prefs)); - this.drawModulesPanel(); - return prefs; - } else { - alert('error - no prefs specified'); - } - }, - container: RESConsoleContainer, - create: function() { - // create the console container - RESConsoleContainer = createElementWithID('div', 'RESConsole'); - // hide it by default... - // RESConsoleContainer.style.display = 'none'; - // create a modal overlay - modalOverlay = createElementWithID('div', 'modalOverlay'); - modalOverlay.addEventListener('click',function(e) { - e.preventDefault(); - return false; - }, true); - document.body.appendChild(modalOverlay); - // create the header - RESConsoleHeader = createElementWithID('div', 'RESConsoleHeader'); - // create the top bar and place it in the header - RESConsoleTopBar = createElementWithID('div', 'RESConsoleTopBar'); - this.logo = 'data:image/gif;base64,R0lGODlhPAAeAPcAADo6OlxcXSQkJDExMQ8PDwkJCRISEhwcHCgoKBAQEBYWFgQEBAcHBxQVFAICAtDT2pCSlyAgIvDz+2BhZf7//5KTlSIiIvPz87y8vJGRkf7+/jU1NRkZGScnJ6enp/79/WNjY+nr8rW2ulBQUB8fH0xMTBgYGD4+PvX19S8vL42OkN7e3uXl5f7//tXX3Pb29v9PAOvr69fX18XFxe3v98LCwmVlZZmanf9UAOfq8P9YAJKSkrGxseTk5FpaWoWGiP39/f5LACAgIENDQ0dHR56fokhISC0tLXp6ep2eoDk5Of9NALe4u1JSUnZ2dpOUltrc4aurq/adcYeHh9DS15SUl76+vv328u3w+PiVY1lZWvZxLsLDx0VFRfa1kcfIzXx8fGFiY/rYxZSUlP9VAPaVYfhcC5qbmurs9PxJAHFyc+zs7Pvq3/3//+/x+ezv9jg4OF9fX+/v7/tNAOLk6uDg4ODi6IqKimRkZLKysqqrrv369uPj4+jo6CkpKnBxcm1tbUZGRmprbBgYGfnJrjs7PPekdvhbBxcXGPZ9Pvh1NpaXmdLT2Pvr4flfFfzv5u/y+omKjI2Njebo76+vsUdHSPvn3NXV1fZtJoODg/r6+mtra9zc3MrKysnLz/jRuF5fYOrs8+zu9bi4uLu7u2BgYPeMU3h4eHh5e/ehc/nGrPLy8svM0eTm7dja346PkU9PT39/f3R1dmRkZZ6enpiYmLW1tfz8/LO0t/T09Ovu9erq6v///jk6Off39/i4ls7Q1PZ/Qfd/RS4tLtbW1lhYWP36+O7x+Pa1j+7x+YSFh8TExPlZCaOjo5CQkPz18be3t+7u7jc3N3R0dFZXV+Pl697g5uHh4aOkptvd4mxtboiJi29vcUBBQ5GSlPvp3qGipbOzs/nYxKmqrcXGypWVlf369/i8mU9PUBUWFvWWYejp6Ofn55mbnSoqKnV1df359WxsbE1NTbe4vP1IAP5IAP9JAGZmaGdnaDQ0NA0NDf9MAPpNAAAAAP////Dz/CH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzBCMDk1MzM5NkZGMTFERjgyQTZGNzE3MzdDRTMxNzUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzBCMDk1MzQ5NkZGMTFERjgyQTZGNzE3MzdDRTMxNzUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozMEIwOTUzMTk2RkYxMURGODJBNkY3MTczN0NFMzE3NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozMEIwOTUzMjk2RkYxMURGODJBNkY3MTczN0NFMzE3NSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAAAAAAALAAAAAA8AB4AAAj/AP8JHEiwoMGDCBMqXMhwoIRjBnNU+QGlocWLBr316/WDC41/LvqlONEPHMaTFo+g0qOkQIEUBPD48+dsARaUOBHSYfBGoIRJT/qRmtnDAaOcSAmq8GOQxKaZtPrpSkr1QBKDX/oVMtJPBdWkIfpVO2jnnhZPX5PesJC27UBR2UQsOtBhnis0bpECk0WinwN9FjYMSOCg3yBB5CTkRQipyKx2bv5hQ9RPSYYaK1Zp8NcCRZ0ZtYYsMFBBMRN8ykLktUOAg5EOBhoQiMVipu3bt2PcUZBACAcifvqJcCugxC1/p/rZWHO7Be6ZFG5feNfPx8xM/XIYjPCg4AQICq05/+DkD0y/Zs/T+4uO29YCEP40CCmyvTvB7wpdLEARpZ+H2xoQkooqHzwnhiG/XHGbFf3s4M8wr9TnHXgJ0bBABkcEgNs5/OwzBzLszSQOM0HQU0aI/iBhAgYLsDIQBP3EGGM3D8goY0I39FOADLe1IQwMOsCgCIpSBKEDDo48chs7lFFzEHcTMsRNPs9lUQ8Z9piCmxdp4LDEFnvgNkQhCEF5H4UKRSLPc98Ec0giluAGjzpmYPLJcyCAUqZ9A+G3UBIApGcMG+b4wwtuHzTyTHqBqLEYFQvUpt6k6V1gACWLSZCOE5R2etsOCySz2D+49LMMbi8Ug0F6KzRxCW4yFJlQwagC/UHADLcBMUI/I2RAySh5nGFDAQL0cBsxJqBD60Bh9FNOrjycYAADCyxAwBFjXHCbBwxUotiyAo3TjzvhvHCbL7vw0Ucut2mCARz9zAouQaFoswAC0/AQQ3pyQIPEAAsE0Mq8B23TTwMMEBBYFyUQIY0ABiygQD+wEHxQBQYY0Ek0NUgCSCk+xBHPFBisc80BBghCa0AAOw=='; - this.loader = 'data:image/gif;base64,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'; - RESConsoleTopBar.innerHTML = '

reddit enhancement suite

'; - RESConsoleHeader.appendChild(RESConsoleTopBar); - this.RESConsoleVersion = createElementWithID('div','RESConsoleVersion'); - this.RESConsoleVersion.innerHTML = 'v' + RESVersion; - RESConsoleTopBar.appendChild(this.RESConsoleVersion); - RESSubredditLink = createElementWithID('a','RESConsoleSubredditLink'); - RESSubredditLink.innerHTML = '/r/Enhancement'; - RESSubredditLink.setAttribute('href','http://reddit.com/r/Enhancement'); - RESSubredditLink.setAttribute('alt','The RES Subreddit'); - RESConsoleTopBar.appendChild(RESSubredditLink); - // create the close button and place it in the header - RESClose = createElementWithID('span', 'RESClose', 'RESCloseButton'); - RESClose.innerHTML = 'X'; - RESClose.addEventListener('click',function(e) { - e.preventDefault(); - RESConsole.close(); - }, true); - RESConsoleTopBar.appendChild(RESClose); - // create the help button and place it in the header - /* - RESHelp = createElementWithID('span', 'RESHelp'); - RESHelp.innerHTML = ' '; - RESHelp.addEventListener('click',function(e) { - e.preventDefault(); - modules['RESTips'].randomTip(); - }, true); - RESConsoleTopBar.appendChild(RESHelp); - */ - /* - if (RESStorage.getItem('RESoutdated') == 'true') { - var RESOutdated = document.createElement('div'); - RESOutdated.setAttribute('class','outdated'); - RESOutdated.innerHTML = 'There is a new version of RES! click to grab it'; - RESConsoleTopBar.appendChild(RESOutdated); - } - */ - this.categories = new Array(); - for (i in modules) { - if ((typeof(modules[i].category) != 'undefined') && (this.categories.indexOf(modules[i].category) == -1)) { - this.categories.push(modules[i].category); - } - } - this.categories.sort(); - // create the menu - // var menuItems = this.categories.concat(Array('RES Pro','About RES')); - var menuItems = this.categories.concat(Array('About RES')); - RESMenu = createElementWithID('ul', 'RESMenu'); - for (i in menuItems) { - thisMenuItem = document.createElement('li'); - thisMenuItem.innerHTML = menuItems[i]; - thisMenuItem.setAttribute('id', 'Menu-' + menuItems[i]); - thisMenuItem.addEventListener('click', function(e) { - e.preventDefault(); - RESConsole.menuClick(this); - }, true); - RESMenu.appendChild(thisMenuItem); - } - RESConsoleHeader.appendChild(RESMenu); - RESConsoleContainer.appendChild(RESConsoleHeader); - // Store the menu items in a global variable for easy access by the menu selector function. - RESMenuItems = RESMenu.querySelectorAll('li'); - // Create a container for each management panel - this.RESConsoleContent = createElementWithID('div', 'RESConsoleContent'); - RESConsoleContainer.appendChild(this.RESConsoleContent); - // Okay, the console is done. Add it to the document body. - document.body.appendChild(RESConsoleContainer); - }, - drawModulesPanel: function() { - // Create the module management panel (toggle modules on/off) - RESConsoleModulesPanel = this.RESConsoleModulesPanel; - RESConsoleModulesPanel.innerHTML = ''; - var prefs = this.getAllModulePrefs(true); - var modulesPanelHTML = ''; - for (i in modules) { - (prefs[i]) ? thisChecked = 'CHECKED' : thisChecked = ''; - if (typeof(modules[i]) != 'undefined') { - thisDesc = modules[i].description; - modulesPanelHTML += '

'+thisDesc+'

'; - } - } - RESConsoleModulesPanel.innerHTML = modulesPanelHTML; - var RESConsoleModulesPanelButtons = createElementWithID('span','RESConsoleModulesPanelButtons'); - var RESSavePrefsButton = createElementWithID('input','savePrefs'); - RESSavePrefsButton.setAttribute('type','button'); - RESSavePrefsButton.setAttribute('name','savePrefs'); - RESSavePrefsButton.setAttribute('value','save'); - RESSavePrefsButton.addEventListener('click', function(e) { - e.preventDefault(); - var modulePrefsCheckboxes = RESConsole.RESConsoleModulesPanel.querySelectorAll('input[type=checkbox]'); - var prefs = {}; - for (i=0, len=modulePrefsCheckboxes.length;i modules[b].moduleName.toLowerCase()) return 1; - return -1; - }); - /* - for (var i=0, len=moduleList.length; i'; - var thisToggle = document.createElement('div'); - addClass(thisToggle,'moduleToggle'); - thisToggle.innerHTML = 'onoff'; - if (modules[moduleID].isEnabled()) addClass(thisToggle,'enabled'); - thisToggle.setAttribute('moduleID',moduleID); - thisToggle.addEventListener('click', function(e) { - var activePane = RESConsole.RESConfigPanelModulesPane.querySelector('.active'); - var enabled = !(!hasClass(this, 'enabled')); - if (enabled) { - removeClass(activePane, 'enabled') - removeClass(this, 'enabled') - addClass(RESConsole.moduleOptionsScrim,'visible'); - $('#moduleOptionsSave').hide(); - } else { - addClass(activePane, 'enabled'); - addClass(this, 'enabled'); - removeClass(RESConsole.moduleOptionsScrim,'visible'); - $('#moduleOptionsSave').fadeIn(); - } - RESConsole.enableModule(this.getAttribute('moduleID'), !enabled); - }, true); - thisHeader.appendChild(thisToggle); - // not really looping here, just only executing if there's 1 or more options... - for (var i in thisOptions) { - var thisSaveButton = createElementWithID('input','moduleOptionsSave'); - thisSaveButton.setAttribute('type','button'); - thisSaveButton.setAttribute('value','save options'); - thisSaveButton.addEventListener('click',function(e) { - RESConsole.saveCurrentModuleOptions(e); - }, true); - /* - var thisBottomSaveButton = createElementWithID('input','moduleOptionsSaveBottom'); - thisBottomSaveButton.setAttribute('type','button'); - thisBottomSaveButton.setAttribute('value','save options'); - thisBottomSaveButton.addEventListener('click',function(e) { - RESConsole.saveCurrentModuleOptions(e); - }, true); - */ - // thisHeader.appendChild(thisSaveButton); - this.RESConsoleConfigPanel.appendChild(thisSaveButton); - var thisSaveStatus = createElementWithID('div','moduleOptionsSaveStatus','saveStatus'); - thisHeader.appendChild(thisSaveStatus); - break; - } - var thisDescription = document.createElement('div'); - addClass(thisDescription,'moduleDescription'); - thisDescription.innerHTML = modules[moduleID].description; - thisHeader.appendChild(thisDescription); - RESConfigPanelOptions.appendChild(thisHeader); - var allOptionsContainer = createElementWithID('div', 'allOptionsContainer'); - RESConfigPanelOptions.appendChild(allOptionsContainer); - // now draw all the options... - for (var i in thisOptions) { - if (!(thisOptions[i].noconfig)) { - optCount++; - var thisOptionContainer = createElementWithID('div', null, 'optionContainer'); - var thisLabel = document.createElement('label'); - thisLabel.setAttribute('for',i); - thisLabel.innerHTML = i; - thisOptionDescription = createElementWithID('div', null, 'optionDescription'); - thisOptionDescription.innerHTML = thisOptions[i].description; - thisOptionContainer.appendChild(thisLabel); - if (thisOptions[i].type == 'table') { - addClass(thisOptionDescription,'table'); - // table - has a list of fields (headers of table), users can add/remove rows... - if (typeof(thisOptions[i].fields) == 'undefined') { - alert('misconfigured table option in module: ' + moduleID + ' - options of type "table" must have fields defined'); - } else { - // get field names... - var fieldNames = new Array(); - // now that we know the field names, get table rows... - var thisTable = document.createElement('table'); - thisTable.setAttribute('moduleID',moduleID); - thisTable.setAttribute('optionName',i); - thisTable.setAttribute('class','optionsTable'); - var thisThead = document.createElement('thead'); - var thisTableHeader = document.createElement('tr'); - thisTable.appendChild(thisThead); - for (var j=0;j 0) { - this.keyCodeModal = createElementWithID('div','keyCodeModal'); - this.keyCodeModal.innerHTML = 'Press a key (or combination with shift, alt and/or ctrl) to assign this action.'; - document.body.appendChild(this.keyCodeModal); - for (var i=0, len=keyCodeInputs.length;i= 0)) { - var tempArray = inputs[i].value.split(','); - // convert the internal values of this array into their respective types (int, bool, bool, bool) - var optionValue = Array(parseInt(tempArray[0]), (tempArray[1] == 'true'), (tempArray[2] == 'true'), (tempArray[3] == 'true'), (tempArray[4] == 'true')); - } else { - var optionValue = inputs[i].value; - } - } - if (typeof(optionValue) != 'undefined') { - RESUtils.setOption(moduleID, optionName, optionValue); - } - } - } - // Check if there are any tables of options on this panel... - var optionsTables = panelOptionsDiv.querySelectorAll('.optionsTable'); - if (typeof(optionsTables) != 'undefined') { - // For each table, we need to go through each row in the tbody, and then go through each option and make a multidimensional array. - // For example, something like: [['foo','bar','baz'],['pants','warez','cats']] - for (i=0, len=optionsTables.length;i= 0)) { - var tempArray = inputs[l].value.split(','); - // convert the internal values of this array into their respective types (int, bool, bool, bool) - optionValue = Array(parseInt(tempArray[0]), (tempArray[1] == 'true'), (tempArray[2] == 'true'), (tempArray[3] == 'true')); - } else { - optionValue = inputs[l].value; - } - } - if ((optionValue != '') && (inputs[l].getAttribute('type') != 'radio')) { - notAllBlank = true; - } - // optionRow[k] = optionValue; - } - optionRow.push(optionValue); - } - // just to be safe, added a check for optionRow != null... - if ((notAllBlank) && (optionRow != null)) { - optionMulti[optionRowCount] = optionRow; - optionRowCount++; - } - } - if (optionMulti == null) { - optionMulti = []; - } - // ok, we've got all the rows... set the option. - if (typeof(optionValue) != 'undefined') { - RESUtils.setOption(moduleID, optionName, optionMulti); - } - } - } - } - - var statusEle = document.getElementById('moduleOptionsSaveStatus'); - statusEle.innerHTML = 'Options have been saved...'; - statusEle.setAttribute('style','display: block; opacity: 1'); - RESUtils.fadeElementOut(statusEle, 0.1) - /* - var statusEleBottom = document.getElementById('moduleOptionsSaveStatusBottom'); - statusEleBottom.innerHTML = 'Options have been saved...'; - statusEleBottom.setAttribute('style','display: block; opacity: 1'); - RESUtils.fadeElementOut(statusEleBottom, 0.1) - */ - if (moduleID == 'RESPro') RESStorage.removeItem('RESmodules.RESPro.lastAuthFailed'); - }, - drawAboutPanel: function() { - RESConsoleAboutPanel = this.RESConsoleAboutPanel; - var AboutPanelHTML = ' \ -
\ -
Donate
\ -
About RES
\ -
About the RES Team
\ -
\ -
\ -
\ -

Donate to support RES

\ -

RES is entirely free - as in beer, as in open source, as in everything. If you like our work, a contribution would be greatly appreciated.

\ -

When you donate, you make it possible for the team to cover hosting costs and other expenses so that we can focus on doing what we do best: making your Reddit experience even better.

\ -

\ -

\ -

\ -

\ -

\ -

\ - Or use Google Checkout: \ -

\ - \ - \ - \ - $ \ - \ - \ - \ -
\ -

\ -
\ -
\ -

About RES

\ -

Author: honestbleeps

\ -

UI Designer: solidwhetstone

\ -

Description: Reddit Enhancement Suite is a collection of modules that makes browsing reddit a whole lot easier.

\ -

It\'s built with an API that allows you to contribute and include your own modules!

\ -

If you\'ve got bug reports, you\'d like to discuss RES, or you\'d like to converse with other users, please see the Enhancement subreddit.

\ -

If you want to contact me directly with suggestions, bug reports or just want to say you appreciate the work, an email would be great.

\ -

License: Reddit Enhancement Suite is released under the GPL v3.0.

\ -

Note: Reddit Enhancement Suite will check, at most once a day, to see if a new version is available. No data about you is sent to me nor is it stored.

\ -
\ -
\ -

About the RES Team

\ -
\ -

Steve Sobel (honestbleeps) and Daniel Allen (solidwhetstone) are Chicago-area Redditors on a mission to make your Reddit experience the best it can possibly be. You might say they\'re on a mission from Snoo.

\ -
\ -
\ - ' - RESConsoleAboutPanel.innerHTML = AboutPanelHTML; - $(RESConsoleAboutPanel).find('.moduleButton').click(function() { - $('.moduleButton').removeClass('active'); - $(this).addClass('active'); - var thisID = $(this).attr('id'); - var thisPanel = thisID.replace('Button-',''); - var visiblePanel = $(this).parent().parent().find('.aboutPanel:visible'); - $(visiblePanel).fadeOut(function() { - $('#'+thisPanel).fadeIn(); - }); - }); - this.RESConsoleContent.appendChild(RESConsoleAboutPanel); - }, - drawProPanel: function() { - RESConsoleProPanel = this.RESConsoleProPanel; - var proPanelHeader = document.createElement('div'); - proPanelHeader.innerHTML = 'RES Pro allows you to save your preferences to the RES Pro server.

Please note: this is beta functionality right now. Please don\'t consider this to be a "backup" solution just yet. To start, you will need to register for a PRO account first, then email steve@honestbleeps.com with your RES Pro username to get access.'; - RESConsoleProPanel.appendChild(proPanelHeader); - this.proSetupButton = createElementWithID('div','RESProSetup'); - this.proSetupButton.setAttribute('class','RESButton'); - this.proSetupButton.innerHTML = 'Configure RES Pro'; - this.proSetupButton.addEventListener('click', function(e) { - e.preventDefault(); - modules['RESPro'].configure(); - }, false); - RESConsoleProPanel.appendChild(this.proSetupButton); - /* - this.proAuthButton = createElementWithID('div','RESProAuth'); - this.proAuthButton.setAttribute('class','RESButton'); - this.proAuthButton.innerHTML = 'Authenticate'; - this.proAuthButton.addEventListener('click', function(e) { - e.preventDefault(); - modules['RESPro'].authenticate(); - }, false); - RESConsoleProPanel.appendChild(this.proAuthButton); - */ - this.proSaveButton = createElementWithID('div','RESProSave'); - this.proSaveButton.setAttribute('class','RESButton'); - this.proSaveButton.innerHTML = 'Save Module Options'; - this.proSaveButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].savePrefs(); - modules['RESPro'].authenticate(modules['RESPro'].savePrefs()); - }, false); - RESConsoleProPanel.appendChild(this.proSaveButton); - - /* - this.proUserTaggerSaveButton = createElementWithID('div','RESProSave'); - this.proUserTaggerSaveButton.setAttribute('class','RESButton'); - this.proUserTaggerSaveButton.innerHTML = 'Save user tags to Server'; - this.proUserTaggerSaveButton.addEventListener('click', function(e) { - e.preventDefault(); - modules['RESPro'].saveModuleData('userTagger'); - }, false); - RESConsoleProPanel.appendChild(this.proUserTaggerSaveButton); - */ - - this.proSaveCommentsSaveButton = createElementWithID('div','RESProSaveCommentsSave'); - this.proSaveCommentsSaveButton.setAttribute('class','RESButton'); - this.proSaveCommentsSaveButton.innerHTML = 'Save saved comments to Server'; - this.proSaveCommentsSaveButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].saveModuleData('saveComments'); - modules['RESPro'].authenticate(modules['RESPro'].saveModuleData('saveComments')); - }, false); - RESConsoleProPanel.appendChild(this.proSaveCommentsSaveButton); - - this.proSubredditManagerSaveButton = createElementWithID('div','RESProSubredditManagerSave'); - this.proSubredditManagerSaveButton.setAttribute('class','RESButton'); - this.proSubredditManagerSaveButton.innerHTML = 'Save subreddits to server'; - this.proSubredditManagerSaveButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].saveModuleData('SubredditManager'); - modules['RESPro'].authenticate(modules['RESPro'].saveModuleData('subredditManager')); - }, false); - RESConsoleProPanel.appendChild(this.proSubredditManagerSaveButton); - - this.proSaveCommentsGetButton = createElementWithID('div','RESProGetSavedComments'); - this.proSaveCommentsGetButton.setAttribute('class','RESButton'); - this.proSaveCommentsGetButton.innerHTML = 'Get saved comments from Server'; - this.proSaveCommentsGetButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].getModuleData('saveComments'); - modules['RESPro'].authenticate(modules['RESPro'].getModuleData('saveComments')); - }, false); - RESConsoleProPanel.appendChild(this.proSaveCommentsGetButton); - - this.proSubredditManagerGetButton = createElementWithID('div','RESProGetSubredditManager'); - this.proSubredditManagerGetButton.setAttribute('class','RESButton'); - this.proSubredditManagerGetButton.innerHTML = 'Get subreddits from Server'; - this.proSubredditManagerGetButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].getModuleData('SubredditManager'); - modules['RESPro'].authenticate(modules['RESPro'].getModuleData('subredditManager')); - }, false); - RESConsoleProPanel.appendChild(this.proSubredditManagerGetButton); - - this.proGetButton = createElementWithID('div','RESProGet'); - this.proGetButton.setAttribute('class','RESButton'); - this.proGetButton.innerHTML = 'Get options from Server'; - this.proGetButton.addEventListener('click', function(e) { - e.preventDefault(); - // modules['RESPro'].getPrefs(); - modules['RESPro'].authenticate(modules['RESPro'].getPrefs()); - }, false); - RESConsoleProPanel.appendChild(this.proGetButton); - this.RESConsoleContent.appendChild(RESConsoleProPanel); - }, - open: function() { - // no more modules panel! - // this.drawModulesPanel(); - // Draw the config panel - this.drawConfigPanel(); - // Draw the about panel - this.drawAboutPanel(); - // Draw the RES Pro panel - // this.drawProPanel(); - // Set an easily accessible array of the panels so we can show/hide them as necessary. - RESConsolePanels = this.RESConsoleContent.querySelectorAll('.RESPanel'); - - this.isOpen = true; - // hide the ad-frame div in case it's flash, because then it covers up the settings console and makes it impossible to see the save button! - var adFrame = document.getElementById('ad-frame'); - if ((typeof(adFrame) != 'undefined') && (adFrame != null)) { - adFrame.style.display = 'none'; - } - // var leftCentered = Math.floor((window.innerWidth - 720) / 2); - // modalOverlay.setAttribute('style','display: block; height: ' + document.documentElement.scrollHeight + 'px'); - removeClass(modalOverlay, 'fadeOut'); - addClass(modalOverlay, 'fadeIn'); - - // RESConsoleContainer.setAttribute('style','display: block; left: ' + leftCentered + 'px'); - // RESConsoleContainer.setAttribute('style','display: block; left: 1.5%;'); - removeClass(RESConsoleContainer, 'slideOut'); - addClass(RESConsoleContainer, 'slideIn'); - RESConsole.menuClick(RESMenuItems[0]); - }, - close: function() { - $('#moduleOptionsSave').fadeOut(); - this.isOpen = false; - // Let's be nice to reddit and put their ad frame back now... - var adFrame = document.getElementById('ad-frame'); - if ((typeof(adFrame) != 'undefined') && (adFrame != null)) { - adFrame.style.display = 'block'; - } - // RESConsoleContainer.setAttribute('style','display: none;'); - removeClass(modalOverlay, 'fadeIn'); - addClass(modalOverlay, 'fadeOut'); - removeClass(RESConsoleContainer, 'slideIn'); - addClass(RESConsoleContainer, 'slideOut'); - // just in case the user was in the middle of setting a key and decided to close the dialog, clean that up. - if (typeof(RESConsole.keyCodeModal) != 'undefined') { - RESConsole.keyCodeModal.style.display = 'none'; - RESConsole.captureKey = false; - } - }, - menuClick: function(obj) { - if (obj) objID = obj.getAttribute('id'); - // make all menu items look unselected - for (i in RESMenuItems) { - if (i == 'length') break; - removeClass(RESMenuItems[i], 'active'); - } - // make selected menu item look selected - addClass(obj, 'active'); - // hide all console panels - for (i in RESConsolePanels) { - // bug in chrome, barfs on for i in loops with queryselectorall... - if (i == 'length') break; - RESConsolePanels[i].setAttribute('style', 'display: none'); - } - switch(objID) { - case 'Menu-Enable Modules': - // show the modules panel - RESConsoleModulesPanel.setAttribute('style', 'display: block'); - break; - case 'Menu-Configure Modules': - // show the config panel - this.RESConfigPanelSelector.selectedIndex = 0; - this.RESConsoleConfigPanel.setAttribute('style', 'display: block'); - break; - case 'Menu-About RES': - // show the about panel - RESConsoleAboutPanel.setAttribute('style', 'display: block'); - break; - case 'Menu-RES Pro': - // show the pro panel - RESConsoleProPanel.setAttribute('style', 'display: block'); - break; - default: - var objSplit = objID.split('-'); - var category = objSplit[objSplit.length-1]; - this.RESConfigPanelSelector.selectedIndex = 0; - this.RESConsoleConfigPanel.setAttribute('style', 'display: block'); - this.drawConfigPanel(category); - break; - } - } -}; - - -/************************************************************************************************************ - -Creating your own module: - -Modules must have the following format, with required functions: -- moduleID - the name of the module, i.e. myModule -- moduleName - a "nice name" for your module... -- description - for the config panel, explains what the module is -- isEnabled - should always return RESConsole.getModulePrefs('moduleID') - where moduleID is your module name. -- isMatchURL - should always return RESUtils.isMatchURL('moduleID') - checks your include and exclude URL matches. -- include - an array of regexes to match against location.href (basically like include in GM) -- exclude (optional) - an array of regexes to exclude against location.href -- go - always checks both if isEnabled() and if RESUtils.isMatchURL(), and if so, runs your main code. - -modules['myModule'] = { - moduleID: 'myModule', - moduleName: 'my module', - category: 'CategoryName', - options: { - // any configurable options you have go here... - // options must have a type and a value.. - // valid types are: text, boolean (if boolean, value must be true or false) - // for example: - defaultMessage: { - type: 'text', - value: 'this is default text', - description: 'explanation of what this option is for' - }, - doSpecialStuff: { - type: 'boolean', - value: false, - description: 'explanation of what this option is for' - } - }, - description: 'This is my module!', - isEnabled: function() { - return RESConsole.getModulePrefs(this.moduleID); - }, - include: Array( - /http:\/\/([a-z]+).reddit.com\/user\/[-\w\.]+/i, - /http:\/\/([a-z]+).reddit.com\/message\/comments\/[-\w\.]+/i - ), - isMatchURL: function() { - return RESUtils.isMatchURL(this.moduleID); - }, - go: function() { - if ((this.isEnabled()) && (this.isMatchURL())) { - // do stuff now! - // this is where your code goes... - } - } -}; // note: you NEED this semicolon at the end! - -************************************************************************************************************/ - - -modules['subRedditTagger'] = { - moduleID: 'subRedditTagger', - moduleName: 'Subreddit Tagger', - category: 'Filters', - options: { - subReddits: { - type: 'table', - addRowText: '+add tag', - fields: [ - { name: 'subreddit', type: 'text' }, - { name: 'doesntContain', type: 'text' }, - { name: 'tag', type: 'text' } - ], - value: [ - /* - ['somebodymakethis','SMT','[SMT]'], - ['pics','pic','[pic]'] - */ - ], - description: 'Set your subreddits below. For that subreddit, if the title of the post doesn\'t contain what you place in the "doesn\'t contain" field, the subreddit will be tagged with whatever you specify.' - } - }, - description: 'Adds tags to posts on subreddits (i.e. [SMT] on SomebodyMakeThis when the user leaves it out)', - isEnabled: function() { - return RESConsole.getModulePrefs(this.moduleID); - }, - include: Array( - /https?:\/\/([a-z]+).reddit.com\/[\?]*/i - ), - isMatchURL: function() { - return RESUtils.isMatchURL(this.moduleID); - }, - go: function() { - if ((this.isEnabled()) && (this.isMatchURL())) { - // get this module's options... - // RESUtils.getOptions(this.moduleID); - // do stuff now! - // this is where your code goes... - this.checkForOldSettings(); - this.SRTDoesntContain = new Array(); - this.SRTTagWith = new Array(); - this.loadSRTRules(); - - document.body.addEventListener('DOMNodeInserted', function(event) { - if ((event.target.tagName == 'DIV') && (event.target.getAttribute('id') && event.target.getAttribute('id').indexOf('siteTable') != -1)) { - modules['subRedditTagger'].scanTitles(event.target); - } - }, true); - this.scanTitles(); - - } - }, - loadSRTRules: function () { - var subReddits = this.options.subReddits.value; - for (var i=0, len=subReddits.length; i 0) { - RESUtils.setOption('subRedditTagger', 'subReddits', settingsCopy); - } - } - -}; - - -modules['uppersAndDowners'] = { - moduleID: 'uppersAndDowners', - moduleName: 'Uppers and Downers Enhanced', - category: 'UI', - options: { - showSigns: { - type: 'boolean', - value: false, - description: 'Show +/- signs next to upvote/downvote tallies.' - }, - applyToLinks: { - type: 'boolean', - value: true, - description: 'Uppers and Downers on links.' - }, - postUpvoteStyle: { - type: 'text', - value: 'color:rgb(255, 139, 36); font-weight:normal;', - description: 'CSS style for post upvotes' - }, - postDownvoteStyle: { - type: 'text', - value: 'color:rgb(148, 148, 255); font-weight:normal;', - description: 'CSS style for post upvotes' - }, - commentUpvoteStyle: { - type: 'text', - value: 'color:rgb(255, 139, 36); font-weight:bold;', - description: 'CSS style for comment upvotes' - }, - commentDownvoteStyle: { - type: 'text', - value: 'color:rgb(148, 148, 255); font-weight:bold;', - description: 'CSS style for comment upvotes' - }, - forceVisible: { - type: 'boolean', - value: false, - description: 'Force upvote/downvote counts to be visible (when subreddit CSS tries to hide them)' - } - }, - description: 'Displays up/down vote counts on comments.', - isEnabled: function() { - return RESConsole.getModulePrefs(this.moduleID); - }, - include: Array( - /https?:\/\/([a-z]+).reddit.com\/?(?:\??[\w]+=[\w]+&?)*/i, - /https?:\/\/([a-z]+).reddit.com\/r\/[\w]+\/?(?:\??[\w]+=[\w]+&?)*$/i, - /https?:\/\/([a-z]+).reddit.com\/user\/[-\w\.]+/i, - /https?:\/\/([a-z]+).reddit.com\/[-\w\.\/]+\/comments\/[-\w\.]+/i, - /https?:\/\/([a-z]+).reddit.com\/comments\/[-\w\.]+/i - ), - isMatchURL: function() { - return RESUtils.isMatchURL(this.moduleID); - }, - go: function() { - if ((this.isEnabled()) && (this.isMatchURL())) { - // get rid of the showTimeStamp options since Reddit now has this feature natively. - if (typeof(this.options.showTimestamp) != 'undefined') { - delete this.options.showTimestamp; - RESStorage.setItem('RESoptions.uppersAndDowners', JSON.stringify(modules['uppersAndDowners'].options)); - } - // added code to force inline-block and opacity: 1 to prevent CSS from hiding .res_* classes... - var forceVisible = (this.options.forceVisible.value) ? '; opacity: 1 !important; display: inline-block !important;' : ''; - var css = '.res_comment_ups { '+this.options.commentUpvoteStyle.value+forceVisible+' } .res_comment_downs { '+this.options.commentDownvoteStyle.value+forceVisible+' }'; - css += '.res_post_ups { '+this.options.postUpvoteStyle.value+forceVisible+' } .res_post_downs { '+this.options.postDownvoteStyle.value+forceVisible+' }'; - RESUtils.addCSS(css); - if ((RESUtils.pageType() == 'comments') || (RESUtils.pageType() == 'profile')) { - this.commentsWithMoos = Array(); - this.moreCommentsIDs = Array(); - this.applyUppersAndDownersToComments(); - var moreComments = document.querySelectorAll('.morecomments > a'); - for (var i=0, len=moreComments.length; i rather than one of its children... - while ((moreCommentsParent != null) && (moreCommentsParent.className != 'morecomments')) { - moreCommentsParent = moreCommentsParent.parentNode; - } - var i=0; - var isDeepComment = true; - // Now, check if this is link nested deep inside comments, or a top level "load more comments" link at the bottom of a page. - while (i<6) { - if ((moreCommentsParent != null) && (typeof(moreCommentsParent.parentNode) != 'undefined')) { - moreCommentsParent = moreCommentsParent.parentNode; - if (moreCommentsParent.className == 'commentarea') { - i=6; - isDeepComment = false; - } - } else { - i=6; - isDeepComment = false; - } - i++; - } - if (isDeepComment) { - moreCommentsParent.addEventListener('DOMNodeInserted', modules['uppersAndDowners'].processMoreComments, true); - } else { - // There isn't a good way to handle this with a single API call right now, so it'd make a new API call for each - // hit, and that sucks. Skipping this for now. - // document.body.addEventListener('DOMNodeInserted', modules['uppersAndDowners'].processMoreCommentsTopLevel, true); - } - }, - processMoreCommentsTopLevel: function (event) { - if (typeof(trackCount) == 'undefined') { - trackCount = 0; - } else { - if (event.target.tagName == 'DIV') { - trackCount++; - if (trackCount < 30) { - // console.log(event.target); - } - } - } - }, - processMoreComments: function (event) { - if ((event.target.tagName == 'DIV') && (hasClass(event.target, 'thing'))) { - var getID = /id-([\w])+\_([\w]+)/i; - var IDMatch = getID.exec(event.currentTarget.getAttribute('class')); - if (IDMatch) { - var thisID = IDMatch[2]; - if (typeof(modules['uppersAndDowners'].moreCommentsIDs[thisID]) == 'undefined') { - modules['uppersAndDowners'].moreCommentsIDs[thisID] = true; - var thisHREF = location.href + thisID; - event.currentTarget.removeEventListener('DOMNodeInserted', this.processMoreComments, true); - modules['uppersAndDowners'].applyUppersAndDownersToComments(thisHREF); - } - } - } - }, - applyUppersAndDownersToComments: function(href) { - /* - The Reddit Uppers/Downers module is included as a convenience, but I did not write it. - Original credits are below. - - I have, however, greatly modified it to integrate better with RES and also add some configuration options. - */ - /* - This code is provided as is, with no warranty of any kind. - - I hacked it together in one night for my own use, and have not tested it extensively. - - The script can slow down comment page load time; if the lag is noticeable, you may want - to change your preferences to load fewer comments per page. - - Note that this runs once and does not install any persistent code on the page. So any votes - you cast will not affect the numbers displayed until you reload. - - Also note that the ups and downs will not always add up to the score displayed on reddit. - I think this is because of caching on reddit's part. It's usually within one or two points though. - - Code contributors: Allan Bogh - http://www.opencodeproject.com - brasso - http://userscripts.org/scripts/show/56641 - savetheclocktower - http://gist.github.com/174069 - skeww (jslint, fragment, chunking) - http://kaioa.com - */ - - var loc, jsonURL, voteTable, onloadJSON, displayVotes, processTree, isComment, processChildren, processReplies, chunker; - - //Get the URL for the JSON details of this comments page - if (href) { - loc = href; - } else { - loc = "" + window.location; - } - jsonURL = loc.replace(/\/$/,'') + "/.json"; - if (loc.indexOf("?") !== -1) { - jsonURL = loc.replace("?", "/.json?"); - } - - voteTable = {}; - - onloadJSON = function (response) { - var jsonText = response.responseText, data; - - try { - data = JSON.parse(jsonText); - } catch (e) { - if (window.console) { - // window.console.log(e); - // window.console.log(jsonText); - } - } - - //Load the vote table by processing the tree - processTree(data); //this takes up no time (4ms on 4000 records) - - //Display the loaded votes - displayVotes(); - }; - - // spend up to 50msec a time with a task, wait for 25msec and continue if necessary - // changed to 100/100 - chunker = function (items, process) { - var todo = items.concat(); - setTimeout(function () { - var start = Date.now(); - do { - process(todo.shift()); - } while (todo.length && Date.now() - start < 100); // was 50 - if (todo.length) { - setTimeout(arguments.callee, 100); // was 25 - } - }, 100); // was 25 - }; - - displayVotes = function () { - //Add the style sheets for up and down ratings - - var taglines, - commentID = null, - toArray; - - toArray = function (col) { - var a = [], i, len; - for (i = 0, len = col.length; i < len; i++) { - a[i] = col[i]; - } - return a; - }; - - taglines = toArray(document.getElementsByClassName("tagline")); - - chunker(taglines, function (item) { - if ((item) && (item.nextSibling)) { - var votes, openparen, mooups, pipe, moodowns, voteDowns, voteUps, closeparen, frag; - if (item.nextSibling.nodeName === "FORM") { //the first item is the title of the post - commentID = item.nextSibling.firstChild.value; - if ((voteTable[commentID]) && (typeof(modules['uppersAndDowners'].commentsWithMoos[commentID]) == 'undefined')) { - modules['uppersAndDowners'].commentsWithMoos[commentID] = true; - frag = document.createDocumentFragment(); //using a fragment speeds this up by a factor of about 2 - - votes = voteTable[commentID]; - - if (modules['uppersAndDowners'].options.showSigns.value) { - votes.ups = '+'+votes.ups; - votes.downs = '-'+votes.downs; - } - - openparen = document.createTextNode(" ("); - frag.appendChild(openparen); - - mooups = document.createElement("span"); - mooups.className = "res_comment_ups"; - voteUps = document.createTextNode(votes.ups); - - mooups.appendChild(voteUps); - frag.appendChild(mooups); - - pipe = document.createTextNode("|"); - item.appendChild(pipe); - - moodowns = document.createElement("span"); - moodowns.className = "res_comment_downs"; - - voteDowns = document.createTextNode(votes.downs); - moodowns.appendChild(voteDowns); - - frag.appendChild(moodowns); - - closeparen = document.createTextNode(")"); - frag.appendChild(closeparen); - - frag.appendChild(openparen); - frag.appendChild(mooups); - frag.appendChild(pipe); - frag.appendChild(moodowns); - frag.appendChild(closeparen); - - item.appendChild(frag); - // thanks to Reddit user semanticist for the idea/patch to put the date created in here... - // reddit has now added this natively, we don't need this... - /* - if (modules['uppersAndDowners'].options.showTimestamp.value) { - // find the modified time and wrap it in a span... - for (var i=1, len=item.childNodes.length; i|'+thisMinus+thisdowns+') '; - var upsAndDownsEle = document.createElement('span'); - upsAndDownsEle.innerHTML = upsAndDowns; - // thanks to Reddit user semanticist for the idea/patch to put the date created in here... - // reddit does this natively now, no more need for this code... - /* - if (modules['uppersAndDowners'].options.showTimestamp.value) { - var thisTimeString = new Date(linkList[i].data.created_utc*1000).toString(); - // find the modified time and wrap it in a span... - var timeStampNode = document.createElement('span'); - timeStampNode.innerHTML = thisTagline.childNodes[0].textContent; - timeStampNode.title = thisTimeString; - insertAfter(thisTagline.childNodes[0],timeStampNode); - thisTagline.removeChild(thisTagline.childNodes[0]); - } - */ - if (displayType == 'regular') { - thisTagline.insertBefore(upsAndDownsEle, thisTagline.firstChild); - } else { - insertAfter(thisTagline, upsAndDownsEle); - } - } - } - } - }; - // load the JSON - setTimeout(function() { - GM_xmlhttpRequest({ - method: "GET", - url: jsonURL, - onload: onloadJSONLinks - }); - }, 200); - - } -}; - -modules['keyboardNav'] = { - moduleID: 'keyboardNav', - moduleName: 'Keyboard Navigation', - category: 'UI', - options: { - // any configurable options you have go here... - // options must have a type and a value.. - // valid types are: text, boolean (if boolean, value must be true or false) - // for example: - focusBorder: { - type: 'text', - value: '1px dashed #888888', - description: 'Border style of focused element' - }, - focusBGColor: { - type: 'text', - value: '#F0F3FC', - description: 'Background color of focused element' - }, - focusBGColorNight: { - type: 'text', - value: '#666', - description: 'Background color of focused element in Night Mode' - }, - focusFGColorNight: { - type: 'text', - value: '#DDD', - description: 'Foreground color of focused element in Night Mode' - }, - autoSelectOnScroll: { - type: 'boolean', - value: false, - description: 'Automatically select the topmost element for keyboard navigation on window scroll' - }, - scrollOnExpando: { - type: 'boolean', - value: true, - description: 'Scroll window to top of link when expando key is used (to keep pics etc in view)' - }, - scrollStyle: { - type: 'enum', - values: [ - { name: 'directional', value: 'directional' }, - { name: 'page up/down', value: 'page' }, - { name: 'lock to top', value: 'top' } - ], - value: 'directional', - description: 'When moving up/down with keynav, when and how should RES scroll the window?' - }, - commentsLinkNumbers: { - type: 'boolean', - value: true, - description: 'Assign number keys to links within selected comment' - }, - commentsLinkNewTab: { - type: 'boolean', - value: true, - description: 'Open number key links in a new tab' - }, - clickFocus: { - type: 'boolean', - value: true, - description: 'Move keyboard focus to a link or comment when clicked with the mouse' - }, - onHideMoveDown: { - type: 'boolean', - value: true, - description: 'After hiding a link, automatically select the next link' - }, - toggleHelp: { - type: 'keycode', - value: [191,false,false,true], // ? (note the true in the shift slot) - description: 'Show help' - }, - toggleCmdLine: { - type: 'keycode', - value: [190,false,false,false], // . - description: 'Show/hide commandline box' - }, - hide: { - type: 'keycode', - value: [72,false,false,false], // h - description: 'Hide link' - }, - moveUp: { - type: 'keycode', - value: [75,false,false,false], // k - description: 'Move up (previous link or comment)' - }, - moveDown: { - type: 'keycode', - value: [74,false,false,false], // j - description: 'Move down (next link or comment)' - }, - moveTop: { - type: 'keycode', - value: [75,false,false,true], // shift-k - description: 'Move to top of list (on link pages)' - }, - moveBottom: { - type: 'keycode', - value: [74,false,false,true], // shift-j - description: 'Move to bottom of list (on link pages)' - }, - moveUpSibling: { - type: 'keycode', - value: [75,false,false,true], // shift-k - description: 'Move to previous sibling (in comments) - skips to previous sibling at the same depth.' - }, - moveDownSibling: { - type: 'keycode', - value: [74,false,false,true], // shift-j - description: 'Move to next sibling (in comments) - skips to next sibling at the same depth.' - }, - moveToParent: { - type: 'keycode', - value: [80,false,false,false], // p - description: 'Move to parent (in comments).' - }, - followLink: { - type: 'keycode', - value: [13,false,false,false], // enter - description: 'Follow link (hold shift to open it in a new tab) (link pages only)' - }, - followLinkNewTab: { - type: 'keycode', - value: [13,false,false,true], // shift-enter - description: 'Follow link in new tab (link pages only)' - }, - toggleExpando: { - type: 'keycode', - value: [88,false,false,false], // x - description: 'Toggle expando (image/text/video) (link pages only)' - }, - toggleViewImages: { - type: 'keycode', - value: [88,false,false,true], // shift-x - description: 'Toggle "view images" button' - }, - toggleChildren: { - type: 'keycode', - value: [13,false,false,false], // enter - description: 'Expand/collapse comments (comments pages only)' - }, - followComments: { - type: 'keycode', - value: [67,false,false,false], // c - description: 'View comments for link (shift opens them in a new tab)' - }, - followCommentsNewTab: { - type: 'keycode', - value: [67,false,false,true], // shift-c - description: 'View comments for link in a new tab' - }, - followLinkAndCommentsNewTab: { - type: 'keycode', - value: [76,false,false,false], // l - description: 'View link and comments in new tabs' - }, - followLinkAndCommentsNewTabBG: { - type: 'keycode', - value: [76,false,false,true], // shift-l - description: 'View link and comments in new background tabs' - }, - upVote: { - type: 'keycode', - value: [65,false,false,false], // a - description: 'Upvote selected link or comment' - }, - downVote: { - type: 'keycode', - value: [90,false,false,false], // z - description: 'Downvote selected link or comment' - }, - save: { - type: 'keycode', - value: [83,false,false,false], // s - description: 'Save the current link' - }, - reply: { - type: 'keycode', - value: [82,false,false,false], // r - description: 'Reply to current comment (comment pages only)' - }, - followSubreddit: { - type: 'keycode', - value: [82,false,false,false], // r - description: 'Go to subreddit of selected link (link pages only)' - }, - inbox: { - type: 'keycode', - value: [73,false,false,false], // i - description: 'Go to inbox' - }, - frontPage: { - type: 'keycode', - value: [70,false,false,false], // f - description: 'Go to front page' - }, - subredditFrontPage: { - type: 'keycode', - value: [70,false,false,true], // shift-f - description: 'Go to front page' - }, - nextPage: { - type: 'keycode', - value: [78,false,false,false], // n - description: 'Go to next page (link list pages only)' - }, - prevPage: { - type: 'keycode', - value: [80,false,false,false], // p - description: 'Go to prev page (link list pages only)' - }, - link1: { - type: 'keycode', - value: [49,false,false,false], // 1 - description: 'Open first link within comment.', - noconfig: true - }, - link2: { - type: 'keycode', - value: [50,false,false,false], // 2 - description: 'Open link #2 within comment.', - noconfig: true - }, - link3: { - type: 'keycode', - value: [51,false,false,false], // 3 - description: 'Open link #3 within comment.', - noconfig: true - }, - link4: { - type: 'keycode', - value: [52,false,false,false], // 4 - description: 'Open link #4 within comment.', - noconfig: true - }, - link5: { - type: 'keycode', - value: [53,false,false,false], // 5 - description: 'Open link #5 within comment.', - noconfig: true - }, - link6: { - type: 'keycode', - value: [54,false,false,false], // 6 - description: 'Open link #6 within comment.', - noconfig: true - }, - link7: { - type: 'keycode', - value: [55,false,false,false], // 7 - description: 'Open link #7 within comment.', - noconfig: true - }, - link8: { - type: 'keycode', - value: [56,false,false,false], // 8 - description: 'Open link #8 within comment.', - noconfig: true - }, - link9: { - type: 'keycode', - value: [57,false,false,false], // 9 - description: 'Open link #9 within comment.', - noconfig: true - }, - link10: { - type: 'keycode', - value: [48,false,false,false], // 0 - description: 'Open link #10 within comment.', - noconfig: true - } - }, - description: 'Keyboard navigation for reddit!', - isEnabled: function() { - return RESConsole.getModulePrefs(this.moduleID); - }, - include: Array( - /https?:\/\/([a-z]+).reddit.com\/[-\w\.\/]*/i - ), - isMatchURL: function() { - return RESUtils.isMatchURL(this.moduleID); - }, - go: function() { - if ((this.isEnabled()) && (this.isMatchURL())) { - // get this module's options... - // RESUtils.getOptions(this.moduleID); - // do stuff now! - // this is where your code goes... - // get rid of antequated option we've removed - if (this.options.autoSelectOnScroll.value) { - window.addEventListener('scroll', modules['keyboardNav'].handleScroll, false); - } - if (typeof(this.options.scrollTop) != 'undefined') { - if (this.options.scrollTop.value) this.options.scrollStyle.value == 'top'; - delete this.options.scrollTop; - RESStorage.setItem('RESoptions.keyboardNav', JSON.stringify(modules['keyboardNav'].options)); - } - if (typeof(this.options.focusBorder) == 'undefined') { - focusBorder = '1px dashed #888888'; - } else { - focusBorder = this.options.focusBorder.value; - } - if (typeof(this.options.focusBGColor) == 'undefined') { - focusBGColor = '#F0F3FC'; - } else { - focusBGColor = this.options.focusBGColor.value; - } - if (!(this.options.focusBGColorNight.value)) { - focusBGColorNight = '#666'; - } else { - focusBGColorNight = this.options.focusBGColorNight.value; - } - if (!(this.options.focusFGColorNight.value)) { - focusFGColorNight = '#DDD'; - } else { - focusFGColorNight = this.options.focusFGColorNight.value; - } - - var borderType = 'outline'; - if (typeof(opera) != 'undefined') borderType = 'border'; - RESUtils.addCSS(' \ - .keyHighlight { '+borderType+': '+focusBorder+'; background-color: '+focusBGColor+'; } \ - .res-nightmode .keyHighlight, .res-nightmode .keyHighlight .usertext-body, .res-nightmode .keyHighlight .usertext-body .md, .res-nightmode .keyHighlight .usertext-body .md p, .res-nightmode .keyHighlight .noncollapsed, .res-nightmode .keyHighlight .noncollapsed .md, .res-nightmode .keyHighlight .noncollapsed .md p { background-color: '+focusBGColorNight+' !important; color: '+focusFGColorNight+' !important;} \ - .res-nightmode .keyHighlight a.title:first-of-type {color: ' + focusFGColorNight + ' !important; } \ - #keyHelp { display: none; position: fixed; height: 90%; overflow-y: auto; right: 20px; top: 20px; z-index: 1000; border: 2px solid #AAAAAA; border-radius: 5px 5px 5px 5px; -moz-border-radius: 5px 5px 5px 5px; -webkit-border-radius: 5px 5px 5px 5px; width: 300px; padding: 5px; background-color: #ffffff; } \ - #keyHelp th { font-weight: bold; padding: 2px; border-bottom: 1px dashed #dddddd; } \ - #keyHelp td { padding: 2px; border-bottom: 1px dashed #dddddd; } \ - #keyHelp td:first-child { width: 70px; } \ - #keyCommandLineWidget { font-size: 14px; display: none; position: fixed; top: 200px; left: 50%; margin-left: -275px; z-index: 9999; width: 550px; border: 3px solid #555555; border-radius: 10px 10px 10px 10px; -moz-border-radius: 10px 10px 10px 10px; -webkit-border-radius: 10px 10px 10px 10px; padding: 10px; background-color: #333333; color: #CCCCCC; opacity: 0.95; } \ - #keyCommandInput { width: 240px; background-color: #999999; margin-right: 10px; } \ - #keyCommandInputTip { margin-top: 5px; color: #99FF99; } \ - #keyCommandInputTip ul { font-size: 11px; list-style-type: disc; } \ - #keyCommandInputTip li { margin-left: 15px; } \ - #keyCommandInputError { margin-top: 5px; color: red; font-weight: bold; } \ - '); - this.drawHelp(); - this.attachCommandLineWidget(); - window.addEventListener('keydown', function(e) { - // console.log(e.keyCode); - modules['keyboardNav'].handleKeyPress(e); - }, true); - this.scanPageForKeyboardLinks(); - // listen for new DOM nodes so that modules like autopager, never ending reddit, "load more comments" etc still get keyboard nav. - document.body.addEventListener('DOMNodeInserted', function(event) { - if ((event.target.tagName == 'DIV') && ((event.target.getAttribute('id') && event.target.getAttribute('id').indexOf('siteTable') != -1) || (hasClass(event.target,'child')) || (hasClass(event.target,'thing')))) { - modules['keyboardNav'].scanPageForKeyboardLinks(true); - } - }, true); - } - }, - handleScroll: function(e) { - if ((! modules['keyboardNav'].recentKeyPress) && (! RESUtils.elementInViewport(modules['keyboardNav'].keyboardLinks[modules['keyboardNav'].activeIndex]))) { - for (var i=0, len=modules['keyboardNav'].keyboardLinks.length; i' - str += ''; - this.cmdLineShowTip(str); - } else { - this.cmdLineShowTip(''); - } - }, - cmdLineShowTip: function(str) { - this.commandLineInputTip.innerHTML = str; - }, - cmdLineShowError: function(str) { - this.commandLineInputError.innerHTML = str; - }, - toggleCmdLine: function(force) { - var open = (((force == null) || (force == true)) && (this.commandLineWidget.style.display != 'block')) - delete this.cmdLineTagUsername; - if (open) { - this.cmdLineShowError(''); - this.commandLineWidget.style.display = 'block'; - setTimeout(function() { - modules['keyboardNav'].commandLineInput.focus(); - }, 20); - this.commandLineInput.value = ''; - } else { - modules['keyboardNav'].commandLineInput.blur(); - this.commandLineWidget.style.display = 'none'; - } - }, - cmdLineSubmit: function(e) { - e.preventDefault(); - modules['keyboardNav'].commandLineInputError.innerHTML = ''; - var theInput = modules['keyboardNav'].commandLineInput.value; - // see what kind of input it is: - if (theInput.indexOf('r/') != -1) { - // subreddit? (r/subreddit or /r/subreddit) - theInput = theInput.replace('/r/','').replace('r/',''); - location.href = '/r/'+theInput; - } else if (theInput.indexOf('/') == 0) { - // sort... - theInput = theInput.slice(1); - switch (theInput) { - case 'n': - theInput = 'new'; - break; - case 't': - theInput = 'top'; - break; - case 'h': - theInput = 'hot'; - break; - case 'c': - theInput = 'controversial'; - break; - } - validSorts = ['new','top','hot','controversial']; - if (RESUtils.currentUserProfile()) { - location.href = '/user/'+RESUtils.currentUserProfile()+'?sort='+theInput; - } else if (validSorts.indexOf(theInput) != -1) { - location.href = '/r/'+RESUtils.currentSubreddit()+'/'+theInput; - } else { - modules['keyboardNav'].cmdLineShowError('invalid sort command - must be [n]ew, [t]op, [h]ot or [c]ontroversial'); - return false; - } - } else if (!(isNaN(parseInt(theInput)))) { - if (RESUtils.pageType() == 'comments') { - // comment link number? (integer) - modules['keyboardNav'].commentLink(parseInt(theInput)-1); - } else if (RESUtils.pageType() == 'linklist') { - modules['keyboardNav'].keyUnfocus(modules['keyboardNav'].keyboardLinks[modules['keyboardNav'].activeIndex]); - modules['keyboardNav'].activeIndex = parseInt(theInput) - 1; - modules['keyboardNav'].keyFocus(modules['keyboardNav'].keyboardLinks[modules['keyboardNav'].activeIndex]); - modules['keyboardNav'].followLink(); - } - } else { - var splitWords = theInput.split(' '); - var command = splitWords[0]; - splitWords.splice(0,1); - var val = splitWords.join(' '); - switch (command) { - case 'tag': - var searchArea = modules['keyboardNav'].keyboardLinks[modules['keyboardNav'].activeIndex]; - var tagLink = searchArea.querySelector('a.userTagLink'); - if (tagLink) { - RESUtils.click(tagLink); - setTimeout(function() { - if (val != '') { - document.getElementById('userTaggerTag').value = val; - } - }, 20); - } - break; - case 'sw': - // switch accounts (username is required) - if (val.length <= 1) { - modules['keyboardNav'].cmdLineShowError('No username specified.'); - return false; - } else { - // first make sure the account exists... - var accounts = modules['accountSwitcher'].options.accounts.value; - var found = false; - for (var i=0, len=accounts.length; i 2) { - splitWords.splice(0,2); - var value = splitWords.join(' '); - } - // console.log(command); - if (command == 'get') { - alert('Value of RESStorage['+key+']:

'); - } else if (command == 'update') { - var now = new Date().getTime(); - alert('Value of RESStorage['+key+']:

', function() { - var textArea = document.getElementById('RESStorageUpdate'+now); - if (textArea) { - var value = textArea.value; - RESStorage.setItem(key, value); - } - }); - } else if (command == 'remove') { - RESStorage.removeItem(key); - alert('RESStorage['+key+'] deleted'); - } else if (command == 'set') { - RESStorage.setItem(key, value); - alert('RESStorage['+key+'] set to:

'); - } else { - modules['keyboardNav'].cmdLineShowError('You must specify either "get [key]" or "set [key] [value]"'); - } - } - break; - case '?': - // user is already looking at help... do nothing. - return false; - break; - default: - modules['keyboardNav'].cmdLineShowError('unknown command - type ? for help'); - return false; - break; - } - } - // hide the commandline tool... - modules['keyboardNav'].toggleCmdLine(false); - }, - scanPageForKeyboardLinks: function(isNew) { - if (typeof(isNew) == 'undefined') { - isNew = false; - } - // check if we're on a link listing (regular page, subreddit page, etc) or comments listing... - this.pageType = RESUtils.pageType(); - switch(this.pageType) { - case 'linklist': - case 'profile': - // get all links into an array... - var siteTable = document.querySelector('#siteTable'); - var stMultiCheck = document.querySelectorAll('#siteTable'); - // stupid sponsored links create a second div with ID of sitetable (bad reddit! you should never have 2 IDs with the same name! naughty, naughty reddit!) - if (stMultiCheck.length == 2) { - siteTable = stMultiCheck[1]; - } - if (siteTable) { - this.keyboardLinks = document.body.querySelectorAll('div.linklisting .entry'); - if (!isNew) { - if (RESStorage.getItem('RESmodules.keyboardNavLastIndex.'+location.href) > 0) { - this.activeIndex = RESStorage.getItem('RESmodules.keyboardNavLastIndex.'+location.href); - } else { - this.activeIndex = 0; - } - if (RESStorage.getItem('RESmodules.keyboardNavLastIndex.'+location.href) >= this.keyboardLinks.length) { - this.activeIndex = 0; - } - } - } - break; - case 'comments': - // get all links into an array... - this.keyboardLinks = document.body.querySelectorAll('#siteTable .entry, div.content > div.commentarea .entry'); - if (!(isNew)) { - this.activeIndex = 0; - } - break; - case 'inbox': - var siteTable = document.querySelector('#siteTable'); - if (siteTable) { - this.keyboardLinks = siteTable.querySelectorAll('.entry'); - this.activeIndex = 0; - } - break; - } - // wire up keyboard links for mouse clicky selecty goodness... - if ((typeof(this.keyboardLinks) != 'undefined') && (this.options.clickFocus.value)) { - for (var i=0, len=this.keyboardLinks.length;i span > a'); - RESUtils.click(hideLink); - // if ((this.options.onHideMoveDown.value) && (!modules['betteReddit'].options.fixHideLink.value)) { - if (this.options.onHideMoveDown.value) { - this.moveDown(); - } - }, - followSubreddit: function() { - // find the subreddit link and click it... - var srLink = this.keyboardLinks[this.activeIndex].querySelector('A.subreddit'); - if (srLink) { - var thisHREF = srLink.getAttribute('href'); - location.href = thisHREF; - } - }, - moveUp: function() { - if (this.activeIndex > 0) { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - this.activeIndex--; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - // skip over hidden elements... - while ((thisXY.x == 0) && (thisXY.y == 0) && (this.activeIndex > 0)) { - this.activeIndex--; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - } - this.keyFocus(this.keyboardLinks[this.activeIndex]); - if ((!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) || (this.options.scrollStyle.value == 'top')) { - RESUtils.scrollTo(0,thisXY.y); - } - - modules['keyboardNav'].recentKey(); - } - }, - moveDown: function() { - if (this.activeIndex < this.keyboardLinks.length-1) { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - this.activeIndex++; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - // skip over hidden elements... - while ((thisXY.x == 0) && (thisXY.y == 0) && (this.activeIndex < this.keyboardLinks.length-1)) { - this.activeIndex++; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - } - this.keyFocus(this.keyboardLinks[this.activeIndex]); - // console.log('xy: ' + RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]).toSource()); - /* - if ((!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) || (this.options.scrollTop.value)) { - RESUtils.scrollTo(0,thisXY.y); - } - */ - if (this.options.scrollStyle.value == 'top') { - RESUtils.scrollTo(0,thisXY.y); - } else if ((!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex])))) { - var thisHeight = this.keyboardLinks[this.activeIndex].offsetHeight; - if (this.options.scrollStyle.value == 'page') { - RESUtils.scrollTo(0,thisXY.y); - } else { - RESUtils.scrollTo(0,thisXY.y - window.innerHeight + thisHeight + 5); - } - } - modules['keyboardNav'].recentKey(); - } - }, - moveTop: function() { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - this.activeIndex = 0; - this.keyFocus(this.keyboardLinks[this.activeIndex]); - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - if (!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) { - RESUtils.scrollTo(0,thisXY.y); - } - modules['keyboardNav'].recentKey(); - }, - moveBottom: function() { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - this.activeIndex = this.keyboardLinks.length-1; - this.keyFocus(this.keyboardLinks[this.activeIndex]); - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - if (!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) { - RESUtils.scrollTo(0,thisXY.y); - } - modules['keyboardNav'].recentKey(); - }, - moveDownSibling: function() { - if (this.activeIndex < this.keyboardLinks.length-1) { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - var thisParent = this.keyboardLinks[this.activeIndex].parentNode; - var childCount = thisParent.querySelectorAll('.entry').length; - this.activeIndex += childCount; - // skip over hidden elements... - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - while ((thisXY.x == 0) && (thisXY.y == 0) && (this.activeIndex < this.keyboardLinks.length-1)) { - this.activeIndex++; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - } - if ((this.pageType == 'linklist') || (this.pageType == 'profile')) RESStorage.setItem('RESmodules.keyboardNavLastIndex.'+location.href, this.activeIndex); - this.keyFocus(this.keyboardLinks[this.activeIndex]); - if (!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) { - RESUtils.scrollTo(0,thisXY.y); - } - } - modules['keyboardNav'].recentKey(); - }, - moveUpSibling: function() { - if (this.activeIndex < this.keyboardLinks.length-1) { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - var thisParent = this.keyboardLinks[this.activeIndex].parentNode; - if (thisParent.previousSibling != null) { - var childCount = thisParent.previousSibling.previousSibling.querySelectorAll('.entry').length; - } else { - var childCount = 1; - } - this.activeIndex -= childCount; - // skip over hidden elements... - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - while ((thisXY.x == 0) && (thisXY.y == 0) && (this.activeIndex < this.keyboardLinks.length-1)) { - this.activeIndex++; - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - } - if ((this.pageType == 'linklist') || (this.pageType == 'profile')) RESStorage.setItem('RESmodules.keyboardNavLastIndex.'+location.href, this.activeIndex); - this.keyFocus(this.keyboardLinks[this.activeIndex]); - if (!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) { - RESUtils.scrollTo(0,thisXY.y); - } - } - modules['keyboardNav'].recentKey(); - }, - moveToParent: function() { - if ((this.activeIndex < this.keyboardLinks.length-1) && (this.activeIndex > 1)) { - var firstParent = this.keyboardLinks[this.activeIndex].parentNode; - // check if we're at the top parent, first... if the great grandparent has a class of content, do nothing. - if (!hasClass(firstParent.parentNode.parentNode.parentNode,'content')) { - if (firstParent != null) { - this.keyUnfocus(this.keyboardLinks[this.activeIndex]); - var thisParent = firstParent.parentNode.parentNode.previousSibling; - var newKeyIndex = parseInt(thisParent.getAttribute('keyindex')); - this.activeIndex = newKeyIndex; - this.keyFocus(this.keyboardLinks[this.activeIndex]); - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - if (!(RESUtils.elementInViewport(this.keyboardLinks[this.activeIndex]))) { - RESUtils.scrollTo(0,thisXY.y); - } - } - } - } - modules['keyboardNav'].recentKey(); - }, - toggleChildren: function() { - if (this.activeIndex == 0) { - // Ahh, we're not in a comment, but in the main story... that key should follow the link. - this.followLink(); - } else { - // find out if this is a collapsed or uncollapsed view... - var thisCollapsed = this.keyboardLinks[this.activeIndex].querySelector('div.collapsed'); - var thisNonCollapsed = this.keyboardLinks[this.activeIndex].querySelector('div.noncollapsed'); - if (thisCollapsed.style.display != 'none') { - thisToggle = thisCollapsed.querySelector('a.expand'); - } else { - // check if this is a "show more comments" box, or just contracted content... - moreComments = thisNonCollapsed.querySelector('span.morecomments > a'); - if (moreComments) { - thisToggle = moreComments; - } else { - thisToggle = thisNonCollapsed.querySelector('a.expand'); - } - } - RESUtils.click(thisToggle); - } - }, - toggleExpando: function() { - var thisExpando = this.keyboardLinks[this.activeIndex].querySelector('.expando-button'); - if (thisExpando) { - RESUtils.click(thisExpando); - if (this.options.scrollOnExpando.value) { - thisXY=RESUtils.getXYpos(this.keyboardLinks[this.activeIndex]); - RESUtils.scrollTo(0,thisXY.y); - } - } - }, - toggleViewImages: function() { - var thisViewImages = document.body.querySelector('#viewImagesButton'); - if (thisViewImages) { - RESUtils.click(thisViewImages); - } - }, - toggleAllExpandos: function() { - var thisExpandos = this.keyboardLinks[this.activeIndex].querySelectorAll('.expando-button'); - if (thisExpandos) { - for (var i=0,len=thisExpandos.length; i span > a'); - if (saveLink) RESUtils.click(saveLink); - }, - saveComment: function() { - var saveComment = this.keyboardLinks[this.activeIndex].querySelector('.saveComments'); - if (saveComment) RESUtils.click(saveComment); - }, - reply: function() { - // activeIndex = 0 means we're at the original post, not a comment - if ((this.activeIndex > 0) || (RESUtils.pageType('comments') != true)) { - if ((RESUtils.pageType('comments')) && (this.activeIndex == 0) && (! location.href.match('/message/'))) { - $('.usertext-edit textarea:first').focus(); - } else { - var commentButtons = this.keyboardLinks[this.activeIndex].querySelectorAll('ul.buttons > li > a'); - for (var i=0, len=commentButtons.length;i li > a.comments'); - location.href = commentButton.getAttribute('href'); - } else { - var firstCommentBox = document.querySelector('.commentarea textarea[name=text]'); - firstCommentBox.focus(); - } - } - }, - inbox: function() { - location.href = location.protocol + '//www.reddit.com/message/inbox/'; - }, - frontPage: function(subreddit) { - var newhref = location.protocol + '//www.reddit.com/'; - if (subreddit) { - newhref += 'r/' + RESUtils.currentSubreddit(); - } - location.href = newhref; - }, - nextPage: function() { - // if Never Ending Reddit is enabled, just scroll to the bottom. Otherwise, click the 'next' link. - if (modules['neverEndingReddit'].isEnabled()) { - RESUtils.click(modules['neverEndingReddit'].progressIndicator); - this.moveBottom(); - } else { - // get the first link to the next page of reddit... - var nextPrevLinks = document.body.querySelectorAll('.content .nextprev a'); - if (nextPrevLinks.length > 0) { - var nextLink = nextPrevLinks[nextPrevLinks.length-1]; - // RESUtils.click(nextLink); - location.href = nextLink.getAttribute('href'); - } - } - }, - prevPage: function() { - // if Never Ending Reddit is enabled, do nothing. Otherwise, click the 'prev' link. - if (modules['neverEndingReddit'].isEnabled()) { - return false; - } else { - // get the first link to the next page of reddit... - var nextPrevLinks = document.body.querySelectorAll('.content .nextprev a'); - if (nextPrevLinks.length > 0) { - var prevLink = nextPrevLinks[0]; - // RESUtils.click(prevLink); - location.href = prevLink.getAttribute('href'); - } - } - }, - commentLink: function(num) { - if (this.options.commentsLinkNumbers.value) { - var links = this.keyboardLinks[this.activeIndex].querySelectorAll('div.md a:not(.expando-button):not(.madeVisible)'); - if (typeof(links[num]) != 'undefined') { - var thisLink = links[num]; - if ((thisLink.nextSibling) && (typeof(thisLink.nextSibling.tagName) != 'undefined') && (hasClass(thisLink.nextSibling, 'expando-button'))) { - thisLink = thisLink.nextSibling; - } - RESUtils.click(thisLink); - } - } - } -}; - -// user tagger functions -modules['userTagger'] = { - moduleID: 'userTagger', - moduleName: 'User Tagger', - category: 'Users', - options: { - /* - defaultMark: { - type: 'text', - value: '_', - description: 'clickable mark for users with no tag' - }, - */ - hardIgnore: { - type: 'boolean', - value: false, - description: 'If "hard ignore" is off, only post titles and comment text is hidden. If it is on, the entire block is hidden - note that this would make it difficult/impossible for you to unignore a person.' - }, - colorUser: { - type: 'boolean', - value: true, - description: 'Color users based on cumulative upvotes / downvotes' - }, - hoverInfo: { - type: 'boolean', - value: true, - description: 'Show information on user (karma, how long they\'ve been a redditor) on hover.' - }, - hoverDelay: { - type: 'text', - value: 400, - description: 'Delay, in milliseconds, before hover tooltip loads. Default is 400.' - }, - fadeDelay: { - type: 'text', - value: 200, - description: 'Delay, in milliseconds, before hover tooltip fades away. Default is 200.' - }, - USDateFormat: { - type: 'boolean', - value: false, - description: 'Show date (redditor since...) in US format (i.e. 08-31-2010)' - }, - vwNumber: { - type: 'boolean', - value: true, - description: 'Show the number (i.e. [+6]) rather than [vw]' - }, - vwTooltip: { - type: 'boolean', - value: true, - description: 'Show the vote weight tooltip on hover (i.e. "your votes for...")' - } - }, - description: 'Adds a great deal of customization around users - tagging them, ignoring them, and more.', - isEnabled: function() { - return RESConsole.getModulePrefs(this.moduleID); - }, - isMatchURL: function() { - return RESUtils.isMatchURL(this.moduleID); - }, - include: Array( - /^https?:\/\/([-\w\.]+\.)?reddit\.com\/[-\w\.]*/i - ), - go: function() { - if ((this.isEnabled()) && (this.isMatchURL())) { - // get this module's options... - // RESUtils.getOptions(this.moduleID); - - // Get user tag data... - var tags = RESStorage.getItem('RESmodules.userTagger.tags'); - this.tags = null; - if (typeof(tags) != 'undefined') this.tags = safeJSON.parse(tags, 'RESmodules.userTagger.tags', true); - // check if we're using the old method of storing user tags... yuck! - if (this.tags == null) { - this.updateTagStorage(); - } - // set up an array to cache user data - this.authorInfoCache = Array(); - if (this.options.colorUser.value) { - var voteButtons = document.body.querySelectorAll('.arrow'); - this.voteStates = new Array(); - for (var i=0, len=voteButtons.length;i'+color+''; - } - thisHTML += ''; - thisHTML += ' '; - thisHTML += '';// '; - thisHTML += ' '; - thisHTML += ' '; - thisHTML += '
'; - this.userTaggerToolTip.innerHTML = thisHTML; - var ignoreLabel = this.userTaggerToolTip.querySelector('label[for=userTaggerIgnore]'); - insertAfter(ignoreLabel, RESUtils.toggleButton('userTaggerIgnore', false, 'no', 'yes')); - this.userTaggerTag = this.userTaggerToolTip.querySelector('#userTaggerTag'); - this.userTaggerTag.addEventListener('keyup', modules['userTagger'].updateTagPreview, false); - this.userTaggerColor = this.userTaggerToolTip.querySelector('#userTaggerColor'); - this.userTaggerColor.addEventListener('change', modules['userTagger'].updateTagPreview, false); - this.userTaggerPreview = this.userTaggerToolTip.querySelector('#userTaggerPreview'); - var userTaggerSave = this.userTaggerToolTip.querySelector('#userTaggerSave'); - userTaggerSave.setAttribute('type','submit'); - userTaggerSave.setAttribute('value','✓ save tag'); - userTaggerSave.addEventListener('click', function(e) { - e.preventDefault(); - modules['userTagger'].saveTagForm(); - }, false); - var userTaggerClose = this.userTaggerToolTip.querySelector('#userTaggerClose'); - userTaggerClose.addEventListener('click', function(e) { - modules['userTagger'].closeUserTagPrompt(); - }, false); - //this.userTaggerToolTip.appendChild(userTaggerSave); - this.userTaggerForm = this.userTaggerToolTip.querySelector('FORM'); - this.userTaggerForm.addEventListener('submit',function(e) { - e.preventDefault(); - modules['userTagger'].saveTagForm(); - }, true); - document.body.appendChild(this.userTaggerToolTip); - if (this.options.hoverInfo.value) { - this.authorInfoToolTip = createElementWithID('div', 'authorInfoToolTip', 'RESDialogSmall'); - this.authorInfoToolTipHeader = document.createElement('h3'); - this.authorInfoToolTip.appendChild(this.authorInfoToolTipHeader); - this.authorInfoToolTipCloseButton = createElementWithID('div', 'authorInfoToolTipClose', 'RESCloseButton'); - this.authorInfoToolTipCloseButton.innerHTML = 'X'; - this.authorInfoToolTip.appendChild(this.authorInfoToolTipCloseButton); - this.authorInfoToolTipCloseButton.addEventListener('click', function(e) { - if (typeof(modules['userTagger'].hideTimer) != 'undefined') { - clearTimeout(modules['userTagger'].hideTimer); - } - modules['userTagger'].hideAuthorInfo(); - }, false); - this.authorInfoToolTipContents = createElementWithID('div','authorInfoToolTipContents', 'RESDialogContents'); - this.authorInfoToolTip.appendChild(this.authorInfoToolTipContents); - this.authorInfoToolTip.addEventListener('mouseover', function(e) { - if (typeof(modules['userTagger'].hideTimer) != 'undefined') { - clearTimeout(modules['userTagger'].hideTimer); - } - }, false); - this.authorInfoToolTip.addEventListener('mouseout', function(e) { - if (e.target.getAttribute('class') != 'hoverAuthor') { - modules['userTagger'].hideTimer = setTimeout(function() { - modules['userTagger'].hideAuthorInfo(); - }, modules['userTagger'].options.fadeDelay.value); - } - }, false); - document.body.appendChild(this.authorInfoToolTip); - } - document.getElementById('userTaggerTag').addEventListener('keydown', function(e) { - if (e.keyCode == 27) { - // close prompt. - modules['userTagger'].closeUserTagPrompt(); - } - }, true); - //console.log('before applytags: ' + Date()); - this.applyTags(); - //console.log('after applytags: ' + Date()); - // listen for new DOM nodes so that modules like autopager, river of reddit, etc still get user tags - document.body.addEventListener('DOMNodeInserted', function(event) { - // if ((event.target.tagName == 'DIV') && (event.target.getAttribute('id') && event.target.getAttribute('id').indexOf('siteTable') != -1)) { - if ((event.target.tagName == 'DIV') && ((event.target.getAttribute('id') && event.target.getAttribute('id').indexOf('siteTable') != -1) || (hasClass(event.target,'child')) || (hasClass(event.target,'thing')))) { - modules['userTagger'].applyTags(event.target); - } - }, true); - var userpagere = new RegExp(/https?:\/\/([a-z]+).reddit.com\/user\/[-\w\.]+\/?/i); - if (userpagere.test(location.href)) { - var friendButton = document.querySelector('.titlebox .fancy-toggle-button'); - if ((typeof(friendButton) != 'undefined') && (friendButton != null)) { - var firstAuthor = document.querySelector('a.author'); - if ((typeof(firstAuthor) != 'undefined') && (firstAuthor != null)) { - var thisFriendComment = firstAuthor.getAttribute('title'); - (thisFriendComment != null) ? thisFriendComment = thisFriendComment.substring(8,thisFriendComment.length-1) : thisFriendComment = ''; - } else { - var thisFriendComment = ''; - } - var benefitsForm = document.createElement('div'); - var thisUser = document.querySelector('.titlebox > h1').innerHTML; - benefitsForm.innerHTML = '
'; - insertAfter( friendButton, benefitsForm ); - } - } - } - }, - saveTagForm: function() { - var thisName = document.getElementById('userTaggerName').value; - var thisTag = document.getElementById('userTaggerTag').value; - var thisColor = document.getElementById('userTaggerColor').value; - var thisIgnore = document.getElementById('userTaggerIgnore').checked; - var thisLink = document.getElementById('userTaggerLink').value; - var thisVotes = parseInt(document.getElementById('userTaggerVoteWeight').value); - if (isNaN(thisVotes)) thisVotes = 0; - modules['userTagger'].setUserTag(thisName, thisTag, thisColor, thisIgnore, thisLink, thisVotes); - }, - bgToTextColorMap: { - 'none':'black', - 'aqua':'black', - 'black':'white', - 'blue':'white', - 'fuchsia':'white', - 'gray':'white', - 'green':'white', - 'lime':'black', - 'maroon':'white', - 'navy':'white', - 'olive':'black', - 'orange':'black', - 'purple':'white', - 'red':'black', - 'silver':'black', - 'teal':'white', - 'white':'black', - 'yellow':'black' - }, - openUserTagPrompt: function(obj, username) { - thisXY=RESUtils.getXYpos(obj); - this.clickedTag = obj; - document.querySelector('#userTaggerToolTip h3').innerHTML = 'Tag '+username; - document.getElementById('userTaggerName').value = username; - var thisTag = null; - var thisIgnore = null; - if (typeof(this.tags[username]) != 'undefined') { - if (typeof(this.tags[username].tag) != 'undefined') { - document.getElementById('userTaggerTag').value = this.tags[username].tag; - } else { - document.getElementById('userTaggerTag').value = ''; - } - if (typeof(this.tags[username].ignore) != 'undefined') { - document.getElementById('userTaggerIgnore').checked = this.tags[username].ignore; - var thisToggle = document.getElementById('userTaggerIgnoreContainer'); - if (this.tags[username].ignore) addClass(thisToggle,'enabled'); - } else { - document.getElementById('userTaggerIgnore').checked = false; - } - if (typeof(this.tags[username].votes) != 'undefined') { - document.getElementById('userTaggerVoteWeight').value = this.tags[username].votes; - } else { - document.getElementById('userTaggerVoteWeight').value = ''; - } - if (typeof(this.tags[username].link) != 'undefined') { - document.getElementById('userTaggerLink').value = this.tags[username].link; - } else { - document.getElementById('userTaggerLink').value = ''; - } - if (typeof(this.tags[username].color) != 'undefined') { - RESUtils.setSelectValue(document.getElementById('userTaggerColor'), this.tags[username].color); - } else { - document.getElementById('userTaggerColor').selectedIndex = 0; - } - } else { - document.getElementById('userTaggerTag').value = ''; - document.getElementById('userTaggerIgnore').checked = false; - document.getElementById('userTaggerVoteWeight').value = ''; - document.getElementById('userTaggerLink').value = ''; - document.getElementById('userTaggerColor').selectedIndex = 0; - } - this.userTaggerToolTip.setAttribute('style', 'display: block; top: ' + thisXY.y + 'px; left: ' + thisXY.x + 'px;'); - document.getElementById('userTaggerTag').focus(); - modules['userTagger'].updateTagPreview(); - return false; - }, - updateTagPreview: function() { - modules['userTagger'].userTaggerPreview.innerHTML = modules['userTagger'].userTaggerTag.value; - var bgcolor = modules['userTagger'].userTaggerColor[modules['userTagger'].userTaggerColor.selectedIndex].value; - modules['userTagger'].userTaggerPreview.style.backgroundColor = bgcolor; - modules['userTagger'].userTaggerPreview.style.color = modules['userTagger'].bgToTextColorMap[bgcolor]; - }, - closeUserTagPrompt: function() { - this.userTaggerToolTip.setAttribute('style','display: none'); - if (modules['keyboardNav'].isEnabled()) { - var inputs = this.userTaggerToolTip.querySelectorAll('INPUT, BUTTON'); - // remove focus from any input fields from the prompt so that keyboard navigation works again... - for (var i=0,len=inputs.length; i 0) { - red = Math.max(0, (255-(8*votes))); - green = 255; - blue = Math.max(0, (255-(8*votes))); - } else if (votes < 0) { - red = 255; - green = Math.max(0, (255-Math.abs(8*votes))); - blue = Math.max(0, (255-Math.abs(8*votes))); - voteString = ''; - } - voteString = voteString + votes; - var rgb='rgb('+red+','+green+','+blue+')'; - if (obj != null) { - if (votes == 0) { - obj.style.display = 'none'; - } else { - obj.style.display = 'inline'; - obj.style.backgroundColor = rgb; - if (this.options.vwNumber.value) obj.innerHTML = '[' + voteString + ']'; - if (this.options.vwTooltip.value) obj.setAttribute('title','your votes for '+author+': '+voteString); - } - } - } - }, - showAuthorInfo: function(obj) { - var isFriend = (hasClass(obj, 'friend')) ? true : false; - thisXY=RESUtils.getXYpos(obj); - var objClass = obj.getAttribute('class'); - this.authorInfoToolTipHeader.innerHTML = '' + obj.textContent + ''; - RESUtils.loggedInUserInfo(function(userInfo) { - var myID = 't2_'+userInfo.data.id; - if (isFriend) { - var friendButton = '- friends+ friends'; - } else { - var friendButton = '+ friends- friends'; - } - modules['userTagger'].authorInfoToolTipHeader.innerHTML += friendButton; - }); - this.authorInfoToolTipContents.innerHTML = ''+obj.textContent+':
loading...'; - this.authorInfoToolTip.setAttribute('style', 'top: ' + (thisXY.y - 8) + 'px; left: ' + (thisXY.x - 8) + 'px;'); - RESUtils.fadeElementIn(this.authorInfoToolTip, 0.3); - var thisUserName = obj.textContent; - setTimeout(function() { - if (!RESUtils.elementUnderMouse(modules['userTagger'].authorInfoToolTip)) { - modules['userTagger'].hideAuthorInfo(); - } - }, 1000); - if (typeof(this.authorInfoCache[thisUserName]) != 'undefined') { - this.writeAuthorInfo(this.authorInfoCache[thisUserName]); - } else { - GM_xmlhttpRequest({ - method: "GET", - url: location.protocol + "//www.reddit.com/user/" + thisUserName + "/about.json", - onload: function(response) { - var thisResponse = JSON.parse(response.responseText); - modules['userTagger'].authorInfoCache[thisUserName] = thisResponse; - modules['userTagger'].writeAuthorInfo(thisResponse); - } - }); - } - }, - writeAuthorInfo: function(jsonData) { - var utctime = jsonData.data.created; - var d = new Date(utctime*1000); - // var userHTML = ''+jsonData.data.name+':'; - var userHTML = '
Redditor since:
' + RESUtils.niceDate(d, this.options.USDateFormat.value) + ' ('+RESUtils.niceDateDiff(d)+')
'; - userHTML += '
Link Karma:
' + jsonData.data.link_karma + '
'; - userHTML += '
Comment Karma:
' + jsonData.data.comment_karma + '
'; - if ((typeof(modules['userTagger'].tags[jsonData.data.name]) != 'undefined') && (modules['userTagger'].tags[jsonData.data.name].link)) { - userHTML += '
Link:
'; - } - userHTML += '
'; - userHTML += ' send message'; - if (jsonData.data.is_gold) { - userHTML += 'User has Reddit Gold'; - } else { - userHTML += 'Gift Reddit Gold'; - } - if ((modules['userTagger'].tags[jsonData.data.name]) && (modules['userTagger'].tags[jsonData.data.name].ignore)) { - userHTML += '
∅ Unignore
'; - } else { - userHTML += '
∅ Ignore
'; - } - userHTML += '
'; // closes bottomButtons div - this.authorInfoToolTipContents.innerHTML = userHTML; - this.authorInfoToolTipIgnore = this.authorInfoToolTipContents.querySelector('#ignoreUser'); - this.authorInfoToolTipIgnore.addEventListener('click', modules['userTagger'].ignoreUser, false); - }, - ignoreUser: function(e) { - if (hasClass(e.target,'blueButton')) { - removeClass(e.target,'blueButton'); - addClass(e.target,'redButton'); - e.target.innerHTML = '∅ Unignore'; - var thisIgnore = true; - } else { - removeClass(e.target,'redButton'); - addClass(e.target,'blueButton'); - e.target.innerHTML = '∅ Ignore'; - var thisIgnore = false; - } - var thisName = e.target.getAttribute('user'); - var thisColor, thisLink, thisVotes, thisTag; - if (modules['userTagger'].tags[thisName]) { - thisColor = modules['userTagger'].tags[thisName].color || ''; - thisLink = modules['userTagger'].tags[thisName].link || ''; - thisVotes = modules['userTagger'].tags[thisName].votes || 0; - thisTag = modules['userTagger'].tags[thisName].tag || ''; - } - if ((thisIgnore) && (thisTag == '')) { - thisTag = 'ignored'; - } else if ((!thisIgnore) && (thisTag == 'ignored')) { - thisTag = ''; - } - modules['userTagger'].setUserTag(thisName, thisTag, thisColor, thisIgnore, thisLink, thisVotes, true); // last true is for noclick param - }, - hideAuthorInfo: function(obj) { - // this.authorInfoToolTip.setAttribute('style', 'display: none'); - RESUtils.fadeElementOut(this.authorInfoToolTip, 0.3); - }, - updateTagStorage: function() { - // update tag storage format from the old individual bits to a big JSON blob - // It's OK that we're directly accessing localStorage here because if they have old school tag storage, it IS in localStorage. - (typeof(unsafeWindow) != 'undefined') ? ls = unsafeWindow.localStorage : ls = localStorage; - var tags = {}; - var toRemove = new Array(); - for (var i = 0, len=ls.length; i < len; i++){ - var keySplit = null; - if (ls.key(i)) keySplit = ls.key(i).split('.'); - if (keySplit) { - var keyRoot = keySplit[0]; - switch (keyRoot) { - case 'reddituser': - var thisNode = keySplit[1]; - if (typeof(tags[keySplit[2]]) == 'undefined') { - tags[keySplit[2]] = {}; - } - if (thisNode == 'votes') { - tags[keySplit[2]].votes = ls.getItem(ls.key(i)); - } else if (thisNode == 'tag') { - tags[keySplit[2]].tag = ls.getItem(ls.key(i)); - } else if (thisNode == 'color') { - tags[keySplit[2]].color = ls.getItem(ls.key(i)); - } else if (thisNode == 'ignore') { - tags[keySplit[2]].ignore = ls.getItem(ls.key(i)); - } - // now delete the old stored garbage... - var keyString = 'reddituser.'+thisNode+'.'+keySplit[2]; - toRemove.push(keyString); - break; - default: - // console.log('Not currently handling keys with root: ' + keyRoot); - break; - } - } - } - this.tags = tags; - RESStorage.setItem('RESmodules.userTagger.tags', JSON.stringify(this.tags)); - // now remove the old garbage... - for (var i=0, len=toRemove.length; i