John Boe
John Boe

Reputation: 3611

How to find out if style is present in a class by Jquery?

I tried to google out "jquery function to return object with css properties of the class" but I did not found valuable results.

Let's suppose in a DOM I have a div node with className = "A B C". I have valid Jquery object called "search" which contains html element. I need to find out if it contains some styles and values and in case that they I found I will perform an action (remove the class from node.className)

var search = $("div.A");
var css_arr = search.prop("className").split(" ");

Here are conditions for the styles to be tested:

float != "none" or Float != "" -> if yes, remove the class
position != "absolute" or position != "" -> if yes, remove the class
left is present ... remove the class -> if yes, remove the class
top is present ... remove the class -> if yes, remove the class

My questions are how to perform the test?

Is there function in JQuery to return object with css properties of specified class?

Live example: http://kod.djpw.cz/gwac

Edit: I have started to work in the code based on reading of sheet object.

cssList = function(node) {
    var sheets = document.styleSheets, o = {};
    var sheet;
    for (var i in sheets) {
      if ( sheets[i].hasOwnProperty('cssRules') )
        sheet = sheets[i].cssRules;
      else
      if ( sheets[i].hasOwnProperty('rules') )
        sheet = sheets[i].rules;
      else
        continue;

      var rules = sheets[i].rules || sheets[i].cssRules;
      for (var r in rules) {
          if (node.is(rules[r].selectorText)) 
            {
              o = $.extend(o, make_it_easy.easy.css2json(rules[r].style), css2json(node.attr('style')));
            }
        }  

    }
    return o;
}

Problem here: sheets[i].hasOwnProperty('cssRules') or sheets[i].hasOwnProperty('rules') always returns false. Why? In debugger I see the cssRules property but I cannot check if it exists.

Upvotes: 2

Views: 399

Answers (3)

John Boe
John Boe

Reputation: 3611

Based on the scobaljic advice I have made this code. scobaljic code contained some mistakes which I have corrected. And my goal was not to look for nested elements. I have also added a function to check for ids. The key thing here is backup of the inline styles, to remove them from element before comparison and restore them after comparison. I am still debugging the code, so it may change in the future to fix bugs.

/* Remove classes and ids with unwanted styles */
$.fn.extend({
removeClassWithStyles: function(properties, collectWidthAndPadding = false) 
  {
  paddingAttribs = ["padding", "padding-left", "padding-right"];
  widthAttribs = ["width", "max-width"];
  heightAttribs = ["height", "max-height"];

  function checkObjectProp( obj, element )
  {
    return ( obj.prop == "float" && obj.exclude 
       && 
       (
       obj.exclude == element.css( obj.prop ) 
       )
     ) ? true : false;
  }

  function remove_attr( properties, element, backupObj )
  {
  backupObj;
  for (var p in properties)
    {
    if ( typeof properties[p] === 'object' )
      {
      backupObj.attr.push(properties[p].prop);      
      backupObj.val.push( element.css(properties[p].prop) );
      element.css(properties[p].prop,"");
      }
    else
      {      
      backupObj.attr.push(properties[p]);      
      backupObj.val.push( element.css(properties[p]) );
      element.css(properties[p],"");
      }
    }
  }

  function restore_attr( properties, element, backupObj )
  {
  for (var p in backupObj.attr)
     element.css(backupObj.attr[p], backupObj.val[p]);
  backupObj = { attr: [], val: [] } // reset
  }

  /*
  To detect classes rules and ids rules
  I need to create copy of the original
  element or to backup the inline styles.
  I choosed to backup the inline styles
  because it is faster then clone.
  After I inline styles, I will create 
  clone of the element and compare the
  styles with the modified element.
  Then I restore the styles.
  */
  function filterClasses(element, className, id) 
  {
  if ( className )
    {
    var class_contains_width = false;
    var class_contains_height = false;
    element.css("position", "relative");    
    element.css("float", "left");

    $.each( className.split(/\s+/),
      function(c, className) 
      {
      /* 
      Find out if current class 
      contains the style
      */
      var cloned = $(element).clone();


      // remove class
      cloned.removeClass(className);

      /* Detect padding in element or clone */
      if ( collectWidthAndPadding && cloned.checkPropertiesPresent(element, paddingAttribs) )
        search_padding_collection_classes = search_padding_collection_classes.add(element);            
      /* Detect if width/height could be removed with a class
         + prevent from calling multiple times
         */
      if ( collectWidthAndPadding && !class_contains_width && search_width_classes && cloned.checkPropertiesPresent(element, widthAttribs) )
        search_width_classes = search_width_classes.add(element);
      // div#BlogArchive1 div.widget-content

      $.each(properties, function(p, prop) 
        {
        /* Then remove classes */
        if ( typeof prop === 'object' )
          {
          // A) The style has been inserted
          if ( element.css(prop.prop) != cloned.css(prop.prop) )
            {
            if ( checkObjectProp( prop, cloned ) )
              { // skip it
              }
            else
              {
              // element.removeClass(className);
              return false;
              }              
            }
          else // B) The style has not been inserted
            {
            if (element.css(prop))
              if ( checkObjectProp( prop, element ) )
                { // skip it
                }
              else
                {
                // element.removeClass(className);
                return false;
                }              
            }
          }
        else // prop is not object
          {
          // A) The style has been inserted
          // element.css("right") != cloned.css("right")
          if (element.css(prop) != cloned.css(prop))
            {
            // element.removeClass(className);
            return false;
            }
          else // B) The style has not been inserted
            {
            if (element.css(prop))
              {
              // element.removeClass(className);
              return false;
              }
            }
          }
        });
      });
    };
  };
  function filterIds(element, className, id) 
  {
  if ( id )
    {
    /* 
    Find out if current id 
    contains the style
    */
    var cloned = $(element).clone();
    // remove id    
    cloned.removeAttr("id");

    /* Detect padding in element or clone */
    if ( collectWidthAndPadding && cloned.checkPropertiesPresent(element, paddingAttribs) )
      search_padding_collection_classes = search_padding_collection_classes.add(element);            
    /* Detect if width/height could be removed with a class
       + prevent from calling multiple times
       */
    if ( collectWidthAndPadding && search_width_ids && cloned.checkPropertiesPresent(element, widthAttribs) )
      search_width_ids = search_width_ids.add(element);
    // div#BlogArchive1 div.widget-content

    $.each(properties, function(p, prop) 
      {
      /* Then remove classes */
      if ( typeof prop === 'object' )
        {
        // A) The style has been inserted
        if ( element.css(prop.prop) != cloned.css(prop.prop) )
          {
          if ( checkObjectProp( prop, cloned ) )
            { // skip it
            }
          else
            {
            // element.removeAttr("id");
            return false;
            }              
          }
        else // B) The style has not been inserted
          {
          if (element.css(prop))
            if ( checkObjectProp( prop, element ) )
              { // skip it
              }
            else
              {
              // element.removeAttr("id");
              return false;
              }              
          }
        }
      else // prop is not object
        {
        // A) The style has been inserted
        // element.css("right") != cloned.css("right")
        if (element.css(prop) != cloned.css(prop))
          {
          // element.removeAttr("id");
          return false;
          }
        else // B) The style has not been inserted
          {
          if (element.css(prop))
            {
            // element.removeAttr("id");
            return false;
            }
          }
        }
      });
    };
  };

  return function(element){
    var className = element.attr("class");
    var id = element.attr("id");    
    var backup_inline_styles = { attr: [], val: [] }
    if ( className || id )
      { 
      remove_attr( properties, element, backup_inline_styles );
      }
    filterClasses(element,className,id);
    filterIds(element,className,id);
    if ( className || id )
      restore_attr( properties, element, backup_inline_styles );
  }($(this))

  }
});

Implementation

window.onload = function() {  
  search_padding_collection_classes = $();
  search_width_classes = $();
  search_padding_collection_ids = $();
  search_width_ids = $();
  var search = $("div.column-right-outer");
  $(search).removeClassWithStyles([ { prop: 'float', exclude: 'none' }, 'position', 'top', 'right', 'bottom', 'left' ], true);
  $(search).compressElementsWidth();
  // console.log($('div.column-right-outer').find("*").filter(":visible"));
};

Upvotes: 0

Jared Teng
Jared Teng

Reputation: 311

I don't think what your planning will result to a proper solution.

The AAA ID surely has float right from class hello, but getting class hello css still gives us left even with document ready.

Experiment code below with your way,

http://codepen.io/anon/pen/ozvzwX?editors=1111

Same class can have different styles for different elements.

$( document ).ready(function(){
  var search = $("div#left");
  var class_arr = search.prop("className").split(" ");
  console.log("hello "+class_arr)

  $.each(class_arr,function(){
    console.log($("."+class_arr).css("float"))
    console.log($("#AAA").css("float"))  
    //hello hello
    //left
    //right
  })
})
div #left { float: left }
div #right { float: right}
.hello {float:right}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</head>
<body>
<div>

<div id="left" class="hello">
<h1>Hello</h1>
</div>

<div id="right" class="hello">
<h3>World</h3>
</div>
  
<div id="AAA" class="hello">
<h3>AAAAAAAAAAAAAAA</h3>
</div>
  
</div>

Why not just remove the styles you don't want, you can make it dynamic?

$("#left").css("float","none"); 
$( document ).ready(function(){
      console.log("Final "+$("#left").css("float"))
      //none
    })
div #left { float: left }
div #right { float: right}
.hello {float:right}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</head>
<body>
<div>

<div id="left" class="hello">
<h1>Hello</h1>
</div>

<div id="right" class="hello">
<h3>World</h3>
</div>
  
<div id="AAA" class="hello">
<h3>AAAAAAAAAAAAAAA</h3>
</div>
  
</div>

Upvotes: 0

skobaljic
skobaljic

Reputation: 9634

jQuery's cloned elements are getting default styles and we can use it this way:

$.fn.extend({
    removeClassWithStyles: function(properties) {
        function filterClasses(child, cloned) {
            var thisClassAttr = child.attr("class");
            if (thisClassAttr) {
                var splitClassName = thisClassAttr.split(/\s+/);
                $.each(splitClassName, function(c, className) {
                    cloned.removeClass(className);
                    $.each(properties, function(p, prop) {
                        if (child.css(prop) != cloned.css(prop)) {
                            console.log('remove class: ' + className);
                            child.removeClass(className);
                            return false;
                        };
                    });
                });
            };

        };
        return this.each(function() {
            var thisElement = $(this);
            thisElement.find('*').each(function(e) {
                var child = $(this);
                var cloned = $(this).clone();
                filterClasses(child, cloned);
            });
        });
    }
});
$('body').removeClassWithStyles([
    'float', 'position', 'top', 'right', 'bottom', 'left'
]);
body {
    position: relative;
}
.left {
    float: left;
}
.right-abs {
    position: absolute;
    top: 20px;
    right: 100px;
}
.top-abs {
    position: absolute;
    top: 20px;
}
.center {
    text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="left">
    <h1>Hello</h1>
</div>
<div class="right-abs top-abs center">
    <h3>World</h3>
</div>

Also on Fiddle

Explanation:

We are comparing elements styles to default browser style, therefore we know if those are changed by specific class or not.

Upvotes: 2

Related Questions