Alko
Alko

Reputation: 1439

Javascript/jQuery parse inline style as each object

I want to be able to parse inline css and have it as object in key pairs. Something like:

<div background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">

{ 
  backgroundImage : "http://domain.com/images/image.jpg",
  backgroundSize: "cover",
  padding: "100px 0"
} 

This function works great for the most of the part. I'm having problem with background-image

it strips it completely and I end up with "url(http" instead.

function parseCss(el) {
    var output = {};

    if (!el || !el.attr('style')) {
        return output;
    }

    var camelize = function camelize(str) {
        return str.replace(/(?:^|[-])(\w)/g, function(a, c) {
            c = a.substr(0, 1) === '-' ? c.toUpperCase() : c;
            return c ? c : '';
        });
    }

    var style = el.attr('style').split(';');
    for (var i = 0; i < style.length; ++i) {
        var rule = style[i].trim();
        if (rule) {
            var ruleParts = rule.split(':');
            var key = camelize(ruleParts[0].trim());
            output[key] = ruleParts[1].trim();
        }
    }

    return output;
}

I'm pretty sure that "replace" function needs to be modified to make it work with image url

Upvotes: 1

Views: 1193

Answers (3)

sinisake
sinisake

Reputation: 11328

You can try with this, tested on few examples:

styleObj={};
style=$('div').attr('style');
rules=style.split(';');
rules = rules.filter(function(x){
  return (x !== (undefined || ''));
}); // https://solidfoundationwebdev.com/blog/posts/remove-empty-elements-from-an-array-with-javascript



for (i=0;i<rules.length;i++) {

rules_arr=rules[i].split(/:(?!\/\/)/g); // split by : if not followed by //
rules_arr[1]=$.trim(rules_arr[1]).replace('url(','').replace(')','');

if(rules_arr[0].indexOf('-')>=0) {
rule=rules_arr[0].split('-');
rule=rule[0]+rule[1].charAt(0).toUpperCase()+rule[1].slice(1);
}
else {
rule=rules_arr[0];
}
styleObj[$.trim(rule)]=rules_arr[1];

}

console.log(styleObj);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="font-size: x-large; color: #ff9900; background-image: url('http://placehold.it/100x100');">Using inline style sheets - or is that inline styles?</div>

Demo (easier for testing of different inline styles): https://jsfiddle.net/n0n4zt3f/2/

P.S. Trimming and camel case are left... can be added, of course...

Upvotes: 0

trincot
trincot

Reputation: 350272

Instead of reading the the style attribute, you could iterate over the style properties. This way you avoid the problems with delimiters that are embedded in style values:

function parseCss(el) {
    function camelize(key) {
        return key.replace(/\-./g, function (m) {
            return m[1].toUpperCase();
        });
    }
    
    var output = {};
    for (var a of el.style) {
        output[camelize(a)] = el.style[a];
    }
    return output;
}
// Demo 
var css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>

This does expand some consolidated styles you can have in the style attribute, such as padding, which splits into paddingLeft, paddingRight, ...etc.

With the use of some more ES6 features the above can be condensed to:

function parseCss(el) {
    let camelize = key => key.replace(/\-./g, m => m[1].toUpperCase());
    return Object.assign(
        ...Array.from(el.style, key => ({[camelize(key)]: el.style[key]})));
}
// Demo 
let css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>

Upvotes: 1

epascarello
epascarello

Reputation: 207511

You might be able to do something like this, it would still fail for some edge cases with content. It is not running your camel case, but that is simple enough to call.

var x = document.getElementById("x");
var str = x.getAttribute("style"); //x.style.cssText;
console.log(str);
var rules = str.split(/\s*;\s*/g).reduce( function (details, val) {
    if (val) {
      var parts = val.match(/^([^:]+)\s*:\s*(.+)/);
      details[parts[1]] = parts[2];
    } 
    return details;
}, {});
console.log(rules);
div {
  font-family: Arial;
}
<div style="color: red; background: yellow; background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;" id="x">test</div>

Upvotes: 1

Related Questions