1 | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
---|
2 | * full list of contributors). Published under the Clear BSD license. |
---|
3 | * See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
---|
4 | * full text of the license. */ |
---|
5 | |
---|
6 | /** |
---|
7 | * @requires OpenLayers/Popup/Anchored.js |
---|
8 | */ |
---|
9 | |
---|
10 | /** |
---|
11 | * Class: OpenLayers.Popup.Framed |
---|
12 | * |
---|
13 | * Inherits from: |
---|
14 | * - <OpenLayers.Popup.Anchored> |
---|
15 | */ |
---|
16 | OpenLayers.Popup.Framed = |
---|
17 | OpenLayers.Class(OpenLayers.Popup.Anchored, { |
---|
18 | |
---|
19 | /** |
---|
20 | * Property: imageSrc |
---|
21 | * {String} location of the image to be used as the popup frame |
---|
22 | */ |
---|
23 | imageSrc: null, |
---|
24 | |
---|
25 | /** |
---|
26 | * Property: imageSize |
---|
27 | * {<OpenLayers.Size>} Size (measured in pixels) of the image located |
---|
28 | * by the 'imageSrc' property. |
---|
29 | */ |
---|
30 | imageSize: null, |
---|
31 | |
---|
32 | /** |
---|
33 | * APIProperty: isAlphaImage |
---|
34 | * {Boolean} The image has some alpha and thus needs to use the alpha |
---|
35 | * image hack. Note that setting this to true will have no noticeable |
---|
36 | * effect in FF or IE7 browsers, but will all but crush the ie6 |
---|
37 | * browser. |
---|
38 | * Default is false. |
---|
39 | */ |
---|
40 | isAlphaImage: false, |
---|
41 | |
---|
42 | /** |
---|
43 | * Property: positionBlocks |
---|
44 | * {Object} Hash of different position blocks (Object/Hashs). Each block |
---|
45 | * will be keyed by a two-character 'relativePosition' |
---|
46 | * code string (ie "tl", "tr", "bl", "br"). Block properties are |
---|
47 | * 'offset', 'padding' (self-explanatory), and finally the 'blocks' |
---|
48 | * parameter, which is an array of the block objects. |
---|
49 | * |
---|
50 | * Each block object must have 'size', 'anchor', and 'position' |
---|
51 | * properties. |
---|
52 | * |
---|
53 | * Note that positionBlocks should never be modified at runtime. |
---|
54 | */ |
---|
55 | positionBlocks: null, |
---|
56 | |
---|
57 | /** |
---|
58 | * Property: blocks |
---|
59 | * {Array[Object]} Array of objects, each of which is one "block" of the |
---|
60 | * popup. Each block has a 'div' and an 'image' property, both of |
---|
61 | * which are DOMElements, and the latter of which is appended to the |
---|
62 | * former. These are reused as the popup goes changing positions for |
---|
63 | * great economy and elegance. |
---|
64 | */ |
---|
65 | blocks: null, |
---|
66 | |
---|
67 | /** |
---|
68 | * APIProperty: fixedRelativePosition |
---|
69 | * {Boolean} We want the framed popup to work dynamically placed relative |
---|
70 | * to its anchor but also in just one fixed position. A well designed |
---|
71 | * framed popup will have the pixels and logic to display itself in |
---|
72 | * any of the four relative positions, but (understandably), this will |
---|
73 | * not be the case for all of them. By setting this property to 'true', |
---|
74 | * framed popup will not recalculate for the best placement each time |
---|
75 | * it's open, but will always open the same way. |
---|
76 | * Note that if this is set to true, it is generally advisable to also |
---|
77 | * set the 'panIntoView' property to true so that the popup can be |
---|
78 | * scrolled into view (since it will often be offscreen on open) |
---|
79 | * Default is false. |
---|
80 | */ |
---|
81 | fixedRelativePosition: false, |
---|
82 | |
---|
83 | /** |
---|
84 | * Constructor: OpenLayers.Popup.Framed |
---|
85 | * |
---|
86 | * Parameters: |
---|
87 | * id - {String} |
---|
88 | * lonlat - {<OpenLayers.LonLat>} |
---|
89 | * contentSize - {<OpenLayers.Size>} |
---|
90 | * contentHTML - {String} |
---|
91 | * anchor - {Object} Object to which we'll anchor the popup. Must expose |
---|
92 | * a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>) |
---|
93 | * (Note that this is generally an <OpenLayers.Icon>). |
---|
94 | * closeBox - {Boolean} |
---|
95 | * closeBoxCallback - {Function} Function to be called on closeBox click. |
---|
96 | */ |
---|
97 | initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox, |
---|
98 | closeBoxCallback) { |
---|
99 | |
---|
100 | OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments); |
---|
101 | |
---|
102 | if (this.fixedRelativePosition) { |
---|
103 | //based on our decided relativePostion, set the current padding |
---|
104 | // this keeps us from getting into trouble |
---|
105 | this.updateRelativePosition(); |
---|
106 | |
---|
107 | //make calculateRelativePosition always return the specified |
---|
108 | // fixed position. |
---|
109 | this.calculateRelativePosition = function(px) { |
---|
110 | return this.relativePosition; |
---|
111 | }; |
---|
112 | } |
---|
113 | |
---|
114 | this.contentDiv.style.position = "absolute"; |
---|
115 | this.contentDiv.style.zIndex = 1; |
---|
116 | |
---|
117 | if (closeBox) { |
---|
118 | this.closeDiv.style.zIndex = 1; |
---|
119 | } |
---|
120 | |
---|
121 | this.groupDiv.style.position = "absolute"; |
---|
122 | this.groupDiv.style.top = "0px"; |
---|
123 | this.groupDiv.style.left = "0px"; |
---|
124 | this.groupDiv.style.height = "100%"; |
---|
125 | this.groupDiv.style.width = "100%"; |
---|
126 | }, |
---|
127 | |
---|
128 | /** |
---|
129 | * APIMethod: destroy |
---|
130 | */ |
---|
131 | destroy: function() { |
---|
132 | this.imageSrc = null; |
---|
133 | this.imageSize = null; |
---|
134 | this.isAlphaImage = null; |
---|
135 | |
---|
136 | this.fixedRelativePosition = false; |
---|
137 | this.positionBlocks = null; |
---|
138 | |
---|
139 | //remove our blocks |
---|
140 | for(var i = 0; i < this.blocks.length; i++) { |
---|
141 | var block = this.blocks[i]; |
---|
142 | |
---|
143 | if (block.image) { |
---|
144 | block.div.removeChild(block.image); |
---|
145 | } |
---|
146 | block.image = null; |
---|
147 | |
---|
148 | if (block.div) { |
---|
149 | this.groupDiv.removeChild(block.div); |
---|
150 | } |
---|
151 | block.div = null; |
---|
152 | } |
---|
153 | this.blocks = null; |
---|
154 | |
---|
155 | OpenLayers.Popup.Anchored.prototype.destroy.apply(this, arguments); |
---|
156 | }, |
---|
157 | |
---|
158 | /** |
---|
159 | * APIMethod: setBackgroundColor |
---|
160 | */ |
---|
161 | setBackgroundColor:function(color) { |
---|
162 | //does nothing since the framed popup's entire scheme is based on a |
---|
163 | // an image -- changing the background color makes no sense. |
---|
164 | }, |
---|
165 | |
---|
166 | /** |
---|
167 | * APIMethod: setBorder |
---|
168 | */ |
---|
169 | setBorder:function() { |
---|
170 | //does nothing since the framed popup's entire scheme is based on a |
---|
171 | // an image -- changing the popup's border makes no sense. |
---|
172 | }, |
---|
173 | |
---|
174 | /** |
---|
175 | * Method: setOpacity |
---|
176 | * Sets the opacity of the popup. |
---|
177 | * |
---|
178 | * Parameters: |
---|
179 | * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). |
---|
180 | */ |
---|
181 | setOpacity:function(opacity) { |
---|
182 | //does nothing since we suppose that we'll never apply an opacity |
---|
183 | // to a framed popup |
---|
184 | }, |
---|
185 | |
---|
186 | /** |
---|
187 | * APIMethod: setSize |
---|
188 | * Overridden here, because we need to update the blocks whenever the size |
---|
189 | * of the popup has changed. |
---|
190 | * |
---|
191 | * Parameters: |
---|
192 | * contentSize - {<OpenLayers.Size>} the new size for the popup's |
---|
193 | * contents div (in pixels). |
---|
194 | */ |
---|
195 | setSize:function(contentSize) { |
---|
196 | OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments); |
---|
197 | |
---|
198 | this.updateBlocks(); |
---|
199 | }, |
---|
200 | |
---|
201 | /** |
---|
202 | * Method: updateRelativePosition |
---|
203 | * When the relative position changes, we need to set the new padding |
---|
204 | * BBOX on the popup, reposition the close div, and update the blocks. |
---|
205 | */ |
---|
206 | updateRelativePosition: function() { |
---|
207 | |
---|
208 | //update the padding |
---|
209 | this.padding = this.positionBlocks[this.relativePosition].padding; |
---|
210 | |
---|
211 | //update the position of our close box to new padding |
---|
212 | if (this.closeDiv) { |
---|
213 | // use the content div's css padding to determine if we should |
---|
214 | // padd the close div |
---|
215 | var contentDivPadding = this.getContentDivPadding(); |
---|
216 | |
---|
217 | this.closeDiv.style.right = contentDivPadding.right + |
---|
218 | this.padding.right + "px"; |
---|
219 | this.closeDiv.style.top = contentDivPadding.top + |
---|
220 | this.padding.top + "px"; |
---|
221 | } |
---|
222 | |
---|
223 | this.updateBlocks(); |
---|
224 | }, |
---|
225 | |
---|
226 | /** |
---|
227 | * Method: calculateNewPx |
---|
228 | * Besides the standard offset as determined by the Anchored class, our |
---|
229 | * Framed popups have a special 'offset' property for each of their |
---|
230 | * positions, which is used to offset the popup relative to its anchor. |
---|
231 | * |
---|
232 | * Parameters: |
---|
233 | * px - {<OpenLayers.Pixel>} |
---|
234 | * |
---|
235 | * Returns: |
---|
236 | * {<OpenLayers.Pixel>} The the new px position of the popup on the screen |
---|
237 | * relative to the passed-in px. |
---|
238 | */ |
---|
239 | calculateNewPx:function(px) { |
---|
240 | var newPx = OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply( |
---|
241 | this, arguments |
---|
242 | ); |
---|
243 | |
---|
244 | newPx = newPx.offset(this.positionBlocks[this.relativePosition].offset); |
---|
245 | |
---|
246 | return newPx; |
---|
247 | }, |
---|
248 | |
---|
249 | /** |
---|
250 | * Method: createBlocks |
---|
251 | */ |
---|
252 | createBlocks: function() { |
---|
253 | this.blocks = []; |
---|
254 | |
---|
255 | //since all positions contain the same number of blocks, we can |
---|
256 | // just pick the first position and use its blocks array to create |
---|
257 | // our blocks array |
---|
258 | var firstPosition = null; |
---|
259 | for(var key in this.positionBlocks) { |
---|
260 | firstPosition = key; |
---|
261 | break; |
---|
262 | } |
---|
263 | |
---|
264 | var position = this.positionBlocks[firstPosition]; |
---|
265 | for (var i = 0; i < position.blocks.length; i++) { |
---|
266 | |
---|
267 | var block = {}; |
---|
268 | this.blocks.push(block); |
---|
269 | |
---|
270 | var divId = this.id + '_FrameDecorationDiv_' + i; |
---|
271 | block.div = OpenLayers.Util.createDiv(divId, |
---|
272 | null, null, null, "absolute", null, "hidden", null |
---|
273 | ); |
---|
274 | |
---|
275 | var imgId = this.id + '_FrameDecorationImg_' + i; |
---|
276 | var imageCreator = |
---|
277 | (this.isAlphaImage) ? OpenLayers.Util.createAlphaImageDiv |
---|
278 | : OpenLayers.Util.createImage; |
---|
279 | |
---|
280 | block.image = imageCreator(imgId, |
---|
281 | null, this.imageSize, this.imageSrc, |
---|
282 | "absolute", null, null, null |
---|
283 | ); |
---|
284 | |
---|
285 | block.div.appendChild(block.image); |
---|
286 | this.groupDiv.appendChild(block.div); |
---|
287 | } |
---|
288 | }, |
---|
289 | |
---|
290 | /** |
---|
291 | * Method: updateBlocks |
---|
292 | * Internal method, called on initialize and when the popup's relative |
---|
293 | * position has changed. This function takes care of re-positioning |
---|
294 | * the popup's blocks in their appropropriate places. |
---|
295 | */ |
---|
296 | updateBlocks: function() { |
---|
297 | if (!this.blocks) { |
---|
298 | this.createBlocks(); |
---|
299 | } |
---|
300 | |
---|
301 | if (this.size && this.relativePosition) { |
---|
302 | var position = this.positionBlocks[this.relativePosition]; |
---|
303 | for (var i = 0; i < position.blocks.length; i++) { |
---|
304 | |
---|
305 | var positionBlock = position.blocks[i]; |
---|
306 | var block = this.blocks[i]; |
---|
307 | |
---|
308 | // adjust sizes |
---|
309 | var l = positionBlock.anchor.left; |
---|
310 | var b = positionBlock.anchor.bottom; |
---|
311 | var r = positionBlock.anchor.right; |
---|
312 | var t = positionBlock.anchor.top; |
---|
313 | |
---|
314 | //note that we use the isNaN() test here because if the |
---|
315 | // size object is initialized with a "auto" parameter, the |
---|
316 | // size constructor calls parseFloat() on the string, |
---|
317 | // which will turn it into NaN |
---|
318 | // |
---|
319 | var w = (isNaN(positionBlock.size.w)) ? this.size.w - (r + l) |
---|
320 | : positionBlock.size.w; |
---|
321 | |
---|
322 | var h = (isNaN(positionBlock.size.h)) ? this.size.h - (b + t) |
---|
323 | : positionBlock.size.h; |
---|
324 | |
---|
325 | block.div.style.width = (w < 0 ? 0 : w) + 'px'; |
---|
326 | block.div.style.height = (h < 0 ? 0 : h) + 'px'; |
---|
327 | |
---|
328 | block.div.style.left = (l != null) ? l + 'px' : ''; |
---|
329 | block.div.style.bottom = (b != null) ? b + 'px' : ''; |
---|
330 | block.div.style.right = (r != null) ? r + 'px' : ''; |
---|
331 | block.div.style.top = (t != null) ? t + 'px' : ''; |
---|
332 | |
---|
333 | block.image.style.left = positionBlock.position.x + 'px'; |
---|
334 | block.image.style.top = positionBlock.position.y + 'px'; |
---|
335 | } |
---|
336 | |
---|
337 | this.contentDiv.style.left = this.padding.left + "px"; |
---|
338 | this.contentDiv.style.top = this.padding.top + "px"; |
---|
339 | } |
---|
340 | }, |
---|
341 | |
---|
342 | CLASS_NAME: "OpenLayers.Popup.Framed" |
---|
343 | }); |
---|