2

this code uses classes as css properties and everything that comes after = - as the values of it.

ex:

function getProp(classStr) {
  return classStr.split('=')[0]
}

function getValues(classStr) {
  var values = classStr.split('=')[1]
  return values.split(',').join(' ')
}

function transform(el, prop, values) {
  $(el).css(prop, values)
}


var elements = $('div, p, span, img, li, ul, a, h1, h2, h3, h4, h5, h6')
elements.each(function(i, el) {
  var classList = $(el).attr('class')
  if (!classList) return
  var classProps = classList.split(' ')
  $(classProps).each(function(i, str) {
    var prop = getProp(str)
    var values = getValues(str)
    transform(el, prop, values)
  })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='color=red font-size=50px font-family=arial'>hello world</div>

soo.. here's a problem. when you want to assign a property with multiple values, like border=2px,solid,black and if BEFORE it there's a class that doesn't even have the = sign, the whole code just crashes.

i guess it's because of the

function getValues(classStr) {
  var values = classStr.split('=')[1]
  return values.split(',').join(' ')
}

function??

how can we check if the property has no values (standart css class) or multiple values that are written with commas (border=2px,solid,black)?

valeria
  • 121
  • 1
  • 1
  • 9
  • I would change your class names - the `=` sign is not a valid character for a class name and using it may cause different browsers to react in different ways – Pete Dec 07 '18 at 13:35
  • ok thank you, i will. but what about the problem? – valeria Dec 07 '18 at 13:36
  • you could do a test on your string in the each loop - check `indexOf(',') > -1` (multiple values) or index of the equals for a normal class – Pete Dec 07 '18 at 13:38
  • What you're trying to create can be done simply using the `style` attribute - and still is the wrong approach. You don't want any styling-related code in your HTML. – connexo Dec 07 '18 at 13:55

3 Answers3

1

You can use a regular expression to get your matched parameters. Notice I have added a class called taco that doesn't throw off the results

Here's a fully functional example, using your code as a basis

function transformValue(value) {
  if (!value.includes('rgb')) {
    return value.split(',').join(' ');
  }
  return value;
}

function transform(el, prop, values) {
  $(el).css(prop, values);
}


var elements = $('div, p, span, img, li, ul, a, h1, h2, h3, h4, h5, h6');
elements.each(function(i, el) {
  var classList = $(el).attr('class');
  if (!classList) return true;
  
  var regex = /([\w-]+)=([\w\d,%()\.]+)/g;
  var matches;
  var params = [];

  while (matches = regex.exec(classList)) {
    var prop = matches[1];
    var values = transformValue(matches[2]);
    transform(el, matches[1], values);
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='color=red font-size=50px font-family=arial taco border=1px,solid,red margin-left=20% background-color=rgba(0,255,0,0.5)'>hello world</div>

Reasoning and Performance

Some may question my choice to use a regular expression, as it has a bad reputation as being inefficient; however, given that a non-regular expression route only gave a 0.75% increase, I found the readability of my solution to be a good trade off.

https://jsperf.com/so53670448

AnonymousSB
  • 3,516
  • 10
  • 28
  • man u smart! thank you, it works just perfectly and is more familiar to me – valeria Dec 07 '18 at 14:52
  • 1
    You're welcome! Also note that I added semicolons. Semicolons are optional in JavaScript, but omitting them can cause errors if you decide to minify your code. You can see an example in the [accepted answer here](https://stackoverflow.com/questions/12073960/javascript-semicolon-less-code-style-and-minification) – AnonymousSB Dec 07 '18 at 15:07
  • ok, will do! if i can ask one more question.. why won't the percent measures work though? like 'margin-left=20%'? – valeria Dec 07 '18 at 15:12
  • and there's no way to make it work ? i mean.. percents did in my own lame code haha – valeria Dec 07 '18 at 15:17
  • 1
    It's because I'm not capturing percentage in the regular expression, I'll update my example to include it. – AnonymousSB Dec 07 '18 at 15:19
  • hello once again! i have been trying to add rgba() value in regex, but it seems like im doing something wrong. could you please check it out? ` var regex = /([\w-]+)=([#\w\d,%,rgba\((\d+)\,(\d+)\,(\d+)\,((\d|\.)+)\)]+)/g;` – valeria Dec 09 '18 at 11:41
  • 1
    Here you go. `([\w-]+)=([\w\d,%\(\)\.]+)`. I just added `(`, `)`, and `.` to the last capture group. We're already capturing `rgba` with the `\w` and the numbers with `\d`. You can also checkout [RegExr](https://regexr.com/) to test out regular expressions – AnonymousSB Dec 09 '18 at 11:46
  • wait.. i just tried this and still doesn't work for me.. are you sure it's correct?
    qwerty
    and var regex = /([\w-]+)=([\w\d,%\(\)\.]+)/g;
    – valeria Dec 09 '18 at 12:05
  • 1
    Updated the answer with a working demo. Note the change to `transformValue()` – AnonymousSB Dec 09 '18 at 12:15
1

This is weird and not really valid syntax for a class name/-list. Anyway, you wouldn't need jQuery to convert the class attribute string to a style attribute, and bonus, your code can be cleaner. Something along the lines of:

setStyle(document.querySelector("div#weird"));
setStyleFromShortcuts(document.querySelector("div#weirder"));

function setStyle(elemWithWeirdClass) {
  const weirdClass = Array.from(elemWithWeirdClass.classList);
  if (weirdClass.length < 1 || !weirdClass.join("").includes("=")) { return; }
  const converted = weirdClass
      .reduce( (styleElement, semiClass) => 
          [...styleElement, semiClass.split("=").join(":")], []).join(";");
  elemWithWeirdClass.removeAttribute("class");
  elemWithWeirdClass.setAttribute("style", converted);
}

function setStyleFromShortcuts(elemWithWeirdClass) {
  const shortCuts = {
    c: "color",
    fs: "font-size",
    ff: "font-face"
  }
  const weirdClass = Array.from(elemWithWeirdClass.classList);
  const getShortCut = ([key, value]) => `${shortCuts[key]}:${value}`;
  if (weirdClass.length < 1 || !weirdClass.join("").includes("=")) { return; }
  const converted = weirdClass
      .reduce( (styleElement, semiClass) => 
          [...styleElement, getShortCut(semiClass.split("="))], []).join(";");
  elemWithWeirdClass.removeAttribute("class");
  elemWithWeirdClass.setAttribute("style", converted);
}
<div id="weird" class='color=red font-size=50px font-family=arial'>hello world</div>

<div id="weirder" class='c=orange fs=50px ff=times new roman'>hello world</div>
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • wow this is amazing! but now with this new code i cant figure how to apply the library of shortcuts that i made for the old one.. var shortcuts = { //width and height 'w':'width', 'h':'height', //etc } function getFullName(shortName) { return shortcuts[shortName]; } function transform(el, prop, values) { var propFull = getFullName(prop) || prop; $(el).css(propFull, values) } – valeria Dec 07 '18 at 14:05
  • @valeria If you're using jQuery for more things, then this solution won't work out of the box for you. You'll need to pass a reference of your element back into jQuery, or rewrite your code to not use jQuery. – AnonymousSB Dec 07 '18 at 14:13
  • @valeria, Also note this is ES6 and not fully supported: [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Browser_compatibility), [`...`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Browser_compatibility), [`=>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Browser_compatibility), [`includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Browser_compatibility) – AnonymousSB Dec 07 '18 at 14:23
  • oh well;( that's a pity. i guess im gonna have to take other answers then: – valeria Dec 07 '18 at 14:25
  • @AnonymousSB that's all a bit nonsensical. Modern browsers support the subset of methods used here completely. Futhermore jQuery is ecmascript, so everything you can do in jQuery is doable in ecmascript. – KooiInc Dec 07 '18 at 14:28
  • @valeria even weirder! But I added a method to demonstrate the possibilities ;) – KooiInc Dec 07 '18 at 14:29
  • The OP specified this was a jQuery question, thus a jQuery solution seems applicable. Personally, I never touch the stuff, but that's up to OP to decide. As for browser support, the four things I pointed out have 0% support in any version of IE. Also, I didn't say jQuery wouldn't work with JS, just that she will need to pass a reference for `el` using your solution. – AnonymousSB Dec 07 '18 at 14:33
  • Also, and this is just for your own knowledge, but your solution is extremely slow, 25K ops per/sec, vs 560K ops per/sec using other solutions posted here. This is mostly because you have 7 loops in your code. [Here's the performance test I ran](https://jsperf.com/so53670448) – AnonymousSB Dec 07 '18 at 14:37
1

Regular expression is more expensive than a simple indexOf this code its functionally give them a try...

This code also differ of yours by one "IF" ...

function getProp(classStr) {
  return classStr.split('=')[0]
}

function getValues(classStr) {
  var values = classStr.split('=')[1]
  return values.split(',').join(' ')
}

function transform(el, prop, values) {
  $(el).css(prop, values)
}


var elements = $('div, p, span, img, li, ul, a, h1, h2, h3, h4, h5, h6')
elements.each(function(i, el) {
  var classList = $(el).attr('class')
  if (!classList) return
  var classProps = classList.split(' ')



  $(classProps).each(function(i, str) {

    //if contain a symbol '=' is procesed, like a css
    //else do nothing ...because is a class
    if ( str.indexOf('=') > -1 ) {
        var prop = getProp(str)
        var values = getValues(str)
        transform(el, prop, values)
    }


  })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='color=red class-temporal border=1px,solid,red font-size=50px font-family=arial'>hello world</div>
Sk.
  • 460
  • 7
  • 15
  • You are correct that regex is generally an expensive operation; however, in this particular case, I found it to be better for readability given that indexOf is only a [0.75% performance increase](https://jsperf.com/so53670448). – AnonymousSB Dec 07 '18 at 14:09