Hi, I'm trying to create a Youtube video inserter script for my site. Long story short, I need to be able to prototype an HTML element and add a string into the element's innerHTML, like this: myObj.insertVid(5sw2OvIgoO8); I'm using jQuery to getElementsByClass("sip").

Object.prototype.insertVid = function(id) {
	if (id.length > 0) {
		var insert_string = '<embed src="http://www.youtube.com/v/' + id + '&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"/>';
		this.innerHTML += insert_string;
	}
}

embeds = $(".sip");
for (var i=0; i<embeds.length; i++) {
	// various code to find param for insertVid()
	embeds[i].insertVid(id);
}

All of this code seems correct to me, but in the error console (Firefox 3.5.2), it's telling me: Error: embeds[i].insertVid is not a function Help?

Dani AI

Generated

The error "embeds[i].insertVid is not a function" is explained by the Greasemonkey/profile sandbox. Methods added to Object.prototype (or Element.prototype) inside the userscript live in the userscript's JS realm and do not automatically appear on DOM objects that belong to the page's window. That also explains the "Element.prototype is undefined" symptom that saw and why 's Element.prototype suggestion didn't work in this context. 's idea to avoid prototype extension is the right direction.

Practical options (in order of safety and portability):

  • Add a jQuery plugin (extend $.fn) so the behavior runs on the jQuery wrapper used in the userscript.
  • Use a plain function that accepts a DOM element plus the video id and performs the insertion.
  • If prototype extension is absolutely required, inject a script element into the page so the code runs in the page's window (then the prototype changes will be visible to page DOM). Injecting site globals is risky and not recommended unless necessary.

Example jQuery-friendly approach (keeps everything in the userscript realm and works with $(".sip")):

$.fn.insertVid = function(id) {
  if (!id) return this;
  var src = 'https://www.youtube.com/embed/' + encodeURIComponent(id) + '?rel=0';
  var iframe = '<iframe width="425" height="344" frameborder="0" allowfullscreen src="' + src + '"></iframe>';
  return this.each(function(){ $(this).append(iframe); });
};

A page-injection fallback (only if prototype extension is required) can be done by creating a script node whose text defines the prototype method and appending it to the document. This places the method into the page's window so DOM nodes will see it. Use that pattern with caution: altering host prototypes can break other scripts.

A small runtime diagnostic: compare the element's owner window to the script window (for example, check whether embeds[i].ownerDocument.defaultView === window) to confirm a realm mismatch before attempting prototype patches.

Recommended Answers

All 7 Replies

bump

A) Don't bump like that, its annoying. B) Try Element.prototype. If that doesn't work I have no idea since both Object.proto... and Element.proto... worked for me.

A) I waited a day with no response and my thread was already 9 or 10 posts down. I would prefer not to actually post "bump" if there was another way to bump it up the list, say every 24 hours.

B) Element.prototype didn't work either, Firefox gave me: Error: Element.prototype is undefined The only thing that may be causing this is the fact that I'm running this through a Greasemonkey userscript. Prototype should work fine in a userscript though. I'm not sure what else could be the case.. I even ran alert(typeof embeds[i]); and it gave me "object". Seems like I am doing everything right, but something is wrong somewhere.

Thanks for replying :)

Make sure you're never trying to call the method before you actually define the prototype. Grab Firebug if you don't already and then do some breakpoint debugging to find exactly where the error is coming from.

I don't think Greasemonkey works with Firebug as far as breakpoints because GM scripts are inserted and removed quickly at the end of a page load.

AFAIK, my script doesn't call the prototype before it's defined as the definition is at the top of my script.

Object.prototype.insertVid = function(id) {
	if (id.length > 0) {
		var insert_string = '<embed src="http://www.youtube.com/v/' + id + '&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"/>';
		this.innerHTML += insert_string;
	}
}

if (window == window.top)
	parseEmbeds();

function parseEmbeds() {
	var embeds = $(".sip");
	var handle = new String();
	var cmds = new Array();
	for (var i=0; i<embeds.length; i++) {
		handle = embeds[i].title;
		cmds = handle.split(";");
		for (var v=0; v<cmds.length; v++) {
			if (cmds[v].length > 0) {
				if (/vid\([^\)]*\)/i.test(cmds[v])) {
					var vids = cmds[v].match(/vid\(([^\=]*\?v=([^\)]*))\)/i);
					embeds[i].insertVid(vids[2]);
				}
			}
		}
	}
}

try changing the embeds[i].insertVid(id); into

insertVid(embeds[i].id);

and in case, this doesn't solve your problem try bypassing

Object.prototype.insertVid = function(id) {...

with:
var insertVid = function(id) {...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.