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

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.

Related

How to get an element's left/top attribute in RAW 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)

Get border width from a div with plain javascript

I got this style applied to a div
div#content {
border: 1px solid skyblue;
}
and i want to be able to alert the width of the border, I have tried with this:
window.alert( document.getElementById( "content" ).style.borderWidth );
I heard that depends of the browser maybe you can help me
I'm using Firefox 18
Please try the below javascript:
alert($("#content").css("border-left-width")); //using jquery.
or
alert(getComputedStyle(document.getElementById('content'),null).getPropertyValue('border-left-width'));//without jquery.
getComputedStyle(element, pseudo)
element:The element to get a styling for
pseudo:A pseudo-selector like ‘hover’ or null if not needed.
Reference link: http://javascript.info/tutorial/styles-and-classes-getcomputedstyle
I might be too late but as you never marked it as answered, I thought I could give it a try.
If your problem was compatibility between browser I would create a custom method that I could use in almost every browser there is (that means going back to the very basics).
I actually dug a lot to do this. I use some of the code from jQuery because I did not want to use jQuery but still have the backwards compatibility that jQuery does.
This function solves your question and at the bottom there are some examples on how to use it.
This functions uses the "module pattern" through the immediate function that will be run as soon as the script loads creating a method that will NOT polute the global scope but extend its functionality through a function to do what you wanted.
// I give it a name but it can also be anonymous
(function preloadedFunctions(){
// Preseted methods.
if(window.getComputedStyle){
window.getComputedStylePropertyValue = function(element, prop){
var computedStyle = window.getComputedStyle(element, null);
if(!computedStyle) return null;
if(computedStyle.getPropertyValue) {
return computedStyle.getPropertyValue(prop);
} else if (computedStyle.getAttribute) {
return computedStyle.getAttribute(prop);
} else if(computedStyle[prop]) {
return computedStyle[prop];
};
};
}
// jQuery JavaScript Library v1.9.0
// http://www.minhacienda.gov.co/portal/pls/portal/PORTAL.wwsbr_imt_services.GenericView?p_docname=6240612.JS&p_type=DOC&p_viewservice=VAHWSTH&p_searchstring=
// For IE8 or less
else if ( document.documentElement.currentStyle ) {
var rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
rposition = /^(top|right|bottom|left)$/,
core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
window.getComputedStylePropertyValue = function(element, prop){
var left, rsLeft,
ret = element.currentStyle && element.currentStyle[ prop ],
style = element.style;
if ( ret == null && style && style[ prop ] ) {
ret = style[ prop ];
}
if ( rnumnonpx.test( ret ) && !rposition.test( prop ) ) {
left = style.left;
rsLeft = element.runtimeStyle && element.runtimeStyle.left;
if ( rsLeft ) {
element.runtimeStyle.left = element.currentStyle.left;
}
style.left = prop === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
style.left = left;
if ( rsLeft ) {
element.runtimeStyle.left = rsLeft;
}
}
return ret === "" ? "auto" : ret;
};
};
})();
i.e.
1.-
var borderWidth = getComputedStylePropertyValue(document.getElementsByTagName("div")[0], "border-width");
console.log(borderWidth);
2.-
var div = document.getElementById("someID");
console.log(getComputedStylePropertyValue(div, "border-width"));
If somebody is still looking, this seems to be easiest way to do it with plain JS.
let border =
+getComputedStyle((document.getElementById("idOfYourElement")))
.borderTopWidth.slice(0, -2)
Explanation below:
document.getElementById("idOfYourElement") - Return our HTML element.
getComputedStyle - Return css attributes of chosen element as object.
.borderTopWidth - Corresponding attribute from getComputedStyle object (return array like this: ("10px")).
.slice(0, -2) - Cut the last 2 characters from our array so we get rid of px at the end.
And + at the start - Parse rest of our string, that contains number we want, to the integer.
You can try this:
var border = document.getElementById("yourDiv").clientWidth - document.getElementById("yourDiv").offsetWidth;
alert(border);
Note, that the value will be rounded to an integer. If fractional value is required, you need to use getComputedStyle instead (see other answers).
Very old question, but anyway...
This solution is plain JavaScript, and should work in older browsers too.
It measures the size of the element, with, and without borders.
The following example should work correctly if the borders around the element are all the same size.
If not, the procedure doesn't change much, you just have to set the borders equal to zero, one by one.
var ele=document.getElementById("content");
// measures the element width, WITH borders
var w=ele.offsetWidth;
var cssBackup=ele.style.cssText;
// sets the borders to zero
ele.style.border="0px";
// computes the border size
var bord=(w-ele.offsetWidth)/2;
// resets the css
ele.style.cssText=cssBackup;
alert(bord);
When left & right border has same width:
function getWidth(div) {
return (div.offsetWidth - div.clientWidth) /2
}
getWidth(document.querySelector('#content'))
According to W3Schools, this property is supported by major browsers. Thus you shouldn't have any difficulty in using it.
However, using a JavaScript framework like jQuery would always help you not worrying about trivial issues like this.
Works for me
let content = document.querySelector('#content');
// here 'borderWidth' is similar to element.style syntax
let contentBorderWidth = getComputedStyle(content).borderWidth; // 1px
// number, without 'px'
let contentBorderWidthNumber = parseFloat(getComputedStyle(content).borderWidth); // 1
// demo
content.innerHTML = contentBorderWidth +', '+ contentBorderWidthNumber;
// in your case, to alert
window.alert(contentBorderWidth +', '+ contentBorderWidthNumber);
div#content {
border: 1px solid skyblue;
}
<div id="content"></div>
More about getComputedStyle.

Javascript find child class

I have a table. When the item is dropped I need to apply padding to a single table cell. I have flagged that cell with a class. How do I select it?
droppedRow contains the table row that is has just been dropped.
If it was an id I would do droppedRow.getElementById('..'); Is there something similar for class names. Needs to support >= IE7
Thanks
Using vanilla JavaScript, you'll probably need to load up all of the element's by tag name and then locate it by evaluating each element's classname.
For example (the styles are just for example)...
var tableCells = document.getElementsByTagName('td');
for(var i = 0, l = tableCells.length; i < l; i++) {
if(tableCells[i].className === 'droppedRow') {
tableCells[i].style.padding = '1em';
}
}
If, on the other hand, you're using jQuery, then you should be able to use:
$('.droppedRow').css('padding', '1em');
Note however that in both of these examples, all cells that have the droppedRow class name will receive this styling (rather than just a single element).
If you're not using a library, I'd say stick with the vanilla variant of this functionality - libraries would be too much overhead just to condense this to a single line.
Maxym's answer also provides a solid implementation of getElementsByClassName for older browsers.
There exists getElementsByClassName but it is not supported in IE. Here is what you can do:
var element;
// for modern browsers
if(document.querySelector) {
element = droppedRow.querySelector('.yourClass');
}
else if(document.getElementsByClassName) { // for all others
element = droppedRow.getElementsByClassName('yourClass')[0];
}
else { // for IE7 and below
var tds = droppedRow.getElementsByTagName('td');
for(var i = tds.length; i--; ) {
if((" " + tds[i].className + " ").indexOf(" yourClass ") > -1) {
element = tds[i];
break;
}
}
}
Reference: querySelector, getElementsByClassName, getElementsByTagName
Clientside getElementsByClassName cross-browser implementation:
var getElementsByClassName = function(className, root, tagName) {
root = root || document.body;
if (Swell.Core.isString(root)) {
root = this.get(root);
}
// for native implementations
if (document.getElementsByClassName) {
return root.getElementsByClassName(className);
}
// at least try with querySelector (IE8 standards mode)
// about 5x quicker than below
if (root.querySelectorAll) {
tagName = tagName || '';
return root.querySelectorAll(tagName + '.' + className);
}
// and for others... IE7-, IE8 (quirks mode), Firefox 2-, Safari 3.1-, Opera 9-
var tagName = tagName || '*', _tags = root.getElementsByTagName(tagName), _nodeList = [];
for (var i = 0, _tag; _tag = _tags[i++];) {
if (hasClass(_tag, className)) {
_nodeList.push(_tag);
}
}
return _nodeList;
}
Some browsers support it natively (like FireFox), for other you need provide your own implementation to use; that function could help you; its performance should be good enough cause it relies on native functions, and only if there is no native implementation it will take all tags, iterate and select needed...
UPDATE: script relies on hasClass function, which can be implemented this way:
function hasClass(_tag,_clsName) {
return _tag.className.match(new RegExp('(\\s|^)'+ _clsName +'(\\s|$)'));
}
It sounds like your project is in need of some JQuery goodness or some Dojo if you need a more robust and full-fledged javascript framework. JQuery will easily allow you to run the scenario you have described using its selector engine.
If you are using a library, why not use:
JQuery - $("#droppedRow > .paddedCell")
Thats the dropped row by ID and the cell by class
Prototype - $$("#droppedRow > .paddedCell")

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;
}

Duplicating an element (and its style) with JavaScript

For a JavaScript library I'm implementing, I need to clone an element which has exactly the same applied style than the original one. Although I've gained a rather decent knowledge of JavaScript, as a programming language, while developing it, I'm still a DOM scripting newbie, so any advice about how this can be achieved would be extremely helpful (and it has to be done without using any other JavaScript library).
Thank you very much in advance.
Edit: cloneNode(true) does not clone the computed style of the element. Let's say you have the following HTML:
<body>
<p id="origin">This is the first paragraph.</p>
<div id="destination">
<p>The cloned paragraph is below:</p>
</div>
</body>
And some style like:
body > p {
font-size: 1.4em;
font-family: Georgia;
padding: 2em;
background: rgb(165, 177, 33);
color: rgb(66, 52, 49);
}
If you just clone the element, using something like:
var element = document.getElementById('origin');
var copy = element.cloneNode(true);
var destination = document.getElementById('destination');
destination.appendChild(copy);
Styles are not cloned.
Not only will you need to clone, but you'll probably want to do deep cloning as well.
node.cloneNode(true);
Documentation is here.
If deep is set to false, none of the
child nodes are cloned. Any text that
the node contains is not cloned
either, as it is contained in one or
more child Text nodes.
If deep evaluates to true, the whole
subtree (including text that may be in
child Text nodes) is copied too. For
empty nodes (e.g. IMG and INPUT
elements) it doesn't matter whether
deep is set to true or false but you
still have to provide a value.
Edit: OP states that node.cloneNode(true) wasn't copying styles. Here is a simple test that shows the contrary (and the desired effect) using both jQuery and the standard DOM API:
var node = $("#d1");
// Add some arbitrary styles
node.css("height", "100px");
node.css("border", "1px solid red");
// jQuery clone
$("body").append(node.clone(true));
// Standard DOM clone (use node[0] to get to actual DOM node)
$("body").append(node[0].cloneNode(true));
Results are visible here: http://jsbin.com/egice3/
Edit 2
Wish you would have mentioned that before ;) Computed style is completely different. Change your CSS selector or apply that style as a class and you'll have a solution.
Edit 3
Because this problem is a legitimate one that I didn't find any good solutions for, it bothered me enough to come up with the following. It's not particularily graceful, but it gets the job done (tested in FF 3.5 only).
var realStyle = function(_elem, _style) {
var computedStyle;
if ( typeof _elem.currentStyle != 'undefined' ) {
computedStyle = _elem.currentStyle;
} else {
computedStyle = document.defaultView.getComputedStyle(_elem, null);
}
return _style ? computedStyle[_style] : computedStyle;
};
var copyComputedStyle = function(src, dest) {
var s = realStyle(src);
for ( var i in s ) {
// Do not use `hasOwnProperty`, nothing will get copied
if ( typeof s[i] == "string" && s[i] && i != "cssText" && !/\d/.test(i) ) {
// The try is for setter only properties
try {
dest.style[i] = s[i];
// `fontSize` comes before `font` If `font` is empty, `fontSize` gets
// overwritten. So make sure to reset this property. (hackyhackhack)
// Other properties may need similar treatment
if ( i == "font" ) {
dest.style.fontSize = s.fontSize;
}
} catch (e) {}
}
}
};
var element = document.getElementById('origin');
var copy = element.cloneNode(true);
var destination = document.getElementById('destination');
destination.appendChild(copy);
copyComputedStyle(element, copy);
See PPK's article entitled Get Styles for more information and some caveats.
After looking at a couple of good solutions across the WEB, I decided to combine all the best aspects of each and come up with this.
I left my solution in plain super fast Javascript, so that everybody can translate to their latest and great JS flavour of the month.
Representing the vanilla from manilla.....
* #problem: Sometimes .cloneNode(true) doesn't copy the styles and your are left
* with everything copied but no styling applied to the clonedNode (it looks plain / ugly). Solution:
*
* #solution: call synchronizeCssStyles to copy styles from source (src) element to
* destination (dest) element.
*
* #author: Luigi D'Amico (www.8bitplatoon.com)
*
*/
function synchronizeCssStyles(src, destination, recursively) {
// if recursively = true, then we assume the src dom structure and destination dom structure are identical (ie: cloneNode was used)
// window.getComputedStyle vs document.defaultView.getComputedStyle
// #TBD: also check for compatibility on IE/Edge
destination.style.cssText = document.defaultView.getComputedStyle(src, "").cssText;
if (recursively) {
var vSrcElements = src.getElementsByTagName("*");
var vDstElements = destination.getElementsByTagName("*");
for (var i = vSrcElements.length; i--;) {
var vSrcElement = vSrcElements[i];
var vDstElement = vDstElements[i];
// console.log(i + " >> " + vSrcElement + " :: " + vDstElement);
vDstElement.style.cssText = document.defaultView.getComputedStyle(vSrcElement, "").cssText;
}
}
}
None of those worked for me, but I came up with this based on Luigi's answer.
copyStyles(source: HTMLElement, destination: HTMLElement) {
// Get a list of all the source and destination elements
const srcElements = <HTMLCollectionOf<HTMLElement>>source.getElementsByTagName('*');
const dstElements = <HTMLCollectionOf<HTMLElement>>destination.getElementsByTagName('*');
// For each element
for (let i = srcElements.length; i--;) {
const srcElement = srcElements[i];
const dstElement = dstElements[i];
const sourceElementStyles = document.defaultView.getComputedStyle(srcElement, '');
const styleAttributeKeyNumbers = Object.keys(sourceElementStyles);
// Copy the attribute
for (let j = 0; j < styleAttributeKeyNumbers.length; j++) {
const attributeKeyNumber = styleAttributeKeyNumbers[j];
const attributeKey: string = sourceElementStyles[attributeKeyNumber];
dstElement.style[attributeKey] = sourceElementStyles[attributeKey];
}
}
}

Categories