Recent posts by Mindeye

Subscribe to Recent posts by Mindeye 34 posts found

May 1, 2008
Mindeye 34 posts

Topic: Script development / Stuck in onclick property

It's easier to create a fake event:

var myNode = document.getElementById("mynodeid");
var clickEvt = document.createEvent("MouseEvent");
clickEvt.initEvent("click", true, true);
myNode.dispatchEvent(clickEvt);

 
Apr 19, 2008
Mindeye 34 posts

Topic: Script development / Script works when appended to page end but not in Greasemonkey.

It's an XPCNativeWrapper's limitation

 
Apr 15, 2008
Mindeye 34 posts

Topic: Script development / Find out if a User has Greasemonkey installed

I believe the bug was fixed after beta 5 was released, so the code won't work with Firefox 3 RC1 or recent nightly builds (not sure, though)

 
Apr 15, 2008
Mindeye 34 posts

Topic: Script development / Find out if a User has Greasemonkey installed

The bug that enables that kind of detection (using chrome urls) has been recently fixed. It wouldn't be possible to do that with Firefox 3. See http://adblockplus.org/blog/web-pages-accessing...

 
Apr 11, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube Comments

Are you using Firefox 3 beta? There has been some problems with xmlHttpRequest and Greasemonkey in the beta

 
Apr 11, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube Comments

Do you have any other YouTube script installed? I tested it again and it works

 
Apr 10, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube Comments

Of course I did. Do you have any other YouTube script installed? Maybe it is a script conflict in your end. Any error in the error console?

 
Apr 10, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube Comments

Use this:

// ==UserScript==
// @name          YousableTubeFix (comments only)
// @namespace     http://userscripts.org/scripts/show/13333
// @description   Displays all comments on video page
// @include       http://youtube.tld/*
// @include       http://*.youtube.tld/*
// ==/UserScript==

/*
Author: Mindeye
Script initially based on ETcelera's YousableTube userscript (http://userscripts.org/scripts/show/5906)
Version: 10 Apr 2008
*/

// Shortcut to document.getElementById
function $(id) {
	return document.getElementById(id);
}

// Runs a particular XPath expression p against the context node context (or the document, if not provided)
// If a document (docObj) is provided, its evaluate method is used instead of document.evaluate (and it's also the default context)
// Returns the results as an array
function $x(p, context, docObj) {
	if (!docObj) docObj = document;
	if (!context) context = docObj;
	var item, arr = [], xpr = docObj.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	for (var i = 0; item = xpr.snapshotItem(i); i++) arr.push(item);
	return arr;
}

// Returns only the first element of the array returned by $x
function $x1(p, context, docObj) {
	var nodeArray = $x(p, context, docObj);
	if (nodeArray.length > 0) return nodeArray[0];
	return null;
}

// Creates a new node with the given attributes
function createNode(type, attributes) {
	var node = document.createElement(type);
	for (var attr in attributes) {
		node.setAttribute(attr, attributes[attr]);
	}
	return node;
}

// Adds !important to CSS rules of any type
String.prototype.makeImportant = function() {

	var Selector, DeclarationBlock, CssArray = this.match(/([^{]+)({[^{}]+})/);
	if (CssArray === null) {
		// Inline CSS rule (e.g. "display: none") or scripting rule (e.g. element.style.display = "none")
		Selector = "";
		DeclarationBlock = this;
	}
	else {
		// Complete CSS rule (e.g. ".nd {display: none}")
		Selector = CssArray[1];
		DeclarationBlock = CssArray[2];
	}

	// Adds !important to each rule
	if (DeclarationBlock.indexOf(":") != -1) {
		DeclarationBlock = DeclarationBlock.replace(/[^:;{}]+:[^:;{}]+/g, "$& !important");
	}
	else {
		// No estructure could be recognized, so we'll just add !important
		DeclarationBlock += " !important";
	}
	// Remove any !important duplicates
	DeclarationBlock = DeclarationBlock.replace(/(?:\s*!important\s*){2,}/gi, " !important");

	return Selector + DeclarationBlock;

}

// Adds styles for the ajax wrapper div and its contents
GM_addStyle("#gsajaxWrapper {margin: 100px auto; cursor: default; text-align: center}".makeImportant());
GM_addStyle("#gsajaxWrapper * {vertical-align: middle}".makeImportant()); // vertical-align isn't automatically inherited
GM_addStyle("#gsloadingIcon {margin: 5px}".makeImportant());
GM_addStyle("#gsprogressMeter {font-variant: small-caps}".makeImportant());
GM_addStyle("#gsabortButton {margin: 5px auto; display: block}".makeImportant());

var player = $("movie_player");
if (!player) return;

var ytHost = window.location.protocol + "//" + window.location.host;
var videoId = player.wrappedJSObject.GetVariable("video_id");

// Substitutes the original page size of comments in video page (10) for the bigger one used in the view all comments page (500)
// Other page sizes can't be easily used because Youtube ajax page only accepts those values in the pagesize parameter (others seem to default to 10)
// Gets necessary data from the page
var recentComments = $("recent_comments");
var commentsThreshold = $x1("//div[@id='watch-tab-commentary-body']//form//select[@name='commentthreshold']");

if (recentComments) {

	// Creates the elements that will indicate that the comments are being loaded
	var loadingIcon = createNode("img", {id: "gsloadingIcon", alt: "Loading...", src: ytHost + "/img/icn_loading_animated.gif"});
	var progressMeter = createNode("span", {id: "gsprogressMeter"});
	var abortButton = createNode("input", {id: "gsabortButton", title: "Abort the transaction", type: "button", value: "Abort"});
	var ajaxWrapper = createNode("div", {id: "gsajaxWrapper", title: "The comments are being loaded..."});

	// Inserts the contents within the wrapper
	ajaxWrapper.appendChild(loadingIcon);
	ajaxWrapper.appendChild(progressMeter);
	ajaxWrapper.appendChild(abortButton);

	// Select the original comments with a range and extracts them from the DOM tree into a document fragment
	var recentCommentsRange = document.createRange();
	recentCommentsRange.selectNodeContents(recentComments);
	var recentCommentsFrag = recentCommentsRange.extractContents();
	recentCommentsRange.detach();

	// Inserts the wrapper within the now empty div
	recentComments.appendChild(ajaxWrapper);

	// Adds an event listener to the abort button
	abortButton.addEventListener("click", abortAjax, false);

	// Gets the XML data from Youtube
	// GM_xmlhttpRequest's privileged features aren't necessary and it doesn't support responseXML without using DOMParser
	var xhrComments = new XMLHttpRequest();
	xhrComments.onload = function(evt) {

		// Checks for errors
		if ((xhrComments.readyState != 4) || (xhrComments.status != 200) || (!xhrComments.responseXML)) {
			restoreComments();
			return;
		}

		// The data was received. It is now used to fill the recent comments div
		var xmlData = $x1("//html_content", null, xhrComments.responseXML);
		var xmlReturnCodeNode = $x1("//return_code", null, xhrComments.responseXML);
		var xmlReturnCode = ((xmlReturnCodeNode) && (xmlReturnCodeNode.textContent)) ? xmlReturnCodeNode.textContent : null;
		if ((xmlData) && (xmlData.textContent) && (xmlReturnCode === "0")) {
			recentComments.innerHTML = xmlData.textContent;
		}
		else {
			restoreComments();
			return;
		}

		// Change the commentsThreshold combobox (if it exists) so it won't restore the old pagesize
		if ((commentsThreshold) && (commentsThreshold.hasAttribute("onchange"))) {
			commentsThreshold.setAttribute("onchange", commentsThreshold.getAttribute("onchange").replace("&page_size=10", "&page_size=500"));
		}

	}
	xhrComments.onprogress = function(evt) {
		progressMeter.textContent = Math.round(((evt.position / evt.totalSize) * 100)) + "% completed";
	}
	xhrComments.onerror = function(evt) {
		restoreComments();
	}
	var commentsURL = ytHost + "/watch_ajax?v=" + videoId + "&action_get_comments=1&p=1&commentthreshold=" + ((commentsThreshold) ? commentsThreshold.value : -5) + "&page_size=500";
	xhrComments.open("GET", commentsURL, true);
	xhrComments.send(null);

}


// Function to remove the ajax wrapper (with the loading icon, etc...) and restore the original comments
// It is called if the ajax transaction fails or is aborted
function restoreComments() {
	recentComments.replaceChild(recentCommentsFrag, ajaxWrapper);
}

// Function to abort the ajax transaction
// It is called by the ajax abort button event listener
function abortAjax(evt) {
	abortButton.disabled = true;
	if (xhrComments) xhrComments.abort();
	restoreComments();
}

Tested and adapted to the new YouTube design

 
Apr 10, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube Comments

Some of the code you posted is not really needed...

I said I wouldn't make it because I don't want to maintain a bunch of scripts with only a YousableTubeFix feature. But I can post it here if you want (I don't understand yet why don't you use the full version, though)

 
Apr 8, 2008
Mindeye 34 posts

Topic: Userscripts.org discussion / Feeds for script pages

Ok, now I see the links (a link tag). But a more evident one will be desirable, I think

 
Apr 8, 2008
Mindeye 34 posts

Topic: Userscripts.org discussion / Feeds for script pages

I was obviously not aware of those feeds. Where did you get those URLs from?

EDIT: I'd also like to know if the "Edit post" feature could be implemented in the script comments

This has been brought up a couple of times, see this topic

I have seen that topics, but I wanted to know if any progress have been made

 
Apr 8, 2008
Mindeye 34 posts

Topic: Userscripts.org discussion / Feeds for script pages

Could it be possible to add a RSS feed to each script page with the comments posted? It will make it easier for script authors to know if there is any issue with the script. And maybe the site's used bandwidth could be reduced

If the site could also generate a new rss item when the script is updated, then it will be even better ;-)

EDIT: I'd also like to know if the "Edit post" feature could be implemented in the script comments

 
Mar 18, 2008
Mindeye 34 posts

Topic: Userscripts.org discussion / Many hands make less spam

What I can't understand is why users like this or this aren't deleted and banned right away (and their posts/scripts deleted). Their only contributions are spam, flagged many times, why are this kind of users accounts left untouched? I once flagged a scrap all script, checked the author and found his/her only contributions were about 20 scrap all scripts, all unlisted. What is the benefit of having this kind of user around?

 
Mar 12, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Simple rerolling script for RPG game

Try to use textContent. innerText is a Internet Explorer only property (not standard)

 
Mar 9, 2008
Mindeye 34 posts

Topic: Script development / Useful code snippets


This one doesn't match the spaces in "string ", it needs a whitespace at the beginning.

The function I posted doesn't need a space at the beginning:
"string ".trim() ---> "string"
" string".trim() ---> "string"
" string ".trim() ---> "string"

And the spaces inside the string aren't removed (" 1 2 ".trim() ---> "1 2"), like it should. A trim function isn't supposed to remove those spaces

 
Mar 9, 2008
Mindeye 34 posts

Topic: Script development / Useful code snippets

A better trim function is:

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, "");
}

 
Mar 9, 2008
Mindeye 34 posts

Topic: Script development / removing complete table row without specefic class

And you don't need to check both ads.snapshotItem(i) and ads.snapshotItem(i) != 'undefined'. If ads.snapshotItem(i) === undefined, then ads.snapshotItem(i) would evaluate as false and Javascript would short-circuit the && expression

 
Mar 7, 2008
Mindeye 34 posts

Topic: Script development / removing block of html(no element ID)

You want to remove a table with class "tborder product". An Xpath expression like "//table[@class='tborder product']" would be enough


var ad = $x("//table[@class='tborder product']")[0];
if (ad) ad.parentNode.removeChild(ad);

You can get the $x function in the GreaseSpot wiki (http://wiki.greasespot.net/Code_snippets#XPath_...)

 
Mar 2, 2008
Mindeye 34 posts

Topic: Ideas and script requests / Youtube with better quality

I've added HD support to YousableTubeFix (http://userscripts.org/scripts/show/13333). Thanks leeresblatt for the hint, I didn't know about the fmt parameter ;-)

 
Mar 1, 2008
Mindeye 34 posts

Topic: Userscripts.org discussion / Spam and malware

Spammer:

http://userscripts.org/users/46532

 
Feb 28, 2008
Mindeye 34 posts

Topic: Script development / Avoid rendering before modifications

Glad to help :-)

 
Feb 27, 2008
Mindeye 34 posts

Topic: Script development / Avoid rendering before modifications

Greasemonkey runs the scripts when the DOMContentLoaded event fires. You can read more about it and the flicker you refer in http://wiki.greasespot.net/DOMContentLoaded

 
Feb 27, 2008
Mindeye 34 posts

Topic: Script development / Coralize other streaming sites?

You don't see the "movie_player" reference in the source because the movie player is dynamically written by a Youtube script function. But if you examine the DOM tree after the page has rendered (with Firebug, the DOM Inspector, etc...), you'll see an embed tag with that id

 
Feb 27, 2008
Mindeye 34 posts

Topic: Script development / Help with fake event

Thanks Descriptor and LouCypher for the documentation, I'll check it

Mikado:

You're creating event of wrong type. Check this example.
I wonder why your code even worked (if it did), since "click" doesn't belong to "HTMLEvents".

I can assure it worked before. I had also checked the documentation in Mozilla Developer site, but I haven't checked the official documentation since I was following the Greasemonkey wiki example (http://wiki.greasespot.net/Location_hack#Really...) and it uses HTMLEvents

The location hack is good, but I'd rather use initMouseEvent since it respects possible event Listeners added with addEventListener, and it bubbles up like a real event

 
Feb 26, 2008
Mindeye 34 posts

Topic: Script development / Help with fake event

One of the functions of my script YousableTubeFix (http://userscripts.org/scripts/show/13333) is to automatically expand video description in a Youtube page. A "(more)" link button with an associated onclick event handler does that, so I usually did something like this:


var expandLink = $x1("//div[@class='videoDescDiv collapse-content']//a[@class='smallText eLink'][@onclick]");
if (expandLink) {
// Executes the onclick function
expandLink.wrappedJSObject.onclick(); // unsafeWindow context
}

$x1 is a function that executes a Xpath search and return the first item found

Recently I changed the script to create a fake event and dispatch it. It has the additional advantage of don't breaking the sandbox:


var expandLink = $x1("//div[@class='videoDescDiv collapse-content']//a[@class='smallText eLink'][@onclick]");
if (expandLink) {
var clickEvt = document.createEvent("HTMLEvents");
clickEvt.initEvent("click", true, true);
expandLink.dispatchEvent(clickEvt);
}

It worked until recently, I think because Youtube changed something. I rolled back the change in my script and it is now working with the old code, but I'd like what is the problem with the event code

Thanks in advance