Firefox 5 gives all CSS when running getComputedStyle - javascript

Using firefox 5 when i run
window.getComputedStyle(document.getElementsByTagName("img")[0], null);
I get the complete css file, instead of the styles applied onto the "img" tag.
I ran this on https://developer.mozilla.org/en/DOM/window.getComputedStyle
Anyone knows of a workaround?

I know this is an older post, but for anyone landing here.
Basic idea: you need to call the getPropertyValue() method on the object returned by window.getComputedStyle().
See this fiddle: http://jsfiddle.net/zupa/jyyt9/
MDN states you don't need to call document.defaultView.getComputedStyle() but window.getComputedStyle
Note that window.getComputedStyle() returns used values not computed values. (See previous link.)
Compatibility tables: MDN, quirksmode

It should give you an object of type ComputedCSSStyleDeclaration that includes all styles that have been set. This includes all possible styles and not only those styles that have been manipulated by you in some way.
In order to get a specific rule, use for example:
window.getComputedStyle(document.getElementsByTagName("img")[0], null)['borderLeftColor'];
This gives the left border color without distinguishing how the value as specified / calculated.
To get a list of the available entries print the object to Firebug's console:
console.dir(window.getComputedStyle(document.getElementsByTagName("img")[0], null));

Use this :
document.defaultView.getComputedStyle(document.getElementsByTagName("img")[0], "");

Related

Changing inner text value of tab through javascript

I'm learning Javascript right now, and attempting to change the text title of a particular tab. It's actually part of a larger Shiny dashboard project, but I want to add some custom functionality to a few tabs. Below are the tabs in question:
Simple enough. I first access my tabs in my Javascript file:
var tabScrub2 = $(document).find('[data-value="scrubTab2"]');
console.log(tabScrub2);
When I use Firefox's developer console, I see that the tab is an object:
Moreover, it looks like I need to change the innerText property of 0, whatever this is, since that corresponds to the title of my tab (the innerText of 1 corresponds to the text inside scrubTab2). However, I'm not familiar with the actual object type being returned here:
Simply put, how the heck do I access and manipulate properties from this? And am I actually accessing an array? When I type in
var scrub2 = tabScrub2["1"];
console.log(scrub2);
I get an HTML element. I'm seen the a element in CSS and jQuery, but am not super familiar with how to manipulate its properties programmatically? How do I go about accessing and manipulating the innerText properties of this via Javascript? For instance, how would I hide scrubTab2, or change its title to something else?
The first object you're seeing is jQuery's wrapper around the real DOM elements. It's not an actual array, but it does contain all of the elements that matched your query under zero-indexed properties (e.g. "0" and "1") which allows you to access to them via an array-like API (e.g. tabScrub[1]).
Your method of grabbing a node using tabScrub2["1"] is correct (see this question in the jQuery FAQ). It's more likely to see that done with a numeric key though (i.e. tabScrub[1]) because that matches the way you would access an element in a normal array.
As far as manipulating properties of the DOM node, the DOM's API is notoriously inconsistent and quirky (hence the need for things like jQuery in the first place). However, for your use case you can just assign a string to the innerText property directly (e.g. tagScrub2[1].innerText = "Tab title"). MDN is a great resource if you're looking for reference material on other parts of the DOM.
A side note: if you're looking for a specific element you should use a query that will only match that element. It's generally a bad sign if you're grabbing extra elements and then accessing the element you want at a key other than 0. If you're doing this then your code depends on other (potentially unrelated) nodes in the DOM existing before your node, and if/when you change those nodes your original code will break.
Just use jQuery eq method to get the relevant object index from the array.
For an example
//Query and get first element.
var tabScrub2 = $(document).find('[data-value="scrubTab2"]:eq(0)');
//Hide
tabScrub2.hide();
//Change title
tabScrub2.attr("title", "New Title Text");
Lean more about jQuery eq here.
https://api.jquery.com/eq/
Since you use jquery selectors tabScrub2[0] returns the native DOM element instead of another jQuery object. Therefore the hide function won't work in that object since the native DOM element doesn't implement such type of functionality for an element. That's why you have to use jQuery pseudo selector as above. Because hide will only work with a jQuery object.

Loop though DOM with jQuery to get some data- attribute value

This seems like a simple thing, but I keep getting "undefined"
I am trying out the "data-" HTML5 attribute and I am looping through a bunch of div tags that look like this:
<div id="myEvent"
data-scheduledOn="1399985100000"
data-eventStatus="3">
And I am looping through a bunch of these like this:
$('[id="myEvent"]').each(function(index, divItem) {
alert($(divItem).data("scheduledOn"));
}
But I keep getting "undefined" If I do this (get the attribute) it works fine:
alert($(divItem).attr("data-scheduledOn"));
So What am I missing?
http://api.jquery.com/data/
"The .data() method allows us to attach data of any type to DOM elements in a way that is safe from circular references and therefore from memory leaks."
At least at this point in time, to use the .data function you have to attach the data using the function before you can read it back using the .data function.
If you need to read pre-existing data use the .attr or .prop functions.
It seems as though It is a naming problem as Hamza Kubba suggested, but just a bit different...
if I changed the name of the data attribute to "data-scheduled-on" I can retrieve it by .data("scheduledOn") OR using data-scheduledon and .data("scheduledon") also works.
So don't use CAPS for data- names is the moral of this story!
Please note that per HTML 5 specs, the attribute name should not contain any uppercase letters and some browsers such as FF & Chrome will change any uppercase letter to lowercase. That's why the following demo works if you access the data attributes with lowercase names:
http://jsfiddle.net/fiddleyetu/5LdQd/
$('div.myEvent').each(function(index, divItem) {
console.log($(divItem).data("scheduledon"));
console.log( $(divItem).data("eventstatus") );
});
Ans since you cannot have more than one element on a page with the same ID, I have used a class selector for the demo.
MORAL: Do not use UPPERcase; your browsers may not always be that 'understanding'.

Removing Chrome's "translate" DOM Property

I'm working with some legacy code where the original developers made heavy use of generating HTML DOM nodes with a non-standard attribute named translate
<span translate="[{"shown":"My Account","translated":"My Account","original":"My Account","location":"Text","scope":"Mage_Customer"}]">My Account</span>
and then traversing/searching for those nodes with javascript code like the following.
if (!$(target).match('*[translate]')) {
target = target.up('*[translate]');
}
The problem I'm trying to solve is, it appears that Google Chrome automatically adds a translate attribute to every DOM node in the document, and that this DOM node's value is a boolean true. You can see this by running the following Javascript from Chrome's javascript console
> document.getElementsByTagName('p')[0].translate
true
>
Is there anyway to tell Chrome not to populate these attributes? Their presence is wrying havoc with the legacy code. PrototypeJS's match and up nodes treat these boolean object attributes as matches, while the code I'm dealing with is specifically looking for DOM nodes with an attribute named translate. I'd like to find a solution for my problem that doesn't involved rewriting the old Javascript to use methods like hasAttribute.
I tried (as a wild guess) adding the meta attributes mentioned in this article,
<meta name=”google” value=”notranslate”>
<meta name=”google” content=”notranslate”>
but the nodes in the page still has a boolean true translate attribute.
(if it matters, this is Magento's inline translation system I'm talking about here)
The best I've been able to come up with so far is going through every DOM element in the page defining a getter that checks for the existence of an attribute. (the Object.__defineGetter__ guard clause ensures no errors in browsers that don't support modern Javascript)
if(Object.__defineGetter__)
{
var hasTranslateAttribute = function(){
return $(this).hasAttribute("translate");
};
document.observe("dom:loaded", function() {
$$('*').each(function(theElement){
theElement.__defineGetter__("translate", hasTranslateAttribute);
});
});
}
I tried defining a getting on Object.prototype and Element.prototype, but it seems like the browser's native translate is defined higher up the chain, so you need to redefine things on a per element basis.
Replace the nonstandard attribute translate by an attribute like data-translate, which is virtually guaranteed to be and to remain undefined in HTML specifications and in browsers. The data-* attributes were invented to prevent issues like this, and they can also be used to fix them.

Assign all vendor-prefixed variants to style

Modernizr provides a testAllProps() method which conveniently tests all the vendor prefixed styles of the one given to see if the style is supported by the currently running browser.
However I have no come to a point where I need to actually assign these properties from javascript because of various reasons that boil down to it being too cumbersome to conditionally link CSS files.
So for instance I could build an array and a routine which assigns each vendor specific style to the style of my target element:
['mozTransitionDuration', 'webkitTransitionDuration', 'oTransitionDuration', 'msTransitionDuration', 'transitionDuration'].map(function(s){ element.style.s = "style_setting"; });
Well, this will probably generate a bunch of errors because I will try to assign "style_setting" to 4 or 5 undefined values.
Does anybody know anything to make this a bit less painful?
Probably best to use an existing library that knows all about this stuff:
Prefix Free will let you assign styles from CSS without vendor-prefixing. There is also a jQuery Plugin for it that will allow you to do the same from JavaScript.
Before setting the value, check whether the property is undefined:
['mozTransitionDuration', 'webkitTransitionDuration', 'oTransitionDuration', 'msTransitionDuration', 'transitionDuration']
.map(function(s) {
if (element.style[s] != undefined) element.style[s] = "style_setting";
});

How can I get the font size of an element as it was set by css

I'm writing a simple jQuery that to change the font size of an element by a certain percentage. The problem I'm having is that when I get the size with jQuery's $('#el').css('font-size') it always returns a pixel value, even when set with em's. When I use Javscript's el.style.font-size property, it won't return a value until one has been explicitly set by the same property.
Is there some way I can get the original CSS set font-size value with Javascript? How cross-browser friendly is your method?
Thanks in advance!
Edit: I should note that all the tested browsers (See comment below) allow me to set the the text-size using an 'em' value using the two methods mentioned above, at which point the jQuery .css() returns an equivalent 'px' value and the Javascript .style.fontSize method returns the correct 'em' value. Perhaps the best way to do this would be to initialize the elements on page load, giving them an em value right away.
All of your target browsers with the exception of IE will report to you the "Computed Style" of the element. In your case you don't want to know what the computed px size is for font-size, but rather you want the value set in your stylesheet(s).
Only IE can get this right with its currentStyle feature. Unfortunately jQuery in this case works against you and even gets IE to report the computed size in px (it uses this hack by Dean Edwards to do so, you can check the source yourself).
So in a nutshell, what you want is impossible cross-browser. Only IE can do it (provided you bypass jQuery to access the property). Your solution of setting the value inline (as opposed to in a stylesheet) is the best you can do, as then the browser does not need to compute anything.
In Chrome:
var rules = window.getMatchedCSSRules(document.getElementById('target'))
returns a CSSRuleList object. Need to do a bit more experimentation with this, but it looks like if m < n then the CSSStyleRule at rules[n] overrides the one at rules[m]. So:
for(var i = rules.length - 1; i >= 0; --i) {
if(rules[i].style.fontSize) {
return /.*(em|ex|ch|rem|vh|vw|vmin|vmax|px|in|mm|cm|pt|pc|%)$/.exec(rules[i].style.fontSize)[1];
}
}
In Firefox, maybe use sheets = document.styleSheets to get all your stylesheets as a StyleSheetList, then iterate over each CSSStyleSheet sheet in sheets. Iterate through the CSSStyleRules in sheet (ignoring the CSSImportRules) and test each rule against the target element via document.getElementById('target').querySelector(rule.selectorText). Then apply the same regexp as above..... but that's all just a guess, I haven't tested it out or anything....
This jQuery plugin looks like it will do the trick:
Update: jQuery Plugin for Retaining Scalable Interfaces with Pixel-to-Em Conversion
Github: jQuery-Pixel-Em-Converter
i had this problem once. i use this function to get the int value of a css attribute, if there is one.
function PBMtoInt(str)
{
return parseInt(str.replace(/([^0-9\.\-])+/,"")!=""?str.replace(/([^0-9\.\-])+/,""):"0");
}

Categories

Resources