Convert CSS text to JavaScript object - javascript

I have the following text as a JavaScript string
.mybox {
display: block;
width: 20px;
height: 20px;
background-color: rgb(204, 204, 204);
}
I want to convert to a JavaScript Object
var mybox = {
'display': 'block',
'width': '20px',
'height': '20px';
'background-color': 'rgb(204, 204, 204)';
};
Any ideas or already made scripts?

Year 2017 answer
function parseCSSText(cssText) {
var cssTxt = cssText.replace(/\/\*(.|\s)*?\*\//g, " ").replace(/\s+/g, " ");
var style = {}, [,ruleName,rule] = cssTxt.match(/ ?(.*?) ?{([^}]*)}/)||[,,cssTxt];
var cssToJs = s => s.replace(/\W+\w/g, match => match.slice(-1).toUpperCase());
var properties = rule.split(";").map(o => o.split(":").map(x => x && x.trim()));
for (var [property, value] of properties) style[cssToJs(property)] = value;
return {cssText, ruleName, style};
} /* updated 2017-09-28 */
Description
Passing the following cssText (string) to the function:
.mybox {
display: block;
width: 20px;
height: 20px;
background-color: rgb(204, 204, 204);
}
...will give the following object:
{ cssText: ... /* the original string including new lines, tabs and spaces */,
ruleName: ".mybox",
style: {
"": undefined,
display: "block",
width: "20px",
height: "20px",
backgroundColor: "rgb(204, 204, 204)"
}
}
User can also pass a cssText such as:
display: block; width: 20px; height: 20px; background-color: rgb(204, 204, 204);
Features:
Works both with CSSRule.cssText and
CSSStyleDeclaration.cssText.
Converts CSS property names
(background-color) to JS property names (backgroundColor).
It handles even very erratic names,
such as back%gr- -ound---color: red; (converts to backGrOundColor).
Enables mass modification of existing
CSSStyleDeclarations (such as document.body.style) using
a single call
Object.assign(document.body.style, parseCSSText(cssText).style).
Does not fail when a property name comes without a value (an entry
without a colon) nor even vice versa.
Update 2017-09-28: Handles new lines also in rule names,
collapses white spaces.
Update 2017-09-28: Handles comments (/*...*/).
Quirks:
If the last CSS declaration in the rule ends with a semicolon,
returned style will include a property with an empty name "" and
an undefined value reflecting the null string following the
semicolon. I consider it a correct behaviour.
The function will return a faulty result if property value (string literal)
includes colon or semicolon or CSS comments, for example
div::before {content: 'test:test2;/*test3*/';}. I don’t know
how to avoid this.
At the moment, it converts property names with prefixes
such as -somebrowser-someproperty incorrectly to SomebrowserSomeproperty
instead of somebrowserSomeproperty. I want a remedy that won’t ruin
the brevity of code, therefore I’ll take time to find one.
Live example
function parseCSSText(cssText) {
var cssTxt = cssText.replace(/\/\*(.|\s)*?\*\//g, " ").replace(/\s+/g, " ");
var style = {}, [,ruleName,rule] = cssTxt.match(/ ?(.*?) ?{([^}]*)}/)||[,,cssTxt];
var cssToJs = s => s.replace(/\W+\w/g, match => match.slice(-1).toUpperCase());
var properties = rule.split(";").map(o => o.split(":").map(x => x && x.trim()));
for (var [property, value] of properties) style[cssToJs(property)] = value;
return {cssText, ruleName, style};
} /* updated 2017-09-28 */
Example:
var sty = document.getElementById("mystyle");
var out = document.getElementById("outcome");
var styRule = parseCSSText(sty.innerHTML);
var outRule = parseCSSText(out.style.cssText);
out.innerHTML =
"<b>⦁ CSS in #mystyle</b>: " + JSON.stringify(styRule) + "<br>" +
"<b>⦁ CSS of #outcome</b>: " + JSON.stringify(outRule);
console.log(styRule, outRule); /* Inspect result in the console. */
<style id="mystyle">
.mybox1, /* a comment
and new lines
to step up the game */
.mybox
{
display: block;
width: 20px; height: 20px;
background-color: /* a comment
and a new line */
rgb(204, 204, 204);
-somebrowser-someproperty: somevalue;
}
</style>
<div id="outcome" style="
display: block; padding: 0.5em;
background-color: rgb(144, 224, 224);
">...</div>
<b style="color: red;">Also inspect the browser console.</b>

This is the beginning of a parser that may do what you want. Of course it needs work, especially if you want to handle any generic css that may be provided. This assumes that input css is written as you provided, with the first row being the name of the property, the last row being a '}' and so on.
If you don't want to handle only basic properties, writing a complex parser is not an easy task. For example, what if you declare something like:
input[type="text"],
table > tr:nth-child(2),
#link a:hover {
-webkit-transition: width 2s; /* Safari and Chrome */
}
This is valid css, but how would you extract a valid javascript variable name from it? How to convert -webkit-transition into a meaningful property name? The whole task smells like you're doing it all wrong. Instead of working on a parser, I'd work on a more stable solution at all.
By the way, here is the code you may start from:
var s = '.mybox {\n';
s += 'display: block;\n';
s += 'width: 20px;\n';
s += 'height: 20px;\n';
s += 'background-color: rgb(204, 204, 204);\n';
s += '}\n';
// split css by line
var css_rows = s.split('\n');
// filter out empty elements and strip ';'
css_rows = css_rows.filter(function(x){ return x != '' }).map(function(x){ return x.trim().replace(';', '') });
// create object
var json_name = css_rows[0].trim().replace(/[\.\{\ \#]/g, '');
eval('var ' + json_name + ' = {};');
// remove first and last element
css_rows = css_rows.splice(1, css_rows.length-2)
for (elem in css_rows)
{
var elem_parts = css_rows[elem].split(':');
var property_name = elem_parts[0].trim().replace('-', '');
var property_value = elem_parts[1].trim();
eval(json_name + '.' + property_name + ' = "' + property_value + '";');
}

If the CSS document is included in the html document, so that the style declarations are actually loaded, you can step through all styles in Javascript like this:
// Get all style sheet documents in this html document
var allSheets = document.styleSheets;
for (var i = 0; i < allSheets.length; ++i) {
var sheet = allSheets[i];
// Get all CSS rules in the current style sheet document
var rules = sheet.cssRules || sheet.rules;
for (var j = 0; j < rules.length; ++j) {
var rule = rules[j];
// Get the selector definition ("div > p:first-child" for example)
var selector = rule.selectorText;
// Create an empty object to put the style definitions in
var result = {};
var style = rule.style;
for (var key in style) {
if (style.hasOwnProperty(key)) {
result[key] = style.cssText;
}
}
// At this point, you have the selector in the
// selector variable (".mybox" for example)
// You also have a javascript object in the
// result variable, containing what you need.
// If you need to output this as json, there
// are several options for this.
}
}
If this is not what you want, like if you want to parse a CSS document and create a JavaScript source file, you need to look into lexical parsers, CSS document object models, JSON serialization, and stuff like that...

I have the same issue working with LeafLet trying to separate CSS styles from JavaScript code... I end up with this:
var css = {};
for (var i = 0; i < document.styleSheets.length; ++i) {
var sheet = document.styleSheets[i];
for (var j = 0; j < sheet.cssRules.length; ++j) {
var rule = sheet.cssRules[j];
var cssText = rule.cssText.slice(rule.cssText.indexOf('{')+1);
var attrs = cssText.split(';');
var ruleSet = {};
for (var k = 0; k < attrs.length; ++k) {
var keyValue = attrs[k].split(':');
if (keyValue.length == 2) {
var key = keyValue[0].trim();
var value = keyValue[1].trim();
ruleSet[key] = value;
}
}
for (var testRule in ruleSet) { // We are going to add the rule iff it is not an empty object
css[rule.selectorText] = ruleSet;
break;
}
}
}
console.log(css);
This will produce something like this:

Related

Dynamically append the element through JavaScript Dom

Hers's question which I need answer
Exercises: Level 1
Question 1
I tried to append the child dynamically and get the result vertical not in the compact manner as you will see in the question output when you go to the link
let hh = document.querySelector('h1')
hh.style.textAlign = 'center'
let hh1 = document.querySelector('h2')
hh1.style.textAlign = 'center'
let hh2 = document.querySelector('h3')
hh2.style.textAlign = 'center'
for (i = 0; i <= 100; i++) {
let p1 = document.createElement('div');
{
if (i % 2 == 0) {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.style.backgroundColor = '#91E537'
p1.textContent = i;
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
} else {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.textContent = i;
p1.style.backgroundColor = '#E5D037'
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
}
}
if (i >= 2) {
let flag = 0;
for (j = 2; j <= i / 2; j++) {
if (i % j == 0) {
flag = 1;
break;
}
}
if (flag == 0) {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.style.backgroundColor = '#E55137'
p1.textContent = i;
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
}
}
}
<h1>Number Generator</h1>
<h2>30 days of JavaScript</h2>
<h3>Author:ABC</h3>
<div class="container"></div>
You can see the code of both HTML and javascript above!!!
Do help with the code where I can easily append the data, and don't use box elements I need simple code for this.
I tried to do it with a few HTML styles but it didn't help me, also using insert-adjacent text also didn't work.
Try to make changes only on javascript code, not HTML,if it's possible else make minimum changes on HTML
I am using HTML5 AND CSS3
Rather than adding lots of inline style attributes to all the generate elements some simple CSS can be applied to the parent (container) and thus the children and then use Javascript to assign the classes to the elements based upon the given criteria of odd/even & prime. The comments throughout the code ought to help
// helper function to create basic DOM element with attributes
const node=( type='div', attr={} )=>{
let n = document.createElement(type);
Object.keys( attr ).forEach( a=>n.setAttribute( a, attr[a] ) );
return n;
};
// utility to test if a number is a "Prime Number"
const isprime=( n=0 )=>{
for( let i = 2; i < n; i++ ) {
if( n % i === 0 ) return false;
}
return n > 1;
};
// generate between these numbers
const iStart=1;
const iEnd=100;
// HTML container
const results = document.querySelector('#results');
// iterate through number range and add new DIV for each number
for( let i = iStart; i<=iEnd; i++ ) {
// calculate the className to assign
let cn=i % 2 === 0 ? 'even' : 'odd';
if( isprime( i ) ) cn='prime';
// create the DIV
let div=node( 'div', { 'class':cn, 'data-id':i } );
// append to output container
results.appendChild( div );
}
// generate Page headers before results / output
let headers={
h1:'Number Generator',
h2:'30 days of Javascript',
h3:'Geronimo Bogtrotter III'
};
// iterate over the keys/properties of the object and create
// a new header for each using the value assigned within the object.
Object.keys( headers ).forEach( prop=>{
let n=node( prop );
n.textContent=headers[ prop ];
// add the new header before the numbers grid
document.body.insertBefore( n, results );
});
/*
Some simple variables to help with layout.
Change here to modify displayed grid.
*/
:root{
--width:600px;
--m:0.25rem;
--r:0.35rem;
--wh:calc( calc( var( --width ) / 5 ) - calc( var( --m ) * 4 ) );
}
body{
font-family:monospace;
padding:0;
margin:0;
}
#results {
width: var(--width);
min-height: var(--width);
float: none;
margin: 1rem auto;
font-family:fantasy;
}
#results > div {
width: var( --wh );
height: var( --wh );
border: 1px solid black;
border-radius:var(--r);
margin: var(--m);
display: inline-block;
cursor:pointer;
}
/*
Use the pseudo element :after to
display the number of the square.
This uses the `data-id` attribute
assigned within Javascript.
*/
#results>div:after {
display:flex;
flex-direction:column;
justify-content:center;
align-content:center;
align-items:center;
flex:1;
margin:auto;
content: attr(data-id);
color:black;
text-shadow:0 0 15px rgba(255,255,255,1);
height:100px;
}
/*
modify the display for certain colours
to aid clarity
*/
#results>div.odd:after{
text-shadow:0 0 15px rgba(0,0,0,1);
}
#results>div.prime:after{
text-shadow:0 0 15px rgba(0,0,0,1);
color:white;
}
/*
The basic 3 colours to suit the odd/even/prime
status of each square.
*/
.even {
background: green;
}
.odd {
background: yellow
}
.prime {
background: red
}
h1,h2,h3{
text-align:center;
}
<div id='results'></div>
The idea here is to create a container for all of the blocks and set the display style attribute of this container to flex, style.flewrap to wrap and you can control how many blocks you want per line using style.width attribute.
After creating this element you would want to append to it your dynamically created blocks like p2.appendchild(p1);
Here is the code :
let p2 = document.createElement('div');
p2.className= 'p2';
p2.style.display = 'flex';
p2.style.flexwrap = 'wrap';
p2.style.width = '800px'
for (i = 0; i <= 101; i++) {
...
for every document.body.append(p1); --> p2.append(p1);
...
}
document.body.appendChild(p2);

Combine the properties of two CSS classes with a filter attribute

To sum up the effects of the filter property we have to do as for this 'union class.'
.class1{filter:brightness(125%);}
.class2{filter:blur(5px);}
.unionClass{filter:brightness(125%) blur(5px);}
But what if the code is written this way?
//i want this
<p class="class1 class2">Hello</p>
//instead of
<p class="unionClass">Hello</p>
In the first example as a result we would only apply the class2 class, so filter class1 class property will be lost; While in the second the 'unionClass' class will display all the united properties, as they are already contained in it.
I would like to see the same effect by writing 'class = "class1 class2' ', how can i do it? Does css not have a right way? So with javascript what would be the right way?
That is not possible to do using CSS.
When splitt'd like that, the latter will overwrite the former, as it will with any other property.
From a maintenance and easy-to-read perspective it could be interesting to do something like this
.fil-bright-125 {
filter:brightness(125%);
}
.fil-blur-5 {
filter:blur(5px);
}
.fil-bright-125.fil-blur-5 {
filter:brightness(125%) blur(5px);
}
And then use it like this
p {
color: blue;
background: yellow;
}
.fil-bright-175 {
filter:brightness(175%);
}
.fil-blur-1 {
filter:blur(1px);
}
.fil-bright-175.fil-blur-1 {
filter:brightness(175%) blur(1px);
}
<p class="fil-bright-175">I am bright</p>
<p class="fil-blur-1">I am blurry</p>
<p class="fil-bright-175 fil-blur-1">I am bright and blurry</p>
Updated
For completeness, here is a version using script, which look up the classes in the style sheet and then creates a new, where they are combined.
Compared with the above, I don't find the below more maintainable, almost the opposite actually.
Note, this script can of course be optimized, though the purpose was to show a sample of how it could be done using script
(function(d, w) {
w.addEventListener("load", function() {
function getStyle(cls) {
var classes = d.styleSheets[0].rules || d.styleSheets[0].cssRules;
var val = '';
for (var x = 0; x < classes.length; x++) {
for (var y = 0; y < cls.length; y++) {
if (classes[x].selectorText == cls[y]) {
val += ' ' + ((classes[x].cssText) ? classes[x].cssText : classes[x].style.cssText).split('filter')[1].replace(/[:;} ]/g, '');
}
}
}
return val;
}
var val = getStyle(['.fil-bright-175','.fil-blur-1']);
val = '.fil-bright-175.fil-blur-1 {filter:' + val + '}';
var head = d.head || d.getElementsByTagName('head')[0],
style = d.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = val;
} else {
style.appendChild(d.createTextNode(val));
}
head.appendChild(style);
}, false);
}(document, window));
p {
color: blue;
background: yellow;
}
.fil-bright-175 {
filter: brightness(175%);
}
.fil-blur-1 {
filter: blur(1px);
}
<p class="fil-bright-175">I am bright</p>
<p class="fil-blur-1">I am blurry</p>
<p class="fil-bright-175 fil-blur-1">I am bright and blurry</p>

CSSRules group selectors with common properties

This script when included in an HTML document which includes any declared styles (excluding those set by style="") will output an optimized stylesheet to the to the page. The script uses the following methods...
Ignore any # or : rules to leave responsive styles as is.
Separate the rules into single selector rules so we can test for inheritance later on.
Remove rules that apply to selectors which don't exist in the document, thanks to #RickHitchcock for this.
Retrieve both the declared and computed styles in the same format (excluding percentages) then compare both values each other, then remove the property and check again.
if the declared value matches the computed value and by removing the property the value changes, then set the keep flag. This tells us whether the property has an effect on an element, if no elements were affected by the property... remove it.
If there are no properties in the remaining CSSRule then remove that rule.
As a side effect most selectors which don't change the browsers default setting will be removed (unless using font as opposed to font-* and similar which will activate the rest of the settings for that property).
While running this script on a site which includes styles relating to dynamic elements, I just wrap them in a media query
#media (min-width: 0px) {
/* This says that these styles always apply */
}
Question
How can I group the selectors with common properties?
(Demo)
var stylesheets = document.styleSheets, stylesheet, i;
var ruleText = "";
if(stylesheets && stylesheets.length) {
for (i = 0; (stylesheet = stylesheets[i]); i++) {
var rules = stylesheet.rules, rule, j;
if(rules && rules.length) {
for (j = 0; (rule = rules[j]); j++) {
if(rule.type === rule.STYLE_RULE) {
if(rule.selectorText.indexOf(',') >= 0) {
var newRules = [];
var selectors = rule.selectorText.split(','), selector, k;
for(k = 0; (selector = selectors[k]); k++) {
var styles = rule.style, style, l;
var elements = document.querySelectorAll(selector.trim()), element, l;
if(elements.length) {
var styleString = '';
for(m = 0; (style = styles[m]); m++) {
styleString += style + ': ' + styles.getPropertyValue(style) + "; ";
}
newRules.push((selector.trim() + ' { ' + styleString.trim() + ' }'));
}
}
stylesheet.deleteRule(j);
for(k = 0; (rule = newRules[k]); k++) {
stylesheet.insertRule(rule, j);
}
}
}
}
for (j = 0; (rule = rules[j]); j++) {
if(rule.type === rule.STYLE_RULE && rule.selectorText.indexOf(':') < 0) {
var styles = rule.style, style, k;
var elements = document.querySelectorAll(rule.selectorText);
if(elements && elements.length) {
for(k = 0; (style = styles[k]); k++) {
var value = styles.getPropertyValue(style);
if(value.indexOf('%') < 0) {
var elements = document.querySelectorAll(rule.selectorText), element, m;
var keep = false;
for(m = 0; (element = elements[m]); m++) {
var computed = window.getComputedStyle(element).getPropertyValue(style);
var match1 = value === computed;
styles.removeProperty(style);
var computed = window.getComputedStyle(element).getPropertyValue(style);
var match2 = value === computed;
styles.setProperty(style, value);
if( match1 && !match2 ) {
keep = true;
}
}
if(!keep) {
styles.removeProperty(style);
}
}
}
ruleText += rule.cssText + "\n";
}
} else {
ruleText += rule.cssText + "\n";
}
}
}
}
}
document.body.innerHTML = '<pre>' + ruleText + '<pre>';
Future viewers: this is available on github as optiCSS (read: eye-pleasing)
This looks great, and I have only a minor suggestion.
Change your code as follows:
for (j = 0; rule = rules[j]; j++) {
var styles = rule.style, style, k;
var elements = document.querySelectorAll(rule.selectorText);
if(elements.length) {
for(k = 0; style = styles[k]; k++) {
...
}
console.log(rule.cssText);
}
}
This will prevent the output of rules that don't have any matching HTML.
In this Fiddle, the li rule is output with your code, but it's not output with the above modification.
The next challenge is to simplify those font, border, padding, … styles.
Based on your Edit #25, you're left with a string that looks like this:
html { margin-right: 0px; margin-left: 0px; height: 100%; }
body { margin-right: 0px; margin-left: 0px; height: 100%; margin-top: 0px; }
body { margin-bottom: 5px; background-color: rgb(255, 0, 0); }
#media (max-width: 500px) {
body { background: blue; }
}
Here's how to turn it into this:
html {margin-right:0px;margin-left:0px;height:100%;}
body {margin-right:0px;margin-left:0px;height:100%;margin-top:0px;margin-bottom:5px;background-color:rgb(255 0 0);}
#media (max-width: 500px) {
body { background: blue; }
}
In the process, you'll get two objects:
html {"margin-right":"0px;","margin-left":"0px;","height":"100%;"}
body {"margin-right":"0px;","margin-left":"0px;","height":"100%;","margin-top":"0px;","margin-bottom":"5px;","background-color":"rgb(255, 0, 0);"}
First, keep your media query output separate since you don't want it to be affected:
var ruleText = "", mediaText = "";
...
if (styles.length) {
ruleText += rule.cssText + "\n";
}
} else {
mediaText += rule.cssText + "\n";
}
Then place this after your loop:
var inp= ruleText.split('\n'),
out= '',
selectors= {};
inp.forEach(function(val) {
if(val) {
var selector= val.split(/ *{/)[0],
styles= val.split(/{ */)[1].split('}')[0].split(/; */);
selectors[selector]= selectors[selector] || {};
styles.forEach(function(val) {
if(val) {
var st= val.split(/ *: */);
selectors[selector][st[0]]= st[1]+';';
}
});
}
});
for(var i in selectors) {
out+= i+' '+JSON.stringify(selectors[i]).replace(/[,"]/g,'')+'\n';
}
document.body.innerHTML= '<pre>'+out+mediaText+'</pre>';
For simplicity, the code above assumes there is no string content in the CSS that contains double quotes, semicolons, commas, or curly braces. That would complicate things somewhat.
Fiddle

Get only the ellipsis text using jquery

Nice code, just wondered if it is possible to query and get the ellipsis text (i.e. with the dots in and not the original text)?
If I add the text
This is a long sentence
and (using the relevant css for ellipsis) it gets shortened to
This is a long sen ...
Is there a way to get the text
"This is a long sen ..."
from the $("p") DOM object rather than the original text?
Try that:
function getEllipsis(command, characters) {
for (var i = command.length; i >= 0; i--) {
if (command.substring(0, i).length < characters) {
if (i < command.length) {
command = command.substring(0, i) + "...";
}
return command;
}
}
}
console.log(getEllipsis("I am a long sentence",16))
console.log(getEllipsis("But I am even longer",20))
I have a rough draft that needs some browser-specific tweaking.
JavaScript:
jQuery.fn.getShowingText = function () {
// Add temporary element for measuring character widths
$('body').append('<div id="Test" style="padding:0;border:0;height:auto;width:auto;position:absolute;display:none;"></div>');
var longString = $(this).text();
var eleWidth = $(this).innerWidth();
var totalWidth = 0;
var totalString = '';
var finished = false;
var ellipWidth = $('#Test').html('…').innerWidth();
var offset = 7; // seems to differ based on browser (6 for Chrome and 7 for Firefox?)
for (var i = 0;
(i < longString.length) && ((totalWidth) < (eleWidth-offset)); i++) {
$('#Test').text(longString.charAt(i));
totalWidth += $('#Test').innerWidth();
totalString += longString.charAt(i);
if(i+1 === longString.length)
{
finished = true;
}
}
$('body').remove('#Test'); // Clean up temporary element
if(finished === false)
{
return totalString.substring(0,totalString.length-3)+"…";
}
else
{
return longString;
}
}
console.log($('#ellDiv').getShowingText());
CSS:
#Test {
padding:0;
border:0;
height: auto;
width: auto;
position:absolute;
white-space: pre;
}
div {
width: 100px;
white-space: nowrap;
border: 1px solid #000;
overflow:hidden;
text-overflow:ellipsis;
padding:0;
}
With the caveat that the offset needs to change depending on the browser, unless someone can figure out what is causing it.
I suspect letter-spacing or similar?

jQuery - How to get all styles/css (defined within internal/external document) with HTML of an element

I know that $("#divId").html() will give me innerHtml. I also need its styles (which might be defined by the means of classes) either in-line style attribute or all the styles/classes within a separate <style> tag.
Is it possible?
UPDATE
What if html is like <div id="testDiv">cfwcvb</div> and a css class for #testDiv is defined in external stylesheet?
UPDATE 2
Sorry for not clarifying this earlier
If this is my HTML
<div id="divId">
<span class="someClass">Some innerText</span>
</div>
And styles are defined in separate style sheet or in head styles.
#divId {
clear: both;
padding: 3px;
border: 2px dotted #CCC;
font-size: 107%;
line-height: 130%;
width: 660px;
}
.someClass {
color: blue;
}
Then when I try to get inner html of $("#divId").html() or call any other custom function, I need something like below
<style>
#divId {
clear: both;
padding: 3px;
border: 2px dotted #CCC;
font-size: 107%;
line-height: 130%;
width: 660px;
}
.someClass {
color: blue;
}
</style>
<div id="divId">
<span class="someClass">Some innerText</span>
</div>
UPDATE 3 for Answer by kirilloid
I ran below code in Command Window of Chrome Debugger tools for this page itself and this is what I see TypeError: Cannot read property 'rules' of undefined
function getElementChildrenAndStyles(selector) {
var html = $(selector).get(0).outerHTML;
selector = selector.split(",").map(function(subselector){
return subselector + "," + subselector + " *";
}).join(",");
elts = $(selector);
var rulesUsed = [];
// main part: walking through all declared style rules
// and checking, whether it is applied to some element
sheets = document.styleSheets;
for(var c = 0; c < sheets.length; c++) {
var rules = sheets[i].rules || sheets[i].cssRules;
for(var r = 0; r < rules.length; r++) {
var selectorText = rules[r].selectorText;
var matchedElts = $(selectorText);
for (var i = 0; i < elts.length; i++) {
if (matchedElts.index(elts[i]) != -1) {
rulesUsed.push(CSSrule); break;
}
}
}
}
var style = rulesUsed.map(function(cssRule){
if ($.browser.msie) {
var cssText = cssRule.style.cssText.toLowerCase();
} else {
var cssText = cssRule.cssText;
}
// some beautifying of css
return cssText.replace(/(\{|;)\s+/g, "\$1\n ").replace(/\A\s+}/, "}");
// set indent for css here ^
}).join("\n");
return "<style>\n" + style + "\n</style>\n\n" + html;
};
getElementChildrenAndStyles(".post-text:first");
outerHTML (not sure, you need it — just in case)
Limitations: CSSOM is used and stylesheets should be from the same origin.
function getElementChildrenAndStyles(selector) {
var html = $(selector).outerHTML();
selector = selector.split(",").map(function(subselector){
return subselector + "," + subselector + " *";
}).join(",");
elts = $(selector);
var rulesUsed = [];
// main part: walking through all declared style rules
// and checking, whether it is applied to some element
sheets = document.styleSheets;
for(var c = 0; c < sheets.length; c++) {
var rules = sheets[c].rules || sheets[c].cssRules;
for(var r = 0; r < rules.length; r++) {
var selectorText = rules[r].selectorText;
var matchedElts = $(selectorText);
for (var i = 0; i < elts.length; i++) {
if (matchedElts.index(elts[i]) != -1) {
rulesUsed.push(rules[r]); break;
}
}
}
}
var style = rulesUsed.map(function(cssRule){
if (cssRule.style) {
var cssText = cssRule.style.cssText.toLowerCase();
} else {
var cssText = cssRule.cssText;
}
// some beautifying of css
return cssText.replace(/(\{|;)\s+/g, "\$1\n ").replace(/\A\s+}/, "}");
// set indent for css here ^
}).join("\n");
return "<style>\n" + style + "\n</style>\n\n" + html;
}
usage:
getElementChildrenAndStyles("#divId");
No jQuery and no IE support, that's all I can do:
<!doctype html>
<html>
<head>
<meta charset = "utf-8">
<script type = "text/javascript">
Element.prototype.getStyles = function () {
var array = {};
var styles = window.getComputedStyle (this, null);
for (var i = 0; i < styles.length; i ++) {
var style = styles[i];
array[style] = styles[style];
}
return array; // return new Array (array, this.innerHTML); You can also return the HTMl content. I don't think its necessary
}
window.addEventListener ("load", function () {
var divId = document.getElementById ("divId");
var someClass = document.getElementsByClassName ("someClass");
var string = "";
var styles = divId.getStyles ();
for (var i in styles) {
string += i + ": " + styles[i] + "\n";
}
alert (string);
alert ("In-line style: Height ->" + styles["height"] + "\n" + "Out-line style: Width ->" + styles["width"])
alert ("HTML: " + divId.innerHTML);
// Same thing with the span element
}, false);
</script>
<style>
#divId {
clear: both;
padding: 3px;
border: 2px dotted #CCC;
font-size: 107%;
line-height: 130%;
width: 660px;
}
.someClass {
color: blue;
}
</style>
<title>Test</title>
</head>
<body>
<div id = "divId" style = "height: 100px">
<span class = "someClass">Some innerText</span>
</div>
</body>
</html>
You can get hold of a style object representing the computed style for an element using window.getComputedStyle() in most browsers and the element's currentStyle property in IE. There are several browser differences, however, with values returned for shortcut properties (such as background), color RGB values, lengths and even font-weight (see this useful test page). Test carefully.
function computedStyle(el) {
return el.currentStyle || window.getComputedStyle(el, null);
}
alert(computedStyle(document.body).color);
You can use something like this for script:-
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.js"></script>
<script type="text/javascript">
$(function(){
var styleVal = $('#testDiv').attr('style');
console.warn("styleVal >>> " + styleVal);
})
</script>
and simple html would be like this
<div style="border:1px solid red;" id="testDiv">cfwcvb</div>
if you want to save all of the style of an element i think this will be more complicated as you think
first of all my first ide was the firebug css console. this shows all fo the style of an element and i thought how?
so i searched for the source code of the firebug and i found this:
http://fbug.googlecode.com/svn/branches/firebug1.7/content/firebug/css.js
this code working only on the css part.
const styleGroups =
{
text: [
"font-family",
"font-size",
"font-weight",
"font-style",
"color",
"text-transform",
"text-decoration",
"letter-spacing",
"word-spacing",
"line-height",
"text-align",
"vertical-align",
"direction",
"column-count",
"column-gap",
"column-width"
],
background: [
"background-color",
"background-image",
"background-repeat",
"background-position",
"background-attachment",
"opacity"
],
box: [
"width",
"height",
"top",
"right",
"bottom",
"left",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"border-top-width",
"border-right-width",
"border-bottom-width",
"border-left-width",
"border-top-color",
"border-right-color",
"border-bottom-color",
"border-left-color",
"border-top-style",
"border-right-style",
"border-bottom-style",
"border-left-style",
"-moz-border-top-radius",
"-moz-border-right-radius",
"-moz-border-bottom-radius",
"-moz-border-left-radius",
"outline-top-width",
"outline-right-width",
"outline-bottom-width",
"outline-left-width",
"outline-top-color",
"outline-right-color",
"outline-bottom-color",
"outline-left-color",
"outline-top-style",
"outline-right-style",
"outline-bottom-style",
"outline-left-style"
],
layout: [
"position",
"display",
"visibility",
"z-index",
"overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow
"overflow-y",
"overflow-clip",
"white-space",
"clip",
"float",
"clear",
"-moz-box-sizing"
],
other: [
"cursor",
"list-style-image",
"list-style-position",
"list-style-type",
"marker-offset",
"user-focus",
"user-select",
"user-modify",
"user-input"
]
};
the function which gets all of the styles.
updateComputedView: function(element)
{
var win = element.ownerDocument.defaultView;
var style = win.getComputedStyle(element, "");
var groups = [];
for (var groupName in styleGroups)
{
var title = $STR("StyleGroup-" + groupName);
var group = {title: title, props: []};
groups.push(group);
var props = styleGroups[groupName];
for (var i = 0; i < props.length; ++i)
{
var propName = props[i];
var propValue = stripUnits(rgbToHex(style.getPropertyValue(propName)));
if (propValue)
group.props.push({name: propName, value: propValue});
}
}
var result = this.template.computedTag.replace({groups: groups}, this.panelNode);
dispatch(this.fbListeners, 'onCSSRulesAdded', [this, result]);
}
function stripUnits(value)
{
// remove units from '0px', '0em' etc. leave non-zero units in-tact.
return value.replace(/(url\(.*?\)|[^0]\S*\s*)|0(%|em|ex|px|in|cm|mm|pt|pc)(\s|$)/gi, function(_, skip, remove, whitespace) {
return skip || ('0' + whitespace);
});
}
in this code i figured out that the
win.getComputedStyle(element, "")
to get all of the styles of an element, and then with a for loop gets all of the style and prints out. so i think the getComputedSTyle is the main function to use, and after this you can get the props one by one with:
style.getPropertyValue(propName)
Based on kirilloid's answer, I've created a developer tools extension for Chrome that incorporates that code for capturing styles and markup for a page fragment. The extension is in the Chrome Web Store and is on Github. All of the "Author Styles" output options use that method for iterating over the stylesheets.
The .css() method gets a particular style of the element... I don't know if you can retrieve all styles:
http://api.jquery.com/css/
Generally you can access style parameter using .attr('style'). If you want to access computed style you can use window.getComputedStyle(element) in Opera, Firefox, Chrome and other sane browsers. For IE you'd do the same with element.currentStyle.
Also if you wish to access individual CSS style you can do so with jQuery .css method. Like so $("#divId").css('font-size').
You can get the stylesheet defined inside style tags under document.styleSheets. You can read the rules into a map, and find them by selectorText. So by id: "#id", by classes: ".className". By safari or chrome you can use getMatchedCSSRules.

Categories

Resources