Peter
Peter

Reputation: 83

Duplicate a CSS rule using JavaScript only

I have a list that is generated elsewhere and I cannot change that. The indent level is via & nbsp;, however the font-size is the same for each indent and I would like to change the font-size based on the indent level. Therefore, I need to duplicate a css rule and change the new id and the font-size.

The following is the HTM generated code, which I cannot change:

<style type="text/css">
   span.text12Font1 { 
       font-size:14px;
       font-family:"Arial", sans-serif;
       color:#010101;
       font-weight:normal;
       font-style:normal;
       text-decoration:normal;
   }
</style>

<div id="text12">
</a>
<ul style="margin-left:4px;text-align:left;" >
    <li>
        <span class="text12Font1">Emphasize the beginning of the bullet point</span>
    </li>
    <li>
        <span class="text12Font1">&nbsp;</span >
        <span class="text12Font1">As in this list, when the first few words capture the main idea</span >
    </li>
    <li>
        <span class="text12Font1">&nbsp;&nbsp;That way, readers can skim easily</span>
    </li>
</ul>
</div>

I can get each point and I can find all of the class names in each point. What I need is the ability to duplicate a css class, give it a new id and just change the font-size.

I have the following so far:

function getNewClassName(className, newName, fSize){
    var spanID = 'span.' + className;
//e.g.: span.text12Font1
    for(var i=0; i<document.styleSheets.length; i++){
        var sheet = document.styleSheets[i];
        var cssText = sheet.ownerNode.innerText;
        var posn = cssText.indexOf(spanID);
        if(posn!=-1){
            var oSheet = document.styleSheets[i];
            var oRules = oSheet.cssRules ? oSheet.cssRules : oSheet.rules;
            for(var r=0; r<oRules.length; r++){
                if(oRules[r].cssText.indexOf(spanID)!=-1){
// Here I have the rule that I want to duplicate, change it's name to newName and change the font-size.
// I must not change the existing rule and it must remain as it could be used elsewhere
                    return true;
                }
            }
        }
    }
    return false;
}

Upvotes: 0

Views: 627

Answers (3)

Peter
Peter

Reputation: 83

I now have the following:

function duplicate_cssRule(passClassID, newClassID, fSize){
    var nClassID = 'span.' + newClassID;
    if(findCSS_Rule(nClassID)) return true;  // Must have already done this one
    var classID = 'span.' + passClassID.split(' ')[0];  // Might have multiple classes, we always want the first
    var ruleObj = findCSS_Rule(classID)
    if(!ruleObj) return false;
    var cssText = ruleObj.cssText ? ruleObj.cssText : ruleObj.style.cssText;
    var posn = cssText.indexOf('{');
    cssText = cssText.substr(posn+1).trim().split(';');
    for(var i=0; i<cssText.length; i++){
        var fontData = cssText[i].toLowerCase().trim();  // IE is uppercase
        if(fontData.substr(0,10)=='font-size:'){
            cssText[i] = 'font-size:' + fSize + 'px';
            break;
        }
    }
    cssText = cssText.join(';');
    cssText = cssText.substr(0,cssText.length-1);
    if( styleSheet.insertRule ){
        cssText = nClassID + ' {' + cssText + '}';
        styleSheet.insertRule(cssText,styleSheet.cssRules.length);
    }else if(styleSheet.addRule){
        styleSheet.addRule(nClassID,cssText);
    }
    return true;
}

var styleSheet;
function findCSS_Rule(classID){
    var sheets = document.styleSheets;
    for(var i=0; i<sheets.length; i++){
        styleSheet = sheets[i];
        var styleRules = styleSheet.cssRules ? styleSheet.cssRules : styleSheet.rules;
        if(styleRules){
            for(var r=0; r<styleRules.length; r++){
                if(styleRules[r].selectorText&&styleRules[r].selectorText.toLowerCase()==classID.toLowerCase()) return styleRules[r];
            }
        }
    }
    return false;
}

Works in all browsers, even IE8.

Upvotes: 0

Gerrit Bertier
Gerrit Bertier

Reputation: 4221

See update at the bottom of this post for a reference to editing CSS through JavaScript

Can you add a CSS class with Javascript to the containing li items. You could count the number of &nbsp; occurences in each li and give the li a CSS class accordingly.

Something like this: http://jsfiddle.net/ncdajzur/

CSS

span.text12Font1 {
    font-size:14px;
    font-family:"Arial", sans-serif;
    color:#010101;
    font-weight:normal;
    font-style:normal;
    text-decoration:normal;
}

.whitespace1 span.text12Font1 {
    font-size: 12px;
}

.whitespace2 span.text12Font1 {
    font-size: 8px;
}

JavaScript (I used jQuery for quick testing purposes)

function formatText(id) {
    var $list = $('#' + id);

    $list.find('li').each(function(i) {
        var numWhitespaces = ($(this).html().match(/&nbsp;/g) || []).length;
        $(this).addClass('whitespace' + numWhitespaces);
    });    
}

formatText('text12');

Update

An extensive explanation of how to manipulate stylesheets through JavaScript is available here: http://www.hunlock.com/blogs/Totally_Pwn_CSS_with_Javascript#quickIDX1

Upvotes: 1

Joshua Bakker
Joshua Bakker

Reputation: 2348

AFAIK, you cannot duplicate a CSS rule with javascript. You can only apply a certain style on an element, but that will be applied within an inline style. So you can either change it by applying to the inline style or try something else.

I only know jquery way of doing that, that's by using $('.className').css('font', 'somefont')

Upvotes: 0

Related Questions