summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
blob: e994e47d63b120e06e40529fc4d1d9ef95c9f673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
@VaadinApache2LicenseForJavaFiles@
 */
package com.vaadin.terminal.gwt.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Element;

public class ComputedStyle {

    protected final JavaScriptObject computedStyle;
    private final Element elem;

    /**
     * Gets this element's computed style object which can be used to gather
     * information about the current state of the rendered node.
     * <p>
     * Note that this method is expensive. Wherever possible, reuse the returned
     * object.
     * 
     * @param elem
     *            the element
     * @return the computed style
     */
    public ComputedStyle(Element elem) {
        computedStyle = getComputedStyle(elem);
        this.elem = elem;
    }

    private static native JavaScriptObject getComputedStyle(Element elem)
    /*-{
      if(elem.nodeType != 1) {
          return {};
      }
      
      if($wnd.document.defaultView && $wnd.document.defaultView.getComputedStyle) {
          return $wnd.document.defaultView.getComputedStyle(elem, null);
      }
      
      if(elem.currentStyle) {
          return elem.currentStyle;
      }
    }-*/;

    /**
     * 
     * @param name
     *            name of the CSS property in camelCase
     * @return the value of the property, normalized for across browsers (each
     *         browser returns pixel values whenever possible).
     */
    public final native String getProperty(String name)
    /*-{
        var cs = this.@com.vaadin.terminal.gwt.client.ComputedStyle::computedStyle;
        var elem = this.@com.vaadin.terminal.gwt.client.ComputedStyle::elem;
        
        // Border values need to be checked separately. The width might have a 
        // meaningful value even if the border style is "none". In that case the 
        // value should be 0.
        if(name.indexOf("border") > -1 && name.indexOf("Width") > -1) {
            var borderStyleProp = name.substring(0,name.length-5) + "Style";
            if(cs.getPropertyValue)
                var borderStyle = cs.getPropertyValue(borderStyleProp);
            else // IE
                var borderStyle = cs[borderStyleProp];
            if(borderStyle == "none")
                return "0px";
        }

        if(cs.getPropertyValue) {
        
            // Convert name to dashed format
            name = name.replace(/([A-Z])/g, "-$1").toLowerCase();
            var ret = cs.getPropertyValue(name);
            
        } else {
        
            var ret = cs[name];
            var style = elem.style;

            // From the awesome hack by Dean Edwards
            // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

            // If we're not dealing with a regular pixel number
            // but a number that has a weird ending, we need to convert it to pixels
            if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
                // Remember the original values
                var left = style.left, rsLeft = elem.runtimeStyle.left;

                // Put in the new values to get a computed value out
                elem.runtimeStyle.left = cs.left;
                style.left = ret || 0;
                ret = style.pixelLeft + "px";

                // Revert the changed values
                style.left = left;
                elem.runtimeStyle.left = rsLeft;
            }
            
        }
        
        // Normalize margin values. This is not totally valid, but in most cases 
        // it is what the user wants to know.
        if(name.indexOf("margin") > -1 && ret == "auto") {
            return "0px";
        }
        
        // Some browsers return undefined width and height values as "auto", so
        // we need to retrieve those ourselves.
        if (name == "width" && ret == "auto") {
            ret = elem.clientWidth + "px";
        } else if (name == "height" && ret == "auto") {
            ret = elem.clientHeight + "px";
        }

        return ret;
        
    }-*/;

    public final int getIntProperty(String name) {
        Integer parsed = parseInt(getProperty(name));
        if (parsed != null) {
            return parsed.intValue();
        }
        return 0;
    }

    /**
     * Get current margin values from the DOM. The array order is the default
     * CSS order: top, right, bottom, left.
     */
    public final int[] getMargin() {
        int[] margin = { 0, 0, 0, 0 };
        margin[0] = getIntProperty("marginTop");
        margin[1] = getIntProperty("marginRight");
        margin[2] = getIntProperty("marginBottom");
        margin[3] = getIntProperty("marginLeft");
        return margin;
    }

    /**
     * Get current padding values from the DOM. The array order is the default
     * CSS order: top, right, bottom, left.
     */
    public final int[] getPadding() {
        int[] padding = { 0, 0, 0, 0 };
        padding[0] = getIntProperty("paddingTop");
        padding[1] = getIntProperty("paddingRight");
        padding[2] = getIntProperty("paddingBottom");
        padding[3] = getIntProperty("paddingLeft");
        return padding;
    }

    /**
     * Get current border values from the DOM. The array order is the default
     * CSS order: top, right, bottom, left.
     */
    public final int[] getBorder() {
        int[] border = { 0, 0, 0, 0 };
        border[0] = getIntProperty("borderTopWidth");
        border[1] = getIntProperty("borderRightWidth");
        border[2] = getIntProperty("borderBottomWidth");
        border[3] = getIntProperty("borderLeftWidth");
        return border;
    }

    /**
     * Takes a String value e.g. "12px" and parses that to int 12.
     * 
     * @param String
     *            a value starting with a number
     * @return int the value from the string before any non-numeric characters.
     *         If the value cannot be parsed to a number, returns
     *         <code>null</code>.
     */
    public static native Integer parseInt(final String value)
    /*-{
        var number = parseInt(value, 10);
        if (isNaN(number))
            return null;
        else
            return @java.lang.Integer::valueOf(I)(number);
    }-*/;

}