|
|
(4 intermediate revisions by 3 users not shown) |
Line 1: |
Line 1: |
| == Basic Description ==
| | Most of the information on this site is helpful. See the [[Greasemonkey Manual]] for starters. |
|
| |
|
| Each script has a [[Metadata Block]] that describes a few characteristics of a GreaseMonkey script. It usually contains the name of the script (@name), the description (@description) and for what URLs it should be activated (@include). An example of this would be:
| | == Greasemonkey tutorials == |
|
| |
|
| <pre>// ==UserScript==
| | Warning: these are both several years old. |
| // @name Absterge
| |
| // @namespace http://userscripts.org/users/astojanov
| |
| // @include http://*.facebook.com/*
| |
| // @include https://*.facebook.com/*
| |
| // @require http://code.jquery.com/jquery-1.7.1.min.js
| |
| // ==/UserScript==</pre>
| |
|
| |
|
| | * [http://commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks Greasemonkey hacks] (as a wiki)<br /> |
| | * [http://codebazaar.blogspot.com/2010/11/monkey-see-greasemonkey-do.html Monkey see, GreaseMonkey do!] - Video tutorial for GreaseMonkey userscript development |
|
| |
|
| | == JavaScript tutorials == |
|
| |
|
| After the [[Metadata Block]] the Javascript code follows which will be executed within the pages specified by the @include keys.
| | * [https://developer.mozilla.org/en/JavaScript/Guide Mozilla's JavaScript Guide] |
| | * [http://www.tizag.com/javascriptT/ tizag's JavaScript Tutorial] |
| | * [http://www.quirksmode.org/js/contents.html JavaScript on QuirksMode] |
| | * The JavaScript Programming Language ([http://video.yahoo.com/watch/111593/1710507 part 1], [http://video.yahoo.com/watch/111594/1710553 2], [http://video.yahoo.com/watch/111595/1710607 3], [http://video.yahoo.com/watch/111596/1710658 4]) by Douglas Crockford<br />A set of videos of a wonderful lecture by this JavaScript guru.<br />You can check Crockford's JavaScript dedicated website at http://javascript.crockford.com/ |
| | * [http://blog.morrisjohns.com/javascript_closures_for_dummies.html JavaScript Closures for Dummies] |
| | * [http://www.jibbering.com/faq/faq_notes/closures.html JavaScript Closures] |
|
| |
|
| | == JavaScript references == |
| | Once familiar with the language, one may notice there are many available features in JavaScript which are initially hard to remember. |
| | * [https://developer.mozilla.org/ MDC, an extensive wiki from Mozilla which details JavaScript and Firefox-unique features alike] |
| | * [https://developer.mozilla.org/en/Gecko_DOM_Reference Gecko DOM Reference] |
| | * [http://www.w3schools.com/jsref/ w3schools JS reference] |
|
| |
|
| == Example Script == | | == JavaScript Books == |
| | | * [http://www.oreilly.com/catalog/jscript5/ JavaScript: The Definitive Guide] is well regarded |
| There's an example script that does something on Facebook.
| | * For a modern introduction to JavaScript, check out John Resig's [http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273 Pro JavaScript Techniques] |
| | |
| | |
| <pre>// ==UserScript==
| |
| // @name Absterge
| |
| // @namespace http://userscripts.org/users/astojanov
| |
| // @include http://*.facebook.com/*
| |
| // @include https://*.facebook.com/*
| |
| // @require http://code.jquery.com/jquery-1.7.1.min.js
| |
| // ==/UserScript==
| |
| | |
| function parseUri (str) {
| |
| var o = parseUri.options,
| |
| m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
| |
| uri = {},
| |
| i = 14;
| |
| | |
| while (i--) uri[o.key[i]] = m[i] || "";
| |
| | |
| uri[o.q.name] = {};
| |
| uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
| |
| if ($1) uri[o.q.name][$1] = $2;
| |
| });
| |
| | |
| return uri;
| |
| };
| |
| | |
| parseUri.options = {
| |
| strictMode: false,
| |
| key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
| |
| q: {
| |
| name: "queryKey",
| |
| parser: /(?:^|&)([^&=]*)=?([^&]*)/g
| |
| },
| |
| parser: {
| |
| strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
| |
| loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
| |
| }
| |
| };
| |
|
| |
| window.addEventListener('load', function() {
| |
| | |
| var fb_dtsg = null;
| |
|
| |
| // Get the value of fb_dtsg
| |
| var getConstantParameters = function () {
| |
| if ( fb_dtsg !== null ) {
| |
| return true;
| |
| } else {
| |
|
| |
| if ( fb_dtsg === null ) {
| |
| $('input[name="fb_dtsg"]').each(function(){
| |
| fb_dtsg = $(this).attr("value");
| |
| });
| |
| }
| |
| return (fb_dtsg !== null);
| |
| }
| |
| }
| |
| | |
| var generatePhstamp = function(qs, dtsg) {
| |
| var input_len = qs.length;
| |
| numeric_csrf_value='';
| |
| | |
| for(var ii=0;ii<dtsg.length;ii++) {
| |
| numeric_csrf_value+=dtsg.charCodeAt(ii);
| |
| }
| |
| return '1' + numeric_csrf_value + input_len;
| |
| };
| |
| | |
| | |
| var deleteMinistories = function (actions) {
| |
| | |
| getConstantParameters();
| |
|
| |
| $('li[class="pvs uiStreamMinistoryGroup timelineMinistoryGroup uiListItem uiListMedium uiListVerticalItemBorder"]').each( function() {
| |
|
| |
| // Make sure whether this ministory is supposed to be skipped or not
| |
| if ( $(this).attr('absterge') !== undefined && $(this).attr('absterge') === 'dismiss' ) {
| |
| return;
| |
| } else {
| |
| if ( $(this).attr('absterge') === undefined || $(this).attr('absterge') === null ) {
| |
| $(this).attr('absterge', 'dismiss');
| |
| }
| |
| }
| |
| var ministory = $(this);
| |
| | |
|
| |
| // In the first pass, just try to unroll the action
| |
| if ( ministory.attr('absterge') !== 'considered' ) {
| |
| ministory.find('a[ajaxify]').each(function () {
| |
| var ajaxify = parseUri("http://facebook.com" + $(this).attr("ajaxify"));
| |
| if ( ajaxify.file === "show_story_options.php") {
| |
| var evt = document.createEvent("MouseEvents");
| |
| evt.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
| |
| $(this).context.dispatchEvent(evt);
| |
| ministory.attr('absterge', 'considered');
| |
| }
| |
| });
| |
| }
| |
|
| |
| // Now try to remove the actual action
| |
| if ( ministory.attr('absterge') === 'considered' ) {
| |
|
| |
| ministory.find('a[ajaxify]').each(function () {
| |
|
| |
| var ajaxify = parseUri("http://facebook.com" + $(this).attr("ajaxify"));
| |
| if ( ajaxify.file === "take_action_on_story.php" ) {
| |
|
| |
| if ( actions.indexOf (ajaxify.queryKey["action"]) === -1 ) {
| |
| ministory.attr('absterge', 'dismiss');
| |
| } else {
| |
|
| |
| var remove = true;
| |
| var keys = ['profile_id', 'story_fbid', 'story_row_time', 'story_dom_id'];
| |
| for ( var i = 0; i < keys.length; ++i ) {
| |
| if ( ajaxify.queryKey[keys[i]] === undefined ) {
| |
| remove = false;
| |
| }
| |
| }
| |
|
| |
| if ( remove ) {
| |
|
| |
| var pagelet_all_activity = ministory.parent().attr('id').replace("timeline_all_activity_stream", "pagelet_all_activity");
| |
|
| |
| var data = {
| |
| 'nctr[_mod]' : pagelet_all_activity,
| |
| // 'post_form_id' : post_form_id,
| |
| 'fb_dtsg' : fb_dtsg,
| |
| // 'lsd' : "",
| |
| // 'post_form_id_source' : "AsyncRequest",
| |
| 'confirmed' : "true",
| |
| 'ban_user' : "0"
| |
| };
| |
| for ( var key in ajaxify.queryKey ) {
| |
| data[key] = ajaxify.queryKey[key];
| |
| }
| |
|
| |
| data['phstamp'] = generatePhstamp($.param(data), fb_dtsg);
| |
|
| |
| $.ajax({
| |
| type : "POST",
| |
| url : "https://www.facebook.com/ajax/timeline/take_action_on_story.php?__a=1",
| |
| data : data,
| |
| complete: function(jqXHR, textStatus) {
| |
| if ( jqXHR.status === 200 ) {
| |
| if ( $('#cmdAbsterge').attr('deletecount') === undefined || $('#cmdAbsterge').attr('deletecount') === null ) {
| |
| $('#cmdAbsterge').attr('deletecount', '0');
| |
| }
| |
| var deleteCount = parseInt($('#cmdAbsterge').attr('deletecount')) + 1;
| |
| $('#cmdAbsterge').html("Absterge (" + deleteCount + ")");
| |
| $('#cmdAbsterge').attr('deletecount', '' + deleteCount);
| |
| ministory.remove();
| |
| }
| |
|
| |
| console.log("Deleting:", jqXHR);
| |
| }
| |
| });
| |
|
| |
|
| |
| } else {
| |
| ministory.attr('absterge', 'dismiss');
| |
| }
| |
| }
| |
|
| |
| }
| |
|
| |
| });
| |
|
| |
|
| |
| }
| |
| });
| |
|
| |
| $("html, body").animate({ scrollTop: $(document).height() }, "slow");
| |
| setTimeout(function(){
| |
| deleteMinistories(actions);
| |
| }, 1000);
| |
| | |
| // setTimeout(deleteMinistories, 500, [actions]);
| |
| };
| |
|
| |
| var deleteLikes = function () {
| |
| $('#menuAbsterge').css('display', 'none');
| |
| var likes = new Array();
| |
| likes.push("unlike");
| |
| deleteMinistories (likes);
| |
| };
| |
|
| |
| var deleteComments = function () {
| |
| $('#menuAbsterge').css('display', 'none');
| |
| var comments = new Array();
| |
| comments.push("remove_comment");
| |
| deleteMinistories (comments);
| |
| };
| |
|
| |
| var deleteContent = function () {
| |
| $('#menuAbsterge').css('display', 'none');
| |
| var content = new Array();
| |
| content.push("remove_content");
| |
| deleteMinistories (content);
| |
| };
| |
|
| |
| var deleteAll = function () {
| |
| $('#menuAbsterge').css('display', 'none');
| |
| var all = new Array();
| |
| all.push("unlike");
| |
| all.push("remove_comment");
| |
| all.push("remove_content");
| |
| deleteMinistories (all);
| |
| };
| |
| | |
| // Include the
| |
| $('<li id="navAbsterge" class="topNavLink middleLink"><a id="cmdAbsterge" href="#">Absterge</a></li>').insertAfter('#navHome');
| |
|
| |
| var pathname = window.location.pathname;
| |
| if ( pathname.indexOf('/allactivity') === -1 ) {
| |
| $('#cmdAbsterge').click(function () {
| |
| alert('You must navigate to "Activity Log" using the "Timeline" feature in order to use Absterge');
| |
| });
| |
| } else {
| |
| $('#cmdAbsterge').css("color", "red");
| |
| $('<ul id="menuAbsterge" aria-label="Absterge" role="navigation" id="abstergeNavigation" class="navigation">' +
| |
| '<li><a id="abstergeDeleteLikes" href="#" class="navSubmenu">Delete Likes</a></li>' +
| |
| '<li><a id="abstergeDeleteComments" href="#" class="navSubmenu">Delete Comments</a></li>' +
| |
| '<li><a id="abstergeDeleteContent" href="#" class="navSubmenu">Delete Content</a></li>' +
| |
| '<li><a id="abstergeDeleteAll" href="#" class="navSubmenu">Delete All</a></li>' +
| |
| '</ul>').appendTo('#navAccount');
| |
| $('#menuAbsterge').css('z-index', '-1');
| |
|
| |
| $('#abstergeDeleteLikes').click(function (){ deleteLikes(); });
| |
| $('#abstergeDeleteComments').click(function (){ deleteComments();});
| |
| $('#abstergeDeleteContent').click(function (){ deleteContent(); });
| |
| $('#abstergeDeleteAll').click(function (){ deleteAll(); });
| |
|
| |
| $('#cmdAbsterge').click(function () {
| |
| if ( $('#menuAbsterge').css('display') === 'block' ) {
| |
| $('#menuAbsterge').css('display', 'none');
| |
| } else {
| |
| $('#menuAbsterge').css('display', 'block');
| |
| }
| |
| });
| |
| }
| |
| });
| |
| </pre>
| |