Recent posts by Mindeye
|
May 1, 2008
|
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
|
Topic: Script development / Script works when appended to page end but not in Greasemonkey. It's an XPCNativeWrapper's limitation |
|
Apr 15, 2008
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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 I have seen that topics, but I wanted to know if any progress have been made |
|
Apr 8, 2008
|
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
|
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
|
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
|
Topic: Script development / Useful code snippets
The function I posted doesn't need a space at the beginning:
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
|
Topic: Script development / Useful code snippets A better trim function is:
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, "");
}
|
|
Mar 9, 2008
|
Topic: Script development / removing complete table row without specefic class And you don't need to check both |
|
Mar 7, 2008
|
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
You can get the $x function in the GreaseSpot wiki (http://wiki.greasespot.net/Code_snippets#XPath_...) |
|
Mar 2, 2008
|
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
|
Topic: Userscripts.org discussion / Spam and malware Spammer: |
|
Feb 28, 2008
|
Topic: Script development / Avoid rendering before modifications Glad to help :-) |
|
Feb 27, 2008
|
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
|
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
|
Topic: Script development / Help with fake event Thanks Descriptor and LouCypher for the documentation, I'll check it Mikado:
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
|
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:
$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:
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 |
