]> git.openstreetmap.org Git - rails.git/blob - public/lib/Rico/Corner.js
bugfix for non-intersecting intersections (trac #592)
[rails.git] / public / lib / Rico / Corner.js
1 /**  
2 *  
3 *  Copyright 2005 Sabre Airline Solutions  
4 *  
5 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this  
6 *  file except in compliance with the License. You may obtain a copy of the License at  
7 *  
8 *         http://www.apache.org/licenses/LICENSE-2.0  
9 *  
10 *  Unless required by applicable law or agreed to in writing, software distributed under the  
11 *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,  
12 *  either express or implied. See the License for the specific language governing permissions  
13 *  and limitations under the License.  
14 **/  
15
16
17 var Rico = new Object();
18 Rico.Corner = {
19
20    round: function(e, options) {
21       var e = $(e);
22       this._setOptions(options);
23
24       var color = this.options.color;
25       if ( this.options.color == "fromElement" )
26          color = this._background(e);
27
28       var bgColor = this.options.bgColor;
29       if ( this.options.bgColor == "fromParent" )
30          bgColor = this._background(e.offsetParent);
31
32       this._roundCornersImpl(e, color, bgColor);
33    },
34
35     /**   This is a helper function to change the background
36     *     color of <div> that has had Rico rounded corners added.
37     *
38     *     It seems we cannot just set the background color for the
39     *     outer <div> so each <span> element used to create the
40     *     corners must have its background color set individually.
41     *
42     * @param {DOM} theDiv - A child of the outer <div> that was
43     *                        supplied to the `round` method.
44     *
45     * @param {str} newColor - The new background color to use.
46     */
47     changeColor: function(theDiv, newColor) {
48    
49         theDiv.style.backgroundColor = newColor;
50
51         var spanElements = theDiv.parentNode.getElementsByTagName("span");
52         
53         for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
54             spanElements[currIdx].style.backgroundColor = newColor;
55         }
56     }, 
57
58
59     /**   This is a helper function to change the background
60     *     opacity of <div> that has had Rico rounded corners added.
61     *
62     *     See changeColor (above) for algorithm explanation
63     *
64     * @param {DOM} theDiv A child of the outer <div> that was
65     *                        supplied to the `round` method.
66     *
67     * @param {int} newOpacity The new opacity to use (0-1).
68     */
69     changeOpacity: function(theDiv, newOpacity) {
70    
71         var mozillaOpacity = newOpacity;
72         var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';
73         
74         theDiv.style.opacity = mozillaOpacity;
75         theDiv.style.filter = ieOpacity;
76
77         var spanElements = theDiv.parentNode.getElementsByTagName("span");
78         
79         for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
80             spanElements[currIdx].style.opacity = mozillaOpacity;
81             spanElements[currIdx].style.filter = ieOpacity;
82         }
83
84     },
85
86     /** this function takes care of redoing the rico cornering
87     *    
88     *    you can't just call updateRicoCorners() again and pass it a 
89     *    new options string. you have to first remove the divs that 
90     *    rico puts on top and below the content div.
91     *
92     * @param {DOM} theDiv - A child of the outer <div> that was
93     *                        supplied to the `round` method.
94     *
95     * @param {Array} options - list of options
96     */
97     reRound: function(theDiv, options) {
98
99         var topRico = theDiv.parentNode.childNodes[0];
100         //theDiv would be theDiv.parentNode.childNodes[1]
101         var bottomRico = theDiv.parentNode.childNodes[2];
102        
103         theDiv.parentNode.removeChild(topRico);
104         theDiv.parentNode.removeChild(bottomRico); 
105
106         this.round(theDiv.parentNode, options);
107     }, 
108
109    _roundCornersImpl: function(e, color, bgColor) {
110       if(this.options.border)
111          this._renderBorder(e,bgColor);
112       if(this._isTopRounded())
113          this._roundTopCorners(e,color,bgColor);
114       if(this._isBottomRounded())
115          this._roundBottomCorners(e,color,bgColor);
116    },
117
118    _renderBorder: function(el,bgColor) {
119       var borderValue = "1px solid " + this._borderColor(bgColor);
120       var borderL = "border-left: "  + borderValue;
121       var borderR = "border-right: " + borderValue;
122       var style   = "style='" + borderL + ";" + borderR +  "'";
123       el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
124    },
125
126    _roundTopCorners: function(el, color, bgColor) {
127       var corner = this._createCorner(bgColor);
128       for(var i=0 ; i < this.options.numSlices ; i++ )
129          corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
130       el.style.paddingTop = 0;
131       el.insertBefore(corner,el.firstChild);
132    },
133
134    _roundBottomCorners: function(el, color, bgColor) {
135       var corner = this._createCorner(bgColor);
136       for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
137          corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
138       el.style.paddingBottom = 0;
139       el.appendChild(corner);
140    },
141
142    _createCorner: function(bgColor) {
143       var corner = document.createElement("div");
144       corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
145       return corner;
146    },
147
148    _createCornerSlice: function(color,bgColor, n, position) {
149       var slice = document.createElement("span");
150
151       var inStyle = slice.style;
152       inStyle.backgroundColor = color;
153       inStyle.display  = "block";
154       inStyle.height   = "1px";
155       inStyle.overflow = "hidden";
156       inStyle.fontSize = "1px";
157
158       var borderColor = this._borderColor(color,bgColor);
159       if ( this.options.border && n == 0 ) {
160          inStyle.borderTopStyle    = "solid";
161          inStyle.borderTopWidth    = "1px";
162          inStyle.borderLeftWidth   = "0px";
163          inStyle.borderRightWidth  = "0px";
164          inStyle.borderBottomWidth = "0px";
165          inStyle.height            = "0px"; // assumes css compliant box model
166          inStyle.borderColor       = borderColor;
167       }
168       else if(borderColor) {
169          inStyle.borderColor = borderColor;
170          inStyle.borderStyle = "solid";
171          inStyle.borderWidth = "0px 1px";
172       }
173
174       if ( !this.options.compact && (n == (this.options.numSlices-1)) )
175          inStyle.height = "2px";
176
177       this._setMargin(slice, n, position);
178       this._setBorder(slice, n, position);
179       return slice;
180    },
181
182    _setOptions: function(options) {
183       this.options = {
184          corners : "all",
185          color   : "fromElement",
186          bgColor : "fromParent",
187          blend   : true,
188          border  : false,
189          compact : false
190       }
191       Object.extend(this.options, options || {});
192
193       this.options.numSlices = this.options.compact ? 2 : 4;
194       if ( this._isTransparent() )
195          this.options.blend = false;
196    },
197
198    _whichSideTop: function() {
199       if ( this._hasString(this.options.corners, "all", "top") )
200          return "";
201
202       if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
203          return "";
204
205       if (this.options.corners.indexOf("tl") >= 0)
206          return "left";
207       else if (this.options.corners.indexOf("tr") >= 0)
208           return "right";
209       return "";
210    },
211
212    _whichSideBottom: function() {
213       if ( this._hasString(this.options.corners, "all", "bottom") )
214          return "";
215
216       if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
217          return "";
218
219       if(this.options.corners.indexOf("bl") >=0)
220          return "left";
221       else if(this.options.corners.indexOf("br")>=0)
222          return "right";
223       return "";
224    },
225
226    _borderColor : function(color,bgColor) {
227       if ( color == "transparent" )
228          return bgColor;
229       else if ( this.options.border )
230          return this.options.border;
231       else if ( this.options.blend )
232          return this._blend( bgColor, color );
233       else
234          return "";
235    },
236
237
238    _setMargin: function(el, n, corners) {
239       var marginSize = this._marginSize(n);
240       var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
241
242       if ( whichSide == "left" ) {
243          el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
244       }
245       else if ( whichSide == "right" ) {
246          el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
247       }
248       else {
249          el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
250       }
251    },
252
253    _setBorder: function(el,n,corners) {
254       var borderSize = this._borderSize(n);
255       var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
256       if ( whichSide == "left" ) {
257          el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
258       }
259       else if ( whichSide == "right" ) {
260          el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
261       }
262       else {
263          el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
264       }
265       if (this.options.border != false)
266         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
267    },
268
269    _marginSize: function(n) {
270       if ( this._isTransparent() )
271          return 0;
272
273       var marginSizes          = [ 5, 3, 2, 1 ];
274       var blendedMarginSizes   = [ 3, 2, 1, 0 ];
275       var compactMarginSizes   = [ 2, 1 ];
276       var smBlendedMarginSizes = [ 1, 0 ];
277
278       if ( this.options.compact && this.options.blend )
279          return smBlendedMarginSizes[n];
280       else if ( this.options.compact )
281          return compactMarginSizes[n];
282       else if ( this.options.blend )
283          return blendedMarginSizes[n];
284       else
285          return marginSizes[n];
286    },
287
288    _borderSize: function(n) {
289       var transparentBorderSizes = [ 5, 3, 2, 1 ];
290       var blendedBorderSizes     = [ 2, 1, 1, 1 ];
291       var compactBorderSizes     = [ 1, 0 ];
292       var actualBorderSizes      = [ 0, 2, 0, 0 ];
293
294       if ( this.options.compact && (this.options.blend || this._isTransparent()) )
295          return 1;
296       else if ( this.options.compact )
297          return compactBorderSizes[n];
298       else if ( this.options.blend )
299          return blendedBorderSizes[n];
300       else if ( this.options.border )
301          return actualBorderSizes[n];
302       else if ( this._isTransparent() )
303          return transparentBorderSizes[n];
304       return 0;
305    },
306
307    _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
308    _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
309    _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
310    _isTransparent: function() { return this.options.color == "transparent"; },
311    _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
312    _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
313    _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
314 }