Override members on a built-in JavaScript object - javascript

I would like to override the default behavior of the offsetParent member of all html elements. I would like to do something like this if it's possible:
// For <div id="foo"></div>
var oFooElem = document.getElementById("foo");
oFooElem._offsetParent = oFooElem.offsetParent;
oFooElem.prototype.offsetParent = function() {
window.status = 'offsetParent called.';
return this._offsetParent;
};
Is this even possible? If so, please post the corrected code sample. Thanks!
Update:
#some Thank you for your help. It sounds like this is not possible. I have expanded on the problem that provoked this question in a new question if you're interested.

As far as I know it is not possible.
In firefox I get exception "setting a property that only has a getter", IE gives error, Chrome gives error, but in Opera it works (if I assign it on the element, not the prototype)!
But you have another problem. offsetParent isn't a function so it will never be called like a function and your alert will never happen. In opera (the only browser I found where you could replace it in) you only get the function back.
You can however add a new function (will work in Firefox, Chrome and Opera but not in IE since IE don't have the constructor property):
var e = document.getElementById("mydiv"); //Get a div element
//Adds a _offsetParent function to all DIV elements.
e.constructor.prototype._offsetParent=function(){
alert("offset parent called"); return this.offsetParent;
};
e._offsetParent();
Update
By reading your description here I see your error:
you get a reference to the object
called myInnerContent
you remove that object from the DOM when you replace the content of the outer tag.
you try to get the parent from the old object who is orphan and
that no longer are in the DOM. IE gives you an Error and Firefox gives you null.
You already have the solution on your page: Save the name of the object. Optionally you can choose to update the global variable when you update the content, or only update the innerHTML of the inner div.

Related

Why content within a header element can be accessed with .text and content within a p element with innerHTML in JavaScript

If I have the following html
<h2 id="myheader">some content</h2>
<p id="myp">some content </p>
To get the content of the header, I can do
document.getElementById('myheader').text
But then I was trying the same logic with the paragraph element, but instead I had to use innerHTML
Is there some sort of logic behind this difference?
Also in the console I like the fact that I can write something like window and then I can drill down all the available methods that I can use after window. For example that's how I found what window.document is the same as document. Is there a way to do the same thing for things like document.getElementById('myheader'), a way to investigate what methods are available after the dot document.getElementById('myheader').HERE just to learn by experimenting
EDIT: I realise that I am wrong about .text. There must be something wrong with my code (even though I can't see it), sorry for any confusion, if you think it should be edited not to mislead anyone, please do
Thanks
textContent is available for both elements (H1 and p).
You can examine an HTMLElement like this:
var elem = document.getElementById(some_id),
s = [],
key;
for (key in elem) {
s.push(key + ': ' + elem[key]);
}
s = s.join('\n');
console.log(s);
Many consoles create also a tree of the element structure just by logging an element:
console.log(document.getElementById(some_id));
Can you really do document.getElementById('myheader').text? Because it doesn't seem to me, unless you are using the jQuery .text() method.
In any case, you can methods such as innerText and textContent on both of your elements.
The reasons why window.document is the same as document is because document is a variable in the global scope, which is the window scope.
Also, to investigate which methods are available inside the console, you might assign your element to a variable, and then you can see the autocomplete, at least in Chrome developer tools.
var el = document.getElementById('myheader')
Then start typing el. … in the console.
According to MDN, there's no such thing as a .text property on HTMLHeadingElement. I've tested this on Chrome, just to be sure:
> document.createElement('h2').text
undefined
To reliably get the text content from any element you can use this construct:
var text = element.textContent || element.innerText || '';
Here, .textContent is understood by most browsers, whereas .innerText is specific to IE and '' is the fallback value.

var myVar; returns HTMLDivElement in Chrome but not in FF?

I tried to set a variable in the very first line of my script so I could access it later(and check if it was undefined. The basic gist of the code is:
var map;
var mapIsVisible = false;
console.log(map);
function clearMap() {
if(map != undefined) {
map.clear();
}
}
clearMap();
So in FF, it works perfectly. No errors whatsoever. Chrome throws an error that says:
Uncaught TypeError: Object #<HTMLDivElement> has no method 'clear'
which led me to do that console.log after the variable instantiation and what I got was an HTMLDivElement. Why is it that FF returns undefined while Chrome says its an HTMLDivElement when it clearly isn't? Or does chrome set that to all variables you declare that don't have any type to them?
My fix for now was to explicitly say that map was undefined:
var map = undefined;
and my script works well. What I want to know is why this happens for Chrome
EDIT
As said in the answers, I DO have an element with an id of "map". I didn't know that they automatically added JS variables for that.
You might have a <div id="map"> on your page somewhere and chrome thinks you are referencing it with the "map" variable you use.
My guess is that you have an element on your page with a name or id attribute of "map." I seem to recall id-ed elements automatically becoming global JS variables in Chrome. God knows why.

How to initialize firstChild so I don't get "x.firstChild is null or not an object"?

In my JSP/HTML I have this:
<div id="exampleLabel"> </div>
Then in my javascript section I have a function called from an onclick like this;
function changeLabel(){
exampleLabel.firstChild.nodeValue = 'LABEL HAS CHANGED';
}
This works fine in Chrome, does nothing in Firefox and in IE an error on page appears saying
exampleLabel.firstChild is null or not an object.
Ok I can take it that there was no firstChild so trying to do firstChild.ANYTHING would be a NPE, I can even take it that the other browsers don't just initialize it themselves like Chrome obviously does.
Question is, how do I initialize it myself so I can then go .nodeValue = "blahblah" on it?
The reason it doesn't work in IE is that unlike all other major browsers, it doesn't create text nodes for whitespace in your HTML, hence your <div> that only contains a space has no child nodes in IE. I would suggest adding a text node manually, or changing an existing one.
Also, unless you've declared exampleLabel elsewhere, you're relying on a non-standard and rather icky feature of IE and Chrome that maps IDs of DOM elements to properties of the global object (i.e., you can refer to an element as a variable by its ID). This doesn't work in other browsers. What you should do instead is use document.getElementById().
function changeLabel(labelText) {
var exampleLabel = document.getElementById('exampleLabel');
var child = exampleLabel.firstChild;
if (!child) {
child = document.createTextNode('');
exampleLabel.appendChild(child);
}
child.nodeValue = labelText;
}
changeLabel('LABEL HAS CHANGED');
Create a textNode and then append it.
function changeLabel(){
var textNode = exampleLabel.firstChild;
if (!textNode) {
textNode = document.createTextNode('foo');
exampleLabel.appendChild(textNode);
}
textNode.nodeValue = 'LABEL HAS CHANGED';
}

Scripting Object (as iframe replacement) in IE does odd stuff

I'm using the strict xhtml on my website, so I don't have the "Iframe" element. Instead, I'm trying to use the object tag.
I want to dynamically open content, so I've got a javascript function like this:
<object id="oPageName">
<script>
function openPage(pageName) {
var ifContent = document.getElementById("oPageName");
ifContent.data = pageName;
}
</script>
If I pass in say "someFolder/somepage.aspx" to openPage function, it simply sets the content page to "http://mysite/" - like it's chopping off the remaining part of the URL.
It works great in FF and Chrome, but not IE 8.
Any tips on this odd behavior?
If I pass in say "someFolder/somepage.aspx" to openPage function, it simply sets the content page to "http://mysite/"
You're doing better than most, then. Changing object.data in IE8 does nothing at all for me, just like it always has in IE.
There is a non-standard 'object' property on <object>s in IE, that gives you the document object of the inner HTML page (as you would expect to get from the unsupported contentDocument property). However, navigating that page (through object.object.URL or object.object.parentWindow.location) does the same as writing to object.data: nothing. (IE seems to get confused; if you look at the object.object.location.href, it actually points to the parent URL even though it's the child document.)
Basically, it's bugged to hell and you're best off forgetting <object> for HTML embedding today. Swallow your pride and include the iframe, using the Transitional DTD if you want to validate.
In earlier versions of IE (don't know about IE8) certain attributes on certain element types are immutable after being set once (programmatically or otherwise). I believe object and all the form elements (input, textarea etc.) behave this way.
I'm sure there's a more elegant way of solving this problem, but you could try something like this (untested):
function openPage(pageName) {
var ifContent = document.getElementById("oPageName");
try {
ifContent.setAttribute('data', pageName);
catch (e) { // catch immutable attribute error
// create a new object and replace the old one
var o = document.createElement('object');
o.setAttribute('name', pageName);
ifContent.parentNode.replaceChild(o, ifContent);
}
}
Most JS framworks have their own versions of setAttribute() which work around IE's attribute handling bugs.

Safari Native Code

Is anyone familiar with Native Code in OS X Safari (Version 3 and WebKit)? I'm using Javascript to parse some information in a form and one of my inputs is named "tags". When trying to get the value of that element using:
// button is being passed through a function as a DOM object
var tags = button.form.elements["tags"].value;
Safari returns some kind of function. I've gotten it to alert values like "function tags() { [native code] }" and Node Trees but I just can't understand why I would be having trouble. If anyone has a clue, please let me know. I've gotten it to work by changing the name of the input to something else and also by iterating through all elements and using if () statements to determine whether it's the element I want, but I'm awfully curious as to why Apple would restrict the use of any form element named "tags"...
P.S. - It's test and works fine in firefox.
[native code] just means that it's a function that is built in to the browser, rather than written in JavaScript. tags appears to be a WebKit extension to the DOM to allow you to get a list of elements in the form by tag name. For instance, if I run this on the StackOverflow page, I get the answer text area:
document.getElementById('submit-button').form.elements.tags("textarea")[0]
The issue is that an index into a collection in JavaScript also access any object properties (including methods), so when you try to access your named element tags, you get instead the method on the elements object that WebKit defines. Luckily, there is a workaround; you can call namedItem on the elements list to get an item by id or name:
var tags = button.form.elements.namedItem("tags").value;
edit: Note that its probably better to use namedItem in general even in other browsers, in case you need to retrieve an element named item or length or something like that; otherwise, if you use them as an index with the [] operator, you'll get the built in method item or length instead of your element.

Categories