views:

283

answers:

3

Using Mootools Element.Dimensions I can get the computed size, in pixels, of any element. However, I can find no way of telling whether an element has been sized using pixel or percentage values (other than in the special case of its having an inline style).

Is there a sensible way of doing this? The only solution I can think of (which is so hideous that it barely deserves the name) is to walk through the document stylesheets, looking for selectors that match the target element and then looking through the declared styles for the target propety.

Background

I'm attempting to replace all textareas of a certain class with CKEditor instances. Ideally, textareas with 100% width would be replaced by similarly styled editor instances - so they would scale on window resize - while fixed size textareas would be replaced by fixed sized editors.

Yes, I could just give them a different class (which I will do if there's no nice solution), but ideally I'd like to be able to drop in my CKEditor script and have everything just work without having to tweak the HTML.

A: 

I doubt it can be done. You described the reason quite accurately: We have access to this kind of information only if it is in the element's style attribute. The only way I can think of is enlarge the parent container a bit and see if the textarea grows proportionately in size, but this is probably not always feasible, and probably hard to make cross-browser functional.

I'd be highly interested in more positive answers, though. Cheers, Tom

Tom Bartel
A: 

In IE, element.currentStyle.width. In many other browsers, getComputedStyle(element, null).getPropertyValue('width').

bobince
Yeah, this is exactly what Element.Dimensions uses. Unfortunately, this only gives the pixel values; it doesn't tell you whether the styles were originally specified in pixels or percentages.
D. Evans
@D. Evans: heh, implicit in your comment is that you don't-care/are-not-testing-in IE. `currentStyle` was made for your exact usecase. Unfortunately you're right, the other browsers compute the pixel dimensions.
Crescent Fresh
Ah, you caught me out! You're right: I'm not particularly interested in IE-only solutions but it's worth knowing the option's there. For the first time in my life, I'm tempted to wish that other browser vendors would follow Microsoft's lead ;-)
D. Evans
I didn't think it always did this... on closer inspection, what Firefox is doing is returning the pixelised value when the `width` style is effective (such as on a block element), and the untouched CSS setting (potentially in other units, or `auto`) only when the width is ineffective (eg. on inline elements). Reading the CSS2 spec this is the difference between ‘computed values’ and ‘specified values’... if only there were a `getSpecifiedValue` call...
bobince
You want a solution without classnames to differentiate 100% from pixels? Wrap the textarea in a div with a fixed width and see if the textarea resizes. ;-) I didn't say it was a very nice solution...
bobince
@bobince: yeah, `getComputedStyle` has always worked like this. @D. Evans: if it's any condolence, jQuery doesn't let you at the inherited style either. In fact it goes out of its way to break it in IE (in the name of cross-browser consistency), see http://stackoverflow.com/questions/1313995/how-can-i-get-the-font-size-of-an-element-as-it-was-set-by-css/1314845#1314845 Also check the accepted answer there. apparently it can be done in other browsers but I can't vouch for it.
Crescent Fresh
@D. Evans: on 2nd read of that Q. the accepted answer is simply converting `px` to `em` s.
Crescent Fresh
+1  A: 

Not that familiar with Motools but in jQuery you can do it.

Check here for a live demo http://jsbin.com/ewuqa

Or check this it handles also multiple matching CSS rules but only returns the correct value (the only thing I didn't bother to handle is if !important is set).

Included JS

http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.class.js
http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.selector.js
http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.selector.specifity.js

Own functions

function compare(as,bs) {
    return (as[0] - bs[0]) || (as[1] - bs[1]) || (as[2] - bs[2]);
}

//selector should only match a single element
//property is a css style-name
//returns the set css value (if set) for matched element, not the computed value
//also handles multiple matching rules and only returns most specific match
//doesn't handle !important
function whatIsSet(selector, property) {
    var se = $(selector);
    var regex = new RegExp("(.*)-(.)(.*)","g");
    var p = property;
    if (/-/.test(p)) {
        p = regex.exec(property);
        p = p[1] + p[2].toUpperCase() + p[3];
    }
    if (se.get(0).style[p] != undefined && se.get(0).style[p] != '')
        return se.get(0).style[p]; 

    var matchers = new Object();
    var mostSpecific = undefined;
    for(var i = 0; i < document.styleSheets.length; i++) {
        //IE support
        var rules =
            document.styleSheets[i].cssRules ?
              document.styleSheets[i].cssRules :
              document.styleSheets[i].rules;
        for (var j=0; j < rules.length; j++)
            if (rules[j].style[p])
                if (jQuery.inArray(se, $(rules[j].selectorText)))
                    matchers[rules[j].selectorText] = rules[j].style[p];
    }
    for(var i in matchers) {
        if(mostSpecific != undefined) {
            var ms = $.selector(mostSpecific).specifity();
            var is = $.selector(i).specifity();
            mostSpecific = compare(ms, is) > 0  ? mostSpecific : i;
        } else
            mostSpecific = i;
    }
    return matchers[mostSpecific];
}

CSS

body { background-color: #000; font: 16px Helvetica, Arial; color: #fff; }
#myElement {background-color: yellow; width:10%}
div {background-color: green; width:200px}
div#myElement  {background-color: blue; width:30%}
div.asd#myElement  {background-color: red; width:50%;}

HTML

  <div id="myElement" class="asd" style="width:91%">asd</div>
  <input
      type="button"
      onclick="javascript:alert('width originally set to: '+
          whatIsSet('#myElement', 'width'));"
      value="Tell me original width!"><br>
  <input
      type="button"
      onclick="javascript:alert('height originally set to: '+
          whatIsSet('#myElement', 'height'));"
      value="Tell me original height!"><br>
  <input
      type="button"
      onclick="javascript:alert('background-color originally set to: '+
          whatIsSet('#myElement', 'background-color'));"
      value="Tell me original background-color!"><br>
jitter
OK, that's impressive! I know I described this solution as hideous in my initial post; but, now I've actually seen it working, maybe it wouldn't be too bad. After all, if I'm already including 300kB of CKEditor, what's a few more. I'll have a go at implementing the same thing in Mootools.
D. Evans