How to get an element's left/top attribute in RAW JavaScript? - javascript

I created a codePen here (http://codepen.io/anon/pen/pwoEJ)
document.querySelector('#box').style.left
This line of code doesn't seem return the right value? It gives me "" empty string.

Use getComputedStyle:
document.defaultView.getComputedStyle(document.querySelector('#box')).left

try something like this,http://codepen.io/anon/pen/BjfGu
window.getComputedStyle(document.getElementById('box'),null).getPropertyValue('left');

It depends how cross-browser you want your code to be.
getComputedStyle is not available in IE8- (not sure if it works on IE9 either)
Also, the style might have been already set programmatically, in which case you will find the value inside the element.style object.
Finally, while getComputedStyle accepts CSS-like identifiers (e.g. z-index), the other ways of accessing style elements use camelized names (e.g. zIndex).
In the end, a more general solution is far from trivial:
getStyle = function getStyle (el, property)
{
var style;
if(document.defaultView && document.defaultView.getComputedStyle)
{
style = document.defaultView.getComputedStyle(el, "")
.getPropertyValue (property);
if (style) return style;
}
property = Camelize (property); // this is for older IE versions
if (el.currentStyle) style = el.currentStyle[property];
return style || el.style[property]
}
function Camelize (string)
{
var oStringList = string.split('-');
if (oStringList.length == 1) return oStringList[0];
var camelizedString = string.indexOf('-') == 0
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
: oStringList[0];
for (var i = 1, len = oStringList.length; i < len; i++)
{
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
return camelizedString;
}
(this code adapted for readability from Bernard Sumption's excellent Animator.js library)

Related

how to obtain the list of internal browser css for button in jquery [duplicate]

Here's how you get one css attribute using jQuery:
$('someObject').css('attribute')
How do you get them all? (without specifying and preferably in the following format so it can be reapplied with jQuery later):
cssObj = {
'overflow':'hidden',
'height':'100%',
'position':'absolute',
}
Thanks!!
EDIT
The methods I'm trying to get are declared in a style sheet (they are not inline). Sorry for not specifying.
See this live example using the jQuery attribute selector
$(document).ready(function() {
alert($("#stylediv").attr('style'));
});​
What about something like this:
jQuery CSS plugin that returns computed style of element to pseudo clone that element?
It is ugly, but it appeared to work for the poster...
This also may be of interest:
https://developer.mozilla.org/en/DOM:window.getComputedStyle
Not sure how cross-browser this one is, but it works in Chrome -
https://gist.github.com/carymrobbins/223de0b98504ac9bd654
var getCss = function(el) {
var style = window.getComputedStyle(el);
return Object.keys(style).reduce(function(acc, k) {
var name = style[k],
value = style.getPropertyValue(name);
if (value !== null) {
acc[name] = value;
}
return acc;
}, {});
};
window.getComputedStyle(element);
// For example
var element = document.getElementById('header');
window.getComputedStyle(element);
For a platform (the name is subject to nondisclosure) where the Chrome or Safari DevTools/WebInspector are not available, and you need to dump the styles to the log.
dumpCssFromId (id) {
const el = document.getElementById(id);
const styles = window.getComputedStyle(el);
return Object.keys(styles).forEach((index) => {
const value = styles.getPropertyValue(index);
if (value !== null && value.length > 0) {
console.log(`style dump for ${id} - ${index}: ${value}`);
}
}, {});
}

Why can't jQuery directly manipulate the class of an SVG element?

I blame my own stupidity, but I can't for the life of me understand why jQuery (2.1.4) can't directly change the class of an SVG element (or child elements) using it's class functions? I was messing around with trying to make an SVG manipulation plugin for jQuery, and I was testing all kinds of things to make the class changeable (yes, I've tried the common SVG libraries; no, I don't care for them). I ended up settling on my current version which intelligently overrides the original jQuery.addClass() function. I check if the jQuery element's array contains an SVG type node and if it does I use my custom function, otherwise, I pass it back to the original jQuery function. This seems to work so far. That being said, my "custom" function is the exact same code as the jQuery function because I copied it from the source on GitHub. So if it works with my "custom" function, why doesn't it simply work with the default jQuery function?
Here's the code I have so far. Syntax wise my code is different to match my style, but it effectively does the exact same thing as the original jQuery code.
(function ($) {
var element,
jQueryFunctions = {
addClass: $.fn.addClass
};
var addClass = function (
elements,
value) {
var proceed = typeof (value) === "string" && value;
if (!proceed) {
return this;
}
for (var i = 0, j, l = elements.length, element, klasses = (value || "").match(/\S+/g) || [], klass, currentValue, current, finalValue; element = elements[i], i < l; i++) {
currentValue = element.getAttribute && element.getAttribute("class") || "",
current = element.nodeType === 1 && (" " + currentValue + " ").replace(/[\t\r\n\f]/g, " ");
if (!current) {
return;
}
j = 0;
while (klass = klasses[j++]) {
if (current.indexOf(" " + klass + " ") < 0) {
current += klass + " ";
}
finalValue = jQuery.trim(current);
if (currentValue !== finalValue) {
element.setAttribute("class", finalValue);
}
}
}
};
var hasSvgNodes = function (
elements) {
var returnValue = true;
for (var i = 0, l = elements.length, element; element = elements[i], i < l; i++) {
returnValue = returnValue && (element.nodeName === "svg");
}
return returnValue;
};
$.fn.svg = function () {
return element = this;
};
$.fn.addClass = function (
value) {
if (!hasSvgNodes(this)) {
jQueryFunctions.addClass.apply(this, arguments);
} else {
addClass(this, value);
}
return this;
};
$.fn.svg.test = function () {
element.addClass("Red");
};
}(jQuery));
#Alex is correct. It doesn't work (demo). It used to once upon a time (eg. in the 1.1 branches) but it no longer does.
The reason is basically because the type of the className property is different for SVG elements and HTML elements. In HTML elements, it's a string. In SVG elements it's an SVGAnimatedString.
The addClass() code expects it to be a string.
var htmlelem = document.getElementById("htmlelem"),
svgelem = document.getElementById("svgelem");
alert("HTML = "+(typeof htmlelem.className) + ". SVG = "+(typeof svgelem.className));
<svg>
<rect id="svgelem" width="300" height="150"/>
</svg>
<div id="htmlelem"></div>
The reason your own version is working is because it looks like you have taken code from an older branch of jQuery. It is definitely not the 2.1.4 version of addClass.
Note, workaround ; svg , jsfiddle forked from #PaulLeBeau 's Answer
Try utilizing HTMLElement.dataset to apply css
$().ready(function() {
$("#test")[0].dataset.class = "red";
});
[data-class="red"] {
fill: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<svg>
<rect id="test" width="300" height="150" />
</svg>
#Paul's answer made me wonder a bit because the code I took was from the current source on GitHub. I double checked just in case I did pull from an older version, and sure enough it was the latest. So, I decided to double check the release notes for 3.0.0 a1, and I found my answer. Apparently the jQuery team decided to ever so slightly change their stance on the Won't Fix policy and allow direct manipulation of SVG elements' class attributes. That is the code that's currently up there now and what I was copying.
Here's the discussion thread and commit for reference. So, jQuery does do class manipulation by default, it's just in the next version. For what I'm working on, I don't mind going to the alpha so it works out for me.
I'll still be making my own plug in for SVG specific tasks which are specific to my needs, but with the class issue resolved, it should be much easier now.

Javascript: add an inline style to elements in a page that have a specific computed style attribute

I'm trying to add an inline style to elements in a page that have a specific computed style attribute.
For instance:
<head>
<style>
p.mim {
cursor:pointer;
}
a.fif {
cursor:pointer;
}
</style>
</head>
<body>
<p class="mim">prova</p>
<a class="fif">prova</a>
</body>
I want to add an inline style "cursor:wait" to each element that has "cursor:pointer" set in the computed style:
<body>
<p class="mim" style="cursor:wait;">prova</p>
<a class="fif" style="cursor:wait;">prova</a>
</body>
This is what I tried:
var elms = document.getElementsByTagName("*");
for (var j = 0; j < elms.length; j++) {
var crs = getComputedStyle(elm, null).getPropertyCSSValue('cursor') || "";
crs = crs.replace(/\s/g, "").toLowerCase();
switch (crs) {
case "pointer":
case "Pointer":
case "POINTER":
elm.style.cursor = "wait";
break;
}
});
Your code is redundant for several reasons, and incomplete for others.
Firstly, getComptedStyle doesn't exist in earlier versions of IE. They instead use the currentStyle property. Thankfully it is absurdly easy to shim this:
if( typeof getComputedStyle == "undefined") getComputedStyle = function(elem) {return elem.currentStyle;};
Now that that's been solved, remove that null argument as it is completely redundant. Actually, I didn't even know getComputedStyle had a second argument, but that's just me.
Next, you can get the cursor property just by getting .cursor (or ['cursor']) instead of that .getPropertyCSSValue call (which again I have never heard of...). You can also drop the || "" since getComputedStyle will return an empty string if the cursor property has not been set.
You don't need to trim spaces, but switching to lowercase seems like a good idea just to be on the safe side.
... But then, immediately after toLowerCase(), you check THREE different capitalisations of the word? Really?
Additionally, you never define elm (which is where your actual problem is), and you should cache the value of elms.length.
The final code should look like:
if( typeof getComputedStyle == "undefined") getComputedStyle = function(elem) {return elem.currentStyle;};
var elms = document.getElementsByTagName("*"), l = elms.length, i;
for( i=0; i<l; i++) {
if( getComputedStyle(elms[i]).cursor.toLowerCase() === "pointer") {
elms[i].style.cursor = "wait";
}
}
If you want to be able to undo this, you will need to store an array of elements that you're modifying, loop through it and remove the style (.style.cursor = "";).

Get a CSS value from external style sheet with Javascript/jQuery

Is it possible to get a value from the external CSS of a page if the element that the style refers to has not been generated yet? (the element is to be generated dynamically).
The jQuery method I've seen is $('element').css('property');, but this relies on element being on the page. Is there a way of finding out what the property is set to within the CSS rather than the computed style of an element?
Will I have to do something ugly like add a hidden copy of the element to my page so that I can access its style attributes?
With jQuery:
// Scoping function just to avoid creating a global
(function() {
var $p = $("<p></p>").hide().appendTo("body");
console.log($p.css("color"));
$p.remove();
})();
p {color: blue}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Using the DOM directly:
// Scoping function just to avoid creating a global
(function() {
var p = document.createElement('p');
document.body.appendChild(p);
console.log(getComputedStyle(p).color);
document.body.removeChild(p);
})();
p {color: blue}
Note: In both cases, if you're loading external style sheets, you'll want to wait for them to load in order to see their effect on the element. Neither jQuery's ready nor the DOM's DOMContentLoaded event does that, you'd have to ensure it by watching for them to load.
Normally you should be let the browser apply all the rules and then ask the browser for the results, but for the rare case where you really need to get the value out of the style sheet you can use this: (JSFiddle)
function getStyleSheetPropertyValue(selectorText, propertyName) {
// search backwards because the last match is more likely the right one
for (var s= document.styleSheets.length - 1; s >= 0; s--) {
var cssRules = document.styleSheets[s].cssRules ||
document.styleSheets[s].rules || []; // IE support
for (var c=0; c < cssRules.length; c++) {
if (cssRules[c].selectorText === selectorText)
return cssRules[c].style[propertyName];
}
}
return null;
}
alert(getStyleSheetPropertyValue("p", "color"));
Note that this is pretty fragile, as you have to supply the full selector text that matches the rule you are looking up (it is not parsed) and it does not handle duplicate entries or any kind of precedence rules. It's hard for me to think of a case when using this would be a good idea, but here it is just as an example.
In response to Karim79, I just thought I'd toss out my function version of that answer. I've had to do it several times so this is what I wrote:
function getClassStyles(parentElem, selector, style){
elemstr = '<div '+ selector +'></div>';
var $elem = $(elemstr).hide().appendTo(parentElem);
val = $elem.css(style);
$elem.remove();
return val;
}
val = getClassStyles('.container:first', 'class="title"', 'margin-top');
console.warn(val);
This example assumes you have and element with class="container" and you're looking for the margin-top style of the title class in that element. Of course change up to fit your needs.
In the stylesheet:
.container .title{ margin-top:num; }
Let me know what you think - Would you modify it, and if so how? Thanks!
I have written a helper function that accepts an object with the css attributes to be retrieved from the given css class and fills in the actual css attribute values.
Example is included.
function getStyleSheetValues(colScheme) {
var tags='';
var obj= colScheme;
// enumerate css classes from object
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
tags+= '<span class="'+prop+'"></span>';
}
}
// generate an object that uses the given classes
tags= $('<div>'+tags+'</div>').hide().appendTo("body");
// read the class properties from the generated object
var idx= 0;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop) && typeof(nobj[nprop])=="string") {
nobj[nprop]= tags.find("span:eq("+idx+")").css(nobj[nprop]);
}
}
idx++;
}
}
tags.remove();
}
// build an object with css class names where each class name contains one
// or more properties with an arbitrary name and the css attribute name as its value.
// This value will be replaced by the actual css value for the respective class.
var colorScheme= { chart_wall: {wallColor:'background-color',wallGrid:'color'}, chart_line1: { color:'color'} };
$(document).ready(function() {
getStyleSheetValues(colorScheme);
// debug: write the property values to the console;
if (window.console) {
var obj= colorScheme;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop)) {
console.log(prop+'.'+nprop +':'+ nobj[nprop]);
}
}
}
}
// example of how to read an individual css attribute value
console.log('css value for chart_wall.wallGrid: '+colorScheme.chart_wall.wallGrid);
}
});
I wrote this js function, seems to be working for nested classes as well:
usage:
var style = get_css_property('.container-class .sub-container-class .child-class', 'margin');
console.log('style');
function get_css_property(class_name, property_name){
class_names = class_name.split(/\s+/);
var container = false;
var child_element = false;
for (var i = class_names.length - 1; i >= 0; i--) {
if(class_names[i].startsWith('.'))
class_names[i] = class_names[i].substring(1);
var new_element = $.parseHTML('<div class="' + class_names[i] + '"></div>');
if(!child_element)
child_element = new_element;
if(container)
$(new_element).append(container);
container = new_element;
}
$(container).hide().appendTo('body');
var style = $(child_element).css(property_name);
$(container).remove();
return style;
}

setAttribute is not working for 'style' attribute on IE

I'm porting a piece of JS code written for Firefox into Internet Explorer. I faced a problem of changing style of an element using setAttribute method which was working on Firefox.
button.setAttribute('style', 'float: right;');
I tried setting the style member of button and it didn't work either. This was the solution in case of setting onclick event handler.
button.style = 'float: right;';
First I wanna know the solution for the above problem and
Second are there any maintained lists for these differences between browsers ?
Because style itself is an object. What you want is:
button.style.setAttribute('cssFloat','right');
But IE doesn't support setAttribute for style objects. So use the fully cross-browser supported:
button.style.cssFloat = 'right';
As for reference, I always go to www.quirksmode.org . Specifically: http://www.quirksmode.org/compatibility.html . Click on all the DOM related stuff.
And finally, to set multiple attributes I usually use something like:
function setStyle(el,spec) {
for (var n in spec) {
el.style[n] = spec[n];
}
}
usage:
setStyle(button,{
cssFloat : 'right',
border : '2px solid black'
});
Note: object.attribute = 'value' although works in all browsers may not always work for non-HTML DOM objects. For example, if your document contains embedded SVG graphics that you need to manipulate with javascript you need to use setAttribute to do it.
You need to use cssText
button.style.cssText = 'float: right;';
getAttribute and setAttribute are broken in Internet Explorer.
The correct syntax for what you are trying to achieve is:
button.style.cssFloat = 'right';
The correct solution to the problem is more likely to be:
button.className = 'a class that matches a pre-written CSS rule-set';
I noticed that setAttribute works in IE only when the attribute does not already exist.
Therefore, use remove attribute and then use set attribute.
Haven't tested this for bugs, but conceptually I think this will work:
NOTE - this was written to exist inside object that had property called 'element'.
//Set Property
this.setProperty = function (a, b) {
var c = this.element.getAttribute("style");
var d;
if (!c) {
this.element.setAttribute("style", a + ":" + b);
return;
} else {
d = c.split(";")
}
for (var e = 0; e < d.length; e++) {
var f = d[e].split(":");
if (f[0].toLowerCase().replace(/^\s+|\s+$/g, "").indexOf(a.toLowerCase().replace(/^\s+|\s+$/g, "")) == 0) {
d[e] = a + ":" + b
}
}
d[d.length] = a + ":" + b;
this.element.setAttribute("style", d.join(";"))
}
//Remove Property
this.removeProperty = function (a) {
var b = this.element.getAttribute("style");
var c;
if (!b) {
return
} else {
c = b.split(";")
}
for (var d = 0; d < c.length; d++) {
var e = c[d].split(":");
if (e[0].toLowerCase().replace(/^\s+|\s+$/g, "").indexOf(a.toLowerCase().replace(/^\s+|\s+$/g, "")) == 0) {
c[d] = ""
}
}
this.element.removeAttribute("style");
this.element.setAttribute("style", c.join(";").replace(";;", ";"))
}
Another useful way to mutate a style property is using the square brackets to access the property. This is useful for accessing properties which because of their name would give a syntax error if expressed normally. In JavaScript it is perfectly permissible to have properties with numeric values, numeric first letters and symbols and spaces as characters, but then you must use the square bracket way of accessing properties.
node.style.z-index = 50;//Firefox says error, invalid assignment left hand side.
node.style["z-index"] = "50";//Works without error
It does work in IE. Just tried it out.
The method is passed a style name and a value
The method then checks to see if there are any styles
If no styles attribute exists, then the method simply sets the style and stops
If a style attribute exists, all the styles in the attribute are split into an array
The array is iterated and all applicable style definitions are updated with the new value
The style attribute is then removed from the element
The style attribute is added back to the element with its values set to the new info
gathered from the array

Categories